用Keras實現文本生成

講者:琪雅

時間:2020/5/24

導入需要用到的模塊

from __future__ import print_function
from keras.layers import Dense, Activation
from keras.layers.recurrent import SimpleRNN
from keras.models import Sequential
import numpy as np

讀取文件,並將文件內容解碼為ASCII碼

  • "rb":二進制讀方式打開,只能讀文件, 如果文件不存在,會發生異常
fin = open('alice_in_wonderland.txt', 'rb')

為了要每次讀一行進行轉碼,我們要寫個程式

  • strip() 方法用於移除字符串頭尾指定的字符。
  • lower() 方法轉換字符串中所有大寫字符為小寫。
  • decode的作用是轉碼,ignore指忽略異常

 

lines = []
for line in fin:		
	line = line.strip().lower()
	line = line.decode('ascii', 'ignore')
	if len(line) == 0:
		continue
	lines.append(line)
fin.close()
text = ' '.join(lines)

構建字符到索引之間的映射關係

  • 獲取字符串中不同字符組成的集合
  • 獲取集合中不同元素數量
  • 創建字符到索引的字典
  • 創建索引到字符的字典
chars = set([c for c in text])
nb_chars = len(chars)		
char2index = dict((c, i) for i, c in enumerate(chars))
index2char = dict((i, c) for i, c in enumerate(chars))

創建標籤和輸入文本

  • 在機器學習中,超參數是在學習過程開始之前設置其值的參數
  • 先設定超參數,決定輸入字符串長度
  • 決定輸出字符串長度
  • 創立輸入字符串列表和標籤列表
  • 然後輸入文本
    • append() 方法用於在列表末尾添加新的對象。
SEQLEN = 10		
STEP = 1		
input_chars = []		
label_chars = []	
for i in range(0, len(text) - SEQLEN, STEP):
	input_chars.append(text[i: i + SEQLEN])
	label_chars.append(text[i + SEQLEN])

將輸入和標籤文本向量化

文本轉化為電腦認識的形式

One-Hot編碼,又稱為一位有效編碼,主要是采用位狀態寄存器來對個狀態進行編碼,每個狀態都由他獨立的寄存器位,並且在任意時候只有一位有效。

 

有如下三個特征屬性:
性別:["male","female"]
地區:["Europe","US","Asia"]
瀏覽器:["Firefox","Chrome","Safari","Internet Explorer"]

["male","US","Internet Explorer"] = [0,1,3]

= [1,0,0,1,0,0,0,0,1]

將輸入和標籤文本向量化 

  • 輸入文本數量
  • 標籤文本數
  • 對每個輸入文本進行向量化

 

X = np.zeros((len(input_chars), SEQLEN, nb_chars), dtype=np.bool)	
Y = np.zeros((len(input_chars), nb_chars), dtype=np.bool)		
for i, input_char in enumerate(input_chars):		
	for j, ch in enumerate(input_char):	
		X[i, j, char2index[ch]] = 1
	Y[i, char2index[label_chars[i]]] = 1

構建網絡 

確立Input格式、要經過幾層處理、每一層要作甚麼處理

HIDDEN_SIZE = 128
BATCH_SIZE = 128
NUM_ITERATIONS = 25
NUM_EPOCH_PER_ITERATIONS = 1
NUM_PREDS_PER_EPOCH = 100

model = Sequential()
model.add(SimpleRNN(HIDDEN_SIZE, return_sequences=False, input_shape=(SEQLEN, nb_chars), unroll=True))
model.add(Dense(nb_chars))
model.add(Activation('softmax'))

編譯模型

  • 以compile函數定義損失函數(loss)、優化函數(optimizer)
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')

訓練模型

for iteration in range(NUM_ITERATIONS):
	print('=' * 50)
	print('Iteration #: %d' % (iteration))
	model.fit(X, Y, batch_size=BATCH_SIZE, epochs=NUM_EPOCH_PER_ITERATIONS)
	test_idx = np.random.randint(len(input_chars))
	test_chars = input_chars[test_idx]
	print('Generating from seed: %s' % (test_chars))
	print(test_chars, end='')	
	for i in range(NUM_PREDS_PER_EPOCH):
		Xtest = np.zeros((1, SEQLEN, nb_chars))
		for i, ch in enumerate(test_chars):
			Xtest[0, i, char2index[ch]] = 1	
		ypred = index2char[model.predict_classes(Xtest)[0]]
		print(ypred, end='')
		test_chars = test_chars[1:] + ypred
