用于调整深度神经网络的简单参考指南
入门
考虑到所涉及的参数很多,设计深度神经网络可能是一项痛苦的任务,并且没有通用公式适合所有用例。我们可以使用卷积神经网络(CNN)进行图像分类,LSTM进行NLP相关的任务,但是特征的数量、特征的大小、神经元的数量、隐藏层的数量、激活函数的选择、权重的初始化等在不同的用例中将会有所不同。
图像数据集:与相邻像素相关
参数的这些变化可归因于不同类型的数据,需要独立于其他数据集的分析。像图像数据集将具有不同的属性,因为相邻位置中的像素是相关的,但是在关系数据库条目中可以是随机的而没有关系。因此,需要采用不同的方法。
我们能够为它们推广数据类型和合适的神经网络结构类型,如CNN用于图像,音频,视频和用于NLP相关任务的RNN / LSTM等。但是,为了实现最大性能,我们应该使它们变得智能化。
dim(h)<dim(xi)< - undercomplete autoencoder || overcomplete autoencoder - > dim(h)≥dim(xi)
为了简化,我们将讨论局限于自动编码器,这是一种特殊类型的前馈神经网络,它对隐藏层中的输入进行编码并从此隐藏表示中进行解码。每个神经网络架构都有自动编码器作为其基本块。因此,通过对它们的讨论,我们可以扩展不同深度学习架构的想法。
在本文中,我们将探索微调网络的技术,以获得更好的验证准确性,从而实现更好的预测。此外,我们还将研究这些技术背后的一些数学,以了解这些技术的幕后故事。
创建智能自动编码器有什么问题?
我们真正想从神经网络中得到的是从可用数据中归纳出来的而不是记忆出来的。死记硬背的问题是模型最终可能会过度拟合。由于深度学习模型是复杂的,往往会超出目标函数。考虑一些非常基本的情况,其中模型在训练数据集上进行了广泛的训练,从而使训练数据集上的误差最小化并趋近于零。神经网络有可能不去捕捉数据的趋势,而只是记住了用复杂函数再现整个数据的方法。
让我们使用偏差v / s方差权衡的概念更清楚地理解这一点。看一下下图,x轴表示模型复杂度,而y轴表示误差。随着复杂性的增加,训练误差趋于减小,但方差增加,显示出高验证误差。
蓝色:训练误差,红色:验证误差
模型最初偏差将很高,随着训练误差接近零,模型将过度拟合导致高方差。
我们希望模型能够更敏感地捕捉稀疏但重要的特性的细微细节。因此,不拟合数据根本不是一种选择。因为更复杂的模型对变化更敏感。只有在深度学习的背景下进行关于过度拟合的讨论才有意义。
以overcomplete编码器为例,在这种情况下,他们可以学习简单的编码复制粘贴整个网络的值。就像将输入(xi)复制到隐藏层(h)然后再从h复制到输出层(x hat)。显然,误差将是最小的,但没有学习
它也是一种过度拟合,因为自动编码器捕获训练数据中权重映射的所有变化。
让我们建立在以上讨论的基础上,为了让深度学习的自动编码器成功,过度拟合必须被移除。当然,还存在数据不足、参数量大、相关特征是否掌握、何时停止训练等问题。可以说,智能自动编码器是概括我们可以观察和学习重要的趋势的信息,从中他们可以作出预测。让我们开始探索这些技术,目的是发展直觉,理由是使用它们和合适的例子来增强我们的学习。
- 数据集增强
- 提早停止
- l2正则化
- 避免Vanilla 自动编码器:噪音和稀疏度
- 参数共享和绑定
- DropOut和DropConnect的集成方法
数据集增强
在计算机视觉分类任务中,训练数据越多,模型学习效果越好。但是巨大数据的问题是它增加了训练时间。
在深度学习模型中,参数的数量是巨大的(百万数量级)。如果一开始就没有足够的可用数据,这显然会有帮助。但是,如果你已经有了足够的数据,这会有帮助吗?是的,因为它将增加数据集中的相关特征,这将帮助自动编码器学习重要的稀疏特征,而不是无关的丰富特征。
数据增强是一种技术,我们用现有数据创建新数据,目的是增加原始数据中的相关特征。请参阅下面的插图以了解数据增强的概念。
不变性:数据根据平移,旋转,大小,视点和照明的差异进行稳健分类
以这种方式增加最明显的分类特征成为最相关的特征。在ML管道中增加数据的位置?首先是离线扩充应用转换并将图像添加到数据集。但是,它会根据应用的转换次数增加大小。其次,在进入我们的学习模型之前,在线增强是应用于小批量的。在这里,请参阅一些Tensorflow脚本进行此类转换,假设我们不关心图像边界之外的情况。
这是什么意思 ?假设图像的某些部分没有任何东西,即它是未知空间,那么我们需要不同的变换如下。例如,一些带有黑色背景的旋转图像。
从左侧开始,constant, edge, reflect, symmetric and wrap transformations applied
Tensorflow脚本基于上述关于在小批量上应用简单数据转换的假设。Python示例代码如下:
# 1. Flip: 'x' = A placeholder for an image. shape = [height, width, channels] x = tf.placeholder(dtype = tf.float32, shape = shape) flip_2 = tf.image.flip_up_down(x) flip_5 = tf.image.random_flip_left_right(x) # 2. Rotate: 'y' = A batch of images # To rotate in any angle. In the example below, 'angles' is in radians shape = [batch, height, width, 3] y = tf.placeholder(dtype = tf.float32, shape = shape) rot_tf_180 = tf.contrib.image.rotate(y, angles=3.1415) # 3. Noise: 'x' = A placeholder for an image. shape = [height, width, channels] x = tf.placeholder(dtype = tf.float32, shape = shape) # Adding Gaussian noise noise = tf.random_normal(shape=tf.shape(x), mean=0.0, stddev=0.5, dtype=tf.float32) output = tf.add(x, noise)
可以类似地为随机裁剪,wrapping,颜色通道移位等编写其他增强。
提早停止
正如名字(Early Stopping)所示,它确实给我们提供了一些信息,即我们在训练时提早停止以避免拟合。但是如何提前停止呢?基本上,我们的目标是在训练误差被推向零并且验证误差即将爆发之前停止。
参数P:如果您在步骤k并且在之前的步骤中验证误差没有改善,则停止训练并返回在步骤k-p存储的模型。
这些提早停止规则通过将原始训练集分成新的训练集和验证集来工作。验证集上的误差用于替代原始训练误差,以确定过度拟合何时开始。使用Keras,您可以使用以下方法执行此操作。Python示例如下:
keras.callbacks.EarlyStopping(monitor='val_loss', min_delta=0, patience=0, verbose=0, mode='auto')
min_delta是否在某个epoch量化损失作为改进的门槛。如果损失的差值低于min_delta,则将其量化为没有改善。patience参数表示一旦损失开始增加(停止改善),停止前的epochs数。mode参数取决于您监控数量的方向(它应该是减少还是增加),因为我们监控损失,我们可以使用min。
现在,如果我说Early Stopping也是一种正则化技术。可以证明这句话是真的吗?让我们看看少量数学。请记住,正则化是指在学习神经网络中增加一些权重和偏差约束的技术。
随机梯度下降法的更新规则。设'τ'为delta(wi)的最大值梯度。将不等式应用于上述等式,我们得到:
t控制了wt到初始w0的距离
提早停止只允许更新参数。更重要的是,维度越大,与之相关的损失就越大,如上式所示,我们控制学习率和t,只有与梯度相关的损失是主导因素,这实际上意味着只有损失越大的重要参数才会占更多。
在那里,不那么重要的将无法成长。因此,重要的参数被放大,这将导致更好的准确性。这类似于L2正则化,请参阅下面。
L2正规化
正则化是在学习过程中对模型的约束。L2正则化是权重衰减正则化,它使权值更接近原点,降低不那么重要的特征。
让我们以直观的方式理解true error的概念。这个误差可以用下面这个给定的形式表示,其中添加到经验误差的术语是基于估计程序,因为我们不知道f(x)。
其中yi = f(xi)+ε,ε是samll value
主要目的是将模型复杂性对true error的影响联系起来。显然,它会训练误差加上一些东西。那是什么东西?借助Stein引理和一些数学,我们可以证明这一点
当观察中的微小变化导致估计的大的变化时( fhat(xi)),误差会更多。
这与复杂模型有关吗?是的,上述观察结果与模型越复杂,观察变化越敏感这一事实有关。因此,我们可以说true error=经验训练误差+小常数+Ω(模型复杂性)。该Ω是正则化的基础。因此,在正则化中,我们的目标是最小化由于模型复杂性导致的误差,而模型复杂性又与偏差 - 方差权衡相关。
添加该术语的直觉是训练误差不会达到零。 w影响上述方程的梯度和更新规则。
上面添加到更新规则和SGD公式的含义是什么。上面提到的等式2操作在数学上表示在重要方向上的权重矩阵的缩放,即具有主要特征值和次要特征值的那个被缩放,但是较不重要的特征被缩小更多。该正则化操作有效地首先旋转权重矩阵,然后将其对角化然后再次旋转它。在这里,请参见这些对等contour map有效的操作。
权重向量(w *)旋转到(w̃)。从几何学上可以看出,所有特征都在缩小,但是有些特征缩小更多。重要特征可以分配更多权重。
这里是Tensorflow脚本,用于在基于上述公式的神经网络模型中使用正则化。第一个例子是仅在一层上使用它,第二个是在所有层上使用它。Python代码如下:
# Code 1: # Loss function using L2 Regularization regularizer = tf.nn.l2_loss(weights) loss = tf.reduce_mean(loss + beta * regularizer) # Optimizer. optimizer = tf.train.GradientDescentOptimizer(0.5).minimize(loss) # Code 2: # Loss for all trainable variables, 0.001 is beta above vars = tf.trainable_variables() regularizer = tf.add_n([ tf.nn.l2_loss(v) for v in vars ]) * 0.001 # Let's say you wan't to regularize biases regularizer = tf.add_n([ tf.nn.l2_loss(v) for v in vars if 'bias' not in v.name ]) * 0.001 # More descriptive code regularizers = tf.nn.l2_loss(weights_1) + tf.nn.l2_loss(weights_2) + tf.nn.l2_loss(weights_3) + tf.nn.l2_loss(weights_4) + tf.nn.l2_loss(weights_5) + tf.nn.l2_loss(weights_6) loss = tf.reduce_mean(loss + beta * regularizers)
避免使用Vanilla 自动编码器:噪音和稀疏度
考虑如上所述的overcomplete vanilla 自动编码器的情况。显然,他们容易过度拟合和琐碎的学习。因此,使用这些vanilla 自动编码器在这些情况下不会有太大的好处。通过向输入添加噪声来解决这个问题的一种方法是强制神经网络不要学习琐碎的编码,而是集中更多的概括。
去噪编码器在将其馈送到网络之前使用概率过程(P(x(tilda)ij | xij))简单地破坏输入数据 。这些被称为去噪自动编码器。Python代码如下:
# Generate corrupted MNIST images by adding noise with normal dist # centered at 0.618 and std=0.618 noise = np.random.normal(loc=0.618, scale=0.618, size=x_train.shape) x_train_noisy = x_train + noise noise = np.random.normal(loc=0.618, scale=0.618, size=x_test.shape) x_test_noisy = x_test + noise # np.clip to move out of bound values inside given interval x_train_noisy = np.clip(x_train_noisy, 0., 1.) x_test_noisy = np.clip(x_test_noisy, 0., 1.)
Plot描述了针对不同特征(如MNIST数据集数字的笔划,边缘)触发的神经元。显然,与Vanilla AE相比,我们可以看到通过去噪AE捕获更有意义的模式。
随着高斯噪声的加入,这些隐藏的神经元成为边缘检测器,PCA无法给出这些边缘检测器。此外,噪声可以应用于目标类别,这将导致软目标与随机分析而不是硬目标。
稀疏自编码器也被用来解决这种问题与稀疏参数,这将导致神经元在罕见的情况下,当特征是相关的观察。可以写成Lˆ(θ)= L(θ)+Ω(θ),L(θ)是平方误差损失或交叉熵损失和Ω(θ)是稀疏约束力量触发神经元的重要特征。
好处:Contractive Autoencoders,正则化项Ω(θ)= | | J x(h)| | ^ 2是编码器的雅可比矩阵。雅可比矩阵的(j, l)项捕获第l个神经元输出的变化,而第j个输入的变化很小。L(θ)——捕捉重要变化数据&Ω(θ)——不捕捉变化数据,雅可比矩阵使神经元变化不敏感。通过这种权衡,我们只能捕获最重要的特性。对于稀疏AE也可以进行类似的讨论。
参数共享和绑定
共享权重仅意味着使用相同的权重向量来进行计算。这样做的主要动机是限制参数的数量。
ℎ1 = · [1:3], ℎ2 = · [3:5], ℎ3 = · [5:7]
我们可以通过一个直观的假设来显着减少我们的参数,即如果一个特征在一个点上计算很重要,那么它在另一个点上也重要。示例:如果在特定位置检测到边缘很重要。因此,由于图像的平移不变结构,所有边缘重复自身的位置。这将导致更快的收敛。此外,我们限制了灵活性,这也可以起到避免过度拟合的正则化机制的作用。考虑这样一种情况:我们希望并行处理两组图像,但还希望列共享参数。
def function(x, reuse): with tf.variable_scope(layer_name) as s: output = tf.contrib.layers.convolution2d(inputs = x, num_outputs = 10, kernel_size = [3, 3], stride = [1, 1], padding = 'VALID', reuse = reuse, scope = s) return output output1 = function(image1, False) output2 = function(image2, True)
权重绑定概念基于与上述相同的想法,具有相同的减少参数的动机,但是应用于自动编码器单元,其中编码器权重和解码器权重被绑定和使用。它降低了自动编码器的容量,并充当正则化器。
绑定编码器和解码器的权重,即 W * = W T.
DropOut和DropConnect集成
Ensembles将不同模型的输出组合在一起以减少泛化误差,模型可以是不同的分类器。这里,它们是在不同超参数,特征和训练数据的不同样本上训练的相同神经网络的不同实例。Bagging是一种跨整个数据集的方法,用于在训练数据的子集上训练模型。因此,一些训练示例没有显示在给定的模型中。它允许不同的神经元通过不同的训练数据收集不同的相关特征。所有模型平均预测的误差呢?
期望平方误差由:各模型的平均预测得到的误差期望
从上面看,模型彼此之间的独立性越小,误差仅降低到(V / k)。非常好,因为当神经网络的架构变化很大时,理想情况下误差会非常小。但是,随着各个模型数量的增加,训练参数的数量会急剧增加。随着训练计算成本变得昂贵。
如果我们能减少这些参数不是很好吗。此外,不同的架构将帮助我们增加模型之间的差异。Dropout解决了这两个问题。它给出了组合许多不同网络的近似方法,并训练了几个没有任何显着开销的网络。它在所有网络之间共享权重,并为每个训练实例采样不同的训练网络。仅有效参数从正向和反向传播更新。不是聚合2 ^ n个稀疏网络,而是将每个节点的输出按照训练期间的一小部分进行缩放。
Dropout refers to dropping out units。即临时删除节点及其所有传入/传出连接,从而导致网络变薄。
它适用于每个训练示例中的特征,导致某些特征对网络不可用。因为神经元不能完全依赖于一个输入,所以这些网络中的表示往往更加分散,并且网络不太可能过度拟合。这是由于dropout把掩蔽噪声放到了阻止协同适应的隐藏单元中,本质上隐藏单元不会依赖于其他单元来检测特定的特征,因为这些单元可能会dropout。这使得隐藏单位更加健壮。
Python代码如下:
# Simple keras implementation of MNIST for dropout import tensorflow as tf mnist = tf.keras.datasets.mnist (x_train, y_train),(x_test, y_test) = mnist.load_data() x_train, x_test = x_train / 255.0, x_test / 255.0 model = tf.keras.models.Sequential([ tf.keras.layers.Flatten(), tf.keras.layers.Dense(512, activation=tf.nn.relu), tf.keras.layers.Dropout(0.2), tf.keras.layers.Dense(10, activation=tf.nn.softmax) ]) model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy']) model.fit(x_train, y_train, epochs=5) model.evaluate(x_test, y_test)
什么是dropconnect ?好吧,假设我们不删除节点而是随机删除子集。它的行为方式与dropout相似。将从伯努利分布绘制的二元掩模应用于原始权重矩阵。
由于输入数据类或连接对更深层的贡献,连接不会随机丢弃每次训练中的连接,而是会丢弃并保持连接。
tf.nn.dropout(W, keep_prob=p) * p OR tf.layers.dropout(W, rate=1-p) * p
结论
在何时使用这些技术的直觉中,我们可以创建有效的深层神经网络,在其核心内更智能,同时可以学习任何特定任务。