简化NLP:TensorFlow中tf.strings的使用
TensorFlow中很早就包含了tf.strings这个模块,不过实话说,在tf 1.x的固定计算图的情况下,各种操作颇为复杂,我们在迎来了2.0中才更好可以看出tf.strings的威力。
tf.strings的其中一个重要的作用是可以使字符串成为TensorFlow的第一公民,可以直接加入到模型的输入中,在上一篇最简单的BERT调用中,就用到了类似技术 (https://github.com/qhduan/bert-model)
详细来说,我们之前在NLP中如果要将字符串进行计算,需要进行下面几步:
那么tf.strings的目的,就是我们为什么不能直接将字符串输入,避免上面的几步?这样做有几个好处:
具体来说怎么做呢,需要以下几步:
上图可以看到,英文直接使用tf.strings.split就可以按照空格和标点符号分词,下图中文的分词相对tricky,我们先用字符串替换方法tf.strings.regex_replace来把中文符号的后面都加一个空格,然后就可以用split了。
TensorFlow提供了一个简单的函数tf.strings.to_hash_bucket_fast可以用来代替词表,从其中hash的字样也可以看出,这是通过字符串hashing的方法来直接映射到对应的数字上。这个函数接受两个参数,一个是字符串后者字符串数组,另一个是词表大小。词表大小是整个模型所要接受的词表大小,当然既然是hashing,就有可能导致碰撞冲突,所以这个词表大小应该设置的比实际单词量大来尽量保证冲突不发生。
当我们说我们需要构建一个文本分类模型的时候,例如简单的Bi-LSTM,只需要这样:
就可以完成一个包含tokenizer、字典映射到模型训练的模型。其中的几个细节:
tf.strings.split:分词
tf.strings.to_hash_bucket_fast:词表映射(字典映射,单个字符到整形)
tf.squeeze:用这个是因为我们的输入会产生一个额外的维度,我们需要去掉
tf.to_tensor:实际上我们之前的维度输入的是不定长的(ragged tensor),因为每个句子的词数不一样,我们需要将它转换为定长的普通的tensor,所以这里使用了to_tensor函数并填充0做padding
再之后的代码就与其他所有的TensorFlow/Keras代码无异了。
想要训练时和其他普通的模型一样:
想要预测时更简单:
TensorFlow设计的很多工具也是希望我们能用最简单的代码,最快完成工程实践,提高最多的效率。