サイオステクノロジー(Tech.Lab)のブログ - TECH PLAY

TECH PLAY

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

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

672

こんにちは。サイオステクノロジーの木村です。 今回は、Flutterの環境構築(Macでの手順)から Hello World を表示するまでを書きたいと思います。 コードエディタにはVisual Studio Codeを使います。Visual Studio Codeのインストール手順は含んでおりませんのでインストールしていない方は事前にインストールしておいてください。 Flutterとは Googleが開発したオープンソースのアプリケーション開発用フレームワーク。Dart言語を使用し、単一のコードベースでiOSやAndroid、Web、デスクトップアプリ など様々なプラットフォームのアプリを構築できます。 環境構築 Macでの環境構築の手順を記載します。 拡張機能のインストール VSCodeにて、Flutterの拡張機能をインストールします。 1. VSCodeを起動し、サイドバーの拡張機能のアイコンをクリックします。 2. 「Flutter」と入力すると、検索結果に表示されますので、「インストール」をクリックします。 Flutterをインストールすると、「Dart」の拡張機能も自動でインストールされます。 Flutter SDK のインストール VSCodeにて、Flutter SDK をインストールします。 1. VSCodeにて、メニューバーより「表示」-「コマンドパレット」をクリックしてコマンドパレットを開きます。 2. コマンドパレットにて「flutter」と入力すると、「Flutter:New Project」が表示されるので、選択します。 3. 以下の画像のような SDK のダウンロードを促すプロンプトが表示されますので、「Download SDK」をクリックします。 4. 任意のフォルダを指定し「Clone Flutter」をクリックします。 指定したフォルダ配下に、「flutter」というフォルダが作成されます。こちらのパスをメモしておきます。(メモしたパスは、以降の Path の設定の手順で使います。) Path の設定 FlutterのPathを通します。 1. お使いの Mac のシェルを確認します。ターミナルを起動し、以下のコマンドを実行します。 echo $SHELL 「/bin/zsh」と表示された場合、シェルは zsh です。 「/bin/bash」と表示された場合、シェルは bash です。 2. 以下のコマンドを入力して Path の設定を行います。(以下はシェルが「zsh」の場合のコマンドです。お使いの環境が「bash」の場合は .zshrc のところを .bash_profile としてください。) echo export PATH="$PATH: /bin" >> ~/.zshrc 3. 以下のコマンドを実行して設定を反映させます。(以下はシェルが「zsh」の場合のコマンドです。お使いの環境が「bash」の場合は .zshrc のところを .bash_profile としてください。) source ~/.zshrc 4. ターミナルにて、「flutter」と入力して以下のように表示されれば、Path の設定は完了です。 Android Studio のインストールと設定 1. Android Studio の公式サイト にアクセスします。 2. 「Android Studio Koala をダウンロード」をクリックします。 3. 利用規約の同意にチェックを入れ、お使いの Mac が使用しているチップに応じたもの(チップが「intel」の人は Intel を、「Apple M1」「Apple M2」の人は Apple をダウンロード)をダウンロードします。 お使いの Mac が使用しているチップは、画面の左上にあるメニューバーのAppleアイコンをクリックし、[このMacについて]より確認することができます。 4. ダウンロードしたファイルを開き、案内通りにインストールを進めます。 5. インストールが完了したら、Android Studio を開きます。 6. 画面左の[Plugins]をクリックし、検索欄に「flutter」と入力します。Flutterが検索結果に表示されるので「Install」をクリックします。 7. 「Restart IDE」をクリックします。 8. 「Restart」をクリックします。 9. Android Studio が再起動されます。「More Actions」より「SDK manager」をクリックします。 10. 「SDK Tools」タブを選択し、「Android SDK Command-line Tools」にチェックを入れ、「Apply」をクリックします。 11. 確認ダイアログが表示されますので「OK」をクリックします。 12. 「Finish」をクリックします。 13. ターミナルを起動し、以下のコマンドを実行します。 flutter doctor --android-licenses 何度か確認メッセージが表示されますので、全て「y」を入力します。 以下のメッセージが出れば完了です。 XCode のインストール 1. App Store を起動します。 2. App Store の検索欄に「xcode」と入力し検索します。検索結果に XCode が表示されますので「入手」をクリックしてインストールします。以降は案内通りにインストールを進めます。 Google Chrome のインストール Google Chrome の公式サイト より、ダウンロードしてインストールします。 flutter doctor で確認 環境構築が正しく行えているか確認します。 ターミナルを起動し、以下のコマンドを入力します。 flutter doctor 以下のように、全て緑のチェックマークが表示されれば、完了構築完了です。 「!」や、「×」が表示された場合は、環境に何らかの問題があります。表示されるメッセージの内容に従って対応しましょう。 サンプルアプリで動作確認 VSCodeにて、サンプリアプリを動かしてみましょう。 プロジェクトの作成 1. VSCodeにて、メニューバーより「表示」-「コマンドパレット」をクリックしてコマンドパレットを開きます。 2. コマンドパレットにて「flutter」と入力すると、「Flutter:New Project」が表示されるので、選択します。 3. 「Application」を選択します。 4. 作成するプロジェクトをどこに配置するか聞かれるので、任意のフォルダを選択して「Select a folder to create the project in」をクリックします。 5. 任意のプロジェクト名を入力します。ここでは「flutter_hello_world」とします。 6. プロジェクトの作成が完了すると、以下のように表示されます。 カウンターアプリの実行 作成したプロジェクトにはデフォルトでサンプルアプリとして「カウンターアプリ」の実装が含まれています(lib 配下の main.dart というファイルに記載されています)。まずはこちらをビルドし、動作させてみましょう。 1. 画面右下の「macOS(darwin)」をクリックします。 2. 今回は、iOSのシミュレータで立ち上げます。「Start iOS Simulator」を選択します。 3. シミュレータが立ち上がります。 4. サイドバーの「実行とデバッグ」のアイコンをクリックします。 5. 「実行とデバッグ」をクリックします。 6. シミュレータにて、カウンターアプリが立ち上がります。 右下の「+」をタップすると、画面中央に表示される数字がカウントアップされます。 7. アプリの実行を終了するには、赤い四角のボタンをクリックします。 Hello World 先ほどのカウンターアプリを変更して、Hello World を表示するようにしてみましょう。 「main.dart」の実装を以下のように修正します。 import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'My App', theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue), useMaterial3: true, ), home: const MyHomePage(), debugShowCheckedModeBanner: false, ); } } class MyHomePage extends StatelessWidget { const MyHomePage({super.key}); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Home'), backgroundColor: Theme.of(context).colorScheme.primaryContainer, ), body: const Center( child: Text( 'Hello, World!', style: TextStyle(fontSize: 24,), ), ), ); } } 以下、コードの簡単な説明です。 3〜5行目 Flutterアプリでは、lib配下にある「main.dart」ファイルの main 関数がエントリーポイントとなり、ここからアプリが開始されます。 runApp 関数には、アプリケーションのルートウィジェット(アプリ上で最初に展開して欲しいウィジェット)を指定します。ここでは MyApp を呼び出しています。 7〜22行目 MyAppでは MaterialApp というウィジェットで、アプリケーション全体の基本的な設定と構造を定義しています。画面の中身の部分は MyHomePage を呼び出しています。 debugShowCheckedModeBanner: false, と記載すると、画面右上に表示されるDEBUGバナーを非表示にします。 24〜42行目 MyHomePageでは、アプリバーの表示と、「Hello, World!」の文字を画面中央に表示するようにしています。 実行すると、以下のような画面が表示されます。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 【Dart】 Flutter × VSCode で、環境構築 から HelloWorld まで(Mac) first appeared on SIOS Tech. Lab .
こんにちは。サイオステクノロジーの塙です。 今回は、OpenShift(以下、OCP)上で、VMを実行するための機能となるOpenShift Virtualization(以下、OCP Virt)について説明したいと思います。 前提情報 本記事では、現時点では、以下のバージョンを対象としています。 ■バージョン OpenShift v4.15 OpenShift Virtualization v4.15 *1 *1 OCP Virt のバージョンは、v4.8 から OCP と同じになり、OCPと同様に推移していきます。 https://access.redhat.com/support/policy/updates/openshift_operators 概要 OCP Virt は、OCP 上で VM を動作、管理するためのコンポーネントとなります。 OCP Virt は OCP v4.5 から GA となり、OCP WebUI の OperatorHub から OCP Virt の Operator をインストールすることで利用可能となります。 サブスクリプション は、OCP のサブスクリプションで利用できるようになります。 また、OCP Virt は CNCF の Incubating Project である KubeVirt を利用して開発されているようです。 https://www.cncf.io/projects/kubevirt/ 休暇 アーキテクチャの基礎部分 VM を動作させる仕組みとして KVM を使用します。 KVM が RHCOS のカーネルで実行され、QEMU、libvirt はコンテナの内部で実行される形式となります。 概要では、Kubernetes の他の Pod と同様に、以下の枠組みを使用します。 CNI CSI CRD 内部のコンポーネント VM を動作させるには、主に3つのコンポーネントがあります。 ( Building a unified hybrid cloud strategy with Red Hat OpenShift Virtualization  より 引用) virt-controller :CRD で定義された VM リソースを監視し、VM リソースの Pod をノードに割り当てる virt-handler :各 Worker ノードで実行される DaemonSet。API や virt-controller と連携して、Pod の作成などの操作を、virt-launcher に指示する役割がある virt-launcher :libvirtd と連携し、VM の作成や削除を制御する VM のリソース VM のリソースは Kubernetes の CRD を用いて定義を行う形となります。 # VMリソースの例 apiVersion: kubevirt.io/v1alpha3 kind: VirtualMachine metadata: label: app: demo name: test-vm spec: dataVolumeTemplates: - metadata: name: example-dv spec: pvc: accessModes: - ReadWriteOnce resources: requests: storage: 1G source: http: url: "" running: false template: spec: domain: devices: disks: - name: containerdisk disk: bus: virtio interfaces: - masquerade: {} name: default resources: requests: memory: 1024M networks: - name: default pod: {} volumes: - name: containerdisk containerDisk: image: kubevirt/fedora-cloud-container-disk-demo VirtualMachine(VM)リソース:VMIを作成するためのテンプレートを構成するリソース VirtualMachineInstance(VMI) リソース:VM リソースの定義の、稼働中の実態を表すインスタンスのリソース VirtualMachineInstanceMigration リソース:VM をライブマイグレーションするときに構成するリソース DataVolume(DV) リソース:VM のディスクイメージなどのストレージ側の設定を定義するリソース サポート対象のノードと OS サポート対象のノード VM を動作させるノードは、ベアメタルになります。 OCP Virt の サポート対象 のクラスターノードは以下のとおりです。 ブレインメタルサーバー AWS ベアメタル インスタンス IBM Cloud ベアメタルサーバー (TechPreview機能) サポート対象のOS VM の OS としてサポート対象となっている OS が確認できます。 https://access.redhat.com/articles/973163#ocpvirt 参考までに、rhel OS のライセンスは OCP に含まれており、Windows は別途ライセンスが必要になります。 利用のポイント OCP Virt の利用を考える時のポイントを以下に記載していきます。 1. VM管理のメリット VM のディスク、ネットワークなどのリソース定義は、OCP の Pod と同様に、yaml ファイルのマニフェストで管理出来る形になっています。VM 自体を IaC で管理することで、ある程度 VMの管理自体もしやすく、自動化出来る部分もあるのではないでしょうか。 例えば、現在コンテナ環境も運用されており、コンテナ運用を見据えた取り組みをしたいという考えがある場合は、VM と コンテナの運用管理を統一することができ、効率化を図ることができます。 2. コンテナ環境とシームレスに接続 Kubernetes の仕組みとして CSI(Container Storage Interface)*1、CNI(Container Network Interface)*2 を他のPodと同じように使用できます。 これは、VM と Pod 間で通信を行いたいときに、ネットワークがクラ​​スター内で完結できることを意味します。 そして、他のPodの通信方法と同じように、通信の際のVMのIPを意識せずに良いという所もポイントとなります。ただ、IPを指定して通信を行いたいといった要件の場合は、少し難点があるかもしれません。 *1 CSI(Container Storage Interface):異なるストレージ技術を利用してコンテナに永続的なストレージを提供する仕組み *2 CNI(Container Network Interface): コンテナ間でのネットワーク接続を管理するためのプラグインを提供する仕組み 3. 他環境からのマイグレーションや、稼働中の変更時のダウンタイム OCP Virt は、MTV というツールを用いて、他の VM 環境から VM をマイグレーションすることが可能です。 これは非常に便利な機能ですが、注意点が一つあります。 現時点では、他環境からマイグレーションをするときに VM のダウンタイムが発生します。移行規模にもよりますが、ダウンタイムを考慮した移行を計画する必要があります。 また、OCP Virt で稼働中のリソースを変更する場合、マニフェストを変更、適用する形となります。マニフェスト適用後に Pod の再起動が発生するので、VM のリブートでダウンタイムが発生することを考慮する必要があります。 まとめ 今回は、OpenShift(以下、OCP)上で、VMを実行するための機能となるOpenShift Virtualization(以下、OCP Virt)について説明しました。 また、より詳細のOCP Virt の機能について紹介出来ればと思います。 本書の記載が読者のお役に立てば幸いです。 参考文献 https://docs.redhat.com/ja/documentation/openshift_container_platform/4.15/html-single/virtualization/index OpenShift Virtualization ( Kubevirt ) でVM管理もCloud Nativeに (1) OpenShift Virtualization、コンテナ基盤で仮想マシンを動かす ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post OpenShift Virtualization – OpenShift でのVM管理についてご紹介 first appeared on SIOS Tech. Lab .
こんにちは。サイオステクノロジーの塙です。 今回はEKS上でGPUを扱う生成AIソリューションのデプロイを試し、実際にGPUがどう使われてどう見えるのかを検証してみたいと思います。 概要 前回は、Kubernetes をベースとしたプラットフォームでGPUを扱っていくための手法について解説してみました。 KubernetesでGPUを扱うためにはどんな準備が必要となるのか、またどんな設定をすれば良いかをまとめています。 ■前回の記事はこちら KubernetesでGPUを使用する   前回までの記事は机上ベースでのまとめをしていたため、今回はEKSを用いて、実際にGPUの設定がどう見えるのかについてまとめてみました。 導入 EKS上での検証は以下の記事を参考にしています。 まずこの記事の内容を参考にして導入していきます。 https://aws.amazon.com/jp/blogs/containers/deploy-generative-ai-models-on-amazon-eks/   ■ 検証の概要 上記記事では、EKSに生成AIソリューションをデプロイします。 JARK Stack と呼ばれるモデルの構築と実行に利用出来るツールを用いており、アーキテクチャとしては、JupyterHub, Argo Workflows, Ray Serve, Kubernetes を指しています。(アーキテクチャの詳細は記事をご参考ください) 今回、それぞれのツールの詳細は割愛していますが、生成AIソリューションの構成時に使用するツール群の調査も追々行っていけたらと思います。 この時使用する生成AIは、 Stable Diffusion というText-to-Imageの画像生成AIの拡散モデルを使用しています。 また、 DreamBooth という特定の対象を事後学習させる学習方法を用いてトレーニングを行い、モデルを作成する一連の工程をEKSのPodで行っている形となります。   ■ 前提情報 検証に必要な前提は以下となります。(バージョンは検証時のバージョン) AWS CLI v2.11.13 kubectl Client Version: v1.24.1 Kustomize Version: v4.5.4 Server Version: v1.29.5-eks-1de2ab1 Terraform v1.8.4 helm v3.13.1 Hugging Face のトークン jq v1.6   検証準備 Aの記事の「Steps to deploy Stable Diffusion Model on Amazon EKS」から順次行っていきます。 1. data-on-eks のGitリポジトリをクローンします $ git clone https://github.com/awslabs/data-on-eks.git 2.ブループリントをデプロイします ai-ml/jark-stack/terraformのブループリントまで移動して、./install.sh スクリプトを実行して、terraformで生成AIソリューションを構築していきます。今回の構築用に不要なアドオンの削除、インスタンスタイプ、VPCネットワークなどを少し修正しデプロイを行います。デプロイは30分ほどかかるので完了するまで少し待ちます。 下記では、Hugging Faceのトークンを使用するためファイルのダミートークンを置き換える内容を加えています。 $ cd data-on-eks/ai-ml/jark-stack/terraform # 必要に応じて、不要なアドオンの削除、インスタンスタイプ、VPCネットワークなどを修正 ..(snip).. # 必要に応じて、Hugging face tokenの修正 # data-on-eks/ai-ml/jark-stack/terraform/variables.tf variable "huggingface_token" { description = "Hugging Face Secret Token" type = string default = "DUMMY_TOKEN_REPLACE_ME" ## hugging face token に置き換える sensitive = true $ ./install.sh 3. 記事と同じように、Stable Diffusion モデルの調整を行っていきます $ kubectl get svc proxy-public -n jupyterhub --output jsonpath='{.status.loadBalancer.ingress[0].hostname} k8s-jupyterh-proxypub-xxx.elb.us-west-2.amazonaws.com 出力されたDNS ホスト名をWebブラウザ経由で開き、jupyterhubを起動します。 jupyterhub-values.yamlに記載されているユーザー名とパスワードを使用してログインします。(これにより新規のPodが立ち上がります) # jupyter-xxx1 が立ち上がっていることを確認する $ kubectl get pods -n jupyterhub NAME READY STATUS RESTARTS AGE continuous-image-puller-d4tqs 1/1 Running 0 90m continuous-image-puller-m6ccv 1/1 Running 0 90m hub-64f87f44dd-xlhd2 1/1 Running 0 90m jupyter-admin1 1/1 Running 0 15m proxy-8685586d98-wklvw 1/1 Running 0 90m 起動すると、Jupyter Notebook のコンソールにリダイレクトされるので、記事に従い Notebookで提供されているPythonを実行していきます。(Pythonの実行に関しては、ここでは割愛) ここまでで今回の趣旨の準備段階が完了です。以降からデプロイ後の構成でGPUを確認していきます。 確認内容 それぞれいくつかの観点で設定の確認を行っていきます。   ■ nvidia-device-plugin の確認 nvidia-device-plugin の確認を行うと、いくつかのリソースが動作していることが分かります。 $ kubectl get all -n nvidia-device-plugin NAME READY STATUS RESTARTS AGE pod/nvidia-device-plugin-gpu-feature-discovery-pkfff 1/1 Running 0 75m pod/nvidia-device-plugin-node-feature-discovery-master-568b4977kb2j 1/1 Running 0 76m pod/nvidia-device-plugin-node-feature-discovery-worker-8gddp 1/1 Running 1 (76m ago) 76m pod/nvidia-device-plugin-node-feature-discovery-worker-xf9mp 1/1 Running 1 (76m ago) 76m pod/nvidia-device-plugin-qwm44 1/1 Running 0 75m NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/nvidia-device-plugin-node-feature-discovery-master ClusterIP 10.100.136.70 <none> 8080/TCP 76m NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE daemonset.apps/nvidia-device-plugin 1 1 1 1 1 <none> 76m daemonset.apps/nvidia-device-plugin-gpu-feature-discovery 1 1 1 1 1 <none> 76m daemonset.apps/nvidia-device-plugin-node-feature-discovery-worker 2 2 2 2 2 <none> NAME READY UP-TO-DATE AVAILABLE AGE deployment.apps/nvidia-device-plugin-node-feature-discovery-master 1/1 1 1 76m NAME DESIRED CURRENT READY AGE replicaset.apps/nvidia-device-plugin-node-feature-discovery-master-568b497868 1 1 1 76m 今回用いた data-on-eks では、daemonsetであるnvidia-device-pluginと、付随の機能として備わっているgpu feature discovery(以下、gfd), node feature discovery(以下、nfd)が動作する形となっています。 gfdとnfdはそれぞれ以下の機能を持つものとなっています。 gfd nfdの一部であり、特にGPU関連の機能を検出するために用いるツールとなる nfd  Kubernetesの各ノードのハードウェア機能やカーネル機能などの属性を自動的に検出し、それらの情報をラベルとしてKubernetes APIに公開するツールとなる つまり、gfdとnfdがノードの機能を検出しラベルを付けることで、nvidia-device-pluginがそれらの情報を用いてGPUリソースを管理し適切なPodに割り当てることをしています。   またnvicia-device-pluginのログを確認してみると、GRPCを開始し、Kubeletに nvidia.com/gpu のデバイスプラグインを登録していることが分かります。 $ kubectl logs daemonset.apps/nvidia-device-plugin -n nvidia-device-plugin I0629 07:28:42.381694 1 server.go:165] Starting GRPC server for 'nvidia.com/gpu' I0629 07:28:42.382522 1 server.go:117] Starting to serve 'nvidia.com/gpu' on /var/lib/kubelet/device-plugins/nvidia-gpu.sock I0629 07:28:42.386109 1 server.go:125] Registered device plugin for 'nvidia.com/gpu' with Kubelet ※今回は対象外としていますが、NVIDIA GPU Operator には、gfdとNVIDIA デバイス プラグインの両方が含まれます。   ■ Podから使用しているGPUの見え方の確認 準備段階で立ち上げた、jupyter-xxx1の内容を見てみます。確かにPodからGPUのLimits, Requests でGPUを要求していることが確認出来ます。 $ kubectl describe pod jupyter-admin1 -n jupyterhub Containers: notebook: ..(snip).. Limits: nvidia.com/gpu: 1 Requests: memory: 5368709120 nvidia.com/gpu: 1   ■ EKSのノードからのGPUの見え方の確認 1. kubernetes のコマンドからGPUの見え方の確認 kubectl からノードの状態を確認してみます。 Capacity, Allocatable から nvidia.com/gpu: 1 が確認できます。実際にPodからGPUを消費すると、Allocated resourcesの nvidia.com/gpu の値も更新されるようになります。 $ kubectl get node NAME STATUS ROLES AGE VERSION ip-100-64-105-40.us-west-2.compute.internal Ready <none> 56m v1.29.3-eks-ae9a62a ip-100-64-150-241.us-west-2.compute.internal Ready <none> 56m v1.29.3-eks-ae9a62a # GPU搭載のノードをdescribeで出力 $ kubectl describe node ip-100-64-105-40.us-west-2.compute.internal ..(snip).. Capacity: cpu: 4 ephemeral-storage: 104845292Ki hugepages-1Gi: 0 hugepages-2Mi: 0 memory: 16069056Ki nvidia.com/gpu: 1 pods: 29 Allocatable: cpu: 3920m ephemeral-storage: 95551679124 hugepages-1Gi: 0 hugepages-2Mi: 0 memory: 15378880Ki nvidia.com/gpu: 1 pods: 29 Allocated resources: (Total limits may be over 100 percent, i.e., overcommitted.) Resource Requests Limits -------- -------- ------ cpu 180m (4%) 0 (0%) memory 5494538240 (34%) 768Mi (5%) ephemeral-storage 0 (0%) 0 (0%) hugepages-1Gi 0 (0%) 0 (0%) hugepages-2Mi 0 (0%) 0 (0%) nvidia.com/gpu 1 1 ..(snip)..   2. ノード上からnvidia-smi, deviceQueryコマンドでGPUの見え方の確認 AWS のセッションマネージャーから該当のノードにログインして確認してみます。 nvidia-smiコマンドでGPUの状態を出力すると以下のような情報が確認出来ます。この時、検証準備で行ったPythonアプリケーションを動作させているため、PythonのプロセスがGPUを使用していることが分かります。 また、deviceQueryコマンドを用いてGPUの情報が確認出来ます。 sh-4.2$ nvidia-smi Sat Jun 29 08:57:36 2024 +---------------------------------------------------------------------------------------+ | NVIDIA-SMI 535.183.01 Driver Version: 535.183.01 CUDA Version: 12.2 | |-----------------------------------------+----------------------+----------------------+ | GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |=========================================+======================+======================| | 0 Tesla T4 On | 00000000:00:1E.0 Off | 0 | | N/A 33C P0 32W / 70W | 14819MiB / 15360MiB | 21% Default | | | | N/A | +-----------------------------------------+----------------------+----------------------+ +---------------------------------------------------------------------------------------+ | Processes: | | GPU GI CI PID Type Process name GPU Memory | | ID ID Usage | |=======================================================================================| | 0 N/A N/A 90855 C /opt/conda/bin/python3.10 14816MiB | +---------------------------------------------------------------------------------------+ sh-4.2$ /usr/local/cuda-12.2/extras/demo_suite/deviceQuery /usr/local/cuda-12.2/extras/demo_suite/deviceQuery Starting... ..(snip).. Device 0: "Tesla T4" CUDA Driver Version / Runtime Version 12.2 / 12.2 CUDA Capability Major/Minor version number: 7.5 Total amount of global memory: 15102 MBytes (15835660288 bytes) (40) Multiprocessors, ( 64) CUDA Cores/MP: 2560 CUDA Cores GPU Max Clock rate: 1590 MHz (1.59 GHz) Memory Clock rate: 5001 Mhz Memory Bus Width: 256-bit L2 Cache Size: 4194304 bytes Maximum Texture Dimension Size (x,y,z) 1D=(131072), 2D=(131072, 65536), 3D=(16384, 16384, 16384) Maximum Layered 1D Texture Size, (num) layers 1D=(32768), 2048 layers Maximum Layered 2D Texture Size, (num) layers 2D=(32768, 32768), 2048 layers Total amount of constant memory: 65536 bytes Total amount of shared memory per block: 49152 bytes Total number of registers available per block: 65536 Warp size: 32 Maximum number of threads per multiprocessor: 1024 Maximum number of threads per block: 1024 Max dimension size of a thread block (x,y,z): (1024, 1024, 64) Max dimension size of a grid size (x,y,z): (2147483647, 65535, 65535) Maximum memory pitch: 2147483647 bytes Texture alignment: 512 bytes Concurrent copy and kernel execution: Yes with 3 copy engine(s) Run time limit on kernels: No Integrated GPU sharing Host Memory: No Support host page-locked memory mapping: Yes Alignment requirement for Surfaces: Yes Device has ECC support: Enabled Device supports Unified Addressing (UVA): Yes Device supports Compute Preemption: Yes Supports Cooperative Kernel Launch: Yes Supports MultiDevice Co-op Kernel Launch: Yes Device PCI Domain ID / Bus ID / location ID: 0 / 0 / 30 Compute Mode: < Default (multiple host threads can use ::cudaSetDevice() with device simultaneously) > deviceQuery, CUDA Driver = CUDART, CUDA Driver Version = 12.2, CUDA Runtime Version = 12.2, NumDevs = 1, Device0 = Tesla T4 Result = PASS   ■ ノードグループからGPUの状態を確認 AWS コンソールからGPUをどう使用しているか確認してみます。 結論から言うと、AWSコンソールからはラベルで情報の確認が出来る程度でした。CUDAに関する情報、GPUに関する情報が見える程度です。 GPUへの共有アクセス方法を試す デプロイ後の構成で、GPUへの共有アクセス方法も出来るか追加で試してみました。 GPUへの共有アクセス方法の設定は、以下の記事の内容を参考にして行っていきます。 https://aws.amazon.com/jp/blogs/containers/gpu-sharing-on-amazon-eks-with-nvidia-time-slicing-and-accelerated-ec2-instances/   ■ Time Slicing の設定 今回は、前回の記事で紹介した方法の中からTime Slicingを試してみたいと思います。 今回の nvidia-device-plugin はhelmでデプロイされているため、helm をアップグレードする方法で試します。 まずリポジトリを追加します。 $ helm repo add nvdp https://nvidia.github.io/k8s-device-plugin $ helm repo update Time Slicingを有効にする前のノードで利用できるGPUの数を確認します。 "nvidia.com/gpu": "1" とまだ利用出来る数は1つです。 $ kubectl get nodes -o json | jq -r '.items[] | select(.status.capacity."nvidia.com/gpu" != null) | {name: .metadata.name, capacity: .status.capacity}' { "name": "ip-xxx.us-west-2.compute.internal", "capacity": { "cpu": "4", "ephemeral-storage": "104845292Ki", "hugepages-1Gi": "0", "hugepages-2Mi": "0", "memory": "16069060Ki", "nvidia.com/gpu": "1", "pods": "29" } } nvidia-device-plugin の helmに渡すvalues.yamlとConfigMap の設定を行い、helm upgrade を行います。 $ cat nvidia-device-plugin-helm-values.yaml gfd: enabled: true nfd: worker: tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule - operator: "Exists" $ cat ndp_helm_upgrade.sh helm upgrade -i nvidia-device-plugin nvdp/nvidia-device-plugin \ --version=0.14.5 \ --namespace nvidia-device-plugin \ --values nvidia-device-plugin-helm-values.yaml \ --set config.name=time-slicing-config $ ./ndp_helm_upgrade.sh Time Slicing を行う設定をConfigMapとして投入します。今回はレプリカ数を4にして設定しています。 $ cat time-slicing-config.yaml apiVersion: v1 kind: ConfigMap metadata: name: time-slicing-config namespace: nvidia-device-plugin data: any: |- version: v1 flags: migStrategy: none sharing: timeSlicing: renameByDefault: false failRequestsGreaterThanOne: false resources: - name: nvidia.com/gpu replicas: 4 $ kubectl apply -f time-slicing-config.yaml ノードで利用できるGPUの数を確認します。 "nvidia.com/gpu": "4" と利用出来る数が増加したことを確認できます。 $ kubectl get nodes -o json | jq -r '.items[] | select(.status.capacity."nvidia.com/gpu" != null) | {name: .metadata.name, capacity: .status.capacity}' { "name": "ip-xxx.us-west-2.compute.internal", "capacity": { "cpu": "4", "ephemeral-storage": "104845292Ki", "hugepages-1Gi": "0", "hugepages-2Mi": "0", "memory": "16069060Ki", "nvidia.com/gpu": "4", "pods": "29" } }   ■ Time Slicing の確認 それでは、サンプルのアプリケーションを実行して、増加させたGPUのレプリカ数をどう使用するのか確認してみます。 サンプルのアプリケーションは、参考にした記事にある eks-gpu-sharing-demo を使用しています。今回はアプリケーションのレプリカ数は2に設定して適用しています。 $ kubectl create ns gpu-demonamespace/gpu-demo created $ kubectl apply -f example-train.yaml $ kubectl get pods -n gpu-demo NAME READY STATUS RESTARTS AGE tensorflow-cifar10-deployment-5df5f55756-k8vgp 1/1 Running 2 (3m50s ago) 6m57s tensorflow-cifar10-deployment-5df5f55756-l4wfm 1/1 Running 2 (3m50s ago) 6m57s sh-4.2$ nvidia-smi Fri Jun 28 07:53:07 2024 +---------------------------------------------------------------------------------------+ | NVIDIA-SMI 535.183.01 Driver Version: 535.183.01 CUDA Version: 12.2 | |-----------------------------------------+----------------------+----------------------+ | GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |=========================================+======================+======================| | 0 Tesla T4 On | 00000000:00:1E.0 Off | 0 | | N/A 39C P0 43W / 70W | 14903MiB / 15360MiB | 16% Default | | | | N/A | +-----------------------------------------+----------------------+----------------------+ +---------------------------------------------------------------------------------------+ | Processes: | | GPU GI CI PID Type Process name GPU Memory | | ID ID Usage | |=======================================================================================| | 0 N/A N/A 77803 C python 14074MiB | | 0 N/A N/A 78014 C python 826MiB | +---------------------------------------------------------------------------------------+ nvidia-smiコマンドで確認すると確かに、pythonのプロセスが2つ動作していることが確認出来ています。 Time Slicingを使用して、GPUへの共有アクセスを提供することを簡単に確認しました。   まとめ 今回は、EKS上でGPUを扱う生成AIソリューションのデプロイを試し、実際にGPUがどう使われてどう見えるのかをまとめてみました。 実際に検証してみることで、机上ベースより詳細な情報を確認することが出来ました。 また発展として、MLOpsなどを効率的に回していくための様々なツール群を調査してみるのも面白いと考えています。 本書の記載が読者のお役に立てれば幸いです。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post EKSで生成AIソリューションのデプロイを検証し設定を確認する first appeared on SIOS Tech. Lab .
はじめに こんにちは!5、6月と案件の対応や問い合わせが重なり他のタスクに支障が出てきているなーがです。社会人4年目ということで複数の案件にアサインされていますが、前職ではあまり意識していなかった工数の意識や技術力不足を日々痛感しています。。。 それはさておき、6/14(金)に開催されたOSS推進フォーラム 【第8回】定例テック&ビジネス勉強会~テーマ:SBOM に参加してきました。 参加から少し時間が経ってしまいましたが、イベントレポートをお送りします。今回のテーマは SBOM基礎編 ということで、2つの講演がありました。 登壇者と概要 サイオステクノロジー株式会社 佐々木 寛太さん タイトル: 開発者目線でのSBOMとの向き合い方 株式会社日立ソリューションズ ITプラットフォーム事業部 渡邊 歩さん タイトル: SBOM(ソフトウェア構成表)活用の現状と課題 1. 開発者目線でのSBOMとの向き合い方 1つ目の講演は弊社佐々木寛太が弊社におけるSBOMに関する取り組みやSBOMツールを組み合わせたCI/CDのデモを行いました。 弊社のSBOMに関する取り組みは こちら の記事を見てみてください! デモではSBOM作成ツールとして syft 、管理ツールとして Dependency-Track を使用しました。各ツールの説明や機能、導入方法については、下記の弊社ブログ記事を確認してください! アーキテクチャは以下の通りです。 あるアプリケーションに機能を追加するために使用するライブラリを追加する状況を想定しており、開発者が変更を加えたブランチをリポジトリにPushすると、GitHub Actionsにより以下のような流れで実行されます。 アプリケーションのDocker Imageを作成 Docker Imageをコンテナレジストリに登録 登録したDocker Imageをpull SyftでDocekr Imageを解析 解析結果をArtifactsに永続化 解析結果をDependency-Trackにアップロード 他人事ながら本番で動くかどうかドキドキしていましたが、無事実行されました。参加されていた方々にもSBOM導入の参考になったと思います。 2. SBOM(ソフトウェア構成表)活用の現状と課題 2つ目の講演は日立ソリューションズの渡邊 歩さんが登壇され、 経産省の手引き の内容についての解説をはじめ、世界の動向と日本の取り組みについての紹介をされていました。経産省の手引きの作成を手伝われた方だったので、手引き作成の背景や裏話も話されていました。 講演を通じての感想としてはアメリカやEUはSBOM標準化に向けた取り組みが進んでおり、日本はかなり遅れていると感じました。 しかし、医療機器に関しては他の産業と比較して特に進んでおり、薬機法改正によりSBOMの提出が義務化の流れに向かっているようです。 特に驚いたのは、EUでは EUサイバーレジデンス法 によりEU市場に投入される全てのデジタル製品に関してSBOMを作成することを義務づける予定であり、違反してた場合は1500万ユーロ(日本円で約20億)または全世界売上の2.5%の罰則があることでした。2025年後半の適用を目指しているようで、あと2年もありません。 また、ドイツ、韓国、中国では独自のSBOMフォーマットを作る動きがあるようでした。国防の観点から独自のフォーマットを作っているのではないかということでした。 まとめ 今回は6/14(金)に開催されたOSS推進フォーラム 【第8回】定例テック&ビジネス勉強会~テーマ:SBOMについて書きました。 個人的には講演の後にSBOMツール選定についての議論や各社の取り組みについて知る良い機会になったと思います。 次回 は8/2(金)でAI LT大会が開催されるそうなので、興味のある方は是非参加されてみてください! ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post OSS推進フォーラムSBOM勉強会参加レポート first appeared on SIOS Tech. Lab .
はじめに こんにちはPS/SLの佐々木です。 今回はgithubの草が生えてきたので蛇に食べてもらおうと思います。 設定 まず自分のアカウント名と同じ名前のリポジトリを作成してください。 スクリーンショット 2024-06-28 1.46.41.png 私は atomic-kanta-sasaki なのでこの名前のパブリックリポジトリを作ります。 以下Termialで実行してください。 $ mkdir img $ touch img/.keep$ mkdir -p .github/workflows $ vi GenerateSnake.yml 以下GenerateSnake.ymlに貼り付けてください name: GenerateSnake on: workflow_dispatch: schedule: - cron: "0 1 * * *"jobs: update-repository: name: Update this repo's README with repository_owner runs-on: ubuntu-latest permissions: contents: write steps: - name: Checkout uses: actions/checkout@v2 - name: Generate Snake uses: Platane/snk/svg-only@v3 id: snake-gif with: github_user_name: ${{ github.repository_owner }} outputs: | ./img/snake.svg ./img/snake-dark.svg?palette=github-dark - name: Push to GitHub uses: EndBug/add-and-commit@main with: # ブランチ名はデフォルトブランチ名にする(main or master) branch: main message: ':rocket: Update' $ vi README.md 最後にREADME.mdに <picture> <source media="(prefers-color-scheme: dark)" srcset="<https://raw.githubusercontent.com/obregonia1/obregonia1/master/img/snake-dark.svg>"> <source media="(prefers-color-scheme: light)" srcset="<https://raw.githubusercontent.com/obregonia1/obregonia1/master/img/snake.svg>"> <img alt="github contribution grid snake animation" src="<https://raw.githubusercontent.com/obregonia1/obregonia1/master/img/snake.svg>"></picture> これを貼り付ければおけ。 作成したリポジトリにpushすれば document.createElement('video'); https://tech-lab.sios.jp/wp-content/uploads/2024/06/atomic-kanta-sasaki-kanta.sasaki-Google-Chrome-2024-06-28-06-13-25.mp4 こんな感じで食べてくれます。 かわいいですね ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 2人がこの投稿は役に立ったと言っています。 The post Githubの草を蛇に食べさせる技術 first appeared on SIOS Tech. Lab .
こんにちは、サイオステクノロジーの佐藤 陽です。 今回は、RAGの評価ツールである Ragas の紹介をしたいと思います。 RAGに限らずですが、生成AIを使ったアプリは評価が難しいとよく言われます。 RAGに関しては、RagasというOSSが評価用のフレームワークが存在しており、 OpenAI社の発表 でも紹介されていました。 そこで今回は、「Ragasをとりあえず使ってみる!」というコンセプトで記事を書いていきたいと思います。 RAGを作ってみたはいいものの、システムの精度が分からない Ragas使ってみたいけど使い方がいまいち分からない といった方は、ぜひ最後までご覧ください! はじめに Ragasも既に色々なところで紹介されているのですが、 複雑なユースケースに組み込まれていたりしているケースも多くありました。 そこで Ragas単体の挙動や使い方を知りたい! とりあえずミニマムな感じで使ってみたい! という方向けに、 最小限の形でRagasを使い、使い方や評価項目について解説したいと思います。 なんなら今回の記事では、RAGの構築さえ行いません!! RAGが構築されていると仮定して、Ragasへの入力は仮で自前で用意していきます。 そのため今回の評価結果はまったく当てになりません 。 あくまで今回はRagasの概要と手法を学ぶだけです。 そんなチートな内容になっていますが、最後までご覧いただければ幸いです。 なお、今回はAzure OpenAI ServiceとRagasの組み合わせで評価を行っていきたいと思います。 Ragasとは 概要 簡単にRagasの紹介をします。 RagasはOSSとして公開されている、RAGのパイプラインを評価するためのフレームワークになります。 恐らくですが「ラグァス」と読みます。 RAGを構築するにあたっては 使用するLLMモデル チャンクのサイズ VectorStoreの検索方法 プロンプトの内容 など 決めるべきパラーメータが様々があり、その内容によってRAGの性能が決まってきます。 ただレスポンスが自然言語で返ってくることもあり、RAGを評価することはなかなか難しいとされています。 そこを定量的に評価してくれるのがRagasです。 おそらくRAGを評価する方法としてはかなりメジャーなフレームワークであり、 OpenAIの発表 のなかでも紹介されています。  評価方法 まずは何を評価対象(インプット)とするか、について解説したいと思います。 Ragasで評価を行う際に利用する evaluate関数 を見てみると、引数として dataset というオブジェクトを持ちます。 更にdatasetの中身を見ると、 question , contexts , answer , ground_truth の4つの値が含まれています。 この4つがRAGを評価するために利用されるパラメータになります。 それぞれについて解説します。 パラメータ 型 内容 question list[str] ユーザーがRAGに与えた質問 contexts list] RAGが回答を作成するにあたり、参照した情報 (VectorStoreなどの外部DBから、質問に関連した情報として取得された値(チャンク)) answer list[str] questionに対して、実際にRAGから返された回答内容 ground_truth list] questionに対する真の答え (これは評価前にユーザーが自前、もしくはRagasの機能等を利用して用意しておきます。) 評価項目 次に評価項目(アウトプット)を見ていきたいと思います。 表にまとめてみましたが、 正直なところ厳密に正しいかは自信がないです…。 公式ドキュメント の例や、計算方法を読むのが一番わかりやすいかと思います。 個人的にひとつポイントだと思った点としては、 正しい回答を行っていても答えが冗長だとスコアが低くなる点です。 正確かつ簡潔に答えるようにRAGを組み立てていく必要がありそうです。 評価項目 評価内容 評価対象 Faithfulness LLMによって生成されたanswerの内容をステートメントで区切り、それがcontextsの内容から推論できるかが評価されます。 contextsとanswer Answer relevancy LLMを利用して、answerから想定される質問を生成します(リバースエンジニアリング) そしてリバースエンジニアリングした質問と、questionの値のコサイン類似度が評価結果となります。 questionとanswer Context recall ground_truthの回答をステートメントで区切り、区切ったステートメントがcontextsの内容とどれくらい関連しているかが評価されます。 ground_truthの内容を網羅しているようなcontextであれば高いスコアが割り当てられます。 contextsとground_truth Context precision contextsの中にground_truthのワードが含まれ、なおかつそれが上位のチャンクとしてランキングされているかどうかを示します。 ground_truthのワードが上位のチャンクのcontexts中に含まれていると、高いスコアが割り当てられます。 ground_truthとcontexts Context relevancy ユーザーからのquestionに対して、どれだけ関連されたcontextsが取得されたかを表します。 questionと関連の高いcontextsが存在していればスコアが高くなります。 また、必要な情報が含まれていたとしても、冗長な内容が含まれている場合スコアは下がります。 questionとcontexts Context entity recall ground_truthとcontextsに含まれるエンティティ(ワード)にどの程度相関があるかを表します。 ground_truthに含まれるエンティティがcontextsにも多く含まれているほど高いスコアが得られます。 ground_truthとcontexts Answer semantic similarity ground_truthとanswerがどれだけ類似しているかを評価します。 それぞれの値をベクトル化し、これらのコサイン類似度を計算します。 ground_truthとanswer Answer correctness 得られた回答の正確さを評価します。 正確さは、回答が事実であるかという[factual similarity]という側面と、[answer semantic similarity(上記)]という側面の2つの面から評価が行われます。 factual similarityに関しては、ground_truthとanswerの内容の重複度に基づき計算します。 ground_truthとanswer また注意事項として 評価を行う際にChatの応答や、EmbeddingsなどAzure OpenAIの活用を多くしています。 Ragas自体はOSSなため利用にお金はかかりませんが、中の処理でLLMを利用しているため、むやみやたらに評価を行うとコストがかさむ可能性があります。 実装 評価対象および評価項目が分かったところで実際にRagasを使っていきます。 先程も述べた通り、今回はRAGのパイプラインは構築しません。 RAGを組んだつもりになって、自前で上記の評価対象のパラメータを作っていきます。 事前準備 今回は評価を行うにあたり、Azure OpenAI Service上にデプロイしたモデルを利用します。 AOAI上にChatモデルとEmbeddingsモデルをデプロイしておいてください。 サンプルドキュメント RAGを構築しないといっても何にも題材がないと分かりづらいため、RAGに与える文章をChatGPTに考えてもらいました。 架空のミュージシャンの内容なので、一般的なLLMは知る由もありません。 この内容に回答できるよう、RAGを構築していく。 といったケースを想定します。 名前: 白石 玲奈 (Shiraishi Rena) 年齢: 28歳 生年月日: 1996年3月15日 デビューした歳: 20歳 リリースしたアルバムと詳細: 1. 『青い夢』 (Blue Dream) - リリース日: 2016年5月20日 - 詳細: デビューアルバムであり、瑞々しい感性と透明感あふれるボーカルで話題を呼んだ。アルバムには、青春の儚さや未来への希望を描いた曲が多く収録されており、特に「君と見た空」がシングルカットされ大ヒットを記録。楽曲は全て自身が作詞作曲を手掛け、プロデューサーには有名音楽プロデューサーの田中亮を迎えた。 2. 『流星の詩』 (Meteor Poem) - リリース日: 2018年9月12日 - 詳細: セカンドアルバムで、より成熟した音楽性と深みのある歌詞が特徴。人生の様々な局面や感情を詩的に表現した楽曲が揃っており、「夜空に咲く花」がシングルとしてリリースされ、大人のリスナーからも支持を得た。アルバム全体を通じて、一貫したテーマとして「変化」と「成長」が描かれている。 3. 『永遠の一瞬』 (Eternal Moment) - リリース日: 2021年11月25日 - 詳細: 三枚目のアルバムでは、さらに多様な音楽ジャンルに挑戦。エレクトロニカやアンビエントなどの要素を取り入れ、新たなサウンドを追求している。特に「時の砂」が注目を集め、音楽チャートで長期間ランクイン。アルバムのテーマは「時間」と「記憶」であり、聴く者に深い感動を与える作品となっている。 生い立ち: 白石玲奈は、東京の下町で生まれ育つ。幼少期から音楽に親しみ、ピアノとギターを独学で学ぶ。中学生の時に初めて作曲を始め、高校生になると地元のライブハウスで演奏するようになる。高校卒業後、音楽専門学校に進学し、本格的に音楽理論やボーカルトレーニングを学ぶ。20歳の時に自主制作アルバムをリリースし、これがレコード会社の目に留まりプロデビューを果たす。彼女の音楽は、その透明感のある声と詩的な歌詞、そして心に響くメロディで多くのファンを魅了している。 出演したフェス一覧: 1. フジロックフェスティバル (2017, 2019, 2022) - 日本最大級の野外音楽フェスティバルに複数回出演。特に2019年にはメインステージでのパフォーマンスが大絶賛された。 2. サマーソニック (2018, 2021) - 国内外のアーティストが集う都市型音楽フェス。玲奈のパフォーマンスはエネルギッシュで、観客を魅了した。 3. ロック・イン・ジャパン・フェス (2018, 2020, 2023) - 日本最大のロックフェスティバルで、彼女のライブは毎回大きな話題となり、観客を熱狂させた。 4. コーチェラ・フェスティバル (2019) - アメリカ・カリフォルニアで開催される世界的な音楽フェスティバルに出演。日本人アーティストとして初めての参加で、海外でも注目を集めた。 5. グラストンベリー・フェスティバル (2022) - イギリスの伝統ある音楽フェスティバルに出演し、そのパフォーマンスが高く評価された。 白石玲奈は、その卓越した音楽センスとパフォーマンスで、国内外での評価を高め続けている。彼女の今後の活躍にも大いに期待される。 評価対象の準備 先程も述べた通り、Ragasへの入力は以下4つのパラメータです。 question contexts answer ground_truth それぞれの値を以下のように3パターン用意します。 ※くどいほど繰り返しますが、今回はすべてのパラメータをRAGやベクトルストアを使わず、仮想的に自前で用意しています。 case 1 「関連ドキュメントの参照が正しく行われ、回答内容も正しいケース」 contextsの取得が正しく行われており、それに基づくChat LLMの回答内容も正しいケースです。 question contexts answer ground_truth “白石 玲奈は何歳の時にデビューしましたか?” [ “名前: 白石 玲奈 (Shiraishi Rena) 年齢: 28歳 生年月日: 1996年3月15日 デビューした歳: 20歳 リリースしたアルバム 1 アルバム名: 『青い夢』 (Blue Dream) リリース日: 2016年5月20日 詳細: デビューアルバムであり、瑞々しい感性と透明感あふれるボーカルで話題を呼んだ。アルバムには、青春の儚さや未来への希望を描いた曲が多く収録されており、特に「君と見” , “の下町で生まれ育つ。幼少期から音楽に親しみ、ピアノとギターを独学で学ぶ。中学生の時に初めて作曲を始め、高校生になると地元のライブハウスで演奏するようになる。高校卒業後、音楽専門学校に進学し、本格的に音楽理論やボーカルトレーニングを学ぶ。20歳の時に自主制作アルバムをリリースし、これがレコード会社の目に留まりプロデビューを果たす。彼女の音楽は、その透明感のある声と詩的な歌詞、そして心に響くメロディで多くのファンを魅了している。出演したフェス一覧:フジロックフェスティバル (2” ] “白石 玲奈がデビューしたのは20歳の時です。” “20歳” case 2 「関連ドキュメントの参照が正しく行われているが、回答内容が正しくないケース」 contextsの取得が正しく行われているが、それに基づくChat LLMの回答内容が誤っているケースです。 question contexts answer ground_truth “2枚目にリリースしたアルバムのタイトルは何ですか?” [ “リリースしたアルバム 2アルバム名: 『流星の詩』 (Meteor Poem)リリース日: 2018年9月12日 詳細: セカンドアルバムで、より成熟した音楽性と深みのある歌詞が特徴。人生の様々な局面や感情を詩的に表現した楽曲が揃っており、「夜空に咲く花」がシングルとしてリリースされ、大人のリスナーからも支持を得た。アルバム全体を通じて、一貫したテーマとして「変化」と「成長」が描かれている。” , “の下町で生まれ育つ。幼少期から音楽に親しみ、ピアノとギターを独学で学ぶ。中学生の時に初めて作曲を始め、高校生になると地元のライブハウスで演奏するようになる。高校卒業後、音楽専門学校に進学し、本格的に音楽理論やボーカルトレーニングを学ぶ。20歳の時に自主制作アルバムをリリースし、これがレコード会社の目に留まりプロデビューを果たす。彼女の音楽は、その透明感のある声と詩的な歌詞、そして心に響くメロディで多くのファンを魅了している。出演したフェス一覧:フジロックフェスティバル (2” ] “2枚目にリリースされたアルバムのタイトルは「永遠の一瞬」です。” “『流星の詩』 (Meteor Poem)” case 3 「関連ドキュメントの参照が誤っており、回答内容が正しくないケース」 contextsの取得がうまくいっておらずが、それに伴いChat LLMの回答内容が誤っているケースです。 question contexts answer ground_truth “2019年に出演したフェスは何ですか?” [ “名前: 白石 玲奈 (Shiraishi Rena) 年齢: 28歳 生年月日: 1996年3月15日 デビューした歳: 20歳 リリースしたアルバム 1 アルバム名: 『青い夢』 (Blue Dream) リリース日: 2016年5月20日 詳細: デビューアルバムであり、瑞々しい感性と透明感あふれるボーカルで話題を呼んだ。アルバムには、青春の儚さや未来への希望を描いた曲が多く収録されており、特に「君と見” , “の下町で生まれ育つ。幼少期から音楽に親しみ、ピアノとギターを独学で学ぶ。中学生の時に初めて作曲を始め、高校生になると地元のライブハウスで演奏するようになる。高校卒業後、音楽専門学校に進学し、本格的に音楽理論やボーカルトレーニングを学ぶ。20歳の時に自主制作アルバムをリリースし、これがレコード会社の目に留まりプロデビューを果たす。彼女の音楽は、その透明感のある声と詩的な歌詞、そして心に響くメロディで多くのファンを魅了している。出演したフェス一覧:フジロックフェスティバル (2” ] “ロック・イン・ジャパン・フェスとコーチェラ・フェスティバルに出演しました。” “フジロックフェスティバルとコーチェラ・フェスティバル” 実装の流れ 以上の情報に基づき、Ragasの実装に必要最小限な実装を行っていきます。 必要なパッケージのインストール ! pip install python-dotenv ragas langchain_openai datasets 環境変数の設定 import os from dotenv import load_dotenv load_dotenv() os.environ["AZURE_OPENAI_ENDPOINT"] = os.getenv("AZURE_OPENAI_ENDPOINT") os.environ["AZURE_OPENAI_API_KEY"] = os.getenv("AZURE_OPENAI_API_KEY") 読み込むenvファイルとしては以下のものを用意しておきます。 .env AZURE_OPENAI_ENDPOINT = "https://{resource-name}.openai.azure.com/" AZURE_OPENAI_API_KEY = "api-key" 次に評価指標となるパラメータをimportし、評価時の項目として設定します。 from ragas.metrics import (     context_precision,     answer_relevancy,     faithfulness,     context_recall,     context_relevancy,     context_entity_recall,     answer_similarity,     answer_correctness ) # list of metrics we're going to use metrics = [     context_precision,     answer_relevancy,     faithfulness,     context_recall,     context_relevancy,     context_entity_recall,     answer_similarity,     answer_correctness ] 次にRagas内で利用するためのchat_llmやembeddingsを構築していきます。 今回はAzure OpenAI Serviceを利用し、LangChainを経由して使っていきます。 from langchain_openai.chat_models import AzureChatOpenAI from langchain_openai.embeddings import AzureOpenAIEmbeddings chat_llm = AzureChatOpenAI(     openai_api_version="2024-02-01",  # e.g., "2023-12-01-preview"     azure_deployment="gpt-35-turbo-16k",     temperature=0, ) embeddings = AzureOpenAIEmbeddings(     openai_api_version="2024-02-01",  # e.g., "2023-12-01-preview"     azure_deployment="text-embedding-ada-002", ) 次にデータの準備をします。 contextsに関しては配列の形にして入れてあげることに注意です。 # 質問事項 questions = [     "白石 玲奈は何歳の時にデビューしましたか?", # case 1     "2枚目にリリースしたアルバムのタイトルは何ですか?", # case 2     "2019年に出演したフェスは何ですか?" # case3 ] # 根拠となった情報(VectorStoreから取得した情報) contexts = [     # case 1(正しい関連内容を取得)     [         "名前: 白石 玲奈 (Shiraishi Rena) 年齢: 28歳 生年月日: 1996年3月15日 デビューした歳: 20歳 リリースしたアルバム 1 アルバム名: 『青い夢』 (Blue Dream) リリース日: 2016年5月20日 詳細: デビューアルバムであり、瑞々しい感性と透明感あふれるボーカルで話題を呼んだ。アルバムには、青春の儚さや未来への希望を描いた曲が多く収録されており、特に「君と見",         "の下町で生まれ育つ。幼少期から音楽に親しみ、ピアノとギターを独学で学ぶ。中学生の時に初めて作曲を始め、高校生になると地元のライブハウスで演奏するようになる。高校卒業後、音楽専門学校に進学し、本格的に音楽理論やボーカルトレーニングを学ぶ。20歳の時に自主制作アルバムをリリースし、これがレコード会社の目に留まりプロデビューを果たす。彼女の音楽は、その透明感のある声と詩的な歌詞、そして心に響くメロディで多くのファンを魅了している。出演したフェス一覧:フジロックフェスティバル (2"         ],     # case 2(正しい関連内容を取得)     [         "リリースしたアルバム 2アルバム名: 『流星の詩』 (Meteor Poem)リリース日: 2018年9月12日 詳細: セカンドアルバムで、より成熟した音楽性と深みのある歌詞が特徴。人生の様々な局面や感情を詩的に表現した楽曲が揃っており、「夜空に咲く花」がシングルとしてリリースされ、大人のリスナーからも支持を得た。アルバム全体を通じて、一貫したテーマとして「変化」と「成長」が描かれている。",         "の下町で生まれ育つ。幼少期から音楽に親しみ、ピアノとギターを独学で学ぶ。中学生の時に初めて作曲を始め、高校生になると地元のライブハウスで演奏するようになる。高校卒業後、音楽専門学校に進学し、本格的に音楽理論やボーカルトレーニングを学ぶ。20歳の時に自主制作アルバムをリリースし、これがレコード会社の目に留まりプロデビューを果たす。彼女の音楽は、その透明感のある声と詩的な歌詞、そして心に響くメロディで多くのファンを魅了している。出演したフェス一覧:フジロックフェスティバル (2",         ],     # case 3(誤った関連内容を取得)     [         "名前: 白石 玲奈 (Shiraishi Rena) 年齢: 28歳 生年月日: 1996年3月15日 デビューした歳: 20歳 リリースしたアルバム 1 アルバム名: 『青い夢』 (Blue Dream) リリース日: 2016年5月20日 詳細: デビューアルバムであり、瑞々しい感性と透明感あふれるボーカルで話題を呼んだ。アルバムには、青春の儚さや未来への希望を描いた曲が多く収録されており、特に「君と見",         "の下町で生まれ育つ。幼少期から音楽に親しみ、ピアノとギターを独学で学ぶ。中学生の時に初めて作曲を始め、高校生になると地元のライブハウスで演奏するようになる。高校卒業後、音楽専門学校に進学し、本格的に音楽理論やボーカルトレーニングを学ぶ。20歳の時に自主制作アルバムをリリースし、これがレコード会社の目に留まりプロデビューを果たす。彼女の音楽は、その透明感のある声と詩的な歌詞、そして心に響くメロディで多くのファンを魅了している。出演したフェス一覧:フジロックフェスティバル (2"         ]     ] # RAGから得られた回答 answers = [     "白石 玲奈がデビューしたのは20歳の時です。", # case 1(正解)     "2枚目にリリースされたアルバムのタイトルは「永遠の一瞬」です。", # case 2(不正解)     "ロック・イン・ジャパン・フェスとコーチェラ・フェスティバルに出演しました。 ", # case 3(不正解) ] # 正しい答え ground_truths = [     "20歳",     " 『流星の詩』 (Meteor Poem)",     "フジロックフェスティバルとコーチェラ・フェスティバル ", ] 用意したDictionaryをdatasetの形に変換します。 from datasets import Dataset ds = Dataset.from_dict(     {         "question": questions,         "answer": answers,         "contexts": contexts,         "ground_truth": ground_truths     } ) 最後にRagasを使って評価の方を行います。 from ragas import evaluate # 引数としてデータセット・評価項目・ChatLLM・Embeddingsを与える result = evaluate(     ds, metrics=metrics, llm=chat_llm, embeddings=embeddings ) result.to_pandas() 結果と考察 結果が以下のように表示されました。 case faithfulness answer_relevancy context_recall context_precision 1 1.0 0.990947 1.0 1.0 2 1.0 0.946483 1.0 1.0 3 0.0 0.919827 1.0 0.0 case context_relevancy context_entity_recall answer_similarity answer_correctness 1 0.222222 1.0 0.852763 0.963191 2 0.000000 0.0 0.810099 0.202525 3 0.000000 0.5 0.947935 0.611984 今回、インプットは適当に与えているため結果も当てにならないのですが せっかくなので少し考察してみたいと思います。 考察1:Faithfulness 以下のような結果となりました。 case faithfulness 1 1.0 2 1.0 3 0.0 case 1, 3は問題ないように思えるのですが、case 2の1.0に関してはやや疑問が残ります。 faithfulnessなのでインプットパラメータのanswerとcontextsに注目します。 ここで、contextsの内容からanswerの内容が推論できれば高得点です。 そしてcase 2に関しては、「contextsの内容からanswerを推論できていない」という想定でパラメータを用意しています。 しかし、その意図と反してfaithfulnessは1.0という高いスコアが得られました。 answer contexts 2枚目にリリースされたアルバムのタイトルは「永遠の一瞬」です。 [  “リリースしたアルバム 2アルバム名: 『流星の詩』 (Meteor Poem)リリース日: 2018年9月12日 詳細: セカンドアルバムで、より成熟した音楽性と深みのある歌詞が特徴。人生の様々な局面や感情を詩的に表現した楽曲が揃っており、「夜空に咲く花」がシングルとしてリリースされ、大人のリスナーからも支持を得た。アルバム全体を通じて、一貫したテーマとして「変化」と「成長」が描かれている。”,         “の下町で生まれ育つ。幼少期から音楽に親しみ、ピアノとギターを独学で学ぶ。中学生の時に初めて作曲を始め、高校生になると地元のライブハウスで演奏するようになる。高校卒業後、音楽専門学校に進学し、本格的に音楽理論やボーカルトレーニングを学ぶ。20歳の時に自主制作アルバムをリリースし、これがレコード会社の目に留まりプロデビューを果たす。彼女の音楽は、その透明感のある声と詩的な歌詞、そして心に響くメロディで多くのファンを魅了している。出演したフェス一覧:フジロックフェスティバル (2”] faithfulnessの計算を意訳すると faithfulness = |contextsの内容から、分割したanswerを推測できた数| / |ステートメントに分割したanswerの合計数| という形になります。 今回、分母( "2枚目に2枚目にリリースされたアルバムのタイトルは「永遠の一瞬」です。"のステートメント )に関してはanswerの文が短いので恐らく、1.0です。 そしてfaithfulnessの値が1.0であることから、分子に関しても値としては1.0で、contextsの内容からanswerが推測できていると判断されている、と予想できます。 人間から見ると答えが誤っているため、推測できないように思えますが 必ずしも「 contextsの内容にanswerが含まれていない=推測できていない 」という関係が成り立たないのかな、と思いました。 ここら辺はLLMがどういう判定するか…に依存しそうです。 考察2:Answer relevancy 以下のような結果となりました。 case answer_relevancy 1 0.990947 2 0.946483 3 0.919827 Answer relevancyなので、インプットパラメータのquestionとanswerに注目します。 answerからリバースエンジニアリングした質問内容と、questionの類似度が高ければ高いスコアです。 case question answer 1 白石 玲奈は何歳の時にデビューしましたか? 白石 玲奈がデビューしたのは20歳の時です。 2 2枚目にリリースしたアルバムのタイトルは何ですか? 2枚目にリリースされたアルバムのタイトルは「永遠の一瞬」です。 3 2019年に出演したフェスは何ですか? ロック・イン・ジャパン・フェスとコーチェラ・フェスティバルに出演しました。 スコア的にはcase 1 > case 2> case 3という感じになってます。 answerからどのようなquestionが推論されるかはRagasの実装や、LLM次第かと思うのですが、 超個人的な感想でいえば、妥当なスコアなのかな?と思います。 case 1のanswerを見ると、「デビューした年齢が聞かれているんだろうなぁ」と予想できますし case 3に関しては「answerから2019年という内容を推論するのは難しいので少しスコアが低くなったのかな?」と予想されます。 考察まとめ 今回は2つの結果だけを考察してみました。 今回は仮想で用意したインプットパラメータを評価してるとはいえ faithfulnessの部分は少し疑問が残る部分もあり、完全にRagasの結果をそのまま受け入れるのもいかがなものかな、というように思いました。 しっかりとRagasの評価項目のロジックに関して理解し、結果に対して考察を行える必要がありそうです。 まとめ Ragasを使ってRAGの性能を定量的に測定することができました。 こういった定量的な結果をもとにRAGの各種パラメータを調整することで、要件を満たしているかの評価を行ったり、より精度の高いRAGを構築するための材料にできそうです。 個人的なポイントとしては 評価する際にはRagasの評価項目に対する知見(計算方法、インプット内容など)が必要 全ての項目に高いスコアを求めるのか、仕様に基づいて重要な項目にのみ高いスコアを求めるのかの判断が必要 次回は実際にRAGを組み、そのシステムをRagasで評価していきたいと思います。 ではまた! 参考 Ragas RAG評価フレームワークのragasを使ってみた RAGの評価のフレームワーク Ragas について 提供されているMetrics(評価指標)を調べる! RAG評価ツールの “RAGAS” を使って、RAGパイプラインの性能を測定する   ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 【初心者向け】RAG評価フレームワーク Ragasを必要最低限で使ってみる first appeared on SIOS Tech. Lab .
初めに PS/SLの佐々木です。 今回はオリジナルのNFTを作成できるテンプレートを作成しました。 ぜひEthereumを使用したDapps開発の理解を深めたり、社内外でエンタメとして使用場合に利用してみてください。 リポジトリは こちら 技術スタック アプリケーション Next.js version 14.2.4 TypeScript Azure Blob Storage 画像保存用 Pinata IPFS NFT metadata保存用 Alchemy Ethereum Node Provider Metamask Transaction署名用 スマートコントラクト Solidity 0.8.24 hardhat version: 2.22.5 起動方法 まずアプリケーション起動に必要なサービスのアカウントを作成し、API Keyなどを集めていきます。 application ディレクトリの .env ファイルに必要な情報です。 Azure Blob Storage Azure Portalからストレージアカウントを選択します。 こちらは基本的にデフォルトのまま作成してもらって大丈夫です。(リソースグループは良しなに作成してください。) ストレージが作成できたら ストレージブラウザ > blobコンテナ > コンテナを作成するを選択し、好きな名前でコンテナを作成してください。 次にアクセスキーを取得します。 ストレージブラウザ > セキュリティとネットワーク > アクセスキーから取得できます。 最後にOpenseaなどので作成したNFTを確認したい場合にはパブリックアクセスを許可する必要があります。 ストレージアカウント > 設定 > 構成 からBlobの匿名アクセスを許可しておきましょう 以上の情報をもとに appilcatoin ディレクトリの .env ファイルの以下の項目を設定してください。 AZURE_STORAGE_ACCOUNT_NAME=ストレージの名前(この例だとoscnft) AZURE_STORAGE_ACCOUNT_KEY=取得したアクセスキー AZURE_STORAGE_CONTAONER_NAME=作成したコンテナの名前   Pinata 次にPinataのAPI Keyを取得します。 こちら からアカウントを作成してください。 ログイン後右にあるタブのAPI Keysから生成できます。 PINATA_API_KEY= PINATA_API_SECRET= Alchemy 次にAlchemyのAPI Keyを取得します。 こちら からアカウントを作成してください ログイン後右のタブからAppsを選択しCreate Appを押下します。 Appを作成後データをマスクしている個所にAPI Keyがあります ALCHEMY_API_KEY= Metamask 次にMetamaskです。 こちらはweb3ではおなじみのWalletになります。 こちか らChromeの拡張を入れてアカウントを作成して下さい。 アドレスは赤の線のところからコピーできます。 秘密鍵は右上の三点リーダーからアカウント詳細のところから取得できます。 METAMASK_EOA_ADDRESS=EOAアドレス METAMASK_PRIVATE_KEY=秘密鍵 最後のContractAddressはデプロイしたスマートコントラクトのアドレスを入れてください。(詳細はこの後) 次に smart-contract ディレクトリ側にある .env ファイルの準備です。 以下三点は既出なので省略します。 WALLET_ADDRESS=EOAアドレス SEPOLIA_PRIVATE_KEY=Metamask秘密鍵 ALCHEMY_API_KEY= EtherScan 新しく出てくるのはEtherScanのAPI Keyです。 こちら からEtherScanいログインします。 ログイン後右側のタブから API Keys を選択し Add ボタンからAPI Keyを作成します。 マスクしている個所にAPIKeyがあります 取得したAPI Keyはこちらに追加します。 ETHERSCAN_API_KEY= 以上で事前準備完了です。 SmartContract deploy smart contractをデプロイしていきます。 deployにはEthereumのETHが必要なので こちら から取得して下さい。 今回使用するnetworkがsepoliaなので Sepolia を選択し、Wallet AddressのところにはMetamaskのアドレスを入力し、 Receive 0.0.5 Sepolia ETH を押下してください。しばらくしたらWalletにETHが送られてきます。 smart-contract のディレクトリに移動し以下のコマンドを実行するとコントラクトがデプロイできます。 npm install // 初回のみ npx hardhat compile npx hardhat ignition deploy ignition/modules/Erc721.sol --network sepolia --verify デプロイ後出力されるスマートコントラクトのアドレスを保存しておいてください。 アプリケーション起動 先ほど保存しておいたスマートコントラクトのアドレスを .env ファイルの CONTRACT_ADDRESS= に設定してください。 application ディレクトリで以下のコマンドを事項します。 npm install // 初回のみ npm run dev アプリケーションが起動できます。 名前と画像を選択するとNFTが作成できます。 NFTの確認 openseaで作成したNFTの確認方法です。 こちら にアクセスして検索ボックスに自分のmetamaskのアドレスを入力すると作成できていることが確認できます。 終わりに 以上でNFTを作成するアプリケーションの起動方法になります。 どのようにEthereum networkと通信をしているのかや、スマートコントラクトがどういう作りになっているのかなどの学習の手助けになればと思います。 実装に関する質問は随時受け付けていますので記事のコメントもしくは twitter:@kanta_sasaki_ gmail: ka-sasaki@sios.com まで連絡ください。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 自作のNFTを作れるテンプレートを公開しました first appeared on SIOS Tech. Lab .
こんにちは! 今月も「OSSのサポートエンジニアが気になった!OSSの最新ニュース」をお届けします。 2024/5/27 (月)、Linux Foundation Research は「2024年日本の技術系人材の現状レポート – 日本の技術セクターにおける人材戦略とモダナイゼーションの取り組みに関する調査結果」を公開しました。 Linux Foundationが「2024年日本の技術系人材の現状レポート」を公開、日本はタレントマネジメント戦略でリード https://codezine.jp/article/detail/19618 トレンドマイクロ社が、ランサムウェア「TargetCompany」の Linux 型新型亜種についての解説を公開しました。 今年は 2024/6/15 (土) ~ 6/16 (日)、7 回目の開催となります。 ランサムウェア「TargetCompany」のLinux型亜種がVMware ESXiの仮想環境を攻撃 https://www.trendmicro.com/ja_jp/research/24/f/targetcompany-s-linux-variant-targets-esxi-environments.html 6/20、ロシア製の Kaspersky 製品が米国で提供禁止となりました。 Commerce Department Prohibits Russian Kaspersky Software for U.S. Customers https://www.bis.gov/press-release/commerce-department-prohibits-russian-kaspersky-software-us-customers ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 【2024年6月】OSSサポートエンジニアが気になった!OSS最新ニュース first appeared on SIOS Tech. Lab .
今号では、nmcli コマンドの使い方やオプションについてご紹介します! nmcli コマンドとは nmcli コマンドは、NetworkManager の機能をコマンドライン上から使用できるコマンドです。 GUI が利用できないサーバーやリモートマシンでよく使用されます。 nmcli を使用することで、各ネットワークインターフェースの状態の確認、接続の作成や削除、 IP アドレスの設定などを実行できます。 なお、nmcli コマンドは非常に多機能であり、多くのサブコマンドとオプションがあります。 そのため、数回に分けて各サブコマンド、オプションについて紹介していきます。 今回の記事では、 物理デバイスに関するサブコマンド、オプションをご紹介します。 基本の書式 サブコマンドに “device” もしくは “dev” を指定すると、物理デバイスの情報を表示します。 なお、これはオプションに “status” を指定した時と同じ動作になります。 # nmcli device DEVICE TYPE STATE CONNECTION eth0 ethernet connected System eth0 lo loopback connected (externally) lo nmcli device コマンドのオプション よく使用されると考えられるオプションを抜粋してご紹介します。 オプションに “show” 、その後に対象となるデバイスを指定すると、当該デバイスの 詳細情報を表示します。 # nmcli device show eth0 GENERAL.DEVICE: eth0 GENERAL.TYPE: ethernet GENERAL.HWADDR: 06:EC:94:58:92:9D GENERAL.MTU: 9001 GENERAL.STATE: 100 (connected) GENERAL.CONNECTION: System eth0 GENERAL.CON-PATH: /org/freedesktop/NetworkManager/ActiveConnection/2 WIRED-PROPERTIES.CARRIER: on IP4.ADDRESS[1]: 172.31.7.153/20 IP4.GATEWAY: 172.31.0.1 IP4.ROUTE[1]: dst = 172.31.0.0/20, nh = 0.0.0.0, mt = 100 IP4.ROUTE[2]: dst = 0.0.0.0/0, nh = 172.31.0.1, mt = 100 IP4.DNS[1]: 172.31.0.2 IP4.DOMAIN[1]: ap-northeast-1.compute.internal IP6.ADDRESS[1]: 2406:da14:ac9:2100:8fc0:6d84:a95b:fc9b/128 IP6.ADDRESS[2]: fe80::4ec:94ff:fe58:929d/64 IP6.GATEWAY: fe80::809:7dff:fec0:1 IP6.ROUTE[1]: dst = fe80::/64, nh = ::, mt = 1024 IP6.ROUTE[2]: dst = 2406:da14:ac9:2100::/64, nh = ::, mt = 100 IP6.ROUTE[3]: dst = ::/0, nh = fe80::809:7dff:fec0:1, mt = 100 IP6.ROUTE[4]: dst = 2406:da14:ac9:2100:8fc0:6d84:a95b:fc9b/128, nh = ::, mt = 100 ・ GENERAL.DEVICE:  デバイス名 ・ GENERAL.TYPE:  デバイスの種類 ・ GENERAL.HWADDR:  MAC アドレス ・ GENERAL.MTU:  1回に送信できる最大のデータサイズ ・ GENERAL.STATE:  デバイスの状態 (connected は接続済みであることを示す) ・ GENERAL.CONNECTION:  接続の名前 ・ GENERAL.CON-PATH:  NetworkManager 上での接続のパス ・ WIRED-PROPERTIES.CARRIER:  信号の状態 (on は接続がアクティブであることを示す) ・ IP4.ADDRESS[1]:  IPv4 アドレス、およびサブネットマスク ・ IP4.GATEWAY:  IPv4 のデフォルトゲートウェイ ・ IP4.ROUTE[1]~[2]:  IPv4 のルーティング情報 ・ IP4.DNS[1]:  IPv4 の DNS サーバ ・ IP4.DOMAIN[1]:  ドメイン名 ・ IP6.ADDRESS[1]:  IPv6 アドレス ・ IP6.ADDRESS[2]:  IPv6 アドレス (ローカルアドレス) ・ IP6.GATEWAY:  IPv6 のデフォルトゲートウェイ ・ IP6.ROUTE[1]~[4]:  IPv6 のルーティング情報 オプションに “connect” 、その後に対象となるデバイスを指定すると、当該デバイスに 接続します。 # nmcli device connect eth0 Device 'eth0' successfully activated with '5fb06bd0-0bb0-7ffb-45f1-d6edd65f3e03'. オプションに “disconnect” 、その後に対象となるデバイスを指定すると、当該デバイスから 切断します。 # nmcli device disconnect eth0 Device 'eth0' successfully disconnected. オプションに “modify” 、その後に対象となるデバイス、対象となるパラメータを指定すると、 当該パラメータの設定内容を変更できます。 例えば、eth0 の MTU (Maximum Transmission Unit) サイズを変更したい場合、下記の様に実行します。 # nmcli device modify eth0 mtu 5000 Connection successfully reapplied to device 'eth0'. nmcli device show eth0 コマンドで各パラメータの内容を確認すると、MTU サイズが 上記で変更した 5000 に変更されています。 # nmcli device show eth0 GENERAL.DEVICE: eth0 GENERAL.TYPE: ethernet GENERAL.HWADDR: 06:EC:94:58:92:9D GENERAL.MTU: 5000 GENERAL.STATE: 100 (connected) GENERAL.CONNECTION: System eth0 GENERAL.CON-PATH: /org/freedesktop/NetworkManager/ActiveConnection/4 WIRED-PROPERTIES.CARRIER: on IP4.ADDRESS[1]: 172.31.7.153/20 IP4.GATEWAY: 172.31.0.1 IP4.ROUTE[1]: dst = 172.31.0.0/20, nh = 0.0.0.0, mt = 100 IP4.ROUTE[2]: dst = 0.0.0.0/0, nh = 172.31.0.1, mt = 100 IP4.DNS[1]: 172.31.0.2 IP4.DOMAIN[1]: ap-northeast-1.compute.internal IP6.ADDRESS[1]: 2406:da14:ac9:2100:8fc0:6d84:a95b:fc9b/128 IP6.ADDRESS[2]: fe80::4ec:94ff:fe58:929d/64 IP6.GATEWAY: fe80::809:7dff:fec0:1 IP6.ROUTE[1]: dst = fe80::/64, nh = ::, mt = 1024 IP6.ROUTE[2]: dst = 2406:da14:ac9:2100::/64, nh = ::, mt = 100 IP6.ROUTE[3]: dst = ::/0, nh = fe80::809:7dff:fec0:1, mt = 100 IP6.ROUTE[4]: dst = 2406:da14:ac9:2100:8fc0:6d84:a95b:fc9b/128, nh = ::, mt = 100 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 知っておくとちょっと便利!nmcli コマンドの使い方 ~デバイス編~ first appeared on SIOS Tech. Lab .
初めに こんにちは。 PS/SLの佐々木です。 最近輪読会でDDDについての書籍を扱っているのですが、その中でValueObjectを作るのか作らないのか論争が巻き起こっています。 私自身作るに越したことはないと思うのですが、実装量が多くなるのと、必要なものだけ作ればいいのではないかと思う反面、作る作らないの判断が人によると一貫性のないコードになってしまう懸念点があります。 そこで今回はTypescriptでDomainObjectaのコンストラクタで定義されているプロパティからValueObjectを自動生成する ts-vo-generator というライブラリを作成してみました。 ts-vo-generatorの使い方 こちらのライブラリはnpmとyarnで公開しています。( npm registry ) 今回はnpmでインストールする例を紹介します。 npm install -g ts-vo-generator 使用する際には npx typescript-value-object-generator <input_file> <output_directory> このように使用します。 input_file には解析対象のclassのパスを指定し、 output_directory にはValueObjectを生成するディレクトリを指定します。 実際に使用してみる 今回は以下のようなクラスからValuObjectを自動生成してみます。 type MountainType = { id: number; name: string; elevation: number; description?: string; range: string; } // Mountain.ts export class Mountain { private constructor( private id: number, private name: string, private elevation: number, private range: string, private description?: string ) {} static new(props: MountainType): Mountain { return new Mountain( props.id, props.name, props.elevation, props.range, props.description ); } public genMessage(): string { return `${this.name} の標高は ${this.elevation} mです。`; } } 以下のコマンドを実行します。 npx ts-vo-generator ./src/model/Mountain.ts ./src/ValueObject 実行すると /src/ValueObject 配下に Description.ts や Id.ts が生成されていることが確認できます。 // Id.ts export class Id { private constructor(private readonly value: number) {} static create(value: number): Id { if (!Id.isValid(value)) { throw new Error('Invalid value'); } return new Id(value); } getValue(): number { return this.value; } private static isValid(value: number): boolean { // validation logic here return true; } } 生成されたコードを見てみると上記のようなValueObjectのスケルトンコードが生成されています。 この後は好きなロジックを追加していきます。 また一度生成したものに関して再度生成しようとすると上書きするか処理をスキップするかを聞かれます。 今後の展望 現在の ts-vo-generator ではValueObjectを作成後、元のClassの方にも手動でValueObjectを定義しないといけません。 近いうちにこちらの対応も行っていきたいと思います。 最終的には以下のようなところまで自動で生成したいと思っています。(現時点ではこの修正は手動です) import { Id } from '../ValueObject/Id'; import { Description } from '../ValueObject/Description'; import { Elevation } from '../ValueObject/Elevation'; import { Name } from '../ValueObject/Name'; import { Range } from '../ValueObject/Range'; type MountainType = { id: Id; name: Name; elevation: Elevation; description?: Description; range: Range; } // Mountain.ts export class Mountain { private constructor( private id: Id, private name: Name, private elevation: Elevation, private range: Range, private description?: Description ) {} static new(props: MountainType): Mountain { return new Mountain( props.id, props.name, props.elevation, props.range, props.description ); } public genMessage(): string { return `${this.name.getValue()} の標高は ${this.elevation.getValue()} mです。`; } } 終わりに 最後まで読んでいただきありがとうございました。 もしよろしけべばStarやコントリビュートお待ちしています。 gihtub ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post DomainObjectからValueObjectを自動生成するOSS作ってみた ~ ts-vo-generator~ first appeared on SIOS Tech. Lab .
こんにちは。サイオステクノロジー OSS サポート担当 山本 です。 今回は前回紹介した Solr がなぜ早いのかと、Solr を使いこなすためには必須となる概念についてお話ししてみようと思います。 ■Solr の検索が早いカラクリ 繰り返しになりますが Solr の主な強みは 検索が超高速 であることです。 その検索の早さを支えているのは、 インデックス という仕組みです。 Solr のインデックスはその名のとおり 登録されたドキュメント (データ) の 目次 であり、基本的には ドキュメントを登録する際に自動的に作成 されます。 ※ 前回似ていると紹介した RDB にもインデックスという概念はありますが、Solr のそれとはやり方が大きく異なるものです。 そして、検索の際にはこのインデックスから検索を行うことで超高速な文字列検索を実現できる、というわけです。 さて、ではどのようにしてこの「目次」を作っているのかと言うと…… スキーマ において各 フィールド で設定した内容に応じて ドキュメント内の 文章を解析 して、その解析結果から作られています。 特に日本語を使いたい場合、この解析のために必要になってくるのが自然言語処理の一種である 形態素解析 というものです。 ■形態素解析をなんとなく知る 自然言語処理 は非常にざっくり言ってしまえば、 人間が普段使っている言葉をコンピュータで適切に処理できるようにする ための技術・学問です。 形態素解析 は自然言語処理の一分野で、 文章を単語に分け て品詞の種類や原形などを特定する、ということを扱います。 コンピュータの分野では、更に細分化して 単語に分ける部分だけ を トークナイズ などと呼んだりもするようです。 トークナイズの例を考えてみましょう。 以下の文章を単語に分けてみてください。 This is a red pencil. これは… This / is / a / red / pencil / . こうですね。 このように単語に分割するのがトークナイズで、更に分けた単語の品詞などを特定してやれば形態素解析、と言えるでしょう(非常にざっくりとした考え方でよければ、という前提は付きますが)。 さて、この例で見てもらった英語を含め、 大半の言語では最初から単語ごとに スペースで区切って 文章を書きます 。 そのため、コンピュータで扱う場合でも基本的には 機械的に「スペース」という文字が出てきたら区切る 、という処理で単語に分けられる(一部例外はあり)ため、形態素解析というものは原則としてあまり難しいものではないようです。 一方で日本語はというと……例えば以下の文章を単語に分けてみましょう。 これはあかいえんぴつです。 これは… これ / は / あかい / えんぴつ / です / 。 こうなりますね。 さて、我々のように日常的に日本語を使っている人間であれば特に問題なく単語に分割できるでしょうが、これをコンピュータでやりたいとなるとどうでしょう。 日本語というのは改めて見てみると、明確な区切りとなる目安がなく、文法も比較的自由で、活用形だったり造語だったり口語やスラングなど変則的な単語が乱れ飛ぶ…… そうです。 日本語の形態素解析というのは、非常に難しい ものなのです。 現在の日本語の形態素解析は、コンピュータに単語を判別するための 辞書データ を登録した上で、上手く解析するための様々なアプローチ……例えば  ・考えうる区切り方を全て抜き出して、品詞の繋がり方などから一番それっぽい区切り方を選ぶ  ・「ここで区切ると前後が適切な言語になるか」を逐一チェックしていく などのような処理を実装した、いくつかのアルゴリズムがあるとされています。 現在では高い精度で形態素解析をすることができますが、先述のとおり日本語があまりにも変則的で自由な言語であるため、 100% 完璧に正しく形態素解析をできる保証はない 、というのが現状です。 色々ごちゃごちゃとお話しましたが、Solr で日本語を使う上では、  ・ なんか単語に分けてるらしい  ・ 単語に分けるために 形態素解析 って考え方を使うらしい  ・ 形態素解析には 辞書データ ってものが必要らしい  ・ 確実に意図した通りの単語に区切れるとは限らないらしい という点を覚えておいてください。 余談ですが、例えば英語だと同じスペルでも違う品詞だったり全く違う意味を持つ単語が多数あるため、単語に分割した後の適切な意味を判定するステップが難しかったりするなど、それぞれの言語で違った自然言語処理の難しさがあったりします。 ■Solr のインデックス作成の様子を見てみる 前置きが長くなりましたが、最初にお話した Solr の インデックス作成 (= インデキシング ) がどのように行われるか見てみましょう。 Solr ドキュメントの登録時には、 フィルタ と呼ばれる一連の処理を 複数組み合わせ て、その処理結果をインデックスとして登録します。 フィルタはフィールドごとに組み合わせ方を設定 することができます。 また、 検索時にも設定した組み合わせでフィルタの処理を行った結果を、 実際の検索ワード として使用 します。 フィルタにはデフォルトで用意されているものだけでも様々な種類がありますが、一例としては  ・文章を単語に分割して品詞を特定する  ・単語を基本形に戻す  ・半角文字を全角文字に直す  ・助詞・助動詞・代名詞など検索に適さない要素を削除する などのようなものがあります。(ここで形態素解析の概念を使っていますね) 前回見た Solr の管理画面で実際のインデキシングの処理の様子を確認することができる ので、今回もデモ用環境を使って試してみましょう。 デモ環境の立ち上げは以下のコマンドで、 ## 前回の環境を消してしまっている場合 $ podman run -dt --name test-solr -p 8984:8983 solr solr-demo ## 前回の環境から続けて試す場合 $ podman start test-solr 管理用の WebUI はブラウザで以下のアドレスにアクセスすれば OK でしたね。 http://(IPアドレス or ホスト名):8984/solr WebUI にアクセスできたら、「プルダウンから “demo” を選ぶ」→「Analysis」の順に遷移しましょう。 この画面からインデキシングの処理のテストができます。 今回は “ Analyse Fieldname / FieldType ” を、デフォルトで用意されている日本語向けの設定である “ text_ja ” にして試してみましょう。 画面上部の入力部分 にテストしてみたい文章を入れて、” Analyse Values ” ボタンを押下すると、 設定されているフィルタごとの処理結果 が順に表示されるはずです。 実際にインデックスとして登録される(または検索ワードとして使用される)のは、設定された全てのフィルタを適用した結果となる 一番下 に表示されているものです。 ■うまくいかない例も見てみる 折角なので思い通りにいかない例も見てみましょう。 先の “Analysis” のページで、今度は「 うらにわにはにわにわとりがいる。 」という文章を解析させてみましょう。 これはご存じのとおり 裏庭 / に / は / 二羽 / 鶏 / が / いる / 。 なので、このとおりになってほしいところですが…… 結果はご覧のとおり、「うら / に / わに / はにわ / にわとり / が / いる」と何か鰐や埴輪が生えてきてしまっています。あくまで実験として見るだけなら、ちょっと愉快な感じですね。 ともあれ、このように意図した通りの形になってくれないケースもあり得る、ということは覚えておいてください。 余談ですが、解析させる文章を「裏庭には二羽鶏がいる」と漢字も使った形にしてやれば、大体ちゃんと上手くやってくれます。 意図しない形になってしまう可能性があるのは、あくまで 文法として正しい、意図しない分け方 がある場合という点も気を付けてください。 ■最後に 今回は Solr のカラクリの核である “ インデックス ” と、インデックスを考える上で必要不可欠になる “形態素解析” という概念についてお話ししてみました。 見てもらった通り、Solr では 登録されたドキュメントを単語に分割して “インデックス” を作成する ので、例えば登録したデータ (ドキュメント) から 「ぶどう」という 単語が含まれている ものを探す、というような処理に圧倒的に強くなります。 前回似ている部分もあるというお話をした RDB ではこのような機能はないため、同じようなことをしようとすると検索のたびに逐一全てのデータをチェックする必要があり、例えるなら「本の目次から目標を探す」か「その本を全て読みながら目標を探す」かくらいの差が出る、というわけです。 ※ RDB でも “LIKE” 句で似たようなことはできますし、文字列検索という限定的な用法以外では原則 RDB のほうが便利な点には留意してください。 ここさえ押さえてしまえば、あとはデータの登録手順を覚えれば Solr を使えると言っても差し支えないはずです。 あとは思い通りにいかなかった場合の対処案などもありますが……そのあたりはまたいずれ。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Solr って何者?②:早さの秘訣、インデックスのカラクリ first appeared on SIOS Tech. Lab .
こんにちは、サイオステクノロジー の佐藤 陽です。 今日は Azure の AI サービスである Document Intelligence を利用した RAG システムを構築してみたいと思います。 PDF データを独自データとした RAG を構築したい! Document Intelligence とか Azure AI Search ってどうやって使うの? セマンティックチャンキングって何? といった方は最後までご覧ください! はじめに こちらの サンプル に従って実装の方を行っていきます。 日本語の説明も無いですし、RAG初心者&python 不慣れな自分には分かりづらい部分もあったため、そのあたり丁寧に解説していきたいと思います。 ただの公式サンプル解説記事にはなりますが、同じような境遇の誰かの役に立てば幸いです。 要素の紹介 今回のサンプルで登場する技術要素、サービスとしては以下のようなものがあります。 Azure AI Document Intelligence Azure AI Search Azure OpenAI Service LangChain Azure AI Document Intelligence Document Intelligence の機能を使って PDF からテキストデータを抽出します。 Document Intelligence の layout モデルを利用することで、 文章の構造を保ったまま Markdown の形式で抽出することが可能です。 Markdown の形式で抽出することで、今回の記事の肝であるセマンティックチャンキング(後述)が可能となります。 また、Document Intelligenceに関してはこちらの記事でも以前解説しています。 Azure AI Document Intelligence入門【Resultパラメータ解説付き!】 Azure AI Search RAG を構築する際に利用するベクトルストアです。 チャンク化されたデータをベクトル化し、保存しておきます。 またユーザーからのリクエストに対して、関連のある情報を検索し、抽出します。 Azure OpenAI Service Chat や Embedding の LLM の機能を持ちます。 チャットのやり取りや、チャンキングした情報のベクトル化などを行います。 LangChain LangChain は LLM を手軽に使えるようにしてくれるライブラリです。 様々な機能が提供されていますが、今回は主にチャンクキングの処理や、Azure OpenAI Service を実行するためのラッパー、RAGシステムの構築のために利用します。 システム構成 参考サイトのものをそのまま張っておきます。  全体の処理の流れとしては AI Document Intelligence で PDF を読み取る PDF の内容を分析し、Markdown として出力する LangChain の機能を利用し、Markdown の内容を見出し位置(#,##,###)でチャンク化する チャンク化した内容をベクトル化し、ベクトルストアである AI Search に登録する ユーザーからの質問の内容に関連する情報を AI Search から取り出す Chat に投げる Prompt を構築する Chat から回答を得る といった形となります。 セマンティックチャンキングとは 実装を行う前に、今回の記事のタイトルにもなっている 「セマンティックチャンキング」 について解説します。 まず、セマンティック(Semantic)とは?ということなのですが、以下のように定義されていました。 《言語学》意味の、語義の 次にチャンキングについては、Wikipedia によると あるものをより小さな断片に分割したり(チャンキング・ダウン)、逆により大きな断片にまとめたり(チャンキング・アップ)すること。 とあります。 一般的にRAGの話におけるチャンキングというと、Chat AIが参照するドキュメントの単位に分割することを指します。 分割するサイズなどによってもRAGの性能が変わってくることが言われており、チャンキング戦略はRAGにおける重要なポイントとされています。 これを踏まえると セマンティックチャンキング=意味の塊部分で区切って小さく分割する と捉えることができます。 ちなみに一般的なチャンキングの方法はというと 事前にチャンクサイズ(分割するサイズ)が固定で決まっており、 文章の意味や区切りなどはお構いなしに、決まったサイズで文章を区切るような方法が多いです。 メリット ではセマンティックチャンキングを使うメリットは何でしょうか? こちらも先程のサンプルのページにおいて言及されており、メリットとして以下の 3 つが挙げられています。 効率的な保管と検索(Efficient storage and retrieval) 関連性の向上(Improved relevance) 解釈可能性の向上(Enhanced interpretability) つまり ベクトルストアに対して効率的に保存ができ、関連の強いドキュメントの検索が可能になり、LLM が独立した情報として理解できるため、明確な回答が行えるようになる。 ということがいえます。 参考: セマンティックチャンキング – Microsoft Document Intelligence を活用したセマンティックチャンキング 今回は Document Intelligence を活用して、セマンティックチャンキングを行います。 Document Intelligence は PDF などのデータを、文章の構造を保ったまま Markdown 形式で出力することが可能です。 Markdown 形式で出力することで、見出し(#, ## etc.)の位置でチャンク化することが可能となり、セマンティックチャンキングを実現できます。 実装 では実際にステップを踏んで実行していきます。 ソースコードは基本的にサンプルのコピペです。 環境構築 必要なパッケージのインストールを行います。 ! pip install python-dotenv langchain langchain-community langchain-openai langchainhub openai tiktoken azure-ai-documentintelligence azure-identity azure-search-documents==11.6.0b3 次に環境変数(API キーや、Azure OpenAI Service のエンドポイント等)の設定をします。 .env ファイルを作成して、各パラメータを設定してください。 いつものお約束ですが、KEYの情報などはGitHubなどに公開しないよう注意して下さい。 """ This code loads environment variables using the `dotenv` library and sets the necessary environment variables for Azure services. The environment variables are loaded from the `.env` file in the same directory as this notebook. """ import os from dotenv import load_dotenv load_dotenv() os.environ["AZURE_OPENAI_ENDPOINT"] = os.getenv("AZURE_OPENAI_ENDPOINT") os.environ["AZURE_OPENAI_API_KEY"] = os.getenv("AZURE_OPENAI_API_KEY") doc_intelligence_endpoint = os.getenv("AZURE_DOCUMENT_INTELLIGENCE_ENDPOINT") doc_intelligence_key = os.getenv("AZURE_DOCUMENT_INTELLIGENCE_KEY") .envファイル AZURE_OPENAI_ENDPOINT = "https://{resouce-name}.openai.azure.com/" AZURE_OPENAI_API_KEY = "{openapi_key_from_azure_portal}" AZURE_SEARCH_ENDPOINT = "https://{resource-name}.search.windows.net" AZURE_SEARCH_ADMIN_KEY = "{ai_search_key_from_azure_portal}" AZURE_DOCUMENT_INTELLIGENCE_ENDPOINT= "https://{resource-name}.cognitiveservices.azure.com/" AZURE_DOCUMENT_INTELLIGENCE_KEY = "{document_intelligence_key_from_azure_portal}" 実装で活用する LangChainの機能を import します from langchain import hub from langchain_openai import AzureChatOpenAI from langchain_community.document_loaders import AzureAIDocumentIntelligenceLoader from langchain_openai import AzureOpenAIEmbeddings from langchain.schema import StrOutputParser from langchain.schema.runnable import RunnablePassthrough from langchain.text_splitter import MarkdownHeaderTextSplitter from langchain.vectorstores.azuresearch import AzureSearch Document Intelligence を使ったセマンティックチャンキング 実際に Document Intelligence を使って、PDF を読み込んでセマンティックチャンキングを行っていきます。 まずは、PDF を読み込んで Markdown 形式に変換します。 今回、対象とする PDF(it_servey.pdf)は 前回の記事 で扱ったものと同じものを用意します。 PDFは、ソースコードのファイルと同じ階層に置きました。 # Initiate Azure AI Document Intelligence to load the document. You can either specify file_path or url_path to load the document. loader = AzureAIDocumentIntelligenceLoader(file_path="it_servey.pdf", api_key = doc_intelligence_key, api_endpoint = doc_intelligence_endpoint, api_model="prebuilt-layout") docs = loader.load() もちろん StorageAccount などのサーバー上に公開されている PDF でも読み込み可能であり、 その場合は file_path の引数を、 url_path に変更して URL を設定します。 また Markdown への変換に関してですが、 AzureAIDocumentIntelligenceLoader の Optional の引数として用意されています。 ただし、Default として markdown が設定されているため、引数として明示的に記載する必要はありません。 mode: Optional[str]     The type of content representation of the generated Documents.     Use either "single", "page", or "markdown". Default value is "markdown". 次に、Markdown の内容を LangChain の機能を使って分割します。 今回は、Markdown の # , ## , ### のタグでチャンキングします。 # Split the document into chunks base on markdown headers. headers_to_split_on = [     ("#", "Header 1"),     ("##", "Header 2"),     ("###", "Header 3"), ] text_splitter = MarkdownHeaderTextSplitter(headers_to_split_on=headers_to_split_on) docs_string = docs[0].page_content #DocumentIntelligenceでMarkdown化したコンテンツ splits = text_splitter.split_text(docs_string) #設定したsplitterで分割を行う # ヘッダー情報を表すmetadataのみ出力 for split in splits: print(split.metadata) LangChain の機能である、 MarkdownHeaderTextSplitter で Markdown のチャンキングを行い、splits の配列に格納します。 セマンティックチャンキングの出力確認 セマンティックチャンキングの出力確認のため、分割されたsplitsの中身のヘッダー情報を示す metadata のみを出力してみました。 {} # SIOS HOGEHOGE TECHNOLOGY 111-1111 東京都...の部分 {'Header 1': '調査概要 2024 年9月4日', 'Header 2': '調査目的'} {'Header 1': '調査方法'} {'Header 1': '市場概況'} {'Header 1': '市場概況', 'Header 2': 'クラウドコンピューティング ♡'} {'Header 1': '市場概況', 'Header 2': 'AIN'} {'Header 1': '市場概況', 'Header 2': 'AIN', 'Header 3': 'ブロックチェーン'} するとMarkdownの各ヘッダーの位置で文章が区切れてチャンキングされ、7つのデータに分割されていることが確認できます。 一応併せて元データの画像も載せておきます。 概ね良さそうに見えるのですが、いくつか誤っている部分も見られます。 split[2]の {'Header 1': '調査方法'} は、本来は {'Header 1': '調査概要 2024 年9月4日', 'Header 2': '調査方法'} が正しいように思います。 またsplit[6]に関しても、 {'Header 1': '市場概況', 'Header 2': 'AIN', 'Header 3': 'ブロックチェーン'} とあり、 ブロックチェーン が AI の子要素であると認識されていたりします。 これらはいずれもDocument IntelligenceにおいてMarkdownとして出力する際に、誤った見出しが付けられていることが原因でした。 ここらへんはDocument Intelligenceの精度向上を祈るしかないかもしれないですね…。 一方で、split[3]の中に 技術別市場シェア という見出しがありますが こちらはDocument Intelligenceから出力されたMarkdownには 見出し2(##)として記録されていました。(↓) ## 技術別市場シェア ただ、MarkdownHeaderTextSplitterの対象とならなかったようです。 このあたりの細かい振る舞いに関して、もう少し調査が必要そうです。 情報のベクトル化とベクトルストアへの格納 次にチャンク化した情報をベクトル化し、ベクトルストアに格納していきます。 ベクトル化を行う方法としては、Azure OpenAI Service の embedding model を活用し、 ベクトル化したデータは Azure AI Search に格納していきます。 Langchainの機能を使い、Azure OpenAI のEmbeddingモデルをラップして利用します。 # Embed the splitted documents and insert into Azure Search vector store # AOAIのEmbeddings LLMをラップ aoai_embeddings = AzureOpenAIEmbeddings(     azure_deployment="<Azure OpenAI embeddings model>", e.g., "text-embedding-ada-002"     openai_api_version="<Azure OpenAI API version>",  # e.g., "2023-12-01-preview" ) vector_store_address: str = os.getenv("AZURE_SEARCH_ENDPOINT") vector_store_password: str = os.getenv("AZURE_SEARCH_ADMIN_KEY") index_name: str = "<your index name>" #Azure AI Serch上に作成するIndex名 # ベクトルストアから簡単にデータを取り出すためのvector_storeのインスタンスを構築. # インスタンスを構築したタイミングでIndexが作成されます # 今回は対象をAzure AI Searchとする. vector_store: AzureSearch = AzureSearch(     azure_search_endpoint=vector_store_address,     azure_search_key=vector_store_password,     index_name=index_name,     embedding_function=aoai_embeddings.embed_query ## Azure OpenAI Serviceのembeddingsモデルを利用 ) # 先程チャンク化した情報を格納する # 格納するタイミングでベクトル化も行われる vector_store.add_documents(documents=splits) なお、利用する Azure OpenAI Service のバージョンは こちら を参照してください。 今だと、”2024-02-01″がGAされてる最新バージョンかと思います。  質問に関連する情報をベクトルストアから取り出す 次に実際にベクトルストアから、質問に対して関連した情報を抽出します。 この時 Retriever というインスタンスを作成して情報を取り出していきます。 この Retriever の振る舞いに関しては こちら の記事で分かりやすくまとまっていたので参照ください。 サンプルコードでは SearchType を similarity としているため類似検索が行われ、 search_kwargs を k:3 としているため 3 件の情報が返ってくるよう設定されています。 その後、実際に Retriever に質問を与え、関連する情報を retrieved_docs に格納し表示しています。 # Retrieve relevant chunks based on the question # 先ほど作成したベクトルストアをRetrieverとして定義 retriever = vector_store.as_retriever(search_type="similarity", search_kwargs={"k": 3}) retrieved_docs = retriever.get_relevant_documents(     "この調査の目的は何ですか?" ) print(retrieved_docs) #サンプルコードでは[0].page_contentだけ出力していますが、内容理解のため全部出力します。 出力結果 出力された内容としては以下のようなものです。(分かりやすさのため改行しています。) [Document(page_content='本市場調査の目的は、最新の IT 技術動向を詳細に把握し、各技術の市場シェア、成長予測、およ び競争状況を包括的に明らかにすることであり、特にクラウドコンピューティング、AI(人工知能)、loT (モノのインターネット)、およびブロックチェーン技術の各分野に焦点を当てるものである。', metadata={'Header 1': '調査概要 2024 年9月4日', 'Header 2': '調査目的'}), Document(page_content='1\\. プライマリーデータはアンケート調査およびインタビューによって収集し、直接的かつ現場の 視点から得られる情報を重視する一方で、セカンダリーデータは公開データベースおよび業 界レポートから取得し、信頼性の高い既存の情報源を利用して補完的なデータ収集を行う。  \n2\\. データ分析に関しては、定量分析として統計解析ソフトウェアを駆使して大量の数値データを 精緻に解析し、定性分析として内容分析およびテーマ別分析を行い、収集されたデータの質 的側面を多角的に検討する。', metadata={'Header 1': '調査方法'}), Document(page_content='AI 技術に関しては、IBM が市場シェアの 25%を占め、Google が 20%、Microsoft が 18%、その他が 37%を占めている。', metadata={'Header 1': '市場概況', 'Header 2': 'AIN'}), Document(page_content='クラウドコンピューティング技術に関しては、AWS が市場シェアの 32%を占め、Microsoft Azure が 22%、Google Cloud が18%、その他が28%を占めている。', metadata={'Header 1': '市場概況', 'Header 2': 'クラウドコンピューティング ♡'})] 今回の質問に対して、関連するドキュメントが4件抽出されてました。 ただ、 search_kwargs の値として "k":3 を設定しており、3件返ってくるのかなと思っていました。 retrieverの値をデバッグしてみたところ、k=4が設定されていました。 kのDefault値が4みたいなので、うまくパラメータが設定できていないみたいですね。 このあたりlangchainをうまく使いこなせてない可能性があるので、また再調査します。 件数は一旦さておき、出力の中身としては 以下2 つの内容を含んでいることが分かります。 page_content 参考にした文章内容 metadata Section情報(今回でいえばMarkdown における見出し位置) 一番上の結果のpage_contentは「本市場調査の目的は~」から始まっており、まさに質問に関連する部分ですね。 AI Searchによって、質問に関連するドキュメントが抽出できていることが分かります。 プロンプトを構築する 次にプロンプトを構築していきます。 「え?”このドキュメントの想定される読者は誰ですか?”がプロンプトじゃないんですか?」 と思われた方もいるんじゃないでしょうか? 自分も最初はそうでした。 ただ、LLM に投げかけるプロンプトの内容は非常に重要であり、 プロンプトエンジニアリング としても技術が確立されています。 プロンプトエンジニアリングの知識がないユーザーからの質問文をそのままプロンプトとして投げた場合、求める品質の回答が得られない場合があります。 そのため、システム側である程度プロンプトのテンプレートを構築しておき、そこにユーザーからの質問を組み込む形を取ります。 この時に利用するのが LangChain の Prompt Template の機能になります。 では実際にソースコードを見てみます。 なお、今回は既に定義された Prompt Template を利用します。 # Use a prompt for RAG that is checked into the LangChain prompt hub (https://smith.langchain.com/hub/rlm/rag-prompt?organizationId=989ad331-949f-4bac-9694-660074a208a7) prompt = hub.pull("rlm/rag-prompt") hub というのは GitHub とか、DockerHub のようにこう言った Template などが確立されている場所だと思ってください。 この hub から今回は rlm/rag-prompt というテンプレートを pull してきます。 参照リンク へ飛んで、テンプレートの中身を見てみると以下のように定義されています。 You are an assistant for question-answering tasks. Use the following pieces of retrieved context to answer the question. If you don't know the answer, just say that you don't know. Use three sentences maximum and keep the answer concise. Question: {question} Context: {context} Answer: なおこの時、変数 { } として定義されている値としては以下のような内容になります。 question ユーザーからの質問文そのまま contex ベクトルストアから抽出した関連情報 このようなテンプレートを介すことで、ユーザーから単純な質問を投げられたとしても LLM にとって分かりやすい形のプロンプトを構築することが可能になります。 この後のステップとして、このテンプレートに入れるための {question} と {context} を構築していきます。 余談 今回日本語のシステムを構築しようとしているので、日本語でテンプレート定義しなおした方がいいかもしれないです。 ただ逆に LLM は英語の方が理解しやすいかとおもうので、ぎりぎりまで英語でやり取りした方がいいかもしれないです。 このあたり日本語の扱いが難しいですね… RAG の Chain 構築 最後に、実際に RAG の Chain を構築していきます。 Chain とはその名の通り、LLM や Prompt などのコンポーネントを繋げて、システムを作り上げる機能になります。 なお Chain を実装するにあたり、 LangChain Expression Language (LCEL) といった記述方法を利用しています。  LLM や Prompt 等のコンポーネントを | で繋げるだけで簡単に Chain を構築することが可能です。 Linux のパイプみたいな感じですね。 llm = AzureChatOpenAI(     openai_api_version="<Azure OpenAI API version>",  # e.g., "2023-12-01-preview"     azure_deployment="<your chat model deployment name>",     temperature=0, ) # ベクトルストアから取り出したdocumentからpage_contentの内容だけを抽出し、連結します。 def format_docs(docs):     return "\n\n".join(doc.page_content for doc in docs) rag_chain = (     {"context": retriever | format_docs, "question": RunnablePassthrough()} # step1     | prompt # step2     | llm # step 3     | StrOutputParser() # step4 ) llm の変数に関しては、Azure OpenAI Service の Chat の LLM モデルを構築します。 その後、処理の chain を rag_chain 変数として定義します。 chain のステップとしては以下の通りです。 テンプレートに与える変数である context と、 question を構築する 質問文が retriever に渡され、関連情報が得られた後に context の中に代入される question に関しては、RunnablePassthrough()となっているので、そのまま文字列が渡される テンプレートを利用してプロンプトを構築する プロンプトを Chat LLM に投げる 得られた回答から必要な部分のみ抽出 1, 2, 3 はこれまで言及してきた部分を繋げただけなので省略します。 4 の StrOutputParser() に関しては、LangChain の Output parsers の機能になります。 Chat LLM から得られた回答のうち、最も関連性が高いものを文字列として出力します。 RAG の chain 実行 あとは先程組んだ Chain に質問文を与えて実行するだけです。 rag_chain.invoke("この調査の目的は何ですか?") 以下の回答が得られました。 本調査の目的は、最新の IT 技術動向を詳細に把握し、各技術の市場シェア、成長予測、および競争状況を包括的に明らかにすることです。 ドキュメント参照する RAG システム サンプルのドキュメントにはもう一つ例が載っていました。 特に難しい事はしていないですが、少し複雑な内容になっているので解説していきたいと思います。 まずこのコードの目的ですが、 「回答に 加えて 、参照したドキュメントの情報を返すこと」 を目的としています。 どんな情報を参照したうえで回答したかをユーザーに教えることができるので、よりユーザーフレンドリーですね。 ソースコードの解説をする前に、全体の処理の流れを図に起こしたので載っけておきます。 コード見ていて分からなくなったらこの図を見てみてください。 では実際にソースコードを見ていきます。 # Return the retrieved documents or certain source metadata from the documents from operator import itemgetter from langchain.schema.runnable import RunnableMap rag_chain_from_docs = (     {         "context": lambda input: format_docs(input["documents"]),         "question": itemgetter("question"),     }     | prompt     | llm     | StrOutputParser() ) rag_chain_with_source = RunnableMap(     {"documents": retriever, "question": RunnablePassthrough()} ) | {     "documents": lambda input: [doc.metadata for doc in input["documents"]],     "answer": rag_chain_from_docs, } rag_chain_with_source.invoke("<your question>") 少し長いので分割してみていきます。 まず後半部分から rag_chain_with_source = RunnableMap(     {"documents": retriever, "question": RunnablePassthrough()} ) | {     "documents": lambda input: [doc.metadata for doc in input["documents"]],     "answer": rag_chain_from_docs, } rag_chain_with_source.invoke("<your question>") rag_chain_with_source という chain が構築されており、最後にその chain が実行されています。 chain の中身を見ていきます。 まずは入力に対して retriever の処理を加えたものを documents へ、何も処理を加えないものを questions へ代入します。 ただ、先程の例では RunnableMap を利用しておらず、今回の例で RunnableMap を利用してる点が理解できませんでした。 この点分かる方いらしたらコメントお願いします。 次に、 documents と questions を入力として {     "documents": lambda input: [doc.metadata for doc in input["documents"]],     "answer": rag_chain_from_docs, } の中身を定義していきます。 まず documents の値に関しては、 入力として与えられた documents の metadata 情報を、今回の定義の documents に代入します。 answer に関しては、入力( documents , questions )に対して rag_chain_from_docs の処理を行ったものを代入します。 rag_chain_from_docs = (     {         "context": lambda input: format_docs(input["documents"]),         "question": itemgetter("question"),     }     | prompt     | llm     | StrOutputParser() ) rang_chain_from_docs において、まず context と question を定義します。 context に関しては、 入力として与えられた documents の値に対して、format_docs の処理(連結処理)を行ってから context に代入します。 question に関しては、入力の question の値をそのまま入れます。(つまりユーザーからのリクエストそのままですね。) こうして作られた 値 に対して prompt, llm, StrOutputParser のコンポーネントの処理を通して出力します。 そして出力したものが、 answer の中に入れることになります。。 ということで、最終的に得られた出力はこちらです。 {'documents': [{'Header 1': '調査概要 2024 年9月4日', 'Header 2': '調査目的'}, {'Header 1': '調査方法'}, {'Header 1': '市場概況', 'Header 2': 'AIN'}, {'Header 1': '市場概況', 'Header 2': 'クラウドコンピューティング ♡'}], 'answer': '本調査の目的は、最新の IT 技術動向を詳細に把握し、各技術の市場シェア、成長予測、および競争状況を包括的に明らかにすることです。'} document の中には参照したドキュメントの Metadata が入っており answer の中には Chat LLM から得られた回答が入っていることが分かります。 まとめ Document Intelligence を利用し、セマンティックチャンキングを行う RAG システムを構築しました。 サンプルでも丁寧に解説してくれているのですが、初学者の自分からすると分からないことも結構あったので整理してみました。 Document Intelligenceというよりは、langchainのRAG構築部分が少し複雑でしたね。 今回は「やってみた」で終わってしまったので、また機会があれば評価ツールなどを使いながら マンティックチャンキングの効果を測定してみたりしたいと思います。 ではまた! ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 【徹底解説】Document Intelligenceを利用してRAGを構築する【セマンティックチャンキング】 first appeared on SIOS Tech. Lab .
初めに PS/SLの佐々木です。 今までWeb3チームではEthereumのようなパブリックチェーンを使用しての開発や技術検証を行ってきましたが、今年から新しい取り組みとしてコンソーシアム型のチェーンやプライベートチェーンを使用した開発を行っていこうと思っています。 コンソーシアムチェーンで最も有名なところで行くとHyperledger Fabricが候補に挙がってくるのでキャッチアップがてらチュートリアル( 参考 )を進めて使用感を見てみようと思っています。 Hyperledger Fabricの詳細な説明は別ブログで行いますので今後出る記事を参考にしてください。 今回はHyperledger fabricをドキュメント通りに動かしてみようと思います。 動作環境 windows 10 pro wsl ubuntsu 20.04.3 事前準備 Git cURL Docker Go Hyperleger install サンプルとバイナリとDockerイメージをインストールできる curl -sSL https://bit.ly/2ysbOFE | bash -s ka-sasaki@1020-00001:~/web3$ ls fabric-samples ka-sasaki@1020-00001:~/web3$ docker image ls REPOSITORY TAG IMAGE ID CREATED SIZE hyperledger/fabric-peer 2.5 2d02d49d3d1a 3 weeks ago 142MB hyperledger/fabric-peer 2.5.8 2d02d49d3d1a 3 weeks ago 142MB hyperledger/fabric-peer latest 2d02d49d3d1a 3 weeks ago 142MB hyperledger/fabric-orderer 2.5 c833f32f9244 3 weeks ago 111MB hyperledger/fabric-orderer 2.5.8 c833f32f9244 3 weeks ago 111MB hyperledger/fabric-orderer latest c833f32f9244 3 weeks ago 111MB hyperledger/fabric-ccenv 2.5 b4bf6fadf0c7 3 weeks ago 638MB hyperledger/fabric-ccenv 2.5.8 b4bf6fadf0c7 3 weeks ago 638MB hyperledger/fabric-ccenv latest b4bf6fadf0c7 3 weeks ago 638MB hyperledger/fabric-baseos 2.5 6f1a89df96f3 3 weeks ago 129MB hyperledger/fabric-baseos 2.5.8 6f1a89df96f3 3 weeks ago 129MB hyperledger/fabric-baseos latest 6f1a89df96f3 3 weeks ago 129MB hyperledger/fabric-ca 1.5 c2449e2873d5 3 weeks ago 209MB hyperledger/fabric-ca 1.5.11 c2449e2873d5 3 weeks ago 209MB hyperledger/fabric-ca latest c2449e2873d5 3 weeks ago 209MB サンプルとイメージがダウンロードされていることを確認できます。 最後にbinファイルのパスを通す export PATH=$PATH:$HOME/fabric-samples/bin echo "export PATH=\\$PATH:\\$HOME/fabric-samples/bin" >> ~/.bashrc source ~/.bashrc テストネットワークの構築 Hyperledger Fabricの構築 ディレクトリは/test-network peer 2つ orderer 1つ CAはなし test-networkディレクトリに移動し、 network.sh を使用してローカルマシン上のDockerからネットワークを構築する 以前の実行結果などあれば削除する ./network.sh down ネットワーク起動 ./network.sh up 起動するとPeer ノード二つとordererノード一つが起動していることが確認できる。 docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES f3bf9f73341c hyperledger/fabric-peer:latest "peer node start" 3 minutes ago Up 3 minutes 0.0.0.0:7051->7051/tcp, :::7051->7051/tcp, 0.0.0.0:9444->9444/tcp, :::9444->9444/tcp peer0.org1.example.com 0c7fb71179d6 hyperledger/fabric-peer:latest "peer node start" 3 minutes ago Up 3 minutes 0.0.0.0:9051->9051/tcp, :::9051->9051/tcp, 7051/tcp, 0.0.0.0:9445->9445/tcp, :::9445->9445/tcp peer0.org2.example.com 8d55459a26dd hyperledger/fabric-orderer:latest "orderer" 3 minutes ago Up 3 minutes 0.0.0.0:7050->7050/tcp, :::7050->7050/tcp, 0.0.0.0:7053->7053/tcp, :::7053->7053/tcp, 0.0.0.0:9443->9443/tcp, :::9443->9443/tcp orderer.example.com Channelの作成 ./network.sh createChannel Channel 'mychannel' joined Org1とOrg2がmychannelに参加できたことが確認できる チェーンコードのデプロイ ./network.sh deployCC -ccn basic -ccp ../asset-transfer-basic/chaincode-go -ccl go goで作成されたchaincode(ethereumでいうところの smart contract)をデプロイし、channel上でチェーンコードを使用できるようにする ネットワークとやり取り export FABRIC_CFG_PATH=$PWD/../config/ // 以下はOrg1のPeerに対して実行するための環境変数 export CORE_PEER_TLS_ENABLED=true export CORE_PEER_LOCALMSPID="Org1MSP" export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp export CORE_PEER_ADDRESS=localhost:7051 台帳の初期化 peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n basic --peerAddresses localhost:7051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" --peerAddresses localhost:9051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt" -c '{"function":"InitLedger","Args":[]}' // 以下のようなメッセージが出ればOK -> 2024-06-17 18:48:11.035 JST 0001 INFO [chaincodeCmd] chaincodeInvokeOrQuery -> Chaincode invoke successful. result: status:200 台帳に登録されているAssetの一覧を取得 peer chaincode query -C mychannel -n basic -c '{"Args":["GetAllAssets"]}' // 以下のようなメッセージが出ればOK -> [{"AppraisedValue":300,"Color":"blue","ID":"asset1","Owner":"Tomoko","Size":5},{"AppraisedValue":400,"Color":"red","ID":"asset2","Owner":"Brad","Size":5},{"AppraisedValue":500,"Color":"green","ID":"asset3","Owner":"Jin Soo","Size":10},{"AppraisedValue":600,"Color":"yellow","ID":"asset4","Owner":"Max","Size":10},{"AppraisedValue":700,"Color":"black","ID":"asset5","Owner":"Adriana","Size":15},{"AppraisedValue":800,"Color":"white","ID":"asset6","Owner":"Michel","Size":15}] Assetの移動 peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile "${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem" -C mychannel -n basic --peerAddresses localhost:7051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt" --peerAddresses localhost:9051 --tlsRootCertFiles "${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt" -c '{"function":"TransferAsset","Args":["asset6","Christopher"]}' // 以下のようなメッセージが出ればOK -> 2024-06-17 18:51:02.629 JST 0001 INFO [chaincodeCmd] chaincodeInvokeOrQuery -> Chaincode invoke successful. result: status:200 payload:"Michel" // 以下はOrg2のPeerに対して実行するための環境変数 export CORE_PEER_TLS_ENABLED=true export CORE_PEER_LOCALMSPID="Org2MSP" export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp export CORE_PEER_ADDRESS=localhost:9051 転送結果の確認 peer chaincode query -C mychannel -n basic -c '{"Args":["ReadAsset","asset6"]}' // 以下のようなメッセージが出ればOK -> {"AppraisedValue":800,"Color":"white","ID":"asset6","Owner":"Christopher","Size":15} ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Hyperledeger Fabricのチュートリアルをやってみる Part1 first appeared on SIOS Tech. Lab .
想定読者 オブジェクト指向プログラミングに興味がある 可読性が高く、変更に強いプログラムを作りたい SOLID原則を理解して周りに「ドヤァ( ^)o(^ )」したい(自己満足でも可) はじめに SOLID原則は以下の5つの原則の頭文字を並べて出来たネーミングです。 単一責任の原則(single-responsibility principle) There should never be more than one reason for a class to change. 変更するための理由が、一つのクラスに対して一つ以上あってはならない。 開放閉鎖の原則(open/closed principle)←今回のターゲット software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification. ソフトウェアの実体(クラス、モジュール、関数など)は、拡張に対して開かれているべきであり、修正に対して閉じていなければならない リスコフの置換原則(Liskov substitution principle) Functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it. ある基底クラスへのポインタないし参照を扱っている関数群は、その派生クラスのオブジェクトの詳細を知らなくても扱えるようにしなければならない インターフェース分離の原則(interface segregation principle) Many client-specific interfaces are better than one general-purpose interface. 汎用なインターフェースが一つあるよりも、各クライアントに特化したインターフェースがたくさんあった方がよい 依存性逆転の原則(dependency inversion principle) High-level modules should not import anything from low-level modules. Both should depend on abstractions (e.g., interfaces), [not] concretions. 上位モジュールはいかなるものも下位モジュールから持ち込んではならない。双方とも具象ではなく、抽象(インターフェースなど)に依存するべきである ふむ、なんじゃこりゃって感じですよね。大丈夫です。今から具体例をTypeScriptのコードを用いて解説していきます! 解説は、「悪い例」→「何が悪いか解説」→「良い例」といった順序になります。 開放閉鎖の原則 // 悪い例 // クレジットカードのランクをオブジェクトリテラルで定義 const CreditCardRank { NORMAL: 0, GOLD: 1, PLATINUM: 2, BLACK: 3, } as const; type CreditCardRank = (typeof CreditCardRank)[keyof typeof CreditCardRank]; // クレジットカードを表現するクラス class CreditCard { constructor(private CreditCardRank rank) {} } class Program { run1() { const creditCard = new CreditCard(CreditCardRank.GOLD); if (creditCard.rank !== CreditCardRank.NORMAL) { // クレジットカードのランク判別処理 // 省略 } } run2() { const creditCard = new CreditCard(CreditCardRank.PLATINUM); if (creditCard.rank !== CreditCardRank.NORMAL) { // クレジットカードのランク判別処理 // 省略 } } run3() { const creditCard = new CreditCard(CreditCardRank.BLACK); if (creditCard.rank !== CreditCardRank.NORMAL) { // クレジットカードのランク判別処理 // 省略 } } } 上記のコードの説明を以下に箇条書きします。 CreditCardというクレジットカードを表現したクラス定義 CreditCardはrankというクレジットカードのランクを表す属性を持つ Programはアプリケーションの実行処理を記述したクラス(run1, run2, run3という三つの処理が定義されている) run1, run2, run3それぞれにクレジットカードのランク判別処理が記述されている さて、一体このコードはどこが悪いのでしょうか?「なんかクレジットカードのランク判別処理が重複しているなー」という感想くらいでしょうか? 上記の感想を抱いた読者の方は大変鋭い感覚を持っています。同じようなコードが至る所に表れているのは間違いなく「このソースコードには改善の余地がある」という証です。 ここで仮にクレジットカードのランク名「NORMAL」が「ORDINARY」に変更されたとします。変更されるソースコードの処理内容に注目してください。 // 悪い例(NORMALをORDINARYに変更) // クレジットカードのランクをオブジェクトリテラルで定義 const CreditCardRank { // NORMAL: 0, ORDINARY: 0, // 変更後 GOLD: 1, PLATINUM: 2, BLACK: 3, } as const; type CreditCardRank = (typeof CreditCardRank)[keyof typeof CreditCardRank]; // クレジットカードを表現するクラス class CreditCard { constructor(private CreditCardRank rank) {} } class Program { run1() { const creditCard = new CreditCard(CreditCardRank.GOLD); /* if (creditCard.rank === CreditCardRank.NORMAL) { // クレジットカードのランク判別処理 // 省略 } */ // 変更後 if (creditCard.rank !== CreditCardRank.ORDINARY) { // クレジットカードのランク判別処理 // 省略 } } run2() { const creditCard = new CreditCard(CreditCardRank.PLATINUM); /* if (creditCard.rank === CreditCardRank.NORMAL) { // クレジットカードのランク判別処理 // 省略 } */ // 変更後 if (creditCard.rank !== CreditCardRank.ORDINARY) { // クレジットカードのランク判別処理 // 省略 } } run3() { const creditCard = new CreditCard(CreditCardRank.BLACK); /* if (creditCard.rank === CreditCardRank.NORMAL) { // クレジットカードのランク判別処理 // 省略 } */ // 変更後 if (creditCard.rank !== CreditCardRank.ORDINARY) { // クレジットカードのランク判別処理 // 省略 } } } 上記のソースコードを見ると、変更が入った4つの箇所のうち1つ目は単純に「NORMALからORDINARY」に名称変更したことを定義し直しただけなのでOKです。 問題なのは残りの変更箇所で「全て同じ変更内容」を3つの箇所に施しました。 まさにこれこそが上記のソースコードが悪い例であることの証明になります。「同じような処理がn個所に散りばめられている状態は単純に考えて修正量をn倍に増やす」ことになります。 ここで今回の主題である「開放閉鎖の原則」の定義をもう一度お見せします。 software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification. ソフトウェアの実体(クラス、モジュール、関数など)は、拡張に対して開かれているべきであり、修正に対して閉じていなければならない うーん、少しこの定義自体が分かりにくいのでもう少し分かりやすい言葉に書き直してみます。 拡張しやすく、修正しやすいコードにすべき 今回のソースコードは「クレジットカードのランク判別処理のNORMALをORDINARYに変更する」という1つの修正内容に対して、修正箇所が3倍になってしまったので「修正しやすいコードにすべき」という部分に違反していることになりますね。 ということで早速、違反箇所を修正していきましょう! // 良い例 // クレジットカードを表現するクラス class NormalCreditCard {} class GoldCreditCard {} class PlatinumCreditCard {} class BlackCreditCard {} class Program { run1() { const creditCard = new NormalCreditCard; } run2() { const creditCard = new GoldCreditCard; } run3() { const creditCard = new BlackCreditCard; } } 上記のソースコードは悪い例のように「クレジットカードの種別をCreditCardのrankメンバ変数で管理する」のではなく「クラスごとに分別」するようにしています。 このようにすることで「NORMALからORDINARYへの名称変更」という修正が入っても // 良い例 // クレジットカードを表現するクラス // class NormalCreditCard {} class OrinaryCreditCard {} // 変更後 class GoldCreditCard {} class PlatinumCreditCard {} class BlackCreditCard {} class Program { run1() { // creditCard = new NormalCreditCard; const creditCard = new OrinaryCreditCard; // 変更後 } run2() { const creditCard = new GoldCreditCard; } run3() { const creditCard = new BlackCreditCard; } } このようなソースコードになり、上記の修正は明らかに「同じような修正内容を複数個所に施す」といった作業から解放されています。 これで「開放閉鎖の原則」についてマスターしたといっても過言ではありません。 是非「私はopen/closed principleを完全に理解した」とドヤってください( ^)o(^ ) 次回はSOLIDの「L」の部分である「リスコフの置換原則」について解説します! 良かったら覗いてみてください。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post SOLID原則って何ぞや?(開放閉鎖の原則編) first appeared on SIOS Tech. Lab .
Azure OpenAI ServiceによるRAGハンズオン開催のお知らせ 〜独自データを用いた生成AIの利活用を学ぶ〜【初級編】 この度、「 Azure OpenAI ServiceによるRAG実装ガイド 」 をダウンロードしていただいた方限定に、 RAGのハンズオンを無料開催いたします。 本ガイドの目的は、これからRAGを始める人に参考にしていただくため、「シンプル」「強力」「すぐ動く」をモットーにしたRAGアプリケーションを実装するためのガイドです。本ガイドではRAGのアーキテクチャのみならず「実際に動くコード」もご用意致しました。読者の皆様には、コードを動かしながらRAGをより深くご理解頂けることを一番の目的としております。 ハンズオンのお申込みは先着順となっておりますので、 ご興味がある方はお早めにお申し込みください。   【無償】初級テクニカルトレーニング Azure OpenAI ServiceによるRAGハンズオン 〜独自データを用いた生成AIの利活用を学ぶ〜【初級編】 <概要> Azure OpenAI Serviceの概要説明 RAGの概要説明 RAGの構築 <日時> 2024年7月24日(水)13:00~17:00(受付12: 30~) <場所> 〒106-0047 東京都港区南麻布2-12-3 サイオスビル3F <得られるスキル> Azure OpenAI Serviceの基礎 Azure OpenAI Serviceがどのようなサービスであり、 どのように利用するのかを学ぶことができます。これにより、 クラウドベースのAIサービスの活用方法を理解し、 自身のプロジェクトに適用するための基礎を築くことができます。 RAGの仕組み RAG(Retriever-Augmented Generation)の基本的な仕組みを理解し、 独自データを活用した生成AIの基礎理論を学ぶことができます。 RAG構築方法 実際にRAGを構築するための基本的な手順を学びます。 ハンズオンを通じて、 独自データの準備から外部データベースへの登録、 そして生成AIを用いた回答生成までの流れを体験し、 実践的なスキルを身につけることができます。 <費用> 無料 <定員> 16名(先着順) <対象者> Azure OpenAI ServiceによるRAG実装ガイドをダウンロードされた方 企業にお勤めの方 <準備いただくもの> お名刺 無線LANを利用できるPC(Windows、 MacどちらでもOK) GitHubのアカウント(GitHub Codespacesの180CPU時間の無料枠利用のためFr eeでOK) Azureのサブスクリプション Azureのサブスクリプションで利用可能なAzure Open AI Service( 承認には時間を要するため以下のURLより早めにご申請ください 。ご用意が難しい場合は別途ご相談ください。) https://aka.ms/oai/access <注意事項> 本ハンズオンでは、 受講者ご自身のAzureサブスクリプションを使用していただく ことが前提となります。そのため、 サブスクリプションにかかる費用は受講者様のご負担となります。 ハンズオン中に発生するAzure利用料金は、通常、 数百円程度、1000円未満と見込んでおります。 Azure OpenAI ServiceによるRAG実装ガイドをダウンロードしていない 方がお申込みをした場合、キャンセルとさせていただきますので、 あらかじめご了承ください。   【有償】支援サービス 上級テクニカルトレーニング Azureの最先端技術を駆使したRAGハンズオンです。 このハンズオンでは、最新の検索手法である「 セマンティックハイブリッド検索」、Azure Static Web Apps、Azure Functionsによるフルサーバーレス構成など、 最新技術を用いたRAGの構築方法をお伝えします。 業務委託・技術支援 当社では、AIだけでなく、 クラウドネイティブなアプリケーション開発、 既存システムのクラウド移行・モダナイゼーション、 システムの基盤構築など、 クラウドを中心としたシステム開発あるいは技術支援なども行って おります。システムでの困り事がありましたら、 ぜひご相談ください。 チャットボット作成 (RAGツール開発) RAG(Retrieval-Augmented Generation)を中心に、 話題の生成AIを活用した業務の効率化、 DX化をお手伝いいたします。社内ノウハウの見える化、 カスタマーサポートの省力化、 チャットボットアプリケーションの導入など、 社内資源の有効活用をお考えの場合は、ぜひご相談ください。 AI関連アプリ開発 既存のアプリ・システムを、もっと便利に・ 楽にできないかお考えですか?RAGやLangChain などにより生成AIを活用すれば、 今まで以上により業務効率を上げるのに効率的なアプリの開発を行 うことができます。 まずはコンサルティングという形からご相談いただくことも可能で す。AIで迷われたら、ぜひご相談ください。 Azure CSP販売・技術支援 Azureのライセンス販売を通じてお客様のビジネスをご支援し ています。 Azureライセンスの提供からAI技術のコンサルティングまで 全て当社にお任せください。​​​​ ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post 【7/24無料開催】Azure OpenAI ServiceによるRAGハンズオン 〜独自データを用いた生成AIの利活用を学ぶ〜初級編 first appeared on SIOS Tech. Lab .
始めに 皆さんこんにちは!新卒3年目エンジニアの細川です。 今回はTypeScriptの型ジェネリクスについてまとめていこうと思います。 TypeScriptを書いてて、 <T> とかよく見るけど何それ?という方は是非読んでみてください! 型ジェネリクスって? 型ジェネリクスは、型を変数として受け取り、利用するという仕組みです。 皆さんも以下のような <T> とか <K> の記述をよく目にすることがあるかと思います。 type EchoType<T> = T type StringType = EchoType<string> // string型 これが型ジェネリクスです。Tという型変数を受け取り、それを右辺で利用することができます。この例では受け取った型をそのまま代入しているので、渡した型そのままとなります T の部分は引数の名前なので、なんでもいいのですが、慣例的に T や K などがよく使われます。 関数などの引数と同様に、複数の型を受け取ることもできます。 type UnionType<K, T> = K | T type StringOrBooleanType = UnionType<string, boolean> // string | boolean型 型のみ違う関数への利用 サバイバルTypeScript で利用方法として紹介されているものに、”型のみ”が異なる関数の実装を一つにまとめられるというのがあります。サンプルを見てみましょう。 まず、以下のような、五分五分の確立で1つめの引数か2つ目の引数のどちらかを返す関数を考えてみます。 const chooseRandomlyString = (v1: string, v2: string): string => {   return Math.random() <= 0.5 ? v1 : v2; } この関数を使う場合は以下のように記述します。 const winOrLose = chooseRandomlyString("勝ち", "負け"); console.log(winOrLose);// 勝ち or 負け 次に、文字列だけでなく、数値の抽選も行う必要が出てきた場合のことを考えてみます。 この場合、chooseRandomlyNumberを作る必要があります。   // 数値用の抽選関数 const chooseRandomlyNumber = (v1: number, v2: number): number => { return Math.random() <= 0.5 ? v1 : v2; } const num: number = chooseRandomlyNumber(1, 2); console.log(num); // 1 or 2 このように内部の実装が同じでも型が違うだけで複数関数を作成しなければならない場合に型ジェネリクスを利用することができます。   const chooseRandomly = <T,>(v1: T, v2: T): T => {   return Math.random() <= 0.5 ? v1 : v2; } chooseRandomly<string>("勝ち", "負け"); chooseRandomly<number>(1, 2); このように型変数Tを受け取ることで、一つの実装で様々な型に対応できるようになります。 注意点として、上記のようなアロー関数で記述する場合 <T,> のカンマを忘れるとエラーが出る点に注意してください。 応用編 この型ジェネリクスを応用することで、様々な便利な型を作成することができます。 例えば、以下のようにある型のundefined許容の型を作ったり、配列にしたり、型をより抽象的に定めることもできるようになります。 // undefined許容に変換 type Optional<T> = T | undefined // その型の配列型に変換 type ArrayType<T> = T[] // 受け取った型のvalue1, value2というプロパティを持つ型 type Box<T> = { value1: T; value2: T; } const numberBox: Box<number> = { value1: 42 , value2: 2}; const groupBox: Box<string[]> = { value1: ["apple", "banana"], value2: ["hoge"]}; 実際には他に MappedTypes などと組み合わせて、より強力な型を作成可能ですが、それは後程 MappedTypes についての記事を書く際に紹介しようと思います。 extendsについて extends を用いることで、受けとる型変数を制限することもできます。 元々 extends 自体はinterfaceの継承で使うものというイメージが強く他言語でも目にする機会もあると思います。(例: Javaのextends ) 以下に基本的な extends の使い方を示します。 interface People { name: string age: number } // Peopleを継承したEmployeeを作成 interface Employee extends People { companyName: string employeeNumber: number } // Peopleのプロパティに加えて、Employeeで追加したプロパティを持つ const emp1: Employee = { name: "Taro",      // Peopleのプロパティ age: 25,        // Peopleのプロパティ companyName: "SIOS", // Employeeのプロパティ employeeNumber: 12345 // Employeeのプロパティ } このような使い方は皆さんも馴染み深いものではないでしょうか? この extends を使うと、型ジェネリクスで受け取る型を制限することもできます。 使い方としては以下の通りです。 type MyString<T extends string> = T // MyStringは型変数としてstringしか受け取れない const mystr: MyString<string> = "mystr" T が extends の後ろの型を継承するようになり、例の場合ではstring型しか渡せなくなります。 渡そうとすると以下のようにコンパイルエラーとなります。 このように、型定義の型引数の名前を定義する部分に extends を追加することで、型引数として受け取る型を制限することができます。 TypeScriptの組み込みの型には結構 extends も利用されています。もし型の実装の中に extends を見つけたら、受け取る型を絞っているんだなと思いましょう。 まとめ 型ジェネリクスは引数として型を受け取って変数のように利用できる仕組み type UnionType<K, T> = K | T type StringOrBooleanType = UnionType<string, boolean> // string | boolean型 extendsを使うと受け取る型に制約を持たせられる type MyString<T extends string> = T // MyStringは型変数としてstringしか受け取れない const mystr: MyString<string> = "mystr" 終わりに 今回はTypeScriptの型ジェネリクスについてまとめました。 知っているとなんともないですが、知らずに見ると「難しそう!」と感じてしまうのではないでしょうか? この記事で少しでも型ジェネリクスへの理解が進めば幸いです。 型ジェネリクスを応用すると非常に強力で柔軟な型もたくさん作れるので、追々紹介したいと思います! 他にもTypeScriptの あれこれ についてまとめていますのでぜひ読んでみてください!   ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post TypeScriptのあれこれ⑥型ジェネリクス  とかextendsって何? first appeared on SIOS Tech. Lab .
サイオステクノロジー武井です。今回は、まだ今年半分は残っていますが、おそらく今年のベストバイ間違い無しのデジタルガジェット「Anker 733 Power Bank」を紹介したいと思います。 これは、モバイルバッテリーでありながら、ACアダプターにもなるというすぐれものです。3つのUSBポート (USB-C×2、USB-A×1)を備えており、iPhoneとMacへの給電が可能です。 そして自身もモバイルバッテリーとして動作するので、例えばACアダプターとして動作中に充電しておくことが可能です。 今までは、MacのACアダプター、iPhoneの充電器、そしてモバイルバッテリーと3つのものを持って外出していましたが、Anker 733 Power Bankはこれら3つの用途をすべてまかないます。 例えば、出社するときに電車に乗り、会社につきます。Anker 733 Power BankをMacのACアダプターとして会社でお仕事をしている間に充電して、帰りの電車の中でモバイルバッテリーとしてAnker 733 Power Bankを使います。 つまり、ACアダプターとして使いながら充電してくれるので、ざわざわ「充電する」ということを意識しなくても、いつの間にかモバイルバッテリーの電池はいつも満タンになっており、必要なときにいつでも使えるというものです。 まぁ、お値段もそれなりにはしますが、充電という手間は省けるし荷物は減るし、ホントいい感じです。 絶対これは買いですよ(^o^) ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post モバイルバッテリーAnker 733 Power Bankの紹介 first appeared on SIOS Tech. Lab .
こんにちは、サイオステクノロジーの佐藤 陽です。 今回は Azure の AI Services の 1 つである Azure AI Document Intelligence について入門していきたいと思います。 PDF や画像データを扱いやすいデータにしたい! RAG の開発で PDF の情報を独自データとして活用したい! Document Intelligence から返ってくるパラメータの構造が分からない。 といった方は最後までご覧ください。 特に、3つ目のDocument Intelligence から返ってくるパラメータについて知りたい方は コチラ へどうぞ! AI Document Intelligence概要 Azure AI Document Intelligence は Azure AI Services に含まれるサービスのひとつであり、pdf ファイルや画像データからの文字起こしが可能となります。 Document Intelligence には様々な事前学習済みのモデルが提供されており、一般的な文章の文字起こしや、領収書や請求書などの読み取りなど様々なデータに対応することが可能です。 GUI ベースで操作も可能で、数クリックするだけで簡単に画像からテキストデータを取得し、活用しやすい形へと変換することができます。 また発展的な利用として、 AI Document Intelligence と Azure AI Search を統合することで、RAG(Retrieval-Augmented Generation)をより強力なものにすることが可能 ともいわれています。 リソース作成について Document Intelligence のリソースなのですが 続々と Update が行われており、それらは以下のリージョンで先んじて行われているようです。 East US West US2 West Europe 最新の機能に触れるためにも、これらのリージョンでのリソース作成をお勧めします。 そもそもこれらのリージョンでないと、SDK が扱えなかったりするので注意です。 価格については、今回は Free プランで Document Intelligence のリソースを作成しました。 Free プランの制限として、pdf が最初の 2 ページしか読み取れなかったりしますが、検証には十分です。 また、おそらくですが Free プランは Azure のサブスクリプションあたり 1 つしか作成できません。 そのため新規に作成するためには既存のFreeプランのリソースを削除する必要があります。 ただ注意することとして、単にリソース削除するだけでは完全に削除されません。 「削除されたリソースの管理」というタブから完全に削除することで、新たに Free プランのリソースが作成できるようになります。 利用方法 Document Intelligence を利用する方法としては、以下 2 つがあります。 Document Intelligence Studio REST API & SDK Document Intelligence Studio GUI ベースでさくっと機能をお試しできます。 今回はこちらをベースに作業していきたいと思います。 REST API & SDK 実際にシステムに組み込むとなったら API や SDK を活用することになります。 SDK としては C#や python 用のものが提供されています。 今回は利用しませんが、 サンプルコード なども豊富なので是非見てみてください。 Model DocumentIntelligenceのモデルは大きく分けて3種類あります Document analysis Prebuilt models Custom model Document analysisとPrebuilt modelsは、Microsoft によって事前にトレーニングされた強力なモデル群です。 一方Custom modelに関しては、独自のトレーニングを行って作成するモデルになります。 本記事では Document analysis と Prebuild models にスポットを当てて紹介していきます。 Document analysis Document Analysisの モデル群を使用すると、 フォームやドキュメントからテキストを抽出し、文章を文字起こしすることが可能 です。 一般的な文章や、論文の解析などに使われることが多いように思います。 このDocument analysisにおいては Read Layout General documents の 3 種類のモデルが用意されています。 ただし、 General documents に関しては 公式ドキュメント において Document Intelligence バージョン 2024-02-29-preview、2023-10-31-preview 以降、一般的なドキュメント モデル (事前構築済みドキュメント) は非推奨となりました。 とあるため、今回は説明から除外したいと思います。 後ほど詳しく解説しますが、ReadモデルとLayoutモデルの違いとしては Read:文章のテキストを抽出 Layout:文章のテキストに加えて、ドキュメントの構造や表情報なども取得可能 といった感じです。 もちろん使用料金に関してはLayoutモデルの方が高い形となっています。 Layout (順序的にはReadモデルの方が先ですが、記事の解説の都合でLayoutモデルから解説します。) Layout モデルは、文章からテキストだけではなく、 構造や表情報なども取得することが可能 です。 また 文章の Markdown への変換機能 も備えており、このあたりも非常に強力です。 今回、文字起こしの対象とするデータとして、以下のような pdf データを用意しました。 表やグラフ、チェックボックスを含むよう作成しています。 (なお文章の内容に関しては ChatGPT に適当に作ってもらったものなので、参考にしないでください。) では以下のステップで分析の方進めていきます。 Document Intelligence Studio から Layout のモデルを選択 Browse for files から pdf をアップロード Run analysis のボタンをクリック 解析が完了すると、pdf 上にマーキングがされ、結果が右側のエリアに表示されます。 細かいパラメータは後ほど見ていきますが、ひとまず文章が正しく書き起こされていることが確認できます。 また、テーブル情報もチェックボックス情報も正しく読み取れていることが確認できます。 ただ、さすがに絵文字はうまく認識してくれませんでした Resultパラメータ解説 次に Result タブの内容を見てみます。 ここには、解析された結果が json 形式で表示されます。 ちなみにREST API や SDK を利用した場合も、この json 形式と同じフォーマットとして分析結果が得られます。 なお、これらのjsonの中には以下のような情報が含まれています。 SDK や API 、モデルなどの情報 要素の位置 要素の大きさ 文章の内容 構造(要素の親子関係) 信頼度 中身を見ると非常に細かい情報まで返してくれているのですが、いかんせん分かりづらいです。 そのため、今回はこのResultのパラメータについて細かく見ていきたいと思います! Result に説明コメントを付けて、以下のようなjson形式で表しました。 (可読性向上のため、内容を抜粋して書いています。) {   "apiVersion": "2024-02-29-preview", //使用されたAPIバージョン   "modelId": "prebuilt-layout", //使用されたモデルID   "stringIndexType": "textElements", //文字列のオフセットと長さを計算する方法   "content": "", //全体の文章,   "pages": [//抽出されたコンテンツ要素とレイアウト要素     {       "pageNumber": 1,       "angle": 0, //角度(時計回りの方向のコンテンツの一般的な向き)       "width": 8.5, //イメージ/PDF の幅       "height": 11, //画像/PDF の高さ       "unit": "inch", //幅、高さ、境界ポリゴンのプロパティで使用される単位       "words": [         //ページから抽出された単語         {           "content": "SIOS", //テキスト. ※日本語の場合は1文字ずつ           "polygon": [             //ページの左上を基準にして座標を指定した、単語の境界ポリゴン             0.9898, //左上x座標             1.1093, //左上y座標             1.4297, //右上x座標             1.1097, //右上y座標             1.4266, //右下x座標             1.2766, //右下y座標             0.9868, //左下x座標             1.2779 //左下y座標           ],           "confidence": 0.989, //単語を正しく抽出する信頼度           "span": {             //読み取り順序の連結されたコンテンツ内の単語の場所             "offset": 0, //スパンで表されるコンテンツの 0 から始まるインデックス             "length": 4 //スパンで表されるコンテンツ内の文字数           }         }       ],       "selectionMarks": [ // チェック ボックス、ラジオ ボタン、および選択範囲を示すその他の要素を表す選択マーク オブジェクト。         {           "state": "unselected", //選択されているかどうか(selected,unselected)           "polygon": [             //選択マークの境界ポリゴン。             //略           ],           "confidence": 0.988, //選択マークを正しく抽出する信頼度           "span": {             //読み取り順序の連結されたコンテンツ内の選択マークの位置             "offset": 1241,             "length": 12           }         }       ],       "lines": [         //単語や選択マークなどのコンテンツ要素の隣接するシーケンスで構成されるコンテンツ行オブジェクト。         {           "content": "SIOS HOGEHOGE TECHONLOGY", //コンテンツ           "polygon": [             //略           ],           "spans": [             //linesのoffsetとspan             {               "offset": 0,               "length": 24             }           ]         }       ],       "spans": [         //page自体のoffsetとspan         {           "offset": 0,           "length": 639         }       ]     }   ],   "tables": [     {       "rowCount": 5, //行数       "columnCount": 3, //列数       "cells": [         //テーブルに含まれるセル情報         {           "kind": "columnHeader", //セルの種類(content,rowHeader,columnHeader,stubHead,description)           "rowIndex": 0, //行のインデックス           "columnIndex": 0, //列のインデックス           "content": "技術分野", //セルの内容           "boundingRegions": [             //テーブルセルをカバーする境界領域             {               "pageNumber": 1, //境界領域を含む 1 から始まるページ番号               "polygon": [                 //ページ上の多角形の境界、または指定されていない場合はページ全体。左上を基準にして指定された座標.                 //略               ]             }           ],           "spans": [             {               "offset": 491,               "length": 4             }           ],           "elements": [             //テーブル セルの子要素             "/paragraphs/8"           ]         }       ]     }   ],   "paragraphs": [//一般的に、一般的な配置と間隔を持つ連続した行で構成される段落オブジェクト。     {       "spans": [         {           "offset": 63,           "length": 17         }       ],       "boundingRegions": [         {           "pageNumber": 1,           "polygon": [             //略           ]         }       ],       "role": "sectionHeading", //段落のセマンティックロール(FOOTNOTE, FORMULA_BLOCK,PAGE_FOOTER,PAGE_HEADER,PAGE_NUMBER,SECTION_HEADING,TITLE)       "content": "# 調査概要 2024 年9月4日"     }   ],   "contentFormat": "markdown",   "sections": [     //ドキュメント内のセクションを表すオブジェクト。     {       "spans": [         //読み取り順序の連結されたコンテンツ内の単語の場所         {           "offset": 0,           "length": 60         }       ],       "elements": [         //セクションの子要素。         "/sections/1"       ]     }   ],   "figures": [     {       "id": "2.1", //不明       "boundingRegions": [         {           "pageNumber": 2,           "polygon": [             //略           ]         }       ],       "spans": [         {           "offset": 639,           "length": 289         }       ],       "elements": [         //図の子要素(キャプションや脚注を除く)         "/paragraphs/23"       ]     }   ] } これで各パラメータの内容に関して雰囲気はつかめるかと思うのですが、もう少し詳しく解説していきたいと思います。 構造について Resultのjsonを構成する主な要素として、以下の配列オブジェクトがあります。 pages(ページ) tables(表) paragraphs(段落) sections(セクション) figures(図) 各要素について何となく名前から想像がつくのですが、それぞれの関係性がやや分かりづらく感じました。 そこでjsonの中から 構造(親子関係) を抜き出し、階層関係をまとめてみます。 (それぞれの要素が elements というパラメータを持っており、このパラメータにて構造(親子関係)が表現されています。) ※階層が深すぎると分かりづらいので、paragraphsを最下層として書いています。 ※重複している部分などはだいぶ省略して書いています。 sections/0   /sections/1     /paragraphs/0:"SIOS HOGEHOGE TECHONLOGY 111-1111 東京都ホゲ村 ホゲ番地 (+81) 000-0000"     /sections/2       /paragraphs/1:"調査概要 2024 年9月4日"         /sections/3           /paragraphs/2:"調査目的"           /paragraphs/3:""本市場調査の目的は、最新の IT 技術動向を詳細に把握し、各技術の市場シェア、成長予測、およ び競争状況を包括的に明らかにすることであり、特にクラウドコンピューティング、AI(人工知能)、loT (モノのインターネット)、およびブロックチェーン技術の各分野に焦点を当てるものである。"   /sections/4       /paragraphs/4:"調査方法"       /paragraphs/5:"1. プライマリーデータはアンケート調査およびインタビューによって収集し、直接的かつ現場の 視点から得られる情報を重視する一方で、セカンダリーデータは公開データベースおよび業 界レポートから取得し、信頼性の高い既存の情報源を利用して補完的なデータ収集を行う。"       /paragraphs/6:"2. データ分析に関しては、定量分析として統計解析ソフトウェアを駆使して大量の数値データを 精緻に解析し、定性分析として内容分析およびテーマ別分析を行い、収集されたデータの質 的側面を多角的に検討する。" /sections/5     paragraphs/7:"市場概況"     tables/0         cells/0             paragraphs/11":"クラウドコンピューティング"         paragraphs/8 "技術分野"     figures/0         paragraph/23~41 :"Market Size and Growth Rate of Major Technology Fields"     sections/6         paragraphs/42:"技術別市場シェア"     sections/7         paragraphs/43:"クラウドコンピューティング ♡"     sections/8         paragraphs/45:"AIN"         paragraphs/46:"AI 技術に関しては、IBM が市場シェアの 25%を占め、Google が 20%、Microsoft が 18%、その他が 37%を占めている。"         sections/9             paragraphs/47:"ブロックチェーン" また、このまま分かりずらいので図との対応表を作成しました。 このような形で pdf が各要素に分解され、それぞれの要素において位置情報やコンテンツの内容を含む構造となっています。 なおparagraphs/8という表現は、 jsonにおけるparagraphs[]配列の8番目の要素 を表しています。 この時に気を付けたい点としては、 json の階層と pdfの要素の階層は一致していない! ということです。 例えば json の階層としては pragraphs と sections は同じ階層にありますが、 pdf要素 としては sections が paragraphs を含むようになっています。 このあたり別に考える必要があるため気を付けましょう! Enum値について "role": "sectionHeading", //段落のセマンティックロール(FOOTNOTE, FORMULA_BLOCK,PAGE_FOOTER,PAGE_HEADER,PAGE_NUMBER,SECTION_HEADING,TITLE) といったようなEnum値の内容に関しては、 公式ドキュメント に説明があるのでこちらを参照ください。 wordの扱いについて pagesの配列の中にwordという要素が存在しています。 このwordに関して、日本語においては文字が1文字ずつ分割されてしまいます。 "words": [                   { "content": "概", "polygon": [ ], "confidence": 0.995, "span": { "offset": 63, "length": 1 } }, { "content": "要", "polygon": [ これは 公式ドキュメント にも書いてある通りです。 単語間にスペース区切りを使用しない言語の場合、セマンティックな単語単位を表していない場合でも、各文字は個別の単語として返されます。 そのため、日本語の文章を分析するとpagesの配列が膨大になりがちです。 この点、今後の改善に期待です。 その他のパラメータ 分析対象とする pdf の内容によっては、記事の中で触れていない要素が出てくる場合もあります。 そういった場合は 公式ドキュメント にて各要素のクラスが定義しているため確認してみてください。  Markdownへの変換 Layoutモデルの強力な機能のひとつとして、Markdownへの変換があります。 Analyze optionsのボタンをクリックし、その中でOutput form styleをMarkdownにします。 この状態で分析を行うと、Markdownというタブでの結果が表示されます。 また、Resultの中に入っている最上位の content の中身がMarkdownの形式として出力されます。 精度は完ぺきではないですが、このくらいのレベルでpdfをMarkdownに変換してくれるのは助かります。 文章の構造を認識できるLayoutモデルならではの機能ですね。 Markdownへ変換するメリット Layoutモデルの機能として、Markdownへ変換が可能なことが分かりました。 これによって得られるメリットとして、生成AIとの親和性の高さが言えるかと思います。 プロンプトエンジニアリングの一つに「 明確な構文を追加する 」というものがあります。 また、さらに 使用する構文がわからない場合は、Markdown または XML の使用を検討してください。 モデルは、XML と Markdown の大量の Web コンテンツでトレーニングされており、より良い結果が得られる可能性があります。 といった記載もみられます。 つまり、 生成AIはMarkdownの構文を理解しやすい ということが言えます。 そのため、Document Intelligenceで抽出したMarkdownのテキストを生成AIに投げることによって、より質の高い回答が得られることが期待できます。 Document IntelligenceとRAGを組み合わせたケースなどで効果を発揮しそうですね。 手書き文書 先程はpdfということで、文字崩れがないデータの読み取りを行いました。 一方で「手書きの文章の画像データを読み込む」というユースケースも大いにあり得るかと思います。 分析を行う画像として、以下のものを用意しました。 それでは分析してみます。 さすがにだいぶ崩した文章は難しいですが、それなりに汚い字でも正しく読み取ってくれました。 またこの時、Resultのjsonの中身を見てみると、先程までは含まれていなかった styles という配列オブジェクトが見られました。 中身としては以下のような感じです。 "styles": [ // 観察されたテキストスタイルを表すオブジェクト     {         "confidence": 1, //信頼度         "spans": [             {                 "offset": 0,                 "length": 30             }         ],         "isHandwritten": true // コンテンツが手書きかどうかを示す     } 基本的には先ほども出てきたパラメータですが、 isHandWritten のパラメータが新規なパラメータとして存在しています。 その名の通りですが、手書きである事の判定パラメータであり、判定が正しく行われています。 Read 次に Read のモデルを見ていきます。 Read は Layout と比較して、文章のテキスト読み取りだけの機能を持ちます。 そのため文章の構造情報やテーブル情報などは読み取ることができません。 早速 Read モデルを利用し、先程と同じ pdf を分析してみます。 結果のタブを見ると「Text」しかなく、Layout で見られたような「Tables」や「Selection marks」などが無いことが分かります。 次に Result タブから json 形式の値も見てみたいと思います。 先ほど挙げた主な構成要素に関してみてみると、Layoutと比較して pages paragraphs しか含まれていないことが分かります。 Layoutモデル に含まれていた tables sections figures に関しては存在していません。 これが構造に関する情報の読み取りをしていないということの表れでもあります。 テキストだけ分かればいいというのであれば Read モデルで十分という判断ができそうです。 ちなみに Layout と Read では使用するにあたり、価格が異なります。 Prebuild models 事前構築済みモデルを使用することで、独自モデルのトレーニングや構築をしなくても様々なドキュメントを処理することができます。 Document analysisは一般文書がターゲットでしたが、こちらの事前構築済みモデルは請求書、領収書、名刺といった特定のドキュメントの解析に対する強みを持ちます。 様々なモデルがありすぎるので、全部は試せませんが 今回は名刺の分析を行ってみたいと思います。 Business cards 名刺のモデルを選択し、先程と同じステップを踏んで分析していきます。 今回は用意されているサンプル画像を利用します。 早速分析してみると、正しく各情報が抽出できていることが確認できます。 また、Resultの値を見ると documents という配列オブジェクトがあるのが分かります。 中身を少し見てみると、 docType として businessCard が指定されており その下のfieldsの中で、住所や氏名情報が含まれていることが分かります。 "documents": [     {         "docType": "businessCard",         "boundingRegions": [             {                 "pageNumber": 1,                 "polygon": [                     0,                     0,                     1024,                     0,                     1024,                     768,                     0,                     768                 ]             }         ],         "fields": {             "Addresses": {                 "type": "array",                 "valueArray": [                     {                         "type": "address",                         "content": "〒108-0075 東京都港区港南 2-16-3" まとめ 今回は、Azure AI Servicesの一つであるAzure AI Document Intelligenceに入門してみました。 Document Intelligence Studioという、GUIでも扱いやすいサービスも提供されており、簡単に画像の分析ができることが分かりました。 ただ返されるパラメータがやや複雑ということもあり、その点は本記事を通して理解してもらえればと思います。 また、今回は入門編ということで基本的な機能だけを触っています。 まだまだ触れていない機能が盛りだくさんなので、引き続き勉強して記事にしていこうと思います ではまた! 参考 Azure AI Document Intelligence のドキュメント 【最新】Azure AI Document Intelligence による文書構造の解析(Markdown、図、セクション) ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post Azure AI Document Intelligence入門【Resultパラメータ解説付き!】 first appeared on SIOS Tech. Lab .
DevOpsの歴史、導入メリット、そして直面する障壁について詳しく解説します。CI/CD、自動化、文化変革に関心のある方向けの導入記事になります。例として「GitHubで見てみるDevOps」を作っています。 ご挨拶 こんにちは、久しぶりです。最近、ブログ以外の外部発信活動を整備している龍です。目に見える成果がないのが、少し辛いですね。 今回は、「DevOps」についてまとめていきます。インターネットで情報を探していると、たまに見かけますよね。私もふわっと理解するところから始めました。最近は文脈上でよく使うので、ここで歴史を含めてまとめたいと思います。 特別な前提知識は必要ありませんが、GitHubを使ってCI/CDを組んだことがある方にとっては、理解しやすい内容だと思います。「ウォーターフォール」・「アジャイル」・「MVP」などのプロジェクトの進め方に関しては、 こちらの記事 でまとめています。 それでは始めましょう。 歴史的背景 DevOpsがどのような経緯で生まれたのかについて説明する前に、まずその背景を紹介します。 アジャイル開発 アジャイル開発は、実装したい機能を細分化し、要件定義からリリースまでを一つのサイクル内で行う開発手法です。 – 「要件定義」を行い、機能ごとの小さな開発サイクルで開発する – 「設計」を機能ごとに行うため、急な仕様変更に対応できる – すべての機能開発が終了せずに基本機能のみ開発が終了すればリリースできる – 頻繁なリリースによって迅速な機能追加・変更が可能 最大の特徴として、サイクル終了ごとにリリースが行われます。これにより、「ウォーターフォール開発」に比べて高頻度なリリースが可能となります。 メリット・デメリット リリースがサイクルごとに行われるため、仕様変更に柔軟に対応することが可能です。アジャイル開発は広く実践され、そのキーワードは深く浸透しています。 アジャイル開発が適しているサービスとしては、「自社サービス」のように機能を細分化して開発を進められるものがあります。 アジャイル開発を支える技術としては、 自動化 というキーワードがあり、GitHubやCI/CDが挙げられます。 CI/CD アジャイル開発を支える技術としてのCI/CDについて説明します。CI/CDは以下のような意味を持っています。 CDは二つの意味を持ち、どちらもリリースに関する内容です。CI/CDでは『自動化』が重視され、特にビルド・テスト・デプロイのステップの自動化が注目されています。 GitHubで見るCI/CD 開発体験としては、GitHubのソース管理も重要です。その流れを含めて、『GitHubで見るCI/CD』として図化します。 GitHubでCI/CDを実現する方法としては、GitHub Actionsを使用します。 Pull Request上でCIのみを実行し、特定のブランチにマージされた際にCI/CDを一緒に実行します。 CI/CDを実行するタイミングやレビューや開発者の取り組みは、ブランチ運用やテスト戦略の文脈と共に考える必要があります。これはプロジェクトごとの判断になるため、また別のブログで詳しく説明します。 この環境を整備することで、開発者やレビュワーがソースの変更を加えることで、リリースを行うことが可能となります。 アジャイルからDevOpsへのつながり アジャイル開発からDevOpsが提唱された背景について説明します。アジャイル開発が広く浸透し、開発チームのコミュニケーションが促進され、プロジェクトのスピードが上がりました。 2008年のカンファレンス では、プロジェクトを運用するインフラチームと開発チームとの確執について問題提起がなされました。開発チーム内でのコミュニケーションは向上しているものの、運用チームとのコミュニケーションがうまくいっていないという現場の声がまとめられています。 その後、 2009年に運用チームと開発チームの連携を密に取ることを解決策として『DevOps』という単語が提唱 されました。ここでは開発チームと運用チームが目指すゴールの違いに注目し、最終的なゴールはより良い体験をユーザーに提供することとしました。 このような背景から、『DevOps』には「アジャイル」的アプローチが根底にあり、開発チームと運用チームが協力してより良いプロジェクトを実現するという『概念』が生まれました。 Agile2008 Conference「 Agile Infrastructure & Operations 」 Velocity 2009「 10+ Deploys per Day: Dev and Ops Cooperation at Flickr 」 DevOps まず理解すべきは、「DevOps」は開発手法ではなく、運用チームと開発チームが協力し、より良いプロジェクトを目指すための考え方であるということです。まずその根本的な考え方を説明し、次に「DevOps」を実現する方法を解説します。 DevOpsの考え方 「DevOps」は上記のような図で表現されることが多いです。DevOpsでは、「開発チーム」と「運用チーム」の二つのチームを一つに統合し、同一のゴールを目指すことを提唱しています。 開発チームと運用チームはそれぞれ異なるゴールを目指していますが、DevOpsの考え方では、これらを統合し「プロジェクトの目的達成」という共通のゴールを追求する一つのDevOpsチームを形成します。 DevOpsに関する誤解 「DevOps」はツールを使って実現するという誤解がありますが、実際は、プロジェクトに関わる全ての人が円滑にプロジェクトに参加し、目的達成を目指すという考え方が根底にあります。この考え方を実現するためのツールが多く存在していますが、DevOps自体は考え方そのものです。 DevOpsの流れ DevOpsの概念図は英語で表現されていますので、それを日本語に訳して図化します。 開発手法においては、「計画」から「デプロイ」までに焦点が当てられています。しかし、DevOpsでは「運用」から「継続的なフィードバック」までを統合し、一つのプロセスとして捉えます。「運用」や「監視」でプロジェクトの問題点を特定し、「継続的なフィードバック」でプロジェクトの変更点を「計画」に反映させていきます。 DevOpsで重要な「キーワード」 DevOpsを実現するために重要なキーワードは「自動化」と「DevOps Culture」です。 自動化 は、DevOpsの基礎となるアジャイル開発手法からも理解しやすいです。顧客の要望が直接伝わる現場では、「ビルド」から「デプロイ」までをCI/CDで自動化することで、迅速な開発スピードを実現しつつ、「継続的なフィードバック」により要望を取り込むことが可能になります。 DevOps Culture は、「Respect」「Trust」「Healthy attitude about failure」「Avoiding Blame」の四つのキーワードで構成されています。これらを日本語に訳すと、「尊敬」「信頼」「寛容」「責任の共有」となります。DevOpsの目的は、異なる目的を持つもの同士が一つのゴールを共に追求することです。これらのキーワードは、プロジェクト運用だけでなく、人生にも通じるものです。 DevOpsのメリット DevOpsのメリットは以下の観点で考えられます。 人的ミスの防止 自動化プロセスにより手作業が減少し、標準化が推進されます。これにより、人的ミスが大幅に減少し、信頼性の高いシステム運用が可能となります。 生産性の向上 開発チームと運用チームの協力により、コミュニケーションが円滑になり、生産性が上がります。迅速な問題解決と効率的なタスクの進行が可能になります。 高品質かつ迅速な開発 頻繁なリリースとフィードバックサイクルを通じて、品質を保ちつつ迅速な開発を実現します。継続的なテストとデプロイにより、バグの早期発見と修正が可能です。 ランニングコストの削減 自動化と効率化により、開発と運用のコストが下がります。手作業の削減により人件費が減少し、システムのダウンタイムや障害対応のコストも軽減されます。 予定外の作業のスムーズな解決 継続的な監視とフィードバックにより、予想外の問題や変更に素早く対応できます。問題が発生した際も、自動化されたプロセスと迅速なコミュニケーションによりスムーズに解決できます。 DevOps導入の障壁 DevOpsにおける障壁としては、以下の観点が考えられます。 必要な知識の導入 効果的なDevOpsの導入には、開発者や運用担当者がCI/CD、インフラ管理、監視ツールなどの知識を身につける必要があります。これらの学習曲線は障害となることがあります。 企業やチームの文化 DevOpsの成功は、開発チームと運用チームの協力に依存しています。既存の文化や習慣を変えることは困難であり、特にセクショナリズムが根深い組織では抵抗が生じることがあります。 学習コスト DevOpsのツールやプロセスを学ぶためには時間とリソースが必要です。新たなスキルの習得やトレーニングに関するコストは、導入の障壁となることがあります。 導入コスト 新しいツールやシステムの導入には初期投資が必要です。インフラの整備、ツールの購入、運用体制の構築には費用がかかり、特に小規模な組織には大きな負担となることがあります。 GitHubで見るDevOps 開発でよく使われるGitHubを例に、「GitHub機能で見るDevOps」をまとめてみます。 プロジェクトは「GitHub Project」で管理します。ここでは、プロジェクトの進行管理やタスクのチケット管理などを行います。実際のタスクは「issue」として起票し、開発者に割り当ててチケット管理を行います。運用を担当する人が「GitHub Project」に参加し、起票することで、全ての計画や要望が集約されます。 今回の図には含めていませんが、SlackやTeamsなどの「コミュニケーションツール」も重要な要素となります。GitHubと連携して通知をコミュニケーションツールに送ることで、関係者の見落としを防ぐことができます。どの程度の通知を実装するかは、重要な要素となります。通知が多すぎると、通知の意味がなくなることもあります(例えば、迷惑メールに埋もれる重要なメールなど)。 まとめ 今回の記事では、DevOpsという概念について、その起源と歴史的背景を深く掘り下げて解説しました。GitHubを使って、DevOpsの適用方法についてもまとめました。次回の記事では、プロジェクトを進める際に必要な仕様書に注目して解説します。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post DevOpsの基礎知識:歴史、利点、導入時の障壁とは? first appeared on SIOS Tech. Lab .
このブログでは、プロジェクトの開発手法(ウォーターフォール、アジャイル、MVP)について詳しく解説します。各手法の特徴、メリット、デメリット、向いているプロジェクトの種類について学んでいきましょう。 ご挨拶 皆さん、こんにちは!龍です。長らくブログの更新を休んでいましたが、今回は久しぶりに執筆をしています。YouTubeへの出演など、ブログ以外の活動も行っていますが、常に学び続けて良いブログを書くための知識を深めています。 今回は『プロジェクトの開発手法』について解説します。X(旧:Twitter)などで話題になることもありますね。業務を通じて得たプロジェクト進行に関する体験をもとに、所感を交えながら執筆していきます。こちらの解説をベースに「DevOps」の解説を進めていきます。 DevOpsの記事はこちら です。 プロジェクトの進め方 開発手法をまとめてみます。具体的には「ウォーターフォール」「アジャイル開発」「MVP開発」について説明します。 ウォーターフォール開発 ウォーターフォール開発は、「要件定義」から「リリース」まで上流から下流まで順番に進めていく手法です。一つ一つのステップが終了するごとに次の工程に進むため、要件定義や設計が進まなければアプリケーション開発に入ることができません。各フェーズに対する理解が深まるため、各ステップの重要性が際立ちます。 – 「要件定義」から「リリース」まで上流から下流まで順番に進める – 前の工程に問題が発生した場合、手戻りの影響が大きい – 上流工程の品質を担保する必要がある メリット 各フェーズごとに分担して開発 スケジュールの管理がしやすい 理想的な状態(バグもなければ、仕様変更もない)では、スケジュールの管理がしやすいプロジェクト手法です。 デメリット 仕様変更が発生した場合の影響が大きい すべての要件を考慮する必要がある 上流から下流までのすべてのステップがつながっているため、一つのステップが遅れることで「手戻り」としてスケジュールに影響します。仕様変更や要件漏れが発生するたびに影響が大きくなります。 向いているプロジェクト ウォーターフォール向きなプロジェクトは、比較的要件が定まっているシステムです。 アジャイル開発 アジャイル開発は、「設計」から「リリース」までを1サイクルとして、短いスパンで繰り返すことで機能を開発する手法です。実装したい機能を細分化してサイクルに当てはめていきます。要件定義はサイクルごとに行い、サイクルの終了ごとにリリースが行われるため、頻繁なリリースが発生します。最終的なゴール(製品)に向かってマイルストーン(小さな機能)を設定しながら進む開発手法です。 – 「要件定義」を行い、機能ごとの小さな開発サイクルで開発する – 「設計」を機能ごとに行うため、急な仕様変更に対応できる – すべての機能開発が終了せずに基本機能のみ開発が終了すればリリースできる – 頻繁なリリースによって迅速な機能追加・変更が可能 メリット 仕様変更に柔軟に対応できる リリースの頻度が高く、高い開発スピード 機能ごとに「要件定義」を実施するため、柔軟に仕様変更に対応できます。それすなわち、フィードバックを取り込みやすくなるということでもあります。 デメリット メンバー全員に設計からテストのスキルが必要 スケジュール管理が難しい スケジュール管理が複雑になる点です。僕が知っている手法では、1サイクルを2週間と設定してアジャイル開発を行っていました。1サイクルの中で対応する機能を適切に分割する必要があります。適切に分割されていない場合、サイクル内に対応できなかったり、予定よりも多い時間を投入したりといった事態が発生します。アジャイル開発を実施するには、アジャイル開発の手法に対する知識が必要です。 向いているプロジェクト アジャイル向きなプロジェクトは、機能を細分化して実装できるシステムです。比較的に仕様の決定権がチームと近い位置にあるプロジェクト、自社サービスなどが向いています。 MVP(Minimum Viable Product) MVPは「アジャイル」と混同されがちな開発手法です。実際に僕も勘違いしていました。 MVPは、リリースごとに目的をはっきりとさせて実装していく手法です。「アジャイル」や「ウォーターフォール」では機能のリリースに注目しますが、「MVP」ではリリース後のフィードバックを取り込んでプロジェクトを成長させることに注目しています。 以下のようなイメージで進めます。 Ver 目的 成果物 1 甘いもの クッキー 2 柔らかい甘いもの 薄いパンケーキ 3 柔らかく、ホイップクリームがのっている甘いもの ベルベットケーキ 4 柔らかく、ホイップクリームと果物がのっている甘いもの 豪華なパンケーキ 最初に「甘いもの」の最小限の要望で「クッキー」を作りました。その後、フィードバックを受けながら最終的に「豪華なパンケーキ」にたどりつきました。フィードバックを取り込みながら開発を進めるのが「MVP開発」の最大の特徴です。 メリット フィードバックを開発に取り込みやすい リリースの頻度が高く、高い開発スピード デメリット フィードバックの分析や解析の知識が必要 スケジュール管理が難しい 大規模な開発には適応が難しい点が挙げられます。 プロジェクトの目的が明確に決まっていない場合、フィードバックの選択によって当初想定していたプロジェクトとは異なるプロジェクトになる可能性があります。 向いているプロジェクト フィードバックをもとに取り込むため、比較的小さなプロジェクトや仕様が決まっていない(プロトタイプ)開発に適しています。 実際に「MVP開発」に取り組んで学んだ観点ですが、プロジェクトの目的を忘れてはなりません。「フィードバック」が大きな要素となります。どのフィードバックを機能として盛り込むのかは、プロジェクトの目的と照らし合わせながら判断する必要があります。目的がぶれると、作成段階でまったく異なるアプリケーションになる可能性があります。 比較 どの開発手法が良いかはプロジェクトごとに判断する必要があります。ここでは、メリットとデメリットを列 挙し、所感を交えながらどのようなプロジェクトに向いているかを述べます。 どの開発手法を採用するにしても、要件定義はしっかりとする必要があります。「ウォーターフォール」と比較して、他の二つでは高頻度なリリースが想定されます。高頻度なリリースが発生する開発手法では、GitHubを活用したCI/CD環境の構築などが必要です。 おわり 今回の記事をまとめましょう。今回はプロジェクトの開発手法について詳しく見てきました。それぞれの手法には特徴、メリット、デメリットがあり、また、特定の種類のプロジェクトに向いていることを理解することが重要です。 「ウォーターフォール」は一つ一つのステップを順番に進める手法で、要件が比較的決まっているプロジェクトに適しています。「アジャイル」は短いスパンで開発を繰り返す手法で、機能を細分化して実装できるプロジェクトに適しています。そして、「MVP開発」はリリースごとに目的を明確にして実装を進め、フィードバックを取り込むことに焦点を当てた手法で、仕様が決まっていないプロジェクトやプロトタイプ開発に適しています。 それぞれの手法の選択はプロジェクトの具体的な状況や要件によります。適切な手法を選ぶことで、開発の効率性と成功率を高めることができます。 次回のブログでは、DevOpsについて詳しく解説します。DevOpsは開発(Development)と運用(Operations)の統合を目指す考え方で、アジャイル開発やMVP開発など高頻度リリースを支えるための重要な手法です。次回もお楽しみに! それでは、今回はこれで終わります。ご覧いただきありがとうございました。 ご覧いただきありがとうございます! この投稿はお役に立ちましたか? 役に立った 役に立たなかった 0人がこの投稿は役に立ったと言っています。 The post プロジェクト開発手法を解説:ウォーターフォール、アジャイル、MVPの特徴 first appeared on SIOS Tech. Lab .