Taste of Tech Topics

Acroquest Technology株式会社のエンジニアが書く技術ブログ

Amazon Bedrock と Pinecone でマルチモーダル検索を行う

こんにちは、機械学習チーム YAMALEX の駿です。
YAMALEX は Acroquest 社内で発足した、会社の未来の技術を創る、機械学習がメインテーマのデータサイエンスチームです。
(詳細はリンク先をご覧ください。)

皆さんは、飼っている猫が寂しそうだから兄弟みたいな犬を連れてきてあげようかな、と思ったことはありませんか?

私は猫も犬も飼ったことがないので何とも言えませんし、なぜ犬かはさておき、マルチモーダル検索を使えばそんな要望にも応えることができます。


茶トラにはレトリーバーがお似合い

概要

マルチモーダル検索

マルチモーダル検索とは、テキストだけではなく、画像や音声などのデータも利用して情報検索を行う技術です。

例えば、画像を元に検索したり、テキストと画像を合わせて検索したりすることができるようになります。

今回は Amazon Bedrock 上で使える Titan Multimodal Embeddings と、外部サービスの Pinecone を組み合わせて、マルチモーダル検索を実現します。

Titan Multimodal Embeddings

Titan Multimodal Embeddings は Bedrock 上で利用可能な埋め込み(Embedding)モデルです。
入力としてテキスト、画像、またはその両方を受け取り、特徴を埋め込んだベクトルを出力(ベクトル化)します。

テキストに基づいた画像検索や、画像間の類似度検索など、複雑な検索クエリに応答できます。

aws.amazon.com

Pinecone

Pinecone はベクトルデータを高速かつ安価で扱うために設計されたマネージドのベクトルデータベースです。

Python クライアントが用意されており簡単に利用できるだけでなく、他のベクトルデータベースと比べて最大で50倍も安くデータベースを利用できるそうです。

www.pinecone.io

構成

下記処理を行うシステムを構築しました。

① 検索用画像を受け取る
② Bedrock の Titan Multimodal Embeddings でベクトル化する
③ Pinecone で類似画像を検索する
④ 検索結果をユーザに返す


構成図

なお、検索対象のデータとして、こちらのデータセットをあらかじめベクトル化し、Pineconeに保存しました。
全部入れると安価とは言えど高額になってしまうため、犬、猫、ハムスターを各70枚ほどずつに絞ってあります。

www.kaggle.com

Titan Multimodal Embeddings でベクトル化する

下記のコードを用いて、画面から受け取ったBase64文字列化された画像をベクトル化しました。

出力ベクトル次元は1024、384、256のいずれかを選択できますが、今回はデフォルトの1024次元にしました。

入力する画像/テキストには下記制限があるため適宜画像のリサイズなどが必要になる場合があります。
なお、画像は制限に収まっている限り、画像サイズや比率に制限はありません。

# 形式 上限
1 画像 25MB × 1枚
2 テキスト 128トーク
bedrock = boto3.client("bedrock-runtime") model_id = "amazon.titan-embed-image-v1"   def invoke(image_base64: str = None, text: str = None) -> list[float]:     """画像とテキストをベクトル化する"""     body = {}     if image_base64:         body["inputImage"] = image_base64     if text:         body["inputText"] = text      response = bedrock.invoke_model(         body=json.dumps(body),         modelId=model_id,     )     # 1024次元のベクトルが取得できる     return json.loads(response["body"].read())["embedding"] 

Pinecone で類似画像を検索する

下記コードを用いてTitan Multimodal Embeddingsが出力したベクトルで画像を検索します。
Titan Multimodal Embeddingsが出力するベクトルが1024次元なので、Pineconeの設定も1024次元で作成してあります。

なお、Pineconeには画像のベクトル化された配列と、メタデータとして元画像のファイルパスが保存されており、元画像本体は保存していません。
検索後にメタデータのパスを参照し、画像を画面に表示します。

