用numpy库手写算子二 : Conv2d_backward

用numpy库手写算子一: Conv2d_backward前言我们经常可以调用pytorch,tensorflow库等来实现我们的神经网络,但是有的时候需要开发自己的框架,这个时候就得了解每一个算子的计算规则,了解这些计算规则也有助于我们了解他们的计算特性,然后就可以在底层优化上面有一定的针对性。Conv2d_backward一个算子的求导,包括两个方面:对Filter求导,这部分的求导作为之后更新梯度的梯度;对Input求导,也就是对每层的Featurre_map进行求导,作为链式求导中的一环向前
摘要由CSDN通过智能技术生成

用numpy库手写算子二: Conv2d_backward

前言

我们经常可以调用pytorch,tensorflow库等来实现我们的神经网络,但是有的时候需要开发自己的框架,这个时候就得了解每一个算子的计算规则,了解这些计算规则也有助于我们了解他们的计算特性,然后就可以在底层优化上面有一定的针对性。

Conv2d_backward

一个算子的求导,包括两个方面:对Filter求导,这部分的求导作为之后更新梯度的梯度;对Input求导,也就是对每层的Featurre_map进行求导,作为链式求导中的一环向前面的神经层传导。

输入说明

对于conv2d的反向而言:
默认dout,也就是从后面的层反传回来的,对应正向的本层的feature_map的梯度,这部分梯度是作为链式传导过程中的中间变量.数据布局为(N,C,H,W),N代表batch_size,C代表input_channel,H代表input_height,W代表input_width.
默认x数据布局为(N,C,H,W),N代表batch_size,C代表input_channel,H代表input_height,W代表input_width。
关于x和dout的关系,dout相当于正向过程中,根据x和w算出来的本层的feature_map的导数。
w代表正向的本层的filter,默认数据布局为(N,C,H,W),N代表channel_multiplier,C代表input_channel,H代表kernel_height,W代表kernel_width。
stride代表的是(stride__h,stride_w)。
pad代表的是(pad_h,pad_w)。

对Filter求导

本层的filter的导数的形状和w的形状大小是一致。对于一个(ko,ki,kh,kw)的卷积核,其梯度大小相当于反向传导回来的dout和前向的input做正常的卷积计算,累加的轴是batch_size。

对Input求导

本层对input的求导(x),首先是要根据前向的stride的数值,进行dilate,也就是相当于给dout补0,具体参考是dilate_python。dilate之后的dout,根据前向的pad,给边界补0。然后将所有的filter进行翻转180度。最后将dilate+边界补0后的dout和旋转180度的filter,做正常的卷积得到对本层x的梯度。将求的梯度反向传导,作为链式求导过程的中间变量。

总体代码

import numpy as np
def dilate_python(input_np, strides):
    """Dilate operation.
    Parameters
    ----------
    input_np : numpy.ndarray
        n-D, can be any layout.
    strides : list / tuple of n ints
        Dilation stride on each dimension, 1 means no dilation.
    Returns
    -------
    output_np : numpy.ndarray
        n-D, the same layout as Input.
    if stride = 1,input = output
    if stride = 2.input = [[[[1. 1.][1. 1.]][[1. 1.][1. 1.]]]],output = 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,我可以帮你解答这个问题。 首先,体识别可以使用卷积神经网络(Convolutional Neural Network, CNN)来实现。而在Python中,我们可以使用NumPy来实现这个网络。 以下是一个简单的CNN网络结构,包括了卷积层、池化层、全连接层和输出层: ``` # 网络结构定义 class CNN: def __init__(self): # 卷积层,3个3x3的卷积核,步长1 self.conv1 = Conv2D(3, 3, 3, stride=1) # 池化层,2x2的池化窗口,步长2 self.pool1 = MaxPool2D(2, 2, stride=2) # 全连接层,将卷积层输出的特征图拉成一维向量 self.fc1 = Dense(13*13*3, 128, activation='relu') # 输出层,10个神经元对应10个数字类别 self.out = Dense(128, 10, activation='softmax') def forward(self, x): x = self.conv1(x) x = self.pool1(x) x = x.reshape(x.shape[0], -1) x = self.fc1(x) x = self.out(x) return x ``` 其中,`Conv2D`表示卷积层,`MaxPool2D`表示池化层,`Dense`表示全连接层,`activation`为激活函数,`reshape`函数用于将卷积层输出的特征图拉成一维向量。 下面是一个简单的训练函数,包括了前向传播、反向传播和参数更新: ``` # 训练函数 def train(model, x, y, lr=0.01): # 前向传播 out = model.forward(x) # 计算损失 loss = cross_entropy_loss(out, y) # 反向传播 grad = out - y grad = model.out.backward(grad) grad = model.fc1.backward(grad.reshape(grad.shape[0], -1)) grad = grad.reshape(-1, 13, 13, 3) grad = model.pool1.backward(grad) grad = model.conv1.backward(grad) # 参数更新 model.conv1.update(lr) model.fc1.update(lr) model.out.update(lr) return loss, out ``` 其中,`cross_entropy_loss`为交叉熵损失函数,`backward`函数为反向传播函数,`update`函数为参数更新函数。 最后,我们可以训练这个网络,并输出权值和参数: ``` # 初始化网络 model = CNN() # 训练网络 for i in range(100): loss, out = train(model, x_train, y_train) print('Epoch:', i+1, 'Loss:', loss) # 输出权值和参数 print('Conv1 Weights:', model.conv1.weights) print('Conv1 Bias:', model.conv1.bias) print('Fc1 Weights:', model.fc1.weights) print('Fc1 Bias:', model.fc1.bias) print('Out Weights:', model.out.weights) print('Out Bias:', model.out.bias) ``` 其中,`x_train`为数字的训练数据,`y_train`为训练数据对应的标签。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值