一、one-hot 编码
任务描述
本关任务:简单掌握文本转 one-hot 编码操作。
相关知识
为了完成本关任务,你需要掌握:
- one-hot 编码简介
- 单词级的 one-hot 编码
- 字符级的one-hot编码
- 用keras实现单词级的one-hot编码
one-hot 编码简介
在前面的实训中,我们已经使用过简单的one-hot编码,one-hot编码是将标记转换为向量的最常用,最基本的方法。对于单词级别的one-hot编码,它将每个单词与一个唯一的整数索引相关联,然后将这个整数索引i转换为长度为N的二进制向量(N是词表的大小),这个向量只有第i个元素是1,其余都是0,对于字符级别的one-hot编码,它将每个字符与一个唯一的整数索引相关联,其余与单词级别的类似。
单词级的 one-hot 编码
初始数据:每个样本是列表的一个元素(本例中的样本是一个句子,但也可以是一篇文档) 现在我们通过以下方式来完成单词级的one-hot编码(该步骤不需要学员实现),代码如下:
import numpy as np
#自行创建的简单数据
samples = ['The cat sat on the mat.', 'The dog ate my homework.']
# 构建数据中所有标记的索引,用一个字典来存储
token_index = {}
for sample in samples:
# 利用split方法对样本进行分词.
for word in sample.split():
if word not in token_index:
#为每个唯一单词指定一个唯一索引
token_index[word] = len(token_index) + 1
#没有为索引编号0指定单词
#对样本进行分词
# 只考虑每个样本前max_length个单词。
max_length = 10
#结果返回给results:
results = np.zeros((len(samples), max_length, max(token_index.values()) + 1))
for i, sample in enumerate(samples):
for j, word in list(enumerate(sample.split()))[:max_length]:
index = token_index.get(word)
#指定唯一的元素为1
results[i, j, index] = 1.
#查看索引字典
print(token_index)
print(results[1,1])#样本列表的第二个元素的第二个单词编码情况
代码执行结果:
{'The': 1,
'cat': 2,
'sat': 3,
'on': 4,
'the': 5,
'mat.': 6,
'dog': 7,
'ate': 8,
'my': 9,
'homework.': 10}
[0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]
字符级的one-hot编码
与上面类似现在我们通过以下方式来完成单词级的 one-hot 编码,请复制代码到 .ipynb 文件中并运行,代码如下:
import string
samples = ['The cat sat on the mat.', 'The dog ate my homework.']
characters = string.printable #所以可以打印的ASCII字符
#创建索引字典
token_index = dict(zip(characters, range(1, len(characters) + 1)))
#为所有可能打印的字符创建一个字典
max_length = 50
results = np.zeros((len(samples), max_length, max(token_index.values()) + 1))
for i, sample in enumerate(samples):
for j, character in enumerate(sample[:max_length]):
index = token_index.get(character)
results[i, j, index] = 1.
print(token_index)#查看索引字典
print(results[1,1])#样本列表的第二个元素的第二个字符编码情况
代码执行结果:
{'The': 1,
'cat': 2,
'sat': 3,
'on': 4,
'the': 5,
'mat.': 6,
'dog': 7,
'ate': 8,
'my': 9,
'homework.': 10,
'a.': 11,
'panda.': 12,
'is.': 13 ,
'sleeping.': 14}
[0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0.]
用keras实现单词级的one-hot编码
我们可以通过以下简单的方式用keras来实现one-hot编码(该步骤不需要学员实现),请复制代码到.ipynb文件中并运行,代码如下:
from keras.preprocessing.text import Tokenizer
samples = ['The cat sat on the mat.', 'The dog ate my homework.']
#创建一个分词器
# 只考虑前1000个最常见的单词
tokenizer = Tokenizer(num_words=1000)
# 构建单词索引
tokenizer.fit_on_texts(samples)
# 将字符串转换为整数索引的组成的列表
sequences = tokenizer.texts_to_sequences(samples)
# 可以直接得到one-hot编码二进制表示
# 分词器也支持除one-hot编码外的其他向量化模式
one_hot_results = tokenizer.texts_to_matrix(samples, mode='binary')
# 找回单词索引
word_index = tokenizer.word_index
word_index
代码执行结果:
{'the': 1,
'cat': 2,
'sat': 3,
'on': 4,
'mat': 5,
'dog': 6,
'ate': 7,
'my': 8,
'homework': 9}
编程要求
根据提示,在右侧编辑器补充代码。
-
给上述samples列表新增一个元素‘a panda is sleeping’
-
自行完成单词级别的分词任务,并查看索引字典和样本列表的第二个元素的第二个单词的编码情况。(注意索引是0开始)
-
创建字符级 one-hot 编码索引字典,查看第三个元素中的第三个字符的编码情况
测试说明
平台会对你编写的代码进行测试。
开始你的任务吧,祝你成功!
代码部分
import numpy as np
import string
from keras.preprocessing.text import Tokenizer
"""
单词级的 one-hot 编码
"""
def word_one_hot(samples):
# x,y表示显示的第x个元素的第y个单词
# 构建数据中所有标记的索引,用一个字典来存储
token_index = {}
for sample in samples:
########## Begin ##########
# 利用split方法对样本进行分词.
for word in sample.split():
if word not in token_index:
#为每个唯一单词指定一个唯一索引
token_index[word] = len(token_index)
#没有为索引编号0指定单词
########## End ##########
# 只考虑样本前max_length个单词
max_length = 10
#结果返回给results:
results = np.zeros((len(samples), max_length, max(token_index.values())+1))
for i, sample in enumerate(samples):
for j, word in list(enumerate(sample.split()))[:max_length]:
index = token_index.get(word)
#唯一的元素为1
results[i, j, index] = 1
########## Begin ##########
# 查看索引字典和样本列表的第二个元素的第二个单词的编码情况
# print(token_index)
print(results[1,1])
########## End ##########
"""
字符级的one-hot编码
"""
def char_one_hot(samples):
# x,y表示显示的第x个元素的第y个字符
# 可以打印的ASCII字符
characters = string.printable
########## Begin ##########
#创建索引字典
token_index = dict(zip(characters, range(0, len(characters) )))
#为所有可能打印的字符创建一个字典
max_length = 50
results = np.zeros((len(samples), max_length, max(token_index.values())+1 ))
########## End ##########
for i, sample in enumerate(samples):
for j, character in list(enumerate(sample[:max_length])):
index = token_index.get(character)
results[i, j, index] = 1.
########## Begin ##########
# 查看索引字典和样本列表的第三个元素的第三个单词的编码情况
# print(token_index)#查看索引字典
###################
print(results[2,2])#样本列表的第3个元素的第3个字符编码情况
########## End ##########
########## Begin ##########
# 给 samples 列表新增一个元素‘a panda is sleeping’
samples = ['The cat sat on the mat.',
'The dog ate my homework.',
'a panda is sleeping.'
]
#创建一个分词器
# 只考虑前1000个最常见的单词
tokenizer = Tokenizer(num_words=1000)
# 构建单词索引
tokenizer.fit_on_texts(samples)
# 将字符串转换为整数索引的组成的列表
sequences = tokenizer.texts_to_sequences(samples)
# 可以直接得到one-hot编码二进制表示
# 分词器也支持除one-hot编码外的其他向量化模式
one_hot_results = tokenizer.texts_to_matrix(samples, mode='binary')
########## End ##########
word_one_hot(samples)
char_one_hot(samples)
"""
用keras实现单词级的one-hot编码
"""
tokenizer = Tokenizer(num_words=1000)
tokenizer.fit_on_texts(samples)
word_index = tokenizer.word_index
print(word_index)
二、词嵌入模型
任务描述
本关任务:使用 keras 实现词嵌入模型。
相关知识
为了完成本关任务,你需要掌握:
- 词嵌入简介
- 利用Embedding层学习词嵌入
- 构建keras模型并训练拟合模型
词嵌入简介
将单词与向量相关联的另外一个强大的方法就是词嵌入,one-hot编码得到的向量是二进制的、稀疏的(绝大部分你元素都是0)、维度很高(维度大小等于词表中的单词个数),而词嵌入是低微的浮点数向量(即密集向量,与稀疏向量相对),如下图所示,与one-hot编码得到的词向量不同,词嵌入是从数据中学习得到的。常见的词向量维度是256、512或1024(处理非常大的词表时)。与此相对,one-hot编码的词向量维度通常是20000或者更高(对应包含20000个标记的词表),因此词向量可以将更多的信息塞入更低的维度中。
利用Embedding层学习词嵌入
实例化Embedding层
可以将Embedding层理解为一个字典,将整数索引(表示特定单词)映射为密集向量。它接收整数作为输入,并在内部字典查找这些整数,然后返回相关联的向量。
在我们通过以下方式来实例化一个Embedding(该步骤不需要学员实现),请复制代码到.ipynb文件中并运行,代码如下:
from keras.layers import Embedding
# Embedding层至少需要2个参数
# 标记的个数(这里是1000,即最大单词索引+1)和嵌入维度(这里是64)
embedding_layer = Embedding(1000, 64)
加载IMDB数据
本节使用IMDB数据集,它包含来自互联网电影数据库(IMDB)的50000条严重两极分化的评论。数据集被分为用于训练的25000条评论和用于测试的25000条评论,训练集和测试集都包含50%的正面评论和50%的负面评论。
可以通过以下方式构造我们的数据集(该步骤不需要学员实现),请复制代码到.ipynb文件中并运行,代码如下:
from keras.datasets import imdb
from keras import preprocessing
# 作为特征的单词,即选取出现频率最高的单词数量
max_features = 10000
# 在这么多单词后截断文本
# (这些单词都属于前max_features个最常见单词)
maxlen = 20
#将数据集加载为列表
(x_train, y_train), (x_test, y_test) = imdb.load_data(num_words=max_features)
# 将整数列表转换成形状为(samples,maxlen)的二维整数张量
x_train = preprocessing.sequence.pad_sequences(x_train, maxlen=maxlen)
x_test = preprocessing.sequence.pad_sequences(x_test, maxlen=maxlen)
构建keras模型并训练拟合模型
from keras.models import Sequential
from keras.layers import Flatten, Dense
model = Sequential()
# 指定 Embedding 层的最大输入长度,以便后面将嵌入输入展平。
model.add(Embedding(2000, 4, input_length=10))
# 将三维的嵌入张量展平为(samples, 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)
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
embedding_2 (Embedding) (None, 10, 4) 8000
_________________________________________________________________
flatten_1 (Flatten) (None, 40) 0
_________________________________________________________________
dense_1 (Dense) (None, 1) 41
=================================================================
Total params: 8,041
Trainable params: 8,041
Non-trainable params: 0
_________________________________________________________________
Train on 20000 samples, validate on 5000 samples
Epoch 1/10
20000/20000 [==============================] - 3s 169us/step - loss: 0.6759 - acc: 0.6049 - val_loss: 0.6399 - val_acc: 0.6800
Epoch 2/10
20000/20000 [==============================] - 1s 43us/step - loss: 0.5659 - acc: 0.7421 - val_loss: 0.5469 - val_acc: 0.7202
Epoch 3/10
20000/20000 [==============================] - 1s 44us/step - loss: 0.4753 - acc: 0.7806 - val_loss: 0.5114 - val_acc: 0.7380
Epoch 4/10
20000/20000 [==============================] - 1s 44us/step - loss: 0.4265 - acc: 0.8077 - val_loss: 0.5009 - val_acc: 0.7454
Epoch 5/10
20000/20000 [==============================] - 1s 44us/step - loss: 0.3933 - acc: 0.8254 - val_loss: 0.4982 - val_acc: 0.7540
Epoch 6/10
20000/20000 [==============================] - 1s 44us/step - loss: 0.3671 - acc: 0.8393 - val_loss: 0.5014 - val_acc: 0.7530
Epoch 7/10
20000/20000 [==============================] - 1s 47us/step - loss: 0.3438 - acc: 0.8531 - val_loss: 0.5052 - val_acc: 0.7520
Epoch 8/10
20000/20000 [==============================] - 1s 60us/step - loss: 0.3226 - acc: 0.8654 - val_loss: 0.5132 - val_acc: 0.7482
Epoch 9/10
20000/20000 [==============================] - 1s 55us/step - loss: 0.3026 - acc: 0.8762 - val_loss: 0.5213 - val_acc: 0.7490
Epoch 10/10
20000/20000 [==============================] - 1s 53us/step - loss: 0.2843 - acc: 0.8854 - val_loss: 0.5301 - val_acc: 0.7464
编程要求
根据提示,在右侧编辑器补充代码,需要完成的步骤如下:
- 导入包 Sequential,Flatten,Dense,Embedding
- 定义一个序列模型
- 添加一个Embedding层,标记个数 10000,维度 8,输入长度是maxlen
- 添加一个Flatten层
- 添加一个全连接层,输出维度是1,激活函数‘sigmoid’
- 编译模型,优化器选取‘rmsprop’,损失函数选取‘binary_crossentropy’,评估方式是‘acc’
- 用.summary()方法查看模型架构
- 拟合模型,epoch选取 10,batch_size选取 32,validation_split为 0.2
测试说明
平台会对你编写的代码进行测试。
开始你的任务吧,祝你成功!
代码部分
from keras import preprocessing
########## Begin ##########
# 导入包 Sequential,Flatten,Dense,Embedding
from keras.models import Sequential
from keras.layers import Flatten
from keras.layers import Dense
from keras.layers import Embedding
from keras.datasets import imdb
from keras import preprocessing
########## End ##########
import os
def main():
max_features = 10000
maxlen = 20
# 加载数据
(X_train, y_train), (X_test, y_test) = imdb.load_data(path="/data/workspace/myshixun/imdb.npz",num_words=max_features)
# 重塑数据形状为(samples, maxlen)的二维整数张量
X_train = preprocessing.sequence.pad_sequences(X_train, maxlen=maxlen)
X_test = preprocessing.sequence.pad_sequences(X_test, maxlen=maxlen)
########## Begin ##########
# 定义一个序列模型
model = Sequential()
# 添加一个Embedding层,标记个数 10000,维度 8,输入长度是maxlen
model.add(Embedding(10000, 8, input_length=maxlen))
# 添加一个Flatten层
model.add(Flatten())
# 添加一个全连接层,输出维度是1,激活函数‘sigmoid’, 作为分类器
model.add(Dense(1, activation='sigmoid'))
# 编译模型,优化器选取‘rmsprop’,损失函数选取‘binary_crossentropy’,评估方式是‘acc’
model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['acc'])
# 拟合模型,epoch选取 10,batch_size选取 32,validation_split为 0.2
model.fit(X_train, y_train,epochs=10, batch_size=32, validation_split=0.2)
# 打印模型结构
model.summary()
return model
########## End ##########