卷积层是卷积神经网络中的核心层之一,它运用卷积操作来提取输入数据的特征。在这个过程中,卷积层运用一组可学习的卷积核来对输入数据进行卷积操作,并生成一个新的特征图,其间每个元素表明特定方位和尺度的特征。

下面是卷积层的计算公式:

深度学习之卷积神经网络卷积层

其间,khk_hkwk_w 别离表明卷积核的高度和宽度,CinC_{in} 表明输入数据的通道数,sis_isjs_j 表明卷积核在输入数据上的滑动步长,kk 表明输出数据的通道数。input(i,j,k)\text{input}(i, j, k) 表明输入数据在方位 (i,j)(i,j) 和通道 kk 上的元素值,filter(i,j,k,l)\text{filter}(i, j, k, l) 表明卷积核在方位 (i,j)(i,j) 和通道 (k,l)(k, l) 上的元素值,output(i,j,k)\text{output}(i, j, k) 表明输出数据在方位 (i,j)(i,j) 和通道 kk 上的元素值。

在实际运用中,卷积层通常还包含偏置项和激活函数,以及一些高档特性,如批归一化和残差连接等。下面是一个卷积层的 TensorFlow 完成示例:

import tensorflow as tf
def conv_layer(x, filter_size, num_filters, stride_size, padding_mode, activation=None):
    # 界说卷积核变量
    input_shape = x.get_shape().as_list()
    filter_shape = [filter_size, filter_size, input_shape[-1], num_filters]
    filters = tf.Variable(tf.truncated_normal(filter_shape, stddev=0.05))
    # 界说卷积操作
    conv = tf.nn.conv2d(x, filters, strides=[1, stride_size, stride_size, 1], padding=padding_mode)
    # 增加偏置项
    biases = tf.Variable(tf.constant(0.05, shape=[num_filters]))
    conv = tf.nn.bias_add(conv, biases)
    # 增加激活函数
    if activation is not None:
        conv = activation(conv)
    return conv

在这个示例中,咱们界说了一个 conv_layer 函数来创建卷积层。该函数运用 TensorFlow 的 tf.nn.conv2d 函数完成卷积操作,并运用 tf.Variable 来界说可学习的卷积核和偏置项。此外,该函数还支持不同的填充形式和步幅巨细,并答应选择不同的激活函数和批归一化是卷积层中常用的高档特性。下面别离介绍这两个特性的完成方法。

  1. 激活函数

激活函数用于在卷积操作之后对输出数据进行非线性变换,以增加模型的表达才能。常用的激活函数包含 sigmoid 函数、ReLU 函数和 tanh 函数等。

如上卷积层的 TensorFlow 完成所示,咱们在卷积操作之后增加了一个 ReLU 激活函数。能够看到,咱们在函数的界说中将 activation 参数设置为 tf.nn.relu,并在 conv 变量上调用该函数来完成激活操作。

  1. 批归一化

批归一化是一种常用的卷积层优化方法,能够提高模型的收敛速度和泛化才能。它通过对每个批次的数据进行归一化操作,减少不同批次之间的散布差异。下面是一个运用批归一化的卷积层示例:

def conv_layer(x, filter_size, num_filters, stride_size, padding_mode, is_training):
    # 界说卷积核变量
    input_shape = x.get_shape().as_list()
    filter_shape = [filter_size, filter_size, input_shape[-1], num_filters]
    filters = tf.Variable(tf.truncated_normal(filter_shape, stddev=0.05))
    # 界说卷积操作
    conv = tf.nn.conv2d(x, filters, strides=[1, stride_size, stride_size, 1], padding=padding_mode)
    # 增加偏置项
    biases = tf.Variable(tf.constant(0.05, shape=[num_filters]))
    conv = tf.nn.bias_add(conv, biases)
    # 增加批归一化
    mean, variance = tf.nn.moments(conv, axes=[0, 1, 2])
    scale = tf.Variable(tf.ones([num_filters]))
    shift = tf.Variable(tf.zeros([num_filters]))
    epsilon = 1e-3
    conv = tf.nn.batch_normalization(conv, mean, variance, shift, scale, epsilon)
    # 增加激活函数
    conv = tf.nn.relu(conv)

在上面的示例中,咱们在卷积操作之后增加了批归一化操作。咱们首先计算批次数据的均值和方差,并运用它们来归一化数据。这儿的 axes 参数指定了需求计算均值和方差的维度,即通道维度。咱们运用 tf.nn.moments 函数来计算均值和方差,然后运用 tf.nn.batch_normalization 函数对数据进行归一化操作。这个函数的参数包含:

  • x:需求归一化的数据。
  • mean:数据的均值。
  • variance:数据的方差。
  • shift:用于平移归一化后的数据的偏置项。
  • scale:用于缩放归一化后的数据的比例因子。
  • epsilon:一个小常数,用于避免除以零过错。

在归一化之后,咱们增加了一个 ReLU 激活函数。需求注意的是,咱们在这个示例中运用了一个 is_training 参数,用于指定是否处于训练形式。在训练形式下,咱们运用当前批次的均值和方差进行归一化,而在猜测形式下,咱们运用所有训练数据的均值和方差进行归一化,这是因为在猜测时咱们无法知道当前批次的均值和方差。

综上所述,批归一化是一种简单而有用的卷积层优化方法,能够提高模型的收敛速度和泛化才能。它的完成方式比较简单,只需求在卷积操作之后增加归一化操作即可。