Бессерверное NLP с использованием spaCy и AWS Lambda
spaCy - полезный инструмент, который позволяет нам выполнять множество задач обработки естественного языка. При интеграции spaCy в существующее приложение его удобно предоставить как API с помощью AWS Lambda и API Gateway. Однако из-за ограничений Lambda сложно развернуть большие модели.
В этой статье я покажу вам, как развернуть spaCy с помощью недавно выпущенной функции для монтирования эластичной файловой системы (EFS) на AWS Lambda. Используя эту функцию, мы можем сохранить модель большого размера в EFS и загрузить ее из лямбда-функций. В частности, можно загружать данные, размер которых превышает доступное пространство в Lambda’s/tmp
(512 МБ).
Общая архитектура выглядит следующим образом. Lambda загружает пакет spaCy на Lambda Layers. EFS хранит модели spaCy. Затем Lambda загружает модели из EFS. Для резервирования четыре подсети размещены в двух разных зонах доступности.
Требования:
- Докер
- AWS CLI
Создание VPC и подсетей
Прежде всего, мы должны настроить VPC, который может достигать целей монтирования EFS. Здесь мы создаем VPC, интернет-шлюз, два шлюза NAT и четыре подсети (две общедоступные, две частные).
В консоли VPC я выбираю Создать VPC и устанавливаю Тег имени и блок IPv4 CIDR следующим образом:
На следующем этапе я создаю интернет-шлюз для подключения к Интернету из VPC со следующими настройками. После этого прикрепляю к созданному VPC.
На следующем этапе я создаю четыре подсети (public-spacy-1, public-spacy-2, private-spacy-1, private-spacy-2) со следующими настройками. Обратите внимание, что public-spacy-1 и private-spacy-1 имеют одинаковую зону доступности.
Затем я создаю два шлюза NAT и присоединяю их к общедоступным подсетям для доступа в Интернет с помощью лямбда-функции в частной подсети. Я дал имена шлюзов NAT: NAT spaCy 1 и NAT spaCy 2.
Наконец, я создаю таблицы маршрутов. Для общедоступных подсетей я добавляю пункт назначения 0.0.0.0/0 и целевой Интернет-шлюз для доступа в Интернет. Для частных подсетей я добавляю пункт назначения 0.0.0.0/0 и целевой NAT spaCy 1 для private-spacy-1 и NAT spaCy 2 для private-spacy-2.
Создание эластичной файловой системы
В консоли EFS я выбираю Создать файловую систему и убеждаюсь, что выбраны VPC по умолчанию и его подсети. Для всех подсетей я использую группу безопасности, которая разрешает сетевой доступ к другим ресурсам в VPC. Для простоты я создал группу безопасности, которая разрешает весь трафик.
На следующем шаге я присваиваю файловой системе тег Name и выбираю Next Step.
Затем я выбираю Добавить точку доступа. Я использую 1001
для User ID, Group ID, Owner User ID and Owner Group ID
и 750
для разрешений. Также я ограничиваю доступ к пути /models
.
Создание EFS завершено. Перейдем к следующему шагу.
Публикация spaCy в лямбда-слоях
На следующем этапе мы публикуем spaCy как Lambda Layers. Мы должны сделать следующее:
- Установить spaCy
- Сжать как Zip-файл
- Опубликуйте файл в Lambda Layer
Для простоты я подготовил следующий сценарий оболочки:
Вам нужно только выполнить это как sh publish_spacy_as_lambda_layer.sh
.
Создание лямбда-функции
Затем мы создаем лямбда-функцию. В консоли Lambda создайте функцию и выберите Python 3.7 в качестве среды выполнения. Для разрешений выберите роль, к которой прикреплены политикиAWSLambdaVPCAccessExecutionRole
и AmazonElasticFileSystemClientReadWriteAccess
.
После создания функции мы настраиваем конфигурацию VPC. Здесь нам нужно указать ту же группу безопасности и VPC, которые мы указали для точек монтирования EFS, и выбрать частные подсети.
Затем мы выбираем Добавить файловую систему. Мы выбираем ESF и точку доступа, которая была создана ранее. Здесь мы устанавливаем /mnt/models
как локальную точку монтирования. Это путь, по которому смонтирована точка доступа, он соответствует каталогу /models
в EFS.
В разделе слоев мы выбираем Добавить слой, чтобы добавить spaCy.
В редакторе функций скопируйте и вставьте следующий код.
Наконец, мы должны увеличить выделение памяти и значения тайм-аута. Если выделенная память недостаточно велика, произойдет следующая ошибка.
{ "errorType": "Runtime.ExitError", "errorMessage": "RequestId: Error: Runtime exited with error: signal: killed" }
В качестве теста, когда я тестирую с данными {"text": "He works at Google."}
, будет возвращен следующий ответ.
[ { "text": "Google", "label": "ORG", "start": 12, "end": 18 } ]