在亚马逊 lambda 中使用 moviepy、scipy 和 numpy

Using moviepy, scipy and numpy in amazon lambda

我想使用 AWS Lambda 功能生成视频。

我已按照找到的说明进行操作 here and here

我现在有以下过程来构建我的 Lambda 函数:

第 1 步

触发一个 Amazon Linux EC2 实例并 运行 以 root 身份运行它:

#! /usr/bin/env bash

# Install the SciPy stack on Amazon Linux and prepare it for AWS Lambda

yum -y update
yum -y groupinstall "Development Tools"
yum -y install blas --enablerepo=epel
yum -y install lapack --enablerepo=epel
yum -y install atlas-sse3-devel --enablerepo=epel
yum -y install Cython --enablerepo=epel
yum -y install python27
yum -y install python27-numpy.x86_64
yum -y install python27-numpy-f2py.x86_64
yum -y install python27-scipy.x86_64

/usr/local/bin/pip install --upgrade pip
mkdir -p /home/ec2-user/stack
/usr/local/bin/pip install moviepy -t /home/ec2-user/stack

cp -R /usr/lib64/python2.7/dist-packages/numpy /home/ec2-user/stack/numpy
cp -R /usr/lib64/python2.7/dist-packages/scipy /home/ec2-user/stack/scipy

