Word2vecモデルをAWS Lambdaで動かしてみる


はじめに

これは,mediba Advent Calendar 2020 23日目の記事です.

medibaの野崎です.
現在は,バックエンドエンジニアとして au Webポータル などのプロダクトの担当し,バックエンドアプリケーションやインフラ範囲の運用を行っています.
また,兼務でテクノロジーセンターにて,TechLeadチームにも所属しています.
※参考:2020年度エンジニア組織について | mediba Creator × Engineer Blog


AWS Lambda の新機能 – コンテナイメージのサポート | Amazon Web Services ブログ

今月発表されたAWS Lambdaのコンテナイメージサポートされました.
Lambda 関数を最大 10 GB のコンテナイメージとしてパッケージ化し、デプロイできるようになりました。とあるように, これまでより大きなサイズのパッケージが出来るようになり,
機械学習のモデルや自然言語処理(NLP)で利用する辞書データなどをコンテナに含めることが出来そうです.

そこで本記事では,訓練済みのWord2vecモデルをコンテナ内に含めAWS Lambda上で動かしてみます.
作る機能としては,入力したワードに対して類似したワードとその類似度(0~1の範囲の値)を返却するもので,これをAPI経由で呼び出せるようにします.
訓練済みのWord2vecモデルは,類似したワードを返却する部分で使います.

全体像としては,図のような形になります.

背景

なぜ今回このような検証を行うかを背景ですが,
au Webポータルではニュース記事の配信を行っているプロダクトがあり,
この機能としてニュース記事に対して自然言語処理(NLP)を施して提供しているものいくつかあります.

現在このシステムはEC2上で構築されていますが,
今後はコンテナ化あるいはサーバレス化への変更を検討しています.
この検討の一環として,掲題のような内容を思い立ちました.

実施した手順

AWS サーバーレスアプリケーションモデル - アマゾン ウェブ サービス
今回はAWS Lambdaのフレームワークとして,SAMを利用します.

1. sam init

以下のバージョンで進めていきます.

$ sam --version
SAM CLI, version 1.13.2

samプロジェクトの初期化を行います.

$ sam init
Which template source would you like to use?
    1 - AWS Quick Start Templates
    2 - Custom Template Location
Choice: 1
What package type would you like to use?
    1 - Zip (artifact is a zip uploaded to S3)
    2 - Image (artifact is an image uploaded to an ECR image repository)
Package type: 2

Which base image would you like to use?
    1 - amazon/nodejs12.x-base
    2 - amazon/nodejs10.x-base
    3 - amazon/python3.8-base
    4 - amazon/python3.7-base
    5 - amazon/python3.6-base
    6 - amazon/python2.7-base
    7 - amazon/ruby2.7-base
    8 - amazon/ruby2.5-base
    9 - amazon/go1.x-base
    10 - amazon/java11-base
    11 - amazon/java8.al2-base
    12 - amazon/java8-base
    13 - amazon/dotnetcore3.1-base
    14 - amazon/dotnetcore2.1-base
Base image: 3

Project name [sam-app]: sam-wiki-entity-vectors

以下のようなプロジェクトが出来ます.
※以降の作業で含めるディレクトリ,ファイルも記載してあります.


.
├── README.md
├── __init__.py
├── events
│   └── event.json
├── hello_world
│   ├── Dockerfile
│   ├── __init__.py
│   ├── app.py
│   ├── requirements.txt
│   └── tohoku_entity_vector         // 2. モデルの取得で作成するディレクトリ
│       ├── entity_vector.model.bin
│       └── entity_vector.model.txt
├── samconfig.toml                   // 7. sam deployで作成される
├── template.yaml
└── tests
    ├── __init__.py
    └── unit
        ├── __init__.py
        └── test_handler.py

2. モデルの取得

今回は東北大学 乾・岡崎研究室にて公開されている訓練済みのモデルを使わせていただきます.

日本語 Wikipedia エンティティベクトル

