AWSlambdaでkerasを動かす

AWSのlambdaはサーバレスアーキテクチャで非常に扱いがいいのですが、一つ難点があって、アップロードできるファイルサイズが限られていることです。
最大50MのZIPファイルまでなのですが、裏技を使って展開時に500M以上のファイルを使うことができます。

そのカラクリは、Lambdaの/tmp以下は500Mまで使うことができます。この領域に、Lambdaが起動するときにファイルをS3から読み込めば、非常に大きなライブラリが必要なプログラムも動かすことができます。
以下は、pythonにてkeras+tensorflow+opencvを動かすサンプルです。

ライブラリ準備

python3を使用します。
ライブラリは、あらかじめ、EC2でAmazonLinuxを使って作成しておきます。

requirements.txt

keras
opencv-python
tensorflow
numpy
mkdir lib
pip3 install -U -r requirements.txt -t lib

このlib以下にライブラリがインストールされます。

find lib -name "*.pyc" -exec rm -rf {} ¥;

pycは削除しておきます。しなくてもいいですが。。。

これを全てLambdaの起動時に追加してもいいのですが、ロードが面倒になるので2つに分けます。

mv lib lib_other
mkdir lib
cd lib_other
mv cv2* ../lib
mv h5py* ../lib
mv keras* ../lib
mv tensor* ../lib
cd ..

libを固めてS3にアップ

zip -r lib.zip lib
aws s3 cp s3://bucketname/

lambdaディレクトリ

lambda用のディレクトリに、先ほど分けたlib_otherのライブラリを入れておきます。
これ全部を入れてようやく50Mぐらいまでに収まります。

mkdir lambda_dir
cd lambda_dir
mkdir vendor
cd vendor
cp -pr ../../lib_other/* .

lambdaプログラム

lambdaのプログラムには少し工夫が必要です。
起動時に、S3から先ほどアップしたlib.zipをダウンロードし展開、ロードします。

lambda_functioy.py


import sys
import os
sys.path.append(os.path.join(os.path.abspath(os.path.dirname(__file__)), './vendor'))

import boto3
import zipfile
import importlib

def lambda_handler(event, context):
    s3 = boto3.resource("s3")

    def load_zip(file):
        print("load_zip:"+file)
        s3.Bucket(bucket_name).download_file(libfiledir+"/"+file,"/tmp/"+file)
        with zipfile.ZipFile("/tmp/"+file) as zip:
            zip.extractall("/tmp")
        os.remove("/tmp/"+file)

    if os.path.exists("/tmp/lib") is False:  # 2回目以降はスキップ
        load_zip("lib.zip")

    sys.path.append('/tmp/lib')
    importlib.import_module("numpy")
    importlib.import_module("scipy")
    importlib.import_module("six")
    importlib.import_module("yaml")
    importlib.import_module("enum")
    importlib.import_module("h5py")
    importlib.import_module("absl")
    importlib.import_module("astor")
    importlib.import_module("bleach")
    importlib.import_module("external")
    importlib.import_module("gast")
    importlib.import_module("google.protobuf")
    importlib.import_module("grpc")
    importlib.import_module("html5lib")
    importlib.import_module("markdown")
    importlib.import_module("werkzeug")
    importlib.import_module("wheel")
    importlib.import_module("cv2")
    importlib.import_module("tensorflow")
    importlib.import_module("keras")

    import cv2
    import keras
    import numpy as np

こんな感じでコードを書きます。
Lambdaは一度起動すると、しばらくはインスタンスが残っているので、2回目以降に再度S3からダウンロードするのを防ぎます。

こんな感じで、500M以上のモジュールをつかったLambdaファンクションが作ることができます。