当前位置:   article > 正文

Modelscope 翻译模型 CSANMT(en2zh)本地部署_model="damo/nlp_csanmt_translation_en2zh

model="damo/nlp_csanmt_translation_en2zh

Modelscope 翻译模型 CSANMT(en2zh)本地部署

1. 环境配置

  • 模型介绍:
https://modelscope.cn/models/damo/nlp_csanmt_translation_en2zh/summary
  • 1
  • 文件导出文档:
https://modelscope.cn/docs/%E6%A8%A1%E5%9E%8B%E7%9A%84%E5%AF%BC%E5%87%BA
  • 1

根据官网上的信息进行环境配置,我在这块吃了很多亏,特别是docker镜像,不知道为什么我在镜像中就是不好用。本地需要装的包主要有三个:

这是我最终跑通的包的版本:

python                    3.8.18 
tensorflow                2.13.0
pytorch                   2.1.0           py3.8_cuda12.1_cudnn8.9.2_0    pytorch
modelscope                1.9.5                    pypi_0    pypi
  • 1
  • 2
  • 3
  • 4

其它的包可能会缺失一些,但是缺啥就pip install 啥就好,无关痛痒的问题。

也可以尝试一下使用docker(但是我失败了):

docker pull registry.cn-beijing.aliyuncs.com/modelscope-repo/modelscope:ubuntu20.04-py38-torch2.0.1-tf2.13.0-1.9.5
  • 1

2. 模型下载

这个有些坑,官方的模型下载这个代码很难找,希望以后文档慢慢变得更加友好吧:

from modelscope import snapshot_download
model_dir = snapshot_download("damo/nlp_csanmt_translation_en2zh", revision = "v1.0.1",cache_dir="./model")
  • 1
  • 2

就使用这两行代码就可以将模型下载到当前位置。

3. 模型转换

下面的是官方示例的转换代码,会将模型转换为SavedModel 格式:

from modelscope.models import Model
model_id = 'damo/nlp_csanmt_translation_en2zh'
model = Model.from_pretrained(model_id)
from modelscope.exporters import TfModelExporter
output_files = TfModelExporter.from_model(model).export_saved_model(output_dir='./CSANMT')
print(output_files) # {'model': '/tmp'}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

4. 本地翻译测试

这里有个很坑的地方,官方提供了SavedModel 格式的模型的转换和调用代码,但是它的输入和输出都是编码的数组,并没有提供如何将输入的文本编码以及将输出内容解码的代码,我是通过看pipeline源码,仿造他们的preprocess和postprocess写的:

  • 需要导入的包
import tensorflow as tf
from modelscope.models.base import Model
from modelscope.utils.constant import ModelFile, Tasks
from modelscope.utils.config import Config
from sacremoses import MosesDetokenizer, MosesPunctNormalizer, MosesTokenizer
from subword_nmt import apply_bpe
from modelscope.outputs import OutputKeys
import numpy as np
import time

if tf.__version__ >= '2.0':
    tf = tf.compat.v1
    tf.disable_eager_execution()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 读取配置文件和中英字典(这些文件需要再模型下载中获得):
cfg_dir = "./model/damo/nlp_csanmt_translation_en2zh/configuration.json"
cfg = Config.from_file(cfg_dir)

src_vocab_dir = "./model/damo/nlp_csanmt_translation_en2zh/src_vocab.txt"
# _src_vocab 是一个字典,key是英文src_vocab.txt中的一行,value是index,length = 49998, _trg_rvocab同理
_src_vocab = dict([
            (w.strip(), i) for i, w in enumerate(open(src_vocab_dir))
        ])

trg_vocab_dir = "./model/damo/nlp_csanmt_translation_en2zh/trg_vocab.txt"
_trg_rvocab = dict([
            (i, w.strip()) for i, w in enumerate(open(trg_vocab_dir))
        ])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 输入输出配置
input_wids = tf.placeholder(
            dtype=tf.int64, shape=[None, None], name='input_wids')
output = {}

_src_lang = cfg['preprocessor']['src_lang'] #en
_tgt_lang = cfg['preprocessor']['tgt_lang'] #zh

_src_bpe_path = "./model/damo/nlp_csanmt_translation_en2zh/bpe.en"

