python - 在 AWS 上使用自定义标记器序列化/反序列化 tfidf-vectorizer
问题描述
早上好!
我目前正在使用来自 sklearn 的 TfidfVectorizer 和自定义标记器。这个想法是创建一个腌制的 TfidfVectorizer 并将这个矢量化器加载到一个 AWS Lambda 函数中,该函数可以转换文本输入。
问题是:在我的本地机器上它工作正常:我能够从 S3 存储桶加载矢量化器,反序列化它,创建一个新的矢量化器对象并使用它来转换文本。在 AWS 上它不起作用。似乎它无法加载我自定义的标记器,我总是得到一个 AttributeError。
我已经尝试过使用 lambda 函数和 dill-pickler,但它也不适用于 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 Lambda 服务中):
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 中,我得到了这个 Traceback:
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'>
你有什么想法我做错了吗?
编辑:我选择在 AWS Lambda-skript 中进行 tfidf-vectorization,而不使用 pickle-serialization,这在计算上有点昂贵,但它可以正常工作而不会引起问题。
解决方案
根据这两个参考资料,我找到了适用于我的 Heroku 应用程序的解决方案:
基本上,对于我的两个泡菜(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
上面的链接有更详细的解释。
推荐阅读
- pytorch - pytorch 数据集和可变大小的数据加载器
- html - 图片未在 HTML 中显示,错误 404 但路径正确
- discord.py - 使用 Discord PY 在嵌入消息中显示表格
- python - Gurobi:获取约束的 LHS(左侧)
- sql - 在同一个表中用另一个值填充空值
- .net - Owin OpenIddict 授权码对于 URL 来说太长了
- swiftui - SwiftUI,关于结束的通知,取消拖拽操作
- python - 从本地 R 会话将数据帧写入 AWS 上的 csv,生成 cp1252 编码
- python - 从数组中删除与另一个数组的特定元素相对应的值
- javascript - 如何使用 TypeScript 中 React useState 中的新值更新数组中对象中键的值