社区分享 | NLP 在 TensorFlow 2.x 中的最佳实战

2020 年 12 月 4 日 TensorFlow

本文来自社区投稿与征集,作者 段清华 DEAN,Google Developers Expert。

本文转自:https://zhuanlan.zhihu.com/p/293208563


本文会介绍TensorFlow 2.x在处理NLP任务中的一些工具和技巧,包括:

  • tf.keras.layers.experimental.preprocessing.TextVectorization

  • tf.strings

  • tf.data.experimental.bucket_by_sequence_length

  • BERT with strings



TextVectorization

在完成 NLP 任务的时候,经常需要把文字(一般是字符串),转换为具体的词向量(或字向量)。


或者说把文字转换为对应的词嵌入 (Word Embedding/Token Embedding)。


一般来说我们可能会这么做:制作一个词表,然后写程序把对应的词(字)映射到整数序号,然后就可以使用如tf.keras.layers.Embedding层,把这个整数映射到词嵌入。


但是这种做法有一个问题,就是你需要一个额外的程序,和一份此表,才能把文字(字符串)转换为具体的整数序号。


因为需要额外的程序,比如需要把一个 TensorFlow 保存后的模型传给别人,也同时需要传输给别人这个程序和词表,显然麻烦的多。


有没有一种不需要额外程序和采标的方法呢?TensorFlow 新加入的特性TextVectorization就是这样的功能。


TextVectorization默认输入以空格为分割的字符串,同时它和其他 TensorFlow/Keras 的层不同,它需要先进行学习,具体的代码如下:

x = [
'你 好 啊',
'I love you'
]
# 构建层
text_vector = tf.keras.layers.experimental.preprocessing.TextVectorization()
# 学习词表
text_vector.adapt(x)
# 我们可以通过这种方式获取词表(一个list)
print(text_vector.get_vocabulary())

# 输出:
# ['', '[UNK]', '好', '啊', '你', 'you', 'love', 'i']

# 可以看出结果已经
print(text_vector(x))

# 输出:
# tf.Tensor(
# [[4 2 3]
# [7 6 5]], shape=(2, 3), dtype=int64)


然后就可以把 text_vector 加入一个普通的 TensorFlow 模型

model = tf.keras.Sequential([
text_vector,
tf.keras.layers.Embedding(
len(text_vector.get_vocabulary()),
32
),
tf.keras.layers.Dense(2)
])

print(model(x))

# 输出:
# <tf.Tensor: shape=(2, 3, 2), dtype=float32, numpy=
# array([[[-0.01258635, -0.01506722],
# [-0.02729277, -0.04474692],
# [ 0.02955768, 0.00149873]],
# [[ 0.01346388, 0.01626211],
# [-0.03160518, 0.07346839],
# [-0.01061894, -0.0035725 ]]], dtype=float32)>



tf.strings 是什么

那么 TextVectorization 是怎么实现的呢?其实我们自己也可以实现这个功能,这就要说到 TensorFlow 的字符串类型和相关的各种算子。


比如我们可以通过tf.strings.split来分割字符串

x = [
'你 好 啊',
'I love you'
]
print(tf.strings.split(x))

# 输出:
# <tf.RaggedTensor [[b'\xe4\xbd\xa0', b'\xe5\xa5\xbd', b'\xe5\x95\x8a'], [b'I', b'love', b'you']]>


词表怎么实现呢,我们就需要使用tf.lookup.StaticHashTable

keys_tensor = tf.constant(['你', '好', '啊'])
vals_tensor = tf.constant([1, 2, 3])

table = tf.lookup.StaticHashTable(
tf.lookup.KeyValueTensorInitializer(keys_tensor, vals_tensor), -1)
print(table.lookup(tf.constant(['你', '好'])))

# 输出:
# tf.Tensor([1 2], shape=(2,), dtype=int32)



数据对齐: bucket_by_sequence_length

处理图片模型的时候,经常需要将图谱缩放到一个固定的大小,不过对于 NLP 任务来说,句子长度可是不同的,这虽然也可以通过增加 padding 的方式,即插入空字符的方式对齐。


但是实际上这样的处理是有一定的问题的,就是效率损失。


这种方式虽然能满足算法,但是实际上无论是 LSTM/Transform,其实效率都和句子长度有关。


例如有 4 个句子,两个是长度 2,两个是长度 100,假设分成两个批次 (batch),第一个批次是两个长度 2 的句子,第二批次是两个长度 100 的句子,那算法就只需要计算 (2 + 100) 的算力。


但是如果四个句子,把一个长度 2 的句子和一个长度 100 的句子凑一起,就需要在每个批次的长度 2 句子后面插入 98 个空字符,算法需要的算力就是 (100 + 100)的算力。


在 TensorFlow 中,可以使用tf.data.Dataset.experimental.bucket_by_sequence_length自动对齐输入数据。


基于BERT的举例:更简易的BERT

BERT 模型实际上是有 3 个输入的:token,mask,type


token 是经过分词的字符串,转换为的整数序号。


mask 是输入长度的遮盖,是在一个 batch 有中不同长度的句子时的情况。


type 是 0 或 1,是 bert 训练目标中的第二个 NSP 任务相对的 type embedding 所需的。


不过对于大多数情况,其实 BERT 只需要一个输入,就是字符串。


