深度学习—神经网络基础原理及循环神经网络

前向传播(Forward)

为什么要有激活函数

这里用两层来代表多层的神经网络举例:第一层的输出是第二层的输入,其中MM的W*X矩阵乘法,ADD是向量加法即加上偏置,如果每一层都只有线性变换,那么最终无论多少层都可以化简成一层(见上图左边的公式),这样多层数就没有意义了,所以要在每一层都加上非线性函数即激活函数,才能保证每一层都有它独特的作用。

链式法则 

反向传播(Backward) 

  

当x是上一层的输出时也需要算,它这时就相当于是上一层的输出z一样。

损失L对z的偏导是从后面反向传播时传过来的,z对x的偏导是前面做前向传播时计算f这个函数时算出来的局部梯度。

下面举个具体例子:

比如在前向传播中,函数f=x*w,那么z对x的偏导为w,z对w的偏导为x,当传入的x=2,w=3时,输出z=x*w=6。

然后在反向传播中,我们拿到损失Loss,计算出L对z的偏导为5,接着计算出L对x的偏导为5*w即5*3=15,同理L对w的偏导为10,然后L对x的偏导的结果再继续往上一层传,这样每一层都通过对w的偏导就可以由此做权重w的更新了。

上面是前向和反向的整体流程,计算出loss对w的偏导就可以用梯度下降算法对w进行更新了。

上面是梯度下降算法的公式推导。

上面这个是随机梯度下降算法的公式。 

代码演示:

循环神经网络(RNN)

一般神经网络不能处理具有序列关系的数据,比如给一张图片用卷积神经网络然后输出该图片的类别,这个输出只跟该输入的图片有关,和之前输入了什么图片无关,这种就是没有序列关系的数据。而比如像自然语言,字词、语句之间存在明显的前后关系,这时就要用循环神经网络处理了。

RNN Cell就是一个线性变换层,上图右边的四个RNN Cell都是指同一个RNN Cell,其中h又叫hidden, 每次输入都是x_{i}与上一次的输出h_{i-1}一起放到RNN Cell里得出h_{i},然后到下一个序列的数据x_{i+1}又会与h_{i}一起得出h_{i+1},就这样循环往复,这样每次的输入都结合了上个序列的结果,体现了数据间的序列关系。

比如上图中有三层,第一层的RNN Cell接收的是原始的数据x和上个序列的输出h,第二层的RNN Cell接收的是上一层该序列的输出h和上个序列的输出h,第三层与第二层同理,以此类推。

实践举例

这里要求学习hello->ohlol的规律,其中Seq是序列的缩写。

具体实现代码 

import torch

input_size = 4
hidden_size = 3
batch_size = 1

#构建输入输出字典
idx2char_1 = ['e', 'h', 'l', 'o']
idx2char_2 = ['h', 'l', 'o']
x_data = [1, 0, 2, 2, 3]
y_data = [2, 0, 1, 2, 1]
# y_data = [3, 1, 2, 2, 3]
one_hot_lookup = [[1, 0, 0, 0],
                  [0, 1, 0, 0],
                  [0, 0, 1, 0],
                  [0, 0, 0, 1]]
#构造独热向量,此时向量维度为(SeqLen*InputSize)
x_one_hot = [one_hot_lookup[x] for x in x_data]
#view(-1……)保留原始SeqLen,并添加batch_size,input_size两个维度
inputs = torch.Tensor(x_one_hot).view(-1, batch_size, input_size)
#将labels转换为(SeqLen*1)的维度
labels = torch.LongTensor(y_data).view(-1, 1)

class Model(torch.nn.Module):
    def __init__(self, input_size, hidden_size, batch_size):
        super(Model, self).__init__()
        self.batch_size = batch_size
        self.input_size = input_size
        self.hidden_size = hidden_size

        self.rnncell = torch.nn.RNNCell(input_size = self.input_size,
                                        hidden_size = self.hidden_size)

    def forward(self, input, hidden):
        # RNNCell input = (batchsize*inputsize)
        # RNNCell hidden = (batchsize*hiddensize)
        hidden = self.rnncell(input, hidden)
        return hidden

    #初始化零向量作为h0,只有此处用到batch_size
    def init_hidden(self):
        return torch.zeros(self.batch_size, self.hidden_size)

net = Model(input_size, hidden_size, batch_size)

criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(net.parameters(), lr=0.1)

for epoch in range(15):
    #损失及梯度置0,创建前置条件h0
    loss = 0
    optimizer.zero_grad()
    hidden = net.init_hidden()

    print("Predicted string: ",end="")
    #inputs=(seqLen*batchsize*input_size) labels = (seqLen*1)
    #input是按序列取的inputs元素(batchsize*inputsize)
    #label是按序列去的labels元素(1)
    for input, label in zip(inputs, labels):
        hidden = net(input, hidden)
        #序列的每一项损失都需要累加
        loss += criterion(hidden, label)
        #多分类取最大
        _, idx = hidden.max(dim=1)
        print(idx2char_2[idx.item()], end='')

    loss.backward()
    optimizer.step()

    print(", Epoch [%d/15] loss = %.4f" % (epoch+1, loss.item()))
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北边一颗小星星

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值