index = Pinecone(api_key=API_KEY).Index(INDEX_NAME)   def upsert(vectors: list[list[float]], paths: list[str]):     """ベクトル化した画像を保存する      各リストの同一番目の要素は同じ画像の情報を保持しているものとする     """     entries = [         {             # IDは何でもいいが、同じ画像に対して同じ値になるといい             "id": path,             # これが検索対象のベクトル             "values": vector,             # metadataの中身も特に規定はないため、検索時や検索後に使いたい情報を入れる             "metadata": {"path": path},         }         for vector, path in zip(vectors, paths)     ]     index.upsert(vectors=entries)   def query(vector: list[float]) -> list[dict]:     """ベクトル値で検索を行う      ここでは上位5件の検索結果を返却している     """     response = index.query(         # 検索するベクトル         vector=vector,         # 取得件数         top_k=5,         # 検索結果のベクトル値をレスポンスに含めない         include_values=False,         # 検索結果のメタデータはレスポンスに含める(画像パスを取得するため)         include_metadata=True,     )      results = []     for result in response.get("matches", []):         results.append({             "path": result["metadata"]["path"],             "score": result["score"],         })     return results 

できること

今回は上記構成のFastAPIアプリをローカル実行して、どんな検索が可能になるのかを確認してみました。

テキストでの検索

「茶色」で検索すると茶色い動物たちの画像がヒットしました。


茶色い動物を検索できる

画像での検索

マルチモーダルなので、テキストだけではなく画像もベクトル化できます。


おもちゃを持った犬を検索できる

カテゴリを指定した検索

今回は③「Pineconeで類似画像を検索する」の部分でカテゴリ(犬、猫など)によるフィルタを設けることで、単に似ている画像というだけでなく「この猫に似ている犬の画像」の検索も実現しました。


[再掲]茶トラにはレトリーバーがお似合い

処理時間

下記条件で実行した際の処理時間を表に示します。

  • Bedrockで処理している画像のサイズは800x800
  • Pineconeは1024次元のベクトルで220件の中から検索する
  • PineconeはAWS上のServerless タイプを使用
# 検索方法 Bedrock
レスポンス
Pinecone
レスポンス
合計 画面に返るまで
1 テキスト ~0.9s ~1.0s ~1.9s ~3.5s
2 画像 ~1.4s ~1.0s ~2.4s ~4.0s

テキストをベクトル化するのよりも、画像をベクトル化するほうが時間がかかるようです。 直感とも一致しますね。

Pineconeで検索するときには、どちらも1024次元のベクトルに埋め込まれているため、実行時間に差はありませんでした。

なお「画面に返るまで」の時間には、画像のリサイズなどのデータ変換の時間を含みます。

まとめ

Titan Multimodal EmbeddingsとPineconeを使ったマルチモーダル検索エンジンを構築し、遊んでみました。

それぞれのAPIをただ呼び出しているだけですが、想定していたよりも求めていた結果が得られて驚いています。
素晴らしい!

Acroquest Technologyでは、キャリア採用を行っています。
  • ディープラーニング等を使った自然言語/画像/音声/動画解析の研究開発
  • Elasticsearch等を使ったデータ収集/分析/可視化
  • マイクロサービス、DevOps、最新のOSSクラウドサービスを利用する開発プロジェクト
  • 書籍・雑誌等の執筆や、社内外での技術の発信・共有によるエンジニアとしての成長
  少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。 www.wantedly.com

Sakana.aiが公開した「Evolutionary Model Merge」手法を「mergekit」で実施してみる

皆さんこんにちは
機械学習チームYAMALEX@tereka114です。
YAMALEXは Acroquest 社内で発足した、会社の未来の技術を創る、機械学習がメインテーマのデータサイエンスチームです。
(詳細はリンク先をご覧ください。)

日々、LLMが進化していて、画像が本職(のはず)の私ですら、ここ数年LLMの勉強をはじめています。
学習してモデル公開しましたといった記事はよく見ますが、今回は今、非常に注目されている倭国に拠点があるAIスタートアップである「Sakana.ai」が公開した「Evolutionary Model Merge」を使う話をします。

Evolutionary Model Merge

Evolutionary Model Merge」は「Sakana.ai」から発表された進化的モデルマージと呼ばれる技術です。
端的に言ってしまえば、複数のモデルを利用して新しいモデルを作ります。これにより、例えば数学の知識を持つモデルとECサイトの知識を持つモデルがあったときにECと数学の知識を持つモデルの生成ができます。

Evolutionary Model Mergeのイメージ図(公式ブログより)

この方式では2つのマージ方式を使っています。

1. 既存モデルから層を採用する。
2. 既存モデルの重みを混ぜ合わせる。

しかし、この2つのマージ方式をどうするのか(混ぜ合わせパラメータやどの層を使うのかetc..)を人力で取り組んで成功させることは複雑すぎてできていませんでした。
Evolutionary Model Merge」はこれらの複雑なマージをするために進化的な計算を取り入れるアプローチを組み込むことで、自動で複雑なマージを実施し、高精度化を実現しました。

構築済のものをマージすることで良い精度を出せるのはありがたく、一から学習するよりも容易です。今回実施するように個人環境でも十分動きます。
この技術を使ってドメイン特化のモデルを作りやすくなるのかなといった感触です。今回はこのEvolutionary Model Mergeをmergekitで試します。

※進化的な計算とは何か・と言った説明は公式の方で詳しくされていますので、次の公式ページを参照してください。この記事では実際の使い方などを解説します
sakana.ai

※Evolutionary Model Mergeオリジナルのリポジトリ、公式作成済モデル(EvoLLM-JPなど)も公開されています
github.com

EvoMergeを試す

Merge Kit

本手法は以下の「mergekit」に組み込まれています。
mergekit」は、LLM学習済モデルのマージをする機能を持つ汎用ライブラリです。
github.com

開発元の次のブログを参考にして動かしてみますが、一部動作しないところがありましたのでその点をこの記事では修正しています。
blog.arcee.ai

インストール

まずは「merge-kit」のインストールです。
以下のコマンドを実行します。

git clone https://github.com/arcee-ai/mergekit.git cd mergekit pip install -e .[evolve]

設定ファイル

設定を次の通りに記述しました。
今回はspartqaのデータセットを利用しますが、データセットの量が多いので、サンプリングします。

import datasets ds = datasets.load_dataset("metaeval/spartqa-mchoice") slice_ds = ds["test"].select(range(200)) ds["test"] = slice_ds slice_ds = ds["train"].select(range(200)) ds["train"] = slice_ds ds.save_to_disk("./spartqa-mchoice-200") 

次に以下の設定を記載します。

eval_tasks/spartqa_train.yaml

task: spartqa_train dataset_path: arrow dataset_kwargs:   data_files:     train: spartqa-mchoice-200/train/data-00000-of-00001.arrow     test: spartqa-mchoice-200/test/data-00000-of-00001.arrow output_type: multiple_choice training_split: train validation_split: train test_split: train doc_to_text: !function preprocess_spartqa.doc_to_text doc_to_choice: [ 'A', 'B', 'C', 'D' ] doc_to_target: "{{answer}}" metric_list:   - metric: acc     aggregation: mean     higher_is_better: true metadata:   version: 1.0 

次のPythonスクリプトも保存します。
これは、データセット1レコードを取得し、文章を構築して返す関数を定義し、与えられたデータの前処理を行います。
このパスは「eval_tasks/spartqa_train.yaml」のdoc_to_textの値に対応しています。

eval_tasks/preprocess_spartqa.py

def doc_to_text(doc) -> str:     answer_chunks = []     for idx, answer in enumerate(doc["candidate_answers"]):         letter = "ABCD"[idx]         answer_chunks.append(f"{letter}. {answer}")     answers = "\n".join(answer_chunks)     return f"Context:\n{doc['story']}\n\nQuestion: {doc['question']}\n{answers}\nAnswer:" 

そして、merge-kitで利用するモデル設定ファイルを作ります。マージ実行時にダウンロードがはじまります。
Mistral7Bを3種類のデータでInstruct Tuningをしたモデルに対して実施します。これにより3種類の特性を持ったモデルの作成を目指します。

evol_merge_config.yml

genome:     models:       - NousResearch/Hermes-2-Pro-Mistral-7B       - PocketDoc/Dans-AdventurousWinds-Mk2-7b       - HuggingFaceH4/zephyr-7b-beta     merge_method: task_arithmetic     base_model: mistralai/Mistral-7B-v0.1     layer_granularity: 8 # sane default     allow_negative_weights: true # useful with task_arithmetic tasks:   - name: spartqa_train     weight: 1.0 

実行

次のコマンドを実行します。

mergekit-evolve ./evol_merge_config.yml \ 		--storage-path evol_merge_storage \ 		--task-search-path eval_tasks \ 		--in-memory \ 		--merge-cuda --wandb


進化的計算を行っているログが表示され、計算されていきます。
Wandbを見ると、精度向上した段階の精度が記録されます。10回に一度ぐらい更新されていき、全体で1〜2時間ほど実行時間がかかります。

Evolutionary Model MergeのWandb記録

なお、データはサンプリングしないと時間がかかるので、可能であればデータをサンプリングして実施するのが望ましいです。
感動的なのは、私のマシン構成であるRTX3090x2の構成で十分動いたので、7Bをそのまま学習するよりは簡単だったことです。すごいです。推論だけならまだしも7Bの重み全ての学習は通常GPUメモリが不足し、動きません。
適切な学習データを準備してモデルの候補並べて、「Evolutionary Model Merge」をするとドメイン特化の良いモデルが手軽に作れそうです。

トラブルシュート

1. ログインを要求された場合
実行途中途中、Mistralのダウンロードがありますが、事前にcliの設定によるhuggingfaceアカウントへのログインが必要となります。
APIKeyを作成して、ログインしましょう。

huggingface-cli login

2. Flash Attentionのバージョン不足
以下の例外が発生した場合、flash-attnのライブラリのバージョンが低すぎることを示します。

ImportError: FlashAttention2 has been toggled on, but it cannot be used due to the following error: you need flash_attn package version to be greater or equal than 2.1.0. Detected version 2.0.4. Please refer to the documentation of https://huggingface.co/docs/transformers/perf_infer_gpu_one#flashattention-2 to install Flash Attention 2.

以下のコマンドを実行して、アップグレードしましょう。

pip install flash-attn --upgrade 

実行

最後に「Evolutionary Model Merge」の結果で得られたモデルを実行します。
まずは、「Evolutionary Model Merge」のベストなパラメータは「evol_merge_storage/best_config.yaml」に保存されています。
その設定に従ってまずは、次のコマンドでマージ後のモデルを生成します。マージ後のモデルは「merge」ディレクトリに保存されます。

mergekit-yaml evol_merge_storage/best_config.yaml merge

後はhuggingfaceと同じ使い方で推論可能です。

import torch from transformers import AutoTokenizer, AutoModelForCausalLM device = "cuda" # the device to load the model onto model = AutoModelForCausalLM.from_pretrained("merge", device_map="auto") tokenizer = AutoTokenizer.from_pretrained("merge")  messages = [     {"role": "user", "content": "What is your favourite condiment?"},     {"role": "assistant", "content": "Well, I'm quite partial to a good squeeze of fresh lemon juice. It adds just the right amount of zesty flavour to whatever I'm cooking up in the kitchen!"},     {"role": "user", "content": "Do you have mayonnaise recipes?"} ]  encodeds = tokenizer.apply_chat_template(messages, return_tensors="pt") model_inputs = encodeds.to(device)  generated_ids = model.generate(model_inputs, max_new_tokens=1000, do_sample=True) decoded = tokenizer.batch_decode(generated_ids) print(decoded[0]) 

最後に

LLMを一から全て学習させるのは非常に高いコストがかかります。
LoRAによる追加学習も(比較して)スタンダードな低コストなアプローチの代表例ですが、Model Mergeによるベースモデルの改修といった観点は今までになく非常に面白いアプローチに思えます。
今後、業務の中でモデルのマージ技術も使って精度向上の検討をしていきたいと思いました。とても今後の「Evolutionary Model Merge」の進化に期待しています。

Acroquest Technologyでは、キャリア採用を行っています。


  • ディープラーニング等を使った自然言語/画像/音声/動画解析の研究開発
  • Elasticsearch等を使ったデータ収集/分析/可視化
  • マイクロサービス、DevOps、最新のOSSを利用する開発プロジェクト
  • 書籍・雑誌等の執筆や、社内外での技術の発信・共有によるエンジニアとしての成長

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。

Azure OpenAI Serviceを活用したいエンジニア募集! - Acroquest Technology株式会社のデータサイエンティストの採用 - Wantedlywww.wantedly.com

Agents for Amazon Bedrock の作成がより簡単になった!

こんにちは、機械学習チーム YAMALEX の駿です。
YAMALEX は Acroquest 社内で発足した、会社の未来の技術を創る、機械学習がメインテーマのデータサイエンスチームです。 (詳細はリンク先をご覧ください。)

先日Amazon Bedrock(以下、 Bedrock)の新機能が複数発表されましたが、今回は「Agents for Amazon Bedrock」(以下、エージェント)作成に追加されたアップデートを確認します。

以前、当社のブログでエージェントを扱った記事があったので、同じことをやってみて、どれくらい変わったのか確認してみます。

ysnw.workpolska.online

概要

エージェントは生成AIを活用したアプリケーションの作成を助ける仕組みです。
ユーザーは、自然言語を用いてAIアプリで実施したいタスクを入力します。

エージェントは上記のタスクを推論モデルを用いて細分化、複数ステップのタスクに自動で分割し、それぞれの実行結果をまとめ、 最終的なタスクの実行結果をユーザーに返すAIアプリケーションを生成します。

今回のアップデートでエージェントを作成し設定するフローが簡易化され、今まで以上に誰でも簡単にAIアプリケーションを作れるようになりました。

aws.amazon.com

以下、以前の記事と同じアプリケーションを作成していきます。

横に並べて一緒にスクロールしながら読むと、特にLambda関数の定義が簡単になっていることがよくわかると思います。

Bedrock エージェントでEC2インスタンスを作成する

ユーザの入力に基づいてEC2インスタンスを起動するエージェントを作成します。

以下のような構成になります。


構成図

エージェントは次の順番に処理を行います。

  1. [エージェント] ユーザの入力を受け取る(①)
  2. [エージェント] 関数呼び出しが必要か判定(②)
  3. [エージェント] 関数呼び出しに使う引数を抽出(②)
  4. [エージェント] 関数呼び出し(③)
  5. [Lambda] EC2インスタンスを起動(④)
  6. [Lambda] 結果を返却(⑤)
  7. [エージェント] 返り値を元に返答を生成(⑥)
  8. [エージェント] ユーザに返答する(⑥)

us-west-2リージョンでBedrockのサイドメニューから、オーケストレーション > エージェントをクリックし、続けて「エージェントを作成」をクリックします。

エージェント

エージェントを作成

エージェント名入力

まずエージェント名と説明を求めるダイアログが出るので、入力します。

作成の一番最初で細かいところを気にせずに進められるのが良いですね。

エージェント名と説明を入力

エージェントの詳細入力

続いてエージェントの詳細を入力します。

ここでは利用するモデルやエージェント向けの指示(いわゆるシステムプロンプト)を設定できます。

「Additional settings」を開くと細かいエージェントの動きを設定できます。

詳細入力

モデル選択のプルダウンを開くと、先日Bedrockに追加されたClaude 3のモデルも利用可能になっていることが分かります。

今回は迷わず Claude 3 Haiku を選択しました。 性能が高い、早い、安いの三拍子がそろっています。


使えるモデルが増えた

アクショングループの追加

続いてアクショングループとしてLambda関数を指定します。

ここではEC2インスタンスを起動するLambdaを作成し、実行に必要な引数の情報などをエージェントに入力します。

Action group typeは「Define with function details」を選択します。

「Define with API schemas」を選択すると今までと同じくOpenAPIのYAML定義をS3に置いて読み込む従来の指定方法になります。

アクショングループの追加

Define with function details

functionの設定

Action group invocation はお勧めされている「Quick create a new Lambda function」を選択しました。

上記のParameters部などが今までOpenAPI形式でYAMLを記述してS3に保存しないといけなかったところです。
画面をポチポチするだけで設定が完了しました。

すぐに使い始めたい、複雑なことをする予定はないので簡単に始めたいユースケースにマッチします。

(ナレッジベースは今回使わないためスキップします。)

Lambda 作成

Lambdaのコンソールにアクセスします。

アクショングループを作成する際に新しいLambda関数を作る設定にしたため、自動でひな型が作られています。

アクセス権限が設定済みなので、ポリシーステートメントなど難しいことに煩わされることはありません。

Lambdaのひな型が自動で作成されます

アクセス権限も設定済み

ひな型に合わせて、EC2インスタンスを作成するコードを少し修正しています。

import json  import boto3  ec2 = boto3.client("ec2")   def lambda_handler(event, context):     agent = event["agent"]     actionGroup = event["actionGroup"]     function = event["function"]     parameters = event.get("parameters", [])      # Execute your business logic here. For more information,     # refer to: https://docs.aws.amazon.com/bedrock/latest/userguide/agents-lambda.html      instance_type = next(item for item in parameters if item["name"] == "instance_type")["value"]     ami_id = next(item for item in param if item["name"]  == "ami_id")["value"]          instances = ec2.run_instances(         ImageId=ami_id,         InstanceType=instance_type,         MinCount=1,         MaxCount=1,     )          responseBody =  {         "TEXT": {             "body": f"Instance Created: {str(instances)}"         }     }      action_response = {         "actionGroup": actionGroup,         "function": function,         "functionResponse": {             "responseBody": responseBody         },     }      function_response = {"response": action_response, "messageVersion": event["messageVersion"]}     print(f"Response: {function_response}")      return function_response 

※ ec2:RunInstances の権限をLambdaの実行ロールに付与する必要はあります。

以上でエージェントの作成が完了です。

作成したエージェントを試してみる

早速作成したエージェントにamazonlinux:2023ベースのインスタンスを作ってもらいましょう。

入力

"ami-0c0d141edc4f470cc" のAMIをベースに、インスタンスタイプを”t2.micro"として、EC2インスタンスを作成してください。

出力

EC2 instance created successfully with the following details: - AMI ID: ami-0663b059c6536cac8 - Instance Type: t2.micro - Instance ID: i-xxxx - Private IP Address: xxx.xxx.xxx.xxx

作成できました

指示通りのAMIとインスタンスタイプで作成してくれました。

EC2のコンソールを確認すると、実際にLambda関数が実行されインスタンスが起動していることが確認できます。

実際に作られたインスタンス

「トレースを表示」を押下してステップの中身を確認することで、下記のようにAMI IDとinstance typeを適切に抽出できていることを確認できます。

(前略)   "rationale": {     "text": "To create the EC2 instance based on the user's request, I will need to invoke the CreateEC2::create-ec2 function with the provided AMI ID and instance type.",     "traceId": "abdfe555-eca2-4670-8ca4-77a7344ff365-0"   },   "invocationInput": {     "actionGroupInvocationInput": {       "actionGroupName": "CreateEC2",       "function": "create-ec2",       "parameters": [         {           "name": "ami_id",           "type": "string",           "value": "ami-0663b059c6536cac8"         },         {           "name": "instance_type",           "type": "string",           "value": "t2.micro"         }       ]     },     "invocationType": "ACTION_GROUP",     "traceId": "abdfe555-eca2-4670-8ca4-77a7344ff365-0"   }, (後略) 

まとめ

エージェントの作成がどのように変わったのかを、以前作成したエージェントと同等のものを作成することで確認してきました。

関数定義の指定とLambdaの権限設定が簡単になっている部分が個人的には推しポイントです。

自分でシステムを作ることなく高度なAIアプリケーションを構築できる、エージェントの利点がさらに補強され、より気軽に利用できますね。

Acroquest Technologyでは、キャリア採用を行っています。
  • ディープラーニング等を使った自然言語/画像/音声/動画解析の研究開発
  • Elasticsearch等を使ったデータ収集/分析/可視化
  • マイクロサービス、DevOps、最新のOSSクラウドサービスを利用する開発プロジェクト
  • 書籍・雑誌等の執筆や、社内外での技術の発信・共有によるエンジニアとしての成長
  少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。 www.wantedly.com

Azure OpenAI Service の Assistants API でデータ分析

こんにちは、igaです。
最近は気温の上下が大きいので、服装選びが大変ですね。


今回は、Azure OpenAI Servce Assistants APIを使ってみました。
Azure OpenAI Servce Assistants API横浜市の人口データを投入して、人口の増減がどう推移しているのか自動で分析させてみました。

Azure OpenAI Servce Assistants API

Azure OpenAI Servce Assistants APIとは

Azure OpenAI Servce Assistants APIは、2024年4月現在パブリックプレビューとして利用できる機能です。

learn.microsoft.com

Azure OpenAI Servce Assistants API(以降、Assistantsと表記します)により、Azure OpenAI Servceに独自データを投入して、投入したデータに対してユーザーからの問い合わせの回答、コードインタープリターによる分析、Function callingによる独自処理を実施することができます。

Azure OpenAI Servce Assistants APIのポイント

Azure OpenAI Servce Assistants APIを利用するには、以下の条件があります。

項目
利用可能なリージョン オーストラリア東部、
米国東部2、
スウェーデン中部
利用可能なモデル gpt-35-turbo(0613)
gpt-35-turbo(1106) ※1
gpt-4(0613)、gpt-4(1106)

※1 米国東部2リージョンでは利用することができません。
※2024年4月15日現在の条件です。

learn.microsoft.com

Assistantsで利用可能なデータファイルの拡張子は、以下のページを参照してください。
learn.microsoft.com

利用手順

Assistantsを準備する

Assistantsを利用するため、 Azureポータル からAzure OpenAI Service環境を作成します。
Azure OpenAI Service環境の利用方法については、 過去の記事 を参照してください。

Assistantsの利用手順は、こちらを参照してください。
learn.microsoft.com


Azure OpenAI Studio にアクセスして、「アシスタント(プレビュー)」メニューから、Assistantsの設定画面に移動します。

「アシスタントのセットアップ」に必要な内容を入力します。

入力する項目のポイントは以下の通りです。

入力項目
関数 Function callingの関数定義をJSON形式で指定します
コードインタープリタ 「ファイル」に独自データを指定する場合は、ONにする必要があります

今回、ファイルには横浜市の人口動態のCSVファイルを使用しました。

www.city.yokohama.lg.jp


関数については、 過去の記事 でも解説した通り、呼び出す関数とその引数を特定するために必要な情報をJSON形式で指定します。
関数自体の定義を指定するのではない点を注意してください。

必要事項を入力したら、Saveボタンを押して入力情報を保存します。

Assisntantsの動作を確認する

Azure OpenAI Studioのチャット画面から、今回定義したAssistantsとチャットを行います。まずは与えた人口動態データから平均人口増加数を分析させてみました。
Assistantsに渡したCSVファイルにどのような列が入っているか、こちらで説明する必要はありません。すべて勝手に読み取って解析までやってくれます。


「10年単位の人口増加数の平均値を求めて」というユーザーの入力に対して、内部でコードインタープリターが動作して、「10年単位の人口増加数の平均値」を回答してくれます。2020年代は2020年から2023年までの人口増加数が減少しているため、マイナスの値になっています。
Assistantsからの回答に対して、グラフ化してほしい、という追加の要望を出します。

グラフを生成するのと合わせて、ダウンロード可能な形式にしてくれました。
ダウンロードしたファイルは以下のようになっています。


AssistantsでFunction callingを利用する

関数定義を入力する

Assistantsに、関数の定義を追加します。
「関数の追加」をクリックすると、関数定義の入力ダイアログが開くので、関数定義のJSONを入力します。
関数定義の入力ダイアログで「保存」ボタンをおしてダイアログが閉じた後、忘れずにアシスタントのセットアップで「Save」ボタンによりAssistantsに関数定義を反映させます。

今回の定義内容は以下の通りです。
こちらの関数では、前年と今年の人口の増減比率により、「HIGH」「NORMAL」「LOW」というラベルを決定します。

{   "name": "diff_label",   "description": "The label for the population increase is 'HIGH' if the population increase is 10% or more compared to the previous year, 'LOW' if the population increase is -10% or less, and 'NORMAL' for any other cases.",   "parameters": {     "type": "object",     "properties": {       "prev_population_increase": {         "type": "number",         "description": "Number of population increases in the previous year."       },       "current_population_increase": {         "type": "number",         "description": "Number of population increases this year."       }     },     "required": [       "prev_population_increase",       "current_population_increase"     ]   } } 
Function callingを確認する

チャット画面から、上で定義したFunction callingが必要となるように、「2000年の人口増加数に対してラベルをつけて」というメッセージを入力します。
Assistantsが呼び出す関数と引数を特定してくれます。

関数を呼び出した結果を、Assistantsの応答に対して入力します。
そのままでは回答を返してくれなかったので、回答をお願いしたところFunction callingの結果を含めて回答してくれました。


APIによるAssistantsの操作

Azure OpenAI Studioのプレイグラウンドではなく、APIを使ってAssisntantsに要求を出して結果を受け取る方法を検証します。

APIの使い方については、以下の内容を参考にしました。
learn.microsoft.com

APIを操作するPythonのプログラムは以下のようになります。

Assistantsへのリクエストの送信や、応答の解析などの処理については、以下のプログラムを参考にしました。
Function callingで指定する関数については、JSONで定義した挙動になるように実装しました。

github.com

import json import os import time from pathlib import Path from typing import Optional  from openai import AzureOpenAI   def create_message(client, thread_id, role, content, message_id=None):     """Assistantsのメッセージを作成する      Args:         client (AzureOpenAI): Azure OpenAIのクライアント         thread_id (str): スレッドID         role (str): メッセージのロール         content (str): メッセージ内容         message_id (str): メッセージID     """     if client is None:         print("Client is required.")         return None      if thread_id is None:         print("ThreadID is required.")         return None      try:         if message_id is not None:             return client.beta.threads.messages.retrieve(thread_id=thread_id, message_id=message_id)          return client.beta.threads.messages.create(thread_id=thread_id, role=role, content=content)     except Exception as ex:         print(ex)         return None   def wait_run_finish(client, thread_id, run_id):     """実行結果の終了を待機する      Args:         client (AzureOpenAI): Azure OpenAIのクライアント         thread_id (str): スレッドID         run_id (str): 実行ID     """     if (client is None and thread_id is None) or run_id is None:         print("Client, Thread ID and Run ID are required.")         return      print("wait run finish.")      wait = 30  # 待機時間(秒)     try:         # 一定回数、状態確認を行う         for cnt in range(20):             run = client.beta.threads.runs.retrieve(                 thread_id=thread_id, run_id=run_id)              print(f"Poll {cnt}: {run.status}")              if run.status == "requires_action":                 tool_responses = []                 if (                     run.required_action.type == "submit_tool_outputs"                     and run.required_action.submit_tool_outputs.tool_calls is not None                 ):                     tool_calls = run.required_action.submit_tool_outputs.tool_calls                      for call in tool_calls:                         # Function callingが必要とAssisntantsが判断したので、指定された関数を実行する                         if call.type == "function":                             if call.function.name not in available_functions:                                 raise Exception(                                     "Function requested by the model does not exist")                             function_to_call = available_functions[call.function.name]                             tool_response = function_to_call(                                 **json.loads(call.function.arguments))                             tool_responses.append(                                 {"tool_call_id": call.id, "output": tool_response})                  run = client.beta.threads.runs.submit_tool_outputs(                     thread_id=thread_id, run_id=run.id, tool_outputs=tool_responses                 )             if run.status == "failed":                 print("Run failed.")                 break             if run.status == "completed":                 break             time.sleep(wait)     except Exception as ex:         print(ex)   def retrieve_and_print_messages(client, thread_id, verbose, out_dir=None):     """スレッド内のメッセージリストを取得して、結果を出力する      Args:         client (AzureOpenAI): Azure OpenAIのクライアント         thread_is (str): スレッドID         verbose (bool): 詳細表示の要否         out_dir (str): 画像ファイルの出力先フォルダ     Returns         list: メッセージのリスト     """      if client is None and thread_id is None:         print("Client and Thread ID are required.")         return None     try:         messages = client.beta.threads.messages.list(thread_id=thread_id)         display_role = {"user": "User query",                         "assistant": "Assistant response"}          prev_role = None          if verbose:             print("\n\nCONVERSATION:")         for message_data in reversed(messages.data):             if prev_role == "assistant" and message_data.role == "user" and verbose:                 print("------ \n")              for message_content in message_data.content:                 # Check if valid text field is present in the mc object                 if message_content.type == "text":                     txt_val = message_content.text.value                 # Check if valid image field is present in the mc object                 elif message_content.type == "image_file":                     image_data = client.files.content(                         message_content.image_file.file_id)                     if out_dir is not None:                         out_dir_path = Path(out_dir)                         if out_dir_path.exists():                             image_path = out_dir_path / \                                 (message_content.image_file.file_id + ".png")                             with image_path.open("wb") as f:                                 f.write(image_data.read())                  if verbose:                     if prev_role == message_data.role:                         print(txt_val)                     else:                         print(f"{display_role[message_data.role]}:\n{txt_val}")             prev_role = message_data.role         return messages     except Exception as e:         print(e)         return None   def get_label(prev_population_increase, current_population_increase):     """前年からの増減の比率により、ラベルを返す      Args:         prev_population_increase (int): 前年の数値         current_population_increase (int): 今年の数値      Returns:         dict: 今年の数値が前年比+10%以上ならば"HIGH"、今年の数値が前年比-10%以下ならば"LOW"、それ以外は"NORMAL"     """     if current_population_increase >= prev_population_increase * 1.1:         label = "HIGH"     elif current_population_increase <= prev_population_increase * 0.9:         label = "LOW"     else:         label = "NORMAL"      return json.dumps({"label": label})   available_functions = {"diff_label": get_label}  client = AzureOpenAI(     api_key=os.getenv("AZURE_OPENAI_API_KEY"),     api_version="2024-02-15-preview",     azure_endpoint=os.getenv("AZURE_OPENAI_ENDPOINT") )  assistant_id = os.getenv("AZURE_OPENAI_ASSISTANT_ID")  assistant_list = client.beta.assistants.list()  # スレッドの作成 thread = client.beta.threads.create()  # メッセージの作成 first_message = create_message(     client, thread.id, "user", "2000年の人口増加数について、前年との比較のラベルをつけてください。")  # メッセージをAzure OpenAIに送信する run = client.beta.threads.runs.create(     thread_id=thread.id, assistant_id=assistant_id)  # Azure OpenAIからの応答を待つ wait_run_finish(client, thread.id, run.id)  # 応答内容を出力する retrieve_and_print_messages(client, thread.id, True) 

送信するメッセージは、Function callingが必要になる内容を送信します。
このプログラムを実行した結果は以下のようになります。プレイグラウンドでやった時と同じように、Function callingを使ったラベル付けした結果を得られています。

wait run finish. Poll 0: in_progress Poll 1: in_progress Poll 2: requires_action Poll 3: completed   CONVERSATION: User query: 2000年の人口増加数について、前年との比較のラベルをつけてください。 Assistant response: 2000年の人口増加数は前年比で高い増加(10%以上の増加)となっており、ラベルは「HIGH」となります。

実行結果に 「ラベルは「HIGH」となります」というメッセージが出力されているので、Function callingが必要とAssistantsが判断してプログラムで実行した結果を使って、Assistantsが応答を返していることが確認できます。

APIによるファイルのダウンロード

APIを使ってAssistantsに要求するメッセージで、ファイルのダウンロードを確認します。

先ほど提示したPythonのプログラムで、作成するメッセージ内容を以下のように修正します。

# メッセージの作成 first_message = create_message(     client, thread.id, "user", "10年単位での、平均人口増加数をグラフにして、画像ファイルにしてください。") 

このプログラムを実行すると、以下のように画像ファイルがダウンロード可能な形式の結果が返ってきます。
プログラム中の`retrieve_and_print_messages()`で、ファイル情報を保存しています。

CONVERSATION: User query: 10年単位での、平均人口増加数をグラフにして、画像ファイルにしてください。 Assistant response: データには和暦の年と西暦の年、そして3種類の人口増加数が含まれています。ここでは「人口増加数[人]」の列を使用して、10年 単位での平均人口増加数を計算し、グラフにして画像ファイルとして保存します。まずは各10年ごとの期間に分けて平均を計算しましょう。 It seems there was an issue with plotting the data. Let me try again to calculate the average population increase per decade and create the graph. It seems there was an issue with plotting the data. Let me try again to calculate the average population increase per decade and create the graph. I have successfully calculated the average population increase per decade and created a bar graph. The graph has been saved as an image file. You can download the image using the link below:  [Download the image of the average population increase per decade](sandbox:/mnt/data/average_population_increase_per_decade.png)

ダウンロードした画像は以下の通りです。
10年単位の平均人口増加数が棒グラフになっています。


まとめ

今回は、Assistantsの利用方法について確認しました。
過去の記事で、Function callingや独自データの利用方法を検証しましたが、その時にはデータの準備など手順を踏む必要がありました。
Assistantsでは、データ準備の手順が簡略化されているため、簡単なチャットシステムを用意することができるようになりました。



Acroquest Technologyでは、キャリア採用を行っています。
  • ディープラーニング等を使った自然言語/画像/音声/動画解析の研究開発
  • Elasticsearch等を使ったデータ収集/分析/可視化
  • マイクロサービス、DevOps、最新のOSSクラウドサービスを利用する開発プロジェクト
  • 書籍・雑誌等の執筆や、社内外での技術の発信・共有によるエンジニアとしての成長

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。

www.wantedly.com

OpenAIのBatch APIを使ってお得にプロンプトを一括処理してみる

はじめに

こんにちは。データサイエンスチームYAMALEXのSsk1029Takashiです。
最近はOpenAIに倭国支社が出来て、倭国語対応が加速するというニュースにわくわくしています。
今回はそんなOpenAIから発表されたBatch APIという機能が便利、かつお得な機能だったのでどのように使えるのか試してみます。


このBatch APIという機能はその名の通りAPIから利用できる機能で、複数のプロンプトをファイルにしてアップロードすることで一括処理できるという機能になります。
チャットのようにインタラクティブに結果を得られない代わりに、通常のAPIよりも50%も料金が安くなるというかなりうれしい機能になります。

Batch APIの特徴

Batch APIは以下の特徴を持っています。

  1. トークンあたりの料金が通常のAPIより50%安い。
  2. 入力・出力はJSONLファイルになる。
  3. 最大処理時間は24時間で、24時間以上かかる処理については途中まで実行して残りはキャンセルされる。

注意するべきは処理の最大時間が24時間で、24時間以上かかるタスクについては途中まで実施してそれ以降の処理はキャンセルされます。
なので、もし24時間以上かかるBatchを実行したい場合は、複数回に分けて実行する必要があります。

Batch APIを使ってみる

ファイルを用意する

まずはBatch APIの入力にするプロンプトをまとめたファイルを作ります。
フォーマットが決められているので、以下の形のJSONを一行にしたJSONLファイルを用意します。

{     "custom_id": "request-1", # ファイルの中で一意になるID     "method": "POST", # 固定     "url": "/v1/chat/completions", # 固定     "body": {         "model": "gpt-3.5-turbo", # 使うモデルを選択         "messages": [ # ChatCompletionの入力形式             {                 "role": "system",                 "content": "You are helpful assistant."             },             {                 "role": "user",                 "content": "What`s OpenAI?"             }         ]     } } 

重要なのはbodyの中に、ChatCompletion APIの入力にするときのmessagesの形式でプロンプトを用意することです。
ここでシステムプロンプトとユーザーの入力を定義して入力できます。

今回はサンプルの実行なので、以下のようにGPT-4 Turboを使うプロンプトを10件用意します。

{"custom_id": "request-1", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-4-turbo", "messages": [{"role": "system", "content": "You are helpful assistant."}, {"role": "user", "content": "What`s OpenAI?"}]}} {"custom_id": "request-2", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-4-turbo", "messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "What`s GPT?"}]}} {"custom_id": "request-3", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-4-turbo", "messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Please explain about Transformer."}]}} {"custom_id": "request-4", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-4-turbo", "messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Please explain about LLM."}]}} {"custom_id": "request-5", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-4-turbo", "messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Please explain about Azure."}]}} {"custom_id": "request-6", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-4-turbo", "messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Please explain about Python."}]}} {"custom_id": "request-7", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-4-turbo", "messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "How do I get started with machine learning?"}]}} {"custom_id": "request-8", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-4-turbo", "messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Please give me sample code for running the OpenAI API in Python."}]}} {"custom_id": "request-9", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-4-turbo", "messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "What are your strengths?"}]}} {"custom_id": "request-10", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "gpt-4-turbo", "messages": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "What are your weaknesses?"}]}}

