我们首先使用 MNIST 数据集,该数据集包含 6 万个手写和标记数字训练样本和 10,000 个的测试样本,0 到 9,因此共有 10 个“分类”。 我会注意到,这是一个非常小的数据集,就你在任何现实环境中的工作而言,它也应该足够小到在每个人的电脑上工作。
MNIST 数据集具有图像,我们将使用纯粹的黑色和白色,阈值,图像,总共 28×28 或 784 像素。 我们的特征是每个像素的像素值,阈值。 像素是“空白”(没有什么,0),或有东西(1)。 这些是我们的特征。 我们尝试使用这个非常基本的数据,并预测我们正在查看的数字(0 ~ 9)。 我们希望我们的神经网络,将以某种方式创建像素之间的关系的内在模型,并且能够查看数字的新样例,并且高准确度预测。
虽然这里的代码不会那么长,但如果你不完全了解应该发生的事情,那么我们可以尝试凝结我们迄今为止所学到的知识,以及我们在这里会做什么。
首先,我们传入输入数据,并将其发送到隐藏层1。因此,我们对输入数据加权,并将其发送到层1。在那里将经历激活函数,因此神经元可以决定是否触发,并将一些数据输出到输出层或另一个隐藏层。在这个例子中,我们有三个隐藏层,使之成为深度神经网络。从我们得到的输出中,我们将该输出与预期输出进行比较。我们使用成本函数(或称为损失函数)来确定我们的正确率。最后,我们将使用优化器函数,Adam Optimizer。在这种情况下,最小化损失(我们有多错误)。成本最小化的方法是通过修改权重,目的是希望降低损失。我们要降低损失的速度由学习率决定。学习率越低,我们学习的速度越慢,我们越有可能获得更好的结果。学习率越高,我们学习越快,训练时间更短,也可能会受到影响。当然,这里的收益递减,你不能只是继续降低学习率,并且总是做得更好。
通过我们的网络直接发送数据的行为,意味着我们正在运行前馈神经网络。 向后调整权重是我们的反向传播。
我们这样做是向前和向后传播,但我们想要多次。 这个周期被称为一个迭代(epoch)。 我们可以选择任何数量的迭代,但你可能想要避免太多,这会导致过拟合。
在每个时代之后,我们希望进一步调整我们的权重,降低损失和提高准确性。 当我们完成所有的迭代,我们可以使用测试集进行测试。
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("/tmp/data/", one_hot = True)
我们导入 TensorFlow 和我们将要使用的样本数据。 请注意one_hot
参数。 这个术语来自只有一个元素的点子,在其余元素当中,字面上是“热”的,或者开启的。 这对于我们这里的多类分类任务是有用的(0 ~ 9)。 因此,不是简单的 0 或者 1,我们拥有:
0 = [1,0,0,0,0,0,0,0,0]
1 = [0,1,0,0,0,0,0,0,0]
2 = [0,0,1,0,0,0,0,0,0]
3 = [0,0,0,1,0,0,0,0,0]
...
好的,所以我们有了数据。 我选择使用 MNIST 数据集,因为它是一个合适的起始数据集,实际上,收集原始数据并将其转换为可以使用的东西,比创建机器学习模型本身需要更多的时间,我认为这里大多数人都想学习 神经网络,而不是网页抓取和正则表达式。
现在我们要开始构建模型:
n_nodes_hl1 = 500
n_nodes_hl2 = 500
n_nodes_hl3 = 500
n_classes = 10
batch_size = 100
我们首先指定每个隐藏层将有多少个节点,我们的数据集有多少份额里,以及我们的批量大小。 虽然你理论上可以一次训练整个网络,这是不切实际的。 你们中的许多人可能有可以完全处理 MNIST 数据集的计算机,但是大多数人都没有或可以访问这种计算机,它们可以一次完成实际大小的数据集。 因此,我们进行批量优化。 在这种情况下,我们进行 100 个批次。
x = tf.placeholder('float', [None, 784])
y = tf.placeholder('float')
这些是我们图中某些值的占位符。 回想一下,你只需在 TensorFlow 图中构建模型即可。 在这里,TensorFlow 操纵一切,而你不会。 一旦完成,这将更加明显,你尝试寻找在哪里修改重量! 请注意,我已经使用[None,784]
作为第一个占位符中的第二个参数。 这是一个可选参数,然而这样显式指定非常有用。 如果你不显式指定,TensorFlow 会在那里填充任何东西。 如果你的形状是显式的,并且一些不同形状的东西尝试放进这个变量的地方,TensorFlow 将抛出一个错误。
我们现在完成了我们的常量以及其实值。现在我们可以实际构建神经网络模型了:
def neural_network_model(data):
hidden_1_layer = {'weights':tf.Variable(tf.random_normal([784, n_nodes_hl1])),
'biases':tf.Variable(tf.random_normal([n_nodes_hl1]))}
hidden_2_layer = {'weights':tf.Variable(tf.random_normal([n_nodes_hl1, n_nodes_hl2])),
'biases':tf.Variable(tf.random_normal([n_nodes_hl2]))}
hidden_3_layer = {'weights':tf.Variable(tf.random_normal([n_nodes_hl2, n_nodes_hl3])),
'biases':tf.Variable(tf.random_normal([n_nodes_hl3]))}
output_layer = {'weights':tf.Variable(tf.random_normal([n_nodes_hl3, n_classes])),
'biases':tf.Variable(tf.random_normal([n_classes]))}
这里,我们开始定义我们的权重和我们的...等等,这些偏差是什么? 偏差是在通过激活函数之前,与我们的相加的值,不要与偏差节点混淆,偏差节点只是一个总是存在的节点。 这里的偏差的目的主要是,处理所有神经元生成 0 的情况。 偏差使得神经元仍然能够从该层中触发。 偏差与权重一样独特,也需要优化。
我们迄今所做的一切都是为我们的权重和偏差创建一个起始定义。 对于层的矩阵的应有形状,这些定义只是随机值(这是tf.random_normal
为我们做的事情,它为我们输出符合形状的随机值)。 还没有发生任何事情,没有发生流动(前馈)。我们开始流程:
l1 = tf.add(tf.matmul(data,hidden_1_layer['weights']), hidden_1_layer['biases'])
l1 = tf.nn.relu(l1)
l2 = tf.add(tf.matmul(l1,hidden_2_layer['weights']), hidden_2_layer['biases'])
l2 = tf.nn.relu(l2)
l3 = tf.add(tf.matmul(l2,hidden_3_layer['weights']), hidden_3_layer['biases'])
l3 = tf.nn.relu(l3)
output = tf.matmul(l3,output_layer['weights']) + output_layer['biases']
return output
在这里,我们将值传入第一层。 这些值是什么? 它们是原始输入数据乘以其唯一权重(从随机开始,但将被优化):tf.matmul(l1,hidden_2_layer['weights'])
。 然后,我们添加了tf.add
的偏差。 我们对每个隐藏层重复这个过程,直到我们的输出,我们的最终值仍然是输入和权重的乘积,加上输出层的偏差值。
完成后,我们只需返回该输出层。 所以现在,我们已经构建了网络,几乎完成了整个计算图形。 在下一个教程中,我们将构建一个函数,使用 TensorFlow 实际运行并训练网络。