【 反向传播算法 Back-Propagation 数学推导以及源码详解 深度学习 Pytorch笔记 B站刘二大人(3/10)】

14 篇文章 0 订阅
11 篇文章 0 订阅

反向传播算法 Back-Propagation 数学推导以及源码详解 深度学习 Pytorch笔记 B站刘二大人(3/10)

数学推导

BP算法 BP神经网络可以说机器学习的最基础网络。对于普通的简单的神经网络层,我们还能通过推导计算得到梯度表达式,但是当网络结构如下图所示
在这里插入图片描述
此时梯度grad就变成了非常庞大的计算量,对于复杂的多层级网络,权重w个数多,无法直接对权重w进行解析式求导。面对这种情况我们引入数据结构中的图的概念,通过形成计算图在图上传播梯度利用链式法则对各个节点的梯度进行求解。
在这里插入图片描述
需要注意的是,基础线性单元(一层)的构成,应该以矩阵思维看待,w权重矩阵+b偏置量,将参数和输入输出都视为向量或者矩阵。Matrix cookbook 是主要矩阵运算的参考资料,可以去查阅。
在这里插入图片描述
由于各个层都是线性关系,而线性映射之间可以进行线性拼接和化简,会导致多个线性层直接连接与单一线性层的功能相同无法表示足够的网络复杂程度。在此引入激活函数概念,在各个层之间连接处加入激活函数Sigmoid
在这里插入图片描述
在每一线性层后加上激活函数Nonliner Function,激活函数的本质是非线性映射
eg: sigmoid: x -> 1/1+e^(-x1)
之后通过链式法则,累计求导,实际上就是高数中的复合函数求导和求偏导的相关知识,如下图
在这里插入图片描述
梯度计算过程,首先前馈计算出loss函数,之后根据loss函数,之后反向求loss与输出Z导数,由于Z由输入x和权重w的复合组成,因此可以求出loss与x和w的导数,根据loss的意义,loss最小则模型达到最优,而x输入为固定,则根据w关于loss导数动态调整w进行更新即可得到最新的loss
细节:在多层的运算过程中一般会将求导的导数存储在层单元中,pytorch是将导数存储在输入单元x中,而非运算模块f=x*w中
下图是Forward与backward具体流程推导,其中注意wx与wx+b的区别
在这里插入图片描述
在这里插入图片描述
Pytorch基本数据类型tensor,用于储存所有数值(标量,向量,矩阵,高维矩阵),主要成员:data保存权重本身值+grad损失函数对权重的导数

源码解读与实现

在这里插入图片描述
编程细节,在进行数据类型定义的时候将w的tensor数据类型中求导的标识符定义为真**(tensor数据类型默认不进行梯度求导以节省运算)**
在这里插入图片描述
此时,运算符重载,进行tensor与tensor之间的乘法运算,将x自动进行数据转化变换为tensor类型,同时该计算模块由于内部成员w是需要进行梯度计算的tensor类型x,则该计算模块x*w也自动将梯度计算的表示符转化为true
需要注意的是,在tensor的计算中是按照图的形式进行生成,每进行一次调用和运行,就动态生成一次计算图

  1. .backward()函数将整条计算链上的梯度全部进行计算并存储**,在进行一次backward后,将之前生成的计算图进行清除释放**
  2. .data运算,通过.data运算是直接运算其中的存储数据进行标量计算,而不构建计算图,如果使用w直接进行计算将在运算过程中构建计算图,产生大量冗余计算。
    3.在计算中不可以定义sum使用sum += l将loss值累加,同样因为l为张量,在与标量sum进行计算的过程中将生成计算图,产生冗余运算。如使用需要使用语句 sum += l.item()

整体代码

import torch

x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0 ,6.0]

w = torch.Tensor([1.0]) # 预测模型的参数w应当作为tensor量进行定义
w.requires_grad = True # 将tensor中的求导标识符定义为True,默认为False

def forward(x):
    return x * w    # 注意:此时由于w是tensor张量,在进行乘法时自动讲x转换为张量,进行张量乘法

def loss(x,y):
    y_pred = forward(x) #调用forward函数计算预测值
    return (y_pred - y)**2 #返回损失

print("predict (before training)", 4, forward(4).item()) # 输出未训练的结果