これをinstructions.jsonlというファイルで保存します。

ファイルをアップロードする

ファイルを作成したら、OpenAI APIから一度ファイルをOpenAIのStorageにアップロードします。
今のところOpenAIのコンソールからのアップロードには上記フォーマットは対応していないので、curlなどを使って直接アップロードしましょう。

curl https://api.openai.com/v1/files \   -H "Authorization: Bearer $OPANAI_KEY" \   -F purpose="batch" \   -F file="@instructions.jsonl" 

ここで重要なのは、purposeをbatchに設定することです。
こうすることで、Batch用のフォーマットということを認識させてアップロードできます。

リクエストを実行して以下のようなレスポンスを得られればアップロード成功です。

{   "object": "file",   "id": "file-otymKIlaJNJxVx8LaM1bAEQ2",   "purpose": "batch",   "filename": "instructions.jsonl",   "bytes": 2501,   "created_at": 1713285032,   "status": "processed",   "status_details": null } 

OpenAIのコンソールからもアップロードしたファイルが確認できるようになります。
この中で、File IDの値はBatch実行時に使用するので控えておきましょう。

Batchを実行する

ファイルをアップロードしたらBatchを実行します。
今のところ公式ドキュメントで紹介されているのはAPI経由の実行のみなので、こちらでもcurlなどを使用して実行しましょう。

