Сериализация / десериализация tfidf-vectorizer с пользовательским токенизатором в AWS - PullRequest
0 голосов
/ 25 июня 2018

Доброе утро!

В настоящее время я работаю с TfidfVectorizer от sklearn и настроенным токенизатором. Идея состоит в том, чтобы создать маринованный TfidfVectorizer и загрузить этот векторизатор в лямбда-функцию AWS, которая преобразует ввод текста.

Проблема в том, что на моей локальной машине все работает нормально: я могу загрузить векторизатор из S3-корзины, десериализовать его, создать новый объект-векторизатор и использовать его для преобразования текста. На AWS это не работает. Кажется, что он не может загрузить мой настроенный токенизатор, я всегда получаю AttributeError.

Я уже пробовал использовать лямбда-функцию и инструмент для укропа, но он также не работает на AWS. Не удается найти модуль PorterStemmer, который я использую в своем настроенном токенизаторе.

Сериализованный TfidfVectorizer (я сериализировал его на моей локальной машине):

import pickle
from sklearn.feature_extraction.text import TfidfVectorizer
from nltk.stem.porter import PorterStemmer

def tokenizer_porter(text):
    porter = PorterStemmer()
    return [porter.stem(word) for word in text.split()]

tfidf = TfidfVectorizer(ngram_range=(1, 1), stop_words=None, tokenizer=tokenizer_porter)

tfidf.fit(X)

pickle.dump(tfidf, open(pickle_path + 'tfidf_vect.pkl', 'wb'), protocol=4)

Десериализация (в лямбда-сервисе AWS):

def tokenizer_porter(text):
    porter = PorterStemmer()
    return [porter.stem(word) for word in text.split()]

def load_model_from_bucket(key, bucket_name):
    s3 = boto3.resource('s3')
    complete_key = 'serialized_models/' + key
    res = s3.meta.client.get_object(Bucket=bucket_name, Key=complete_key)
    model_str = res['Body'].read()
    model = pickle.loads(model_str)
    return model

tfidf = load_model_from_bucket('tfidf_vect.pkl', bucket_name)

tfidf.transform(text_data)

В AWS Cloudwatch я получаю эту трассировку:

Can't get attribute 'tokenizer_porter' on <module '__main__' from '/var/runtime/awslambda/bootstrap.py'>: AttributeError
Traceback (most recent call last):
File "/var/task/handler.py", line 56, in index
tfidf = load_model_from_bucket('tfidf_vect.pkl', bucket_name)
File "/var/task/handler.py", line 35, in load_model_from_bucket
model = pickle.loads(model_str)
AttributeError: Can't get attribute 'tokenizer_porter' on <module '__main__' from '/var/runtime/awslambda/bootstrap.py'>

У вас есть идеи, что я делаю неправильно?

РЕДАКТИРОВАТЬ: я решил выполнить tfidf-векторизацию в лямбда-скрипте AWS без использования pickle-сериализации, которая немного дороже в вычислительном отношении, но работает без проблем.

1 Ответ

0 голосов
/ 06 октября 2018

Я нашел решение, которое работало для моего приложения Heroku на основе этих двух ссылок:

AttributeError при чтении файла рассола

Не удалось найти объект приложения 'server' в 'app'

По сути, для двух моих рассолов (file1.pickle и file2.pickle) я изменил способ чтения файлов, добавив следующее:

class MyCustomUnpickler(pickle.Unpickler):
    def find_class(self, module, name):
        if module == "__main__":
            module = "app"
        return super().find_class(module, name)

with open('file1.pickle', 'rb') as f:
    unpickler = MyCustomUnpickler(f)
    object1 = unpickler.load()

with open('file2.pickle', 'rb') as f:
    unpickler = MyCustomUnpickler(f)
    object2 = unpickler.load()

А также добавил это после app = dash.Dash(__name__):

server = app.server

Более подробные пояснения по ссылкам выше.

...