深度学习入门

深度学习

神经网络大致结构:卷积层,池化层,affine(dot,sigmoid) ,softmax,loss

激活函数

众所周知,用作激活函数的函数最好具有关于原点对称的性质。tanh函数是关于原点(0, 0)对称的S型曲曲线。

tanh函数

在这里插入图片描述

def tanh(x):
    a = 1 - np.exp(-2 * x)
    b = 1 + np.exp(-2 * x)
    return a / b

Sigmoid函数

连续,sigmoid函数是关于(x, y)=(0, 0.5)对称的S型曲曲线

import numpy as np
def sigmoid(x):
    return 1/1+np.exp(-x)

在这里插入图片描述

阶跃函数

非连续

def step(x):
	if x > 0:
        return 1
    else: 
    	return 0

在这里插入图片描述

ReLU函数

修正函数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Y9MCs7Tu-1622190502282)(D:\notes\images\image-20210523100602327.png)]

def ReLu(x):
    if x > 0:
        return x
    else:
        return 0

在这里插入图片描述

输出层函数

恒等函数

原样输出,不做改变

def	equal(x):
    return x

Softmax函数

常见于分类问题

多元分类softmax(由于softmax特性,即softmax的所有输出结果相加为1)

在这里插入图片描述

def softmax(x):
    c = np.max(x)
    exp_x = np.exp(x - c)# 防止溢出
    return exp_a / np.sum(exp_x)

损失函数

均方误差

均方根差 = sqrt(均方误差)

RMSE = sqrt(MSE)

在这里插入图片描述

def mse(y,t):
    return 0.5 * np.sum((y-t)**2)

交叉熵误差

常用

在这里插入图片描述

def Cee(y,t):
    delta = 1e-7
	return - np.sum(t * np.log(y + delta))

Mini-batch 交叉熵

在这里插入图片描述

def mini_batch_Cee(y,t):
    delta = 1e-7
    if y.dim == 1:
        t = t.reshape(1,t.size)
        y = y.reshape(1,y.size)
    batch_size = y.shape[0]
    return - np.sum(t * np.log(y + delta)) / batch_size

数值微分

需掌握基础知识

导数(存在误差)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SyawIwJ0-1622190502291)(D:\notes\images\image-20210523102421208.png)]

数值微分(推荐使用)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FYv647f0-1622190502292)(D:\notes\images\image-20210523102516190.png)]

def	numercial_diff(f,x):
    h = 1e-4
    return (f(x+h) - f(x-h))/(2 * h)

梯度(数值微分实现,耗时)

全部变量的偏导数汇总而成的向量

def numerial_gradient(f,x):
    h = 1e-4
    grad = np.zeros_like(x)
    for i in range(x.size):
        tmp_val = x[i]
        # f(x + h)
        x[i] = tmp_val + h
        fxh1 = f(x)
        
        # f(x - h)
        x[i] = tmp_val - h
        fxh2 = f(x)
        
        grad[i] =  (fxh1 - fxh2) / (2 * h)
       	x[i] = tmp_val
    return grad

梯度下降

随机梯度下降(SGD):对随机选择的梯度进行梯度下降法

lr : 学习率,step:步数

def	gradient_descent(f,init_X,lr = 0.01,step = 100):
    x = init_x
    for i in range(step):
        grad = numerial_gradient(f,x)
        x-=lr*grad
    return x

误差反向传播

理论依据:链式法则

简单层实现

加法节点

将输入信号输出到下一个节点,不做处理

eg:z = x+y,求x,y的偏导

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JmF9NQIX-1622190502294)(D:\notes\images\image-20210523114043613.png)]

class AddLayer:
    def __init__(self):
        pass

    def forward(self, x, y):
        out = x + y
        return out

    def backward(self, dout):
        dx = dout * 1
        dy = dout * 1
        return dx, dy
乘法节点

将上游的值乘以正向传播时的输入信号的翻转值后传递给下游

eg:z = xy,求x,y的偏导

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ks5Hh7kh-1622190502295)(D:\notes\images\image-20210523114438043.png)]

class MulLayer:
    def __init__(self):
        self.x: int = 0
        self.y: int = 0

    def forward(self, x, y):
        self.x = x
        self.y = y
        out = x * y
        return out

    def backward(self, val):
        dx = val * self.y
        dy = val * self.x
        return dx, dy

激活函数层实现

ReLu

如果正向传播x>0:

​ 反向传播时将上游的值原封不动传递下去

否则:

​ 传递信号在此处停止

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ba93dmqd-1622190502298)(D:\notes\images\image-20210523114851360.png)]

