昨天我们尝试动手刻了一个神经网路,准确度虽然看似很高了,但似乎还有进步的空间,今天我们就来介绍如何优化我们的神经网路。
在优化前我们要先搞清楚,要优化神经网路的哪个部分,那就必须知道什麽样的神经网路是好的,一般来说评估标准有以下三点:
准确度自然不用多说,我们当然希望模型预测的答案越准越好,而推论速度是指模型预测出答案的时间,在一些实务上(自动驾驶),我们需要模型在短时间内就给出预测值,这时候推论速度就很重要,而模型大小则会影响神经网路在一些边缘装置上的应用,例如架设摄影机辨识路人有没有戴口罩,我们不可能搬一台电脑到路上,就要应用一些边缘装置,像是Jetson Nano。
具体该优化哪个指标,其实还是要看我们面对什麽样的问题,假如是自动驾驶要感应周围有没有障碍物,推论速度就是一个很重要的指标;假如是要找出潜在的信用卡盗刷交易,那麽准确度就是重要的指标,先了解该追求哪项指标,再去优化自己的神经网路模型,下面我们开始介绍有哪些优化方法。
对资料集的优化通常是最有效的办法,尤其是对於准确率的提升,能拥有一个好的资料集比其他模型超参数的优化来的重要许多,资料集优化主要有以下几项:
这部分我们在前面的章节有详细的介绍过,大家可以回去看这篇。
调参的部分也是在打比赛中一个很重要的优化过程,有人说神经网路内部的训练过程就像一个黑盒子,我们无法得知他的计算过程,因此只能透过调整参数的方式去尝试更好的组合,下面我们就来介绍一些超参数以及调整方式:
每个训练批次所提取的资料数,通常我们会设定比目标类别还要多一些,才能确保每次训练都会抽到不同标签的样本,但批次大小也不太能随意调整,需考虑自身设备的记忆体大小,若批次太大可能会跑不动。
神经网路训练的次数,当你发现模型训练的准确度不断上升时,就可以调高训练的轮次,让模型继续收敛,反之模型如果一直没有进步,就要将降低训练的轮次
学习率是控制梯度下降的参数,学习率过大会导致模型找不到局部最佳解;而学习率过小则会造成收敛速度过慢,且会被困在局部最佳解的点,无法找到全局最佳解,一般来说会设定0.01,但要随时根据不同情况做调整。
最好的方法是设置"动态学习率",在模型随着训练次数的增加去调整它的学习率,当梯度下降较快时,增加学习率,而当梯度趋於平缓时就降低学习率,下面的程序码范例可根据不同情况做调整。
#设置动态学习率
from tensorflow.keras.callbacks import ReduceLROnPlateau
LR_function=ReduceLROnPlateau(monitor='val_acc',
patience=5,
# 5 epochs 内acc没下降就要调整LR
verbose=1,
factor=0.5,
# LR降为0.5
min_lr=0.00001
# 最小 LR 到0.00001就不再下降
)
最佳化方法有很多种,最常见的就是随机梯度下降(SGD),其他还有像是Adagrad、RMSProp、Adam...等多种方法,模型都可以尝试去套套看,Keras中也有支援,只需简单的程序码即可使用。
#SGD
tf.keras.optimizers.SGD(
learning_rate=0.01, momentum=0.0, nesterov=False, name='SGD', **kwargs
)
#Adagrad
tf.keras.optimizers.Adagrad(
learning_rate=0.001, initial_accumulator_value=0.1, epsilon=1e-07,
name='Adagrad', **kwargs
)
#RMSProp
tf.keras.optimizers.RMSprop(
learning_rate=0.001, rho=0.9, momentum=0.0, epsilon=1e-07, centered=False,
name='RMSprop', **kwargs
)
#Adam
tf.keras.optimizers.Adam(
learning_rate=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-07, amsgrad=False,
name='Adam', **kwargs
)
除了参数的调整,我们也可以对整个网路模型进行一些优化方法。
这是Google提出的一种正规化技术,用来防止过度拟合的问题,其作法是在神经网路的某些层中,随机丢弃部分的神经元,如此可避免在训练的过程中有过多的神经元产生复杂的相互适应,让剩下的神经元在更新资讯後更强健,作法如下:
input_shape = (128, 128, 3)
# 建立简单的线性执行的模型
model = Sequential()
# 建立卷积层
model.add(Conv2D(32, kernel_size=(3, 3),
activation='relu',
input_shape=input_shape,
padding="same"))
# 建立卷积层
model.add(Conv2D(64, (3, 3), activation='relu',padding="same"))
# 建立池化层,池化大小2x2,取最大值
model.add(MaxPooling2D(pool_size=(2, 2)))
# Dropout层随机断开输入神经元,用於防止过度拟合,断开比例:0.25
model.add(Dropout(0.25))
# Flatten层把多维的输入一维化,常用在从卷积层到全连接层的过渡。
model.add(Flatten())
# 全连接层: 128个output
model.add(Dense(128, activation='relu'))
# Dropout层随机断开输入神经元,用於防止过度拟合,断开比例:0.5
model.add(Dropout(0.5))
# 使用 softmax activation function,将结果分类
model.add(Dense(num_classes, activation='softmax'))
这个技巧主要是为了使模型变小,其原理为去除神经网路中冗余的参数,使得模型大小缩减、运算速度提高,有点类似Dropout,但Pruning是对已训练完成或套用其他权重的模型使用。这个做法稍微有些复杂,但Tensorflow有好心的提供范例,小编在此附上连结大家可以去参考。
目前大多数的神经网路模型在训练即推论时都是使用FP32的精度(32位元浮点数),而我们可以透过咿些转换的方法将精度调降为FP16或是int8,如此一来其运算速度可以倍数成长,但精度调整就像一把双面刃,调整时会造成资讯的流失,准确度也会随之降低,因此要决定出一个好的平衡点,再去使用这个方法,TensorRT有提供转换教学,网址如下:
TFLite是Tensorflow提供的一种架构,其价值在於将神经网路部属到一些微型装置,透过转换、压缩等功能可以降低模型的大小、提升模型的推论速度。
篇幅的关系我这边就不详细介绍了,一样附上网址:
今天介绍了一些优化神经网路的方法,最後想要提醒大家的是,尽管优化方法有很多,但不代表我们用了很多方法加到模型里,我们的模型就会变得多厉害,也不是一次把所有方法加上去就好,调参时要有耐心的慢慢尝试每种方法,找到一个最适合模型的组合。
明天我们将介绍另一种常见的优化方法-使用预训练模型,敬请期待吧!
>>: Day 09:今天又想不出标题了!tmux plugin 和 mouse mode
焦虑感的来袭 不得不说,在有工作的情形下,一方面要努力完成现有的工作,另一方面还得焦虑自己是否能够真...
想要快速开发一个 Bootstrap 网页设计样版的网站,可以利用网路上已经设计好的网页样版下载套用...
昨天的range函式有搞清楚了吗?如果没有一定要再回去复习,不然今天的for回圈你会一直混乱呦 (⊙...
从 2020 Day 21 - Replication 开始到现在,我们大多都是在谈系统出错了怎麽办...