Уменьшение размера scipy и numpy для развертывания лямбда aws

Я пытаюсь развернуть приложение Python на aws lambda. Он имеет несколько больших зависимостей Python, самые большие из которых - scipy и numpy. В результате размер моего приложения значительно превышает разрешенные 250 МБ.

Пытаясь найти способ уменьшить размер, я наткнулся на подход, подробно описанный здесь:

https://github.com/szelenka/shrink-linalg

По сути, при установке с использованием pip во время компиляции scipy & numpy cython флаги могут быть переданы компилятору c, который оставит отладочную информацию в скомпилированных двоичных файлах c. В результате scipy и numpy уменьшаются примерно до 50% от исходного размера. Я смог запустить это локально (ubuntu 16.04) и без проблем создал двоичные файлы. Используемая команда была:

CFLAGS = "-g0 -I/usr/include:/usr/local/include -L/usr/lib:/usr/local/lib" pip install numpy scipy --compile --no-cache-dir --global-option=build_ext --global-option = "-j 4"

Проблема в том, что для работы с лямбда-выражением aws двоичные файлы должны быть скомпилированы в среде, аналогичной той, в которой выполняется лямбда-выражение. Изображение окружающей среды можно найти здесь:

https://docs.aws.amazon.com/lambda/latest/dg/current-supported-versions.html

После загрузки образа в экземпляр ec2 я попытался запустить ту же установку pip после установки нескольких зависимостей.

sudo yum install python36 python3-devel blas-devel atlas atlas-devel lapack-devel atlas-sse3-devel gcc gcc-64 gcc-gfortran gcc64-gfortran libgfortran, gcc-c++ openblas-devel python36-virtualenv

Numpy компилируется нормально, но scipy - нет. Cython не вызывает никаких проблем, но компиляция fortran вызывает. Я получаю следующую ошибку:

error: Command "/usr/bin/gfortran -Wall -g -Wall -g -shared build/temp.linux-x86_64-3.6/build/src.linux-x86_64-3.6/scipy/integrate/_test_odeint_bandedmodule.o build/temp.linux-x86_64-3.6/build/src.linux-x86_64-3.6/build/src.linux-x86_64-3.6/scipy/integrate/fortranobject.o build/temp.linux-x86_64-3.6/scipy/integrate/tests/banded5x5.o build/temp.linux-x86_64-3.6/build/src.linux-x86_64-3.6/scipy/integrate/_test_odeint_banded-f2pywrappers.o -L/usr/lib64/atlas -L/usr/lib/gcc/x86_64-amazon-linux/6.4.1 -L/usr/lib/gcc/x86_64-amazon-linux/6.4.1 -L/usr/lib64 -Lbuild/temp.linux-x86_64-3.6 -llsoda -lmach -llapack -lptf77blas -lptcblas -latlas -lptf77blas -lptcblas -lpython3.6m -lgfortran -o build/lib.linux-x86_64-3.6/scipy/integrate/_test_odeint_banded.cpython-36m-x86_64-linux-gnu.so -Wl,--version-script=build/temp.linux-x86_64-3.6/link-version-scipy.integrate._test_odeint_banded.map" failed with exit status 1

Я попытался переустановить gfortran, а также всю коллекцию gcc, но безуспешно. К сожалению, у меня очень ограниченный опыт работы с компиляторами fortran. Если у кого-то есть идеи или скомпилированная версия двоичных файлов c, я был бы весьма признателен.

Это последняя (и наименее информативная) строка сообщения об ошибке ... То, что она сообщает вам первой, вероятно, более полезно.

DavidW 13.11.2018 08:10

К сожалению нет. Отслеживание Пипа не очень помогает. Перед этим он просто показывает все, что успешно скомпилировано.

joek575 13.11.2018 08:17

Возможно, вы сможете запустить pip в подробном режиме. Почти наверняка информации больше (даже если она от вас скрыта)

DavidW 13.11.2018 09:26

Или, если подробный режим недоступен, где-то должен быть какой-то файл журнала.

Vladimir F 13.11.2018 11:06

Я делаю аналогичные вещи в DOCKER, есть образ докера для amazon-linux, и с небольшим монтажом взад и вперед вы можете создать достойный процесс сборки

Jan Zyka 17.04.2020 14:53
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
13
5
3 245
4

Ответы 4

Итак, я решил это, хотя и довольно хакерским способом.

Флаги, которые я передавал в pip, были предназначены для уменьшения размера зависимостей c, а не зависимостей fortran. Так что действительно не было проблем с использованием предварительно скомпилированных зависимостей fortran, которые обычно загружаются через pip.