class Relu:
    def __init__(self):
        self.mask = None

    def forward(self, x):
        self.mask = (x <= 0)
        out = x.copy()
        out[self.mask] = 0
        return out

    def backward(self, dout):
        dout[self.mask] = 0
        dx = dout
        return dx
Sigmoid

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lNJo8rl9-1622190502299)(D:\notes\images\image-20210523132844783.png)]

/ 节点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2foADkNS-1622190502301)(D:\notes\images\image-20210523134054935.png)]

Exp(x)的偏导

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WCtQqRhY-1622190502302)(D:\notes\images\image-20210523133955020.png)]

得到结果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XPQ0Zenz-1622190502304)(D:\notes\images\image-20210523134129854.png)]

def Sigmoid:
    def __init__(self):
        self.out = None
        
    def forward(self,x):
        self.out = 1 / (1 + np.exp(-x))
        return self.out
    def backward(self,dout):
        dx = dout * (1.0 - self.out) * self.out
        return dx

Affine、Softmax层

Affine

神经网络的正向传播中进行的矩阵的乘积运算在几何学领域被称为“仿
射变换”。因此,这里将进行仿射变换的处理实现为“Affine层”。

反向传播(线性代数)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7nqV7S3L-1622190502305)(D:\notes\images\image-20210523135616759.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QcXDgzmi-1622190502307)(D:\notes\images\image-20210523135514880.png)]

class Affine:
    def __init__(self, W, b):
        self.W =W
        self.b = b
        
        self.x = None
        self.original_x_shape = None
        # 权重和偏置参数的导数
        self.dW = None
        self.db = None

    def forward(self, x):
        # 对应张量
        self.original_x_shape = x.shape
        x = x.reshape(x.shape[0], -1)
        self.x = x

        out = np.dot(self.x, self.W) + self.b

        return out

    def backward(self, dout):
        dx = np.dot(dout, self.W.T)
        self.dW = np.dot(self.x.T, dout)
        self.db = np.sum(dout, axis=0)
        
        dx = dx.reshape(*self.original_x_shape)  # 还原输入数据的形状(对应张量)
        return dx
SoftmaxWithLoss

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kHViqThA-1622190502308)(D:\notes\images\image-20210523142701183.png)]

class SoftmaxWithLoss:
    def __init__(self):
        self.loss = None
        self.y = None # softmax的输出
        self.t = None # 监督数据

    def forward(self, x, t):
        self.t = t
        self.y = softmax(x)
        self.loss = cross_entropy_error(self.y, self.t)
        
        return self.loss

    def backward(self, dout=1):
        batch_size = self.t.shape[0]
        if self.t.size == self.y.size: # 监督数据是one-hot-vector的情况
            dx = (self.y - self.t) / batch_size
        else:
            dx = self.y.copy()
            dx[np.arange(batch_size), self.t] -= 1
            dx = dx / batch_size
        
        return dx

梯度确认

确认数值微分求出的梯度结果和误差反向传播法求出的结果是否一致(严格地讲,是
非常相近)的操作称为梯度确认(gradientcheck)

使用两种不同的求梯度方式,将求解后的结果进行相减求平均值

grad_numerical = network.numerical_gradient(x_batch,t_btach)
grad_backprop = network.gradient(x_batch,t_btach)
# 求平均值
for key in grad+numerical.keys():
    diff = np.average(np.abs(grad_backprop[key] - grad_numerucak[key]))
    print(key + ":" + str(diff))

技巧

参数更新、梯度下降

SGD

随机梯度下降

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZTFasf7u-1622190502310)(D:\notes\images\image-20210525155455564.png)]

class SGD:

    """随机梯度下降法(Stochastic Gradient Descent)"""

    def __init__(self, lr=0.01):
        self.lr = lr
        
    def update(self, params, grads):
        for key in params.keys():
            params[key] -= self.lr * grads[key] 
Momentum

Momentum 意味“动量”

与SGD相比,可以更快地朝x轴方向靠近,减弱“之”字形的变动程度。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Vr4xu5eF-1622190502311)(D:\notes\images\image-20210525154948318.png)]

α 对应 为地面摩擦、空气阻力

v 对应 为速度

class Momentum:

    """Momentum SGD"""

    def __init__(self, lr=0.01, momentum=0.9):
        self.lr = lr
        self.momentum = momentum
        self.v = None
        
    def update(self, params, grads):
        if self.v is None:
            self.v = {}
            for key, val in params.items(): # val 什么操作?                              
                self.v[key] = np.zeros_like(val)
                
        for key in params.keys():
            self.v[key] = self.momentum*self.v[key] - self.lr*grads[key] 
            params[key] += self.v[key]