tar -czvf stack.tgz /home/ec2-user/stack/*

第 2 步

我将生成的 tarball scp 到我的笔记本电脑。然后 运行 这个脚本来构建一个 zip 存档。

#! /usr/bin/env bash

mkdir tmp
rm lambda.zip
tar -xzf stack.tgz -C tmp

zip -9 lambda.zip process_movie.py
zip -r9 lambda.zip *.ttf
cd tmp/home/ec2-user/stack/
zip -r9 ../../../../lambda.zip *

process_movie.py 脚本目前只是测试堆栈是否正常:

def make_movie(event, context):
    import os
    print(os.listdir('.'))
    print(os.listdir('numpy'))
    try:
        import scipy
    except ImportError:
        print('can not import scipy')

    try:
        import numpy
    except ImportError:
        print('can not import numpy')

    try:
        import moviepy
    except ImportError:
        print('can not import moviepy')

第 3 步

然后我将生成的存档上传到 S3 作为我的 lambda 函数的来源。 当我测试该功能时,我得到以下 callstack:

START RequestId: 36c62b93-b94f-11e5-9da7-83f24fc4b7ca Version: $LATEST
['tqdm', 'imageio-1.4.egg-info', 'decorator.pyc', 'process_movie.py', 'decorator-4.0.6.dist-info', 'imageio', 'moviepy', 'tqdm-3.4.0.dist-info', 'scipy', 'numpy', 'OpenSans-Regular.ttf', 'decorator.py', 'moviepy-0.2.2.11.egg-info']
['add_newdocs.pyo', 'numarray', '__init__.py', '__config__.pyc', '_import_tools.py', 'setup.pyo', '_import_tools.pyc', 'doc', 'setupscons.py', '__init__.pyc', 'setup.py', 'version.py', 'add_newdocs.py', 'random', 'dual.pyo', 'version.pyo', 'ctypeslib.pyc', 'version.pyc', 'testing', 'dual.pyc', 'polynomial', '__config__.pyo', 'f2py', 'core', 'linalg', 'distutils', 'matlib.pyo', 'tests', 'matlib.pyc', 'setupscons.pyc', 'setup.pyc', 'ctypeslib.py', 'numpy', '__config__.py', 'matrixlib', 'dual.py', 'lib', 'ma', '_import_tools.pyo', 'ctypeslib.pyo', 'add_newdocs.pyc', 'fft', 'matlib.py', 'setupscons.pyo', '__init__.pyo', 'oldnumeric', 'compat']
can not import scipy
'module' object has no attribute 'core': AttributeError
Traceback (most recent call last):
  File "/var/task/process_movie.py", line 91, in make_movie
    import numpy
  File "/var/task/numpy/__init__.py", line 122, in <module>
    from numpy.__config__ import show as show_config
  File "/var/task/numpy/numpy/__init__.py", line 137, in <module>
    import add_newdocs
  File "/var/task/numpy/numpy/add_newdocs.py", line 9, in <module>
    from numpy.lib import add_newdoc
  File "/var/task/numpy/lib/__init__.py", line 13, in <module>
    from polynomial import *
  File "/var/task/numpy/lib/polynomial.py", line 11, in <module>
    import numpy.core.numeric as NX
AttributeError: 'module' object has no attribute 'core'

END RequestId: 36c62b93-b94f-11e5-9da7-83f24fc4b7ca
REPORT RequestId: 36c62b93-b94f-11e5-9da7-83f24fc4b7ca  Duration: 112.49 ms Billed Duration: 200 ms     Memory Size: 1536 MB    Max Memory Used: 14 MB

我不明白为什么 python 找不到文件夹结构中存在的核心目录。

编辑:

按照@jarmod 的建议,我将 lambda 函数缩减为:

def make_movie(event, context):
    print('running make movie')
    import numpy

我现在有以下错误:

START RequestId: 6abd7ef6-b9de-11e5-8aee-918ac0a06113 Version: $LATEST
running make movie
Error importing numpy: you should not try to import numpy from
        its source directory; please exit the numpy source tree, and relaunch
        your python intepreter from there.: ImportError
Traceback (most recent call last):
  File "/var/task/process_movie.py", line 3, in make_movie
    import numpy
  File "/var/task/numpy/__init__.py", line 127, in <module>
    raise ImportError(msg)
ImportError: Error importing numpy: you should not try to import numpy from
        its source directory; please exit the numpy source tree, and relaunch
        your python intepreter from there.

END RequestId: 6abd7ef6-b9de-11e5-8aee-918ac0a06113
REPORT RequestId: 6abd7ef6-b9de-11e5-8aee-918ac0a06113  Duration: 105.95 ms Billed Duration: 200 ms     Memory Size: 1536 MB    Max Memory Used: 14 MB

我也在关注你的第一个 link 并设法在 Lambda 中导入 numpypandas以这种方式运行(在 Windows 上):

  1. 使用 64 位 Amazon Linux AMI 2015.09.1 启动了 (free-tier) t2.micro EC2 instance 并使用Putty 到 SSH 中。
  2. 尝试了与您使用的相同命令以及亚马逊文章推荐的命令:

    sudo yum -y update
    sudo yum -y upgrade
    sudo yum -y groupinstall "Development Tools"
    sudo yum -y install blas --enablerepo=epel
    sudo yum -y install lapack --enablerepo=epel
    sudo yum -y install Cython --enablerepo=epel
    sudo yum install python27-devel python27-pip gcc
    
  3. 创建了虚拟环境:

    virtualenv ~/env
    source ~/env/bin/activate
    
  4. 安装了 软件包:

    sudo ~/env/bin/pip2.7 install numpy
    sudo ~/env/bin/pip2.7 install pandas
    
  5. 然后,我使用 WinSCP 登录并下载所有内容(_markerlib、pip*、pkg_resources、setuptools* 和 easyinstall* 除外)来自 /home/ec2-user/env/lib/python2.7/dist-packages,以及来自 /home/ec2-user/env/lib64/python2.7/site-packages 的所有内容来自 EC2 实例。

  6. 我将所有这些文件夹和文件与包含 Lambda 函数的 .py 文件一起放入一个 zip 中。 illustration of all files copied

  7. 因为这个 .zip 大于 10 MB,所以我创建了一个 S3 存储桶 来存储文件。我从那里复制了文件的 link 并粘贴到 Lambda 函数的 "Upload a .ZIP from Amazon S3"。

  8. EC2实例可以关闭,不再需要了。

有了这个,我可以导入 numpy 和 pandas。我不熟悉 moviepy,但 scipy 可能已经很棘手了,因为 Lambda 有一个 limit 解压缩部署包大小为 262 144 000 字节。恐怕 numpy 和 scipy 一起已经结束了。

在此线程中的所有帖子的帮助下,这里是记录的解决方案:

要使其正常工作,您需要:

  1. 用至少 2GO RAM 启动一个 EC2 实例(以便能够编译 NumPy & SciPy

  2. 安装所需的依赖项

    sudo yum -y update
    sudo yum -y upgrade
    sudo yum -y groupinstall "Development Tools"
    sudo yum -y install blas --enablerepo=epel
    sudo yum -y install lapack --enablerepo=epel
    sudo yum -y install Cython --enablerepo=epel
    sudo yum install python27-devel python27-pip gcc
    virtualenv ~/env
    source ~/env/bin/activate
    pip install scipy
    pip install numpy
    pip install moviepy
    
  3. stack 文件夹中目录(_markerlib、pip*、pkg_resources、setuptools* 和 easyinstall* 除外)的所有内容复制到您的语言环境机器:

    • home/ec2-user/env/lib/python2.7/dist-packages
    • home/ec2-user/env/lib64/python2.7/dist-packages
  4. 从您那里获取所有需要的共享库EC2实例:

    • libatlas.so.3
    • libf77blas.so.3
    • liblapack.so.3
    • libptf77blas.so.3
    • libcblas.so.3
    • libgfortran.so.3
    • libptcblas.so.3
    • libquadmath.so.0
  5. 将它们放在 stack 文件夹的 lib 子文件夹中

  6. imageiomoviepy 的依赖项,您需要下载其依赖项的一些二进制版本:libfreeimageffmpeg ;可以找到它们 here。将它们放在堆栈文件夹的根目录下,并将 libfreeimage-3.16.0-linux64.so 重命名为 libfreeimage.so

  7. 您现在应该有一个 stack 文件夹,其中包含:

    • 所有 python 根依赖关系
    • lib 子文件夹中的所有共享库
    • ffmpeg 根目录下的二进制文件
    • libfreeimage.so 在根目录
  8. 压缩此文件夹:zip -r9 stack.zip . -x ".*" -x "*/.*"

  9. 使用以下 lambda_function.py 作为您的 lambda

    的入口点
    from __future__ import print_function
    
    import os
    import subprocess
    
    SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
    LIB_DIR = os.path.join(SCRIPT_DIR, 'lib')
    FFMPEG_BINARY = os.path.join(SCRIPT_DIR, 'ffmpeg')
    
    
    def lambda_handler(event, context):
        command = 'LD_LIBRARY_PATH={} IMAGEIO_FFMPEG_EXE={} python movie_maker.py'.format(
            LIB_DIR,
            FFMPEG_BINARY,
        )
        try:
            output = subprocess.check_output(command, shell=True)
            print(output)
        except subprocess.CalledProcessError as e:
            print(e.output)
    
  10. 写一个 movie_maker.py 脚本依赖于 moviepy, numpy, ...

  11. 将这些脚本添加到您的 stack.zip 文件 zip -r9 lambda.zip *.py

  12. 将 zip 上传到 S3 并将其用作您的 lambda

  13. 的来源