Итак, сначала я создал эталонную версию неизмененного пакета scipy в папке sp:

pip install scipy -t sp

Затем я создал программу go, которая действует как оболочка для компилятора gfortran (или технически вокруг ссылки на компилятор gfortran в / usr / bin)

package main

import "os"
import "strings"
import "io/ioutil"
import "log"
import "os/exec"
import "fmt"


func checkErr(err error) {
    if err != nil {
        log.Fatal(err)
    }
}


func exists(path string) (bool, error) {
    _, err := os.Stat(path)
    if err == nil { return true, nil }
    if os.IsNotExist(err) { return false, nil }
    return true, err
}


func copyr(src string, dst string) {
    // Read all content of src to data
    data, err := ioutil.ReadFile(src)
    checkErr(err)
    // Write data to dst
    err = ioutil.WriteFile(dst, data, 0644)
    checkErr(err)
}


func main() {

    search_folder := "/home/ec2-user/sp/scipy"
    wrapped_compiler := "/usr/bin/inner_gfortran"
    argsWithProg := os.Args
    noProg := os.Args[1:]
    primed := 0
    check := "-o"
    var (
        cmdOut []byte
        err    error
    )
    for _, el := range argsWithProg {
        if primed == 1{
            primed = 0
            s := strings.Split(el, "scipy")
            if len(s) != 2{
                continue
            }
            src := search_folder + s[1]
            src_exi, _ := exists(src)
            if src_exi == false {
                continue
            }
            primed = 2
            dir_parts := strings.Split(el, "/")
            dir_parts = dir_parts[:len(dir_parts)-1]
            dir := strings.Join(dir_parts,"/")
            exi, _ := exists(dir)
            if exi == false {
                os.MkdirAll(dir, os.ModePerm)
            }
            os.Create(el)
            copyr(src, el)

        }
        if el == check{
            primed = 1
        }
    }
    if primed == 0 {
        if cmdOut, err = exec.Command(wrapped_compiler, noProg...).Output(); err != nil {
            fmt.Fprintln(os.Stderr, "There was an error running fortran compiler: ", err)
            os.Exit(1)
        }
        os.Stdout.Write(cmdOut)
    }

}

Фактический компилятор перемещен в inner_gfortran

sudo mv /usr/bin/gfortran /usr/bin/inner_gfortran

И положите обертку на свое место

Оболочка передаст большинство инструкций компилятору, но если инструкция состоит в том, чтобы скомпилировать программу fortran в scipy, а скомпилированный двоичный файл уже существует в моей справочной версии scipy, оболочка просто копирует справочную версию в новую компилируемую версию. .

И это сделало это. Версии scipy и numpy уменьшенного размера теперь работают с aws lambda для python 3.6.

Я знаю, что вы давно не задавали этот вопрос, но, возможно, это поможет кому-то другому.

вы можете использовать лямбда-подобный контейнер докеров для компиляции ресурсов, а затем скопировать библиотеки обратно в среду разработки. использовать эти скомпилированные файлы в качестве лямбда-ресурсов

Эта статья мне очень помогла: https://medium.com/@mohd.lutfalla/how-to-compile-resources-for-aws-lambda-f46fadc03290

Использование пакета serverless-python-requirements на Бессерверный помогло мне упростить весь этот процесс, а также уменьшить размер пакета. Определенно рекомендую проверить это.

Это руководство, которому я следовал

Плагин бессерверных требований Python

Обязательно оставьте флаг strip для false, чтобы избежать удаления двоичных файлов, что приводит к проблеме «Адрес / смещение команды загрузки ELF неправильно выровнены»,

Это то, чем оказался мой последний serverless.yml, который дал мне результаты, которые я хотел упаковать sklearn + cv2 как слой:

custom:
  pythonRequirements:
    dockerizePip: true
    useDownloadCache: true
    useStaticCache: false
    slim: true
    strip: false
    layer:
      name: ${self:provider.stage}-cv2-sklearn
      description: Python requirements lambda layer
      compatibleRuntimes:
        - python3.8
      allowedAccounts:
        - '*'

Я знаю, что это довольно старый вопрос, но теперь AWS Lambda позволяет запускать функции из образа Docker, хранящегося в ECR. Размер образа Docker может достигать 10 ГБ.

https://aws.amazon.com/fr/blogs/aws/new-for-aws-lambda-container-image-support/

Другие вопросы по теме