AdaGrad

AdaGrad会为参数的每个元素适当地调整学习率

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TPtqkhWb-1622190502312)(D:\notes\images\image-20210525160204105.png)]

h 保存了以前的所有梯度值的平方和

一式中的”⊙“ 表示对应矩阵元素的乘法

class AdaGrad:

    """AdaGrad"""

    def __init__(self, lr=0.01):
        self.lr = lr
        self.h = None
        
    def update(self, params, grads):
        if self.h is None:
            self.h = {}
            for key, val in params.items():
                self.h[key] = np.zeros_like(val)
            
        for key in params.keys():
            self.h[key] += grads[key] * grads[key]
            params[key] -= self.lr * grads[key] / (np.sqrt(self.h[key]) + 1e-7)
Adam

Momentum参照小球在碗中滚动的物理规则进行移动,AdaGrad为参数的每个元素适当地调整更新步伐。将这两个方法融合即为Adam

权重初始值

Sigmod、tanh

使用Xavier的初始值

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BE8qEnbo-1622190502314)(D:\notes\images\image-20210526114850691.png)]

ReLU

使用”He初始值“,速度更快

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ymHLcfDS-1622190502315)(D:\notes\images\image-20210526120402405.png)]

Batch Norm

优点:

  1. 可以使学习快速进行(可以增大学习率,加速收敛)。
  2. 不那么依赖初始值(对于初始值不用那么神经质)。
  3. 抑制:过拟合(降低Dropout等的必要性)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fjzmwsuK-1622190502317)(D:\notes\images\image-20210526121017871.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Qf2PwgnY-1622190502317)(D:\notes\images\image-20210526121146937.png)]

这里对mini-batch的m个输人数据的集合B= {x1, x2,… xm}求均值Ub和方差σ^2b,然后,对输人数据进行均值为0、方差为1(合适的分布)的正规化。式中的∈是一个微小值(比如,1e-7等), 它是为了防止出现除以0的情况。

接着,Batch Norm层会对正规化后的数据进行缩放和平移的变换,用数学式可以如下表示。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YKYAT8w5-1622190502319)(D:\notes\images\image-20210526121717011.png)]

这里,γ和β是参数。开始γ=1,β=0,然后再通过学习调整到合适的值。
归一化层作用在
● 全连接层和卷积层输出,上,激活函数前
●全连接层和卷积层输入.上
对全连接层,作用在特征维
对于卷积层,作用在通道维

过拟合

过拟合指的是只能拟合训练数据,但不能很好地拟合不包含在训练数据中的其他数据的状态。

权值衰减

一种抑制过拟合的方法。该方法通过在学习的过程中对大的权重进行惩罚,来抑制过拟合。

为损失函数加上权重的平方范数(L2范数)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OE82Pi7T-1622190502320)(D:\notes\images\image-20210526205224291.png)]且L2范数常用

L1范数是各个元素的绝对值之和

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ljgCGCm5-1622190502321)(D:\notes\images\image-20210526205302550.png)]

L∞范数,相当于各个元素的绝对值中最大的那一个

def l2_penalty(w):
    return torch.sum(w.pow(2)) / 2
Dropout

一种在学习的过程中随机删除神经元的方法

在这里插入图片描述

class Dropout:
    def __init__(self,dropout_ratio=0.5):
        self.dropout_tatio = dropout_ratio
        self.mask = None
        
    def forward(self,x,train_flg=True):
        if train_flg:
            self.mask = np.random.rand(*x.shape)>self.dropout_ratio
            return x * self.mask
        else
        	return x * (1.0 - self.dropout_ratio)
        
    def backword(self,out):
        return out * self.mask

pytorch 实现

def dropout(x, dropout):
    # 边界判断
    assert 0 <= dropout <= 1
    # 全丢
    if dropout == 1:
        return torch.zeros_like(x)
    # 不丢
    elif dropout == 0:
        return x
    # 随机生成数字取大于dropout的index
    mask = (torch.randn(x.shape) > dropout).float()
    return mask * x / (1.0 - dropout)
超参数最优化

训练数据集:训练模型参数
验证数据集:选择模型超参数
数据量不够时:k-折交叉验证
将一个数据集分成几段(常见5,10)将其中的一段作为验证数据集,其余为训练数据集,一共训练5/10次(每一次的训练和验证数据集不相同),将验证精度相加求平均

卷积神经网络(CNN)

CNN被用于图像识别、语音识别等各种场合,在图像识别的比赛中,基于深度学习的方法几乎都以CNN为基础。

