用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
deck
By q8745912
deck
- 129