第1关:迈出第一步----数据预处理
代码文件
import numpy as np
test_point = input()
with open('cmn.txt', 'r', encoding='utf-8') as f:
data = f.read()
data = data.split('\n')
data = data[:100]
#########begin#########
en_data = [line.split('\t')[0] for line in data]
ch_data = ['\t' + line.split('\t')[1] + '\n' for line in data]
#########end#########
print('英文数据:\n', en_data[:5])
print('\n中文数据:\n', ch_data[:5])
print('数据读取完成')
# 分别生成中英文字典
#########begin#########
en_vocab = set(''.join(en_data))
en_vocab = sorted(en_vocab)
id2en = {i: char for i, char in enumerate(en_vocab)}
en2id = {char: i for i, char in enumerate(en_vocab)}
ch_vocab = set(''.join(ch_data))
ch_vocab = sorted(ch_vocab)
id2ch = {i: char for i, char in enumerate(ch_vocab)}
ch2id = {char: i for i, char in enumerate(ch_vocab)}
#########end#########
print('\n英文字典:\n', en2id)
print('\n中文字典\n:', ch2id)
print('字典构建完成')
en_num_data = [[en2id[en] for en in line] for line in en_data]
ch_num_data = [[ch2id[ch] for ch in line] for line in ch_data]
de_num_data = [[ch2id[ch] for ch in line][1:] for line in ch_data]
import numpy as np
# 获取输入输出端的最大长度
max_encoder_seq_length = max([len(txt) for txt in en_num_data])
max_decoder_seq_length = max([len(txt) for txt in ch_num_data])
#########begin#########
# 将数据进行onehot处理
# 将数据进行onehot处理
encoder_input_data = np.zeros(
(len(en_num_data), max_encoder_seq_length, len(en2id)), dtype='float32')
decoder_input_data = np.zeros(
(len(ch_num_data), max_decoder_seq_length, len(ch2id)), dtype='float32')
decoder_target_data = np.zeros(
(len(ch_num_data), max_decoder_seq_length, len(ch2id)), dtype='float32')
for i, (input_text, target_text) in enumerate(zip(en_num_data, ch_num_data)):
for t, char in enumerate(input_text):
encoder_input_data[i, t, char] = 1.
for t, char in enumerate(target_text):
decoder_input_data[i, t, char] = 1.
# 注意:target_text是从索引1开始,因为索引0是'\t'开始标记
if t > 0:
# decoder_target_data是从索引0开始,结束标记是'\n'
decoder_target_data[i, t - 1, char] = 1.
#########end#########
print(encoder_input_data[int(test_point)])
print(decoder_input_data[int(test_point)])
print(decoder_target_data[int(test_point)])
print('向量化完成')
题目描述
任务描述
本关任务:基于机器学习的思想,是一种数据驱动的研究思想,因此首先要对准备研究的数据进行处理。对于机器翻译模型,数据预处理主要分为两个方面:
- 标准化自然语言语句的格式
- 构建训练所用的语言词典
- 将语词转化为向量
相关知识
为了完成本关任务,你需要掌握:
- 读取原始数据并对其进行标准化整理
- 根据自然语言语句数据,构建英语和法语两个词典。
- 将自然语言向量化
数据整理
本实训提供20,000个英语句子和其相对应的20,000个翻译好的法语句子。数据的原始格式如下:
每一行包含一句英语句子和其对应的法语句子,它们中间用
\t
隔开。现在希望将英语和法语句子分割开来,将英语句子存入
en_data
,将法语句子存入
ch_data
,并且为了后续模型训练,规定英语句子保持不变,而法语每个句子都以
\t
开头,并以
\n
结尾。
#英文句子
line.split('\t')[0]
#中文句子
'\t' + line.split('\t')[1] + '\n'
构建词典
所谓词典,就是指在整个数据集中出现的所有
token
所构成的集合。该
token
可以是单词,也可以是字母。本文以字母作为
token
。所有的英文字符存储在
en_vocab
中,中文字符存储在
ch_vocab
中。词典一般使用
dictionary
数据类型,以英文为例子,英文的词典分为两个:
id2en
,其中的key
为词典的index
,而value
对应相应的英文字母en2id
,其中key
为英文字母,而value
为对应的词典index
例如: 1.id2en[0]
2.# out: a
3.en2id['a']
4.# out: 0
自然语言向量化
向量化后的自然语言语句,将被用于模型的输入。对自然语言的向量化,一种常用的方法是one-hot编码。 one-hot编码,又称“独热编码”。其实就是用N位状态寄存器编码N个状态,每个状态都有独立的寄存器位,且这些寄存器位中只有一位有效。 例如一个特征“性别”,性别有“男性”、“女性”,这个特征有两个特征值,也只有两个特征值,如果这个特征进行one-hot编码,则特征值为“男性”的编码为“10”,“女性”的编码为“01” 在代码片段中,使用
encoder_input_data
,
decoder_input_data
和
decoder_target_data
,分别来存储向量化的英文、中文和目标语言句子。以
encoder_input_data
为例:
# 三维数组,第一维度是数据集中的总句子数,第二维度为最长的
# 句子长度,最后一维度为字典的长度
encoder_input_data = np.zeros((len(en_num_data), max_encoder_seq_length, len(en2id)), dtype='float32')
# 向量化时,根据词典将0向量的相应位置置为1
for i in range(len(ch_num_data)):
for t, j in enumerate(en_num_data[i]):
encoder_input_data[i, t, j] = 1.
编程要求
根据提示,在右侧编辑器补充代码。完成数据的标准化处理、构建训练所用的语言词典并将语词转化为向量。
测试说明
平台会对你编写的代码进行测试: 测试输入: 1 预期输出(会输出对应测试输入的向量化数据):
英文数据:
['Hi.', 'Hi.', 'Run.', 'Wait!', 'Hello!']
中文数据:
['\t嗨。\n', '\t你好。\n', '\t你用跑的。\n', '\t等等!\n', '\t你好。\n']
数据读取完成
英文字典:
{' ': 0, '!': 1, "'": 2, '.': 3, '?': 4,...
中文字典:
{'\t': 0, '\n': 1, '!': 2, '。':...
字典构建完成
[[0. 0. 0. 0.....
向量化完成
开始你的任务吧,祝你成功!
第2关: 模型训练----搭建seq2seq训练模型
代码文件
import data_prepare
from keras.models import Model
from keras.layers import Input, LSTM, Dense, Embedding,concatenate,TimeDistributed,RepeatVector,Bidirectional
from keras.optimizers import Adam
EN_VOCAB_SIZE = 47
CH_VOCAB_SIZE = 147
HIDDEN_SIZE = 256
LEARNING_RATE = 0.003
BATCH_SIZE = 100
EPOCHS = 200
encoder_input_data, decoder_input_data,decoder_target_data,_,_,_ = data_prepare.getdata()
# ==============encoder=============
#########begin#########
# Encoder
encoder_inputs = Input(shape=(None, EN_VOCAB_SIZE))
encoder_LSTM = LSTM(HIDDEN_SIZE, return_sequences=True, return_state=True, name='encoder')
encoder_outputs, state_h, state_c = encoder_LSTM(encoder_inputs)
encoder_states = [state_h, state_c]
#########end#########
# # ==============decoder=============
#########begin#########
# Decoder
decoder_inputs = Input(shape=(None, CH_VOCAB_SIZE))
decoder_LSTM = LSTM(HIDDEN_SIZE, return_sequences=True, return_state=True, name='decoder')
decoder_outputs, _, _ = decoder_LSTM(decoder_inputs, initial_state=encoder_states)
decoder_dense = Dense(CH_VOCAB_SIZE, activation='softmax', name='dense')
decoder_outputs = decoder_dense(decoder_outputs)
#########end#########
#
#
model = Model([encoder_inputs, decoder_inputs], decoder_outputs)
opt = Adam(lr=LEARNING_RATE, beta_1=0.9, beta_2=0.999, epsilon=1e-08)
model.compile(optimizer=opt, loss='categorical_crossentropy', metrics=['accuracy'])
model.summary()
# model.fit([encoder_input_data, decoder_input_data], decoder_target_data,
# batch_size=BATCH_SIZE,
# epochs=EPOCHS,
# validation_split=0.2)
题目描述
任务描述
本关任务:准备好数据后,就要着手搭建训练模型了。本关将完成seq2seq模型的搭建和模型的训练。
相关知识
为了完成本关任务,你需要掌握: 1.seq2seq模型基本原理 2.搭建seq2seq模型 3.训练seq2seq模型
seq2seq模型基本原理
Seq2Seq模型是RNN最重要的一个变种,这种结构又叫Encoder-Decoder模型。 由于我们遇到的大部分问题序列都是不等长的,如机器翻译中,源语言和目标语言的句子往往并没有相同的长度。
为此,Encoder-Decoder结构先将输入数据编码成一个上下文向量,该上下文向量通常是Encoder的最后一个隐藏状态。 Decoder将该上下文向量作为输入,对其进行解码,输出相应的目标序列。 由于Encoder-Decoder结构不限制输入和输出的序列长度,因此应用的范围非常广泛,比如:机器翻译、文本摘要、阅读理解、语音识别等。
搭建seq2seq模型
Encoder模型
首先对模型的Encoder部分进行搭建,为此我们需要考虑3个方面:
- Encoder模型的输入是什么样子?
- Encoder模型使用怎样的RNN单元?
- 模型的哪部分作为Decoder的输入?
模型的输入可以使用Input来设定,输入的形状要与字典长度相同:
encoder_input = Input(shape=(None,len(vocabulary)))
本关模型使用LSTM单元,维度设置为
HIDDEN_SIZE
,
return_sequences
字段用来决控制是否需要每一步的输出,
return_states
用来控制是否输出隐藏层状态。
encoder_LSTM = LTM(HIDDEN_SIZE, return_sequences=True, return_state=True,name='encoder')
Encoder使用最后一层的隐藏状态,即
encoder_state_h
和
encoder_state_c
作为Decoder的输入:
encoder_h, encoder_state_h, encoder_state_c = encoder_LSTM (encoder_input)
Decoder模型
对Decoder部分进行搭建,我们需要考虑3个方面:
- Decoder模型的输入是什么样子?
- Decoder模型使用怎样的RNN单元?
- 模型的输出是怎样的结构?
前两步与Encoder相似,对于Decoder的输出,我们使用一个全连接层,并使用
softmax
激活函数将输出的向量映射到目标语言的字典上。
lstm = LSTM(HIDDEN_SIZE, return_sequences=True, return_state=True,name='decoder')
decoder_h, _, _ = lstm(decoder_inputs, initial_state=[encoder_state_h, encoder_state_c])
decoder_dense = Dense(CH_VOCAB_SIZE, activation='softmax',name='dense')
decoder_outputs = decoder_dense(decoder_h)
Decoder部分还可以使用注意力机制:
该方法通过一个
attention
层,将
Encoder
部分的每一步的输出与
decoder_inputs
联系起来作为
decoder
的输入。相当于根据序列的每个时间步将编码器编码为不同隐藏向量
c
,在解码时,结合每个不同的
c
进行解码输出,这样得到的结果会更加准确。在本实训中,请先掌握较为简单的普通
Decoder
结构。
训练seq2seq模型
训练模型时,我们用Model模块将Encoder和Decoder封装,并通过
optimizer
选择优化器,
loss
选择损失函数。
model = Model([encoder_inputs, decoder_inputs], decoder_outputs)
opt = Adam(lr=LEARNING_RATE, beta_1=0.9, beta_2=0.999, epsilon=1e-08)
model.compile(optimizer=opt, loss='categorical_crossentropy', metrics=['accu\fracy'])
模型在训练时,将之前预处理好的数据输入模型,并设置相应参数即可。
model.fit([encoder_input_data, decoder_input_data], decoder_target_data,
batch_size=BATCH_SIZE,
epochs=EPOCHS,
validation_split=0.2)
其中
x
为输入的数据,
y
为输出的数据。
batch_size
为每一批处理的序列数,
epochs
为训练的迭代次数,
validation_split
为训练集和验证集的比例。 ####编程要求
根据提示,在右侧编辑器补充代码,完成seq2seq模型的搭建和训练。
测试说明
平台会对你编写的代码进行测试:
模型结构与要求相符即可通过本关。
开始你的任务吧,祝你成功!
第3关:模型实践----搭建seq2seq推断模型
代码文件
import data_prepare
from keras.models import Model
from keras.layers import Input, LSTM, Dense, Embedding, concatenate, TimeDistributed, RepeatVector, Bidirectional
from keras.optimizers import Adam
import numpy as np
# Existing code for setting up the model
EN_VOCAB_SIZE = 47
CH_VOCAB_SIZE = 147
HIDDEN_SIZE = 256
LEARNING_RATE = 0.003
BATCH_SIZE = 100
EPOCHS = 100
encoder_input_data, decoder_input_data, decoder_target_data, ch2id, id2ch, en_data = data_prepare.getdata()
# ==============encoder=============
encoder_inputs = Input(shape=(None, EN_VOCAB_SIZE))
encoder_h, encoder_state_h, encoder_state_c = LSTM(HIDDEN_SIZE, return_sequences=True, return_state=True, name='encoder')(encoder_inputs)
# ==============decoder=============
decoder_inputs = Input(shape=(None, CH_VOCAB_SIZE))
decoder = LSTM(HIDDEN_SIZE, return_sequences=True, return_state=True, name='decoder')
decoder_dense = Dense(CH_VOCAB_SIZE, activation='softmax', name='dense')
decoder_h, _, _ = decoder(decoder_inputs, initial_state=[encoder_state_h, encoder_state_c])
decoder_outputs = decoder_dense(decoder_h)
model = Model([encoder_inputs, decoder_inputs], decoder_outputs)
opt = Adam(lr=LEARNING_RATE, beta_1=0.9, beta_2=0.999, epsilon=1e-08)
model.compile(optimizer=opt, loss='categorical_crossentropy', metrics=['accuracy'])
model.fit([encoder_input_data, decoder_input_data], decoder_target_data, batch_size=BATCH_SIZE, epochs=EPOCHS, validation_split=0.2, verbose=0)
# Encoder Inference Model
encoder_model = Model(encoder_inputs, [encoder_state_h, encoder_state_c])
# Decoder Inference Model
decoder_state_input_h = Input(shape=(HIDDEN_SIZE,))
decoder_state_input_c = Input(shape=(HIDDEN_SIZE,))
decoder_h, state_h, state_c = decoder(decoder_inputs, initial_state=[decoder_state_input_h, decoder_state_input_c])
decoder_outputs = decoder_dense(decoder_h)
decoder_model = Model([decoder_inputs, decoder_state_input_h, decoder_state_input_c], [decoder_outputs, state_h, state_c])
for k in range(40, 50):
test_data = encoder_input_data[k:k + 1]
h, c = encoder_model.predict(test_data)
target_seq = np.zeros((1, 1, CH_VOCAB_SIZE))
target_seq[0, 0, ch2id['\t']] = 1
outputs = []
while True:
output_tokens, h, c = decoder_model.predict([target_seq, h, c])
sampled_token_index = np.argmax(output_tokens[0, -1, :])
outputs.append(sampled_token_index)
if sampled_token_index == ch2id['\n'] or len(outputs) > 20:
break
target_seq = np.zeros((1, 1, CH_VOCAB_SIZE))
target_seq[0, 0, sampled_token_index] = 1
print(en_data[k])
print(''.join([id2ch[i] for i in outputs if i not in [ch2id['\t'], ch2id['\n']]])+'\n')
题目描述
任务描述
本关任务:本关将使用训练好的翻译模型,对英文句子进行翻译。
相关知识
为了完成本关任务,你需要掌握: 1.如何建立推断模型。 2.如何将模型的输出整理成最终翻译的结果
建立推断模型
推断模型的建立也分为两部分,模型Encoder部分的结构与训练时完全相同,因此只需要将原来的
encoder
部分封装起来即可:
# Encoder inference model
encoder_model = Model(encoder_inputs, [encoder_state_h, encoder_state_c])
而Decoder部分,需要将每一步的输出作为下一步的输入:
因此需要对Decoder部分重新设计。 首先确定Decoder部分的输入与输出,输入部分的大小应与Encoder输出的大小相同。
decoder_state_input_h = Input(shape=(HIDDEN_SIZE,))
decoder_state_input_c = Input(shape=(HIDDEN_SIZE,))
由于我们需要每一步的输出作为下一步的输入,因此需要将Decoder的隐藏状态和输出向量都存下来以备用。
decoder_h, state_h, state_c = decoder(decoder_inputs, initial_state=[decoder_state_input_h, decoder_state_input_c])
decoder_outputs = decoder_dense(decoder_h)
最后将Decoder的部分封装:
decoder_model = Model([decoder_inputs, decoder_state_input_h, decoder_state_input_c], [decoder_outputs, state_h, state_c])
输出整理
Decoder部分的输出是一个概率向量,它的每一位对应着字典中相应位置的概率,通常我们将输出向量中概率值最高的一位,作为预测的结果:
output_tokens, h, c= decoder_model.predict([target_seq, h, c])
sampled_token_index = np.argmax(output_tokens[0, -1, :])
在获得Encoder部分的输出后,我们需要设计一个程序结构,使得Decoder部分将每一步的输出送入下一步之中,并且当输出了终止符号或者超过最长输出序列长度(本实训中设置为20)时,停止程序。
while True:
output_tokens, h, c= decoder_model.predict([target_seq, h, c])
#...
target_seq = np.zeros((1, 1, CH_VOCAB_SIZE))
target_seq[0, 0, sampled_token_index] = 1
if sampled_token_index == ch2id['\n'] or len(outputs) > 20: break
编程要求
根据提示,在右侧编辑器补充代码,搭建推断模型,完成英语到法语的翻译模型。 ####测试说明
平台会对你编写的代码进行测试: 输入英文,输出相应的中文语句。 注意:本关需要运行模型,因此评测可能较慢,请耐心等待1-2分钟。
开始你的任务吧,祝你成功!
版权归原作者 「已注销」 所有, 如有侵权,请联系我们删除。