_punct_normalizer = MosesPunctNormalizer(lang=_src_lang)
_tok = MosesTokenizer(lang=_src_lang)
_detok = MosesDetokenizer(lang=_tgt_lang)
_bpe = apply_bpe.BPE(open(_src_bpe_path))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 文本encode:
input = ["How are you?", "OK, I am fine. Thank you! And you?", "Do you know where you are?", "Mr.Zhang test firstly!"]

input = [_punct_normalizer.normalize(item) for item in input]

aggressive_dash_splits = True

if (_src_lang in ['es', 'fr'] and _tgt_lang == 'en') or (_src_lang == 'en' and _tgt_lang in ['es', 'fr']):
    aggressive_dash_splits = False

input_tok = [
                _tok.tokenize(
                    item,
                    return_str=True,
                    aggressive_dash_splits=aggressive_dash_splits)
                for item in input
            ]
input_bpe = [
            _bpe.process_line(item).strip().split() for item in input_tok
        ]

MAX_LENGTH = max([len(item) for item in input_bpe])#200

input_ids = np.array([[
            _src_vocab[w] if w in _src_vocab else
            cfg['model']['src_vocab_size'] - 1 for w in item
        ] + [0] * (MAX_LENGTH - len(item)) for item in input_bpe])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 模型配置、读取、调用:
tf_config = tf.ConfigProto(allow_soft_placement=True)

sess = tf.Session(graph=tf.Graph(), config=tf_config)
# Restore model from the saved_modle file, that is exported by TensorFlow estimator.
MetaGraphDef = tf.saved_model.loader.load(sess, ['serve'], './CSANMT')

# SignatureDef protobuf
SignatureDef_map = MetaGraphDef.signature_def
SignatureDef = SignatureDef_map['translation_signature']
# TensorInfo protobuf
X_TensorInfo = SignatureDef.inputs['input_wids']
y_TensorInfo = SignatureDef.outputs['output_seqs']
X = tf.saved_model.utils.get_tensor_from_tensor_info(
    X_TensorInfo, sess.graph)
y = tf.saved_model.utils.get_tensor_from_tensor_info(
    y_TensorInfo, sess.graph)
sttime = time.time()
outputs = sess.run(y, feed_dict={X: input_ids})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • decode
x, y, z = outputs.shape

translation_out = []
for i in range(x):
    output_seqs = outputs[i]
    wids = list(output_seqs[0]) + [0]
    wids = wids[:wids.index(0)]
    translation = ' '.join([
        _trg_rvocab[wid] if wid in _trg_rvocab else '<unk>'
        for wid in wids
    ]).replace('@@ ', '').replace('@@', '')
    translation_out.append(_detok.detokenize(translation.split()))
translation_out = '<SENT_SPLIT>'.join(translation_out)
result = {OutputKeys.TRANSLATION: translation_out}
endtime = time.time()
print(result)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

以上就是一整套本地调用翻译的全部流程,将它们按顺序放在一整个脚本中就可以顺利翻译了。

5. 部署(Flask)

import tensorflow as tf
from modelscope.models.base import Model
from modelscope.utils.constant import ModelFile, Tasks
from modelscope.utils.config import Config
from sacremoses import MosesDetokenizer, MosesPunctNormalizer, MosesTokenizer
from subword_nmt import apply_bpe
from modelscope.outputs import OutputKeys
import numpy as np
from loguru import logger
from flask import Flask, request

if tf.__version__ >= '2.0':
    tf = tf.compat.v1
    tf.disable_eager_execution()