因为对于 BERT 很多单句/单文档模型的情况,type 只需要单一的 0 就可以了。


而 mask 也可以通过字符串本身计算出来,例如是否为空字符串。


这个时候我们就可以使用以上提到的字符串方法,让 BERT 模型直接输入字符串,配合 TensorFlow Hub,这就可以方便很多模型的计算。


当然对于 BERT 的分词器,就很难简单的直接用上面提到的 TextVectorization 了,这里需要配合 TensorFlow Text。


最简单算法可以简化如下:

# $ pip install tensorflow tensorflow-text tensorflow-hub
import tensorflow as tf
import tensorflow_text
import tensorflow_hub as hub
tokenizer = hub.load(
'https://code.aliyun.com/qhduan/bert_v4/raw/500019068f2c715d4b344c3e2216cef280a7f800/bert_tokenizer_chinese.tar.gz'
)
albert = hub.load(
'https://code.aliyun.com/qhduan/bert_v4/raw/500019068f2c715d4b344c3e2216cef280a7f800/albert_tiny.tar.gz'
)
out = albert(tokenizer(['你好']))

assert out['sequence_output'].shape == (1, 2, 312)
assert out['pooled_output'].shape == (1, 312)



— 推荐阅读 —



如果您想在 TensorFlow 社区分享经验与用例,点击 “阅读原文” 填写相关信息,我们会尽快与您联系。

登录查看更多
1

相关内容

【实用书】Python机器学习Scikit-Learn应用指南,247页pdf
专知会员服务
268+阅读 · 2020年6月10日
Transformer文本分类代码
专知会员服务
117+阅读 · 2020年2月3日
TensorFlow Lite指南实战《TensorFlow Lite A primer》,附48页PPT
专知会员服务
70+阅读 · 2020年1月17日
【干货】谷歌Joshua Gordon 《TensorFlow 2.0讲解》,63页PPT
专知会员服务
28+阅读 · 2019年11月2日
2019年机器学习框架回顾
专知会员服务
36+阅读 · 2019年10月11日
机器学习入门的经验与建议
专知会员服务
94+阅读 · 2019年10月10日
社区分享 | Spark 玩转 TensorFlow 2.0
TensorFlow
15+阅读 · 2020年3月18日
盘一盘 Python 系列 10 - Keras (上)
平均机器
5+阅读 · 2019年8月26日
盘一盘 Python 系列 8 - Sklearn
平均机器
5+阅读 · 2019年5月30日
实战 | 用Python做图像处理(一)
七月在线实验室
25+阅读 · 2018年5月23日
【干货】基于Keras的注意力机制实战
专知
59+阅读 · 2018年5月4日
Tensorflow 文本分类-Python深度学习
Python程序员
12+阅读 · 2017年11月22日
tensorflow系列笔记:流程,概念和代码解析
北京思腾合力科技有限公司
30+阅读 · 2017年11月11日
Python 自然语言处理(NLP)工具库汇总
数据挖掘入门与实战
7+阅读 · 2017年9月25日
Arxiv
0+阅读 · 2021年1月31日
Bidirectional Attention for SQL Generation
Arxiv
4+阅读 · 2018年6月21日
Arxiv
9+阅读 · 2016年10月27日
Arxiv
5+阅读 · 2015年9月14日
VIP会员
相关VIP内容
【实用书】Python机器学习Scikit-Learn应用指南,247页pdf
专知会员服务
268+阅读 · 2020年6月10日
Transformer文本分类代码
专知会员服务
117+阅读 · 2020年2月3日
TensorFlow Lite指南实战《TensorFlow Lite A primer》,附48页PPT
专知会员服务
70+阅读 · 2020年1月17日
【干货】谷歌Joshua Gordon 《TensorFlow 2.0讲解》,63页PPT
专知会员服务
28+阅读 · 2019年11月2日
2019年机器学习框架回顾
专知会员服务
36+阅读 · 2019年10月11日
机器学习入门的经验与建议
专知会员服务
94+阅读 · 2019年10月10日
相关资讯
社区分享 | Spark 玩转 TensorFlow 2.0
TensorFlow
15+阅读 · 2020年3月18日
盘一盘 Python 系列 10 - Keras (上)
平均机器
5+阅读 · 2019年8月26日
盘一盘 Python 系列 8 - Sklearn
平均机器
5+阅读 · 2019年5月30日
实战 | 用Python做图像处理(一)
七月在线实验室
25+阅读 · 2018年5月23日
【干货】基于Keras的注意力机制实战
专知
59+阅读 · 2018年5月4日
Tensorflow 文本分类-Python深度学习
Python程序员
12+阅读 · 2017年11月22日
tensorflow系列笔记:流程,概念和代码解析
北京思腾合力科技有限公司
30+阅读 · 2017年11月11日
Python 自然语言处理(NLP)工具库汇总
数据挖掘入门与实战
7+阅读 · 2017年9月25日
相关论文
Arxiv
0+阅读 · 2021年1月31日
Bidirectional Attention for SQL Generation
Arxiv
4+阅读 · 2018年6月21日
Arxiv
9+阅读 · 2016年10月27日
Arxiv
5+阅读 · 2015年9月14日
Top
微信扫码咨询专知VIP会员