一、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模型。