您还可以下载 stack.zip here.

这里的帖子帮助我找到了一种使用可包含在 AWS Lambda 部署包中的库文件静态编译 NumPy 的方法。此解决方案不像@rouk1 解决方案那样依赖于 LD_LIBRARY_PATH 值。

编译好的NumPy库可以从https://github.com/vitolimandibhrata/aws-lambda-numpy

下载

这里是自定义编译NumPy的步骤

从头开始编译这个包的说明

使用 AWS Linux.

准备一个新的 AWS EC 实例

安装编译器依赖项

sudo yum -y install python-devel
sudo yum -y install gcc-c++
sudo yum -y install gcc-gfortran
sudo yum -y install libgfortran

安装 NumPy 依赖项

sudo yum -y install blas
sudo yum -y install lapack
sudo yum -y install atlas-sse3-devel

创建 /var/task/lib 以包含运行时库

mkdir -p /var/task/lib

/var/task 是您的代码将驻留在 AWS Lambda 中的根目录,因此我们需要将所需的库文件静态 link 在一个众所周知的文件夹中,在本例中为 /var/task/lib

将以下库文件复制到/var/task/lib

cp /usr/lib64/atlas-sse3/liblapack.so.3 /var/task/lib/.
cp /usr/lib64/atlas-sse3/libptf77blas.so.3 /var/task/lib/.
cp /usr/lib64/atlas-sse3/libf77blas.so.3 /var/task/lib/.
cp /usr/lib64/atlas-sse3/libptcblas.so.3 /var/task/lib/.
cp /usr/lib64/atlas-sse3/libcblas.so.3 /var/task/lib/.
cp /usr/lib64/atlas-sse3/libatlas.so.3 /var/task/lib/.
cp /usr/lib64/atlas-sse3/libptf77blas.so.3 /var/task/lib/.
cp /usr/lib64/libgfortran.so.3 /var/task/lib/.
cp /usr/lib64/libquadmath.so.0 /var/task/lib/.