print()

完整程式碼

from __future__ import print_function
from keras.layers import Dense, Activation
from keras.layers.recurrent import SimpleRNN
from keras.models import Sequential
import numpy as np

# 读取文件,并将文件内容解码为ASCII码
fin = open('alice_in_wonderland.txt', 'rb')
lines = []		#
for line in fin:		# 遍历每行数据
	line = line.strip().lower()		# 去除每行两端空格
	line = line.decode('ascii', 'ignore')		# 解码为ASCII码
	if len(line) == 0:
		continue
	lines.append(line)
fin.close()
text = ' '.join(lines)

chars = set([c for c in text])		# 获取字符串中不同字符组成的集合
nb_chars = len(chars)		# 获取集合中不同元素数量
char2index = dict((c, i) for i, c in enumerate(chars))		# 创建字符到索引的字典
index2char = dict((i, c) for i, c in enumerate(chars))		# 创建索引到字符的字典

SEQLEN = 10		# 超参数,输入字符串长度
STEP = 1		# 输出字符串长度
input_chars = []		# 输入字符串列表
label_chars = []		# 标签列表
for i in range(0, len(text) - SEQLEN, STEP):
	input_chars.append(text[i: i + SEQLEN])
	label_chars.append(text[i + SEQLEN])

# 将输入文本和标签文本向量化: one-hot编码
X = np.zeros((len(input_chars), SEQLEN, nb_chars), dtype=np.bool)		# 输入文本张量
Y = np.zeros((len(input_chars), nb_chars), dtype=np.bool)		# 标签文本张量
for i, input_char in enumerate(input_chars):		# 遍历所有输入样本
	for j, ch in enumerate(input_char):		# 对于每个输入样本
		X[i, j, char2index[ch]] = 1
	Y[i, char2index[label_chars[i]]] = 1

# 构建模型
HIDDEN_SIZE = 128
BATCH_SIZE = 128
NUM_ITERATIONS = 25
NUM_EPOCH_PER_ITERATIONS = 1
NUM_PREDS_PER_EPOCH = 100

model = Sequential()
model.add(SimpleRNN(HIDDEN_SIZE, return_sequences=False, input_shape=(SEQLEN, nb_chars), unroll=True))
model.add(Dense(nb_chars))
model.add(Activation('softmax'))


# 编译模型
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')

for iteration in range(NUM_ITERATIONS):
	print('=' * 50)
	print('Iteration #: %d' % (iteration))		# 打印迭代次数
	# 训练模型
	model.fit(X, Y, batch_size=BATCH_SIZE, epochs=NUM_EPOCH_PER_ITERATIONS)		# 每次迭代训练一个周期
	# 使用模型进行预测
	test_idx = np.random.randint(len(input_chars))		# 随机抽取样本
	test_chars = input_chars[test_idx]
	print('Generating from seed: %s' % (test_chars))
	print(test_chars, end='')		# 不换行输出
	for i in range(NUM_PREDS_PER_EPOCH):		# 评估每一次迭代后的结果
		Xtest = np.zeros((1, SEQLEN, nb_chars))
		for i, ch in enumerate(test_chars):
			Xtest[0, i, char2index[ch]] = 1		# 样本张量
		# pred = model.predict(Xtest, verbose=0)[0]
		# ypred = index2char[np.argmax(pred)]		# 找对类别标签对应的字符
		ypred = index2char[model.predict_classes(Xtest)[0]]
		print(ypred, end='')
		# 使用test_chars + ypred继续
		test_chars = test_chars[1:] + ypred
print()

Thank you for listening.

References

用Keras實現SimpleRNN:生成文本-CSDN博客

https://blog.csdn.net/tszupup/article/details/85930383

 

Day 14:循環神經網路(Recurrent Neural Network, RNN)-IT邦幫忙

https://ithelp.ithome.com.tw/articles/10193469

 

Made with Slides.com