上記サイトより以下の2つのファイルを取得し,samプロジェクト内にtohoku_entity_vectorディレクトリを作成しこれらを格納します.

  • バイナリファイル (entity_vector.model.bin)
  • テキストファイル (entity_vector.model.txt)

$ du -h hello_world/tohoku_entity_vector
2.6G

これらのファイルサイズは2.6GBありました.

3. コードの変更

プロジェクト内の以下のファイルを変更します.

requirements.txt

以下を追加します,

gensim

Gensimは,大規模コーパスを用いたトピックモデリング,文書インデックス作成,類似性検索のためのPythonライブラリです.

Dockerfile

COPY箇所を以下のように修正します.
tohoku_entity_vector/もcopy対象に加えて,モデルもDockerコンテナに含めます.


COPY app.py requirements.txt tohoku_entity_vector/ ./

app.py

以下のように修正します.


import os
import json

from gensim.models import KeyedVectors


def lambda_handler(event, context):

    word = event.get('queryStringParameters').get('word')

    model = KeyedVectors.load_word2vec_format(
        './entity_vector.model.bin', binary=True)
    result = model.most_similar('[' + word + ']')

    return {
        "statusCode": 200,
        "body": json.dumps(result, indent=2, ensure_ascii=False),
    }

most_similarは,入力したワードに対して類似したワードとその類似度(0~1)を類似度順に返却します.

gensim.models.Word2Vec.most_similar

template.yaml

Globalsの項,メモリとタイムアウト値を変更します.


Globals:
  Function:
    Timeout: 900
    MemorySize: 10240

Lambda quotas - AWS Lambda

どちらも上記クォータの上限まで上げてみます.

4. sam build

dockerを起動した状態で,以下のコマンドを実行します.


$ sam build

5.ローカルでの動作の確認

ローカル環境にて以下のコマンドで,apiのテストが行えます.

$ sam local start-api

ブラウザで以下のようにリクエストします.

クエリパラメータで入力した川崎フロンターレという入力に対して,
類似したワードとして,ジュビロ磐田 大分トリニータといったワードとその類似度が期待通り返却されました.大丈夫そうです.

6.ECRリポジトリの作成

以下のコマンドで,DockerイメージをPUSHする用のECRリポジトリを作成します.

aws ecr create-repository --repository-name repository-name

7.sam deploy

#初回
$ sam deploy --guided

#2回目以降
$ sam deploy

初回のデプロイでは,--guidedオプションをつけることによりデプロイ設定を選択していきます.samconfig.tomlが作成されます.
2回目以降のデプロイでは,このファイルを元にデプロイされます.

deployコマンドで,ECRへのimageのpushとAWS Lambdaへの関数のデプロイが行われます.

8.動作の確認

まずはECRのイメージを確認します.
PUSHされており,1.8GBほどあることが確認できます.

次に,APIの確認を行います.
今度はクエリパラメータで入力したFCバルセロナという入力を行い,
類似したワードとして,レアル・マドリード ACミランといったワードとその類似度が期待通り返却されました.期待通りです.
APIのレイテンシは10sec程度でした.

機械学習システムのデザインパターン

本記事を執筆して知ったのですが,
メルカリ様にて,機械学習システムのデザインパターンを公開されていました.
機械学習システムの設計パターンを公開します。 | メルカリエンジニアリング
具体的なパターン別に,ユースケースや利点難点などが整理されています.

今回の構成は,Web single pattern | ml-system-design-pattern
こちらのパターンになりそうです.

まとめ

  • Word2vecモデルをAWS Lambdaで動かしてみました
  • Word2vecモデルをコンテナに内包出来るようになり,アプリケーションの開発が単純になりました
    • これまでAWS Lambdaでサイズな大きなファイルを扱う場合は,EFSなどのサービス連携が必須でした
  • AWS Lambdaの関数のメモリ割り当てを,どのように最適化するか検討が必要です

参考記事