curl https://api.openai.com/v1/batches \   -H "Authorization: Bearer $OPANAI_KEY" \   -H "Content-Type: application/json" \   -d '{     "input_file_id": "file-otymKIlaJNJxVx8LaM1bAEQ2",     "endpoint": "/v1/chat/completions",     "completion_window": "24h"   }' 

この時リクエストボディに設定するパラメータは以下になります。

パラメータ名 設定する値
input_file_id ファイルアップロード時に取得したファイルのOpenAI上でのID
endpoint 固定で/v1/chat/completionsを設定
completion_window Batchの最大実行時間指定。今は24hしか指定できない。

無事に実行できると以下のようなレスポンスを取得できます。

{   "id": "batch_9E41M4O8YeY78GcarOnzwaB0",   "object": "batch",   "endpoint": "/v1/chat/completions",   "errors": null,   "input_file_id": "file-otymKIlaJNJxVx8LaM1bAEQ2",   "completion_window": "24h",   "status": "in_progress",   "output_file_id": null,   "error_file_id": null,   "created_at": 1713285571,   "in_progress_at": 1713285573,   "expires_at": 1713371971,   "finalizing_at": null,   "completed_at": null,   "failed_at": null,   "expired_at": null,   "cancelling_at": null,   "cancelled_at": null,   "request_counts": {     "total": 10,     "completed": 0,     "failed": 0   },   "metadata": null } 