http://sourceforge.net/projects/numpy/files/NumPy/

获取最新的numpy源代码

转到 numpy 源代码文件夹,例如 numpy-1.10.4 使用以下条目创建一个 site.cfg 文件

[atlas]
libraries=lapack,f77blas,cblas,atlas
search_static_first=true
runtime_library_dirs = /var/task/lib
extra_link_args = -lgfortran -lquadmath

-lgfortran -lquadmath 标志需要静态 link gfortran 和 quadmath 库以及 runtime_library_dirs

中定义的文件

构建 NumPy

python setup.py build

安装 NumPy

python setup.py install

检查库是否linked到/var/task/lib

中的文件
ldd $PYTHON_HOME/lib64/python2.7/site-packages/numpy/linalg/lapack_lite.so

你应该看看

linux-vdso.so.1 =>  (0x00007ffe0dd2d000)
liblapack.so.3 => /var/task/lib/liblapack.so.3 (0x00007ffad6be5000)
libptf77blas.so.3 => /var/task/lib/libptf77blas.so.3 (0x00007ffad69c7000)
libptcblas.so.3 => /var/task/lib/libptcblas.so.3 (0x00007ffad67a7000)
libatlas.so.3 => /var/task/lib/libatlas.so.3 (0x00007ffad6174000)
libf77blas.so.3 => /var/task/lib/libf77blas.so.3 (0x00007ffad5f56000)
libcblas.so.3 => /var/task/lib/libcblas.so.3 (0x00007ffad5d36000)
libpython2.7.so.1.0 => /usr/lib64/libpython2.7.so.1.0 (0x00007ffad596d000)
libgfortran.so.3 => /var/task/lib/libgfortran.so.3 (0x00007ffad5654000)
libm.so.6 => /lib64/libm.so.6 (0x00007ffad5352000)
libquadmath.so.0 => /var/task/lib/libquadmath.so.0 (0x00007ffad5117000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007ffad4f00000)
libc.so.6 => /lib64/libc.so.6 (0x00007ffad4b3e000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007ffad4922000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007ffad471d000)
libutil.so.1 => /lib64/libutil.so.1 (0x00007ffad451a000)
/lib64/ld-linux-x86-64.so.2 (0x000055cfc3ab8000)

我喜欢@Vito Limandibhrata 的回答,但我认为在 numpy==1.11.1 中使用 runtime_library_dirs 构建 numpy 是不够的。如果有人认为 site-cfg 被忽略,请执行以下操作:

