循环神经网络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')