app = Flask(__name__)
def load_model():
    cfg_dir = "./model/damo/nlp_csanmt_translation_en2zh/configuration.json"
    cfg = Config.from_file(cfg_dir)
    # model = tf.saved_model.load("/path/to/your/exported/model")
    src_vocab_dir = "/home/sc/vscode/trans/model/damo/nlp_csanmt_translation_en2zh/src_vocab.txt"
    # _src_vocab 是一个字典,key是英文src_vocab.txt中的一行,value是index,length = 49998, _trg_vocab同理

    global _src_vocab, _trg_vocab
    _src_vocab = dict([
                (w.strip(), i) for i, w in enumerate(open(src_vocab_dir))
            ])
    trg_vocab_dir = "/home/sc/vscode/trans/model/damo/nlp_csanmt_translation_en2zh/trg_vocab.txt"
    _trg_vocab = dict([
                (i, w.strip()) for i, w in enumerate(open(trg_vocab_dir))
            ])

    global _src_lang, _tgt_lang
    _src_lang = cfg['preprocessor']['src_lang'] #en
    _tgt_lang = cfg['preprocessor']['tgt_lang'] #zh

    _src_bpe_path = "/home/sc/vscode/trans/model/damo/nlp_csanmt_translation_en2zh/bpe.en"
    global _punct_normalizer, _tok, _detok, _bpe

    _punct_normalizer = MosesPunctNormalizer(lang=_src_lang)
    _tok = MosesTokenizer(lang=_src_lang)
    _detok = MosesDetokenizer(lang=_tgt_lang)
    _bpe = apply_bpe.BPE(open(_src_bpe_path))

    
    global sess
    tf_config = tf.ConfigProto(allow_soft_placement=True)
    sess = tf.Session(graph=tf.Graph(), config=tf_config)
    MetaGraphDef = tf.saved_model.loader.load(sess, ['serve'], '/home/sc/vscode/trans/CSANMT')

    SignatureDef_map = MetaGraphDef.signature_def
    SignatureDef = SignatureDef_map['translation_signature']
    X_TensorInfo = SignatureDef.inputs['input_wids']
    y_TensorInfo = SignatureDef.outputs['output_seqs']
    global X, y
    X = tf.saved_model.utils.get_tensor_from_tensor_info(X_TensorInfo, sess.graph)
    y = tf.saved_model.utils.get_tensor_from_tensor_info(y_TensorInfo, sess.graph)

    
    # return sess

def preprocess_input(data):
    input = [_punct_normalizer.normalize(item) for item in data]

    aggressive_dash_splits = True
    if (_src_lang in ['es', 'fr'] and _tgt_lang == 'en') or (_src_lang == 'en' and _tgt_lang in ['es', 'fr']):
        aggressive_dash_splits = False
    
    input_tok = [
                _tok.tokenize(
                    item,
                    return_str=True,
                    aggressive_dash_splits=aggressive_dash_splits)
                for item in input
            ]
    input_bpe = [
            _bpe.process_line(item).strip().split() for item in input_tok
        ]
    MAX_LENGTH = max([len(item) for item in input_bpe])

    input_ids = np.array([[
            _src_vocab[w] if w in _src_vocab else
            cfg['model']['src_vocab_size'] - 1 for w in item
        ] + [0] * (MAX_LENGTH - len(item)) for item in input_bpe])
    
    return input_ids

def postprocess(data):
    x, y, z = data.shape

    translation_out = []
    for i in range(x):
        output_seqs = data[i]
        wids = list(output_seqs[0]) + [0]
        wids = wids[:wids.index(0)]
        translation = ' '.join([
            _trg_vocab[wid] if wid in _trg_vocab else '<unk>'
            for wid in wids
        ]).replace('@@ ', '').replace('@@', '')
        translation_out.append(_detok.detokenize(translation.split()))
    translation_out = ''.join(translation_out)
    return {OutputKeys.TRANSLATION: translation_out}

@app.route('/predict', methods=['POST'])
def predict():
    logger.info("接受到POST请求,开始翻译...")
    data = request.get_json()
    input_ids = preprocess_input(data['text'])
    outputs = sess.run(y, feed_dict={X: input_ids})
    return postprocess(outputs)

if __name__ == '__main__':
    load_model()
    app.run(port=6006)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114

6. 客户端

import requests
import json
import time

url = "http://127.0.0.1:6006/predict"
# 准备请求数据
data = {"text":["How are you?", "What's wrong with you?", "May I help you?", "Today is a good day!"]}

json_data = json.dumps(data)

start = time.time()
# 发送 POST 请求
response = requests.post(url, data=json_data, headers={"Content-Type": "application/json"})
end = time.time()
# 获取并解码返回的数据
if response.status_code == 200:
    returned_data = response.content.decode("unicode_escape")
    print("Returned Data:", returned_data)
    print("time is ", end - start)
else:
    print("Error:", response.status_code, response.text)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/189631
推荐阅读
相关标签
  

闽ICP备14008679号