【适用于初学者的Keras入门指南】:构建你的第一个神经网络

Keras是一个简单易用但功能强大的Python深度学习库。在本文中,我们将看到构建前馈神经网络并对其进行训练以解决Keras的实际问题是多么容易。

这篇文章是为Keras的初学者准备的,但是确实假设了神经网络基本背景知识

让我们开始吧!

问题:MNIST数字分类

我们将解决一个经典的机器学习问题: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_shapeSequential模型的第一层指定一个来做到这一点:

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容