また、一度実行したBatchは今の状態をAPIから確認できます。

curl https://api.openai.com/v1/batches/batch_9E41M4O8YeY78GcarOnzwaB0 \   -H "Authorization: Bearer $OPANAI_KEY" \   -H "Content-Type: application/json" 

パスパラメータにはBatch作成時のレスポンスの中からidの値、今回でいえば「batch_9E41M4O8YeY78GcarOnzwaB0」を入れます。
その値が実行したBatchを表すIDになっており、以下のような結果を得られます。

{   "id": "batch_9E41M4O8YeY78GcarOnzwaB0",   "object": "batch",   "endpoint": "/v1/chat/completions",   "errors": null,   "input_file_id": "file-otymKIlaJNJxVx8LaM1bAEQ2",   "completion_window": "24h",   "status": "in_progress",   "output_file_id": null,   "error_file_id": null,   "created_at": 1713285571,   "in_progress_at": 1713285573,   "expires_at": 1713371971,   "finalizing_at": null,   "completed_at": null,   "failed_at": null,   "expired_at": null,   "cancelling_at": null,   "cancelled_at": null,   "request_counts": {     "total": 10,     "completed": 0,     "failed": 0   },   "metadata": null } 

レスポンスが長いですが、この中でstatusを見ればいまBatchがどのような状態なのか確認できます。
例えば、上記のレスポンスの場合だとin_progressになっているので、現在実行中ということになります。
このstatusが「completed」という値になればBatchが完了したことになります。

実行結果を確認する

Batchが完了すると以下のようにOpenAIのコンソールにBatch実行結果のファイルが追加されていることが分かります。
今回はGPT-4 Turboを使うとはいえ10行だけだったので、10分弱で処理が完了しました。

ダウンロードして中身を見ると以下のようにプロンプトを実行した結果の一覧を見ることができます。
ChatCompletionで得られるレスポンスは一通り記載されているので、usageなどの情報も見ることができます。
(長いので3行抜粋)

