您当前的位置:首页 > IT编程 > 自然语言处理
| C语言 | Java | VB | VC | python | Android | TensorFlow | C++ | oracle | 学术与代码 | cnn卷积神经网络 | gnn | 图像修复 | Keras | 数据集 | Neo4j | 自然语言处理 | 深度学习 | 医学CAD | 医学影像 | 超参数 | pointnet | pytorch | 异常检测 | Transformers | 情感分类 |

自学教程:从零开始用Tensorflow2.0 Keras 完成NLP分类任务并使用serving进行部署

51自学网 2023-11-19 11:11:26
  自然语言处理
这篇教程从零开始用Tensorflow2.0 Keras 完成NLP分类任务并使用serving进行部署写得很实用,希望能帮到您。

从零开始用Tensorflow2.0 Keras 完成NLP分类任务并使用serving进行部署

Tensorflow2.0 发布以来,越来越感觉到Google应该是大力推行Keras而不是Estimator。虽然Bert为首的Transformer大行其道,在有些情况下,我们依然需要从零开始搭建自己的模型。
这篇文章基于 Github 项目地址,我们用一个简单的RNN 模型对数据进行三分类情感分析,并将训练好的模型部署到服务器。
代码的流程大致是

  1. 数据预处理
  2. tf.data 生成数据流
  3. 训练模型并保存
  4. 部署

一,数据

数据是一个手机评论的情感分析,正面,负面,中性,数据样例如下:

1|挺好的,赞一个,手机很好,很喜欢
0|手机还行,但是手机刚开箱时屏幕和背面有很多指纹痕迹,手机壳跟**在地上磨过似的,好几条印子。要不是看在能把这些痕迹擦掉,和闲退货麻烦,就给退了。就不能规规矩矩做生意么。还有送的都是什么吊东西,运动手环垃圾一比,贴在手机后面的固定手环还**是塑料的渡了一层银色,耳机也和图片描述不符,碎屏险已经注册,不知道怎么样。讲真的,要不就别送或者少送,要不,就规规矩矩的,不然到最后还让人觉得不舒服。其他没什么。
2|手机整体还可以,拍照也很清楚,也很流畅支持华为。给一星是因为有缺陷,送的耳机是坏的!评论区好评太多,需要一些差评来提醒下,以后更加注意细节,提升质量。
0|前天刚买的, 看着还行, 指纹解锁反应不错。

其中0是中性,1是正面,2是负面,我们将数据分为train,dev,test

二,tf.data 生成数据流

我们来看如何喂数据:

dataset = tf.data.TextLineDataset(path)
dataset = dataset.map(
    lambda line: (tf.compat.v1.string_split([line]).values[1:], tf.compat.v1.string_split([line]).values[0]),
    num_parallel_calls=configs.num_parallel_calls
)

其中num_parallel_calls,用来做多线程,配合后面的一步可以加快读取速度。

dataset = dataset.map(lambda text,label: (text,tf.strings.to_number(
    label,
    out_type=tf.dtypes.int64,
    name=None
)))

这边需要将label的格式改为int64来匹配tensorflow的数据格式。

dataset = dataset.padded_batch(batch_size,padded_shapes=([-1],[]),padding_values=(tf.constant(pad_value, dtype=tf.string),tf.constant(1, dtype=tf.int64)))

这边的dataset就是pad并分batch的数据,等待模型的读取。

三,训练模型并保存

首先先定义一个input函数,这个函数将之前读入的文字数据映射成了模型可以读取的数字数据,注意到prefetch(1),就是搭配之前的num_parallel_calls,加速读取。

def input_data_func(data_path,shuffle=True):
    vocab = vocab_func(vocab_path)
    input_data = build_dataset(data_path)
    indices = tf.range(len(vocab), dtype=tf.int64)
    table_init = tf.lookup.KeyValueTensorInitializer(vocab, indices)
    table = tf.lookup.StaticVocabularyTable(table_init,num_oov_buckets)
    def encode_words(X_batch, y_batch):
        return table.lookup(X_batch), y_batch
    input_data = input_data.map(encode_words).prefetch(1)
    return input_data

主的model我们这样定义:

    model = keras.models.Sequential([
        keras.layers.Embedding(len(vocab)+num_oov_buckets, embed_size,
                            mask_zero=True,
                            # embeddings_initializer=tf.keras.initializers.Constant(matrix),
                            # trainable=True,
                            input_shape=[None]),
        keras.layers.GRU(n_units,return_sequences=True),
        keras.layers.GRU(n_units),
        keras.layers.Dense(n_outputs, activation="softmax")
    ])

