基于文本的深度学习方法的TensorFlow实现(1)——词嵌入

词嵌入

用数字表示文本

机器学习模型以向量(数字数组)作为输入,为了使用文本,需要将字符串转为数字,即向量化。

三种向量化策略

  • One-hot编码
    向量长度等于词汇量,在词汇对应的索引置1,其他置0
    例如:
    The cat sat on the mat.
    cat (0,1,0,0,0,0)
    ……
    缺点:效率低下,向量稀疏
  • 整数编码
    用唯一的数字给词编码
    例如:
    The cat sat on the mat.
    (1,2,3,4,5,6)
    缺点:
    编码不能表示单词之间的关系;单词之间的相似性与编码的相似性无关,编码的权重组合无意义。
  • 词嵌入
    高效,密集,且相似的单词具有相似的编码
    自动嵌入浮点数密集向量(向量长度需指定),具体的数值是可以训练的参数。高维的嵌入可以捕获单词间的细粒度关系,同时需要更多的数据来学习。

使用Embedding层

Keras提供词嵌入的方法,即Embedding层。
可以将词嵌入看为查找表,它从代表单词的整数索引映射到单词嵌入的密集向量。

embedding_layer = layers.Embedding(1000, 5)

创建嵌入层时,嵌入的权重会随机初始化。在训练过程中,通过反向传播逐渐调整嵌入值。经过训练后,词嵌入可以学习编码词之间的相似性。
对于文本或序列,Embedding层的输入为2维整数张量(samples, sequence_length),每个条目为一个整数序列。
Embedding层可以嵌入可变长度的序列。
返回的张量比输入多一维,嵌入的向量和最后一维对齐。
例如:
输入维度(2,3),输出维度为(2,3,5)。
为了从可变长度的序列转换为固定的表示形式,可以有多种方法,比如RNN,Attention或pooling层。

从头开始学习嵌入

首先加载文本数据集。
对于长度不同的文本,使用padded_batch标准化文本的长度。

padded_shapes = ([None],())
train_batches = train_data.shuffle(1000).padded_batch(10, padded_shapes = padded_shapes)
test_batches = test_data.shuffle(1000).padded_batch(10, padded_shapes = padded_shapes)

通过在句尾补0填充到批处理中例子最长的长度。

  1. 使用keras的API创建一个简单的模型
embedding_dim=16
model = keras.Sequential([
  layers.Embedding(encoder.vocab_size, embedding_dim),
  layers.GlobalAveragePooling1D(),
  layers.Dense(1, activation='sigmoid')
])
model.summary()

首先,使用“连续词袋”样式模型,嵌入层采用整数编码的词汇表,并为每个单词索引查找嵌入向量。
然后,GlobalAveragePooling1D()通过对序列维进行平均,为每个样本返回固定长度的输出向量。
固定长度的输出向量通过16个隐藏单元的完全连接层进行管道传输。最后一层与单个输出节点紧密相连。
使用S形激活函数,表示置信度。

  1. 编译和训练模型
model.compile(optimizer='adam',
              loss='binary_crossentropy',
              metrics=['accuracy'])
history = model.fit(
    train_batches,
    epochs=10,
    validation_data=test_batches, validation_steps=20)

检索学习的词嵌入

首先,检索学习到的词嵌入。

e = model.layers[0]
weights = e.get_weights()[0]
print(weights.shape) # shape: (vocab_size, embedding_dim)

然后,将权重写入磁盘。使用Embedding Prijector将以制表符分隔的格式上传两个文件:一个向量文件(包含嵌入)和一个元数据文件(包含单词)。

encoder = info.features['text'].encoder

import io
encoder = info.features['text'].encoder
out_v = io.open('vecs.tsv', 'w', encoding='utf-8')
out_m = io.open('meta.tsv', 'w', encoding='utf-8')
for num, word in enumerate(encoder.subwords):
  vec = weights[num+1] # skip 0, it's padding.
  out_m.write(word + "\n")
  out_v.write('\t'.join([str(x) for x in vec]) + "\n")
out_v.close()
out_m.close()

可视化词嵌入

打开Embedding Prijector,可以搜索单词找到其最近的邻居。

参考链接

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章