首先,看一段代码,只有几行Python语句却完成了AI翻译的功能。
#!/usr/bin/python3
import sys
from transformers import MarianMTModel, MarianTokenizer
def translate(word_list):
model_name = "Helsinki-NLP/opus-mt-en-zh"
tokenizer = MarianTokenizer.from_pretrained(model_name)
model = MarianMTModel.from_pretrained(model_name)
translated = model.generate(**tokenizer(word_list, return_tensors="pt", padding=True))
for res in [tokenizer.decode(t, skip_special_tokens=True) for t in translated]:
print(res)
if __name__ == "__main__":
translate(sys.argv[1:])
这里可以看到,只要调用这个tranlate
函数,向它传递一个英语词汇的list,就能返回一个翻译好的中文词汇列表。这里的词汇指的是单词、词组或句子。
不过这个函数有个问题,就是运行起来比较慢。因为它需要加载 tokenizer 和 model. 这最快也要5-6秒;如果这个程序是跑在docker里面,就更慢了,可能要十几甚至几十秒。
(这些tokenizer和model可以由pip install得到,这个在后面再详细介绍。)
所以,总不能每次翻译都要把tokenizer和model都加载一遍。解决的办法也有多种。比如写一个类,在类的实例初始化的时候就把这些加载好,后面调translate函数的时候自然就快了。不过这篇博文里想介绍的方法是,利用一个Python的轻量级的web框架来提供一个Http的服务,从而可以向这个Http服务提出REST请求以获得翻译服务。
写Python应用程序的第一步总是建立virtualenv环境,为了避免和本地系统的Python库冲突的情况。
运行以下命令
virtualenv FlaskServer
cd FlaskServer
source bin/activate
注意,本博文的程序基于Linux系统运行。如果在Windows上,则以上的激活命令是不同的。
另外,如果没有安装 virtualenv, 则需要运行pip3 install virtualenv
命令进行安装。
第二步就是在virtualenv环境下安装必要的library了。
这里需要的库包括翻译模型相关的库以及Flask.
pip install transformers sentencepiece sacremoses
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu
pip install Flask
我们希望一次能翻译多个单词或词组或句子。那么就需要向翻译服务提供一个list;相应的,翻译之后,也就会返回一个list.
例子如下:
POST /translate
# request body example
{
"target_words": ["Hello, what's you name", "I am good", "How are you"]
}
# response example
{
"translated_words": ["xx", "xxx", "xx"]
}
Flask是一个轻量级的框架。我们只需要撰写很少的代码,即可实现以上的POST请求的backend处理部分。
具体代码如下,假设Python文件名为 hello.py
#!/usr/bin/python3
# Run: flask run -h -p 7979
from flask import Flask, request
from transformers import MarianMTModel, MarianTokenizer
app = Flask(__name__)
model_name = "Helsinki-NLP/opus-mt-en-zh"
tokenizer = MarianTokenizer.from_pretrained(model_name)
model = MarianMTModel.from_pretrained(model_name)
@app.route("/")
def hello_world():
return "Hello, World!
"
@app.post("/translate")
def translate():
data = request.get_json()
word_list = data.get('target_words')
translated = model.generate(**tokenizer(word_list, return_tensors="pt", padding=True))
key = 'translated_words'
result = {
key: [tokenizer.decode(t, skip_special_tokens=True) for t in translated]
}
print(result)
return result
if __name__ == '__main__':
app.run(host='10.111.222.111',port=7979,debug=True)
从以上代码可以看出,我们在http服务器启动的时候加载了tokenizer和model,而将来接收到 POST /translate
请求的时候,translate()函数里的翻译动作的耗时就很短了。
这一步仍是在virtualenv环境下,运行以下命令
export FLASK_APP=hello.py
export FLASK_ENV=development
flask run -h 10.111.222.111 -p 7979
如果对以上命令不熟悉或容易遗忘,可以查看 flask --help
和 flask run --help
以获得帮助。
这里指定 7979 端口号,是为了避免机器上有其他程序已经占用了Flask的默认端口5000.
至此,我们的翻译服务已经提供好了,下面就是对它进行测试了。
运行以下命令
curl -X POST "http://10.111.222.111:7979/translate" -H "Content-Type: application/json" -d'{"target_words": ["clean", "how are you"]}' | jq
注意,这里必须使用 jq
程序帮助解析。如果不使用jq,则cURL返回的response的内容会直接显示为像 “\u6d01” 这样的字符串形式,并不会将其按照UTF-解码。
下面是实际的执行效果。
curl -X POST "http://10.111.222.111:7979/translate" -H "Content-Type: application/json; charset=UTF-8" -d'{"target_words": ["clean", "how are you"]}' | jq
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 121 100 79 100 42 121 64 --:--:-- --:--:-- --:--:-- 186
{
"translated_words": [
"清洁",
"你好吗?"
]
}
实测结果,响应速度非常之快,即使包括网络延迟,也不到1秒。
(END)