0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

個人的アドカレAdvent Calendar 2024

Day 3

Lambda + Dockerでscikit-learn実行環境を作成し、Lambdaでテキスト類似度を計算する

Posted at

はじめに

本記事では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を作成します。

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(検索クエリ)を受け取り、それぞれの類似度を計算します。

app.py
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のリポジトリを選択し関数を作成します。

image.png

6. 実行テスト

Lambda テストイベント
{
  "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で実行しているのも原因だと思いますが、結構時間がかかった印象です。

実行ログ(1回目)
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
実行ログ(2回目)
~~~
REPORT RequestId: ~~~	Duration: 35.62 ms	Billed Duration: 36 ms	Memory Size: 128 MB	Max Memory Used: 124 MB	

参考資料

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?