cp /usr/lib64/atlas-sse3/*.a /var/task/lib/

*.a 需要atlas-sse3 下的文件来构建numpy。此外,您可能需要 运行 以下内容:

python setup.py config

检查 numpy 配置。如果需要更多信息,您将看到以下消息:

atlas_threads_info:
Setting PTATLAS=ATLAS   libraries ptf77blas,ptcblas,atlas not found in /root/Envs/skl/lib
    libraries lapack_atlas not found in /root/Envs/skl/lib
    libraries ptf77blas,ptcblas,atlas not found in /usr/local/lib64   
    libraries lapack_atlas not found in /usr/local/lib64
    libraries ptf77blas,ptcblas,atlas not found in /usr/local/lib         
    libraries lapack_atlas not found in /usr/local/lib
    libraries lapack_atlas not found in /usr/lib64/atlas-sse3
<class 'numpy.distutils.system_info.atlas_threads_info'>
Setting PTATLAS=ATLAS
Setting PTATLAS=ATLAS
Setting PTATLAS=ATLAS
Setting PTATLAS=ATLAS
    libraries lapack not found in ['/var/task/lib']
Runtime library lapack was not found. Ignoring
    libraries f77blas not found in ['/var/task/lib']
Runtime library f77blas was not found. Ignoring
    libraries cblas not found in ['/var/task/lib']
Runtime library cblas was not found. Ignoring
    libraries atlas not found in ['/var/task/lib']
Runtime library atlas was not found. Ignoring
    FOUND:
        extra_link_args = ['-lgfortran -lquadmath']
        define_macros = [('NO_ATLAS_INFO', -1)]
        language = f77
        libraries = ['lapack', 'ptf77blas', 'ptcblas', 'atlas', 'lapack', 'f77blas', 'cblas', 'atlas']
        library_dirs = ['/usr/lib64/atlas-sse3']
        include_dirs = ['/usr/include']

然后 site-cfg 将被忽略。

提示:如果使用pip构建numpy runtime_library_dirs,最好创建~/.numpy-site.cfg并添加以下内容:

[atlas]
libraries = lapack,f77blas,cblas,atlas
search_static_first = true
runtime_library_dirs = /var/task/lib
extra_link_args = -lgfortran -lquadmath

然后 numpy 识别 .numpy-site.cfg 文件。这是非常简单易行的方法。

另一种非常简单的方法是使用 LambCI 为模仿 Lambda 而制作的很棒的 docker 容器进行构建:https://github.com/lambci/docker-lambda

lambci/lambda:build 容器类似于 AWS Lambda,但增加了 mostly-complete 构建环境。要在其中启动 shell 会话:

docker run -v "$PWD":/var/task -it lambci/lambda:build bash

会话内部:

export share=/var/task
easy_install pip
pip install -t $share numpy

或者,使用 virtualenv:

export share=/var/task
export PS1="[\u@\h:\w]$ " # required by virtualenv
easy_install pip
pip install virtualenv
# ... make the venv, install numpy, and copy it to $share

稍后您可以使用 lambci/lambda 主容器来测试您的构建。

截至 2017 年,NumPy 和 SciPy 具有可在 Lambda 上运行的轮子(这些包包括预编译的 libgfortranlibopenblas)。 据我所知,MoviePy 是一个纯粹的 Python 模块,所以基本上你可以这样做:

pip2 install -t lambda moviepy scipy

然后将您的处理程序复制到 lambda 目录并压缩。除了,您很可能会超过 50/250 MB 的大小限制。有几件事可以提供帮助:

  • 删除.pycs、文档、测试和其他不需要的部分;
  • 保留 NumPy 和 SciPy 公共库的单个副本;
  • 剥离不必要的库,例如调试符号;
  • 使用更高的设置压缩存档。

这里有一个例子script,可以自动执行上述几点。

我可以确认@attila-tanyi 发布的步骤在 Amazon Linux 下可以正常工作。我只想补充一点,不需要使用 EC2,因为默认存储库中有一个 Amazon Linux docker 容器可用。

docker pull amazonlinux && docker run -it amazonlinux
# Follow @attila-tanyi steps
# Note - sudo is not necessary here

我使用应用程序中嵌入的 Dockerfile 来构建和部署到 Lambda。

截至 2018 年,在 AWS EC2 Python3 中安装外部模块的步骤:

  1. 在 Amazon Linux AMI 201709 上启动 EC2。

  2. 使用私钥和 public 密钥通过 putty ssh 并成为超级用户。

  3. 安装Python 3 并创建虚拟环境,然后将其设为默认值

    yum install python36 python36-virtualenv python36-pip
    
    virtualenv -p python3.6 /tmp/my_python_lib
    
    source /tmp/my_python_lib/bin/activate
    
    which python --to check which version s installed
    
    pip3 install  numpy
    
  4. 使用winscp将站点包和dist包下的文件复制到本地机器中。

    要查找实际位置,请使用 grep 命令 ---

      grep -r dist-packages *. 
    

这些包可能在 lib 和 lib64 中。

  1. 站点和 dist 包将位于以下位置:

    /tmp/my_python_lib/lib64/python3.6,
    /tmp/my_python_lib/lib/python3.6
    
  2. 将这些包与您的脚本文件一起压缩并上传到 S3,可以在压缩根文件夹的 lambda.Instead 中访问您必须 select 所有文件并压缩它或发送到压缩文件夹。

其他提示:

  1. 如果要将所有包安装在一个目录下,可以使用命令:

     pip install --upgrade --target=/tmp/my_python_lib/lib/python3.6/dist-packages pandas
    

截至 2018 年 8 月,最简单的方法可能是开始 new AWS Cloud9 environment。 然后在环境中创建一个 Lambda 函数。接下来运行这个进入Cloud9命令行:

    cd YourApplicationName
    /venv/bin/pip install scipy -t .
    /venv/bin/pip install numpy -t .
    /venv/bin/pip install moviepy -t .

现在我可以在 lambda_handler 函数中导入模块了。

2018 年 11 月。嗨,朋友们,这个 post 对我非常有帮助。但是,到目前为止,答案并不是很自动化。我在此处 https://gist.github.com/steinwaywhw/6a6a25d594cc07146c60af943f74c16f 编写了一个 Python 脚本和教程,以在 EC2 上使用 pipvirtualenv 自动创建已编译的 Python 包。一切都是 Python (Boto3),没有 bash 脚本,没有 Web 控制台,没有 awscli

除了自动化之外还有一个变化,我认为这是一个改进。我从 EC2 下载了整个 Python 虚拟环境,保留了它的文件夹结构,而不是将 liblib64 包合并在一起。我永远不明白合并这两个文件夹的预期含义。如果某些包覆盖了其他包怎么办,对吗?此外,伪造一个官方虚拟环境仍然比自己动手更安全。

为了使下载的虚拟环境正常工作,Lambda 函数的源代码添加了一些样板代码以使用 sys.path 更新 Python 搜索路径。 Python 虚拟环境的预期 sys.path 可以通过

找到
  • 在你自己的机器上,创建一个虚拟环境并激活它。
  • 运行 在此虚拟环境中执行 Python 脚本并在 import sys 之后执行 print(sys.path)。 您可以从那里开始并根据需要进行修改。

为了加载 numpy 和我打包的虚拟环境中的其他包,为 Lambda 函数添​​加的样板代码片段粘贴在下面。在我的例子中,我加载了依赖于 numpypandas_datareader

import os
import sys 

# https://docs.aws.amazon.com/lambda/latest/dg/current-supported-versions.html
workdir = os.getenv('LAMBDA_TASK_ROOT')
version = f'{sys.version_info[0]}.{sys.version_info[1]}'
additionals = [f'{workdir}/venv/lib64/python{version}/site-packages',
               f'{workdir}/venv/lib64/python{version}/lib-dynload',
               f'{workdir}/venv/lib64/python{version}/dist-packages',
               f'{workdir}/venv/lib/python{version}/dist-packages',
               f'{workdir}/venv/lib/python{version}/site-packages']
sys.path = additionals + sys.path

import pandas_datareader as pdr

您可以使用 scipy、numpy、moviepy 和 pandas 在任何 OS 上为 lambda 创建 zip 文件。

https://pypi.org/project/scipy/#files

pypi 有不同 OS 的 wheel 文件,你可以下载 manylinux whl 文件并解压。之后删除 dist-info 和 pyc 文件并全部压缩。 然后可以将最终的 zip 文件上传到 S3 并转换为 lambda 层。

This教程有助于深入理解