这周主要学习seq2seq模型,先敲代码感受一下,之后会总结学习过程中学习到的理论知识。
1.获取数据
from keras.models import Model
from keras.layers import Input,LSTM,Dense,TimeDistributed
import numpy as np
import keras.backend as K
import re
def clean_text(text):#可以根据下面的characters再回来调整要替换的特殊字符,保证字母纯洁
text = re.sub(r'\n', ' ', text) #前一个参数由后一个参数取代,在text中
text = re.sub(r'[{}@_*>()\\#%+=\[\]]','', text)
text = re.sub('\xa0','', text)
text = re.sub( '\u2009','', text)
text = re.sub('\u202f','', text)
text = re.sub('\u2009','', text)
return text
#1.获取数据
data_path='fra.txt'
num_samples=10000
def get_dataset(data_path,num_samples):#数据地址,利用地址内的多少数据进行网络训练
input_texts=[]
target_texts=[]
input_characters = set()#含有的英文字母
target_characters = set()#含有的法文字母
with open(data_path,'r',encoding='utf-8') as f:
lines=f.read().split('\n')#读取所有行,作为列表元素存入lines
for line in lines[:min(num_samples,len(lines))]:#取所有样本或者固定数量样本数
input_text,target_text,_=line.split('\t')#用\t划分出英文,法文和无用数据
target_text='\t'+target_text+'\n'#target以\t作为第一输入,后面的输入由前面的预测作为输入
target_text=clean_text(target_text)
input_textt=clean_text(input_text)
input_texts.append(input_text)
target_texts.append(target_text)
#取出每一个英法字母,作为集合,将输入的每个单词的字母以onehot形式输入
for char in input_text:
if char not in input_characters:
input_characters.add(char)
for char in target_text:
if char not in target_characters:
target_characters.add(char)
return input_texts,target_texts,input_characters,target_characters
2.调整数据格式
#2.设置数据输入格式
batch_size=64
epochs=100
latent_dim=256#LSTM网络的神经元个数
input_texts,target_texts,input_characters,target_characters = get_dataset(data_path, num_samples)
max_input_length=max(len(txt) for txt in input_texts)
max_out_length=max(len(txt) for txt in target_texts)
input_characters = sorted(list(input_characters))
target_characters = sorted(list(target_characters))
num_encoder_tokens = len(input_characters)
num_decoder_tokens = len(target_characters)
print('一共有多少训练样本:', len(input_texts))
print('多少个英文字母:', num_encoder_tokens)
print('多少个法文字母:',num_decoder_tokens)
print('最大英文序列:', max_input_length)
print('最大法文序列:', max_out_length)
print(input_characters,target_characters)
#建立字母到数字的映射
input_token_index={char:i for i,char in enumerate(input_characters)}
target_token_index={char:i for i,char in enumerate(target_characters)}
#print(input_token_index)
#设置输入输出数据维度格式
encoder_input_data=np.zeros((len(input_texts),max_input_length,num_encoder_tokens),dtype='float32')#(10000,16,71)
decoder_input_data=np.zeros((len(input_texts),max_out_length,num_decoder_tokens),dtype='float32')#(10000,59,92)
decoder_target_data=np.zeros((len(input_texts),max_out_length,num_decoder_tokens),dtype='float32')#(10000,59,92)
#将数据放入固定格式中
for i ,(input_text,target_text) in enumerate(zip(input_texts,target_texts)):#遍历每一个单词
for t,char in enumerate(input_text):#遍历每一个字母
encoder_input_data[i,t,input_token_index[char]]=1.
encoder_input_data[i,t+1:,input_token_index[' ']]=1.#后面补空格
for t,char in enumerate(target_text):
decoder_input_data[i,t,target_token_index[char]]=1.#num_decoder_tokens
if t>0:
decoder_target_data[i,t-1,target_token_index[char]]=1.## decoder_target_data不num_decoder_tokens
decoder_input_data[i,t+1:,input_token_index[' ']]=1.
decoder_target_data[i, t:, target_token_index[' ']] = 1.
3.构建网络并训练
#构建网络
encoder_inputs=Input(shape=(None,num_encoder_tokens))#None其实是单词的最大长度,以此为网络的输入序列数,num_encoder_tokens是每个输入的维度
encoder_outputs,state_h,state_c=LSTM(latent_dim,return_state=True)(encoder_inputs)
encoder_states=[state_h,state_c]
decoder_inputs=Input(shape=(None,num_decoder_tokens))#None其实是单词的最大长度,设为None是因为后面实际预测时是一个字母一个字母的预测
decoder_outputs,_,_=LSTM(latent_dim,return_sequences=True,return_state=True)(decoder_inputs,initial_state=encoder_states)
decoder_outputs=TimeDistributed(Dense(num_decoder_tokens,activation='softmax'))(decoder_outputs)
model=Model([encoder_inputs,decoder_inputs],decoder_outputs)
model.summary()
#开始训练
model.compile(optimizer='rmsprop',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)
model.save('fra.h5')
K.clear_session()
4.开始实际预测
#开始实际预测使用
encoder_inputs=Input(shape=(None,num_encoder_tokens))
encoder_outputs,state_h,state_c=LSTM(latent_dim,return_state=True)(encoder_inputs)
encoder_states=[state_h,state_c]
encoder_model=Model(encoder_inputs,encoder_states)
encoder_model.load_weights('fra.h5',by_name=True)
encoder_model.summary()
decoder_inputs=Input(shape=(None,num_decoder_tokens))
decoder_state_input_h=Input(shape=(latent_dim,))#从encoder算出来的h
decoder_state_input_c=Input(shape=(latent_dim,))#从encoder算出来的c
decoder_states_inputs=[decoder_state_input_h,decoder_state_input_c]
decoder_outputs,state_h,state_c=LSTM(latent_dim,return_sequences=True,return_state=True)(decoder_inputs,initial_state=decoder_states_inputs)
decoder_states=[state_h,state_c]
decoder_outputs=TimeDistributed(Dense(num_decoder_tokens,activation='softmax'))(decoder_outputs)#每个输出连接一个Dense,算出此输出位置哪个字母的概率最大
decoder_model=Model([decoder_inputs]+decoder_states_inputs,[decoder_outputs]+decoder_states)
decoder_model.load_weights('fra.h5',by_name=True)
#将预测结果进行解码
num2char_input={i:char for i,char in enumerate(input_characters)}
num2char_target={i:char for i,char in enumerate(target_characters)}
def decoder_sequence(input_seq):
states_value=encoder_model.predict(input_seq)#将要翻译的单词输入encoder进行预测输出
target_seq=np.zeros((1,1,num_decoder_tokens))#输出的shape,
target_seq[0,0,target_token_index['\t']]=1#decoder的第一个输入是'\t'(化成onehot形式)
stop_condition=False
decoder_sentence=''
while not stop_condition:
output_token,h,c=decoder_model.predict([target_seq]+states_value)#将'\t‘和encoder的输出作为decoder的输入,预测下一个字母的输出
sample_tokend_index=np.argmax(output_token[0,-1,:])#取出字母概率最大的哪个位置的下标
sample_char=num2char_target[sample_tokend_index]#取出那个字母
decoder_sentence+=sample_char#将字母添加到输出字符串
if (sample_char=='\n' or len(decoder_sentence)>=max_out_length):
stop_condition=True
states_value=[h,c]#decode对上一个字母预测后的预测输出
target_seq=np.zeros((1,1,num_decoder_tokens))
target_seq[0,0,sample_tokend_index]=1
return decoder_sentence
for seq_index in range(60):
input_seq=np.expand_dims(encoder_input_data[seq_index],axis=0)
decoder_sentence=decoder_sequence(input_seq)
print('-')
print('Input sentence:', input_texts[seq_index])
print('Decoded sentence:', decoder_sentence)
参考:https://blog.csdn.net/weixin_44791964/article/details/103988481