TECH PLAY

サイオステクノロジー(Tech.Lab)

サイオステクノロジー(Tech.Lab) の技術ブログ

546

はじめに こんにちはサイオステクノロジーの小野です。 前回 はOpenShift AIのデータサイエンスパイプラインを実装して実行しました。今回はそのパイプラインをスケジュール設定により、定期実行する方法を解説します。MLOpsにおいて重要な設定なので、ぜひ覚えて帰ってください。 パイプラインのスケジュールについて OpenShift AIではパイプラインのスケジュール設定を行うことが可能です。 パイプラインの定期実行により、常に最新のモデルAPIを利用することができます。 パイプラインのスケジュール実装例 モデルのデータ対応 今回は2つの画像データを用いて、スケジュールによるモデルの更新を確認します。 A画像 今まで利用してきたMNIST画像です。今までの記事で作成したモデルはこのA画像に対応したモデルになります。 B画像 A画像の色を反転させた画像です。 今回用いるデータ。A画像は今まで利用してきた画像。B画像はA画像の色を反転させた画像。モデルAPIをA画像に対応したモデルからB画像に対応したモデルに更新する。 A画像に対応しているモデルAPIをパイプラインのスケジュールによる自動更新により、B画像に対応したモデルに更新します。 パイプライン構成図 今回スケジュール設定を行うパイプラインは前回実行したものと同じになります。詳しくは前回の記事を参照して下さい。(URL) その構成図を再掲すると以下になります: パイプラインの構成図 このS3内の画像データをA画像からB画像に変更することで自動的にB画像に対応したモデルが作成され、デプロイされます。 前提条件 OpenShift AI:2.13 以前の記事のモデルサービングを実行済み( OpenShift AIのモデルサービング機能について ) すでにA画像で学習したモデルがデプロイされている状態になります。 以前の記事のパイプラインを実行済み( OpenShift AIのデータサイエンスパイプラインについて ) サービスアカウントの設定を行って、モデルの更新ができる状態にしてください。 今回利用するプログラムは以下のリンクからダウンロードしてください。 MLschedule モデル更新前動作確認 モデル更新前:A画像によるAPIリクエスト実施 JupyterLab上で5_test-api.ipynbを実行してください。なお実行時はコード内のエンドポイントやAPIのトークンのシークレットを各自設定した値に変更してください。 モデル更新前はA画像によって学習が行われたモデルAPIなので、A画像に対して正しい推論が行われていることが確認できます。 モデル更新前のA画像に対する推論結果。推論と実際の結果が一致しているのが確認できる。 以前の記事でデプロイしたモデルはA画像で学習している。したがって、A画像の推論はうまくいく。 モデル更新前:B画像によるAPIリクエスト実施 JupyterLab上で6_test-api-inv.ipynbを実行してください。なお実行時はコード内のエンドポイントやAPIのトークンのシークレットを各自設定した値に変更してください。このプログラムは色が反転したB画像をモデルAPIに送信しています。 モデルAPIはB画像を学習していないので、推論した画像の数字と実際の画像の数字が一致しないことが確認できます。 モデル更新前のB画像に対する推論結果。推論と実際の結果が一致していないのが確認できる。 デプロイされているモデルはA画像でしか学習していないのでB画像の推論はうまくいかない。 スケジュール設定 パイプラインのエクスポート JupyterLab上で4_pipeline-demo.pipelineファイルを開いてください。このパイプラインファイルをKubeflow Pipelines形式のyamlファイルにエクスポートしてください。詳しくは前回の記事を参照してください。(URL) エクスポートしたyamlの一部が以下になります。デフォルトだとパイプラインのキャッシング機能がオンになっていますが、今回構築したパイプラインはキャッシング機能がついていると毎回の実行が省略されてしまいます。スケジュール設定によって毎回実行してほしいのでキャッシング機能をオフにします。そのためにenableCacheをfalseに設定します。 root: dag: tasks: run-a-file: cachingOptions: enableCache: false # enableCacheをfalseに変更する componentRef: name: comp-run-a-file taskInfo: name: 1_dataprocessed run-a-file-2: cachingOptions: enableCache: false # enableCacheをfalseに変更する componentRef: name: comp-run-a-file-2 dependentTasks: - run-a-file taskInfo: name: 2_training run-a-file-3: cachingOptions: enableCache: false # enableCacheをfalseに変更する componentRef: name: comp-run-a-file-3 dependentTasks: - run-a-file-2 taskInfo: name: 3_modeldeploy schemaVersion: 2.1.0 sdkVersion: kfp-2.8.0 パイプラインのインポート 編集したyamlファイルをパイプラインサーバーにインポートします。Import Pipelineを押下して、パイプライン名を記入して、upload fileでyamlファイルをアップロードします。 パイプラインのインポート パイプラインのスケジュール設定 作成したパイプラインのActionsから、Create Scheduleを押下すると、スケジュール設定できます。 Create scheduleを押下するとスケジュール設定が行える スケジュール設定は以下のように設定します: Experiment:Default Name:スケジュール名 Trigger type:Periodic(スケジュール設定する形式を指定) Run every:実行する間隔を指定(今回はモデルの更新を確認するだけなので5分程度の間隔で十分です) Maximum concurrent runs:10(並行して実行するパイプラインの最大数) Start date:オフ(スケジュール実行の始める日にちを指定) End date:オフ(スケジュール実行が終わる日にちを指定) Catch up:オン(スケジュールが遅れた場合、本来のスケジュールに追いつく必要があるかどうかの設定) Pipeline:スケジュール設定するパイプラインを指定 Pipeline version:スケジュール設定するパイプラインのバージョンを指定 スケジュール設定 パイプラインのスケジュール実行 スケジュールを実行するとパイプラインのRunsのSchedulesに追加されます。 パイプラインのスケジュール Runsにスケジュール設定通りの間隔でパイプラインが実行されます。 パイプラインのスケジュール実行。設定した5分間隔でパイプラインが実行されているのが確認できる。 学習元データの変更 B画像アップロード 以上の操作で、スケジュールによってモデルの自動更新がされている状態になります。 ここでモデルの更新がされることを確認します。そこで、パイプライン中で取り扱っているA画像をB画像に上書きします。 JupyterLab上で7_dataupload-inv.ipynbを実行してください。これはパイプラインで取り扱うA画像が保存されている場所にB画像を上書きするプログラムです。 A画像が保存されている場所にB画像を上書きする。 モデル更新後動作確認 モデル更新後:B画像によるAPIリクエスト実施 B画像をアップロードしてからパイプラインが実行されるのを確認したら、もう一度JupyterLab上で6_test-api-inv.ipynbを実行してください。B画像に対応したモデルが自動的にデプロイされているので正しく推論できるようになったことが確認できます。 モデル更新後のB画像に対する推論結果。推論と実際の結果が一致しているのが確認できる。 パイプラインが実行されてB画像を学習したモデルがデプロイされたのでB画像の推論がうまくいく。 モデル更新後:A画像によるAPIリクエスト実施 次にJupyterLab上で5_test-api.ipynbを実行してください。更新後のモデルAPIはB画像でしか学習していないので、A画像に対しては推論ができていないことが確認できます。 モデル更新後のA画像に対する推論結果。推論と実際の結果が一致していないのが確認できる。 B画像でしか学習していないモデルなのでA画像に対してはうまく推論できない。 最後に このようにパイプラインのスケジュール設定を行うと自動的にモデルの更新を行うことができます。MLOpsを実現するにはパイプラインのスケジュール設定が必須だと思います。モデルを常に最新の品質を保つためにもぜひパイプラインを実装して、スケジュール設定してみてください。 参考 データサイエンスパイプラインの設定: https://docs.redhat.com/ja/documentation/red_hat_openshift_ai_self-managed/2.13/html/working_with_data_science_pipelines/index 前回: OpenShift AIのデータサイエンスパイプラインについて ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post OpenShift AIのパイプラインにスケジュール設定してみた first appeared on SIOS Tech. Lab .
アバター
はじめに こんにちはサイオステクノロジーの小野です。 前回 はOpenShift AIのモデルサービング機能を用いて、推論APIを実装しました。今回はOpenShift AIのもう一つの重要な機能であるデータサイエンスパイプラインを実装します。パイプラインを利用することでモデル開発を高速化することが可能になります。MLOpsの実現には欠かせない機能なので、しっかり実装できるようにしましょう。 データサイエンスパイプラインについて データサイエンスパイプラインとは、機械学習のワークフローを標準化および自動化し、データサイエンスモデルを開発およびデプロイします。 OpenShift AI(バージョン2.9以降)ではKubeflow Pipelines バージョン2.0を利用してパイプラインを実行しています。 Kubeflow Pipelines バージョン2.0はワークフローエンジンとしてArgo Workflowを利用しています。 パイプラインの種類 パイプラインの実装方法は2通りあります。 Elyra ElyraはJupyterLab上でGUIを利用してパイプラインを構築できます。パイプラインで自動化したいソースコードファイルをドラッグ&ドロップし、そのファイル同士に線を引くだけで構築できるので、直感的にパイプラインを構築できます。 パイプラインの実行もJupyterLab上で簡単に実行できるので非常にお手軽です。 また、Kubeflow Pipelines形式にエクスポートすることも可能です。 Kubeflow Pipelines SDK Kubeflow Pipelines SDKはPythonコードを使用して作成したパイプラインをyaml形式にコンパイルするSDKです。 Pythonでパイプラインを構築するので、細かい処理や設定を行うことが可能です。 パイプラインの実装例 今回はパイプラインの設定を行い、データの準備からモデルの更新を行うところまで行うパイプラインを構築します。 MLOpsに対応する部分としては以下のようになります: 今回実装するパイプラインに対応するMLOpsの範囲 今回実装するパイプラインでは、データの準備、モデルの学習、モデルの提供を作成しております。 パイプライン概要 今回実行するパイプラインは以下の構成になっています: 今回実行するパイプラインの構成 1_dataprocessed.ipynb(データの準備) 画像データをS3からダウンロードして、学習がしやすい形に前処理を行います。その後、前処理済み学習データをS3にアップロードします。 2_training.ipynb(モデルの学習) 前処理を行った学習データをS3からダウンロードして、モデルの学習を行います。その後、ONNX形式にモデルをエクスポートし、S3にアップロードします。 3_modeldeploy.ipynb(モデルの提供) モデルサーバーを更新して、モデルの再デプロイを行います。 パイプライン構成図 パイプラインの構成図は以下に示します。 ➀ユーザーのパイプライン実行 ②パイプラインアーティファクトと呼ばれるパイプライン情報をS3に保存 ③パイプラインサーバーのパイプライン実行におけるパイプライン情報取得 ④パイプラインのコードを順次実行 ⑤1_dataprocessed.ipynbにおける画像データの取得 ⑥1_dataprocessed.ipynbによって前処理した学習データのアップロード ⑦2_training.ipynbにおける学習データの取得 ⑧2_training.ipynbによってONNX形式にエクスポートした学習モデルのアップロード ⑨3_modeldeploy.ipynbによるモデルサービングサーバーの更新 ⑩モデルサービングサーバー再起動によるモデル再デプロイ パイプラインの構成図 前提条件 OpenShift AI:2.13 データサイエンスプロジェクト作成済み 以前の記事を参考にしてください( OpenShift AI を導入してみた ) データ接続設定済み 以前の記事を参考にしてください( OpenShift AIで機械学習をやってみた ) モデルデプロイ済み 以前の記事を参考にしてください( OpenShift AIのモデルサービング機能について ) 注意:ワークベンチをすでに作成している場合はパイプラインサーバーを設定した後に作り直してください。 パイプラインサーバー設定 OpenShift AIのデータサイエンスプロジェクト内のPipelineというタブを開いて下さい。Configure pipelineを押下すると設定画面が開きます。S3ストレージの接続設定が行えるので、データ接続と同じ設定にするか新しくS3の接続情報を入力してください。 パイプラインサーバー設定 この接続先にパイプラインのアーティファクトと呼ばれるパイプラインの実行に必要な情報や実行した際の中間成果物が保存されます。 ワークベンチ作成 パイプラインサーバーを作成した後にワークベンチを作成します。作成方法は以前の記事を参考にして下さい。( OpenShift AIで機械学習をやってみた ) サービスアカウント設定 今回構築するパイプラインにはモデルの更新を行う処理が含まれています。したがって、パイプラインを動作させるサービスアカウントに対して、モデルサーバーの設定を行うinferenceserviceというリソースとモデルサーバーのポッドを管理するDeploymentを操作する権限を付与する必要があります。 最初にOpenShiftコンソールからユーザー管理 > Rolesを開きます。Roleの作成を押下し、InferenceserviceとDeploymentを操作する権限があるロールをyamlで作成します: kind: Role apiVersion: rbac.authorization.k8s.io/v1 metadata: name: pipeline-modeldeploy-role namespace: test-ai # ロールが属するネームスペースを指定 rules: - verbs: - get - list - watch - create - update - patch - delete apiGroups: - serving.kserve.io resources: - inferenceservices - verbs: - get - list - watch - create - update - patch - delete apiGroups: - apps resources: - deployments ロール設定 次に作成したロールとパイプラインを動作させるサービスアカウントにロールバインディングを設定して連携させます。 ユーザー管理 > RoleBindingsを開いてください。 バインディングの作成を押下して、以下のように設定してください: バインディングタイプ:namespace のロールバインディング (RoleBinding) 名前:ロールバインディングの名前 Namespace:ロールバインディングが属するネームスペース Role名:先ほど作成したロールの名前 サブジェクト:ServiceAccount namespaceの選択:データサイエンスプロジェクト名(サービスアカウントが属するネームスペース) サブジェクトの名前:pipeline-runner-dspa ロールバインディング設定 これでパイプラインでモデルの更新ができるようになりました。 パイプラインの実装 それではいよいよパイプラインを実行します。今回はElyraを用いてパイプラインを構築します。以下のリンクからファイルをダウンロードし、JupyterLabにアップロードしてください。 MLpipeline パイプラインの実行前に0_dataupload.ipynbを実行して、S3内に画像データを保存してください。すでに実行している場合は省略して下さい。 4_pipeline-demo.pipelineファイルを開いてください。1~3のプログラムがつながったパイプラインが確認できます。 Elyraの画面 Elyraの上部メニューのRun pipelineを押下するとパイプラインを実行できます。 Run pipelineによりパイプラインの実行が可能 OpenShiftAIのコンソール画面に移動して、データサイエンスプロジェクトのPipelineのタブを開いてください。 実行したパイプラインと同じファイル名(4_pipeline-demo)のパイプラインが実行されているのが確認できます。 また、パイプライン名の左の を押下するとパイプラインのバージョンを確認できます。 パイプライン一覧 その一番新しいバージョンのメニューをクリックして、View runを押下すると実行中のパイプラインを確認することができます。 メニューからView runより実行中のパイプラインを表示できる 実行されているパイプラインを開くとパイプラインの進行状況を確認できます。 実行中のパイプライン パイプラインの実行がSuccseedになったら実行完了です。 Succseedになったら実行完了 もしエラーが起きてFailedとなったら該当のプログラムをクリックして、ログを確認してみてください。 パイプラインのログ確認 次にパイプラインのアーティファクトが保存されているのを確認します。S3に移動して実行したパイプラインのバージョンと同じ名前のディレクトリが作成されていることが分かります。 パイプラインのアーティファクト保存場所 そのディレクトリの中身を見ると、パイプラインで実行した1~3のプログラムが圧縮されて保存されていたり、htmlにエクスポートされ保存されたりしています。 パイプラインのディレクトリ中身 最後に 今回はデータの取得からモデルの更新を行うパイプラインを実行しました。パイプライン機能をうまく活用して、AIを効率よく開発してみてください。次回はパイプラインのスケジュール設定を解説します。 参考 Kubeflow Pipelines: https://www.kubeflow.org/docs/components/pipelines/ パイプライン設定: https://docs.redhat.com/ja/documentation/red_hat_openshift_ai_self-managed/2.13/html/working_with_data_science_pipelines/index 前回: OpenShift AIのモデルサービング機能について ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post OpenShift AIのデータサイエンスパイプラインについて first appeared on SIOS Tech. Lab .
アバター
メリークリスマス!12月も終盤ですね。年末向けて仕事を爆速で消化しなければならなく、濃密な最終週を過ごす予定の龍ちゃんです。 実は昨日まで、弊社でもアドベントカレンダーの実施を行っていました。お題は「サイオス社員が今年一年で新しく学んだ技術」というタイトルになります。だいぶ幅広く、いろいろな内容の投稿を募集していました。1201~1224まで見事に切れ目なく投稿が続いたので、宣伝を兼ねて紹介記事を作成していきます。 アドベントカレンダー さすがにそれぞれを読んで紹介するのも大変なので、生成AIをフルに活用して要約してもらっていこうと思います。 【Azure】CosmosDBにおけるRU入門ガイド【初心者向け】 2024-12-01 【Azure】CosmosDBにおけるRU入門ガイド【初心者向け】 Azure Cosmos DBは、Microsoft Azureが提供するグローバル分散型NoSQLデータベースサービスで、高スループットと低レイテンシーが特徴です。重要な概念である「Request Unit(RU)」は、操作に必要なリソースを統一指標化したもので、データサイズや操作の複雑さに応じて消費量が変動します。スループット設定には、需要に応じた自動調整が可能な「AutoScale」モードや固定設定の「Manual」モードがあり、効率的なコスト管理が可能です。また、RU消費を最適化するためには、データモデリングやパーティションキー設計が重要となります。Cosmos DBの柔軟な設定や最適化手法を理解し、運用効率を高める詳細が本記事で解説されています。 Hyperleger Fabric v3.0の解説! 2024-12-02 Hyperleger Fabric v3.0の解説! Hyperledger Fabric v3.0が2024年9月にリリースされ、新機能としてビザンチン障害耐性(BFT)オーダリングサービスが導入されました。これにより、最大でノードの1/3未満が悪意ある行動をしてもシステムが正常に動作します。また、Ed25519暗号アルゴリズムのサポートにより、署名と検証の高速化とセキュリティ強化が図られています。さらに、全ての承認済みチェーンコードのクエリ機能が追加され、管理が容易になりました。これらの新機能により、Fabric v3.0は分散システムの信頼性と性能を向上させています。 【Ragas】日本語テストセットの生成方法のご紹介【v0.2】 2024-12-03 【Ragas】日本語テストセットの生成方法のご紹介【v0.2】 Ragas v0.2では、日本語のテストセットを自動生成する機能が強化されました。これにより、例えば「社内規約」の文書から「有給休暇は何日取れますか?」といった質問と、その回答ペアを自動的に作成できます。従来、英語で出力されていたテストセットも、プロンプトの多言語対応機能を活用することで、日本語での生成が可能となりました。具体的な実装方法やコード例については、公式ドキュメントや関連資料を参照することをおすすめします。 LINE LIFFアプリを開発する際にはまったポイント 2024-12-04 LINE LIFFアプリを開発する際にはまったポイント LINEのLIFFアプリ開発における注意点として、以下の3点が挙げられます。 トークンの取り扱いとユーザー情報の取得 : ユーザー特定のため、フロントエンドで取得したAccessTokenをサーバーに送信し、サーバー側でトークン検証とユーザー情報の取得を行う方法が推奨されています。 LINEからのアクセス確認 LIFFアプリ外からのアクセス時にエラーを防ぐため、 liff.isInClient() 関数を使用して実行環境を判定し、適切な対応を取ることが重要です。 動作確認環境の構築 開発中の動作確認には、手元の環境をHTTPS化する必要があります。その際、ngrokなどのツールを活用すると効率的です。 これらのポイントを押さえることで、LIFFアプリ開発の効率と品質を向上させることができます。 【Azure】CosmosDBにおけるパーティション入門ガイド【初心者向け】 2024-12-05 【Azure】CosmosDBにおけるパーティション入門ガイド【初心者向け】 Azure Cosmos DBのパーティションは、データの効率的な管理とスケーラビリティに不可欠な概念です。主に「論理パーティション」と「物理パーティション」の2種類が存在します。論理パーティションは、指定したパーティションキーに基づき、コンテナ内のデータを分類する単位で、各パーティションは最大20GBのデータを保持できます。一方、物理パーティションは、Azure Cosmos DBが内部的に管理するリソース単位で、複数の論理パーティションが1つの物理パーティションにマッピングされます。適切なパーティションキーの選択は、データの均等な分散とスループットの最適化に直結し、特定のパーティションに負荷が集中する「ホットパーティション」を避けるためにも重要です。さらに、クエリの効率性にも影響を与え、単一のパーティション内で完結する「インパーティションクエリ」は高速でリソース消費が少なく、複数のパーティションにまたがる「クロスパーティションクエリ」はその逆となります。これらの特性を理解し、適切なパーティションキーを設定することで、Azure Cosmos DBの性能を最大限に引き出すことが可能です。 Tailwindをstyle属性へ変換【mailwind】 2024-12-06 Tailwindをstyle属性へ変換【mailwind】 Tailwind CSSでデザインされたHTMLを、インラインスタイル形式に変換するツール「mailwind」が紹介されています。このツールを使用することで、HTMLメールの作成や、特定の要件に応じたスタイル変換が容易になります。インストールは npm install mailwind で簡単に行え、コマンドラインから入力HTMLファイルを指定して、インラインスタイルのHTMLや外部CSSファイルを生成できます。具体的な使用例として、Tailwindクラスで記述されたHTMLをmailwindで変換し、インラインスタイル形式に変換する手順が示されています。ただし、Tailwindの設定ファイルで指定したGoogle Fontsの情報は自動的にロードされないため、必要に応じてHTML内に直接記載するなどの対応が必要です。このツールを活用することで、HTMLメールのデザインや特定の要件に合わせたスタイル変換が効率的に行えます。 Firestoreの使い方を改めて図解しておく 2024-12-07 Firestoreの使い方を改めて図解しておく Firestoreは、Googleが提供するNoSQLデータベースで、ドキュメント指向のデータ構造を持ち、柔軟なスケーラビリティとリアルタイムのデータ同期を特徴としています。データはコレクションとドキュメントの階層構造で管理され、ドキュメント内にサブコレクションを持つことも可能です。データ取得方法として、ドキュメントIDを指定した単一ドキュメントの取得、コレクション全体の取得、コレクショングループを用いた複数コレクションからの一括取得などがあり、用途に応じて使い分けられます。クエリを使用する際には、特定の条件でのデータ抽出が可能ですが、複雑なクエリやコレクショングループを使用する場合、インデックスの作成が必要となることがあります。また、配列データの取り扱いには制限があり、配列内のオブジェクト検索では完全一致が求められるため、データ設計時に注意が必要です。Firestoreの柔軟性を活かすためには、データ構造の設計やクエリの最適化が重要であり、公式ドキュメントやリファレンスを参照しながら適切な実装を心掛けることが推奨されます。 バージョン管理ツールasdfを使ってみた 2024-12-08 バージョン管理ツールasdfを使ってみた asdfは、複数のプログラミング言語やツールのバージョンを一元管理できるバージョンマネージャーです。従来、各言語ごとに異なるバージョン管理ツールを使用していましたが、asdfを導入することで、これらを統合的に管理できます。Mac環境では、Homebrewを用いて簡単にインストール可能で、プラグインの追加やバージョンの切り替えも直感的に行えます。さらに、プロジェクトごとに異なるバージョンを設定することも可能で、ディレクトリ単位でのバージョン管理が容易です。これにより、複数のプロジェクトを並行して進める際の環境構築や管理が効率化されます。asdfの活用により、開発環境の整備がシンプルになり、作業効率の向上が期待できます。 【Azure Functions】No HTTP triggers found発生時の調査方法 2024-12-09 【Azure Functions】No HTTP triggers found発生時の調査方法 Azure Functionsでデプロイ後に関数が表示されない問題に対処する方法が紹介されています。具体的には、デプロイ時にエラーメッセージが表示されないものの、関数が見当たらない場合、Azureポータルの「問題の診断と解決」機能を活用することが推奨されています。特に、Python関数に関連する例外情報を確認することで、問題の原因を特定できます。記事では、 Client.__init__() 関数に予期しないキーワード引数 'proxies' が渡されたことによるエラーの例が挙げられています。このような診断手法を用いることで、デプロイ時の問題解決に役立てることができます。 【RAG評価手法】評価できないものは改善できない!?体系的に評価指標をご紹介! 2024-12-10 【RAG評価手法】評価できないものは改善できない!?体系的に評価指標をご紹介! 自然言語生成(NLG)の評価は、伝統的なプログラムのテストとは異なり、多様な表現が可能であるため評価が困難です。人手評価や模範回答を用いる自動評価、または記述解答を使わない新方式LLM as a judgeといったアプローチに分かれます。RAGの評価は特に難易度が高く、質問、コンテキスト、回答、模範解答を基に総合的に評価する手法が必要です。主要な評価手段にRAGAsやRAGCheckerがあり、それぞれの指標を使い再現性・忠実性などを測っています。今後の研究と改善で評価手法の成熟が期待されます。 AIエージェントでロボットを制御する【langchain・Streamlit】 2024-12-11 AIエージェントでロボットを制御する【langchain・Streamlit】 生成AIをテーマにしたデモを通じて、AIエージェントによるロボット操作の実装を紹介します。使用した技術にはStreamlit、Qumcum、Langchainが含まれます。システムはユーザーの入力を解釈し、ロボットの動作を制御します。設計はPythonで行い、QumcumをAPI経由で操作。Streamlitはページ制御を担い、接続状況に応じたインターフェースを提供します。課題としては、同期処理によるフリーズやUIの改善点が挙げられ、今後の取り組みが期待されます。このデモはAIエージェントとロボットの新たな可能性を示しました。 Rancher入門:Rancherを用いたKubernetesクラスター管理 2024-12-12 Rancher入門:Rancherを用いたKubernetesクラスター管理 本記事では、Rancherを使用して複数のKubernetesクラスターを管理する方法を解説します。RancherからEKSクラスターを作成し、既存のKubernetesクラスターをRancherにインポートする手順を詳述。Node数の調整やクラスターのアップグレード、ワークロード管理の方法も紹介。特に、Rancherのダッシュボードを活用することで、効率的なクラスター管理が可能となります。次回はRancherのモニタリング機能について探ります。 Apache HTTPとApache Tomcatを連携するWebサーバを構築してみた 2024-12-13 Apache HTTPとApache Tomcatを連携するWebサーバを構築してみた Apache HTTPとApache Tomcatを連携したWebサーバの構築手順を解説します。まず、連携の利点や使用環境を紹介し、次にApache HTTPとTomcat、OpenJDKのインストール手順を詳述。続いて、自己署名証明書の作成やApache HTTPの設定(HTTP、SSL、Virtual Hostなど)、Tomcatの設定を行います。特に、複数のWebサイトを提供するための設定や、管理者用Webアプリの設定もカバー。最後に、サービスの起動とWebサイトの確認を行い、全体の流れをまとめています。構築の参考にどうぞ。 linterとformatterが一つに!?Biome使ってみた 2024-12-14 linterとformatterが一つに!?Biome使ってみた 本記事では、TypeScript界隈で注目されているツール「Biome」を紹介します。Biomeは、LinterとFormatterが一体化したツールで、ESLintやPrettierの代替として利用可能です。Rustで動作しており、高速な静的解析とコード整形を実現します。導入は簡単で、npmコマンドでインストール後、設定ファイルを生成するだけです。使い方もシンプルで、 format や lint コマンドでそれぞれの機能を実行可能。さらに、 check コマンドで両方を同時に行えます。今回の内容は、エンジニアの細川氏によるアドベントカレンダーの記事からの情報です。 ChatGPTでニュアンスを数値化する 2024-12-15 ChatGPTでニュアンスを数値化する 生成AIを活用して日本人が感覚的に理解する「表現」を数値化する方法を紹介しています。特に「喜びの感情」を1~100で評価するプロンプトを用い、シンプルな数値化から、評価基準を追加することで精度を向上させる手法が解説されています。デモとして「泳げ!進め!カツオくん」や「AIエージェントでロボットを制御する」などが挙げられ、生成AIの可能性を示しています。この技術により、多様なアプリケーションが期待されています。 OpenShift AIで機械学習をやってみた 2024-12-16 OpenShift AIで機械学習をやってみた OpenShift AIを使用した機械学習の手法を解説します。まず、データサイエンスプロジェクトを作成し、データ接続を設定します。次に、ワークベンチを構築し、JupyterLabにプログラムをアップロード。具体的には、MNISTデータセットを使用して数字の画像を学習するモデルを作成します。作業はデータ収集、前処理、モデルの学習と進み、最終的に精度を評価します。OpenShift AIは、インフラ目線での学びを提供し、外部ストレージとの接続も可能です。これにより、機械学習の実践が容易になります。 Rancher入門:Rancherを用いたKubernetesクラスターの監視 2024-12-17 Rancher入門:Rancherを用いたKubernetesクラスターの監視 本記事では、Rancherを利用したKubernetesクラスターの監視方法について解説しています。Rancherの標準モニタリング機能を有効化し、PrometheusやGrafanaと連携することで、クラスターのリソース消費状況をダッシュボードで可視化し、アラート通知を設定できます。導入手順としては、まずRancherのダッシュボードからrancher-monitoringアプリケーションをインストールし、その後各クラスターのリソースを監視する方法を紹介。アラート設定では、Slackへの通知も実現可能です。Rancherの一元管理により、複数クラスターの運用負担を軽減できる点が大きなメリットです。 【Azure】CosmosDBにおけるインデックス入門ガイド【初心者向け】 2024-12-18 【Azure】CosmosDBにおけるインデックス入門ガイド【初心者向け】 今回はCosmosDBのインデックス機能についてご紹介します。インデックスはデータベースの検索パフォーマンスを向上させる重要な機能であり、CosmosDBでも自動的にインデックスが作成されます。特に逆インデックスという仕組みが使われ、アイテムが追加されるたびにツリー構造が更新されます。検索時にはインデックスシークやインデックススキャンなどの手法が用いられ、効率的にデータを取得します。適切なフィルター句を選択することで、検索速度の向上やコスト削減が可能です。また、インデックスポリシーを調整することで、さらに最適化が可能です。詳細な設定方法や具体例については公式ドキュメントを参照してください。 SIOS輪読会の取り組み 2024-12-19 SIOS輪読会の取り組み PS/SLの佐々木が、2年間続けている輪読会の取り組みを紹介しています。この輪読会は、エンジニアの基礎スキル向上や共通言語の形成、学習文化の定着を目的としており、週1回の活動を通じて若手エンジニアが書籍を基に議論しながら学んでいます。これにより、心理的安全性も向上し、円滑なコミュニケーションが実現。輪読会は単なる学習に留まらず、技術的な議論を活発にし、組織全体の成長に寄与しています。今後はペアプロなど新たな試みも考えています。 Red Hat OpenShift Serverlessとは? 2024-12-20 Red Hat OpenShift Serverlessとは? サーバーレスアーキテクチャを導入することで、開発者はインフラ管理から解放され、コスト削減とパフォーマンス向上を図れます。Red Hat OpenShift Serverlessは、Knativeを基盤に、アプリケーションの自動デプロイやスケーリングを実現します。これにより、イベント駆動型アプリやマイクロサービスの構築が容易になり、リアルタイムデータ処理が可能です。OpenShift Serverlessはリソースの効率的な使用を促進し、AWS LambdaやKubelessなどの他のサービスと比較して、特定のクラウドプロバイダーへの依存を軽減します。 Azure Pipelinesのタスク「AzureBlob File Copy」をバージョンアップした際にハマった話 2024-12-21 Azure Pipelinesのタスク「AzureBlob File Copy」をバージョンアップした際にハマった話 11月にAzure DevOpsのCDパイプラインでデプロイ時に発生したエラーの解決方法を紹介します。デプロイ中に「Unsupported authentication scheme ‘WorkloadIdentityFederation’」というエラーが発生し、調査の結果、クライアントシークレットの有効期限切れが原因と判明。サービス接続をワークロードIDフェデレーションに切り替え、無事にデプロイが成功しました。しかし、デプロイしたアプリにCSSが適用されず、CDNリソースで404エラーが発生。設定を見直したところ、無事にCSSも適用されました。公式情報が少ない中、同様の問題を抱える方の参考になれば幸いです。 NestJSでJestからVitestに移行してみた 2024-12-22 NestJSでJestからVitestに移行してみた 今回は、JavaScriptおよびTypeScript開発向けのテスト用パッケージ「Vitest」を紹介します。Vitestは、Jestに似た機能を持ちながら、動作が高速で、移行が容易な点が特徴です。特にNestJSプロジェクトでの単体テストでは、体感で3-5倍の速度向上が見られます。また、Viteを使用していないプロジェクトでも利用可能で、ESMOnlyパッケージにも対応しています。一方で、既存のJestテストを完全に移行するのは難しい場合があります。導入方法としては、Jestを削除し、Vitestをインストールする手順が推奨されています。興味がある方はぜひ試してみてください。 Azure OpenAIの音声認識試してみた 2024-12-23 Azure OpenAIの音声認識試してみた サイオステクノロジーの和田拓也氏が、Azure OpenAIを利用して音声認識アプリを作成した手順を紹介します。使用するのはPythonのStreamlitで、ブラウザのマイクから音声を入力し、AIで文字起こしを行います。まず、AzureポータルでOpenAIリソースを作成し、音声認識モデル「whisper」をデプロイします。次に、実装に必要なソースコードをPythonで記述します。動作確認も行い、全体の流れをまとめて解説します。 React 19でuseActionStateで入力フォーム【Typescript】 2024-12-24 React 19でuseActionStateで入力フォーム【Typescript】 React 19の新機能useActionStateを使用して、TypeScriptでの入力フォーム実装方法を解説。フォームのバリデーション、非同期処理の状態管理、エラーハンドリングなど、実践的な実装例を通じて、新しいHookの活用方法を紹介しています。 OpenShift AIのモデルサービング機能について 2024-12-25 OpenShift AIのモデルサービング機能について OpenShift AIのモデルサービング機能について解説しています。モデルサービングとは、学習済みのモデルをデプロイし、APIとして提供する技術です。OpenShift AIでは、以下の2種類のサービングプラットフォームを提供しています。 シングルモデルサービング 大規模モデル向けで、各モデルが独立したサーバー上で動作します。KServeを基盤としており、OpenShift ServerlessやService Meshの設定が必要です。 マルチモデルサービング 小規模から中規模のモデル向けで、複数のモデルを同一サーバー上で管理します。ModelMeshを基盤としており、リソースの効率的な利用が可能です。 記事では、マルチモデルサービングの設定手順や、デプロイしたモデルへのAPIリクエスト方法について具体的に説明しています。これにより、OpenShift AI上でのモデル運用がよりスムーズに行えるようになります。 終わり せっかくなので最終的な総評も生成AIを使ってまとめていきたいと思います。 2024年のSIOS Tech Labアドベントカレンダーでは、以下のような技術的なトピックが投稿されました: 技術分野の分布 クラウドサービス: Azure CosmosDB、Red Hat OpenShift Serverless、Azure OpenAIなど、クラウド関連の記事が多く投稿されました。 開発ツール: NestJSのテストツール(VitestへのJestからの移行)、Azure Pipelinesなど、開発効率化に関する記事が見られました。 組織文化: 輪読会の取り組みなど、技術組織の文化形成に関する記事も含まれています。 特徴的な傾向 実践的な内容: 具体的な実装方法や、実際に遭遇した問題の解決方法など、実務に直結する内容が多く含まれています。 最新技術への注目: Azure OpenAIの音声認識など、最新のAI技術の実践的な活用例が紹介されています。 知識共有の重視: 技術的なトピックだけでなく、組織内での学習文化の醸成についても触れられており、継続的な技術力向上への取り組みが見られます。 全体として、クラウドサービスとAIを中心に、実践的で最新の技術トレンドを反映した投稿が多く、技術組織としての成長と学習を重視する企業文化が垣間見える内容となっています。 アドベントカレンダーの総評 今年は、いろんな社員の協力をいただいてアドベントカレンダーの投稿が間に合いました。この場を借りてお礼を申し上げます。特に月の前半は、同じチームのメンバーの協力が半端なかったです。おかげで12月の投稿数も伸びているので、ブログの運営チームうっはうはです。 これからも時には企画・執筆を継続していきますのでぜひ共有・コメントよろしくお願いします。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 2024年 SIOS Tech Lab アドベントカレンダー first appeared on SIOS Tech. Lab .
アバター
はじめに こんにちはサイオステクノロジーの小野です。 前回 はOpenShift AIのワークベンチを設定して、実際に機械学習を行いました。今回はOpenShift AIの主要な機能の一つであるモデルサービング機能を利用して、学習したモデルをAPIとして提供する方法を解説します。 モデルサービングとは モデルサービングとは学習したモデルをモデルサーバーにデプロイすることで、推論APIとしてモデルを提供する機能です。 サービングの種類 OpenShiftAIではマルチモデルサービングとシングルモデルサービングという2つのモデルサービングプラットフォームを提供しています。 シングルモデルサービング LLMなどの大規模モデル用のプラットフォームです。KServeコンポーネントをベースとしているため、OpenShift AIのほかにRed Hat OpenShift ServerlessとRed Hat OpenShift Service Meshのインストールをする必要があります。各モデルが独自のモデルサーバーからデプロイされるため、多くのリソースを必要とする大規模なモデルに適しています。 マルチモデルサービング 小規模および中規模モデル用のプラットフォームです。ModelMeshコンポーネントをベースとしています。同じモデルサーバーに複数のモデルをデプロイできます。 マルチモデルサービング実例 今回はマルチモデルサービングの設定をして、APIのリクエストを送るところまで解説します。マルチモデルサービングの一般的な構成図は以下のようになります: マルチモデルサービングの構成図 モデルデプロイ OpenShiftAIの設定 前提条件 OpenShift AI:2.13 データサイエンスプロジェクト作成済み 以前の記事を参考にしてください( OpenShift AIを導入してみた ) データ接続設定済み 以前の記事を参考にしてください( OpenShift AIで機械学習をやってみた ) 前回の機械学習サンプルプログラム実行済み 以前の記事を参考にしてください( OpenShift AIで機械学習をやってみた ) 実行済みだとS3内にtest-demo/models/mnist_model_latest.onnxというファイルが作成されます。このONNXファイルをデプロイします。 今回デプロイするモデルデータ モデルのデプロイ方法 モデルのデプロイ方法を説明します。データサイエンスプロジェクト内のModelsの項目に移動します。 最初にモデルサーバーの設定を行います。Add model serverを押下して以下の項目を入力してください: Model server name:test-serving Serving runtime:OpenVINO Model Server Number of model server replicas to deploy:1 Model server size:small Accelerator: NVIDIA GPU(GPUがない場合None) Number of accelerators:1(GPUがある場合設定する) Make deployed models available through an external route: (APIを外部公開するかどうかの設定) Require token authentication: (認証トークンを利用するかどうかの設定。外部公開する場合必須。) Service account name:トークン名 モデルサーバー設定 以上を設定することでモデルサーバーを立ち上げることができます。また、Tokensの項目から認証トークンの値が確認できます。 モデルサーバー設定後画面 Tokensを押下すると、認証トークンのシークレットが確認できる deploy modelを押下することでモデルのデプロイ設定を行います: Model name:test-onnx Model framework(name – version):onnx-1 Existing data connection: Name:test-connection(設定したデータ接続名を選択) Path:test-demo/models/mnist_model_latest.onnx モデルデプロイ設定 設定後、statusが になればデプロイ完了です。エンドポイントが表示されるので、以降のAPIリクエストする手順で用いるためメモしておいてください。 モデルデプロイ設定後画面。ここからAPIエンドポイントを確認できる。 APIインターフェース情報 インターフェース情報は以下のようになります: 内部公開用エンドポイント gRPC用エンドポイント:grpc://modelmesh-serving.<プロジェクト名>:8033 rest用エンドポイント:http://modelmesh-serving.<プロジェクト名>:8008 外部公開エンドポイント:https://<モデル名>-<プロジェクト名>.apps.<クラスタードメイン>/v2/models/<モデル名>/infer リクエストヘッダー { "Content-Type": "application/json", "Authorization": "Bearer {トークンのシークレット}" } リクエストボディ { "model_name": {モデル名}, "inputs": [ { "name": {入力名}, "shape": {入力するデータの形}, "datatype": {入力するデータの型}, "data": {リクエストを送るデータの値} } ] } レスポンス {      "model_name": {モデル名},      "model_version": {モデルのバージョン},      "outputs": [           {                "name": {出力名},                "datatype": {出力するデータの型},                "shape": {出力するデータの形},                "data": {レスポンスとして返ってきた推論の値}           }      ] } APIリクエスト手順 前回 のMNISTの画像を識別するモデルを例にAPIリクエストを行います。 curlでAPI情報確認 APIリクエストを送る手順を説明します。以降に説明するコマンドやコードはOpenShift AIワークベンチのJupyterNotebookで実行することを想定します。 リクエストを送る前にcurlでAPI情報を確認します。エンドポイントの末尾/inferを削除したURLに対してcurlコマンドを実施します。 <token> の部分には実際の認証トークンの値を入れてください。 curl -ks https://test-onnx-test-ai.apps.<クラスタードメイン>/v2/models/test-onnx -H 'Authorization: Bearer <token>' | jq curlの結果が以下のようになります。結果からモデルAPIの情報を確認することができます。 {    "name": "test-onnx__isvc-045f6c46c3",    "versions": [       "1"    ],    "platform": "OpenVINO",    "inputs": [       {          "name": "input",          "datatype": "FP32",          "shape": [             "-1",             "1",             "28",             "28"          ]       }    ],    "outputs": [       {          "name": "output",          "datatype": "FP32",          "shape": [             "-1",             "10"          ]       }    ] } PythonコードでAPIリクエスト実行 実際にリクエストを送るPythonコードを以下に示します。 <クラスタードメイン> の部分にはクラスタードメインを入力してください。またはinfer_url変数にモデルAPI設定後に表示されてメモしたエンドポイントを入力してください。 <token> の部分には実際の認証トークンの値を入れてください。 また、APIリクエストに対する構成図は以下のようになります: PythonコードによるAPIリクエスト実行の構成図 import numpy as np import torchvision.transforms as transforms from torchvision.datasets import MNIST from torch.utils.data import DataLoader import matplotlib.pyplot as plt import requests def load_mnist_image(): transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,)) ]) mnist_dataset = MNIST(root='./data', train=False, download=True, transform=transform) dataloader = DataLoader(mnist_dataset, batch_size=5, shuffle=True) images, labels = next(iter(dataloader)) return images.numpy(), labels.numpy() def show_image(image): # 画像を表示 plt.imshow(image.squeeze(), cmap='gray') plt.title("MNIST Image") plt.show() deployed_model_name = "test-onnx" # クラスタードメインの値を入れる infer_endpoint = "https://test-onnx-test-ai.apps.<クラスタードメイン>" infer_url = f"{infer_endpoint}/v2/models/{deployed_model_name}/infer" # トークンの値を入れる token = " " def rest_request(data): # NumPy配列をリストに変換 data_list = data.flatten().tolist() headers = { "Content-Type": "application/json", "Authorization": f"Bearer {token}" } json_data = { "model_name": deployed_model_name, "inputs": [ { "name": "input", "shape": [1, 1, 28, 28], "datatype": "FP32", "data": data_list } ] } response = requests.post(infer_url, headers=headers, json=json_data, verify=True) response.raise_for_status() # HTTPエラーが発生した場合に例外をスロー response_dict = response.json() return response_dict['outputs'][0]['data'] # MNISTデータセットから画像を読み込む data, label = load_mnist_image() for i in range(5): # 画像を表示 show_image(data[i]) # RESTAPIリクエストの送信 result = rest_request(data[i]) predicted_label = np.argmax(result) print("Inference result:", result) print("Predicted label:", predicted_label) print("Actual label:", label[i]) 実行した結果が以下になります。MNIST Imageという画像はAPIにリクエストとして送った画像になります。Inference resultが実際にAPIからレスポンスとして返ってきた結果です。10個の値は画像が0~9のどの数字に該当するかスコアを示しています。例えば0番目の値が最も高い値になっていれば、モデルAPIはリクエストとして受け取った画像を0の可能性が一番高いと推論を行ったことを示しています。Predicted labelはInference resultの中で最も高いスコアの数字です。すなわちモデルAPIがリクエストとして受け取った画像がどの数字であるかを推論したか示しています。Actual labelはリクエストとして送った画像が実際にはどの数字なのかを示しています。Predicted labelとActual labelが一致していればモデルAPIが正しい推論ができていることを示しています。 モデルAPIの推論結果 最後に 以上の手順によりOpenShift AIのモデルサービング設定を行い、推論APIを利用することができました。このようにモデルサービング機能を活用することで、簡単にモデルAPIを提供することが可能になります。このモデルサービング機能をぜひAIアプリケーション開発に役立ててください。 次回はパイプライン機能の解説を行う予定なので、そちらもよろしくお願いします。 参考 モデルサービング設定: https://docs.redhat.com/ja/documentation/red_hat_openshift_ai_self-managed/2.13/html/serving_models/index OpenShift AIチュートリアル不正検出の例: https://docs.redhat.com/ja/documentation/red_hat_openshift_ai_self-managed/2.13/html/openshift_ai_tutorial_-_fraud_detection_example/deploying-and-testing-a-model 前回: OpenShift AIで機械学習をやってみた   ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post OpenShift AIのモデルサービング機能について first appeared on SIOS Tech. Lab .
アバター
ども!年末の追い込みが激しくどかどか働いている龍ちゃんです。寒すぎて暖房で過ごしていますが、電気代におびえています。 皆さん、 React 19のドキュメント は確認しましたか?12/5についに React 19がstableになりました 。僕はお恥ずかしながら、Next.jsの検証環境を作っていた時にNext15がStableになっていることで気づきました。Stableになったので、そろそろ学ぼうということで新しいHookを学んでいこうと思います。 今回の内容は、「新しいHookである、useActionStateを使ってTypescriptで入力フォームを作る」という内容になります。極力Typescriptで型を付けた状態で紹介していきます。 useActionStateについて確認 まずは、基本の使い方についてまとめていきます。いろいろと利用シーンがあると思います。ざっくりとuseActionStateのうれしいところは以下の点です。 useActionState内で非同期処理の状態を取得することができる ライブラリを使用せずにReactのみでフォームの管理が楽になった ここでは二つの例を紹介していきます。二つの例の違いとしては、Formの入力値の使用の有無になります。 どちらの使い方でも共通しているのは、useStateと同じようにStateを保存することができます。イメージとしては、asyncの処理を連携したState更新処理をForm(入力)とセットで管理することができるHookとなります。 Formの値を使用しないuseActionState 例として、カウントアップを作成します。こちらの内容は、Reactの公式ドキュメントにも記載されています。 useActionStateで 設定がマストな引数 は2つになります。第一引数には action 関数、第二引数には初期値を渡します。 action 関数では、初回の実行時には初期値が渡り、それ以降は前回のaction関数で返答された値が返答されます。型付け行った場合は、 action 関数の戻り値は型と一致する必要があります。 import { useActionState } from "react"; export const FormTest1 = () => { const [count, countAction, isCountPending] = useActionState<number>( async (prevCount: number) => { await new Promise((res) => setTimeout(res, 1000)); console.log(prevCount); return prevCount + 1; }, 0 ); return ( <> <form action={countAction}> <button type="submit" disabled={isCountPending}> カウントアップ </button> <p>{count}</p> </form> </> ); }; 今回のaction関数はuseActionStateの機能を試すために、処理を2秒止めています。useActionStateからの返り値は3つです。 count:Stateの値 初回では初期値が、実行後はaction関数によって更新された値が挿入 countAction:action関数の実行トリガー isCountPending:action実行状態を取得 useActionStateの素晴らしい点としては、ソース中の isCountPending にあります。これまで、useStateやuseRefを組み合わせて作成していた。loading表示などもこちらを使用することで一つにまとめることができます。 Formの値を使用するuseActionState 例としては、簡易的なバリデーションがついたフォームとなります。実用性はありませんが、useActionStateの挙動を理解する手助けと、Typescriptでの型検証には有用だと思います。 フォームの入力情報を受け取る場合は、action関数の第二引数に情報が飛んできます。Stateとしては、 Error | null の状態を持つことで、バリデーションの有無を表現しています。 import { useActionState } from "react"; export const FormTest1 = () => { const [error, action, isPending] = useActionState<Error | null, FormData>( async (prevError: Error | null, formData: FormData) => { console.log(prevError); // 値の取得方法法 const data = Object.fromEntries(formData.entries()); console.log(data); // APIの処理などを行ってResultによって処理を分岐させる // returnを返せばエラー発生とする const error = new Error("Failed to submit data"); if (error) { return error; } return null; }, null ); return ( <> <form action={action}> <input type="text" name="name" /> <button type="submit" disabled={isPending}> 送信 </button> {error && <p>{error.message}</p>} </form> </> ); }; この例で確認できる内容としては以下になります。 useActionStateで送信されるForm情報の構造化 State設定の自由度がそれなりにある useActionStateで入力フォームを作成する 2つの例でuseActionStateの挙動については理解できたと仮定して、実際利用するフォームの作成を進めていきます。 作成するフォームの情報をまとめます。 名前:String・年齢:number バリデーション 名前:空文字禁止・10文字以内 年齢:0以上 バリデーション通過後、API通信をするイメージ(今回は2秒後エラー) ソースコードの全体を先に置いておきます。 import { useActionState } from "react"; type FormType = { name: string; age: number; }; type PrevFormDataType = { value: FormType; validationError: { name: Error | null; age: Error | null }; apiError: Error | null; }; const validationName = (name: string) => { if (name === "") { return new Error("名前を入力してください"); } else if (name.length > 10) { return new Error("名前は10文字以内で入力してください"); } return null; }; const validationAge = (age: number) => { if (age <= 0) { return new Error("年齢は0以上で入力してください"); } return null; }; export const FormTest3 = () => { const initialFormData: PrevFormDataType = { value: { name: "", age: 0 }, validationError: { name: null, age: null }, apiError: null, }; const [formData, action, isPending] = useActionState< PrevFormDataType, FormData >(async (_: PrevFormDataType, formData: FormData) => { // FormDataをobjectに変換 const _formData = Object.fromEntries(formData.entries()); const data: FormType = { name: _formData.name as string, age: Number(_formData.age), }; // validationを掛ける いい感じのライブラリがあれば参考にする const nameError = validationName(data.name); const ageError = validationAge(data.age); if (nameError || ageError) { return { value: { name: data.name, age: data.age }, validationError: { name: nameError, age: ageError, }, apiError: null, }; } // ここでAPI処理を実装・今回は2秒待ってエラーを返す await new Promise((res) => setTimeout(res, 2000)); const apiError = new Error("Failed to submit data"); return { value: { name: data.name, age: data.age }, validationError: { name: nameError, age: ageError, }, apiError: apiError, }; }, initialFormData); return ( <> <form action={action} className="flex w-full max-w-xl flex-col gap-2 rounded-md p-4 shadow" > <label className="flex flex-col"> <div className="flex flex-row text-xl"> <span className="w-1/3">名前:</span> <input className="w-full border p-1 text-right" type="text" name="name" defaultValue={formData.value.name} /> </div> <span className="h-4 text-xs text-red-500"> {formData.validationError.name && ( <>{formData.validationError.name.message}</> )} </span> </label> <label className="flex flex-col"> <div className="flex flex-row text-xl"> <span className="w-1/3">年齢:</span> <input className="w-full border p-1 text-right" type="number" name="age" defaultValue={formData.value.age} /> </div> <span className="h-4 text-xs text-red-500"> {formData.validationError.age && ( <>{formData.validationError.age.message}</> )} </span> </label> <button className={ "w-full rounded-md py-4 text-lg text-white" + (isPending ? " bg-gray-400" : " bg-blue-500") } type="submit" formAction={action} disabled={isPending} > 送信{isPending && "中"} </button> <span className="h-4 text-xs text-red-500"> {formData.apiError && <p>{formData.apiError.message}</p>} </span> </form> </> ); }; Stateの型定義 useActionStateでaction関数実行後は、Formの入力値はリセットが掛かってしまいます。フォームのバリデーション評価の間は値を継続させたいので、Stateの定義としてはFormの入力値・バリデーションエラー・apiエラーの三つを取得できるオブジェクトとして定義しておきます。 // Formのタイプ type FormType = { name: string; age: number; }; // Stateの型定義 type PrevFormDataType = { value: FormType; validationError: { name: Error | null; age: Error | null }; apiError: Error | null; }; バリデーション 将来的にはライブラリを使って運用を進めていきたいのですが、ここでは簡易的に自作したバリデーションを使用します。 名前のバリデーション const validationName = (name: string) => { if (name === "") { return new Error("名前を入力してください"); } else if (name.length > 10) { return new Error("名前は10文字以内で入力してください"); } return null; }; 年齢のバリデーション const validationAge = (age: number) => { if (age <= 0) { return new Error("年齢は0以上で入力してください"); } return null; }; バリデーション関数としては、型定義と合わせて Error | null を戻り値として設定しています。 useActionStateの実装 初期化の値を別途定義しています。初期状態では、各種エラーは null を入れておきます。フォームの値も初期値を設定します。 const initialFormData: PrevFormDataType = { value: { name: "", age: 0 }, validationError: { name: null, age: null }, apiError: null, }; const [formData, action, isPending] = useActionState< PrevFormDataType, FormData >(async (_: PrevFormDataType, formData: FormData) => { // FormDataをobjectに変換 const _formData = Object.fromEntries(formData.entries()); const data: FormType = { name: _formData.name as string, age: Number(_formData.age), }; // validationを掛ける いい感じのライブラリがあれば参考にする const nameError = validationName(data.name); const ageError = validationAge(data.age); if (nameError || ageError) { return { value: { name: data.name, age: data.age }, validationError: { name: nameError, age: ageError, }, apiError: null, }; } // ここでAPI処理を実装・今回は2秒待ってエラーを返す await new Promise((res) => setTimeout(res, 2000)); const apiError = new Error("Failed to submit data"); return { value: { name: data.name, age: data.age }, validationError: { name: nameError, age: ageError, }, apiError: apiError, }; }, initialFormData); action 関数の中身としては、以下のような流れになっています。 formDataの積み替え → FormTypeの情報へ変換 バリデーションチェック・早期リターンでバリデーションエラー表示 API通信 今回は、検証の意味を込めてAPIエラーも用意しています。ここは使用用途によって、ErrorBoundaryでキャッチする仕様でも問題ないかと思います。 終わり 今回は、useActionStateをTypescriptで型付けしながら入力フォームの実装をしてみました。新しい機能が出ても、Stableまで手を出さないというのは、良いことなのか悪いことなのかわかりませんね。きっと、技術選定でリジェクトされた思い出が強く残っているのだと思います。 useActionState以外にも便利そうなHooksが追加されていたので、React 19とNext 15で色々作ってみるのも楽しそうですね。ふんわりと年末に入りますが、一旦はメリークリスマス! ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post React 19でuseActionStateで入力フォーム【Typescript】 first appeared on SIOS Tech. Lab .
アバター
こんにちは。サイオステクノロジーの和田拓也です。今回はAzure OpenAIを使って音声認識アプリを作ってみたので、作成手順や使用感を書いていきたいと思います。 前提条件 今回はPythonのStreamlitを使ってブラウザのマイクからインプットした音声をAIを使って文字お越ししていきます。StreamlitはPythonでWebアプリケーションを簡単に作ることができるフレームワークです。ここからはStreamlitが動く環境があることを前提に話を進めていきます。 Azure OpenAIモデル作成 まず初めにAzurePortalにアクセスして、リソースを作成します。MarketplaceでAzure OpenAIと検索して、リソース作成画面に飛びます。 作成をクリックすると、リソースの作成画面に飛びます。必要な項目を入力してリソースを作成します。今回はEast US 2をリージョンとして作成しました。 リソースの作成が終わったら、概要の上のほうにGo to Azure AI Foundry portalというボタンがあるのでクリックします。すると以下のようなページに移動します。   左側のメニューからデプロイをクリックします。すると、モデルのデプロイが行える画面が表示されます。モデルのデプロイをクリックして、基本モデルをデプロイするを選択します。   このような画面が表示されます。今回は音声認識のモデルを利用したいので、音声認識で絞り込みます。whisperというモデルのみが使えるみたいなので、今回はこちらを使用していきます。 モデルを作成し終わったら、左のメニューからホームをクリックして、表示されているエンドポイントとAPIキーをメモしておきます。 ソースコード実装 続いてソースコードのほうを実装していきます。Pythonを用いて以下のソースコードで動かしていきます。 main.py import streamlit as st from audio_recorder_streamlit import audio_recorder import tempfile from openai import AzureOpenAI endpoint = "メモしたエンドポイント" key = "メモしたAPIキー" version = "2024-10-01-preview" deployment_id = "whisper" client = AzureOpenAI( api_key=key, api_version=version, azure_endpoint = endpoint ) def transcribe_audio_to_text(audio_bytes): with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as temp_audio_file: temp_audio_file.write(audio_bytes) temp_audio_file_path = temp_audio_file.name result = client.audio.transcriptions.create( file=open(temp_audio_file_path, "rb"), model=deployment_id ) return result.text st.title("Voice to Text Transcription") # Streamlitウィジェットを使用して音声を録音 audio_bytes = audio_recorder(pause_threshold=30) # 録音した音声を再生 if audio_bytes: st.audio(audio_bytes, format='audio/wav') # OpenAI Whisper APIを使用して音声をテキストに変換 if audio_bytes: transcript = transcribe_audio_to_text(audio_bytes) st.write(transcript) これで一通り動く準備ができたので、実際に動作を確認していきたいと思います。 動作確認 Streamlitで立ち上げたブラウザにアクセスすると、以下のような画面が表示されます。 マイクのボタンをクリックして音声を録音します。すると、録音した音声を再生するボタンと、Azure OpenAIを使って文字お越しされたテキストが表示されます。   まとめ 今回は、Azure OpenAIの音声認識を使って音声認識アプリを作ってみました。使ってみた感想としては、音声認識の精度はかなり良い印象でした。しかし、無音の状態だとハルシネーションを起こすことがあったので、リアルタイムで音声認識させたい場合はすこし工夫が必要だと感じました。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Azure OpenAIの音声認識試してみた first appeared on SIOS Tech. Lab .
アバター
はじめに 皆さんこんにちは!エンジニアの細川です。 今月はサイオステクノロジーのアドベントカレンダー、テーマは「サイオス社員が今年一年で新たに学んだ技術」です! 今月2回目の執筆ですが、今回はJavaScriptなどの開発に使える高速なテスト用パッケージVitestを紹介します! Vitestとは 既にかなり話題になっているのでご存知の方も多いかもしれませんが、VitestはJavaScriptやTypeScriptの開発で利用可能なTest用のパッケージです。 もっとも有名なものはJestかと思いますが、VitestはJestとほとんど同じ機能を提供しており、移行もしやすいためVitestに移行している方も多いそうです。 Vitestのメリット 非常に高速 VitestはJestに比べて非常に高速に動作します。依存関係を事前に解決しておくなどの処理で早くなるそうです。解決しなければならない依存関係によって変わると思いますが、NestJSのserviceの単体テストを回した場合、体感で3-5倍程度早くなったので初めて導入した時は驚きました。 Jestからの移行が簡単 describe や it , expect など、Jestで提供されている機能の多くが提供されており、移行がかなり簡単かと思います。 BuildツールでViteを利用していなくても利用可能 VitestはViteでbuildをすることで高速化しているようですが、プロジェクトのbuildツールでViteを採用していなくても利用することができます。buildツールを後から変更するのはいろいろ怖い部分もあるかと思うので、buildツールを変えなくてもいいというのもメリットかなと思います。 ESMOnlyのパッケージを利用できる NestJSはcommonJSを前提としているので、あまり意識しないかもしれませんが、JestもNestJS同様commonJSを前提に動作しています。そのため、ESMOnlyのパッケージなどを利用する場合、別に設定をする必要がありました。しかしVitestではESMにも対応しているため、ESMOnlyのパッケージもそのまま利用できます。NestJSを使っていてもESMOnlyのパッケージを利用する場合もあるかと思うのでそのような場合はぜひVitestへの移行をお勧めします。(NestJSでESMOnlyパッケージを使う方法については こちら で解説しています。) Vitestのデメリット Vitestのデメリットとしては、既にJestで大量のテストを記述済みの場合などに完全に書き換えずに移行ができないという点です。 詳細は こちら のドキュメントを確認していただきたいのですが、mockの書き方や名前空間の有無など一部書き方が異なるため移行するにはそれらを書き換える必要があります。 思いつくデメリットとしてはこれくらいなので、許容できるプロジェクトではぜひ導入を検討してみてください。 前提の環境 今回のパッケージなどのバージョンは以下になります パッケージ バージョン Node.js 22.11.0 NestJS 10.0.0 Vitest 2.1.3 導入方法(NestJSの場合) Vitestの導入方法を紹介します。今回はNestJSの場合ですが、他の場合でも手順はそんなに変わらないかなと思います。 Jestの削除 NestJSはデフォルトでJestがインストールされていると思いますので、Jestの削除をしておくことをお勧めします。 デフォルトの場合、testディレクトリにe2eテスト用のconfigファイル jest-e2e.json ができていると思いますので、削除しておきます。 また、以下のコマンドでパッケージも削除しておきましょう npm uninstall -D jest @types/jest ts-jest Vitest導入 まずは以下のコマンドでパッケージのインストールを行います。 npm i --save-dev vitest unplugin-swc @swc/core @vitest/coverage-v8 その後 vitest.config.mts を作成します。 import { resolve } from "node:path"; import swc from 'unplugin-swc'; import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { globals: true, root: './', include: ["src/**/*.spec.ts"], exclude: ["node_modules", "dist"], coverage: { reporter: ["text", "json", "html"], reportsDirectory: resolve(dirname, "../coverage"), include: ["**/*.(t|j)s"], }, }, plugins: [ // This is required to build the test files with SWC swc.vite(), ], }); NestJSは基本的にcommonJSのはずですが、こちらのconfigファイルはESMの形式で書かれているので、拡張子を .ts ではなく、 .mts にしている点に注意してください。 また、 vitest.config.e2e.mts も作成しておきます。 import swc from 'unplugin-swc'; import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { include: ['**/*.e2e-spec.ts'], globals: true, root: './', }, plugins: [swc.vite()], }); 続いて、 package.json にテスト用のスクリプトを設定します。 "vitest:common": "vitest --config ./vitest.config.mts", "vitest:e2e": "vitest run --config ./vitest.config.e2e.mts", "test": "npm run vitest:common run", "test:watch": "npm run vitest:common", "test:cov": "npm run vitest:common -- --coverage", "test:e2e": "npm run vitest:e2e", あとは npm run test を叩くだけでテストを実行できます。 もちろん以下のようにファイル名を指定すれば一つだけ実行することなども可能です。 npm run test src/app.controller.spec.ts configファイルなどの設定は皆さんのプロジェクトに合わせて読み変えてください。 まとめ Vitestは非常に高速! Jestから簡単に移行できる 一部書き方を変える必要あり Viteを使ってなくても利用可能 ESMOnlyパッケージも利用できる おわりに 今回はVitestの導入方法について紹介しました! Vitestにはたくさんメリットがありますので、ぜひ皆さんのプロジェクトでも導入を検討してみてください! 今月はサイオステクノロジーのアドベントカレンダーで他にもたくさん記事が出ますのでぜひ読んでみてください!!(URLは こちら ) 今回参考にさせていただいた記事 https://devlog.mescius.jp/vitest-quickstart/ https://zenn.dev/ot_offcial/articles/6933b5e8be3091 https://vitest.dev/guide/ ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post NestJSでJestからVitestに移行してみた first appeared on SIOS Tech. Lab .
アバター
はじめに こんにちは!11月は登壇2本に講師対応と忙しかったですが、今月は社内で導入を検討しているシステムの調査をしているなーがです。前回から少し時間が空いてしまいましたが、今回はアドベントカレンダー21日目として、Azure DevOpsのCDパイプラインでデプロイ時に発生したエラーを解決した方法について書こうと思います。 とある先日のこと 先輩があるシステムでデプロイを行った際にエラーが発生したので調査を依頼されました。そのシステムはAzure上にデプロイされており、ソースコードはAzure DevOpsで管理されているためAzure PipelinesのCDパイプライン(Releases)のログを確認しました。すると、下記のようなエラーが確認できました。 Unsupported authentication scheme ‘WorkloadIdentityFederation’ for Azure endpoint. Azure エンドポイントでサポートされていない認証スキーム ‘WorkloadIdentityFederation’ があります。 そのため、AzureとAzure Pipelinesの接続設定である Service connections の該当リソースからManage App registrationをクリックし、サービスプリンシパルを確認しました。 すると、クライアントシークレットの有効期限が切れていました。 調査結果を先輩に報告したところ、先程エラーとなっていたCDパイプライン内のタスク「AzureBlob File Copy」がバージョン3であることからクライアントシークレットを使う必要があり、その有効期限が切れていたためデプロイが失敗していると判明しました。 現在では「AzureBlob File Copy」のバージョンは6まで出ており、  ワークロード ID フェデレーション を使用するサービス接続も サポートされる ようになっています。 そのため、先輩に  ワークロード ID フェデレーション への切り替えとCDパイプラインの実行をしてもらったところ、無事にデプロイが成功しました。 めでたしめでたし… と思ったのも束の間! デプロイしたアプリケーションにアクセスしてみると、CSSが適用されていませんでした… ここからが本題です! CDNに対してデプロイしたファイルが、どれも404エラーでアプリから読み込めなくなっていました。そこでAzureのCDNリソースを確認してみると、cdnというフォルダが作成されてその中にアップロードされていたためでした。 これはCIパイプラインでビルド成果物の公開名(Artifact name)で cdn とし、CDパイプラインのソースで以下のように参照していたためです。 CIパイプライン CDパイプライン 「AzureBlob File Copy」のバージョンが3の時は問題なくデプロイされてCSSも適切に適用されていました。そこで、AzureFileCopyに関する MSの公式ドキュメント や リポジトリの変更履歴 、 Issue を見ても解決方法が分かりませんでした。(ご存じの方はコメントで教えて頂けると助かります!) どうするか ダメもとで、CDパイプラインのソースで以下のように設定してみたところ、デプロイが成功し、無事にCSSも適用されていました。 さいごに 今回はAzure DevOpsのCDパイプラインでデプロイ時に発生したエラーを解決した方法について書きました。公式に記載がないため根拠があるわけではありませんが、同様の現象で困っている方の参考になれば幸いです。今後も業務で学んだことをブログにしていきたいと思います。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Azure Pipelinesのタスク「AzureBlob File Copy」をバージョンアップした際にハマった話 first appeared on SIOS Tech. Lab .
アバター
サーバーレスアーキテクチャを採用することで、開発者はトラフィックやスケーリングなどのインフラストラクチャに関する作業を気にすることなく、コスト削減やパフォーマンス向上を実現し、アプリケーション開発に集中することが可能です。 OpenShift 環境では、Red Hat OpenShift Serverless を導入することでサーバーレスアーキテクチャを実現でき、以前の記事で紹介した OpenShift Pipelines や OpenShift GitOps と組み合わせることで、CI/CD パイプラインを通じたサーバーレスアプリケーションのデプロイもスムーズに行えます。 本記事では Red Hat が提供する OpenShift Serverless と、そのベースとなっている Knative について簡単に概要をつかめるようにまとめていきます。 OpenShift Serverless とは? OpenShift Serverless は、OpenShift クラスタ上でサーバーレスのアプリケーションを実行させるサービスです。OSS の Knative プロジェクトをベースとしています。通常、アプリを動かすにはサーバーの設定やメンテナンスが必要ですが、OpenShift Serverless を使うと、それらを気にせずにサービスを提供できます。必要な時にだけ Pod を立ち上げるため、リソースの節約にもつながります。 OpenShift Serverless のメリット アプリケーションのデプロイメントやスケーリングを自動で行い、サーバーの管理に関する手間を省くことができます。 イベントをトリガーとしてアプリケーションを実行させることが可能で、リアルタイムデータ処理などのイベントベースのアプリケーションを容易に構築できます。 アプリケーションのトラフィックに応じてリソースを自動的にスケールアップ・ダウンするため、パフォーマンスを最適化し、リソースの無駄遣いを防ぐことができます。 OpenShift Serverless のコンポーネント OpenShift Serverless には主に以下のコンポーネントがあります。以前は Knative Build もありましたが、現在(執筆時点のバージョン 1.34.1)は CI/CD の OpenShift Pipelines に移行されています。 Knative Serving アプリケーションのデプロイメント、オートスケーリング(自動でスケールアップやスケールダウンを行う)、トラフィック管理を担当します。リクエストに応じてコンテナを起動し、不要になれば停止することでリソースの節約を図ることができます。リビジョン管理も可能で、バージョン管理を容易にし、ブルー/グリーンデプロイメントやカナリアリリースなどのデプロイメント戦略もとることができます。 Knative Eventing イベント駆動型アーキテクチャを実現するためのコンポーネントで、様々なイベントソース(Event Producer)からのイベントを受け取り、それを CloudEvents 仕様へ成形してサービス(Event Consumer)に渡します。CloudEvents 仕様とは、イベントデータの標準化を目的とした CNCF のプロジェクトで、イベントの形式やプロトコルを統一して、異なるシステム間でのイベントの受け渡しを容易にします。Knative Eventing はこの仕様に準拠し、イベントのルーティングやフィルタリング、変換を行うことができます。定期的なイベントであったり、Kafka の Topic メッセージ、GitHub からの Webhook などをイベントソースとして利用することができます。 ユースケース イベント駆動型アプリケーション Knative Eventing を利用することで、開発者はイベントソースからのイベントを受け取り、それに応じてサービスをトリガーすることができます。これにより、リアルタイムでのデータ処理や、ユーザーの行動に応じた動的なレスポンスを実現することが可能になります。 API やマイクロサービスの構築 Knative Serving を使用して、トラフィックに基づいて自動的にスケールする API やマイクロサービスを作成できます。アプリケーションは必要に応じてリソースを確保し、使用していないときはリソースを解放します。 類似サービス AWS Lambda Amazon Web Services が提供するサーバーレスコンピューティングサービスです。Kubernetes とは異なり、AWS の独自のインフラストラクチャ上で動作します。OpenShift Serverless と比較すると、プログラミング言語のサポートやオートスケールの機能に関しては類似していますが、管理が OpenShift か AWS といった点が大きな違いになります。そのため、OpenShift Serverless(Knative)は特定のクラウドプロバイダーにロックインされるリスクを軽減することができます。 Kubeless、Fission Kubeless と Fission はどちらも Kubernetes 上で軽量に動作するオープンソースのサーバレスフレームワークです。OpenShift Serverless と比較すると、こちらも管理が OpenShift か Kubernetes といった点が違いにはなりますが、OpenShift Serverless のベースとなっているKnative は同じ Kubernetes 上で動作します。Fission と Kubeless もオートスケールはサポートしていますが、ゼロスケールはサポートしていない点も違いになります。Fission と Kubeless は、よりシンプルで軽量なフレームワークを求める場合などの要件に適しています。 まとめ OpenShift Serverless( Knative)について簡単にまとめてみました。OpenShift Serverless を実際に構築してみる記事も投稿する予定なのでそちらも読んでみてください。 参考文献 https://www.redhat.com/ja/technologies/cloud-computing/openshift/serverless https://www.scsk.jp/sp/openshift/developer5.html https://docs.openshift.com/serverless/1.34/about/about-serverless.html https://www.redhat.com/ja/blog/introducing-using-openshift-serverless-event-driven-applications?channel=blog/channel/red-hat-openshift&page=3 https://rheb.hatenablog.com/entry/2021/12/14/%E3%81%82%E3%82%89%E3%81%9F%E3%82%81%E3%81%A6Knative%E5%85%A5%E9%96%80%EF%BC%81%EF%BC%88Knative_Serving%E3%82%84%E3%82%84%E7%99%BA%E5%B1%95%E7%B7%A8%EF%BC%89 https://www.densify.com/openshift-tutorial/openshift-serverless/ ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Red Hat OpenShift Serverlessとは? first appeared on SIOS Tech. Lab .
アバター
PS/SLの佐々木です。 アドベントカレンダー19日目です。 今回は2年ほど続けてきた輪読会の取り組みについて紹介します。 輪読会の目的 輪読会の開催目的には以下のようなものがあります。 エンジニアの基礎レベルの底上げ 書籍による体系的な知識の取得 共通言語を用いたコミュニケーションが取れるようにする 学習習慣、学習文化の形成 特に学習文化の形成という点に関しては継続的、自律的に組織としての技術レベルを向上させるために非常に重要だと考えています。 今までの取扱書籍 Unit Testing ドメイン駆動設計入門 ボトムアップでわかる!ドメイン駆動設計の基本 フロントエンド開発入門 プロフェッショナルな開発ツールと設計・実装 OAuth, OAuth認証、OpenID Connectの違いを整理して理解できる本 今日から始める情報設計 リーダブルコード 雰囲気でOAuth2.0を使っているエンジニアがOAuth2.0を理解して、手を動かしながら学べる本 今更聞けない暗号技術&認証・認可 達人に学ぶDB設計 活動内容 活動は週1日の夕方に行っています。 参加メンバーは若手中心で若手の中で課題図書の担当の発表を行いそこに、先輩エンジニアにも入ってもらい議論に参加していただいたり、技術的なアドバイスをいただいたりしています。 発表資料は綺麗に作るのは大変なのでnotionにまとめてもらい、画面共有しながら発表しています。 また技術書を読む際に理解ができないものや、内容が抽象的すぎて解釈が色々できてしまうものに関しては発表の段階で自分で頑張って調べて結論をだすのではなく、発表の時にその部分をみんなで議論するという進め方をして参加のハードルをなるべく下げるようにして運用してます。( 大学のゼミみないなのは結構辛いですよね。。) 効果 1. エンジニアの基礎スキルの向上 輪読会を通じて体系的な知識を習得することができ、エンジニアとしての基礎スキルが着実に向上します。特に書籍を活用することで、断片的な情報ではなく、基礎から応用まで一貫性のある内容を学べるため、業務に直結するスキルを効果的に強化することができたと思います 2. 共通言語の形成による円滑なコミュニケーション 同じ書籍を通じて学習することで、用語や概念に関する共通の理解が生まれ、コミュニケーションがスムーズになっていくと思います。またメンバー間で技術的な考え方やアプローチについて議論することで、より深い理解と協調が生まれ、実務でも技術的な議論がしやすくなると考えています。 3. 学習文化・習慣の定着 輪読会は単発の学習活動ではなく、週ごとに定期的に開催されることで、継続的な学習の基盤を築いています。これにより、組織全体に学び続ける文化が根付くと同時に、若手エンジニアが自ら主体的に学ぼうとする姿勢が自然と養われます。また、輪読会では、抽象的で難解なテーマについても個人で結論を出す必要はなく、みんなで議論しながら理解を深めるスタイルを取っており、初心者にとっても学びやすい環境を提供できていると考えています。 4. 心理的安全性の向上 情報を取りまとめて人と前で発表する経験が積めるとともにディスカッションを行っており、経験の浅い若手エンジニアでも安心して発言や質問ができる場が提供できています。 このような場でコミュニケーションをとることにより実務でもコミュニケーションがとりやすくなったりと、技術力向上以外の面においても組織の成長に貢献できる取り組みになっていると思います。 まとめ 今回はPS/SLで行っている輪読会の取り組みと2年間運用してきた効果をまとめてみました。 わかりやすく技術力向上という面以外にも様々なメリットがあり、この輪読会きっかけて課題図書以外の技術的な議論も盛んになっていくと面白い会になるなと思っています。 輪読会の中で実際にペアプロをして動かしてみたりするのも面白そうだなと思っているので会の中で他の試作も取り入れてみようと思います。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post SIOS輪読会の取り組み first appeared on SIOS Tech. Lab .
アバター
こんにちは! 今月も「OSSのサポートエンジニアが気になった!OSSの最新ニュース」をお届けします。 FINOS が Linux Foundation Research と協力して、業界の最新動向を調査したレポート「金融サービスにおけるオープンソースの現状 – 2024」を公開しました。 FINOS & LF Research 調査レポート「金融サービスにおけるオープンソースの現状 – 2024」を公開 https://prtimes.jp/main/html/rd/p/000000329.000042042.html 2024/12/16、LPI-Japan は無償でダウンロード可能な「Linux標準教科書 バージョン4.0.0」をリリースしました。 LPI-Japan、無償教材「Linux標準教科書」の最新版をリリース https://japan.zdnet.com/article/35227352/ NTT コミュニケーションズがサーバ攻撃対策として準備した内容、一連の被害体験で得た教訓までを公表しました。 NTTコムが「サイバー攻撃の被害」公表前にした準備 顧客を傷つけず、社内の混乱を抑えた方策とは https://news.yahoo.co.jp/articles/422c9a380b7a4449909948ee60aafa80b1fc4295 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 【2024年12月】OSSサポートエンジニアが気になった!OSS最新ニュース first appeared on SIOS Tech. Lab .
アバター
今号は、前号の「 パッケージマネージャについて 」の続きになります! 今回は Debian 系システムの apt で、以前紹介できなかったサブコマンドについてご紹介します。 apt の便利なサブコマンド パッケージの情報を表示 apt-cache show コマンドを実行すると、特定のパッケージの詳細な情報を表示します。 例えば、git というパッケージの情報を表示する場合は、下記の様なコマンドになります。 # apt-cache show git … Package: git Architecture: amd64 Version: 1:2.34.1-1ubuntu1.6 Multi-Arch: foreign Priority: optional Section: vcs Origin: Ubuntu Maintainer: Ubuntu Developers original-Maintainer: Jonathan Nieder Bugs: https://bugs.launchpad.net/ubuntu/+filebug Installed-Size: 18484 Provides: git-completion, git-core Depends: libc6 (>= 2.34), libcurl3-gnutls (>= 7.56.1), libexpat1 (>= 2.0.1), libpcre2-8-0 (>= 10.34), zlib1g (>= 1:1.2.0), perl, liberror-perl, git-man ( = 1:2.34.1-.) Recommends: ca-certificates, patch, less, ssh-client Suggests: gettext-base, git-daemon-run | git-daemon-sysvinit, git-doc, git-email, git-gui, gitk, gitweb, git-cvs, git-mediawiki, git-svn … (長いため省略) この時、結果には アーキテクチャ、パッケージバージョン、ライセンス情報、依存パッケージ (Depends) の情報など 、様々な情報が表示されます。 なお、上記のコマンドはネットワーク上のリポジトリから情報を取得してくるため、 対象のパッケージがインストールされていなくても情報が表示されます。 パッケージの依存関係を表示 apt-cache depends コマンドを実行すると、特定のパッケージの依存関係を表示します。 例えば、git というパッケージと依存関係のあるパッケージ一覧を表示する場合は、下記の様なコマンドになります。 依存関係の情報は apt-cache show でも確認できますが、 apt-cache depends の方が整理された状態で、より分かりやすく表示されます。 # apt-cache depends git Depends: libc6 Depends: libcurl3-gnutls Depends: libexpat1 Depends: libpcre2-8-0 Depends: zlib1g Depends: perl Depends: liberror-perl Depends: git-man Depends: git-man Recommends: ca-certificates Recommends: patch patch:i386 Recommends: less less:i386 Recommends: openssh-client openssh-client:i386 Suggests: gettext-base gettext-base:i386 Suggests: git-daemon-run Suggests: git-daemon-sysvinit Suggests: git-doc Suggests: git-email Suggests: git-gui Suggests: gitk Suggests: gitweb Suggests: git-cvs Suggests: git-mediawiki Suggests: git-svn この時、結果には Depends、Recommends、Suggests という 3種類の情報が表示されます。 ・Depends:対象のパッケージが動作するために必須となる、依存パッケージ ・Recommends:依存パッケージではないが、インストールが推奨されるパッケージ ・Suggests:依存パッケージではないが、あると便利な機能を提供するパッケージ パッケージをインストールする際、デフォルトの動作では Depends、Recommends のパッケージがインストールされます。 ただし、 –no-install-recommends オプションを指定した場合 Recommends はインストールされず、Depends のパッケージのみがインストールされます。 # apt-get install --no-install-recommends git パッケージのリストを表示 apt list コマンドを実行すると、特定の条件に合致するパッケージのリストを表示します。 例えば、git という文字列から始まるパッケージのリスト (一覧) を表示する場合は、下記の様なコマンドになります。 # apt list git* … git-absorb/jammy 0.6.6-2build2 amd64 [installed] git-all/jammy-updates,jammy-updates,jammy-security,jammy-security, 1:2.34.1-1ubuntu1.11 all git-annex-remote-rclone/jammy,jammy 0.6-1 all git-annex/jammy 8.20210223-2ubuntu2 amd64 git-autofixup/jammy,jammy 0.003001-2 all git-big-picture/jammy,jammy 1.1.1-1 all git-build-recipe/jammy,jammy 0.3.6 all git-buildpackage-rpm/jammy,jammy 0.9.25 all git-buildpackage/jammy,jammy 0.9.25 all git-bump/jammy,jammy 1.1.0-2 all … (長いため省略) 上記は、 ご利用環境で有効になっているリポジトリから、指定した条件でパッケージを検索しています。 また、上記の条件に併せてインストール済みパッケージのみを抽出することができます。 例えば、git という文字列から始まるパッケージのうち、インストール済みのパッケージのみを表示する場合は、下記の様なコマンドになります。 # apt list --installed git* 補足:apt 関連のコマンドの実行履歴は確認できる? apt には dnf history のようなサブコマンドはありません。 そのため /var/log/apt 配下に出力されるログから確認する必要があります。 /var/log/apt 配下には、下記の様なログが出力されます。 /var/log/apt/history.log パッケージのインストール/アップデート/削除などの実行履歴を記録するログです。 /var/log/apt/term.log パッケージのインストール/アップデート/削除などを実行した際、コンソール上に表示された内容を記録するログです。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 知っておくとちょっと便利!パッケージマネージャについて4 ~Debian 系システム編・続き~ first appeared on SIOS Tech. Lab .
アバター
  こんにちは、サイオステクノロジーの佐藤 陽です。 今回ははCosmosDBのインデックス機能についてご紹介したいと思います。 RDBにおいても登場するインデックスですが、CosmosDBにおいても重要な概念です。 ただRDBとは設定方法などは異なってくるため、CosmosDBにおけるインデックスについてご紹介していきたいと思います。 はじめに CosmosDBのインデックスについてご紹介していきます。 インデックスを正しく設定・使用することで、検索速度の向上や、使用するRUの削減にもつながります。 CosmosDBにおいて どのようにインデックスが構築されるのか どのようにインデックスが使われるのか について見ていきたいと思います。 インデックスの作成 CosmosDBにおいては、アイテムが追加・削除などされたタイミングでインデックスが自動で設定されます。 そのため基本的に何も設定しなくても高い検索パフォーマンスが得られます。 逆インデックス CosmosDBにおいては、格納されるアイテムを元にツリーが形成され、そのツリーを元に 逆インデックス というものが構築されます。 これはアイテムが追加されるたびに行われ、常にツリーの内容に反映されます。 と言われてもピンとこない気がするので、 前回まで扱っていた値(を少し修正したもの)を例にして提示したいと思います。 以下のデータがCosmosDBにおいて格納されているとします。 {     "id": "1",     "name": "寿司",     "price": 2000,     "ingredients": [         {"name":"米"},         {"name":"魚"}] }, {     "id": "2",     "name": "うどん",     "price": 500,     "ingredients": [         {"name":"小麦"},         {"name":"塩"},         {"name":"水"}] }, {     "id": "3",     "name": "パスタ",     "price": 1000,     "ingredients": [         {"name":"デュラム小麦"},         {"name":"塩"},         {"name":"水"}] } その場合、これらのアイテムは以下のようなツリーで表示されます。 配列を持つアイテムに関しては、配列内のそのエントリのインデックス (0、1 など) でラベル付けされた中間ノードを取得します。 これをベースとして、逆インデックスを作成していきます。 まず、各アイテムのidがツリーにおけるどのルートに対応するかを見ていきます。 全てのルートに対して図示すると見づらいので、Ingredientsのノードだけ確認します。 ここで①、②、③はそれぞれ各アイテムのidを表します。 例えば root/ingredients/1/name/塩 というルートは うどん , パスタ のアイテムの値が存在しているため②,③のマーキングがしてあります。 このツリーを元に、逆インデックス表を作成します。 (あくまでイメージです) パス 値 id /name 寿司 1 /name うどん 2 /name パスタ 3 /price 500 2 /price 1000 3 /price 2000 1 /ingredients/0/name 米 1 /ingredients/0/name 小麦 2 /ingredients/0/name デュラム小麦 3 /ingredients/1/name 魚 1 /ingredients/1/name 塩 2,3 /ingredients/2/name 水 2,3 この逆インデックス表がどのように使われるのかというと 例えば、 うどん という名前の料理を取得したい場合は以下のクエリを実行します。 select * from c where c.name = "うどん" この時、クエリエンジンは各アイテム(寿司、うどん、パスタ)を個別には検索しません。 逆インデックス表から 「name=うどん」ということは、idが1のアイテムだな という事がすぐに判明するため、id=1のアイテムのみを取得します。 …といったものが全体像になります。 ここからインデックスを用いた検索についてもう少し詳しく見ていきます。 検索 検索の流れとしては、 検索エンジンがクエリのフィルターを評価する 作成したツリーを利用してルートからプロパティまで走査する 該当するアイテムを返す といった流れです。 検索エンジンは、次に記載する評価方法のうち最も効率的なものを自動で選択し、評価を行います。 なお、これらの評価方法一覧は 公式ドキュメント にまとまってるので、概要は一旦こちらで確認してもらって 本記事ではもう少し具体的な例に落とし込んで紹介したいと思います。 インデックスシーク インデックスシークは最も効率の良い検索方法になります。 クエリエンジンが、指定されたフィールド値との完全一致したもののみを検索します。 先程挙げた例となりますが 以下のようなクエリの場合はnameが うどん と完全一致するものだけを検索すればよいので、インデックスシークが行われます。 select * from c where c.name = "うどん" また、検索するものが2つ以上ある場合でもインデックスシークが行われます。 これは うどん , パスタ それぞれの値に対する完全一致のみを検索しているためです。 select * from c where c.name IN ("うどん", "パスタ") 検索する際に、 完全一致か否か が判断のポイントかと思います。 インデックススキャン インデックススキャンは、クエリエンジンが対象となフィールドに対して、可能性のある全ての値を見つけるよう検索します。 先程のインデックスと比較して 完全一致 のものだけを探すのではなく、可能性があるものを操作することがポイントです。 また、インデックススキャンに関してもは、更に3つに細かく分類されるため、それぞれの値を見ていきたいと思います。 正確なインデックス スキャン 以下のようなクエリが対象です。 select * from c where c.price >= 1000 この場合、priceというフィールドの値に対して比較を行います。 この比較の処理を、ドキュメントでは バイナリ検索 と定義しています。 このバイナリ検索によって、複雑さが増し、インデックス シークから正確なインデックス スキャンへと変化しました。 そしてここでポイントなのですが、検索時に用いられる逆インデックスにおいて、一部の値に関しては昇順に並び替えられています。 パス 値 id /price 500 2 /price 1000 3 /price 2000 1 上記した表から抜粋 つまり、今回であれば 1000 という値を見つけた後は、逆インデックス表を昇っていくだけで値を取得することが可能です。 一方でこういったクエリも正確なインデックススキャンの対象となります。 select * from c where startswith(c.name, "うど")   ここからは公式ドキュメントに明言されてなかった部分なので、考察になるのですが 文字列に関しても、数値と同様に逆インデックス上においては昇順に並び替えられるのだと思います。 (そのため、上記に示した逆インデックスももしかしたら並び順は正確ではないかもしれません) そのため、今回であれば うど で検索されたポイントから昇順で検索していくだけでよいので、正確なインデックススキャンが使用されると思います。 なお、これに関しては後述する 拡張インデックススキャン の例と比較すると分かりやすいかと思います。 逆インデックスに関する並び順 逆インデックスにおいては値が昇順に並んでいるという言及をしましたが、公式ドキュメントに以下の記載がありました。 逆インデックスには、2 つの重要な属性があります。 ・特定のパスでは、値は昇順に並べ替えられます。 そのため、クエリ エンジンでインデックスから簡単に ORDER BY を提供できます。 ・特定のパスについて、クエリ エンジンで可能な値の個別のセットをスキャンして、結果が存在するインデックス ページを識別できます。 「特定のパスでは」という表現があるので、全てではないと思うのですが、数値・文字列・日付などは昇順に並び替えられ これらに関しては正確なインデックススキャンが利用されるのではないかと予想しています。 拡張インデックススキャン 拡張インデックススキャンに関しても、正確インデックススキャンと同じで特定のフィールドに対してバイナリ検索を行うものになります。 具体的なクエリを見てみたいと思います。 select * from c where startswith(c.name, "うど", true) 先程の正確なインデックススキャンの例のstartwithに true の引数が追加されました。 これは大文字・小文字を区別するかしないかを表すパラメータです。 そのため、正直日本語の検索ワードに対しては意味ないのですが、そこは雰囲気で感じ取ってください…。 大文字小文字を区別しないことで、「正確なインデックスキャン」から「拡張インデックススキャン」になるわけですが これが、先程言及した逆インデックス上の文字列の並び順に影響していると考えています。 逆インデックス上で文字列が昇順に並び替えられるわけですが、この時恐らく大文字と小文字は別物として並び替えられます。 つまり、大文字・小文字を区別せずに検索する場合、昇順に上がっていくだけではなく、降っていく範囲の検索も必要になると予想されます。 そのため、検索範囲が「拡張」され、拡張インデックススキャンとして検索されるのだと思われます。 フルインデックススキャン フルインデックススキャンはこれまで述べてきたものよりも、更に検索範囲が広いものになります。 以下のようなクエリのケースがフルインデックススキャンにあたります。 select * from c where endswith(c.name, "どん") この場合、 name のお尻の文字でフィルタリングをかけようとしているため、 逆インデックスの並び順は役立ちません。 結局、 name のプロパティを持つアイテムを全て検索することになります。 そのため、拡張インデックススキャンと比べても更に検索範囲が広がることが分かります。 これらの点から分かることとして、フィルタリングに使う句は必要最低限のものを採用するべきであることが分かります。 たとえば、 startswith 句でのフィルタリングで要件を満たすはずなのに、 contains 句を採用してしまうことで、 正確なインデックススキャンで済んでいたものが、フルインデックススキャンとして実行され、検索速度が劣化し、余計なRUも発生します。 クエリを書く際は果たしてそれが最適なフィルタリングになっているかどうかをよく考える必要がありそうです。 フルスキャン 最後にフルスキャンについてです。 これはそもそもインデックスを利用できない場合の評価方法になります。 フルインデックススキャンの例の場合は、 name のプロパティを持つアイテムだけを全てスキャンしていましたが フルスキャンの場合は name のプロパティを持たないアイテムも含め、全てのアイテムをスキャンするような形となります。 検証 インデックスによる検索によって、検索速度やRU量にどの程度影響が出ているかはCosmosDBのデータエクスプローラ空も確認することができます。 クエリを実行した後に Query Stats を確認すると、Request Chargeとindex lookup timeという値が確認できます。 今回は入れているデータが少なすぎたため、検索方法を切り替えてもあまり差異は見られませんでした。 データが膨大である場合はこのあたりの数値に変化がみられると思うので、是非一度自分の環境でも試してみてください。 まとめ 今回はCosmosDBにおけるインデックスの概念と、インデックスを利用した検索方法の内容についてご紹介しました。 逆インデックスの性質を把握し、正しいフィルター句を選択することで検索速度の向上や、コストの抑制が行えることが分かりました。 あとはインデックスに関しては、他にもインデックスポリシーという概念があり、インデックスを作成するプロパティなどを切り替え、より最適化を行うことができます。 このインデックスポリシーに関しては、また別途記事にしたいと思います。 ではまた! 参考 https://learn.microsoft.com/ja-jp/azure/cosmos-db/index-overview https://learn.microsoft.com/ja-jp/training/modules/define-indexes-azure-cosmos-db-sql-api/2-understand-indexes ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 【Azure】CosmosDBにおけるインデックス入門ガイド【初心者向け】 first appeared on SIOS Tech. Lab .
アバター
はじめに サイオステクノロジーの塚田です。Rancher入門ブログシリーズとして、 前回 はRancherを使って複数のクラスターを管理する方法について解説しました。本記事では、Rancherを用いてKubernetesクラスターの監視を行う方法について解説します。具体的には、Rancher標準のモニタリング機能を有効化し、PrometheusやGrafanaと連携することでRancherのダッシュボードからクラスターのリソース消費状況をモニタリングしたり、アラート通知を実現する手順を紹介します。これにより、複数のクラスターを効率的に監視・管理できる仕組みを構築することができます。 概要 前提条件 Rancher Serverが構築済みであること Rancher Serverにログインできること Rancherから管理対象クラスターを連携済みであること 構築イメージ RancherのダッシュボードからHelmを利用して、rancher-monitoringアプリケーションをインストールします。これにより、管理対象クラスター内にPrometheusやGrafanaなどのモニタリングツールを導入することができます。 rancher-monitoringアプリケーションは、主要なオープンソースの監視およびアラート機能をクラスタに迅速に導入するためのツールです。 Prometheusは、システム監視や時系列データの収集を目的としたオープンソースのモニタリングツールです。Prometheusを利用することで、CPU使用率やメモリ使用量などのリソースデータを効率的に収集し、システムの状況を可視化することができます。 導入後のイメージは以下の通りです。 バージョン情報 Rancher Monitoring: 105.1.0+up61.3.2 ※ ※本記事執筆時点における最新バージョン 導入手順 モニタリングのインストール まずはCluster Management画面上で対象クラスターのExploreを押下してクラスターのダッシュボードに遷移します。 Apps内のChartsからMonitoringを選択します。 Monitoringを選択し、Installを押下します。 インストール設定を以下のように入力し、Installを実行します。 Project: System 他はデフォルト     インストール完了後、サイドバーからWorkloadsを選択し、Installed Appsページにrancher-monitoringが存在することを確認します。 Monitoringアプリケーションをインストールすると、クラスターダッシュボードのメニューにMonitoringが追加されます。 この画面から、インストールしたPrometheus、Grafana、Alertmanagerの詳細な設定画面に遷移することができます。 クラスターのモニタリング rancher-monitoringアプリケーションを導入することで、RancherのUI画面に各種ダッシュボードが追加されます。これを利用して、クラスターのモニタリングを行います。 メニューからClusterを選択し、画面を下にスクロールすると、クラスターのリソース消費状況を表示するダッシュボードが追加されています。 ここではクラスター内の各NodeのCPU利用率、メモリ利用率、ディスク利用率などを確認することができます。 Summaryの横にある、Grafanaへのリンクを押下するとクラスター内で稼働しているGrafanaの画面に遷移することができます。 Grafanaへ遷移した直後は未ログイン状態です。 この状態でもダッシュボードの閲覧は可能ですが、Data Sourceの追加などができません。 Grafanaにadminユーザーとしてログインすると、Data Sourceの追加やダッシュボードの編集が実行できるようになります。 デフォルトのGrafanaのログイン情報は以下の通りです。 ユーザー:admin パスワード:prom-operator ワークロードのモニタリング クラスター単位だけではなく、クラスター内部のリソースも監視することができます。手順は以下の通りです。 サイドバーからWorkloadsに遷移します。 DeploymentsやPodsに移動し、Metricsタブを押下するとPodのリソース消費状況のダッシュボードが表示されます。 アラート設定 Rancherのダッシュボード上でAlertmanagerのルールを設定し、各クラスターから設定した通知先にアラート通知を送信することができます。 今回は、nginxのPodからアラートを発報する設定を作成するデモを行います。Rancher上でPodを作成する方法は 前回の記事 にて紹介しておりますので、参考になれば幸いです。 前提条件 nginxのPodが起動していること SlackのIncoming Webhookを設定し、Slcak API用のURLを発行していること Slack Webhook URLをキーとするSecretをnginx namespaceに作成します。 Key: slack_url Value: <SLACK_WEBHOOK_URL> Monitoring→AlartmanagerConfigへ遷移します。 Createを押下してAlartmanagerConfigを新規作成します。 Add Receiverを押下してReciever設定画面へ遷移します。 Add Slackを選択します。 Target情報を入力します。 作成したSecretを選択 defaultチャンネル欄に作成した検証用チャンネルを入力 Routeを設定します プルダウンからAlartmanagerConfigを選択 MatcherでSecretと同じnamespaceを指定 サイドバーのMonitoringからPrometheus Ruleに遷移し、Createを押下してアラートルールを作成します。 以下のように設定します。 namespace: アラートを発報したいリソースと同じnamespaceを指定 name: 任意の名称 Rule Group 1の設定 Group Name: 任意の名称 Add Alertを選択し、アラートルールを入力 Alert Name: 任意の名称 PromQL Expression: container_memory_working_set_bytes{pod=~”nginx.*”} > 1000000 Severity: critical Annotations: Messageを有効化し、任意のメッセージを入力   指定したSlackチャンネルにアラートが送信されたことを確認します。 このように、Rancherのダッシュボード画面上からAlertmanagerの通知ルールを設定し、アラートをSlackに送信することができます。これにより、複数のクラスターが稼働している環境下でも、アラート設定をRancher上で一元管理することができます。 まとめ 本記事では、RancherのKubernetesクラスター監視機能を利用して管理対象クラスターをモニタリングする方法を解説しました。 一般的に、PrometheusやGrafanaはHelmを用いてインストールされることが多いですが、この方法ではインストール後に設定やツール間の連携を手動で行う必要があり、セットアップに時間と手間がかかる場合があります。さらに、管理するクラスターが増えるほど、それぞれのクラスターでモニタリング環境を構築・管理する工数も比例して増加し、運用の負担が大きくなる傾向があります。一方で、rancher-monitoringアプリケーションを利用することで、PrometheusやGrafanaのインストールと設定をRancherのUIから簡単に一括管理でき、手動設定の手間を大幅に削減できます。特に、複数クラスターを管理している環境では、Rancherの一元化されたダッシュボードを活用することで、効率的にモニタリング環境を構築できる点が大きなメリットです。 次回の記事では、RancherとLonghornを組み合わせた分散ストレージの管理方法を紹介します。ぜひご期待ください。 参考 Rancher公式ドキュメント: Monitoring and Alerting ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Rancher入門:Rancherを用いたKubernetesクラスターの監視 first appeared on SIOS Tech. Lab .
アバター
はじめに こんにちはサイオステクノロジーの小野です。私は今年入社したばかりの新卒社員なので今年一年は新しいことしか学んできませんでした。その学んできた中でもOpenShift AIは一番インフラエンジニアとして学びになったと感じました。(あと単純にAIが好きだったので一番楽しかったです。)今まで、様々なソフトウェアに対してアプリケーション目線のことしか考えてきませんでしたが、OpenShift AIの勉強を通じて、そのソフトウェアがどのようにして動いているのか、内部のアプリケーションがどのようにして実行されているのかインフラ目線で見る意識が養われた気がします。 今回はそんなOpenShift AIを利用して機械学習を行う方法について解説します。 前回 はOpenShift AIを導入してワークベンチのJupyterNotebookを起動するところまで解説したので、まだ見ていない方は先にそちらをご覧ください。 Openshift AIでの機械学習 今回はOpenShift AIのワークベンチ機能とデータ接続機能を用いて実際に機械学習を行います。 ワークベンチは機械学習のモデルを作成、操作するために隔離された作業環境です。MLOpsにおけるデータの分析やモデルの学習、評価、検証を行うために用いられます。 データ接続はOpenShift AIの各種機能を外部のS3オブジェクトストレージに接続するための機能です。 今回構築する機械学習モデル 機械学習におけるモデルとは、あるデータを入力するとそのデータに応じた出力をする数学的関数のことを言います。 今回はMNISTという数字の画像を入力して、その画像が何の数字かを出力するモデルを構築します。 今回構築する機械学習モデル 機械学習をやってみる 全体的な作業流れ 最初にOpenShiftAIでプログラムを実行するための環境を設定します。そのために、OpenShiftAIのデータサイエンスプロジェクト、データ接続、ワークベンチをそれぞれ設定します。その次にサンプルプログラムをJupyterLabにアップロードします。最後にプログラムを実行すると、簡単な機械学習を行うことができます。 本環境の条件 OpenShift情報 OpenShift:4.17 OpenShift AI:2.13 ストレージ情報 AWS(S3) S3を操作するためのIAMと作業用バケットを事前に作成してください。 プログラムソース 0_dataupload.ipynb 1_dataprocessed.ipynb 2_training.ipynb 環境構築手順 データサイエンスプロジェクト作成 最初にデータサイエンスプロジェクトを作成します。この作業は前回の記事の「 Data Science Projects作成 」を参考にして設定してください。 データ接続作成 次にデータ接続設定を行います。データサイエンスプロジェクトの詳細画面からData connectionsに移動します。Add data connectionを押下して、設定は以下のようにします: Name test-connection Access key S3へのアクセス権限があるIAMのアクセスキー Secret key S3へのアクセス権限があるIAMのシークレットキー Endpoint https://s3.<S3のリージョン>.amazonaws.com Region S3のリージョン Bucket S3に作成したバケット名 データ接続設定 ワークベンチ作成 次にワークベンチを作成します。詳細は前回の記事の「 ワークベンチ作成 」を参考にしてください。データサイエンスプロジェクトの詳細画面からWorkbenchesに移動します。Create workbenchを押下して設定は以下のようにします: Name:test-workbench Notebook image Image selection:PyTorch Version selection:2024.1 Deployment size Container size:Small Accelerator:NVIDIA GPU(GPUがない場合None) Number of accelerators:1(GPUがある場合設定する) Cluster storage Create new persistent storage Name:test-workbench Persistent storage size:20Gi Data connections Use existing data connection Data connection:test-connection ワークベンチへのプログラムアップロード このリンクからプログラムをダウンロードしてください。 MLcode ダウンロードしたプログラムをJupyterLabにドラッグ&ドロップするとワークベンチにプログラムをアップロードできます。 プログラム動作 データの収集 0_dataupload.ipynbを実行します。データソースからMNISTの画像をダウンロードし、S3の/test-demo/dataディレクトリにアップロードします。 実行後、S3の/test-demo/dataディレクトリを確認すると、データがzipにまとめられて保存されているのが確認できます。 0_dataupload実行後のS3 データの準備 1_dataprocessed.ipynbを実行します。S3にあるMNISTの画像をダウンロードして、画像を学習に使える形に前処理します。その後、S3の/test-demo/processed_dataディレクトリにアップロードします。 実行後、S3の/test-demo/processed_dataディレクトリを確認すると、前処理済みデータがzipにまとめられて保存されているのが確認できます。 1_dataprocessed実行後のS3 モデルの学習 2_training.ipynbを実行します。S3にある前処理済みの学習データをダウンロードし、モデルの学習・推論を行い、学習後のモデルをS3の/test-demo/modelsディレクトリにアップロードします。その構成図を以下に示します: モデルの学習構成図 実行するとMNIST画像とその画像に対しての推論結果とAccuracy(正解率)が表示されます。表示されているMNIST画像は学習後のモデルに入力する推論用のデータです。推論結果は入力されたMNIST画像がどんな数字であるかモデルが推論した回答になります。Accuracy(正解率)は10000枚のMNIST画像をモデルが推論を行い、その推論した結果とMNISTの画像の数字が一致した確率を示しています。 モデルの推論・評価の結果 実行後、S3の/test-demo/modelsディレクトリを確認すると、モデルデータがONNX形式として保存されているのが確認できます。 2_training実行後のS3 最後に 以上の手順によりOpenShift AI内で実際に機械学習を行うことができました。このようにワークベンチ内のJupyterLab環境で自由にJupyterNotebookを実行することが可能です。さらにデータ接続機能を利用すると外部のストレージにアクセスも可能になります。ぜひOpenShift AIを利用してモデル開発に役立ててみてください。 参考 ワークベンチ設定: https://docs.redhat.com/ja/documentation/red_hat_openshift_ai_self-managed/2.13/html/working_on_data_science_projects/using-project-workbenches_projects#creating-a-workbench-select-ide_projects データ接続設定: https://docs.redhat.com/ja/documentation/red_hat_openshift_ai_self-managed/2.13/html/working_with_data_in_an_s3-compatible_object_store/index OpenShift AIチュートリアル不正検出の例: https://docs.redhat.com/ja/documentation/red_hat_openshift_ai_self-managed/2.13/html/openshift_ai_tutorial_-_fraud_detection_example/index 前回: OpenShift AIを導入してみた ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post OpenShift AIで機械学習をやってみた first appeared on SIOS Tech. Lab .
アバター
挨拶 ども!すごく良い調子で弊社開催の「 #2024アドベントカレンダー 」が進んでいます。内容としても様々な内容が投稿されていて、弊社の特徴が出ていて素晴らしいですね。 今期は、【Streamlit】【Qumcum】【AIエージェント】の3つを掛け合わせて、ロボットを操作するAIエージェントを作成しました。 2024-12-11 AIエージェントでロボットを制御する【langchain・Streamlit】 このデモの過程で、今回の内容がすごく面白いと感じたので注目して書いていきたいと思います。今回の内容は以下の通りです。 日本人が感覚で理解している「表現」を数値化する 生成AIでニュアンスを数値化する これまで、「文章から特定の評価に従って数値化」には時間と手間がかかっていました。生成AIを活用することで、プロンプトのみで数値化することができるようになっています。今回はサンプルとして検証した内容を公開していきます。 シンプルな数値化 とても単純な方法は、以下のようなプロンプトを入力すればよいです。 文章に含まれる、喜びの感情を1~100で数値化してください。 {{input}} 例えば、「とてもうれしい」という入力をChatGPTに投げかけてみます。 「とてもうれしい」に含まれる喜びの感情を1~100で数値化すると、98と評価できます。 理由: 「とても」という強調表現が、喜びの度合いを極めて高めているため、ほぼ最大値に近い値を割り当てます。 最大値である100を絶対的なピークとすると、「とてもうれしい」はそれに非常に近い表現と考えられます。 単純な数値のみでなく理由も返答されてきました。数値化した内容の利用用途に寄りますが、プロンプトで出力を制限することができます。 文章に含まれる、喜びの感情を1~100で数値化してください。 - 出力結果は数字のみにしてください。 {{input}} プロンプトに一行追加するだけで出力を数字のみに限定することができます。また、数値の範囲も範囲を変更することで判断して出力してくれます。 指標を追加する シンプルな方法で「喜び」の感情を数値化しました。ここでは、もう少し深堀していきたいと思います。シンプルな実装方法の場合だと、「とても」や「めっちゃ」などの表現が入っていれば、最大点となります。それを制限する方法は、以下のような手段が挙げられます。 例を与えて最大点を引き下げる:Few-Shot One-Shot 制限を追加する 例を与えて最大点を引き下げる方法 シンプルな実装では、「とても」や「めっちゃ」で最大点になります。プロンプト内でサンプルとして、採点した情報を与えることで最大点をずらすことができます。 文章に含まれる、喜びの感情を1~100で数値化してください。 - 出力結果は数字のみ 例は以下になります。 - とてもうれしい:20 {{input}} サンプルの数値を下げることで、判別の閾値を下げることができます。よく使われる表現などをまとめてサンプルとして与えてあげることで、よりサンプルの感覚に近い数値をはじき出せるようになります。 値を散らす方法に関しては、後輩が検証している記事があったので紹介しておきます。 2024-08-07 プロンプトでいかに5の倍数を出させないか 制限を追加する こちらの方法では、追加の制限を設けることで点数を散らす方法について紹介します。制限については以下のような内容から選択すると良いと思います。 よく使われる表現の場合は減点してください 面白い表現の場合は加点してください 古風な表現を用いた場合は加点してください 比喩表現は良いですね~加点しましょう 加点や減点の指標が衝突する可能性もあるので、制限をすべて追加するわけにはいきません。利用目的に即した制限を追加する必要があります。 個人的には「よく使われる表現の場合は減点してください」を追加するだけで評価指標が大きく変わるのが面白いですね。 文章に含まれる、喜びの感情を1~100で数値化してください。 - 出力結果は数字のみ - よく使われる表現の場合は減点してください {{input}} ニュアンス数値化を使ってみた 今回紹介した、数値化を行っているデモは二つ作成していました。軽ーく紹介しておきますね。 泳げ!進め!カツオくん このゲームでは、「音声認識」と「生成AI」をベースに考えたゲームになります。ゲーム内では、「感情」を数値化して活用しています。 文字列の長さで魚の位置を決定して障害物をよけて進みます。音声入力されたテキストを数値化し、スコアとして加点していくことで競うゲームですね。 ロボットを操作する:AIエージェント こちらは、「AIエージェント」「ロボット」をベースに考えたデモになります。デモでは、「表現」を数値化して活用しています。 こちらのデモでは、ユーザーの入力から内容をAIエージェントに処理してもらい、ロボットの出力として動作してもらいます。ダンスの項目では、生成AIの実行の結果として実行回数と実行スピードを受け取ることができます。 サンプルでは「日本舞踊のようなスピード」と「最高のスピード」とで実行してみました。結果としては、日本舞踊は「ゆっくり」と最高のスピードは「あらぶり」という結果になりました。 絶妙なニュアンスに関しても生成AIは拾うことができるので面白いです。 デモは、こちらにまとまっています。 終わり 今回は生成AIを使って、テキストからニュアンスを数値化する方法を紹介しました。プロンプトの工夫次第で、より精度の高い数値化が可能になることが分かりました。この技術を活用することで、様々な面白いアプリケーションが作れそうですね。これまでなかなか数値化しにくい業界にも入り込みやすくなりました。 ではまた! ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post ChatGPTでニュアンスを数値化する first appeared on SIOS Tech. Lab .
アバター
はじめに 皆さんこんにちは。エンジニアの細川です。 今回はアドベントカレンダーで記事を書いてみたいと思います! テーマは「サイオス社員が今年一年で新たに学んだ技術」です! 今回はTypeScript界隈で注目されている!?Biomeについて紹介したいと思います! Biomeとは BiomeはTypeScriptやJavaScriptなどの言語のLinterとFormatterが一つになったようなツールです。ESLintやprettierなどは皆さん使われているかと思いますが、それらの代わりにBiome一つで、コードの静的解析を行ったり、成形をしてくれたりします。 BiomeはRustで動作しており、既存のESLintやprettierなどと比べてかなり高速に動作するみたいです。 導入方法 早速導入方法について紹介します。 まず、Biomeを以下のコマンドでインストールします。 npm install --save-dev --save-exact @biomejs/biome その後、以下のコマンドを叩くことで、Biomeの設定ファイルである biome.json が作成されます。 npx @biomejs/biome init デフォルトの設定で良い場合は作成不要とのことですが、作成しておくことをお勧めします。 これで基本的には導入完了です。 使い方 導入が完了すれば以下のコマンドでlinterやformatterを実行できます。 formatコマンドでファイルやディレクトリなどをformatできます。 npx biome format --write <files> lintコマンドを実行すると、コードの静的解析が行えます。 npx biome lint --write <files> また、writeオプションを利用すると、安全に修正可能な問題に対しては修正をしてくれます。詳細は こちら をご確認ください。 checkコマンドを利用すればlintとformat両方を実行できます。 npx biome check --write <files> それぞれ package.json に以下のように設定しておくと便利かと思います。 "scripts": { "lint": "biome lint src", "format": "biome format src", "check": "biome check src" }, 拡張機能 また、BiomeはVSCodeの拡張機能も存在しており、導入しておくことで、ルールにそぐわない場合にエラー表示を出してくれたり、保存時にformatをかけてくれたりするので、ぜひ導入しておくことをお勧めします。 こちら からインストールすることができます。 導入した後は Ctrl + Shift + P でコマンドパレットを開き、「format」と入力して表示される Format Document をクリックしてください。 その後既定のフォーマッターを構成からBiomeを選択しておくことで、その言語のデフォルトのフォーマッターでBiomeが使われるようになります。 また、VSCodeの設定を開き、saveで検索して出てくる Format On Save をONにしておけば、save時に自動でフォーマットしてくれるようになります。 運用 linterを導入しても、手でいちいちコマンドを叩くのがめんどくさいこともあるのではないでしょうか?また、叩き忘れがあったりなども多いため、自動でlinterが走るようにしたいこともあると思います。 僕のプロジェクトでは、lefthookと併用し、commit時に自動でlintコマンドを走らせることで叩き忘れ等を防止しています。 lefthookとはgitコマンドが実行される前後に自動で走るスクリプトを管理できるツールです。詳しくは公式の ドキュメント をご確認ください。 まず、以下のコマンドでlefthookをインストールします。 npm install @evilmartians/lefthook --save-dev その後、 .git が存在するディレクトリで以下のコマンドを叩きます。 lefthook install このコマンドを叩くことで、そのディレクトリにてlefthookが利用できるようになります。 lefthook.yml が生成されるはずなので、 pre-commit 部分に以下を追記します。 pre-commit: commands: glob: "*.{js,ts,jsx,tsx}" biome: run: npm run check <- biome checkなど実行したいコマンド これでcommit時に自動で biome check が走るようになります。 Biomeは動作も高速なので、そこまでストレスには感じずにチェックを行えるかと思います。 モノレポ設定について 一つのリポジトリでフロントとバックを両方管理するような場合もあるかと思います。 その場合、フロントとバックで共通のルールもあれば、このルールはバックエンドだけに適用したいなんて言うこともあるかと思います。 そのような場合、フロントとバックでそれぞれ biome.json を用意することで別々のルールを適用することができます( 参考 )。 ただし、この方法には一つ問題があります。それはVSCodeの拡張機能では現在開いているディレクトリに存在する biome.json しか認識してくれないという点です。 具体的には、例えば以下のような構成があったとします。 - root | - biome.json <- 共通の設定 | - front/ | - biome.json <- フロントのみの設定 | - src/ | - back/ | - biome.json <- バックのみの設定 | - src/ このときrootを開いて作業すると、フロントやバックに指定しているルールは拡張機能でエラー表示してくれず、クイックフィックスなども利用できません。 都度都度ディレクトリを開きなおせばいいのですが、フロントとバック横断して開発する場合などはいちいち開きなおすのが面倒なこともあると思います。 このような場合は、以下のように overrides を利用することで、フロントとバックのルールを一つにまとめることができます。 { "$schema": "https://biomejs.dev/schemas/1.8.0/schema.json", "formatter": { "indentStyle": "space", "indentWidth": 2 }, "organizeImports": { "enabled": true }, "linter": { "enabled": true, "rules": { "recommended": true // <- 全体に適用するルール } }, "overrides": [ { "include": ["backend/**"], "ignore": [ "backend/node_modules/**", "backend/dist/**", ], "linter": { "enabled": true, "rules": { // <- バックエンドのみに適用するルール "style": { "useImportType": "off" }, } }, "javascript": { "parser": { "unsafeParameterDecoratorsEnabled": true } } }, { "include": ["frontend/**"], "ignore": [ "frontend/node_modules", "frontend/dist", ], "linter": { "enabled": true, "rules": { // <- フロントエンドのみに適用するルール "nursery": { "noConsole": "error" } } } }, ] } デメリットとして設定ファイルが巨大化して少し読みづらくなるという点はありますが、僕のプロジェクトでは拡張機能の利便性の方を優先し、このような設定にしています。 Biomeのデメリット これまでBiomeのメリットや使い方等をお話ししてきましたが、Biomeには一つかなり大きな問題点があるかなと思います。 それはカスタムルールが設定できないという点です(このブログ執筆時点では方法を見つけられませんでした)。カスタムルールのためのプラグイン開発は進行中のようです( 参考 )。 そこで、Biomeで対応できないルールのみESLintでチェックを行うというような構成をお勧めします。 ESlintは以下のコマンドでインストールすることができます。 npm install --save-dev eslint そのあと eslinrc.js を作成します。(ymlやjsonでも設定ファイルを記述することができます。 こちら の記事で分かりやすく書いてくれていました。) module.exports = { parser: "@typescript-eslint/parser", parserOptions: { project: "tsconfig.json", tsconfigRootDir: __dirname, sourceType: "module", }, plugins: ["@typescript-eslint/eslint-plugin"], extends: ["plugin:@typescript-eslint/recommended"], root: true, env: { node: true, jest: true, }, ignorePatterns: [".eslintrc.js", "src/generated/*"], rules: { "@typescript-eslint/interface-name-prefix": "off", "@typescript-eslint/explicit-function-return-type": "off", "@typescript-eslint/explicit-module-boundary-types": "off", "@typescript-eslint/no-explicit-any": "off", //biomeがカバーしているルールを無効化 semi: "off", quotes: ["error", "double"], // ----------------↓Biomeで対応できないルールを追加----------------------- "no-restricted-syntax": [ "error", { // letを禁止 selector: "VariableDeclaration[kind='let']", message: "'let'は禁止です。代わりに'const'を使用してください。", }, ], }, }; 注意点としては、Biomeで設定しているルールとバッティングする内容についてはoffにしておくことです。 基本的なチェックはBiomeで行うので、pluginなどが無い方が簡潔になるかもしれません。 今回は例として、 let を禁止するルールを追加してみています。 後は、以下のコマンドを package.json に追加しておけばeslintも叩けるようになります。 "scripts": { "lint:es": "eslint --ext .ts src", ... } ESLintはBiomeに比べると実行に時間がかかるので、僕のプロジェクトではcommit時のチェックはせずに、PR作成時にCIで回るようにしています。 このあたりは皆さんのプロジェクトに合わせて調整してください。 まとめ Biomeはlinterとformatterが一つになったツール lint npx biome lint --write <files> format npx biome format --write <files> lint + format npx biome check --write <files> VSCodeの拡張機能を導入すればエラー表示&自動フォーマット可能 lefthookと併用することでcommit時に自動チェック フロント、バックなどでルールを分けたい場合は overrides を利用 overrides を利用することでVSCodeの拡張機能も問題なく利用できる! Biomeで設定できないルールはESLintでチェック おわりに 今回は、Biomeについて紹介しました。基本的には設定も簡単で動作も早く、かなりお勧めなツールになります。ただ、カスタムルールを設定できないという弱点もあるので、その場合はぜひESLintと併用するという方法も試していただければと思います! 今後もお勧めの構成などがあれば紹介していきたいと思います! 他にも今月は アドベントカレンダー で様々な記事が投稿されると思うのでぜひチェックしてみてください。 今回参考にさせていただいた記事 https://biomejs.dev/ja/guides/getting-started/ https://qiita.com/howdy39/items/6e2c75861bc5a14b2acf https://blog.solunita.net/posts/change-lefthook-instead-of-lintstaged-with-husky/ ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post linterとformatterが一つに!?Biome使ってみた first appeared on SIOS Tech. Lab .
アバター
こんにちはアプリチームの織田です  先日、12月7日に開催された OSC福岡 で、初めてセミナーに登壇するという貴重な経験をしてきました。今回の私の発表テーマは「生成AI」です。生成AIの基礎知識を中心に、これからこの分野に触れる方々にもわかりやすく、その魅力や可能性をお伝えすることを目指しました。このブログではセミナーの内容や登壇しての感想を少し詳しくまとめたいと思います。セミナーで用いた資料は コチラ から閲覧できます。また、今回のOSCでの展示は別の ブログ記事 にて紹介していますので、是非そちらもご覧ください。   セミナーの目的 発表の目的は、生成AIについてあまり詳しくない方にも、その魅力や利便性をわかりやすく伝えることでした。生成AIがどんなことができるのか、具体的なイメージを持ってもらうことで、興味を持ってもらい、理解を深めてもらいたいと考えていました。 また、私の発表の後には、武井さんや山崎さんによるAIエージェント、AIロボットに関する発表がありました。これらの発表は、生成AIの知識を前提とした、より発展的な内容でした。そのため、私の発表では、これらの発表を理解するために必要な基礎知識を、わかりやすく提供することも目的の一つでした。   セミナーの概要 セミナーは、デモセッションからスタートしました。細かな説明の前に様々な生成AIツールの動きを実際に見てもらい、この後の話が聞きやすくなることを狙いました。デモの内容としては、ChatGPTを使ったアイデア出し、Geminiによる誤字検出、AIイラストメーカーによるイラスト生成など、生成AIツールの具体的な活用事例を、実際に動かしながら紹介しました。生成AIがどんなことができるのか、その可能性を直感的に理解してもらえたのではないかと思います。  次に、生成AIの概要を説明しました。ここでは、まず従来のAIと生成AIの違いを明確にし、それぞれの得意分野や活用例を挙げながら、生成AIが持つ「創造性」という新たな可能性を強調しました。続いて、生成AIの強みとして、コンテンツ制作の効率化や、新しいアイデアの創出などを紹介しました。 しかし、その一方で、生成AIを利用する上での注意点も詳しく解説しました。特に、生成AIが生成するコンテンツは、必ずしも正確であるとは限らないという点について、具体的な例を挙げて説明しました。また、生成AIが生成したコンテンツの著作権や、倫理的な問題についても言及し、利用者自身が責任を持ってこれらの問題に対処する必要があることを強調しました。 最後に、「生成AIはあくまでツールである」という点を強調し、その出力結果を鵜呑みにせず、常に自身の知識や判断力を働かせることの重要性を伝えました。生成AIの持つ可能性を最大限に活かしつつ、その限界やリスクも理解した上で、適切に利用していくことの重要性を訴えました。 最後に大規模言語モデル(LLM)の説明を行いました。LLMの説明を行う際には、生成AIとLLMの関係性が伝わりづらくなるだろうと思い、図解を用いて整理しました。また、LLMでできること、LLM単体ではできないことについての説明も実施しました。例えば、LLMは最新の情報や非公開の情報にはアクセスできないという限界があります。このような点を理解した上で、LLMを活用していくことが重要であることを伝えました。また、これらの課題を克服するためには、LLMを他の技術やシステムと組み合わせることが必要であり、それが次のセッションで紹介される「AIエージェント」へとつながることを示唆しました。このように、LLMの解説を通じて、生成AIの理解を深めると同時に、AIエージェントへのスムーズな橋渡しとなるように配慮しました。   感想 今回でOSCへの参加は2回目となりましたが、今回は初めて登壇という形で参加させていただきました。初めての登壇のため非常に緊張していましたが、参加者の皆さんの熱心な様子を見て、私も楽しく発表することができました。質疑応答の時間には、多くの質問が寄せられ、生成AIに対する関心の高さを改めて実感しました。私自身も、参加者の皆さんから多くの刺激を受け、大変有意義な経験となりました。 発表後には自社のブースの宣伝を行ったところ、聴講してくださった方がブースにも足を運んでくださったようで、嬉しかったです。また、企業の方から「社内向けの生成AIセミナーの参考になった」という嬉しいお言葉をいただきました。 初めての登壇ということもあり、反省点もいくつかあります。例えば、もう少しイラストや図解を多用することで、視覚的な理解を促すことができたかもしれません。また、クイズ形式の時間を設けるなど、参加型の要素を取り入れることで、より楽しく、記憶に残る発表にすることができたのではないかと感じています。 今回の経験を活かし、今後も技術に関する知識や情報を積極的に発信していきたいと考えています。また、次回登壇する機会があれば、さらにわかりやすく、興味深い発表ができるよう工夫していきたいと思います。 それでは、最後までお読みいただきありがとうございました。 当日のセミナーの様子。学生さんが大変多く聴講に来てくださいました。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 2024年OCS福岡_生成AIに関するセミナー登壇の感想 first appeared on SIOS Tech. Lab .
アバター
こんにちは、伊藤です。 今回は、Apache HTTPとApache Tomcatを連携するWebサーバの構築手順について紹介します。 連携Webサーバの利点 Apache HTTPはHTTPの処理(リクエストとレスポンス)に優れており、Apache TomcatではJAVAの実行処理(動的処理)が可能です。これらを組み合わせることで応答性を担保した動的Webアプリケーションを構築することができます。 Apache HTTPでは複数のドメインで別々のWebサイトを提供することができます。利用者と管理者それぞれにWebサイトを提供したい場面があったため、今回はその設定をApache Tomcatのサンプルページを利用して紹介します。 使用環境 構築時に利用した環境は以下です。 Rocky Linux 9.2 また、クライアントPCからWebサーバに対してhttp, https通信ができるようにしておく必要がありますが、今回は割愛します。 ソフトウェアインストール 以下のソフトウェアをインストールします。 Apache HTTP Apache HTTP SSLモジュール Apache Tomcat OpenJDK Apache HTTPのインストール Apache HTTPをインストールし、バージョンを確認します。 $ sudo dnf -y install httpd $ httpd -v Server version: Apache/2.4.62 (Rocky Linux) Server built: Aug 3 2024 00:00:00 Apache HTTP SSLモジュールのインストール Apache HTTP SSLモジュールをインストールし、バージョンを確認します。 $ sudo dnf -y install mod_ssl $ rpm -aq | grep mod_ssl mod_ssl-2.4.62-1.el9.x86_64 Apache Tomcatのインストール Apache Tomcatをインストールし、バージョンを確認します。 $ sudo dnf -y install tomcat $ tomcat version Server version: Apache Tomcat/9.0.87 Server built: Jan 10 1970 04:21:54 UTC Server number: 9.0.87.0 OS Name: Linux OS Version: 5.14.0-284.11.1.el9_2.x86_64 Architecture: amd64 JVM Version: 11.0.25+9-LTS JVM Vendor: Red Hat, Inc. OpenJDKをインストール OpenJDKをインストールし、バージョンを確認します。 $ sudo dnf -y install java-17-openjdk $ java -version openjdk version "17.0.13" 2024-10-15 LTS OpenJDK Runtime Environment (Red_Hat-17.0.13.0.11-1) (build 17.0.13+11-LTS) OpenJDK 64-Bit Server VM (Red_Hat-17.0.13.0.11-1) (build 17.0.13+11-LTS, mixed mode, sharing) Webアプリケーションのダウンロード dnfでインストールした場合Apache TomcatのWebアプリはダウンロードされないため、Tomcatが提供するWebアプリ(ドキュメント集や管理者用Webアプリ)をダウンロードサイトからダウンロードします。ダウンロード対象フォルダはwebapps配下のフォルダです。ダウンロードしたフォルダはWebサーバのtomcat/webapps配下に配置します。 「ROOT」ディレクトリはドキュメントルート「/」のwebページの配置場所となりますが、今回は使用しないため、ディレクトリ名を「ROOT」から「home」に変更します。 ダウンロードサイト: https://tomcat.apache.org/download-90.cgi Apache Tomcatのサンプルwebアプリ用ファイル(sample.war)もダウンロードします。sample.warファイルをtomcat/webapps配下に配置します。配置するとsampleディレクトリが自動生成されます。 ダウンロードサイト: https://tomcat.apache.org/tomcat-7.0-doc/appdev/sample/ Webアプリの配置を確認します。 $ ls /usr/share/tomcat/webapps/ docs examples home host-manager manager sample sample.war 自己署名証明書の作成 検証用の自己署名証明書を作成します。自己署名証明書は信頼されていないため、本番環境での使用は推奨されていません。本番環境では認証局(CA)から発行された証明書を使用してください。今回はSAN付き自己署名証明書の作成方法 1 を参考にして、複数のWebサイトに対応するSubject Alternative Name (SAN) 付き証明書を作成します。 秘密鍵の作成 秘密鍵を(server.key)作成します(RSA4096ビット長)。 $ sudo openssl genpkey -algorithm RSA -out /etc/pki/tls/private/server.key -pkeyopt rsa_keygen_bits:4096 署名リクエストの作成 署名リクエスト(server.csr)を作成します。 $ sudo openssl req -new -key /etc/pki/tls/private/server.key -out /etc/pki/tls/certs/server.csr 署名リクエストで以下の質問に回答します。 Country Name (2 letter code) [XX]:JP State or Province Name (full name) []:Tokyo Locality Name (eg, city) [Default City]:Minato-ku Organization Name (eg, company) [Default Company Ltd]:Example Inc. Organizational Unit Name (eg, section) []:Example section Common Name (eg, your name or your server's hostname) []:example.com Email Address []:admin@example.com Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []: 署名リクエストを確認します。 $ openssl req -text -in /etc/pki/tls/certs/server.csr -noout Certificate Request: Data: Version: 1 (0x0) Subject: C = JP, ST = Tokyo, L = Minato-ku, O = Example Inc., OU = Example section, CN = example.com, emailAddress = admin@example.com Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (4096 bit) …<省略>… 証明書の作成 SANを記述したファイル san.txtを作成します。 $ vim san.txt subjectAltName = DNS:example.com, DNS:manager.example.com, DNS:user.example.com 証明書(server.crt)を作成します(有効期限約10年間)。 $ sudo openssl x509 -in /etc/pki/tls/certs/server.csr -out /etc/pki/tls/certs/server.crt -req -signkey /etc/pki/tls/private/server.key -days 3650 -extfile san.txt 証明書を確認します。 $ openssl x509 -text -in /etc/pki/tls/certs/server.crt -noout Certificate: Data: Version: 3 (0x2) Serial Number: 17:76:19:47:c7:0f:0b:fe:ff:b9:33:ec:21:3e:1f:83:e0:1b:8a:9a Signature Algorithm: sha256WithRSAEncryption Issuer: C = JP, ST = Tokyo, L = Minato-ku, O = Example Inc., OU = Example section, CN = example.com, emailAddress = admin@example.com Validity Not Before: Dec 6 02:42:24 2024 GMT Not After : Dec 4 02:42:24 2034 GMT Subject: C = JP, ST = Tokyo, L = Minato-ku, O = Example Inc., OU = Example section, CN = example.com, emailAddress = admin@example.com Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (4096 bit) …<省略>… X509v3 extensions: X509v3 Subject Alternative Name: DNS:example.com, DNS:manager.example.com, DNS:user.example.com …<省略>… Apache HTTPの設定 HTTPの設定 HTTPの設定(/etc/httpd/conf/httpd.conf)です。下記の設定を行います。各種設定は、Virtual Hostの設定 2 、SSLモジュールの設定 3 、Mozilla SSL Configuration Generator 4 を参考にしました。 ディレクトリ一覧表示を禁止する設定 Virtual Hostの設定 Tomcatへの転送設定 SSLの設定 httpからhttpsへのリダイレクト設定 $ sudo vim /etc/httpd/conf/httpd.conf Listen 80 Listen 443 …<省略>… ServerName example.com:443 …<省略>… Options FollowSymLinks # Indexesを削除してディレクトリ一覧表示を禁止する …<省略>… # manager.example.com <VirtualHost *:443> # Webサーバ名 ServerName manager.example.com # SSL設定 SSLEngine on SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1 SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH SSLHonorCipherOrder on SSLCertificateFile /etc/pki/tls/certs/server.crt SSLCertificateKeyFile /etc/pki/tls/private/server.key SSLCompression off SSLSessionTickets off # リクエスト転送設定 <Location "/home"> ProxyPass ajp://127.0.0.1:8009/home </Location> <Location "/manager"> ProxyPass ajp://127.0.0.1:8009/manager </Location> <Location "/host-manager"> ProxyPass ajp://127.0.0.1:8009/host-manager </Location> <Location "/docs"> ProxyPass ajp://127.0.0.1:8009/docs </Location> <Location "/examples"> ProxyPass ajp://127.0.0.1:8009/examples </Location> </VirtualHost> # user.example.com <VirtualHost *:443> # Webサーバ名 ServerName user.example.com # SSL設定 SSLEngine on SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1 SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH SSLHonorCipherOrder on SSLCertificateFile /etc/pki/tls/certs/server.crt SSLCertificateKeyFile /etc/pki/tls/private/server.key SSLCompression off SSLSessionTickets off # リクエスト転送設定 <Location "/sample"> ProxyPass ajp://127.0.0.1:8009/sample </Location> </VirtualHost> <VirtualHost *:80> # httpでアクセスした場合はhttpsに書き換える RewriteEngine On RewriteCond %{REQUEST_URI} !^/\.well\-known/acme\-challenge/ RewriteRule ^.*$ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,QSA,L] </VirtualHost> SSLの設定 SSLを設定します(/etc/httpd/conf.d/ssl.conf)。 $ sudo vim /etc/httpd/conf.d/ssl.conf #Listen 443 …<省略>… # SSL設定 SSLCertificateKeyFile /etc/pki/tls/private/server.key SSLCertificateFile /etc/pki/tls/private/server.crt テストページの無効化 Apache HTTPのテストページ(/etc/httpd/conf.d/welcome.conf)をコメントアウトして無効化します。 $ sudo vim /etc/httpd/conf.d/welcome.conf # # This configuration file enables the default "Welcome" page if there # is no default index page present for the root URL. To disable the # Welcome page, comment out all the lines below. # # NOTE: if this file is removed, it will be restored on upgrades. # #<LocationMatch "^/+$"> # Options -Indexes # ErrorDocument 403 /.noindex.html #</LocationMatch> …<省略>… Apache Tomcatの設定 サーバ設定 Apache Tomcatサーバを設定します(/usr/share/tomcat/conf/server.xml)。http1.1通信無効化とlocalhostの8009番ポートからの※AJP1.3 通信を受け付けています。 …<省略>… <!-- <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" maxParameterCount="1000" /> --> …<省略>… <Connector protocol="AJP/1.3" address="127.0.0.1" port="8009" redirectPort="8443" maxParameterCount="1000" secretRequired="false" /> ※AJP (Apache JServ Protocol):Apache tomcat 通信プロトコル 参考:ApacheとTomcatの連携 5 環境設定 Apache Tomcatの環境を設定します(/usr/share/tomcat/conf/tomcat.conf)。 Apache TomcatとJavaのディレクトリがデフォルトから異なる場合は設定の変更が必要です。 以下はデフォルト設定となります。 # Where your java installation lives JAVA_HOME="/usr/lib/jvm/jre" # Where your tomcat installation lives CATALINA_HOME="/usr/share/tomcat" 管理者用Webアプリの設定 管理者用Webアプリを設定します(/usr/share/tomcat/conf/tomcat-users.xml)。 ここでは、管理者用Webアプリのログイン情報を設定します。 managerを含むロール名はmanagerアプリに、adminを含むロール名はhost-managerアプリに対応します。 以下の例ではadminユーザはmanagerアプリとhost-managerアプリに、managerユーザはmanagerアプリにログインできます。 $ sudo vim /usr/share/tomcat/conf/tomcat-users.xml <role rolename="admin"/> <role rolename="admin-gui"/> <role rolename="admin-script"/> <role rolename="manager"/> <role rolename="manager-gui"/> <role rolename="manager-script"/> <role rolename="manager-jmx"/> <role rolename="manager-status"/> <user name="admin" password="admin_password" roles="admin,manager,admin-gui,admin-script,manager-gui,manager-script,manager-jmx,manager-status" /> <user name="manager" password="manager_password" roles="manager,manager-gui,manager-script,manager-jmx,manager-status" /> </tomcat-users> 名前解決設定 FQDNでWebサーバにアクセスできるようにするために名前解決を設定します。今回はクライアントPC(Windows)のhostsファイルを編集します。 C:\Windows\System32\drivers\etc\hosts <WebサーバのIPアドレス> user.example.com <WebサーバのIPアドレス> manager.example.com サービス起動・自動起動有効化 Apache HTTPとApache Tomcatのサービス起動および自動起動を有効化します。 $ sudo systemctl start httpd $ sudo systemctl enable httpd $ sudo systemctl start tomcat $ sudo systemctl enable tomcat Webサイト確認 FirefoxでWebページにアクセスします。 アクセスする際には自己署名証明書のために警告が発生しますが、このまま使用します。 管理者側Webサイト 管理者側Webサイトにアクセスできることを確認します。 https://manager.example.com/home ここで「Manager App」を選択し、管理者用Webアプリ設定(tomcat-users.xml)のユーザー名とパスワードを入力します。 https://manager.example.com/manager にアクセスできることを確認します。 https://manager.example.com/home で「Host Manager」を選択し、管理者用Webアプリ設定(tomcat-users.xml)のユーザー名とパスワードを入力した後に「Host Manager」にアクセスできることを確認します。 https://manager.example.com/home で「Documentation」を選択し、ドキュメントページにアクセスできることを確認します。 利用者側Webサイト 利用者側Webサイトにアクセスできることを確認します。 https://user.example.com/sample/ さいごに 今回は、Apache HTTPとApache Tomcatを連携するWebサーバの構築手順について紹介しました。 サーバの構築において少しでも参考になれば幸いです。 参考 SAN付き自己署名証明書: https://qiita.com/nis_d1ce1984/items/b8f87d41ea108d47af61 ︎ Virtual Hostの設定: http://httpd.apache.org/docs/2.4/en/vhosts/name-based.html ︎ SSLモジュールの設定: https://httpd.apache.org/docs/2.4/ja/mod/mod_ssl.html ︎ Mozilla SSL Configuration Generator: https://ssl-config.mozilla.org/ ︎ ApacheとTomcatの連携: https://qiita.com/xyz666/items/387251d0aee41a25fec1 ︎ ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Apache HTTPとApache Tomcatを連携するWebサーバを構築してみた first appeared on SIOS Tech. Lab .
アバター
こんにちはアプリチームの織田です 12月7日に開催された OSC福岡 に参加してきました。前回の広島に続き面白かった展示の紹介を行いたいと思います。前回のブログは コチラ から閲覧できます。   Japanese Raspberry Pi Users Group Japanese Raspberry Pi Users Group さんは、Raspberry Piを駆使した様々なプロジェクトを展開しているコミュニティです。こちらの展示では、リアルタイム物体検出機能を備えた革新的な小型カメラに興味をひかれました。 このカメラの最大の特徴は、動画撮影と物体検出のプロセスを同時に行える点にあります。従来の物体検出システムでは、撮影した動画をRaspberry Pi本体やクラウド上で処理する必要がありました。しかし、この小型カメラは検出処理をカメラ側で完結させることで、Raspberry Piへの負荷を大幅に軽減し、リアルタイムでの物体認識を可能にしています。結果として、遅延の少ないスムーズな物体検出を実現しています。 この技術の応用範囲は幅広く、特にドローンやロボットといった、瞬時の判断と動作が求められる分野での活躍が期待できるかと感じました。例えば、ドローンによる空撮中にリアルタイムで障害物を検知し、自動で回避するといった機能の実装が可能になります。 Japanese Raspberry Pi Users Groupさんの展示は、Raspberry Piの可能性をさらに広げる、革新的な技術の一端を垣間見せてくれるものでした。 ラズベリーパイと物体検出を行うカメラ(ソニーIMAX500)   さくらインターネット さくらインターネット さんは、サーバーレンタル事業を展開している企業で、特に学生や研究者にとって馴染み深い存在です。今回のOSC福岡では、新しいレンタルGPUサーバープランの紹介をされていました。 従来のプランは月額課金制で、その費用は200万円から300万円程度と高額でした。これは主に企業や団体をターゲットにしたもので、個人や研究室にとっては利用のハードルが高いものでした。しかし、今回発表された新プランは、実際にGPUを使用した時間単位での課金となるため、大幅なコスト削減が可能となりました。具体的には、モデルの種類によって価格は変動しますが、1秒あたり0.06円や0.28円といった低価格での利用が可能となっています。この従量課金制により、必要な時に必要な分だけGPUを利用できるため、「ちょっとGPUサーバー触ってみたいな~」というライトユーザーからヘビーユーザーまで、幅広い層にとって魅力的な選択肢となっています。 私自身、大学時代には研究室でGPUサーバーを利用していましたが、他のユーザーが高負荷な処理を実行すると、自分の作業に支障が出るという問題がありました。しかし、このレンタルGPUサーバーを利用すれば、そのような問題を解消し、より快適な研究環境を実現できるのではないかと期待しています。 さくらインターネットさんの新プランは、GPUを利用したいと考えている個人や研究者にとって、非常に魅力的な選択肢となるのではと感じました。これにより、GPUを使った研究や開発がより身近なものとなり、新たなイノベーションが生まれる可能性も広がると期待されます。 さくらインターネットさんの展示ブースの様子 Divers Project  Divers Projectさんは、移動困難者が安心して街を歩けるよう、バリアフリールートを共有するアプリを開発している学生団体です。OSC福岡の展示では、開発中のアプリの詳細について紹介されていました。 このアプリの最大の特徴は、ユーザーが実際に歩いたバリアフリーな道の情報を共有できる点にあります。一般的な地図アプリでは、段差や狭い通路などの情報は表示されず、バリアフリーマークがあっても、実際に車椅子で通行できるかは分かりません。このアプリは、そうした課題を解決するために、ユーザーが実際に体験した情報を共有することで、本当にバリアフリーなルートを見つけ出すことを目指しています。 展示では、アプリのデモ画面や機能の説明があり、実際にどのようにルートを共有し、検索できるのかを体験することができました。また、開発チームのメンバーが、アプリに込めた思いや今後の展望について熱心に語っていました。彼らの「移動困難者がもっと自由に街を歩けるようにしたい」という強い思いが伝わってくる展示でした。 このアプリが普及すれば、移動困難者が安心して外出できるようになり、社会全体のバリアフリー化が進むことが期待されます。Divers Projectさんの活動は、まさに「多様な人々が共に生きる社会」を実現するための重要な一歩だと感じました。また、学生団体さんが積極的にこうした課題解決を行っている様子から非常に活力をもらいました。 Divers Mapの説明用ポスター 南島原市DX推進コンソーシアム 南島原市DX推進コンソーシアムさんの展示は、アスパラガスの等級判定を自動化するシステムの紹介でした。アスパラガスの等級は、その先端部分の形によって決まるのですが、従来はこの選別作業を手作業で行っていたため、多くの時間と労力を要していました。 このシステムでは、アスパラガスの画像を撮影し、画像処理技術を用いて先端部分の形を分析することで、等級を自動的に判定します。具体的には、撮影された画像を白黒に変換し、アスパラガスの輪郭を抽出します。そして、その輪郭情報をもとに、アスパラガスの先端部分の形を数値化し、あらかじめ設定された基準と照らし合わせることで、等級を判定します。 展示では、実際にアスパラガスをカメラにかざして、等級を判定するデモが行われていました。このシステムの導入により、選別作業の効率化だけでなく、判定の精度向上も期待できるため、アスパラガス農家の生産性向上に大きく貢献することが期待されます。 このシステムを見た感想としては、アスパラガスだけでなく、他の農作物の等級判定にも応用できるのではないかと感じました。 余談ですが、展示に足を運んだ際に、南島原市特産のそうめんをいただきました。大変美味しいそうめんでした、ありがとうございました。 ブースで実際にアスパラガスの等級判断をしている様子 TOPPERSプロジェクト TOPPERSプロジェクトさんの展示では、耕運機の自動運転技術の開発に焦点を当てていました。プロジェクトの目的は、中山間地における耕作放棄地の増加という深刻な問題に対処することです。中山間地では、狭くて段差のある土地が多く、大型のトラクターでの耕作が困難なケースが頻繁に見られます。一方、耕運機はそうした悪条件下でも作業が可能ですが、農業従事者の高齢化と人手不足が深刻化しているため、手動での耕運機の操作も困難になってきています。そこで、TOPPERSプロジェクトさんは耕運機の自動運転技術を開発することで、この問題の解決を目指しています。 展示では、実際に自動運転のテストを行っている様子を撮影した動画が紹介されていました。動画を見る限り、耕運機は左右の方向転換を含めて自律的に走行しており、実用化に向けて着実に進展している印象を受けました。TOPPERSプロジェクトさんの取り組みは、耕作放棄地の再生だけでなく、農業における労働力不足の解消にも大きく貢献することが期待されます。今回提案された技術が、中山間地の農業を活性化し、持続可能な農業を実現するための鍵となるかもと感じました。 プロジェクト内容をまとめたポスター   感想 今回のOSC福岡も、様々な団体や企業による興味深い展示が多く、非常に刺激的なイベントでした。特に、Raspberry Piを使ったリアルタイム物体検出カメラや、さくらインターネットの従量課金制GPUサーバー、そしてバリアフリー情報共有アプリやアスパラガス等級判定システムなど、社会の課題解決に貢献するような展示が多く見られました。 これらの展示を見て、テクノロジーの進化が私たちの生活をより便利に、そして豊かにする可能性を改めて感じました。同時に、学生団体が積極的に技術を活用し、社会課題の解決に取り組んでいる姿に感銘を受けました。 今後もOSCのようなイベントを通じて、最新の技術動向に触れ、多くの人々と交流を深めていきたいと考えています。そして、私自身も技術者として、社会に貢献できるようなサービスやプロダクトの開発に携わっていきたいと改めて感じました。 最後に、OSC福岡の関係者の皆様、そして展示に参加された皆様、本当にありがとうございました。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 2024年OSC福岡_展示内容紹介 first appeared on SIOS Tech. Lab .
アバター