Keras是一个简单易用但功能强大的Python深度学习库。在本文中,我们将看到构建前馈神经网络并对其进行训练以解决Keras的实际问题是多么容易。
这篇文章是为Keras的初学者准备的,但是确实假设了神经网络的基本背景知识。
让我们开始吧!
问题:MNIST数字分类
我们将解决一个经典的机器学习问题:MNIST手写数字分类。很简单:给定图像,将其分类为数字。
MNIST数据集中的每个图像均为28x28,并包含居中的灰度数字。我们将每个28x28展平为784维向量,并将其用作神经网络的输入。我们的输出将是10种可能的类别之一:每位数一个。
1.设定
我假设您已经准备好基本的Python安装(您可能已经安装了)。首先安装一些我们需要的软件包:
$ pip install keras tensorflow numpy mnist
注意:我们需要安装,
tensorflow
因为我们要在TensorFlow后端上运行Keras (即TensorFlow将为Keras供电)。
现在,您应该能够导入这些软件包
import numpy as np
import mnist
import keras
# The first time you run this might be a bit slow, since the
# mnist package has to download and cache the data.
train_images = mnist.train_images()
train_labels = mnist.train_labels()
print(train_images.shape) # (60000, 28, 28)
print(train_labels.shape) # (60000,)
2.准备数据
如前所述,我们需要先归一化每个图像,然后才能将其传递到神经网络中。我们还将像素值从[0,255]标准化为[-0.5,0.5],以使我们的网络更易于训练(使用较小的居中值通常更好)。
import numpy as np
import mnist
train_images = mnist.train_images()
train_labels = mnist.train_labels()
test_images = mnist.test_images()
test_labels = mnist.test_labels()
# Normalize the images.
train_images = (train_images / 255) - 0.5
test_images = (test_images / 255) - 0.5
# Flatten the images.
train_images = train_images.reshape((-1, 784))
test_images = test_images.reshape((-1, 784))
print(train_images.shape) # (60000, 784)
print(test_images.shape) # (10000, 784)
我们准备开始构建我们的神经网络!
3.建立模型
每个Keras模型要么使用表示线性层堆栈的Sequential类构建,要么使用可定制的功能性Model类构建。我们将使用更简单的Sequential
模型,因为我们的网络确实是一个线性的层堆栈。
我们从实例化Sequential
模型开始:
from keras.models import Sequential
from keras.layers import Dense
# WIP
model = Sequential([
# layers...
])
所述Sequential
构造函数采用Keras阵列层。由于我们只是在构建标准的前馈网络,因此我们只需要Dense层,这是您的常规全连接(密集)网络层。
让我们分Dense
三层:
# Still a WIP
model = Sequential([
Dense(64, activation='relu'),
Dense(64, activation='relu'),
Dense(10, activation='softmax'),
])
前两层各有64个节点,并使用ReLU激活功能。最后一层是Softmax输出层,具有10个节点,每个类一个。
我们始终需要做的最后一件事是告诉Keras,我们网络的输入将是什么样子。我们可以通过input_shape
在Sequential
模型的第一层指定一个来做到这一点:
model = Sequential([
Dense(64, activation='relu', input_shape=(784,)),
Dense(64, activation='relu'),
Dense(10, activation='softmax'),
])
一旦指定了输入形状,Keras将自动推断出输入形状,供以后的图层使用。我们已经定义了模型!这是我们的位置:
import numpy as np
import mnist
from keras.models import Sequential
from keras.layers import Dense
train_images = mnist.train_images()
train_labels = mnist.train_labels()
test_images = mnist.test_images()
test_labels = mnist.test_labels()
# Normalize the images.
train_images = (train_images / 255) - 0.5
test_images = (test_images / 255) - 0.5
# Flatten the images.
train_images = train_images.reshape((-1, 784))
test_images = test_images.reshape((-1, 784))
# Build the model.
model = Sequential([
Dense(64, activation='relu', input_shape=(784,)),
Dense(64, activation='relu'),
Dense(10, activation='softmax'),
])
4.编译模型
在开始训练之前,我们需要配置训练过程。我们在编译步骤中确定3个关键因素:
- 优化器。我们将坚持一个非常好的默认值:基于Adam梯度的优化器。Keras还提供了许多其他优化器。
-
损失函数。由于我们使用的是Softmax输出层,因此我们将使用交叉熵损失。Keras区分
binary_crossentropy
(2个类别)和categorical_crossentropy
(> 2个类别),因此我们将使用后者。查看所有Keras的损失。 - 指标列表。由于这是一个分类问题,因此我们只提供Keras报告准确性指标。
该编译如下所示:
model.compile(
optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy'],
)
5.训练模型
从Keras训练模型实际上仅包括调用fit()
和指定一些参数。有很多可能的参数,但我们只会手动提供一些:
- 训练数据(图像和标签),通常分别称为X和Y,。
- epoch 的数目在整个数据集迭代的次数。
- 训练时要使用的批次大小(每个梯度更新的样本数)。
看起来像这样:
model.fit(
train_images, # training data
train_labels, # training targets
epochs=5,
batch_size=32,
)
不过,这实际上还行不通-我们忽略了一件事。Keras期望训练目标是10维向量,因为我们的Softmax输出层中有10个节点,但是我们提供了一个整数来表示每个图像的类。
方便地,Keras提供了一种实用程序方法来解决此确切问题:to_categorical。它把我们的类整数数组变成一个一元向量数组。例如,2
将变为[0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
(索引为零)。
现在,我们可以将所有内容放在一起来训练我们的网络:
import numpy as np
import mnist
from keras.models import Sequential
from keras.layers import Dense
from keras.utils import to_categorical
train_images = mnist.train_images()
train_labels = mnist.train_labels()
test_images = mnist.test_images()
test_labels = mnist.test_labels()
# Normalize the images.
train_images = (train_images / 255) - 0.5
test_images = (test_images / 255) - 0.5
# Flatten the images.
train_images = train_images.reshape((-1, 784))
test_images = test_images.reshape((-1, 784))
# Build the model.
model = Sequential([
Dense(64, activation='relu', input_shape=(784,)),
Dense(64, activation='relu'),
Dense(10, activation='softmax'),
])
# Compile the model.
model.compile(
optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy'],
)
# Train the model.
model.fit(
train_images,
to_categorical(train_labels),
epochs=5,
batch_size=32,
)
运行该代码将为我们提供以下信息:
Epoch 1/5
60000/60000 [==============================] - 2s 35us/step - loss: 0.3772 - acc: 0.8859
Epoch 2/5
60000/60000 [==============================] - 2s 31us/step - loss: 0.1928 - acc: 0.9421
Epoch 3/5
60000/60000 [==============================] - 2s 31us/step - loss: 0.1469 - acc: 0.9536
Epoch 4/5
60000/60000 [==============================] - 2s 31us/step - loss: 0.1251 - acc: 0.9605
Epoch 5/5
60000/60000 [==============================] - 2s 31us/step - loss: 0.1079 - acc: 0.9663
5个epoch后,我们达到了96.6%的训练准确性!不过,这并不能告诉我们太多-我们可能会过度拟合。真正的挑战将是看我们的模型如何对我们的测试数据执行。
6.测试模型
评估模型非常简单:
model.evaluate(
test_images,
to_categorical(test_labels)
)
运行使我们:
10000/10000 [==============================] - 0s 15us/step
[0.10821614159140736, 0.965]
validate()返回一个数组,其中包含测试损失,后跟我们指定的任何指标。因此,我们的模型实现了0.108的测试损耗和96.5%的测试精度!对于您的第一个神经网络来说还不错。
7.使用模型
现在,我们有了一个有效的,训练有素的模型,让我们使用它。我们要做的第一件事是将其保存到磁盘,以便我们可以随时将其备份:
model.save_weights('model.h5')
现在,我们可以随时通过重建模型并加载保存的权重来重新加载训练后的模型:
from keras.models import Sequential
from keras.layers import Dense
# Build the model.
model = Sequential([
Dense(64, activation='relu', input_shape=(784,)),
Dense(64, activation='relu'),
Dense(10, activation='softmax'),
])
# Load the model's saved weights.
model.load_weights('model.h5')
使用训练好的模型进行预测很容易:我们将输入数组传递给predict()
它,然后返回输出数组。请记住,我们网络的输出是10个概率(由于softmax),因此我们将使用np.argmax()将其转化为实际数字。
# Predict on the first 5 test images.
predictions = model.predict(test_images[:5])
# Print our model's predictions.
print(np.argmax(predictions, axis=1)) # [7, 2, 1, 0, 4]
# Check our predictions against the ground truths.
print(test_labels[:5]) # [7, 2, 1, 0, 4]
8.扩展
到目前为止,我们所介绍的只是一个简短的介绍-我们可以做更多的工作来尝试和改进此网络。我在下面提供了一些示例:
调整超参数
首先,一个很好的超参数是Adam优化器的学习率。增大或减小它会怎样?
from keras.optimizers import SGD
model.compile(
optimizer=Adam(lr=0.005), loss='categorical_crossentropy',
metrics=['accuracy'],
)
batch size和epoch数呢?
model.fit(
train_images,
to_categorical(train_labels),
epochs=10, batch_size=64,)
网络深度
如果我们删除或添加更多的全连接层会怎样?这如何影响训练和/或模型的最终性能?
model = Sequential([
Dense(64, activation='relu', input_shape=(784,)),
Dense(64, activation='relu'),
Dense(64, activation='relu'), Dense(64, activation='relu'), Dense(10, activation='softmax'),
])
激活方式
如果我们使用除ReLU之外的其他激活方法,例如Sigmoid,该怎么办?
model = Sequential([
Dense(64, activation='sigmoid', input_shape=(784,)), Dense(64, activation='sigmoid'), Dense(10, activation='softmax'),
])
退出
如果我们尝试添加已知可以防止过度拟合的Dropout层怎么办?
from keras.layers import Dense, Dropout
model = Sequential([
Dense(64, activation='relu', input_shape=(784,)),
Dropout(0.5), Dense(64, activation='relu'),
Dropout(0.5), Dense(10, activation='softmax'),
])
验证方式
我们还可以在训练期间使用测试数据集进行验证。Keras将在每个时期结束时根据验证集评估模型,并报告损失和我们要求的任何指标。这使我们可以在训练过程中监视模型随时间的进度,这对于识别过度拟合甚至支持早期停止很有用。
model.fit(
train_images,
to_categorical(train_labels),
epochs=5,
batch_size=32,
validation_data=(test_images, to_categorical(test_labels)))
结论
您已经使用Keras实现了您的第一个神经网络!经过5个时间段后,我们在MNIST数据集上实现了96.5%的测试准确度,这对于这样一个简单的网络来说还不错。我将在下面再次包含完整的源代码,以供您参考。
github 传送门:https://github.com/vzhou842/victorzhou.com