for epoch in range(100):
    for x,y in zip(x_data, y_data):
        l = loss(x,y)   #计算损失函数
        l.backward()    #计算梯度,注意此时进行的是计算图运算
        print("\t grad:", x, y, w.grad.item())  # w属于张量,运算将生成计算图,因此用item函数调用标量数据
        w.data = w.data - 0.01 * w.grad.item()

        w.grad.data.zero_()     #梯度清零

    print("progress:", epoch, l.item())

print("predict (after training)", 4, forward(4).item()) #输出训练预测值

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
反向传播算法(Backpropagation)是一种用于训练神经网络的常见优化算法。它通过计算损失函数相对于每个参数的梯度,并使用梯度下降来更新参数。下面我将给出反向传播算法的公式推导及示例代码。 1. 反向传播算法公式推导: 首先,定义神经网络的损失函数为L,该函数是由网络输出和真实标签之间的差异计算得出。假设神经网络有多个隐藏层,每个隐藏层的参数为W和b。 1.1 前向传播: 首先,我们通过前向传播计算每一层的输出值。假设输入为x,第l层的输出为a[l],则有: a = x z[l] = W[l] * a[l-1] + b[l] a[l] = g(z[l]) 其中,g()是激活函数。 1.2 反向传播: 接下来,我们需要计算损失函数相对于每个参数的梯度,然后使用梯度下降更新参数。假设我们有L层神经网络,则有以下公式: 输出层的梯度: dz[L] = dL / da[L] * g'(z[L]) 隐藏层的梯度: dz[l] = (W[l+1]的转置 * dz[l+1]) * g'(z[l]) 参数梯度: dW[l] = dz[l] * a[l-1的转置] db[l] = dz[l] 更新参数: W[l] = W[l] - learning_rate * dW[l] b[l] = b[l] - learning_rate * db[l] 其中,dL / da[L]是损失函数对输出层输出的导数,g'()是激活函数的导数。 2. 反向传播算法示例代码: 下面是一个使用反向传播算法进行训练的示例代码: ```python # 假设网络有三个隐藏层 hidden_layers = [10, 20, 30] output_size = 2 # 初始化参数 parameters = {} layers_dims = [input_size] + hidden_layers + [output_size] L = len(layers_dims) - 1 for l in range(1, L + 1): parameters['W' + str(l)] = np.random.randn(layers_dims[l], layers_dims[l-1]) * 0.01 parameters['b' + str(l)] = np.zeros((layers_dims[l], 1)) # 前向传播 def forward_propagation(X, parameters): caches = [] A = X for l in range(1, L): Z = np.dot(parameters['W' + str(l)], A) + parameters['b' + str(l)] A = sigmoid(Z) cache = (Z, A) caches.append(cache) Z = np.dot(parameters['W' + str(L)], A) + parameters['b' + str(L)] AL = softmax(Z) cache = (Z, AL) caches.append(cache) return AL, caches # 反向传播 def backward_propagation(AL, Y, caches): grads = {} dZ = AL - Y m = AL.shape[1] grads['dW' + str(L)] = 1/m * np.dot(dZ, caches[-1][1].T) grads['db' + str(L)] = 1/m * np.sum(dZ, axis=1, keepdims=True) for l in reversed(range(1, L)): dA_prev = np.dot(parameters['W' + str(l+1)].T, dZ) dZ = dA_prev * sigmoid_derivative(caches[l-1][0]) grads['dW' + str(l)] = 1/m * np.dot(dZ, caches[l-1][1].T) grads['db' + str(l)] = 1/m * np.sum(dZ, axis=1, keepdims=True) return grads # 参数更新 def update_parameters(parameters, grads, learning_rate): for l in range(1, L+1): parameters['W' + str(l)] -= learning_rate * grads['dW' + str(l)] parameters['b' + str(l)] -= learning_rate * grads['db' + str(l)] return parameters # 训练模型 def train_model(X, Y, learning_rate, num_iterations): for i in range(num_iterations): AL, caches = forward_propagation(X, parameters) cost = compute_cost(AL, Y) grads = backward_propagation(AL, Y, caches) parameters = update_parameters(parameters, grads, learning_rate) if i % 100 == 0: print("Cost after iteration {}: {}".format(i, cost)) return parameters # 使用示例 parameters = train_model(X_train, Y_train, learning_rate=0.01, num_iterations=1000) ``` 这是一个简单的反向传播算法示例代码,其中的sigmoid()、softmax()、sigmoid_derivative()和compute_cost()函数需要根据具体情况自行实现。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

狗头狗不狗

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

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

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

打赏作者

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

抵扣说明:

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

余额充值