循环神经网络RNN
循环
input层
hidden层
output层
传统神经网络是从输入层到隐含层再到输出层的全连接,网络的传播是顺序的,且同层的节点之间无连接。这种网络几乎没有时序相关推理的能力,在文章生成、语音识别领域显得无能为力。
而RNN是一种循环神经网络,它可以保存上一节点输出的信息并向同层节点共享数据,通过对之前信息的记忆增加预测推理的参考。
RNN算法包含普通循环神经网络,双向循环神经网络等,本文仅实现普通RNN网络生成短句。
代码
开发环境:python3.9
库:tensorflow2,numpy,cv2
# index > value index2char = {0:"a",1:"b",2:"c"}
index2char = dict((i, c) for i, c in enumerate(chars)) # 同上
SEQLEN = 10 # 输入序列的长度
STEP = 1 # 输入序列在整个时间序列数据上的跨度,滑动的步长
# 举个例子:假设整个序列是abcdefghijklmnopqrstuvw。
# 字符和标签
input_chars = []
label_chars = []
# 按seqlen的长度,逐步将所有字符分割成 len(文档中所有字符长度) - squlen(输入序列长度)个块并存入input_chars数组 label_chars存储最后一个字符
# 每隔一个字符,就保存一次。比如 abcdefg abc,bcd,cde,def,efg 这样保存。
for i in range(0, len(text) - SEQLEN, STEP): # i=0;i <(训练字符总长度 - 输入序列长度);i+=STEP
input_chars.append(text[i:i + SEQLEN]) # 获取text 从i开始到i+seqlen为止(不包含i + seqlen),中间的这些字符,存入input集合中
label_chars.append(text[i + SEQLEN]) # label就是text【i+seqlen】最后一个字符
# 通过one-hot编码来向量化input和label,
X = np.zeros((len(input_chars), SEQLEN, chars_count), dtype=np.bool) # 全部的标签长度,输入长度10,所有词汇长度,布尔 即是说这是由01组成的矩阵
Y = np.zeros((len(input_chars), chars_count), dtype=np.bool) # 全部标签长度,所有词汇长度,布尔
for i, input_char in enumerate(input_chars):
for j, c in enumerate(input_char):
X[i, j, char2index[c]] = 1
Y[i, char2index[label_chars[i]]] = 1
# 给训练好的模型一个随机的时间序列输入,得到一个字符的输出
# 然后去掉输入的第一个字符,加上那个输出的一个字符,当作新的序列输入
# 构建网络
model = tf.keras.models.Sequential([
# simpleRNN 输入为:inputshape(SEQLEN = 10,charcount =1) (输入序列的长度、字符总数)
tf.keras.layers.SimpleRNN(128, return_sequences=False, input_shape=(SEQLEN, chars_count), unroll=True),
tf.keras.layers.Dense(chars_count, activation='softmax')
])
# 定义损失函数和优化器
model.compile(loss="categorical_crossentropy", optimizer="rmsprop")
# 获取模型 重复训练
if os.path.isfile(os.path.join('/', 't1.h5')):
model = tf.keras.models.load_model('t1.h5')
# 按指定次数训练模型 (此处训练25次)
for iteration in range(25):
# 打印当前训练进程
print('Iteration : %d' % iteration)
# 每十轮保存一次模型
if iteration % 10 == 0:
model.save('t1.h5')
print("mdoel saved")
# 训练
model.fit(X, Y, batch_size=128, epochs=1)
# 测试
test_idx = np.random.randint(len(input_chars)) # 测试index
test_chars = input_chars[test_idx] # 测试字符
print('test seed is : %s' % test_chars)
print(test_chars, end='') # ''换行, ' '空格, '1'字符1
# 按指定次数生成新字符
for i in range(300):
# 测试序列向量化
vec_test = np.zeros((1, SEQLEN, chars_count))
for i, ch in enumerate(test_chars):
vec_test[0, i, char2index[ch]] = 1
# 预测
pred = model.predict(vec_test, verbose=0)[0]
pred_char = index2char[np.argmax(pred)]
print(pred_char, end='')
# 不断的加入新生成字符组成新的序列
test_chars = test_chars[1:] + pred_char
print('\n')