はじめに
本記事ではDockerイメージをECRに格納し、そのコンテナイメージからLambdaでscikit-learnの実行環境を作成します。Lambdaではscikit-learnを使用してテキストの類似度を算出する処理を実装します。
環境
- Python 3.12
- Docker: 24.0.7
- Docker Desktop
- AWS CLI(設定済み想定)
ゴール
- ECRに格納したコンテナイメージを使ってデプロイし、Lambdaを構築
- scikit-learnを使ったテキスト分析をLambdaで実行
作るもの
- Dockerイメージ:1つ(Lambda環境構築)
- ECRのリポジトリ:1つ(Dockerイメージの保存)
- Lambda:1つ(テキスト類似度計算)
本記事で書かない事
- Lambda実行用のIAMロール作成
ディレクトリ構成
text-similarity/
├── Dockerfile
└── app.py
1. Dockerfileの作成
次のようなDockerfileを作成します。
FROM public.ecr.aws/lambda/python:3.12
# Pythonパッケージのインストール
RUN pip install --no-cache-dir \
scikit-learn \
numpy \
scipy
# イメージ内のLAMBDA_TASK_ROOTにapp.pyをコピー
COPY app.py ${LAMBDA_TASK_ROOT}
# Lambdaが実行する関数を指定
CMD [ "app.lambda_handler" ]
2. Lambda関数のスクリプト
テキストの類似度を計算する処理(app.py)を実装します。
入力としてtexts
(比較対象とする複数のテキスト)とquery
(検索クエリ)を受け取り、それぞれの類似度を計算します。
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
import json
# テキストの類似度を計算
def calculate_similarity(query, texts):
vectorizer = TfidfVectorizer()
# クエリと参照テキストを一緒にベクトル化
all_texts = [query] + texts
tfidf_matrix = vectorizer.fit_transform(all_texts)
# クエリと各テキストのコサイン類似度を計算
similarities = cosine_similarity(tfidf_matrix[0:1], tfidf_matrix[1:]).flatten()
return similarities
def lambda_handler(event, context):
try:
# リクエストボディからデータを取得
body = json.loads(event.get('body', '{}'))
query = body.get('query', '')
texts = body.get('texts', [])
# 類似度計算
similarities = calculate_similarity(query, texts)
# 結果の作成
results = [
{'text': text, 'score': float(score)}
for text, score in zip(texts, similarities)
]
# 最も類似度が高いものを取得
best_match = max(results, key=lambda x: x['score'])
return {
'statusCode': 200,
'body': json.dumps({
'results': results,
'best_match': best_match
}, ensure_ascii=False)
}
except Exception as e:
return {
'statusCode': 500,
'body': json.dumps({
'error': str(e)
})
}
- 参考
3. Dockerイメージの作成
次のコマンドでカレントディレクトリのDockerfileから sample-test-lambda
という Dockerイメージを作成します。
docker build -t sample-test-lambda .
イメージが作成できてるか確認したい場合は、次のコマンドで確認できます。
docker images
4. ECR
マネジメントコンソール > Amazon Elastic Container Registry からリポジトリを作成し、DockerイメージはECRのリポジトリへプッシュしておいてください。
5. Lambdaのデプロイ
マネジメントコンソールからだと、Lambda > コンテナイメージ > イメージを参照 から対象のECRのリポジトリを選択し関数を作成します。
6. 実行テスト
{
"body": {
"query": "How is the weather forecast for this weekend?",
"texts": [
"This weekend will be sunny with high temperatures. Expected high is 73°F and low is 59°F. Don't forget your sunscreen.",
"Next week will be rainy due to low pressure. Remember to bring an umbrella.",
"Saturday will be clear and comfortable. Mild winds with a high of 75°F and low humidity. Perfect weather for outdoor activities."
]
}
}
{
"statusCode": 200,
"body": {
"results": [
{
"text": "This weekend will be sunny with high temperatures. Expected high is 73°F and low is 59°F. Don't forget your sunscreen.",
"score": 0.2393
},
{
"text": "Next week will be rainy due to low pressure. Remember to bring an umbrella.",
"score": 0.0
},
{
"text": "Saturday will be clear and comfortable. Mild winds with a high of 75°F and low humidity. Perfect weather for outdoor activities.",
"score": 0.1213
}
],
"best_match": {
"text": "This weekend will be sunny with high temperatures. Expected high is 73°F and low is 59°F. Don't forget your sunscreen.",
"score": 0.2393
}
}
}
ウォームスタート状態の2回目は約36ミリ秒で実行完了しましたが、初回のLambda実行はコールドスタートで約27秒ほどかかりました。メモリは128MBで実行しているのも原因だと思いますが、結構時間がかかった印象です。
INIT_REPORT Init Duration: 10008.14 ms
~~~
REPORT RequestId: ~~~ Duration: 16813.38 ms Billed Duration: 16814 ms Memory Size: 128 MB Max Memory Used: 95 MB
~~~
REPORT RequestId: ~~~ Duration: 35.62 ms Billed Duration: 36 ms Memory Size: 128 MB Max Memory Used: 124 MB