作者:《python深度学习》学习笔记,用于自己熟悉和理解
目录
1.实现单词级的one-hot编码:稀疏,高维,硬编码
2.使用词嵌入word embeding:密集,低维,学习得到
2.1 方法一:利用 Embedding 层学习得来
2.2 方法二: 使用预训练的词嵌入
参考
深度学习模型不会接收原始文本作为输入,它只能处理数值张量。文本向量化(vectorize)是指将文本转换为数值张量的过程。主要有三种实现方式:1.单词级;2字符级;3.提取单词或者字符的n-gram(多个连续的集合)
将文本分解成的单元(单词、字符或 n-gram)叫作标记(token),将文本分解成标记的过程叫作分词(tokenization)。所有文本向量化过程都是应用某种分词方案,然后将数值向量与生成的标记相关联。这些向量组合成序列张量,被输入到深度神经网络中。将向量与标记相关联的主要方法有两种:做 one-hot 编码(one-hot encoding)与标记嵌入[token embedding,通常只用于单词,叫作词嵌入(word embedding)]。
1.实现单词级的one-hot编码:稀疏,高维,硬编码
samples = ['The cat sat on the mat.', 'The dog ate my homework.']
tokenizer=Tokenizer(num_words=1000)#只考虑前一千个最常见单词,设成你想要的维度
tokenizer.fit_on_texts(samples)#构建单词索引
"""分词器(tokenizer)支持多种模式的向量化模型"""
#1.将字符串转化为整数索引组成的列表:[[1, 2, 3, 4, 1, 5], [1, 6, 7, 8, 9]]
sequences=tokenizer.texts_to_sequences(samples)
#2.可以得到onehot二进制表示的列表:[[ 0. 1. 1. ..., 0. 0. 0.][ 0. 1. 0. ..., 0. 0. 0.]]
one_hot_results=tokenizer.texts_to_matrix(samples,mode='binary')
#3.还有一种散列的one-hot编码
2.使用词嵌入word embeding:密集,低维,学习得到
常见的词向量维度是256、512 或 1024(处理非常大的词表时),有两种方法获得:
2.1 方法一:利用 Embedding 层学习得来
几何距离(比如 L2 距离)应该和这两个词的语义距离有关(表示不同事物的词被嵌入到相隔很远的点,而相关的词则更加靠近)。除了距离,你可能还希望嵌入空间中的特定方向也是有意义的。
并且在不同的场景当中,两个词的相近程度也有所不同,所以不能一劳永逸,而是要针对不同场景去学习。
因此,合理的做法是对每个新任务都学习一个新的嵌入空间。我们要做的无非就是学习一个层的权重,这个层就是
Embedding 层。
将 Embedding 层理解为一个字典,能将单词索引映射为密集向量。它接收整数作为输入,并在内部字典中查找这些整数,然后返回相关联的向量。Embedding 层实际上是一种字典查找。
Embedding 层的实例化:
from keras.layers import Embedding
embedding_layer = Embedding(1000, 64)
"""标记的个数(词汇表大小,这里是 1000,即最大单词索引 +1)和嵌入的维度(这里是 64,有64个特征组成一个单词)"""
Embedding 层的输入和输出:
- 输入:一个二维张量,形状为(samples,sequential_length)
samples:代表不同的句子。
sequential_length:代表句子中的单词的个数,每个单词对应一个数字,一共sequential_length个单词。
一批数据中的所有序列必须具有相同的长度(因为需要将它们打包成一个张量),短的补0,长的截断 - 输出:一个三维张量,形状为(samples,sequential_length,dimensionality)
samples:代表不同的句子。
sequential_length:代表句子中的单词的个数
dimensionality:代表通道数,同一samples,同一sequential_length上的所有通道上的值组成的向量表示一个单词,如(0,0,:)代表一个单词。
Embedding 层的学习和目的:
将一个 Embedding 层实例化时,它的权重(即标记向量的内部字典)最开始是随机的,与其他层一样。在训练过程中,利用反向传播来逐渐调节这些词向量,改变空间结构以便下游模型可以利用。一旦训练完成,嵌入空间将会展示大量结构,这种结构专门针对训练模型所要解决的问题。
Embedding 层的实践:
场景:IMDB 电影评论情感预测任务
方法:将电影评论限制为前 10 000 个最常见的单词(第一次处理这个数据集时就是这么做的),然后将评论长度限制为只有 20 个单词。对于这 10 000 个单词,网络将对每个词都学习一个 8维嵌入,将输入的整数序列(二维整数张量)转换为嵌入序列(三维浮点数张量),然后将这个张量展平为二维,最后在上面训练一个 Dense 层用于分类
from keras.datasets import imdb
from keras.preprocessing.sequence import pad_sequences
from keras.models import Sequential
from keras.layers import Flatten, Dense, Embedding
"""1.获取数据作为embedding层的输入:将整数列表转换成形状为(samples,maxlen)的二维整数张量"""
max_features =10000 #前一万个单词组成词汇表,也就是ont-hot里面特征数
maxlen=20#输入的单词序列长度要相同
"""将数据加载为整数列表"""
(x_train, y_train), (x_test, y_test) = imdb.load_data(num_words=max_features)
"""输入前要截成相同长度"""
x_train = pad_sequences(x_train, maxlen=maxlen)
x_test = pad_sequences(x_test, maxlen=maxlen)
"""2.使用Embedding 层和分类器"""
model=Sequential()
model.add(Embedding(10000,8,input_length=maxlen))
"""将三维的嵌入张量展平成形状为 (samples, maxlen * 8) 的二维张量:
一个sample的所有(maxlen个)单词所有(8个)特征,这就是为什么要截取一样的长度"""
model.add(Flatten())
model.add(Dense(1,activation='sigmoid'))
model.compile(optimizer='rmsprop',loss='binary_crossentropy',metrics=['acc'])
model.summary()#输出网络结构
#训练模型:自己切分来训练
history=model.fit(x_train,y_train,epochs=10,batch_size=32,validation_split=0.2)
结论:得到的验证精度约为 76%,考虑到仅查看每条评论的前 20 个单词,这个结果还是相当不错的。但请注意,仅仅将嵌入序列展开并在上面训练一个 Dense 层,会导致模型对输入序列中的每个单词单独处理,而没有考虑单词之间的关系和句子结构。
更好的做法是在嵌入序列上添加循环层或一维卷积层,将每个序列作为整体来学习特征。
2.2 方法二: 使用预训练的词嵌入
由于手头数据不足,我们可以使用预训练的词嵌入,这种方法也更为常见。最近参加的kaggle文本分类的比赛就是提供了词嵌入glove等几个数据库。有许多预计算的词嵌入数据库,你都可以下载并在 Keras 的 Embedding 层中使用。比如word2vec,glove。
在下一节中我们通过讲解一个完整代码来学习怎么使用预训练的词嵌入和完整流程。
参考
《python深度学习》