更多深度文章,请关注:https://yq.aliyun.com/cloud
卷积神经网络(CNN)是一种特殊的深层的神经网络模型,为什么说它是特殊的神经网络模型呢?一是它的神经元间的连接是非全连接的,另一点是因为同一层中某些神经元之间的连接的权重是共享的。它的这些特点成功的降低了网络模型的复杂度以及减少了权值的数量,这也使得它的网络结构更类似于生物神经网络。今天我们就来用keras来实现CNN,keras是基于Theano和TensorFlow的深度学习库。
我曾经演示过如何使用TensorFlow创建卷积神经网络(CNN)来对MNIST手写数字数据集进行分类。TensorFlow是一款精湛的工具,具有强大的功能和灵活性。然而,对于快速原型制作工作,可能显得有些麻烦。Keras是一个运行在TensorFlow或者Theano的更高级别的库,旨在流线化构建深度学习网络的过程。事实上,在上一篇TensorFlow教程中 ,TensorFlow大约需要42行完成的内容,在Keras中只需11行就可以完成类似的功能。接下来我将向你展示如何通过Keras做到这一点。
该Keras教程将向你展示如何使用MNIST数据集构建CNN并实现> 99%的准确性。它与我之前的卷积神经网络教程中构建的结构完全相同 ,下图显示了网络的架构:
这个Keras教程的完整代码可以在这里找到。
Keras教程中的主要代码讲解:
下面的代码是在此Keras教程中使用的CNN结构的“胆量”
model = Sequential()
model.add(Conv2D(32, kernel_size=(5, 5), strides=(1, 1),
activation='relu',
input_shape=input_shape))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
model.add(Conv2D(64, (5, 5), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(1000, activation='relu'))
model.add(Dense(num_classes, activation='softmax'))
接下来我们一步一步的来解释:
Model = Sequential()
Keras中的模型可以有两种——序贯和通过API函数。对于构建的大多数深度学习网络,序贯模型是最常用的。它允许你从输入到输出整个过程都能轻松地堆叠网络层(甚至循环层)。而API函数可以帮助你构建更复杂的网络体系结构,本教程将不介绍它。
第一行将模型类型声明为Sequential()。
model.add(Conv2D(32, kernel_size=(5, 5), strides=(1, 1),
activation='relu',
input_shape=input_shape))
接下来,我们添加一个2D卷积层来处理2D MNIST输入的图像。传递给Conv2D() 函数的第一个参数是输出通道的数量。这里我们设置为我们有32个输出通道,下一个输入是kernel_size,我们选择了一个5×5移动窗口,其次是x和y方向(1,1)的步态。接着,激活函数是整流线性单元,最后我们必须与输入层的大小提供模型。
还要注意,我们不必声明任何权重或偏差变量,Keras会帮助我们进行完成。
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))
接下来我们添加一个2D max pooling层。层的定义很简单。在这种情况下,我们只是简单地指定在x和y方向上的池的大小 和(2,2)的步。
model.add(Conv2D(64, (5, 5), activation='relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
接下来,我们添加另一个卷积层+最大池化层,具有64个输出通道。在Keras中Conv2D()函数的参数默认的步伐是(1,1),在Keras 中默认步伐是使它等于池的大小。
该层的输入张量是(batch_size,28,28,32)28×28是图像的大小,32是来自上一层的输出通道数。但是,我们不必明确说明输入的形状是什么,Keras也能自动识别。这样可以快速组合网络架构,而不用担心网络周围张量的大小。
model.add(Flatten())
model.add(Dense(1000, activation='relu'))
model.add(Dense(num_classes, activation='softmax'))
现在我们已经在Keras中构建了卷积层,我们希望将这些输出平坦化,以完全进入我们的连接层。在TensorFlow中,我们为了平坦化必须弄清楚卷积层的输出张量的大小,还要明确我们的权重和偏差变量的大小。
接下来的两行声明了我们的完全连接层,使用Keras中的Dense()层。首先我们指定大小,根据我们的架构,我们指定了1000个节点,每个节点都是由ReLU功能激活。第二个是我们softmax分类或输出层,这是我们类数量的大小。就这样 - 我们已经成功地开发了CNN的架构,只有8行代码。现在让我们来训练模型并执行预测。
训练和评估卷积神经网络
我们已经开发了Keras的CNN架构,但是我们还没有指定损失函数,或者告诉框架使用哪种类型的优化器(即梯度下降,Adam optimiser等)。在Keras中,这些可以在一个命令中执行:
model.compile(loss=keras.losses.categorical_crossentropy,
optimizer=keras.optimizers.SGD(lr=0.01),
metrics=['accuracy'])
Keras提供了许多损失函数(或者你可以建立自己的),这里可以看到的keras所有的损失函数。我们将使用标准交叉熵来进行分类(keras.losses.categorical_crossentropy)。Keras还提供了许多优化器,可以在这里看到。在这种情况下,我们使用Adam优化器(keras.optimizers.Adam)。最后,我们可以在模型上运行evaluate()时计算的度量。
接下来,我们要训练我们的模型。这可以通过在Keras中再次运行下面这个命令来完成:
model.fit(x_train, y_train,
batch_size=batch_size,
epochs=epochs,
verbose=1,
validation_data=(x_test, y_test),
callbacks=[history])
该命令看起来类似于非常受欢迎的Python机器学习库中scikit learn 使用的语法。我们首先传递我们的所有训练的数据,x_train和y_train,下一个参数是批量大小,我们不必在Keras训练期间明确我们数据的批量处理,而是指定批量大小。在这种情况下,我们使用的批量大小为128。接下来我们设置训练周期(在这种情况下为10)。详细标志在此处设置为1,指定设定是否要在控制台中打印详细信息以了解训练进度。
3328/60000 [>.............................] - ETA: 87s - loss: 0.2180 - acc: 0.9336
3456/60000 [>.............................] - ETA: 87s - loss: 0.2158 - acc: 0.9349
3584/60000 [>.............................] - ETA: 87s - loss: 0.2145 - acc: 0.9350
3712/60000 [>.............................] - ETA: 86s - loss: 0.2150 - acc: 0.9348
最后,我们将验证或测试数据传递给拟合函数,因此Keras知道在模型上运行evaluate()时,会测量指标的数据。
一旦模型被训练,我们可以评估它并打印结果:
score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])
在上述模型培训10个周期之后,我们实现了99.2%的准确度,你可以看到每个周期的准确性的改善如下图所示:
Kersa让事情很更加简单了,你不觉得吗?我希望这个Keras教程已经展示了它如何成为深度学习解决方案的有用框架。
作为一种附录,我会告诉你如何跟踪我们通过训练时期的准确性,这使我能够生成上面的图表。
在Keras中记录网络性能
Keras有一个实用的程序,名为“回调”,可用于跟踪训练期间的各种变量。你还可以使用它来创建检查点,将模型在训练的不同阶段进行保存,以帮助你避免工作结果丢失。整个结果会被传递到.fit()函数,如上所述。我会向你显示一个相当简单的用例,其中记录了准确性。
要创建一个回调,我们创建一个继承的类,它继承自keras.callbacks.Callback:
class AccuracyHistory(keras.callbacks.Callback):
def on_train_begin(self, logs={}):
self.acc = []
def on_epoch_end(self, batch, logs={}):
self.acc.append(logs.get('acc'))
上面代码继承的Callback超类有一些可以在我们的回调定义中覆盖的方法,例如 on_train_begin,on_epoch_end,on_batch_begin和on_batch_end。这些方法的名称就是代表了训练过程中我们可以“做事情”的时刻。在上面的代码中,在训练开始时,我们初始化一个列表self.acc = []来存储我们的精度结果。使用on_epoch_end ()方法,我们可以从日志中提取我们想要的变量,这是一个字典,默认情况下保留了训练过程中的丢失和准确性。然后我们实例化这样的回调:
history = AccuracyHistory()
现在我们可以使用回调参数名将历史记录传递给.fit()函数。请注意,.fit()需要一个回调参数的列表,所以你必须传递这样的历史:[history]。要访问我们在训练完成后创建的准确性列表,你可以简单地调用history.acc:
plt.plot(range(1,11), history.acc)
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.show()
本文由@阿里云云栖社区组织翻译。
文章原标题《Keras tutorial – build a convolutional neural network in 11 lines》
作者:Andy 译者:袁虎 审阅:
文章为简译,更为详细的内容,请查看原文