这边embeddings_initializer可以选择随机初始化,也可以选择预训练好的字向量。注意到这边用了两层GRU,所以第一层要把所有的输出都返回return_sequences=True。

    checkpoint_cb = keras.callbacks.ModelCheckpoint(check_file_path,
                                                save_best_only=True)
    early_stopping_cb = keras.callbacks.EarlyStopping(patience=5,
                                                  restore_best_weights=True)
    tensorboard_cb = keras.callbacks.TensorBoard(run_logdir)

定义check_point,格式是H5。这一步主要是防止训练过程意外中断。

    optimizer = keras.optimizers.Adam(lr=lr, beta_1=0.9, beta_2=0.999)
    loss = keras.losses.CategoricalCrossentropy()
    model.compile(loss=loss, optimizer=optimizer,
                metrics=["accuracy"])

使用Adam,loss要使用CategoricalCrossentropy()。开始训练:

    history = model.fit(train_data, epochs=n_epochs,
                    validation_data=dev_data,
                    callbacks=[tensorboard_cb,checkpoint_cb,early_stopping_cb])

训练结束后,大概是97%的准确率。我们先不管这个,先把模型存下来:

    model_version = "0001"
    model_name = "my_cls_model"
    model_path = os.path.join(model_name, model_version)
    tf.saved_model.save(model, model_path)

到此,pb格式的模型已经存下来了。下面就是看如何部署了。

四,部署

部署可以分为如下几个步骤:

  1. 安装docker和tf.serving
  2. 部署模型
  3. rest简单测试
  4. 安装中间件Flask
  5. 完成部署

一,安装docker和tf.serving

sudo apt-get install docker
docker pull tensorflow/serving

这边的docker是cpu版本的。

二,部署模型
将上面的模型文件夹my_cls_model拷贝到目标目录,这边的示例是拷到了根目录,运行如下命令起服务:

docker run -it --rm -p 8500:8500 -p 8501:8501 -v "/my_cls_model:/models/my_cls_model" -e MODEL_NAME=my_cls_model tensorflow/serving

三,rest简单测试
当在服务器上部署好过后,可以在本机测试下是否能够联通:

X_new = [[1,4,5,7,8],[2,4,5,9,10]]
input_data_json = json.dumps({
    "signature_name": "serving_default",
    "instances": X_new,
})
SERVER_URL = 'http://144.202.100.179:8501/v1/models/my_cls_model:predict'
response = requests.post(SERVER_URL, data=input_data_json)
response.raise_for_status() # raise an exception in case of error
response = response.json()
y_proba = np.array(response["predictions"])
print(y_proba)

这边144.202.100.179是我部署的服务器的地址,需要相应的修改成自己服务器的地址。如果打印成功,则进行下一步

四,中间件Flask
这个中间件Flask的作用是连接了模型和request,并且在这中间件里面处理数据,变成model可以读取的形式,如将文本数据转化为数字传入。

import numpy as np
import requests
from flask import Flask, request, jsonify

# from flask_cors import CORS

app = Flask(__name__)


# Uncomment this line if you are making a Cross domain request
# CORS(app)

# Testing URL
@app.route('/cls/', methods=['POST'])
def sentiment_cls():
    sentence = request.get_data()
    file_vocab = open('data/vocab.txt','r')
    vocab = []
    for line in file_vocab:
        vocab.append(line.strip())
    file_vocab.close()
    words = list(sentence.decode('utf-8').strip())
    ids=[]
    for word in words:
        if word in vocab:
            ids.append(vocab.index(word))
        else:
            ids.append(len(vocab)-1)
    X_new = [ids]
    input_data_json = json.dumps({
        "signature_name": "serving_default",
        "instances": X_new,
    })
    SERVER_URL = 'http://144.202.100.179:8501/v1/models/my_cls_model:predict'
    response = requests.post(SERVER_URL, data=input_data_json)
    response = json.loads(response.text)
    predictions = response['predictions'][0]
    return str(predictions)

if __name__ == '__main__':
    app.run('0.0.0.0',port=5000)

可以把这个app.py放到对应的服务器上,然后运行app.py,此时Flask服务已经起来了。

五,完成部署

API_ENDPOINT = "http://localhost:5000/cls/"
sentence = '这个手机很垃圾'
r = requests.post(url=API_ENDPOINT,data=sentence.encode('utf-8'))
print(r.text)

这时候,可以测试rest是否能够连接Flask,需要注意的是,API_ENDPOINT需要改成Flask部署的地址。

五,总结

Keras比Estimator更加的便捷和一目了然,不再显示的用session减少了很多麻烦。serving的出现让部署更加的便捷。
Tensorflow2.0真香。


本文Github项目地址

 

返回列表
pandas统计csv总行数和指定列的各元素个数
51自学网自学EXCEL、自学PS、自学CAD、自学C语言、自学css3实例,是一个通过网络自主学习工作技能的自学平台,网友喜欢的软件自学网站。
京ICP备13026421号-1