CNN中新出现了卷积层(Convolution层)和池化层(Pooling层)。

相邻层的所有神经元之间都有连接,这称为全连接(fully-connected)。

CNN的连接顺序为 卷积层-ReLU-Pooling层(有时被省略)

全连接层(Affine)存在问题

丢失空间信息,将(1,28,28)的三维图片拉为784的一维

卷积层

卷积运算

卷积层的处理称为卷积运算

卷积层的输人输出数据称为特征图

卷积层的输人数据称为输入特征图,输出数据称为输出特征图

其中的滤波器也称为卷积核

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MWp9EFIW-1622190502321)(D:\notes\images\image-20210527171333377.png)]

已有如上的输入数据和滤波器,如下进行卷积运算

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wmNeDlod-1622190502322)(D:\notes\images\image-20210527171306642.png)]

将各个位置的滤波器的元素和输人的对应元素相乘,然后再求和。也称乘积累加运算

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-byyh5Thb-1622190502323)(D:\notes\images\image-20210527171510644.png)]

滤波器是(FN,C, FH, FW) 的4维形状

填充

在进行卷积层的处理之前,有时要向输人数据的周围填人周定的数据(比如0等),这称为填充(padding),是卷积运算中经常会用到的处理。

使用填充主要是为了调整输出的大小。比如,对大小为(4, 4)的输入数据应用(3, 3)的滤波器时,输出大小变为(2,2),相当于输出大小比输入大小缩小了2个元素,这样避免了在多层卷积神经网络中输出层出现1x1的情况。(将导致无法进行卷积神经网络运算)

Vaild填充

不进行填充

eg:

现有nxn的输入,fxf的滤波器,输出大小为(n-f+1)x(n-f+1)

Same填充

输出特征图和输出特征图大小相等

eg:

现有nxn的输入,fxf的滤波器,输出大小为(n+2p-f+1)x(n+2p-f+1)

p = (f-1)/2

f通常是奇数

步幅

应用滤波器的位置间隔称为步幅( stride)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9NOlY9Bf-1622190502323)(D:\notes\images\image-20210527182054666.png)]

增大步幅后,输出大小会变小。而增大填充后,输出大小会变大。

假设输入大小为(H,W),滤波器大小为(FH, FW),输出大小为(OH, OW),填充为P,步幅为S。此时,输出大小可通过式子进行计算

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VtROldV7-1622190502324)(D:\notes\images\image-20210527182547620.png)]

三维数据的卷积运算

通道方向上有多个特征图时,会按通道进行输人数据和滤波器的卷积运算,并将结果相加,从而得到输出。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WTXD3u7d-1622190502324)(D:\notes\images\image-20210527212455898.png)]

需要注意的是,在3维数据的卷积运算中,输人数据和滤波器的通道数要设为相同的值。在这个例子中,输人数据和滤波器的通道数一致,均为3。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6CeWdAT5-1622190502325)(D:\notes\images\image-20210527222749261.png)]

书写顺序为(channel, height, width),在这个例子中,数据输出是1张特征图。

池化层

池化是缩小高、长方向上的空间的运算,目标区域中取最大值(或者平均值)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7FxmPWjZ-1622190502325)(D:\notes\images\image-20210527223128041.png)]

2 x 2的窗口的移动间隔为2个元素。另外,-一般来说,池化的窗口大小会和步幅设定成相同的值。比如,3 x 3的窗口的步幅会设为3, 4x 4的窗口的步幅会设为4等。

池化层的特征

没有要学习的参数
池化层和卷积层不同,没有要学习的参数。池化只是从目标区域中取最大值(或者平均值),所以不存在要学习的参数。
通道数不发生变化
经过池化运算,输入数据和输出数据的通道数不会发生变化

对微小的位置变化具有鲁棒性(健壮)
输入数据发生微小偏差(位置不一致?)时,池化仍会返回相同的结果。因此,池化对输入数据的微小偏差具有鲁棒性。

卷积层和池化层的实现

im2col展开

im2col是一个函数,将输人数据展开以适合滤波器(权重)。

对于输入数据,将应用滤波器的区域(3维方块)横向展开为1列

输入数据处理

假设滤波器(卷积核)的大小为3x3,输入数据为4x4,步幅为1

过滤器

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v32lEFOb-1622190502327)(D:\notes\images\image-20210528091348071.png)]

输入数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Agf5dyii-1622190502327)(D:\notes\images\image-20210528091255505.png)]

过滤器im2col

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gaWXi7Zb-1622190502327)(D:\notes\images\image-20210528091220357.png)]

