TensorFlow深度学习实战(5)——神经网络性能优化技术详解
TensorFlow深度学习实战(5)——神经网络性能优化技术详解
- 0. 前言
- 1. 识别 MNIST 手写数字
- 1.1 MNIST 数据集
- 1.2 独热编码
- 1.3 定义神经网络
- 1.4 训练神经网络
- 2. 构建深度神经网络
- 3. 添加 Dropout 提高模型泛化能力
- 4. 不同优化器对模型性能的影响
- 5. 训练 epochs 数对神经网络性能的影响
- 6. 学习率对神经网络性能的影响
- 7. 隐藏层神经元数量对神经网络性能的影响
- 8. 批大小对神经网络性能的影响
- 9. 超参数调整和 AutoML
- 小结
- 系列链接
0. 前言
我们已经学习了神经网络的基础概念,并了解了如何利用 TensorFLow 构建神经网络模型。同时我们还提到了,有多种超参数可以影响神经网络的准确性。在本节中,我们首先回顾使用 TensorFlow
构建 MNIST
手写数字识别神经网络,然后详细介绍神经网络中各种超参数的作用,通过使用不同的超参数优化神经网络性能。
1. 识别 MNIST 手写数字
1.1 MNIST 数据集
在本节中,我们将构建一个能够识别手写数字的网络,使用 MNIST
数据集,MNIST
数据集是一个由手写数字组成的数据集,其中包括 60,000
个训练样本和 10,000
个测试样本,训练样本人工标注了正确标签。例如,如果手写数字是 “3
”,那么 “3
” 就是该样本的标签。MNIST
数据集中的图像都是灰度图像,包含 28 x 28
像素,数据集中的部分数据示例如下所示:
在机器学习中,当有正确标签的数据集可用时,我们称之为监督学习 (supervised learning
)。在这种情况下,可以使用训练样本来改进网络。测试示例也包含每个图像的正确标签,但在测试时,我们假设标签是未知的,让网络进行预测,然后再考虑标签,以评估神经网络的学习效果,测试样本仅用于测试网络性能。
1.2 独热编码
独热编码作为在神经网络内部编码信息的简单工具,常用于将类别型(非数值型)特征转换为数值型变量。例如,将在 [0-9]
范围内的 MNIST
类别标签 d
编码成一个具有 10
个位置的二进制向量,其中除了第 d
个位置是 1
外,其他位置都是 0
。例如,数字 3
可以编码为 [0, 0, 0, 1, 0, 0, 0, 0, 0, 0]
。这种表示方式称为独热编码 (One-Hot-Encoding
, OHE
),或简称 one-hot
。
1.3 定义神经网络
在本节中,我们将使用 TensorFlow
定义一个用于识别 MNIST
手写数字的神经网络。我们从一个非常简单的神经网络开始,并逐步改进。
TensorFlow
提供了用于加载数据集的函数,并将其分割成训练集 X_train
(用于调整网络)和测试集 X_test
(用于评估性能),训练集是用于神经网络从数据样本中学习的数据集。训练过程中,需要将数据转换为 float32
类型,并归一化到范围 [0,1]
,以便在训练神经网络时使用 32
位精度。此外,将真实标签分别加载到 Y_train
和 Y_test
中,并对它们进行独热编码。
直观地说,神经网络训练中的 epoch
定义了训练应该持续多久,BATCH_SIZE
是一次向网络输入的样本数,验证样本是为检查或证明训练过程的有效性而保留的数据量:
import tensorflow as tf
import numpy as np
from tensorflow import keras
# network and training
EPOCHS = 200
BATCH_SIZE = 128
VERBOSE = 1
NB_CLASSES = 10 # number of outputs = number of digits
N_HIDDEN = 128
VALIDATION_SPLIT=0.2 # how much TRAIN is reserved for VALIDATION
# loading MNIST dataset
mnist = keras.datasets.mnist
(X_train, Y_train), (X_test, Y_test) = mnist.load_data()
print(X_train.shape[0], 'train samples')
print(X_test.shape[0], 'test samples')
#normalize in [0,1]
X_train, X_test = X_train / 255.0, X_test / 255.0
#X_train is 60000 rows of 28x28 values --> reshaped in 60000 x 784
RESHAPED = 784
X_train = X_train.reshape(60000, RESHAPED)
X_test = X_test.reshape(10000, RESHAPED)
Y_train = Y_train.astype('float32')
Y_test = Y_test.astype('float32')
# One-hot representation of the labels
Y_train = tf.keras.utils.to_categorical(Y_train, NB_CLASSES)
Y_test = tf.keras.utils.to_categorical(Y_test, NB_CLASSES)
从代码中可以看出,输入层有 784
个神经元,每个神经元与图像中的每个像素相关联,总计 28 x 28 = 784
个神经元,对应 MNIST
图像中的每个像素。
通常,每个像素值会被归一化到范围 [0,1]
内(这意味着每个像素的强度都除以 255
,即最大强度值)。输出是十个类别之一,每个数字对应一个类别。
需要注意的是,to_categorical(Y_train, NB_CLASSES)
将数组 Y_train
转换为独热编码,其列数与类别数相同。因此,如果我们有数组 labels
:
>>> labels = np.array([0, 2, 1, 2, 0])
使用 to_categorical()
进行转换:
>>> tf.keras.utils.to_categorical(labels)
array([[1., 0., 0.],
[0., 0., 1.],
[0., 1., 0.],
[0., 0., 1.],
[1., 0., 0.]], dtype=float32)
网络最后一层是一个单一的神经元,带有激活函数 softmax
,它是 sigmoid
函数的推广。sigmoid
函数中,当输入范围在
(
−
∞
,
∞
)
(−∞, ∞)
(−∞,∞) 之间时,输出的变化范围为
(
0
,
1
)
(0,1)
(0,1) 之间。类似地,softmax
将一个
K
K
K 维的任意实值向量“压缩”为一个
K
K
K 维的实值向量,范围在
(
0
,
1
)
(0, 1)
(0,1) 之间,使得所有值的和为 1
。在代码中可以看到,输出层聚合了前一层的十个神经元提供的十个输出结果:
model = tf.keras.models.Sequential()
model.add(keras.layers.Dense(NB_CLASSES,
input_shape=(RESHAPED,), kernel_initializer='zeros',
name='dense_layer', activation='softmax'))
定义了模型之后,需要对其进行编译,以便 TensorFlow
可以执行。在编译过程中。首先,需要选择一个优化器,用于在训练模型时更新权重。其次,我们需要选择一个目标函数(目标函数通常也称损失函数),优化器使用目标函数在权重空间中寻找最优解,优化过程定义为损失最小化的过程)。第三,我们需要评估训练好的模型。
常见的损失函数如下:
mse
,定义为预测值与真实值之间的均方误差。数学上,如果 y y y 是 n n n 维真实值向量, d d d 是预测向量,则均方误差为 M S E = 1 n ∑ i = 1 n ( d i − y i ) 2 MSE=\frac{1}{n} \sum_{i=1}^n ({d}_i - {y}_i)^2 MSE=n1∑i=1n(di−yi)2。需要注意的是,此损失函数是所有预测误差的平均值。如果预测值与真实值差距很大,平方操作会使这个差距更加明显。此外,平方操作可以累计误差,无论误差是正数还是负数binary_crossentropy
,定义为二分类对数损失。假设模型预测为 p p p,目标为 c c c,则二元交叉熵定义为 L ( p , c ) = − c ln ( p ) − ( 1 − c ) ln ( 1 − p ) L(p, c) = -c \ln(p) - (1 - c) \ln(1 - p) L(p,c)=−cln(p)−(1−c)ln(1−p),此损失函数适用于二元标签的预测categorical_crossentropy
,定义为多分类对数损失。分类交叉熵将预测的分布与真实分布进行比较,此损失函数适用于多类别标签的预测,如果真实类别为 c c c,预测值为 p p p,则分类交叉熵定义为:
L ( c , p ) = − ∑ i c i ln ( p i ) L(c,p)=-\sum_ic_i\ln(pi) L(c,p)=−i∑ciln(pi)
常见的模型评价指标如下:
混淆矩阵 | 真实值 | ||
Positive | Negative | ||
预测值 | Positive | 真阳性(True Positive, TP) | 假阳性(False Positive, FP) |
Negative | 假阴性(False Negative, FN) | 真阴性(True Negative, TN) |
准确率 (Accuracy
, ACC
):判断正确的结果与所有观测样本之比:
A
C
C
=
T
P
+
T
N
T
P
+
F
P
+
F
N
+
T
N
ACC= \frac{TP+TN}{TP+FP+FN+TN}
ACC=TP+FP+FN+TNTP+TN
精确率 (Precision
)或阳性预测值 (Positive Predictive Value
, PPV
):判断正确的结果占预测为 Positive
的比例:
P
r
e
c
i
s
i
o
n
=
T
P
T
P
+
F
P
Precision= \frac{TP}{TP+FP}
Precision=TP+FPTP
灵敏度 (Sensitivity
) 或称召回率 (Recall
) 或真阳率 (True Positive Rate
, TPR
):模型预测正确的个数占真实值为 Positive
的比例:
S
e
n
s
i
t
i
v
i
t
y
=
T
P
T
P
+
F
N
Sensitivity= \frac{TP}{TP+FN}
Sensitivity=TP+FNTP
评价指标与损失函数类似,唯一的区别在于评价指标并不用于训练模型,而仅用于评估模型。损失函数用于优化网络,是由所选用优化器最小化的函数,而评价指标用于评估网络性能,不参与优化过程。当然,直接优化特定的评价指标是最理想的情况,然而,有些指标对其输入不可微,因此无法直接用于优化。
在 TensorFlow
中编译模型时,可以选择不同优化器、损失函数和评价指标:
# summary of the model
model.summary()
# compiling the model
model.compile(optimizer='SGD',
loss='categorical_crossentropy',
metrics=['accuracy'])
随机梯度下降 (Stochastic Gradient Descent
, SGD
) 是一种优化算法,用于减少神经网络在每次训练时产生的误差。一旦模型编译完成,可以使用 fit()
方法对其进行训练,该方法接受以下参数:
epochs
,训练数据集完成了一次前向计算和反向传播的过程称为一个epoch
,通常所有数据仅迭代训练一次是不够的, 需要迭代训练多个epochs
多次才能拟合。在每次迭代中,优化器尝试调整权重,使损失函数最小化batch_size
,为了更好的进行训练,通常将所有数据分成多个batch
(批),每次训练一部分数据训练,batch_size
是每个batch
中数据样本的数量
#training the moodel
model.fit(X_train, Y_train,
batch_size=BATCH_SIZE, epochs=EPOCHS,
verbose=VERBOSE, validation_split=VALIDATION_SPLIT)
需要注意的是,我们需要将一部分训练集保留用于模型验证(称为验证集,validation_split
参数用于指定验证集的比例)。关键思想是在训练过程中保留一部分训练数据,用于测量在验证集上的性能。一旦模型训练完成,我们可以在测试集上进行评估,测试集包含在训练阶段模型未见过的新数据样本。
训练集和测试集是严格分离的。在评估模型时,使用已用于训练的数据样本是没有意义的。在 TensorFlow
中,可以使用 evaluate(X_test, Y_test)
方法来计算测试损失 (test_loss
) 和测试准确率 (test_acc
):
#evalute the model
test_loss, test_acc = model.evaluate(X_test, Y_test)
print('Test accuracy:', test_acc)
1.4 训练神经网络
运行以上代码,观察输出:
首先,输出了网络架构,可以看到使用了不同类型的层,它们的输出形状,需要优化的参数数量 (即权重数量),以及层之间的连接方式。
然后,网络在 48K
个样本上进行训练,并将 12K
样本保留用于验证。神经模型训练完成后,在 10K
个样本上进行测试。观察训练过程,可以看到程序运行了 200
次迭代,每次迭代时准确率都有所提高。
训练结束后,模型在训练数据集上的准确率大约为 92.32%
,在验证集上的准确率为 92.40%
,在测试集上的准确率为 92.19%
:
这意味着大约有十分之一的图像被错误分类了,接下来,我们介绍神经网络性能优化技术,进一步改进以上简单神经网络。
2. 构建深度神经网络
一个简单的改进是向网络中添加更多的层,即增加网络的深度,因为这些额外的神经元可能会帮助学习训练数据中更复杂的模式。换句话说,使用更多的层增加了更多的参数,可能使模型能够记住更复杂的模式。因此,在输入层之后,我们使用一个具有 N_HIDDEN
神经元和激活函数 relu
的全连接层,该层也称隐藏层,因为它既不直接与输入相连,也不直接与输出相连。在第一个隐藏层之后,添加第二个隐藏层,同样具有 N_HIDDEN
个神经元,然后是一个具有十个神经元的输出层,每个神经元在识别到相应的数字时会激活:
import tensorflow as tf
import numpy as np
from tensorflow import keras
# network and training
EPOCHS = 50
BATCH_SIZE = 128
VERBOSE = 1
NB_CLASSES = 10 # number of outputs = number of digits
N_HIDDEN = 128
VALIDATION_SPLIT=0.2 # how much TRAIN is reserved for VALIDATION
# loading MNIST dataset
mnist = keras.datasets.mnist
(X_train, Y_train), (X_test, Y_test) = mnist.load_data()
#X_train is 60000 rows of 28x28 values --> reshaped in 60000 x 784
RESHAPED = 784
X_train = X_train.reshape(60000, RESHAPED)
X_test = X_test.reshape(10000, RESHAPED)
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
#normalize in [0,1]
X_train /= 255
X_test /= 255
print(X_train.shape[0], 'train samples')
print(X_test.shape[0], 'test samples')
#one-hot
Y_train = tf.keras.utils.to_categorical(Y_train, NB_CLASSES)
Y_test = tf.keras.utils.to_categorical(Y_test, NB_CLASSES)
#build the model
model = tf.keras.models.Sequential()
model.add(keras.layers.Dense(N_HIDDEN,
input_shape=(RESHAPED,),
name='dense_layer', activation='relu'))
model.add(keras.layers.Dense(N_HIDDEN,
name='dense_layer_2', activation='relu'))
model.add(keras.layers.Dense(NB_CLASSES,
name='dense_layer_3', activation='softmax'))
# summary of the model
model.summary()
# compiling the model
model.compile(optimizer='SGD',
loss='categorical_crossentropy',
metrics=['accuracy'])
#training the model
model.fit(X_train, Y_train,
batch_size=BATCH_SIZE, epochs=EPOCHS,
verbose=VERBOSE, validation_split=VALIDATION_SPLIT)
#evaluate the model
test_loss, test_acc = model.evaluate(X_test, Y_test)
print('Test accuracy:', test_acc)
# making prediction
predictions = model.predict(X_test)
运行改进后的代码,观察多层网络训练过程:
可以看到,通过添加两个隐藏层,模型在训练数据集上准确率能够达到 99.77%
,在验证集上的准确率达到了 97.43%
,在测试集上的准确率达到了 97.58%
。这意味着与基准网络相比,模型的准确率得到了较大提升,并且迭代次数从 200
次减少到了 50
次。需要注意的是,模型性能的改进在若干个 epoch
后会陷入停滞,在机器学习中称为收敛 (convergence
)。
3. 添加 Dropout 提高模型泛化能力
Dropout
技术会在训练过程中随机(以 DROPOUT
概率)丢弃一些在网络隐藏层中传播的值,换句话说,每批数据训练时只有一定比例的权重被更新,而其余的权重不被更新。在机器学习中,这是一种经典的正则化方法。随机丢弃会迫使网络学习冗余模式,能够更好地泛化:
import tensorflow as tf
import numpy as np
from tensorflow import keras
# network and training
EPOCHS = 50
BATCH_SIZE = 128
VERBOSE = 2
NB_CLASSES = 10 # number of outputs = number of digits
N_HIDDEN = 128
VALIDATION_SPLIT=0.2 # how much TRAIN is reserved for VALIDATION
DROPOUT = 0.3
# loading MNIST dataset
mnist = keras.datasets.mnist
(X_train, Y_train), (X_test, Y_test) = mnist.load_data()
#X_train is 60000 rows of 28x28 values --> reshaped in 60000 x 784
RESHAPED = 784
X_train = X_train.reshape(60000, RESHAPED)
X_test = X_test.reshape(10000, RESHAPED)
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
#normalize in [0,1]
X_train /= 255
X_test /= 255
print(X_train.shape[0], 'train samples')
print(X_test.shape[0], 'test samples')
#one-hot
Y_train = tf.keras.utils.to_categorical(Y_train, NB_CLASSES)
Y_test = tf.keras.utils.to_categorical(Y_test, NB_CLASSES)
#build the model
model = tf.keras.models.Sequential()
model.add(keras.layers.Dense(N_HIDDEN,
input_shape=(RESHAPED,),
name='dense_layer', activation='relu'))
model.add(keras.layers.Dropout(DROPOUT))
model.add(keras.layers.Dense(N_HIDDEN,
name='dense_layer_2', activation='relu'))
model.add(keras.layers.Dropout(DROPOUT))
model.add(keras.layers.Dense(NB_CLASSES,
name='dense_layer_3', activation='softmax'))
# summary of the model
model.summary()
# compiling the model
model.compile(optimizer='SGD',
loss='categorical_crossentropy',
metrics=['accuracy'])
#training the model
model.fit(X_train, Y_train,
batch_size=BATCH_SIZE, epochs=EPOCHS,
verbose=VERBOSE, validation_split=VALIDATION_SPLIT)
#evaluate the model
test_loss, test_acc = model.evaluate(X_test, Y_test)
print('Test accuracy:', test_acc)
# making prediction
predictions = model.predict(X_test)
运行 50
次迭代,可以看到添加 Dropout
后的网络在训练集上的准确率达到了 94.49%
,在验证集上的准确率达到了 96.22%
,在测试集上的准确率达到了 96.09%
:
在隐藏层中使用 Dropout
的网络可以在未见过的测试集样本上表现得更好,即能够更好地“泛化”。直观地说,我们可以认为这是因为每个神经元变得更加强大,因为它并不过分依赖邻近的神经元。此外,它迫使信息以冗余的方式存储。在测试过程中不使用 Dropout
,因此在测试过程中使用了所有经过高度调整的神经元。
需要注意的是,训练准确率应高于测试准确率;否则,可能是由于网络没有进行足够的训练,因此应该增加 epoch
数。
4. 不同优化器对模型性能的影响
梯度下降 (Gradient Descent
, GD
) 是一种流行的网络训练技术。假设,有一个含有单变量
w
w
w 的通用损失函数
C
(
w
)
C(w)
C(w),如下所示:
GD
可以类比为登山者,需要沿着陡坡向下走,并且目标是进入谷底,陡坡代表函数
C
C
C,而谷底则代表最小值
C
m
i
n
C_{min}
Cmin。登山者从起点
w
0
w_0
w0 开始逐步移动,假设可见度几乎为零,登山者无法看到前进的方向,只能谨慎前行。在每一步
r
r
r 中,梯度表示函数在该点处的方向导数沿着该方向取得最大值,即函数在该点处沿着该方向(此梯度的方向)变化最快,变化率最大(为该梯度的模)。
从数学上讲,这个方向就是在步骤
r
r
r 达到的点
w
r
w_r
wr 处计算的偏导数的值
∂
C
∂
w
\frac {\partial C}{\partial w}
∂w∂C。因此,通过沿着相反的方向
−
∂
C
∂
w
(
w
r
)
-\frac {\partial C}{\partial w}(w_r)
−∂w∂C(wr) 移动,登山者可以朝着谷底前进。
在每一步中,登山者可以决定下一步的步伐有多大,这就是 GD
中的学习率 (learning rate
)
η
≥
0
η≥0
η≥0。如果
η
η
η 太小,那么登山者会移动得很慢,如果
η
η
η 太大,登山者可能会因为跨过谷底而错过它。
Sigmoid
是连续函数,并且可以计算导数。可以证明 Sigmoid
函数
σ
(
x
)
=
1
1
+
e
−
x
σ(x)=\frac 1{1+e^{-x}}
σ(x)=1+e−x1 的导数为
d
σ
(
x
)
d
x
=
σ
(
x
)
(
1
−
σ
(
x
)
)
\frac {dσ(x)}{dx}=σ(x)(1−σ(x))
dxdσ(x)=σ(x)(1−σ(x))。
虽然 ReLU
在 0
处不可微。但我们可以通过将其定义为 0
或 1
来扩展其在整个域上的一阶导数。ReLU
函数
y
=
m
a
x
(
0
,
x
)
y = max(0, x)
y=max(0,x) 的分段导数是
d
y
d
x
=
{
0
x
<
0
1
x
≥
0
\frac{dy}{dx} =\begin{cases}0& {x<0}\\1& {x ≥ 0}\end{cases}
dxdy={01x<0x≥0。
有了导数后,就可以使用梯度下降技术优化神经网络。TensorFlow
会自动计算导数,因此我们无需担心如何进行计算。神经网络本质上是多个可导函数的组合,这些函数具有数千甚至数百万个参数。每个网络层计算一个函数,其误差应该在学习阶段中最小化,以提高模型准确性。反向传播时,最小化过程比我们的简单类比要复杂得多,但原理是相同的。
TensorFlow
实现多种 GD
变体,包括随机梯度下降 (Stochastic Gradient Descent
, SGD
)、RMSProp
和 Adam
等。RMSProp
和 Adam
除了具有 SGD
的加速分量外,还使用了动量(一个速度分量)的概念,使得模型收敛速度更快,但计算量也更大。可以证明,动量有助于加速 SGD
朝着相关方向移动,并抑制震荡。
接下来,尝试使用其它优化器:
# compiling the model
model.compile(optimizer='RMSProp',
loss='categorical_crossentropy',
metrics=['accuracy'])
训练模型,观察结果可以看到,RMSProp
比 SGD
更快,仅仅使用 10
个 epochs
,在训练数据集上的准确率就达到了 97.23%
,在验证集上的准确率达到了 97.55%
,在测试集上的准确率达到了 97.66%
,相较 SGD
有了显著的提高。尝试将 epochs
数量增加到 50
,在训练数据集上的准确率为 98.70%
,在验证集上的准确率为 98.44%
,在测试集上的准确率为 97.85%
:
尝试另一个优化器,Adam()
:
model.compile(optimizer='Adam',
loss='categorical_crossentropy',
metrics=['accuracy'])
可以看到,Adam()
的表现更好一些。使用 Adam
,50
次迭代后,在训练数据集上的准确率可以达到 98.92%
,在验证集上的准确率为 97.82%
,在测试集上的准确率为 97.96%
:
优化器的选择并没有一成不变的规则,根据具体问题,使用不同优化器可能会获得不同的性能表现。
5. 训练 epochs 数对神经网络性能的影响
将训练中使用的 epochs
数量从 20
增加到 200
,这会使计算时间增加十倍,但并未带来任何收益。因此,一味的增加更多时间训练,并不一定会改善结果。网络训练关键在于改进技术,而不仅仅是计算时间的长短。使用不同 epochs
进行训练的模型性能对比如下:
6. 学习率对神经网络性能的影响
调整优化器的学习参数。使用 4
个不同的参数 lr=0.1
、lr=0.01
、lr=0.001
和 0.0001
:
7. 隐藏层神经元数量对神经网络性能的影响
改变隐藏层神经元的数量,使用不同数量隐藏层神经元进行的实验。可以看到,增加模型的复杂性,运行时间会显著增加,因为更多的参数需要优化。然而,随着网络规模的增加,通过增加网络大小获得的增益逐渐减少:
另一方面,随着网络规模的增加,所需的训练时间也会增加:
需要注意的是,过度的增加隐藏神经元数量可能会降低模型准确性,因为网络可能无法很好地泛化:
8. 批大小对神经网络性能的影响
梯度下降考虑所有输入特征,在训练集中的所有样本上最小化损失函数。而随机梯度下降是梯度下降的一种变体,一次训练只考虑 BATCH_SIZE
个样本。接下来,修改 BATCH_SIZE
大小,观察模型性能:
9. 超参数调整和 AutoML
对于给定的神经网络,可以通过调整不同参数(如隐藏层神经元数量、批大小、epochs
数量等)进行优化,为了区别网络本身的参数(即权重和偏置),这些参数也称为超参数 ( Hyperparameter
)。
超参数调整是寻找能够最小化损失函数的最佳超参数组合的过程。如果有
n
n
n 个超参数,那么假设它们定义了一个
n
n
n 维空间,目标是找到这个空间中对应于损失函数最优值的点。实现这一目标的一种方法是在这个空间中创建一个网格,并系统地检查每个网格顶点处损失函数的值。换句话说,超参数被划分为网格,然后通过穷举的方法检查不同值的组合。
这种手动调整超参数的过程计算复杂,AutoML
是指通过自动化的技术和工具来简化机器学习模型的开发和优化过程,减少人工干预,从而使得非专业的用户也能够轻松地构建高效的机器学习模型,能够专注于更高层次的任务,而非繁琐的调参和模型选择。
小结
通过不同的变体改进网络,我们能够将手写数字识别模型性能从 90.71%
提升到 97.82%
。首先,在 TensorFlow
中定义了一个简单的单层网络。然后,通过添加一些隐藏层来提高性能。接着,在网络中添加了 Dropout
,并通过尝试不同类型的优化器来改善模型在测试集上的性能。
然而,接下来的两种改进并没有显著改进模型性能。增加神经元的数量会创建更复杂的模型,需要更多计算,但仅带来边际性的提升。同样,如果增加训练的 epoch
数量或改变优化器的 BATCH_SIZE
,会遇到同样的问题。
系列链接
TensorFlow深度学习实战(1)——神经网络与模型训练过程详解
TensorFlow深度学习实战(2)——使用TensorFlow构建神经网络
TensorFlow深度学习实战(3)——深度学习中常用激活函数详解
TensorFlow深度学习实战(4)——正则化技术详解