Бессерверное 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
  }
]

использованная литература