输入数据im2col

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d6cCRbzG-1622190502328)(D:\notes\images\image-20210528091147545.png)]

最终得到结果为1x9的二维矩阵,将结果reshape得到4x4矩阵,最终输出特征图

def im2col(input_data, filter_h, filter_w, stride=1, pad=0):
    """

    Parameters
    ----------
    input_data : 由(数据量, 通道, 高, 长)的4维数组构成的输入数据
    filter_h : 滤波器的高
    filter_w : 滤波器的长
    stride : 步幅
    pad : 填充

    Returns
    -------
    col : 2维数组
    """
    N, C, H, W = input_data.shape
    out_h = (H + 2*pad - filter_h)//stride + 1
    out_w = (W + 2*pad - filter_w)//stride + 1

    img = np.pad(input_data, [(0,0), (0,0), (pad, pad), (pad, pad)], 'constant')
    col = np.zeros((N, C, filter_h, filter_w, out_h, out_w))

    for y in range(filter_h):
        y_max = y + stride*out_h
        for x in range(filter_w):
            x_max = x + stride*out_w
            col[:, :, y, x, :, :] = img[:, :, y:y_max:stride, x:x_max:stride]

    col = col.transpose(0, 4, 5, 1, 2, 3).reshape(N*out_h*out_w, -1)
    return col
卷积层实现

与案例转换的形状相反,是输入 * 卷积核,而非卷积核 * 输入

class Convolution:
    def __init__(self, W, b, stride=1, pad=0):
        self.W = W
        self.b = b
        self.stride = stride
        self.pad = pad
        
        # 中间数据(backward时使用)
        self.x = None   
        self.col = None
        self.col_W = None
        
        # 权重和偏置参数的梯度
        self.dW = None
        self.db = None

    def forward(self, x):
        FN, C, FH, FW = self.W.shape
        N, C, H, W = x.shape
        out_h = 1 + int((H + 2*self.pad - FH) / self.stride)
        out_w = 1 + int((W + 2*self.pad - FW) / self.stride)

        col = im2col(x, FH, FW, self.stride, self.pad)
        col_W = self.W.reshape(FN, -1).T

        out = np.dot(col, col_W) + self.b
        out = out.reshape(N, out_h, out_w, -1).transpose(0, 3, 1, 2)

        self.x = x
        self.col = col
        self.col_W = col_W

        return out

    def backward(self, dout):
        FN, C, FH, FW = self.W.shape
        dout = dout.transpose(0,2,3,1).reshape(-1, FN)

        self.db = np.sum(dout, axis=0)
        self.dW = np.dot(self.col.T, dout)
        self.dW = self.dW.transpose(1, 0).reshape(FN, C, FH, FW)	# 交换列

        dcol = np.dot(dout, self.col_W.T)
        dx = col2im(dcol, self.x.shape, FH, FW, self.stride, self.pad)

        return dx
池化层实现
class Pooling:
    def __init__(self, pool_h, pool_w, stride=1, pad=0):
        self.pool_h = pool_h
        self.pool_w = pool_w
        self.stride = stride
        self.pad = pad
        
        self.x = None
        self.arg_max = None

    def forward(self, x):
        N, C, H, W = x.shape
        out_h = int(1 + (H - self.pool_h) / self.stride)
        out_w = int(1 + (W - self.pool_w) / self.stride)

        col = im2col(x, self.pool_h, self.pool_w, self.stride, self.pad)
        col = col.reshape(-1, self.pool_h*self.pool_w)

        arg_max = np.argmax(col, axis=1)
        out = np.max(col, axis=1)
        out = out.reshape(N, out_h, out_w, C).transpose(0, 3, 1, 2)

        self.x = x
        self.arg_max = arg_max

        return out

    def backward(self, dout):
        dout = dout.transpose(0, 2, 3, 1)
        
        pool_size = self.pool_h * self.pool_w
        dmax = np.zeros((dout.size, pool_size))
        dmax[np.arange(self.arg_max.size), self.arg_max.flatten()] = dout.flatten()
        dmax = dmax.reshape(dout.shape + (pool_size,)) 
        
        dcol = dmax.reshape(dmax.shape[0] * dmax.shape[1] * dmax.shape[2], -1)
        dx = col2im(dcol, self.x.shape, self.pool_h, self.pool_w, self.stride, self.pad)
        
        return dx

更新补充

为何选择3x3,及5x5的卷积核?

  1. 奇数的卷积核可以防止进行卷积运算时,出现不对称运算结果的现象。
  2. 3x3,5x5的卷积核有中心像素点,更加方便指出卷积核位置。
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值