深度学习的“Hello World”
回到上一篇 了解机器学习(深度学习)的几个特点
本文目的是通过深度学习的“Hello World”,向读者展示神经网络的训练过程,是用不那么技术化的文字帮你建立对神经网络的直觉。我们将避免使用数学符号,因为数学符号可能会令没有任何数学背景的人反感,而且对解释问题也不是绝对必要的。本文真正目的不是要解决什么手写识别问题,而是通过这个小小的例子引出深度学习后面你需要了解和掌握的知识技术范围。
问题描述
我们这里要解决的问题是,将手写数字的灰度图像(28 像素×28 像素)划分到 10 个类别中(0~9)。我们将使用 MNIST 数据集,它是机器学习领域的一个经典数据集,其历史几乎和这个领域一样长,而且已被人们深入研究。这个数据集包含 60 000 张训练图像和 10 000 张测试图像,由美国国家标准与技术研究院(National Institute of Standards and Technology,即 MNIST 中 的 NIST)在20世纪80年代收集得到。你可以将“解决”MNIST 问题看作深度学习的“Hello World”,正是用它来验证你的算法是否按预期运行。当你成为机器学习从业者后,会发现MNIST一次又一次地出现在科学论文、博客文章等中。在机器学习中,分类问题中的某个类别叫作类(class)。数据点叫作样本(sample)。某个样本对应的类叫作标签(label)
下图给出了 MNIST 数据集的一些样本。
深度学习的“套路”
套用一句流行术语,套路来说,深度学习解决问题的原理或”套路“如下图所示:
上图是深度学习解决问题的大致流程,不管神经网络深度(层数)有多深,都基本是这个流程。从简单的训练权重网络、到加入损失函数到神经网络、到加入优化器到完整神经网络处理流程。
深度学习训练的最终目的是得到一个合适的权重,而要计算出权重需要构建神经网络、选择损失函数、优化器、学习效率以及**函数等,这些都是为最终训练出合适的权重,简单来说就是这样。
构建神经网络的核心组件是层(layer),它可以把它理解为是一种数据处理模块,看成数据过滤器。进去一些数据,出来的数据变得更加有用。具体来说,层从输入数据中提取表示
——我们期望这种表示
有助于解决手头的问题。大多数深度学习都是将简单的层链接起来,从而实现渐进式的数据蒸馏
(data distillation)。深度学习模型就像是数据处理的筛子,包含一系列越来越精细的 数据过滤器(即层)。经典的卷积神经网络,如VGG,AlexNet,ResNet,GoogleNet,都有较深较复杂的网络结构。
MNIST深度网络构建
按照上述的“套路”,首先构建神经网络,本例设计网络包含 2 个 Dense 层,它们是密集连接(也叫全连接)的神经层。第二层(也是最后一层)是一个 10 路 softmax 层,它将返回一个由 10 个概率值(总和为 1)组成的数组。 每个概率值表示当前数字图像属于10 个数字类别中某一个的概率。这里要说明一点,构建神经网络结构也是一个根据经验或者实验的过程,比如同样是MNIST问题,你可以使用卷积神经网络(CNN),也可以使用循环神经网络(RNN)结构来做,网络层数可以用两层或三层或四层等。所以仅构建神经网络这个点就有很多不同做法
然后,要想训练网络,我们还需要选择编译(compile)步骤的三个参数。
- 损失函数(loss function):网络如何衡量在训练数据上的性能,即网络如何朝着正确的方向前进。
- 优化器(optimizer):基于训练数据和损失函数来更新网络的机制。
- 在训练和测试过程中需要监控的指标(metric):本例只关心精度,即正确分类的图像所占的比例。
Python Keras代码实现
代码使用Kaggle竞赛最常用的深度学习框架Keras编写,完整代码:
from keras import models
from keras import layers
from keras.utils import to_categorical
from keras.datasets import mnist
import ssl
# 避免错误:[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed
ssl._create_default_https_context = ssl._create_unverified_context
# 加载数据
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
# 构建神经网络
network = models.Sequential()
network.add(layers.Dense(512, activation='relu', input_shape=(28 * 28,)))
network.add(layers.Dense(10, activation='softmax'))
# 编译步骤
network.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])
# 准备图像数据
train_images = train_images.reshape((60000, 28 * 28))
train_images = train_images.astype('float32') / 255
test_images = test_images.reshape((10000, 28 * 28))
test_images = test_images.astype('float32') / 255
# 准备标签
train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)
# 训练网络
network.fit(train_images, train_labels, epochs=5, batch_size=128)
# 模型评估
test_loss, test_acc = network.evaluate(test_images, test_labels)
print('test_acc:', test_acc)
代码不过20行左右,是不是很简单?表面理解起来似乎很简单,那是因为Keras框架帮你做了很多事情,同时向你隐藏了众多实现细节。透过代码其实大多数人还是一头雾水,或者不知其所以然。我们不禁要问,深度学习是不是那么简单?这是一个人工手写识别问题,换了其它问题,你能做吗?怎么做?马路上行人识别,怎么做?能做吗?还有很多实际的一些应用场景,如何结合起来解决问题?难道所有问题都可以用神经网络或深度学习来解决?是不是一个“锤子和钉子”的故事?神经网络的应用场景是什么?所有这些问题,我想才是我们要学习机器学习的核心价值所在解决实际问题
小结
深度学习框架很多,要编写代码相对来说比较容易,机器学习(深度学习)重要的是要对其有深刻的理解和洞察,再辅以实践验证。要对上述的神经网络解决问题的“套路”上的各个环节要有很深的功底,才能取得长足的进步。从上述神经网络处理流程,可以看出需要学习了解的东西很多,首先需要学习掌握的就是神经网络的数据存储和表示问题,要理解深度学习,需要熟悉很多简单的数学概念: 张量、张量运算、微分、梯度下降等。
继续下一篇 神经网络的数学基础