下面是TensorFlow官网提供的一个入门代码,对于一个机器学习的新手来说,好难呀,所以下面就只能一行一行的来理解了。
import tensorflow as tf
mnist = tf.keras.datasets.mnist
(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0
model = tf.keras.models.Sequential([
tf.keras.layers.Flatten(input_shape=(28, 28)),
tf.keras.layers.Dense(512, activation=tf.nn.relu),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])
model.compile(
optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'],
)
model.fit(
x_train,
y_train,
epochs=5,
)
model.evaluate(x_test, y_test)
首先是导入tensorflow库,正常操作,不用解释。
import tensorflow as tf
下面这个要分几段理解:
-
tf.keras
:TensorFlow对KerasAPI规范的实现,使用它以设置TensorFlow程序,那么问题来了,啥是KerasAPI呢?KerasAPI是一个用于构建和训练模型的高阶API,包含对TensorFlow特定功能的顶级支持。 -
datasets
:是DatasetsAPI的实现与支持,使用DatasetsAPI可扩展为大型数据集或多设备训练。那么问题又来了,啥是DatasetsAPI呢?DatasetsAPI实现了从内存或者硬盘文件中加载数据组成数据集,同时对数据集进行一系列变换操作,最终将数据集提供给其他API使用的一系列功能。 -
mnist
:是MNIST数据集,来自美国国家标准与技术研究所,由来自250个不同人手写的数字构成,其中50%是高中学生,50%来自人口普查局的工作人员。也是同样比例的手写数字数据。
合在一起的意思就是说,我们要下载MNIST数据集的图像数据了。
mnist = tf.keras.datasets.mnist
上面代码下载的东西本身并没有使用标准的图片格式储存,要用下面代码中的load_data
方法,也就是tf.keras
自带的MNIST数据集加载方法去手动解压。
图片数据将被解压成2维的tensor:[image index, pixel index] 其中每一项表示某一图片中特定像素的强度值, 范围从 [0, 255] 到 [-0.5, 0.5]。 "image index"代表数据集中图片的编号, 从0到数据集的上限值。"pixel index"代表该图片中像素点得个数, 从0到图片的像素上限值。
也就是说,load_data
方法把MNIST数据集划分训练集和测试集来使用。x_train
是训练集图片,y_train
是训练集标签,x_test
是训练集图片,y_test
是训练集标签。
再形象一下,就是下面这张图片咯,每一张图片都有28X28的像素,用一个数字数组来表示每一张图片,把数组展开成一个向量,长度等于28X28=784。因此,MNIST数据集的图片就是在784维向量空间里面的点,相当复杂,784维呢。
(x_train, y_train),(x_test, y_test) = mnist.load_data()
回顾一下上面说的几个点:
-
x_train
是训练集图片,x_test
是训练集图片。 - MNIST数据集的图片就是在784维向量空间里面的点。
- 1个点就是1个像素单位,像素值的范围是 [0, 255] 。
所以,下面代码的意思就很清楚了,将图像的RGB数值,除于255归一到(0,1)
之间的小数。也就是归一化,把数据变成(0,1)
或者(1,1)
之间的小数,主要是为了数据处理方便提出来的,把数据映射到0~1范围之内处理,机器处理起来可以更加便捷快速。
还有一个网上说的不明觉厉的理由:把有量纲表达式变成无量纲表达式,便于不同单位或量级的指标能够进行比较和加权。归一化是一种简化计算的方式,即将有量纲的表达式,经过变换,化为无量纲的表达式,成为纯量。
x_train, x_test = x_train / 255.0, x_test / 255.0
上面有说到,tf.keras
是TensorFlow对KerasAPI 规范的实现,所以,tf.keras
可以运行任何与Keras兼容的代码。下面代码中,就用到了Keras代码。
model是Keras中主要的数据结构,这个数据结构定义了一个完整的图,你可以向已经存在的图中加入任何的网络结构。在Keras中,通过组合层来构建模型,模型通常是由层构成的图。最常见的模型类型是层的堆叠(tf.keras.Sequential
)模型。
Keras文档里是tf.keras.Sequential
,TensorFlow文档里是tf.keras.models.Sequential
,没什么差别,怎么写都可以,效果一个样。下面代码会构建一个简单的全连接网络,即多层感知器,或者叫序贯(Sequential
)模型。
model = tf.keras.models.Sequential([
tf.keras.layers.Flatten(input_shape=(28, 28)),
tf.keras.layers.Dense(512, activation=tf.nn.relu),
tf.keras.layers.Dropout(0.2),
tf.keras.layers.Dense(10, activation=tf.nn.softmax)
])
上面代码里面还有4个函数,分别在下面解释一下是啥意思。
tf.keras.layers.Flatten(input_shape=(28, 28)),
tf.layers.Flatten
函数,在保留axis(axis 0)的同时平移输入张量。轴(axis
)用来为超过一维的数组定义的属性,二维数据拥有两个轴,第0轴沿着行的垂直往下,表示沿着每一列或行标签/索引值向下执行方法;第1轴沿着列的方向水平延伸,表示沿着每一行或者列标签横向执行对应的方法。下面有一张比较形象的图片来解释:
再回顾下,上面有说到,每一张图片都有28X28的像素,使用代码的意思也出来了,就是将图像的格式从2d阵列(28x28像素)转换为28x28=784像素的1d阵列。根本目的是展平图像数据,用通俗的话来说,这就是真正的降维攻击呀。
下一行代码使用构造函数参数实例化全连接(tf.keras.layers.Dense
)层,Dense
层是密集连接或完全连接的神经层。在像素被展平后,网络由两层tf.keras.layers.Dense
序列组成。
第一个Dense
层有512个节点或神经元,该层实现了outputs = activation(inputs * kernel + bias)
,中activation
是作为activation参数传递的激活函数,是由层创建的权重矩阵(非None时)。kernel
是由层创建的权重矩阵,并且bias
是由层创建的偏差向量(use_bias为True时)。
小结一下就是,一个有512列的全连接层,tf.nn.relu
函数是计算校正线性的。
tf.keras.layers.Dense(512, activation=tf.nn.relu),
tf.layers.Dropout
函数,将退出率(Dropout
)应用于输入。Dropout
包括在每次更新期间随机将输入单位的分数rate设置为0,这有助于防止过度拟合(overfitting
)。保留的单位按比例1/(1-rate)进行缩放,以便在训练时间和推理时间内它们的总和不变。
就是设置一下需要断开的神经元的比例,防止过度拟合,过度拟合的定义是:为了得到一致假设而使假设变得过度严格称为过拟合。实际目的是为了让模型更包容一些。
tf.keras.layers.Dropout(0.2),
tf.nn.softmax
函数,计算softmax
激活。在数学,尤其是概率论和相关领域中,Softmax函数,或称归一化指数函数,是逻辑函数的一种推广。
下面的代码是第二个,也是最后一层是10个节点的softmax
层,会返回10个概率分数的数组,其总和为1,每个节点包含指示当前图像属于10个类之一的概率的分数。就是一个有10列的全连接层。
tf.keras.layers.Dense(10, activation=tf.nn.softmax)
现在回顾一下这个模型,首先,将每一个图像的格式从2d阵列降维到1d阵列,再把每一个1d阵列存入到一个784(28x28)行N列的2d阵列中,把数据从原来784维降成2维。
再创建两个全连接(tf.keras.layers.Dense)层,一个是通过校正线性计算的有512个节点或神经元的全连接层,一个是通过归一化指数(tf.nn.softmax
)函数计算的10个节点的全连接层。
最后在两个全连接(tf.keras.layers.Dense)层之间通过退出率(Dropout)函数来防止过度拟合。这个过程就像下面的图片展示的那样:
构建好模型后,我们就可以通过调用compile
方法配置该模型的学习流程。这个方法有下面几个参数:
-
optimizer
参数:优化器,此对象会指定训练过程,从tf.train
模块向其传递优化器实例。 -
loss
参数:损失函数交叉熵,要在优化期间最小化的函数。损失函数由名称或通过从tf.keras.losses
模块传递可调用对象来指定。 -
metrics
参数:评价指标列表,用于监控训练。它们是tf.keras.metrics
模块中的字符串名称或可调用对象。
model.compile(
optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'],
)
因为小型数据集,我们使用内存中的NumPy数组训练和评估模型,即使用fit
方法使模型与训练数据拟合。开始训练迭代5轮。
其中x_train
是输入数据,y_train
是标签元组。epochs
参数,以周期为单位进行训练,一个周期是对整个输入数据的一次迭代,以较小的批次完成迭代。
model.fit(
x_train,
y_train,
epochs=5,
)
tf.keras.Model.evaluate
可以使用NumPy数据,用来评估所提供数据的推理模式损失和指标。我们输入x_test
和y_test
两个测试集对训练后的模型进行测试。
model.evaluate(x_test, y_test)
最后我们就可以执行代码了,执行完成以后,控制台的输出就是下面的这些内容:
Epoch 1/5
60000/60000 [==============================] - 8s 131us/sample - loss: 0.2183 - acc: 0.9355
Epoch 2/5
60000/60000 [==============================] - 7s 119us/sample - loss: 0.0961 - acc: 0.9704
Epoch 3/5
60000/60000 [==============================] - 6s 102us/sample - loss: 0.0691 - acc: 0.9784
Epoch 4/5
60000/60000 [==============================] - 6s 97us/sample - loss: 0.0530 - acc: 0.9826
Epoch 5/5
60000/60000 [==============================] - 6s 97us/sample - loss: 0.0432 - acc: 0.9862
10000/10000 [==============================] - 0s 36us/sample - loss: 0.0801 - acc: 0.9766
# 时期 1/5
# 60000/60000 [==============================] - 6秒 104微秒/抽样 - 损失: 0.2170 - 准确率: 0.9354
# 时期 2/5
# 60000/60000 [==============================] - 6秒 104微秒/抽样 - 损失: 0.0959 - 准确率: 0.9701
# 时期 3/5
# 60000/60000 [==============================] - 7秒 121微秒/抽样 - 损失: 0.0668 - 准确率: 0.9790
# 时期 4/5
# 60000/60000 [==============================] - 7秒 121微秒/抽样 - 损失: 0.0527 - 准确率: 0.9830
# 时期 5/5
# 60000/60000 [==============================] - 7秒 110微秒/抽样 - 损失: 0.0424 - 准确率: 0.9860
# 10000/10000 [==============================] - 0秒 40微秒/抽样 - 损失: 0.0718 - 准确率: 0.9798