您的位置:

CNN反向传播

一、CNN简介

卷积神经网络(Convolutional Neural Network,简称CNN)已经成为计算机视觉领域内的一种重要的深度学习网络结构,主要用于图像识别、目标检测、图像分割等任务。与传统的神经网络相比,CNN利用局部感受野、参数共享、下采样等操作可以大大减少网络参数数量,并且可以有效提取图像特征。

二、CNN反向传播介绍

CNN反向传播是CNN的训练算法,是一种基于梯度下降的方法,用于权值(weight)的优化,从而让网络能够更好地拟合数据。它的基本思想是通过计算预测值与真实值之间的误差,通过链式法则将误差从输出层一直向前传递,最终得到每一层的梯度,以此来更新每一层的权值和偏差(bias)。它的前提条件是我们已经有一批已经标注的数据,通过CNN反向传播算法来调整权重和偏差,使得损失函数最小。

三、CNN反向传播原理

3.1 前向传播

在训练CNN之前,需要我们先对一张图像进行前向传播,计算出卷积层、池化层、全连接层的输出层数据(预测值)。具体步骤如下:

for each conv layer do:
    conv_output = convolve(filter, input)
    pooled_output = max_pool(conv_output)
    input = pooled_output
flatten_input = flatten(pooled_output)
for each fc layer do:
    fc_output = active_function(W * flatten_input + b)
    flatten_input = fc_output

3.2 反向传播

在计算出预测值之后,我们需要计算误差以及梯度,为接下来的优化提供基础。CNN反向传播的流程可以分为以下几个步骤:

3.2.1 计算第n层的误差$\delta_n$

在反向传播的过程中,我们需要从输出层开始计算误差,从而逐层往回传递,计算出每一层的误差。具体计算公式如下:

$$\delta_n = \frac{\partial L}{\partial z_n}$$

其中,$z_n$表示第n层的加权输入,$L$表示最终的损失函数,对于分类问题,通常采用交叉熵(Cross-Entropy)作为损失函数。

3.2.2 计算第n层的权重梯度$\frac{\partial L}{\partial W_n}$和偏差梯度$\frac{\partial L}{\partial b_n}$

根据链式法则,我们可以根据上层的误差$\delta_{n+1}$和当前层的加权输入$z_n$,计算出当前层的误差$\delta_n$。然后,利用误差和上一层输出(或者输入)的值,计算出该层的权重和偏差的梯度。

$$\frac{\partial L}{\partial W_n} = a_{n-1} \delta_n$$ $$\frac{\partial L}{\partial b_n} = \delta_n$$

3.2.3 计算第n-1层的误差$\delta_{n-1}$

通过误差反向传播的过程,我们可以计算出每一层的误差$\delta_n$,然后通过$\delta_{n-1} = f'(\phi_{n-1})W_n^T\delta_n $(其中$f'(\phi_{n-1})$表示激活函数的导数,$\phi_{n-1}$表示第n-1层的加权输入)来计算前一层的误差。

3.2.4 更新权重和偏差

我们可以根据之前计算出的权重和偏差梯度,利用梯度下降的算法,更新权重和偏差,来不断缩小损失函数。具体算法如下:

$$W_n = W_n - \alpha\frac{\partial L}{\partial W_n}$$ $$b_n = b_n - \alpha\frac{\partial L}{\partial b_n}$$

其中,$\alpha$是学习率,表示每次更新的步长。

四、CNN反向传播代码实现

4.1 前向传播

def forward_propagation(X, parameters):
    """
    Implement the forward propagation of the CNN
    
    Arguments:
    X -- input data of shape (input_shape, number of examples)
    parameters -- python dictionary with parameters "W1", "b1", ..., "WL", "bL"
                  W1 -- filter matrix of shape (f1, f1, depth_prev, channels)
                  b1 -- bias vector of shape (1, 1, 1, channels)
                  ...
                  WL -- filter matrix of shape (fL, fL, depth_L-1, channels_L)
                  bL -- bias vector of shape (1, 1, 1, channels_L)
    
    Returns:
    output_layer -- output of the last fully connected layer
    caches -- list of caches for each layer
    """
    caches = []
    A = X
    L = len(parameters) // 2
    
    # conv and pooling layers
    for l in range(1, L+1):
        W = parameters['W' + str(l)]
        b = parameters['b' + str(l)]
        conv_output, conv_cache = conv_forward(A, W, b, stride=1, padding='valid') # convolutional layer
        pooled_output, pool_cache = pool_forward(conv_output, mode='max', pool_size=2, stride=2) # pooling layer
        cache = (conv_cache, pool_cache)
        caches.append(cache)
        A = pooled_output
    
    # flatten layer
    flatten_input, shape_input = flatten(A)
    
    # fully connected layers
    for l in range(L+1, 2*L):
        W = parameters['W' + str(l)]
        b = parameters['b' + str(l)]
        fc_output, fc_cache = fc_forward(flatten_input, W, b, activation='relu')
        cache = (fc_cache, shape_input)
        caches.append(cache)
        flatten_input = fc_output
    
    # output layer
    W = parameters['W' + str(2*L)]
    b = parameters['b' + str(2*L)]
    output_layer, output_cache = fc_forward(flatten_input, W, b, activation='softmax')
    caches.append(output_cache)
    
    return output_layer, caches

4.2 反向传播

def backward_propagation(Y, output_layer, caches):
    """
    Implement the backward propagation of the CNN
    
    Arguments:
    Y -- true "label" vector (containing 0 and 1) of shape (output_shape, number of examples)
    output_layer -- output of the last fully connected layer
    caches -- list of caches for each layer
    
    Returns:
    gradients -- python dictionary with gradients for each parameter
    """
    gradients = {}
    L = len(caches)
    m = Y.shape[1]
    
    # output layer
    delta = softmax_backward(output_layer, Y)
    cache = caches[L-1]
    fc_cache, _ = cache
    dflatten_input, dW, db = fc_backward(delta, fc_cache, activation='softmax')
    gradients['dW' + str(L)] = dW
    gradients['db' + str(L)] = db
    
    # fully connected layers
    for l in reversed(range(L-1, L//2, -1)):
        cache = caches[l]
        fc_cache, shape_input = cache
        dflatten_input, dW, db = fc_backward(dflatten_input, fc_cache, activation='relu')
        gradients['dW' + str(l+1)] = dW
        gradients['db' + str(l+1)] = db
    
    # flatten layer
    dA = flatten_backward(dflatten_input, shape_input)
    
    # conv and pooling layers
    for l in reversed(range(L//2)):
        cache = caches[l]
        conv_cache, pool_cache = cache
        dpooled_output = pool_backward(dA, pool_cache, mode='max', pool_size=2, stride=2)
        dA, dW, db = conv_backward(dpooled_output, conv_cache)
        gradients['dW' + str(l+1)] = dW
        gradients['db' + str(l+1)] = db
    
    return gradients

五、总结

通过对CNN反向传播原理和代码实现的讲解,我们对CNN的训练过程有了更深入的认识。在CNN的训练过程中,反向传播算法是非常重要的一环,通过链式法则计算出误差和梯度,再利用梯度下降的方法更新权重和偏差,从而达到训练的目的。我们可以看到,虽然CNN的网络结构很复杂,但借助于反向传播算法,我们可以非常简单地实现CNN的训练过程。相信通过深入地学习和练习,我们一定可以创建出更加优秀的CNN模型。