Bedrockのキャッチアップしたいなーと思いつつ、全く触れていなかったところ以下の書籍が発売されたので、購入し色々実装してみました。
感想としてはBedrockでできることやAPIの使い方が学習でき、周回遅れ気味な私には非常に良かったです。
簡単に内容や、書籍で学習した内容を元に実装した内容を紹介します。
以下は実装の一例ですが、基本 AWS CDK で Lambda Function URLs で APIを生やして検証していました。 書籍では SageMaker Notebook や Google Colaboratory など、Jupyterを使っています。
目次
TL;DR
書籍に書いてあること
Bedrockの基盤モデルの利用方法が一通り学べるイメージです。
- Amazon Bedrockの説明
- PlayGroundの使い方
- python (boto3) による Bedrock APIの使い方(テキスト生成、画像生成、Embedding)★これがメインコンテンツ
- LangChainの使い方
- curl, JavaScriptによるBedrock APIの使い方
※出版社の書籍HPは以下。
書いてないこと
- 生成AI自体の説明
- Bedrockと他のAWSサービスの連携。Bedrock以外だとSageMaker Notebookのみ登場(ただし、SageMaker特有の機能は利用しない)
- Bedrockの「発展的な」機能(Agents for Amazon Bedrock, Knowledge Base for Amazon Bedrockなどは登場しない。)
どんな人に向いているか
書籍の「はじめに」にも言及がありますが、私見としては以下に該当する人かなと。
例えばAWS公式のBedrock Workshopの内容を一通り理解しているような方であれば、少し物足りない内容かもしれません。
catalog.us-east-1.prod.workshops.aws
内容詳細の紹介
学習内容を元に実装したものを踏まえ、どういうことが学べるか紹介します。実装は以下にあります。
なお書籍の説明内容に直接関わるところ(主にBedrockに関する実装)の説明は基本的に書いていません。気になる場合は書籍をぜひ参照ください。
実装方針
基本的に以下のようにLambda(Python)を実装し検証しています。
- AWS CDKの PythonFunction (2024/3時点ではαモジュール)を利用
- Lambda で実装してLambda Function URLsでAPIを公開、
- API を curl 等で叩いて検証。
※検証用途なのでパブリックに公開して叩いていますが、セキュアにしたい場合は以下の対応等を行った方が良いです。
Lambdaの実装は以下のように CDK の PythonFunction
を中心に実装しています。
// Layer作成 const numpyLayer = new PythonLayerVersion(this, 'NumpyLayer', { entry: 'lambda/layer/numpy', compatibleRuntimes: [lambda.Runtime.PYTHON_3_12] }) // Lambda実装 const checkCosFunction = new PythonFunction(this, 'CheckCosFunction', { functionName: 'checkCosFunction', runtime: lambda.Runtime.PYTHON_3_12, entry: 'lambda/chapter10-check-cos', handler: 'handler', timeout: cdk.Duration.seconds(60), logRetention: logs.RetentionDays.ONE_DAY, layers: [numpyLayer] }); // LambdaにBedrockの権限付与。一旦FullAccessにしているが、本来はもっと絞るべき checkCosFunction.role!.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonBedrockFullAccess')); // Lambda Function URLs で公開。 const lambdaUrl = checkCosFunction.addFunctionUrl({ authType: lambda.FunctionUrlAuthType.NONE, invokeMode: lambda.InvokeMode.BUFFERED }) new cdk.CfnOutput(this, 'CheckCosLambdaEndpoint', { value: lambdaUrl.url })
プロジェクトのlambda
配下にLambdaのコードと、Layerの作成元になる requirements.txt
を配置しています。
これだけでいい感じにLayerを作成してデプロイしてくれるので非常に便利ですね。
. ├── chapter4 │ └── index.py ├── chapter5 │ └── index.py ....中略... └── layer ├── langchain │ └── requirements.txt └── numpy └── requirements.txt
Chapter1~3
この辺りはBedrockの説明や、PlayGroundの使い方なので割愛します。
Chapter4
boto3のlist_foundation_models
で基盤モデルの情報取得方法を学習します。
検証時は Provider や Mode で絞りって検索できるAPIを立ててみました。
Claude 3 がちょうど生えてきた時に試したので、結果に含まれています。
{ "modelName": "Claude 3 Sonnet", "modelId": "anthropic.claude-3-sonnet-20240229-v1:0", "inputModalities": [ "TEXT", "IMAGE" ], "outputModalities": [ "TEXT" ] }
Chapter 5
プロンプトを元にテキスト生成を行う方法を学習します。
書籍では以下のモデルを使用します。
Titan
Jurassic-2
Claude 2.1
検証時は上記のモデルにそれぞれプロンプトを投げて結果を返すLambdaを実装してみました。
また応用として検証時に新しく生えてきたClaude 3 Sonnetバージョンも実装しています。以下Claude 3の部分のみ抜粋。
import boto3 import json runtime_client = boto3.client( service_name="bedrock-runtime", region_name="us-east-1", ) # model claude3_model_id = "anthropic.claude-3-sonnet-20240229-v1:0" def claude3(prompt): body = json.dumps( { "messages": [ {"role": "user", "content": [{"type": "text", "text": f"{prompt}"}]} ], "max_tokens": 1000, "temperature": 0.5, "top_k": 250, "top_p": 0.7, "anthropic_version": "bedrock-2023-05-31", } ) response = runtime_client.invoke_model(body=body, modelId=claude3_model_id) response_body = json.loads(response.get("body").read()) output_text = response_body.get("content") return output_text def handler(event, context): body = json.loads(event["body"]) prompt = body["prompt"] # claude3 claude3_output = claude3(prompt) response_body = { "claude3": claude3_output, } return {"statusCode": 200, "body": json.dumps(response_body, indent=4)}
Chapter 6
SDXL, Titan Image を使用し画像生成について学びます。
検証時はLambda から Bedrock を叩き、画像を生成した後にS3を生成し、対象画像の署名付きURLを返却しアクセス可能とする形にしています。
def save_image(base64_data): # オブジェクトのキーを uuid に設定 unique_id = str(uuid.uuid4()) key = f"{unique_id}.png" # Bedrockで取得した画像(base64)をS3にput image_data = base64.b64decode(base64_data) response = s3_client.put_object(Bucket=bucket_name, Key=key, Body=image_data) # 署名付きURLを生成 url = s3_client.generate_presigned_url( "get_object", Params={ "Bucket": bucket_name, "Key": key, }, ) # URLを返却 return url
Chater 6-1, 6-2は prompt
から SDXL, Titan Image で画像を生成します。
Chapter 6-3 ではSDXL, Titan Image画像の加工を行います。
以下のように、画像、Mask画像、プロンプトから新しいイメージを生成します。
# 6-3 イメージの編集(SDXL) $ curl -X POST -F "prompt=A bird is flying near the hot air balloon." -F "image=@./sample/mask_image/bird.png" -F "mask_image=@./sample/mask_image/mask.png" https://your-lambda-function-url # レスポンス例(生成した画像の署名付きURL) { "SDXL edited image URL": "https://..." }
たとえば画像として鳥の画像を指定し、
Mask画像(白抜きのところ)を編集箇所として指定し
プロンプトで「気球の近くを鳥が飛んでいる」のように指定しリクエストを行うと、Mask画像で白抜きだったところに気球が追加された画像が生成されます。
なお、Lambdaの実装で 標準のcgi
を使用しているのですが、python3.11で非推奨、python3.13で削除予定なので注意が必要です。
Chapter 7
Prompt からテキストを生成した際のトリーミングによるレスポンスを学びます。
書籍を参考にpythonで実施していましたが、Lambda の Stream Response は 2024/3 時点ではNode.jsしか対応していないため、そのまま実装するだけでは想定通りには動きませんでした。。。
そのため検証時はNode.jsで実装しています。実装配下を参照(というかほぼ丸パクリ)させてもらいました。
Chapter 8
テキスト生成について、LangChain で Bedrock を利用する方法を学びます。
書籍から変えている点として、Bedroc
と BedrockChat
を langchain_community
からインポートするようにしています(書籍だとlangchain
からのインポート)
from langchain_community.llms import Bedrock from langchain_community.chat_models import BedrockChat
またモデルとして、書籍では Claude 2.1
を使用していますが、2024/3に登場した Claude 3
に差し替えて動かす等も可能です。モデルID変えるだけなので簡単ですね。
# claude_model_id = "anthropic.claude-v2:1" # claude_model_id = "anthropic.claude-3-sonnet-20240229-v1:0" claude_model_id = "anthropic.claude-3-haiku-20240307-v1:0"
試しに Claude3 の AWS の What's newを要約させてみました(以下のリンクの内容)。
ぱっと見、Claude 3 Sonnet が一番良さそうですが、速度や価格でメリットがある Claude 3 Haiku でも十分ですね。
# レスポンス例(Claude 2.1) { "result": "要約: Anthropic社のClaude 3 Sonnet foundationモデルがAmazon Bedrock上で一般公開された。Claude 3シリーズ(Claude 3 Opus、Claude 3 Sonnet、Claude 3 Haiku)は、Anthropic社の次世代の最先端モデルである。ほとんどのワークロードにおいて、SonnetはAnthropic社のClaude 2よりも入力と出力が高速である。" } # レスポンス例(Claude 3 Sonnet) { "result": "アンスロピックはAmazon Bedrockで一般提供を開始したClaude 3 Sonnetという新しい基盤モデルを発表しました。Claude 3ファミリー(Claude 3 Opus、Claude 3 Sonnet、Claude 3 Haiku)はアンスロピックの次世代の最先端モデルで、大半のワークロードにおいて、Claude 3 SonnetはアンスロピックのClaude 2や2よりも入出力の処理が高速化されています。" } # レスポンス例(Claude 3 Haiku) { "result": "以下のように要約します。 Anthropicが開発したクロード3ソネットモデルが、Amazon Bedrock上で一般提供されるようにな りました。クロード3ファミリ(クロード3 Opus、クロード3 Sonnet、クロード3 Haiku)は、Anthropicの最新鋭のモデルです。ほとんどのワー クロードにおいて、クロード3 Sonnetは入出力の処理において、前世代のクロード2やクロード2 Xより高速です。" }
Chapter 9
ここは curl や JavaScript から Bedrock の API を叩く方法を学びます。
Chapter 10
Embedding および cos類似度をベースにしたセマンティック検索について学びます。
前半はテキストの Embedding およびセマンティック検索を学びます。
後半はマルチモーダルのEmbedding および セマンティック検索 を学びます。
リクエストに含まれる画像やテキストをEmbeddingし、あらかじめ用意した画像の中から類似度が最も高い画像検索します。
# prompt を指定して検索 $ curl -X POST -F "prompt=woman" https://your-lambda-function-url # 画像を指定して検索も可能。 $ curl -X POST -F "image=@./input_image/cat.jpg" https://your-lambda-function-url # レスポンス例(類似度が最も高い画像) { "File name": "human.jpg", "Presigned URL": "https://..." }
今回は簡易的にリクエストが来たタイミングで、S3バケット内の画像を全て Embedding した上で、セマンティック検索を行っています。ですが、リクエストのたびに全画像を処理するのは本来は非効率です。
実際はあらかじめ S3バケットの画像を Embedding してベクターストアに入れておく、等をしておくべきです。
更に Bedrock を学ぶために
最後に、Bedrockに対する理解をさらに深めるために、今後やってみようと思っている学習コンテンツをまとめておきます。
Agents for Bedrockの学習
書籍では学べなかった機能その1。Bedrock Workshopの一部。
catalog.us-east-1.prod.workshops.aws
Knowledge Base for Amazon Bedrockの学習
書籍では学べなかった機能その2。Claude3にも追従しているなど有料級。
ベクターストアの学習
AWSのベクターストアを学ぶワークショップ。とりあえずOpensearchとRDSのものを発見。
catalog.us-east-1.prod.workshops.aws
LangChainの学習
LangChainについて更に学ぶワークショップ。バージョンアップに追従できてるかが若干心配。