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步:为我们的循环神经网络模型创建架构**
我们接来下的任务是将我们在循环神经网络模型中使用的所有必要变量和函数进行定义。我们的循环神经网络模型将接受输入序列,通过100个单位的隐藏层处理它,并产生单值输出:
learning_rate = 0.0001
nepoch = 25
T = 50 # length of sequence
hidden_dim = 100
output_dim = 1
bptt_truncate = 5
min_clip_value = -10
max_clip_value = 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**是循环神经网络层(隐藏层)中共享权重的权重矩阵
最后,我们将定义在隐藏层中使用S型函数:
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:\*\*开始实际训练
>
>
> 步骤2.3.1:正推法
>
>
> 步骤2.3.2:反向传递误差
>
>
> 步骤2.3.3:更新权重
>
>
>
我们需要重复这些步骤直到数据收敛。 如果模型开始过拟合,请停止! 或者只是预先定义epoch的数量。
* \*\*步骤2.1:\*\*检查训练数据是否丢失
我们将通过我们的循环神经网络模型进行正推法,并计算所有记录的预测的平方误差,以获得损失值。
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:\*\*正推法
正推法步骤如下:
>
> 1. 我们首先将输入与输入和隐藏层之间的权重相乘;
> 2. 在循环神经网络层中添加权重乘以此项,这是因为我们希望获取前一个时间步的内容;
> 3. 通过sigmoid 激活函数将其与隐藏层和输出层之间的权重相乘;
> 4. 在输出层,我们对数值进行线性激活,因此我们不会通过激活层传递数值;
> 5. 在字典中保存当前图层的状态以及上一个时间步的状态。
>
>
>
这是执行正推法的代码(请注意,它是上述循环的继续):
train model
for i in range(Y.shape[0]):
x, y = X[i], Y[i]
layers = []
prev_s = np.zeros((hidden_dim, 1))
dU = np.zeros(U.shape)
dV = np.zeros(V.shape)
dW = np.zeros(W.shape)
dU_t = np.zeros(U.shape)
dV_t = np.zeros(V.shape)
dW_t = np.zeros(W.shape)
dU_i = np.zeros(U.shape)
dW_i = np.zeros(W.shape)
# forward pass
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)
layers.append({'s':s, 'prev_s':prev_s})
prev_s = s
* \*\*步骤2.3.2:\*\*反向传播误差
在前向传播步骤之后,我们计算每一层的梯度,并反向传播误差。 我们将使用截断反向传播时间(TBPTT),而不是vanilla backprop(反向传播的非直观效应的一个例子)。这可能听起来很复杂但实际上非常直接。
BPTT与backprop的核心差异在于,循环神经网络层中的所有时间步骤,都进行了反向传播步骤。 因此,如果我们的序列长度为50,我们将反向传播当前时间步之前的所有时间步长。
如果你猜对了,那么BPTT在计算上看起来非常昂贵。 因此,我们不是反向传播所有先前的时间步,而是反向传播直到x时间步以节省计算能力。考虑这在概念上类似于随机梯度下降,我们包括一批数据点而不是所有数据点。
以下是反向传播误差的代码:
derivative of pred
dmulv = (mulv - y)
# backward pass
for t in range(T):
dV_t = np.dot(dmulv, np.transpose(layers[t]['s']))
dsv = np.dot(np.transpose(V), dmulv)
ds = dsv
dadd = add * (1 - add) * ds
dmulw = dadd * np.ones_like(mulw)
dprev_s = np.dot(np.transpose(W), dmulw)
for i in range(t-1, max(-1, t-bptt_truncate-1), -1):
ds = dsv + dprev_s
dadd = add * (1 - add) * ds
dmulw = dadd * np.ones_like(mulw)
dmulu = dadd * np.ones_like(mulu)
dW_i = np.dot(W, layers[t]['prev_s'])
dprev_s = np.dot(np.transpose(W), dmulw)
new_input = np.zeros(x.shape)
new_input[t] = x[t]
dU_i = np.dot(U, new_input)
dx = np.dot(np.transpose(U), dmulu)
dU_t += dU_i
dW_t += dW_i
dV += dV_t
dU += dU_t
dW += dW_t
* \*\*步骤2.3.3:\*\*更新权重
最后,我们使用计算的权重梯度更新权重。 有一件事我们必须记住,如果不对它们进行检查,梯度往往会爆炸。这是训练神经网络的一个基本问题,称为梯度爆炸问题。 所以我们必须将它们夹在一个范围内,这样它们就不会增长得太快。 我们可以这样做:
if dU.max() > max_clip_value:
dU[dU > max_clip_value] = max_clip_value
if dV.max() > max_clip_value:
dV[dV > max_clip_value] = max_clip_value
if dW.max() > max_clip_value:
dW[dW > max_clip_value] = max_clip_value
if dU.min() < min_clip_value:
dU[dU < min_clip_value] = min_clip_value
if dV.min() < min_clip_value:
dV[dV < min_clip_value] = min_clip_value
if dW.min() < min_clip_value:
dW[dW < min_clip_value] = min_clip_value
# update
U -= learning_rate * dU
V -= learning_rate * dV
W -= learning_rate * dW
在训练上述模型时,我们得到了这个输出:
>
> Epoch: 1 , Loss: [[101185.61756671]] , Val Loss: [[50591.0340148]]
>
>
> Epoch: 2 , Loss: [[61205.46869629]] , Val Loss: [[30601.34535365]]
>
>
> Epoch: 3 , Loss: [[31225.3198258]] , Val Loss: [[15611.65669247]]
>
>
> Epoch: 4 , Loss: [[11245.17049551]] , Val Loss: [[5621.96780111]]
>
>
> Epoch: 5 , Loss: [[1264.5157739]] , Val Loss: [[632.02563908]]
>
>
> Epoch: 6 , Loss: [[20.15654115]] , Val Loss: [[10.05477285]]
>
>
> Epoch: 7 , Loss: [[17.13622839]] , Val Loss: [[8.55190426]]
>
>
> Epoch: 8 , Loss: [[17.38870495]] , Val Loss: [[8.68196484]]
>
>
> Epoch: 9 , Loss: [[17.181681]] , Val Loss: [[8.57837827]]
>
>
> Epoch: 10 , Loss: [[17.31275313]] , Val Loss: [[8.64199652]]
>
>
> Epoch: 11 , Loss: [[17.12960034]] , Val Loss: [[8.54768294]]
>
>
> Epoch: 12 , Loss: [[17.09020065]] , Val Loss: [[8.52993502]]
>
>
> Epoch: 13 , Loss: [[17.17370113]] , Val Loss: [[8.57517454]]
>
>
> Epoch: 14 , Loss: [[17.04906914]] , Val Loss: [[8.50658127]]
>
>
> Epoch: 15 , Loss: [[16.96420184]] , Val Loss: [[8.46794248]]
>
>
> Epoch: 16 , Loss: [[17.017519]] , Val Loss: [[8.49241316]]
>
>
> Epoch: 17 , Loss: [[16.94199493]] , Val Loss: [[8.45748739]]
>
>
> Epoch: 18 , Loss: [[16.99796892]] , Val Loss: [[8.48242177]]
>
>
> Epoch: 19 , Loss: [[17.24817035]] , Val Loss: [[8.6126231]]
>
### 最后
Python崛起并且风靡,因为优点多、应用领域广、被大牛们认可。学习 Python 门槛很低,但它的晋级路线很多,通过它你能进入机器学习、数据挖掘、大数据,CS等更加高级的领域。Python可以做网络应用,可以做科学计算,数据分析,可以做网络爬虫,可以做机器学习、自然语言处理、可以写游戏、可以做桌面应用…Python可以做的很多,你需要学好基础,再选择明确的方向。这里给大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!
#### 👉Python所有方向的学习路线👈
Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。
![](https://img-blog.csdnimg.cn/img_convert/604bae65027d4d67fb62410deb210454.png)
#### 👉Python必备开发工具👈
工欲善其事必先利其器。学习Python常用的开发软件都在这里了,给大家节省了很多时间。
![](https://img-blog.csdnimg.cn/img_convert/fa276175617e0048f79437bd30465479.png)
#### 👉Python全套学习视频👈
我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了。
![](https://img-blog.csdnimg.cn/img_convert/16ac689cb023166b2ffa9c677ac40fc0.png)
#### 👉实战案例👈
学python就与学数学一样,是不能只看书不做题的,直接看步骤和答案会让人误以为自己全都掌握了,但是碰到生题的时候还是会一筹莫展。
因此在学习python的过程中一定要记得多动手写代码,教程只需要看一两遍即可。
![](https://img-blog.csdnimg.cn/img_convert/0d8c31c50236a205928a1d8ae8a0b883.png)
#### 👉大厂面试真题👈
我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。
![](https://img-blog.csdnimg.cn/img_convert/99461e47e58e503d2bc1dc6f4668534a.png)
**[需要这份系统化学习资料的朋友,可以戳这里无偿获取](https://bbs.csdn.net/topics/618317507)**
**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**