RNN|代码详解:用Python构建RNN模拟人脑( 二 )


将刚刚生成的正弦波可视化:
plt.plot(sin_wave[:50])
RNN|代码详解:用Python构建RNN模拟人脑文章插图
我们将在下面的代码块中创建数据:
X = []
Y = []
seq_len = 50
num_records = len(sin_wave) - seq_len
for i in range(num_records - 50):
X.append(sin_wave[i:i+seq_len])
Y.append(sin_wave[i+seq_len])
X = np.array(X)
X = np.expand_dims(X, axis=2)
Y = np.array(Y)
Y = np.expand_dims(Y, axis=1)
打印数据的形状:
X.shape, Y.shape
((100, 50, 1), (100, 1))
请注意 , 我们为(num_records - 50)循环 , 因为我们想要留出50条记录作为验证数据 。 我们现在可以创建此验证数据:
X_val = []
Y_val = []
for i in range(num_records - 50, num_records):
X_val.append(sin_wave[i:i+seq_len])
Y_val.append(sin_wave[i+seq_len])
X_val = np.array(X_val)
X_val = np.expand_dims(X_val, axis=2)
Y_val = np.array(Y_val)
Y_val = np.expand_dims(Y_val, axis=1)
步骤1:为RNN模型创建架构
下一个任务是定义将在RNN模型中使用的所有必要变量和函数 。 我们的模型将接受输入序列 , 通过100个单位的隐藏层处理它 , 并产生单值输出:
learning_rate = 0.0001
nepoch = 25
T = 50 # length of sequence
hidden_dim = 100
output_dim = 1
bptt_truncate = 5
min_clip_value = http://kandian.youth.cn/index/-10
max_clip_value = http://kandian.youth.cn/index/10
然后我们将定义网络的权重:
U = np.random.uniform(0, 1, (hidden_dim, T))
W = np.random.uniform(0, 1, (hidden_dim, hidden_dim))
V = np.random.uniform(0, 1, (output_dim, hidden_dim))
在这里 ,
· U是输入和隐藏图层之间权重的权重矩阵
· V是隐藏层和输出层之间权重的权重矩阵
· W是RNN层(隐藏层)中共享权重的权重矩阵
最后 , 我们将定义要在隐藏层中使用的激活函数sigmoid:
def sigmoid(x):
return 1 / (1 + np.exp(-x))
步骤2:训练模型
既然我们已经定义了模型 , 终于可以继续训练序列数据了 。 我们可以将培训过程细分为更小的步骤 , 即:
· 步骤 2.1 : 检查训练数据中的损失
· 步骤 2.1.1 : 前向传播
· 步骤 2.1.2 : 计算错误
· 步骤 2.2 : 检查验证数据的损失
· 步骤 2.2.1 : 前向传播
· 步骤 2.2.2 : 计算错误
· 步骤 2.3 : 开始真正的训练
· Step 2.3.1 : 前向传播
· Step 2.3.2 : 反向传播错误
· Step 2.3.3 : 更新权重
我们需要重复这些步骤直到结束 。 如果模型开始过度装备 , 请停止!或者只是预先定义epoch的数量 。
步骤2.1:检查训练数据中的损失
我们将通过RNN模型进行前向传递 , 并计算所有记录的预测的平方误差 , 以获得损失值 。
for epoch in range(nepoch):
# check loss on train
loss = 0.0
# do a forward pass to get prediction
for i in range(Y.shape[0]):
x, y = X[i], Y[i] # get input, output values of each record
prev_s = np.zeros((hidden_dim, 1)) # here, prev-s is the value of the previous activation of hidden layer; which is initialized as all zeroes
for t in range(T):
new_input = np.zeros(x.shape) # we then do a forward pass for every timestep in the sequence
new_input[t] = x[t] # for this, we define a single input for that timestep
mulu = np.dot(U, new_input)
mulw = np.dot(W, prev_s)
add = mulw + mulu
s = sigmoid(add)
mulv = np.dot(V, s)
prev_s = s
# calculate error
loss_per_record = (y - mulv)**2 / 2
loss += loss_per_record
loss = loss / float(y.shape[0])
步骤2.2:检查验证数据的损失
我们将对计算验证数据的损失(在同一循环中)做同样的事情:
# check loss on val
val_loss = 0.0
for i in range(Y_val.shape[0]):
x, y = X_val[i], Y_val[i]
prev_s = np.zeros((hidden_dim, 1))
for t in range(T):
new_input = np.zeros(x.shape)
new_input[t] = x[t]
mulu = np.dot(U, new_input)
mulw = np.dot(W, prev_s)
add = mulw + mulu
s = sigmoid(add)
mulv = np.dot(V, s)
prev_s = s
loss_per_record = (y - mulv)**2 / 2
val_loss += loss_per_record
val_loss = val_loss / float(y.shape[0])
print('Epoch: ', epoch + 1, ', Loss: ', loss, ', Val Loss: ', val_loss)
你应该得到以下输出:
Epoch: 1 , Loss: [[101185.61756671]] , Val Loss: [[50591.0340148]]
...
...
步骤2.3:开始实际培训
我们现在开始对网络进行实际培训 。 在这里 , 首先进行前向传递以计算误差 , 然后使用后向传递来计算梯度并进行更新 。
步骤2.3.1:正向传递在正向传递中:
· 首先将输入与输入和隐藏层之间的权重相乘
· 在RNN层中添加权重乘以此项 。 因为我们希望捕获前一个时间步的知识