{"id": "batch_req_hZUECCsIMAT0NsrZ9taQC2S6", "custom_id": "request-7", "response": {"status_code": 200, "request_id": "req_735f5251489d353939dbda942ef6b37c", "body": {"id": "chatcmpl-9EgV0dWTMLrXNsPBSWA5Wj1xX2JRY", "object": "chat.completion", "created": 1713286986, "model": "gpt-4-turbo-2024-04-09", "choices": [{"index": 0, "message": {"role": "assistant", "content": "Getting started with machine learning (ML) can be an exciting journey into a field full of opportunities for innovation and impact across various industries like finance, healthcare, automotive, and more. Here\u2019s a structured way to begin learning about machine learning:\n\n### 1. Understand the Basics\nStart by gaining a foundational understanding of the concepts and terminology used in machine learning. Here are some key topics to cover:\n- **Basic Statistics & Mathematics:** Understand mean, median, mode, standard deviation, probability, and linear algebra.\n- **Types of Machine Learning:** Learn about supervised learning, unsupervised learning, reinforcement learning, and semi-supervised learning.\n- **Key Algorithms:** Get familiar with algorithms like linear regression, logistic regression, decision trees, SVM (Support Vector Machines), and neural networks.\n\n### 2. Online Courses\nThere are many online platforms offering free and paid courses that can provide structured learning and hands-on practice:\n- **Coursera:** Andrew Ng\u2019s Machine Learning course is highly recommended.\n- **edX:** Offers courses from MIT and Harvard.\n- **Udacity:** Known for its Nanodegree programs in Deep Learning and Machine Learning.\n- **Khan Academy:** Good for strengthening your math skills.\n\n### 3. Get Hands-On Experience\nAlongside theoretical learning, it\u2019s essential to practice:\n- **Kaggle:** Participate in competitions or explore datasets.\n- **GitHub:** Look at ML projects and try to replicate them. Start your own projects and share them.\n- **Python Libraries:** Get familiar with Scikit-learn, TensorFlow, PyTorch, and Pandas. Python is widely used in the machine learning community due to its simplicity and powerful libraries.\n\n### 4. Books\nSome good books to start with are:\n- **\u201cPattern Recognition and Machine Learning\u201d** by Christopher M. Bishop\n- **\u201cMachine Learning Yearning\u201d** by Andrew Ng (more strategy than technical details)\n- **\u201cHands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow\u201d** by Aur\u00e9lien G\u00e9ron\n\n### 5. Work on Projects\nApplying what you\u2019ve learned to actual projects is crucial:\n- Begin with simple projects like predicting stock prices, or recognizing hand-written digits.\n- Move on to more complex problems as you grow comfortable.\n\n### 6. Follow Thought Leaders and Keep Updated\n- Follow key influencers on platforms like LinkedIn, Twitter, Medium.\n- Regularly read articles, research papers, and blogs to keep up with new trends and breakthroughs in ML technology.\n\n### 7. Engage with the Community\n- Participate in Meetups, Conferences, and Workshops.\n- Engage in forums like Stack Overflow, Reddit's r/MachineLearning, or Cross Validated on Stack Exchange.\n\n### 8. Understand Ethical Implications\nAs you delve deeper, understand the ethical considerations in deploying ML, including bias, fairness, and the environmental impact of training large models.\n\n### 9. Consider Specialization\nAs you advance, think about specializing in areas that are in high demand, such as deep learning, natural language processing, or computer vision, depending on what interests you the most.\n\nStarting with these steps will help you build a strong foundation and guide you through becoming proficient in machine learning. Always remember, consistent practice and continual learning are key components of success in this ever-evolving field."}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 26, "completion_tokens": 685, "total_tokens": 711}, "system_fingerprint": "fp_76f018034d"}}, "error": null} {"id": "batch_req_DiZi0B5pBGwoESHn2VgSjrSz", "custom_id": "request-8", "response": {"status_code": 200, "request_id": "req_c3651f89bbb024df85d35a8d2f0c27b7", "body": {"id": "chatcmpl-9EgV0COWoixZMe7OszEThJlqb6xQU", "object": "chat.completion", "created": 1713286986, "model": "gpt-4-turbo-2024-04-09", "choices": [{"index": 0, "message": {"role": "assistant", "content": "Sure! To run the OpenAI API in Python, you'll primarily rely on the `openai` library. Let\u2019s use an example where we send a prompt to the GPT model and receive a text completion. First, you need to install the OpenAI Python library if you haven't yet. You can install it using pip:\n\n```bash\npip install openai\n```\n\n### Example Code for Using OpenAI GPT\n\nHere's a simple example of how you can use the API to interact with the GPT model. In this code snippet, I assume you have your API key ready. For security reasons, you should not hard-code your API Key in your source code. Instead, use environment variables or other secure methods to store your API Key.\n\n```python\nimport openai\n\ndef get_gpt_response(prompt_text):\n    openai.api_key = 'your-api-key-here'\n\n    try:\n        response = openai.Completion.create(\n            engine=\"text-davinci-003\",  # You can use different models like \"davinci\", \"curie\", etc.\n            prompt=prompt_text,\n            max_tokens=150  # You can adjust this value based on your needs\n        )\n        return response.choices[0].text.strip()\n    except Exception as e:\n        print(f\"An error occurred: {e}\")\n        return None\n\n# Example usage\nprompt_text = \"Explain the benefits of AI in education.\"\nresponse_text = get_gpt_response(prompt_text)\nprint(response_text)\n```\n\n### Notes:\n1. **API Key Security**: Do not hard-code your API keys in your code. Instead, use environment variables. You can set this up in your local environment or whatever deployment environment you are using.\n\n2. **API Usage Limits**: Be aware of the usage limits and potential costs associated with API requests. Make sure to review OpenAI's usage policies and pricing.\n\n3. **Error Handling**: The code includes basic error handling which is crucial for dealing with network issues or API limits.\n\n4. **Model Selection**: OpenAI provides various models with different capabilities and cost structures. Choose the appropriate model based on your needs.\n\n5. **Response Processing**: The response from the API contains multiple components. We are mostly interested in the textual completion, which is accessed via `response.choices[0].text`.\n\n6. **Environment**: This code is to be run in a standard Python environment where you have the necessary permissions and network access to reach OpenAI's API servers.\n\nThis should help you get started with using OpenAI's API in your Python applications!"}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 31, "completion_tokens": 526, "total_tokens": 557}, "system_fingerprint": "fp_76f018034d"}}, "error": null} {"id": "batch_req_8nDALG7zrVMxiFk5o6nvrYbT", "custom_id": "request-5", "response": {"status_code": 200, "request_id": "req_0ef9ec2e8d633ebdf9f5000d9386136d", "body": {"id": "chatcmpl-9EgV0tJJ5JRL8SJxp7IvMlpfcPuYC", "object": "chat.completion", "created": 1713286986, "model": "gpt-4-turbo-2024-04-09", "choices": [{"index": 0, "message": {"role": "assistant", "content": "Microsoft Azure, commonly referred to simply as Azure, is a cloud computing service created by Microsoft for building, testing, deploying, and managing applications and services through Microsoft-managed data centers. It provides software as a service (SaaS), platform as a service (PaaS), and infrastructure as a service (IaaS) and supports many different programming languages, tools, and frameworks, including both Microsoft-specific and third-party software and systems.\n\n### Major Features of Azure:\n1. **Computing**: Azure provides virtual machines, containers, and batch processing, as well as remote application access.\n2. **Storage Solutions**: This includes Azure Blob storage, Queue Storage, File Storage, and Table Storage.\n3. **Networking**: This feature provides a variety of networking tools such as Virtual Networks, VPN Gateways, Application Gateways, and Content Delivery Networks.\n4. **Databases**: Azure offers managed SQL and NoSQL database services.\n5. **Mobile and Web Applications**: Azure facilitates the development, testing, and hosting of web and mobile applications.\n6. **AI and Machine Learning**: Tools and services designed to automate operations using AI and machine learning.\n7. **Internet of Things (IoT)**: Azure IoT Hub and other tools help collect, monitor, and analyze IoT data.\n8. **Developer Tools**: Provides support for DevOps, continuous integration, and testing environments.\n9. **Security**: Azure\u2019s security services protect workloads, applications, and data across cloud and hybrid environments.\n\n### Advantages of Azure:\n- **Scalability and Flexibility**: Azure can scale up or down based on demand, making it suitable for businesses of all sizes.\n- **Compliance and Security**: Azure has many compliance certifications and is built with security in mind, offering users peace of mind regarding their data.\n- **Hybrid Capabilities**: Azure provides a wide range of hybrid connections, including VPNs, caches, content delivery networks, and express routing connections to improve usability and performance.\n- **Integrated Environment**: Azure is deeply integrated with other Microsoft products, making it an ideal choice for organizations that rely on Microsoft tools and software.\n\n### Use Cases:\n- **Web Hosting**: Businesses can use Azure to host their websites and web applications.\n- **Data Storage and Backup**: It provides secure and scalable cloud storage solutions.\n- **Mobile App Development**: Azure supports backend services for mobile applications.\n- **Big Data and Analytics**: Offering powerful analytics services to handle large sets of data.\n- **Disaster Recovery**: With high availability and data recovery capabilities, Azure is an excellent option for disaster recovery.\n\nAzure continually evolves by expanding its services and capabilities to suit a broad spectrum of industries, including finance, health, government, manufacturing, and more, providing comprehensive cloud solutions for businesses globally."}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 22, "completion_tokens": 556, "total_tokens": 578}, "system_fingerprint": "fp_76f018034d"}}, "error": null}

以上でBatch APIを使う一通りの流れは完了になります。
実行自体はファイルアップロードしてAPIを実行するだけなので簡単でしたね。

ただし、簡単な注意事項としてリリースされたばかりだからか、倭国語を結果で出力するときには下記のようにUnicodeがそのまま出力されてしまいます。

{"id": "batch_req_LFEtMhsQqZa4GU5qpXLTVmES", "custom_id": "request-1", "response": {"status_code": 200, "request_id": "req_5cdf7d1538045d5946d0dcaa0edf4c79", "body": {"id": "chatcmpl-9EWZ0wTGl6VRZm0AHZrenKMi6gdiE", "object": "chat.completion", "created": 1713248794, "model": "gpt-3.5-turbo-0125", "choices": [{"index": 0, "message": {"role": "assistant", "content": "\u65b0\u6a2a\u6d5c\u306b\u306f\u591a\u304f\u306e\u304a\u3044\u3057\u3044\u30e9\u30fc\u30e1\u30f3\u5c4b\u304c\u3042\u308a\u307e\u3059\u304c\u3001\u305d\u306e\u4e2d\u3067\u3082\u304a\u3059\u3059\u3081\u306e\u5e97\u8217\u3092\u3044\u304f\u3064\u304b\u7d39\u4ecb\u3057\u307e\u3059\u3002\n\n1. \u3089\u30fc\u3081\u3093\u4e8c\u90ce \u65b0\u6a2a\u6d5c\u5e97\n   - \u6fc3\u539a\u306a\u8c5a\u9aa8\u30b9\u30fc\u30d7\u3068\u5927\u76db\u308a\u306e\u5177\u304c\u7279\u5fb4\u306e\u4e8c\u90ce\u7cfb\u30e9\u30fc\u30e1\u30f3\u304c\u697d\u3057\u3081\u308b\u4eba\u6c17\u5e97\u3067\u3059\u3002\n\n2. \u3089\u30fc\u3081\u3093\u51e6 \u3068\u308f \u65b0\u6a2a\u6d5c\u5e97\n   - \u9d8f\u30ac\u30e9\u3084\u9b5a\u4ecb\u306e\u30b9\u30fc\u30d7\u304c\u30d9\u30fc\u30b9\u306e\u3042\u3063\u3055\u308a\u3068\u3057\u305f\u5473\u308f\u3044\u306e\u30e9\u30fc\u30e1\u30f3\u304c\u8a55\u5224\u3067\u3059\u3002\n\n3. \u3089\u30fc\u3081\u3093 \u5eb5 \u65b0\u6a2a\u6d5c\u672c\u5e97\n   - \u3053\u3063\u3066\u308a\u3068\u3057\u305f\u5473\u308f\u3044\u306e\u8c5a\u9aa8\u91a4\u6cb9\u30e9\u30fc\u30e1\u30f3\u304c\u4eba\u6c17\u3067\u3001\u5177\u6750\u3082\u8c4a\u5bcc\u3067\u6e80\u8db3\u611f\u304c\u3042\u308a\u307e\u3059\u3002\n\n\u3053\u308c\u3089\u306e\u304a\u5e97\u306f\u65b0\u6a2a\u6d5c\u99c5\u5468\u8fba\u306b\u4f4d\u7f6e\u3057\u3066\u304a\u308a\u3001\u7f8e\u5473\u3057\u3044\u30e9\u30fc\u30e1\u30f3\u3092\u697d\u3057\u3080\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002\u305c\u3072\u8db3\u3092\u904b\u3093\u3067\u307f\u3066\u304f\u3060\u3055\u3044\u3002"}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 51, "completion_tokens": 305, "total_tokens": 356}, "system_fingerprint": "fp_c2295e73ad"}}, "error": null}

時間が経てば解決する可能性がありますが、現状の注意点としては留意しておく必要はあります。

まとめ

この記事ではBatch APIを使って複数のプロンプトを一括処理する流れを試してみました。
APIを使うこと自体はとても簡単で入力のファイルさえ用意すれば簡単に実行できました。
リアルタイム性が必要なく、大量のテキストをまとめて要約するようなケースでは非常にありがたい機能になりそうです。
それではまた。

Acroquest Technologyでは、キャリア採用を行っています。


  • ディープラーニング等を使った自然言語/画像/音声/動画解析の研究開発
  • Elasticsearch等を使ったデータ収集/分析/可視化
  • マイクロサービス、DevOps、最新のOSSを利用する開発プロジェクト
  • 書籍・雑誌等の執筆や、社内外での技術の発信・共有によるエンジニアとしての成長
 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。


www.wantedly.com



ChatGPTの Assistants API でPDFを要約

こんにちは、安部です。 最近急に、暖かさを通り越して暑いぐらいになってきましたが、皆さまいかがお過ごしでしょうか。

季節外れかなとも思いつつ、もう半袖で過ごしたいくらいの気候ですね。

さて、今回は、OpenAIのAssistants APIの使い方を紹介していきます。 題材は「PDFを和訳して要約してもらう」としました。 これはWeb版のChatGPTでも単にPDFファイルを添付して依頼すればできますが、APIの使い方を示すサンプルとしてはちょうどよいと思います。

最新情報については以下の公式ドキュメントをご覧ください。

https://platform.openai.com/docs/assistants/overview

https://platform.openai.com/docs/api-reference/assistants

それでは早速、Assistants APIの使い方を見ていきましょう。

1. Assistants APIとは

Assistants APIは、開発者が独自にAIアシスタントを組み込んだアプリケーションを開発できるようOpenAIから提供されているAPIです。 AIアシスタントとは、要はCopilotやChatGPTみたいなもののことです。

旧来提供されていたChat Completions APIはステートレスでしたが、Assistants APIはステートフルになったため、メッセージ履歴の管理やモデルの最大トークンに合わせたメッセージの切り捨てなどの処理を抽象化してくれます。

2. Assistantsには何ができるのか

AssistantsはChatGPTでできるような会話はもちろんのこと、Code Interpreter・Knowledge Retrieval・Function Calling という3つの機能(ツール)を使用できます。各機能に関する詳細な解説は割愛しますが、それぞれ概ね以下のような機能です。

  1. Code Interpreter

    サンドボックス化された実行環境でPythonコードを記述し、実行することができます。このツールは、多様なデータやフォーマットのファイルを処理し、データやグラフの画像を含むファイルを生成できます。

  2. Knowledge Retrieval

    ユーザーから提供されたドキュメントなど、アシスタントのモデル外からの知識でアシスタントを補強します。 これにより、自社製品のマニュアルなど固有の情報に基づいた回答をアシスタントにしてもらうことができるようになります。

  3. Function calling

    文字通り、アシスタントに関数呼び出しをさせることができます。これにより、特定の情報は外部APIを使って取得し、その情報を含んだ自然な応答をアシスタントに返させたり、外部アプリを操作させたりすることができます。

3. Assistants APIを実際に使ってみる

それでは、実際にAssistants APIを使っていきましょう。冒頭で述べたように、PDFファイル("Attention is All You Need"という有名論文)を渡してその要約などをしてもらいます。

以下の順にやっていきます。

  1. 準備

  2. Assistantの作成

  3. Threadを作成し、Messageを追加

  4. Threadの実行

実際のユースケースでは、Webアプリケーションなどに組み込むことで、ユーザからの入力に応じてAssistantへのメッセージ送信などを行うことが多いかと思います。

今回はあくまでAPIの使い方を解説する目的なので、フロント側の処理などは省略しています。

3-1. 準備

本記事では、OpenAI Python API libraryを使ってAssistants APIの使い方を見ていきます。

紹介するサンプルコードは、ローカル環境やJupyter Notebookなどで動かすことを想定しています。 OpenAIのAPIキーを取得し、OPENAI_API_KEYという環境変数に登録しておいてください。

なお、Assistantsの動きを試したいだけであれば、OpenAIサイト内のPlayground > Assistantsで試すこともできます。

3-2. Assistantの作成

それでは、最初のステップとしてAssistantを作成していきましょう。

Assistant作成時に入力する項目のうち、重要なものは以下の通りです。

項目名 内容
model 使用するモデル
file_ids アシスタントに覚えてもらいたいファイル
name アシスタントの名前
instructions アシスタントの方向づけなどに使われる指示
tools アシスタントが利用できるツール

Pythonで実装すると、以下のようになります。

ここでは、モデルとしてgpt-4-turbo-previewを指定し、Knowledge Retrievalの機能を有効にしています。また、ローカルに置いてあるPDFファイルをアシスタントに渡すことで、これを知識ベースに加えてもらいます。

from openai import OpenAI  # 特に指定しなければ、環境変数OPENAI_API_KEYを参照してアカウントとの紐付けが行われる client = OpenAI()  file = client.files.create(   file=open("attention.pdf", "rb"),   purpose='assistants' )  assistant = client.beta.assistants.create(   name="general-assistant",   instructions="あなたはチャットサービスのアシスタントです。問い合わせに対し、可能な場合は知識ベースにある知識に基づいて回答してください。",   model="gpt-4-turbo-preview",   tools=[{"type": "retrieval"}],   file_ids=[file.id] ) 

これを実行し、Assistantが作成されたか確認してみます。OpenAIのサイト内のAssistantsを開いてみましょう。 ここでは、アカウントに紐づいたアシスタントの一覧をGUIで確認したり新規作成したりできます。

確かに、作成したAssistantが確認できていますね。添付したファイルも問題なくアップロードされているようです。

ついでに、Storageも確認してみます。

こちらにも、アップロードした画像が格納されています。

なお、今回のように1回限りのアシスタント作成であれば、最初から"Assistants"からGUIを使ってやってしまっても問題ありません。

Webアプリに組み込んでユーザごとにアシスタントを自動作成する場合などに、アシスタントの作成APIを利用することになるかと思います。

3-3. Threadを作成し、Messageを追加

無事にPDFファイルを保持したAssistantを作成できたので、Threadを作成してメッセージを追加していきましょう。

# Threadの作成 thread = client.beta.threads.create()  # メッセージをThreadに追加 message = client.beta.threads.messages.create(     thread_id=thread.id,     role="user",     content="Attention is All You Needという論文の内容を、要約して教えてください" ) 

Threadとは、アシスタントとユーザー間の会話セッションの単位です。 メッセージを保存したり、会話長をモデルのコンテキスト長に適合させるために自動切り捨て処理などを実行してくれます。

コードを見てもらってわかる通り、Threadは最初はアシスタントとは独立して定義します。 後ほどThreadを実行(Run)する際に、どのアシスタントに応答させるかを指定します。

ちなみにメッセージには、画像・テキストなどのファイルを含めることも可能です。

3-4. Threadの実行

それでは、Threadを実行し、回答を表示してみましょう。 Threadの実行(run)とは、Thread上でアシスタントを呼び出すことです。

Threadを実行することで、アシスタントが応答を返してくれます。

# 作成済みのAssistantを取得 assistant = client.beta.assistants.retrieve(assistant_id='asst_4TCRFV6BAULCpsCjXhAEuf3X')  # Threadの実行 run = client.beta.threads.runs.create(   thread_id=thread.id,   assistant_id=assistant.id )  # アシスタントが回答のメッセージを返したら表示する wait_response(client, thread.id, run.id) print_thread_messages(client, thread.id) 

回答待ちとメッセージの出力用関数は、以下のように作りました。

実際にサービスに組み込む際などは、返答を一気に表示するのではなく1文字ずつ出力するなどの工夫をするかと思いますが、ここでは単に回答を待ち、結果を全て出力するという処理にしています。

def wait_response(client, thread_id, run_id):   """アシスタントが回答を返すまで待つ"""   while True:       time.sleep(5)       # 実行ステータス取得       run = client.beta.threads.runs.retrieve(           thread_id=thread_id,           run_id=run_id       )       status = run.status       if status in ["completed", "cancelled", "expired", "failed"]:           break  def print_thread_messages(client, thread_id):   """メッセージを出力する"""   msgs = client.beta.threads.messages.list(thread_id=thread_id)   for message in msgs:       print({"role": message.role, "message": message.content[0].text.value}) 

ちなみに、Runのライフサイクルは以下のようになっており、"completed"や"cancelled"など完了のステータスになったところで結果を出力するようにしております。

https://platform.openai.com/docs/assistants/how-it-works/run-lifecycle

こちらを実行した結果は、次のようになりました(メッセージ部分だけ載せています)。

論文「Attention Is All You Need」は、従来の系列変換モデルが複雑な再帰的(RNN)や畳み込みニューラルネットワーク(CNN)をベースにしており、 それらがエンコーダとデコーダを経由して接続される場合、その接続に注意機構が使われることが多いと指摘しています【7†source】。 これらのモデルの計算は基本的に連続して行われるため、トレーニング時の並列化が制限されるという問題がありました【8†source】。 この論文では、全体に渡って自己注意機構だけに依存する新しいネットワークアーキテクチャである「Transformer」を提案し、再帰や畳み込みを完全に排除しています。 これにより、モデルはより並列化可能で、トレーニング時間も大幅に短縮されると共に、品質も向上することを示しています【7†source】【8†source】。 Transformerモデルはエンコーダとデコーダから構成され、それぞれが自己注意機構と点ごとの全結合層のスタックで構成されています【10†source】。 この自己注意機構は、クエリと一連のキー・値のペアを出力にマッピングする関数として説明されており、出力は値の加重和として計算されます【11†source】。 2つの機械翻訳タスクでの実験により、このモデルは既存の最高の結果を上回り、英語からドイツ語への翻訳タスクにおいて28.4 BLEU、 英語からフランス語への翻訳タスクにおいては新しい単一モデルの最高スコアである41.8 BLEUを達成しました。 さらに、英文構文解析など他のタスクへの応用も成功しており、Transformerが幅広く汎用的に利用可能であることが確認されています【7†source】。

メッセージ内の【7†source】のような表記は、引用を表しています。引用された文章一覧は、message.content[0].text.annotationsで取得できます。

詳細は以下のドキュメントをご覧ください。

https://platform.openai.com/docs/assistants/how-it-works/message-annotations

4. 価格

Assistants APIの料金発生は、使用モデルに基づくトークンベースの課金と、Retrievalなどツールの使用にかかる課金とがあります。

https://openai.com/pricing

Retrievalの課金は、あくまでも保存しているファイルサイズとそれにアクセスしたアシスタントの数で決まり、Thread数などは関係ありません。 お試しでアシスタントをいくつも作成していると、いつの間にか保存しているファイルサイズが大きくなっていたということもあるので、不要なファイルはこまめに消すよう注意しましょう。

また、Thread上でアシスタントへの問い合わせをすると、過去の問い合わせの全てを含めた内容が送信される仕組み(だからこそ過去のやり取りの文脈を踏まえた回答をしてくれるわけですが)ですので、問い合わせを繰り返すたびに雪だるま式にコンテキストトークンが増えていってしまいます。そうするとトークンベースの課金が大きく膨らむことになるので、対策が必要です。

(ちなみに、Threadから過去のメッセージを削除するAPIは提供されていません。)

例えばWebアプリケーションに組み込んでいる場合などは、上限メッセージ数を定数としてシステムに持たせておき、会話のたびに過去のメッセージ一覧を取得して上限を超えていたら新しい方の一部メッセージのみを持った新たなThreadを作成し、古いThreadは削除する、というようなことをすれば回避できそうです。

まとめ

今回は、Assistants APIの基本的な使い方を見てきました。

APIで、ファイルに対する処理や、Function callingなどを実行できるようになり、できることが増えますね!

Acroquest Technologyでは、キャリア採用を行っています。
  • ディープラーニング等を使った自然言語/画像/音声/動画解析の研究開発
  • Elasticsearch等を使ったデータ収集/分析/可視化
  • マイクロサービス、DevOps、最新のOSSを利用する開発プロジェクト
  • 書籍・雑誌等の執筆や、社内外での技術の発信・共有によるエンジニアとしての成長
  少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。 www.wantedly.com

Amazon Bedrock で Titan Image Generator を使って画像生成

今度、寝台列車で旅行に行きたいな、と思って先日予約に挑んでみたのですが、残念ながら予約競争に敗北してしまった、菅野です。 寝台列車は、今も人気が高いんですね。

ChatGPTでもDALL·E 3を用いることが出来るようになるなど、生成AIでも画像生成や読み込みなど一般的に用いられるようになってきました。
Amazonで利用できる生成AIプラットフォーム、Amazon Bedrokでも、以前から画像生成モデルとして世界的にも最も有名なStability AIが提供するStable DiffusionSDXLモデルを用いた画像生成が可能でしたが、 AmazonオリジナルのモデルTitanからも画像生成を行えるモデル、Titan Image Generatorも利用できるようになっています。
今回は、Titan Image Generatorを用いて実際にどのような画像生成ができるのかを見ていきましょう。

docs.aws.amazon.com

Titan Image Generatorとは

Amazonが提供する画像生成のモデルで以下のような処理を実施できます。

機能 説明
Text2Image テキスト入力から画像を生成する
インペインティング 画像の一部だけを書き換える
アウトペインティング 画像の外側を追加する
画像バリエーション 画像とプロンプトを入力し、入力画像のスタイルや背景を変更する

モデルの仕様は以下になっています。

項目 内容
モデルID amazon.titan-image-generator-v1
最大入力文字数 1024文字
最大入力画像サイズ 50MB
イン/アウトペインティングを使用する場合の最大画像サイズ 1024*1024ピクセル
画像バリエーションを利用する場合の最大画像サイズ 4096*4096ピクセル
言語 英語
出力タイプ 画像
サポートされている画像タイプ JPEG、JPG、PNG

まだ倭国語は未対応みたいなのでプロンプトは英語で入力する必要がありそうです。

Titan Image Generatorの利用方法

それでは早速Titan Image Generatorを利用してみましょう。

モデルのアクティベート

Bedrokのモデルアクセスタブから開いた画面の、モデルアクセスを管理ボタンを押下します。

Titan Image Generator G1モデルにチェックを入れます。

同画面下部の変更を保存すると、モデルが利用できるようになります。

実際の利用

Amazon Bedrokでは利用できるモデルを簡単に試すことが出来るプレイグラウンド機能を提供してくれている為、そちらを利用して実際にTitan Image Generatorを利用してみましょう。
左側メニューのプレイグラウンド>イメージを押下して開いた画面のモデルを選択ボタンを押下します。

プロバイダをAmazon、モデルを Titan Image Generator G1に選択し適用を押下します。

これで Titan Image Generatorを利用する準備が整いました。

text2imageを試してみる

まずはシンプルにプロンプトから画像を生成してみましょう。

表示された、画面の下部からプロンプトを入力して実行ボタンを押下します。
今回はA modern architectual building with large glass windwos, situated on a cliff overlooking a serene ocean at sunset.(夕暮れ時の穏やかな海を望む崖の上に建つ、大きなガラス窓を備えたモダンな建築の建物。)と入力してみました。
およそ1分程度の時間がかかりますが、以下のように画像が生成されます。

デフォルトの設定では1024*1024ピクセルの画像が1枚生成されます。

入力した文字列を忠実に再現した画像が生成されました。
写実的な表現をするような命令文を入れていないにもかかわらず、本当に存在しそうな画像が出てきましたね。

インペインティングを試してみる

つづきまして、入力された画像の一部のみ変更するインペインティングを試してみます。
右側のメニューから、モードをEditに変更、変更したい写真を推論イメージからアップロードして変更したい箇所にマスクの矩形を移動し、プロンプトに変更内容を入力して、実行を押下します。
先ほど出力された画像に、雲を追加してみましょう。

プロンプトにはadd cloud(雲を追加)と入力しました。

夕焼けの印影に合わせて雲が追加されました。
指定した範囲外は元の画像のままになっています。

アウトペインティングを試してみる

お次は、入力画像の対象物体以外を置き換えるアウトペインティングです。
再度、text2imageで作った画像に加工を加えてみましょう。

Editモードのまま、変更したい写真を推論イメージからアップロード、マスクの矩形を画面全体に適応し、マスクプロンプトにsea(海)と入力します。
プロンプトにsea of trees(樹海)と入力して、実行ボタンを押下します。

海がうっそうと生い茂る森に代わりました。

画像バリエーションを試してみる

アップロードした画像とプロンプトをもとに、投入した画像のバリエーションを出力します。
モードをGenerateに戻し、推論イメージにバリエーションを作成したい画像をアップロードします。
text2imageで作った画像をアップロードし、同じ雰囲気の画像を作ってもらいましょう。

一分ほどで画像が生成されました。
配置自体は変わっていますが、建物の雰囲気や、海の中の岩礁など、同じような画像が生成されています。

推論イメージ無しで三枚出力したものと比較すると、より同じテイストになっていることがわかります。

まとめ

Amazonが作成して画像生成モデルTitan Image Generatorを実際に使ってどのような出力をすることが出来るか試してみました。
Stable DiffusionのSDXLとは異なり、いわゆる呪文のようなプロンプトなしで写真ライクな画像を簡単に生成できる点は強みであると感じました。
今後も生成AIでどういったことが出来るのか調査していこうと思います。

Acroquest Technologyでは、キャリア採用を行っています。
  • ディープラーニング等を使った自然言語/画像/音声/動画解析の研究開発
  • Elasticsearch等を使ったデータ収集/分析/可視化
  • マイクロサービス、DevOps、最新のOSSクラウドサービスを利用する開発プロジェクト
  • 書籍・雑誌等の執筆や、社内外での技術の発信・共有によるエンジニアとしての成長
  少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。 www.wantedly.com

https://tabp.frisuba.online https://ympr.haychill.site https://ayrf.lexu.site https://xfpi.workpolska.online https://hpkr.ophimhd.site https://grwm.lexu.site https://wbrd.ophimhd.site https://ypet.lexu.site https://hqqr.workpolska.online https://ngsf.workpolska.online https://ryfg.workpolska.online https://sngt.ophimhd.site https://tqxk.ophimhd.site https://prmw.frisuba.online https://ksbh.ophimhd.site