Tensorflow-MNIST-手写数字图像识别案例-翻译整理

本篇文章主要介绍如何创建卷积神经网络(CNN:Convolutional Neural Network)用来训练模型,识别手写数字图片。

Tensorflow的layer模型可以帮助我们方便的构建神经网络,包括密集层dense layer layer(full-connected layer全连接层)或卷积层convolutional layer。


下载数据集

这个数据集包含了6000个训练样本和1000个测试样本,都是手写数字0~9,灰度图片28像素x28像素。

MNIST dataset 手写数字集图片官方地址
百度网盘下载,密码:w0sk


代码框架

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import numpy as np
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

tf.logging.set_verbosity(tf.logging.INFO) #设定输出日志的模式

#我们的程序代码将放在这里

#这个文件能够直接运行,也可以作为模块被其他文件载入
if __name__ == "__main__":
  tf.app.run()

关于卷积神经网络

卷积神经网络Convolutional neural networks (CNNs) 是目前图像识别领域最先进的模型结构。CNNs对图像应用各种过滤并从中学习得到高级结构,进而实现图像分类。

卷积神经网络包含3个组成部分:

  • Convolutional layers卷积层 对图像应用特定数量的卷积过滤。对于每个子区域,神经层都会在输出特征映射中产生单个值,卷积层通常会将一个ReLU(Rectified Linear Units修正线性单元)激活函数应用到输出,进而在模型内产生一个非线性的结果。

修正线性单元 (ReLU, Rectified Linear Unit),一种激活函数,ƒ(x)=max(0,x),其规则如下:如果输入为负数或 0,则输出 0;如果输入为正数,则输出等于输入。ReLU属于非饱和算法non-saturating neurons,就是说没有把输出值限定在某个特定区间,与它对应的饱和算法有sigmod:ƒ(x)=(1+e-x)-1;tanh:ƒ(x)=|tanh(x)|,ƒ(x)=tanh(x);

激活函数 (activation function),一种函数(例如ReLUS型函数),用于对上一层的所有输入求加权和,然后生成一个输出值(通常为非线性值),并将其传递给下一层。

  • Pooling layers池化层,对卷积层提取的图像数据进行向下采样,减少特征维度,加快处理速度。常用的池化算法是最大化池化max pooling,它把输入的图像分成不重叠的子矩形区域,对每个子区域,保留最大值,忽略其他值,也控制了整体的过采样。理论基础是特征之间的关联比局部特征更加重要。

  • Dense layer密集层(full-connected layer全连接层),基于卷积层提取的特征和池化层的向下采样,进行分类classification。

    RoI pooling to size 2x2. In this example region proposal (an input parameter) has size 7x5.

标准意义上讲,CNN网络是组合堆叠多个卷机模块,进行特征提取。每个卷积模块包含一个卷积层以及跟随其后的池化层。最后的卷积模块跟随着一个或多个密集层以进行分类。CNN网络中最后的密集层为每个可能的分类设定了一个节点,并对这每个节点使用sigmod函数输出0~1之间的值,表示该图形属于某个分类的可能性。


构建CNN MNIST分类器

  1. Convolutional Layer卷积层 #1: 应用 32 5x5 滤镜提取5x5像素子区域,使用ReLU激活函数
  2. Pooling Layer池化层 #1: 执行最大化池化2x2滤镜,步幅stride=2确保区域不重叠
  3. Convolutional Layer卷积层 #2: 应用64 5x5过滤,使用ReLU激活函数
  4. Pooling Layer池化层 #2: Again, performs max pooling with a 执行最大池化2x2过滤,步幅2
  5. Dense Layer密集层 #1: 1,024个神经元, 丢弃正则率0.4 (训练过程中可能性低于0.4的元素将被丢弃)
  6. Dense Layer密集层 #2 (Logits Layer逻辑层): 10个神经元, 对应0~9数字

tf.layers对象包含了创建以上三种神经层的方法:

  • conv2d(),创建2维的卷积层,参数包含:过滤数量,过滤核心尺寸,填充padding,激活函数。
  • max_pooling2d(), 使用最大化算法创建一个2维池化层。参数包含:过滤尺寸、步幅。
  • dense(),创建密集层,参数包含:神经元数量、激活函数。

这些方法都接收一个张量tensor作为输入,然后经过变换再输出一个新的张量,这样就可以一环一环相连起来。

接下来我们向代码结构文件中添加cnn_model_fn(features, labels, mode)函数,它接收MNIST数据的特征、标签和mode(TRAIN,EVAL,PREDICT),返回train训练、loss损失函数、predict预测三个方法。这是Tensorflow Estimator的标准接口。

更多自定义Estimator的详情请看Tensorflow-Estimator-自定义估算器以及Tensorflow-Estimator-估算器-翻译整理两篇文章。

添加后的代码如下:

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import os
import numpy as np
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

tf.logging.set_verbosity(tf.logging.INFO) #设定输出日志的模式

#我们的程序代码将放在这里
def cnn_model_fn(features, labels, mode):
    #输入层,-1表示自动计算,这里是图片批次大小,宽高各28,最后1表示颜色单色
    input_layer = tf.reshape(features["x"], [-1, 28, 28, 1])

    #1号卷积层,过滤32次,核心区域5x5,激活函数relu
    conv1 = tf.layers.conv2d(
        inputs=input_layer,#接收上面创建的输入层输出的张量
        filters=32,
        kernel_size=[5, 5],
        padding="same",
        activation=tf.nn.relu)

    #1号池化层,接收1号卷积层输出的张量
    pool1 = tf.layers.max_pooling2d(inputs=conv1, pool_size=[2, 2], strides=2)

    #2号卷积层
    conv2 = tf.layers.conv2d(
        inputs=pool1,#继续1号池化层的输出
        filters=64,
        kernel_size=[5, 5],
        padding="same",
        activation=tf.nn.relu)
    
    #2号池化层
    pool2 = tf.layers.max_pooling2d(inputs=conv2, pool_size=[2, 2], strides=2)

    #对2号池化层的输入变换张量形状
    pool2_flat = tf.reshape(pool2, [-1, 7 * 7 * 64])
    
    #密度层
    dense = tf.layers.dense(inputs=pool2_flat, units=1024, activation=tf.nn.relu)
    
    #丢弃层进行简化
    dropout = tf.layers.dropout(
      inputs=dense, rate=0.4, training=mode == tf.estimator.ModeKeys.TRAIN)

    #使用密度层作为最终输出,unit可能的分类数量
    logits = tf.layers.dense(inputs=dropout, units=10)
    
    #预测和评价使用的输出数据内容
    predictions = {
      #产生预测,argmax输出第一个轴向的最大数值
      "classes": tf.argmax(input=logits, axis=1),
      #输出可能性
      "probabilities": tf.nn.softmax(logits, name="softmax_tensor")
    }

    #以下是根据mode切换的三个不同的方法,都返回tf.estimator.EstimatorSpec对象
  
    #预测
    if mode == tf.estimator.ModeKeys.PREDICT:
        return tf.estimator.EstimatorSpec(mode=mode, predictions=predictions)

    #损失函数(训练与评价使用),稀疏柔性最大值交叉熵
    loss = tf.losses.sparse_softmax_cross_entropy(labels=labels, logits=logits)

    #训练,使用梯度下降优化器,
    if mode == tf.estimator.ModeKeys.TRAIN:
        optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001)
        train_op = optimizer.minimize(
            loss=loss,
            global_step=tf.train.get_global_step())
        return tf.estimator.EstimatorSpec(mode=mode, loss=loss, train_op=train_op)

    #评价函数(上面两个mode之外else)添加评价度量(for EVAL mode)
    eval_metric_ops = {
        "accuracy": tf.metrics.accuracy(
            labels=labels, predictions=predictions["classes"])}
    return tf.estimator.EstimatorSpec(
        mode=mode, loss=loss, eval_metric_ops=eval_metric_ops)



#这个文件能够直接运行,也可以作为模块被其他文件载入
if __name__ == "__main__":
  tf.app.run()

这时候以上代码还不能运行。以下将逐个代码块详细解说。


Input Layer输入层

tf.layers中创建神经层的方法参数格式是:
[batch_size,imgage_width,imgage_height,channels]

  • batch_size批次尺寸,在训练过程中梯度下降所使用的样本子集的大小。
  • image_width和image_height,图像的宽高。
  • channels通道,图片像素的颜色通道数,一般是3(RGB),在这里是黑白图片只有1个颜色。

MNIST的图片是28x28单色,[batch_size,28,28,1],我们用-1表示依靠features['x']数量动态计算得到这个数值,那么把它变换一下:

input_layer = tf.reshape(features["x"], [-1, 28, 28, 1])

在这里batch_size作为一个超参数hyperparameters,如果我们使用batch_size=5,那么input_layers的形状就是[5,28,28,1],它将包含5x28x28x1=3920个值,每个值表示一个颜色,每784个值表示一张图,5张为一批次。


Convolutional layer #1卷积层1号

conv1 = tf.layers.conv2d(
    inputs=input_layer,
    filters=32,
    kernel_size=[5, 5],
    padding="same",
    activation=tf.nn.relu)

我们使用了32次5x5像素过滤filters,使用ReLU作为激活函数。由于承接了input_layer的输出,所以进入的张量形状是[batch_size,28,28,1].
padding参数有两个可选,默认的"valid"或"same",为了保持输出的宽高不变,我们选择了"same",Tensorflow会自动用0补齐以确保图像是28x28像素。(如果不使用padding,那么在28x28个网格中只有24x24的区域可以放置5x5的面片,如下图所示黄色区域,也就是会产生24x24的张量。)

激活函数ReLU将应用在卷积输出的张量上。最终从conv2d层输出的张量形状是[batch_size,28,28,32],这里的32是指我们进行了32次过滤产生的不同结果。


Pooling Layer #1池化层1号

pool1 = tf.layers.max_pooling2d(inputs=conv1, pool_size=[2, 2], strides=2)

conv1作为输入层,将会输入的张量形状是[batch_size,28,28,32]。
pool_size设定了最大池化过滤的尺寸[width,height]就是[2,2]。
stredes表示过滤的步长,我们这里设定了stredes=2,表示滤镜对子区域subregions进行提取是按照宽高分别间隔2像素进行的,由于过滤尺寸也是[2,2],所以不会产生重叠也不会产生丢失。



max_pooling层pool1输出的张量形状是[batch_size,14,14,32],因为2x2过滤把宽高减少了一半。


Convolutional layer #2 & Pooling layer #2卷积层2号和池化层2号

conv2 = tf.layers.conv2d(
    inputs=pool1,
    filters=64,
    kernel_size=[5, 5],
    padding="same",
    activation=tf.nn.relu)

pool2 = tf.layers.max_pooling2d(inputs=conv2, pool_size=[2, 2], strides=2)

2号卷积层我们使用了64次5x5区域的过滤,仍然是ReLU激活函数。而2号池化层我们仍然使用了[2,2]区域2步幅间隔的设定。

注意2号卷积层设定了padding="same"且64次过滤,所以输出的张量形状是[batch_size,14,14,64]。
池化层2号则再次把维度降低到[batch_size,7,7,64]。


Dense layer密集层

接下来我们将添加一个1024神经元ReLU激活的密集层(全连接层),基于上面卷积层和池化层得到的结果进行分类。

首先,我们把上面pool2池化层得到的特征映射features map([batch_size,7,7,64])展开,转换到[batch_size,features]。

pool2_flat = tf.reshape(pool2, [-1, 7 * 7 * 64])

-1表示这个维度根据计算得到,在这里我们将得到一个[batch_size,3136]的张量(7764=3136)。

然后我们再把这个结果传递到密集层Dense layer:

dense = tf.layers.dense(inputs=pool2_flat, units=1024, activation=tf.nn.relu)

为了改进我们模型的结果,增加一个dropout丢弃规则,

dropout = tf.layers.dropout(
    inputs=dense, rate=0.4, training=mode == tf.estimator.ModeKeys.TRAIN)

这里rate=0.4表示在训练过程中,40%的元素会被随机丢弃。注意training参数限定了尽在训练模式下才执行随机丢弃,预测和评价时候不丢弃。

最终,由于使用了1024个神经元,dropout输出的张量形状是[batch_size,1024]。


Logits layer逻辑层

逻辑层是我们神经网络的最后一层,他将输出预测的原始数据。我们使用dense创建了10个神经元的密集层,表示0~9个数字,使用默认的linear线性激活函数。

logits = tf.layers.dense(inputs=dropout, units=10)

这样,我们的CNN卷积神经网络最后输出的张量形状就是[batch_size,10]。


生成预测函数

以上,逻辑层生成的张量是[batch_size,10]。我们用两个函数将这个原始数据转为两个不同的格式,作为最终的预测结果:

  • 每个样本的预测分类predicted class,0~9中的一个数字。
  • 每个样本属于每个分类的可能性probabilities,样本可能是0,可能是1,可能是2,可能是...

tf.argmax(input=logits, axis=1)

对于我们这个案例,每个样本的预测分类,就是逻辑层输出张量中对应行中值最高的元素。我们使用argmax方法取得它:

tf.argmax(input=logits, axis=1)

注意这里axis等于1而不是0,因为我们从逻辑层获得的张量形状是[batch_size,10],也就是10对应的列中每个元素,选取值最大的元素返回。

我们把预测结果封装到一个字典,放入EstimatorSpec对象:

predictions = {
    "classes": tf.argmax(input=logits, axis=1),
    "probabilities": tf.nn.softmax(logits, name="softmax_tensor")
}
if mode == tf.estimator.ModeKeys.PREDICT:
  return tf.estimator.EstimatorSpec(mode=mode, predictions=predictions)

Calculate loss计算损失函数

对于训练和预测,我们需要定义一个损失函数loss function来评估我们的模型预测的有多么准确。对于多个类别的分类问题,交叉熵算法是最常用的测量标准。

onehot_labels = tf.one_hot(indices=tf.cast(labels, tf.int32), depth=10)
loss = tf.losses.softmax_cross_entropy(
    onehot_labels=onehot_labels, logits=logits)

这里cast是转变数据类型的方法,labels的数据类似[1, 9, 6,7,3...],我们把它转为one_hot独热格式的张量:

[[0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
 [0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
 ...]

tf.one_hot带有两个参数:

  • indices索引,独热数组哪一个热,比如上面第一行对应的labels是1,就是第1个是1(其他都是0);
  • depth深度,独热数组有多少个元素,在这里就是有多少个分类。

然后,我们计算onehot_labels和逻辑层输出的张量[batch_size,10]的这两者的柔性最大交叉熵。

loss = tf.losses.softmax_cross_entropy(
    onehot_labels=onehot_labels, logits=logits)

tf.losses.softmax_cross_entropy方法返回一个标量scalar张量。


设置训练操作Configure the training Op

在以上,我们定义了loss函数用于评估我们预测模型最终logits层输出的结果与实际标签labels的差异度,下面让我们的模型在训练的时候反复优化这个差异度,让模型达到最佳。
我们使用随机梯度下降函数stochastic gradient desent作为优化算法,使用学习率learning_rate=0.1:

if mode == tf.estimator.ModeKeys.TRAIN:
  optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001)
  train_op = optimizer.minimize(
      loss=loss,
      global_step=tf.train.get_global_step())
  return tf.estimator.EstimatorSpec(mode=mode, loss=loss, train_op=train_op)

在这里,我们看到,所谓的训练操作train_op就是优化函数optimizer根据损失函数loss,一步一步尝试构造更好的模型结构。


添加评价度量Evaluation metrics

eval_metric_ops = {
    "accuracy": tf.metrics.accuracy(
        labels=labels, predictions=predictions["classes"])}
return tf.estimator.EstimatorSpec(
    mode=mode, loss=loss, eval_metric_ops=eval_metric_ops)

训练和评价CNN MNIST分类器

上面我们已经完成了CNN MNIST模型函数的编写,下面我们继续实现模型的训练和预测。


载入训练和测试数据

首先从把从百度网盘(密码:w0sk)下载的MNIST_data文件夹(包含四个文件)放在和我们的代码相同目录下。

然后我们添加main主函数,代码载入数据集

dir_path = os.path.dirname(os.path.realpath(__file__))
data_path=os.path.join(dir_path,'MNIST_data')
def main(args):
    #载入训练和测试数据
    mnist = input_data.read_data_sets(data_path)
    train_data = mnist.train.images #得到np.array
    train_labels = np.asarray(mnist.train.labels, dtype=np.int32)
    eval_data = mnist.test.images #得到np.array
    eval_labels = np.asarray(mnist.test.labels, dtype=np.int32)

你也可以参照 这篇文章 自己手工从官方下载这个数据集。


创建估算器Estimator

Estimator是Tensorflow的一个高级接口high-level API,专门用来对模型进行训练、和评估和预测的。

在main里面添加下面的代码

    #创建估算器
    mnist_classifier = tf.estimator.Estimator(
        model_fn=cnn_model_fn, model_dir="/tmp/mnist_convnet_model")

这里使用的两个参数:

  • model_fn,我们在上面创建神经网络CNN的主要函数,里面实现了训练、评价和预测功能。
  • model_dir,这是设置我们训练出来的模型存储的目录,只要这里设置一次,以后Tensorflow都会自动从这里读取我们训练好的模型,不需要我们添加任何其他代码。当然也可以再训练,会覆盖更新。

设置日志钩子logging hook

CNN训练需要花一点时间,呆看屏幕没有任何反应等待会很难熬,我们可以让Tensorflow在训练的时候输出一些有用的日志信息。

    #设置输出预测的日志
    tensors_to_log = {"probabilities": "softmax_tensor"}
    logging_hook = tf.train.LoggingTensorHook(
        tensors=tensors_to_log, every_n_iter=50)

我们在这里用tensors_to_log字典来存储需要打印出来的数据,注意这里的softmax_tensor,实际是我们在上面定义过的名称(实际上我们在编写整个计算模型时候定义的张量name都可以):

predictions = {
      "classes": tf.argmax(input=logits, axis=1),
      "probabilities": tf.nn.softmax(logits, name="softmax_tensor")
    }

然后,我们创建了钩子函数LoggingTensorHook,并关联到我们的需要输出的张量,每50次迭代打印一次。


训练模型

为了训练模型,我们必须创建一个喂食数据的函数train_input_fn,向main函数添加以下代码:

    #训练喂食函数
    train_input_fn = tf.estimator.inputs.numpy_input_fn(
        x={"x": train_data},
        y=train_labels,
        batch_size=100,
        num_epochs=None,
        shuffle=True)

我们使用了numpy_input_fn方法,它的参数里面xy对应了我们的训练特征数据和训练标签数据,batch_size表示每步数step最少训练100个样本,num_epochs=None周期数不设定表示我们一直训练直到到达指定步数为止(训练时候设定)。shuffle=true洗牌为真表示我们将随机调整样品顺序。

我们再向main函数添加代码启动训练:

    #启动训练
    mnist_classifier.train(
        input_fn=train_input_fn,
        steps=20000,
        hooks=[logging_hook])

在这里我们设定了步数20000,并且把日志钩子logging_hook传递进去。

不要着急,我们先继续添加一些其他内容。


评价模型Evaluate model

训练完成后,我们希望使用测试数据集来评估一下我们的模型的精确度,看它是否足够好。继续向main函数添加下面的代码:

    #评价喂食函数
    eval_input_fn = tf.estimator.inputs.numpy_input_fn(
        x={"x": eval_data},
        y=eval_labels,
        num_epochs=1,
        shuffle=False)
    
    #启动评价并输出结果
    eval_results = mnist_classifier.evaluate(input_fn=eval_input_fn)
    print(eval_results)

同样,我们也需要一个评价喂食函数,不断把需要评价的图片数据输入到模型,然后再把模型输出的预测结果和我们真实的标签对比,这样就能知道我们的模型是不是足够准确。
注意在这里我没设置周期是1,不进行反复训练;设置shuffle=False也不随机调整顺序。


运行吧!

整个过程可能需要一些时间,不要着急,训练20000步数会很慢,请耐心等候。

续,十多分钟过去了,目前才到step3000多...求祝福,求光环...
续,我也不知道最终用了多久,大概1个多小时,这是运行后的结果,精度接近97%:

INFO:tensorflow:Saving dict for global step 20004: accuracy = 0.9691, global_step = 20004, loss = 0.10082044
{'accuracy': 0.9691, 'loss': 0.10082044, 'global_step': 20004}

下面是完整代码,如果你的代码运行中出现问题,可以复制它:

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import os
import numpy as np
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

tf.logging.set_verbosity(tf.logging.INFO) #设定输出日志的模式

#我们的程序代码将放在这里
def cnn_model_fn(features, labels, mode):
    #输入层,-1表示自动计算,这里是图片批次大小,宽高各28,最后1表示颜色单色
    input_layer = tf.reshape(features["x"], [-1, 28, 28, 1])

    #1号卷积层,过滤32次,核心区域5x5,激活函数relu
    conv1 = tf.layers.conv2d(
        inputs=input_layer,#接收上面创建的输入层输出的张量
        filters=32,
        kernel_size=[5, 5],
        padding="same",
        activation=tf.nn.relu)

    #1号池化层,接收1号卷积层输出的张量
    pool1 = tf.layers.max_pooling2d(inputs=conv1, pool_size=[2, 2], strides=2)

    #2号卷积层
    conv2 = tf.layers.conv2d(
        inputs=pool1,#继续1号池化层的输出
        filters=64,
        kernel_size=[5, 5],
        padding="same",
        activation=tf.nn.relu)
    
    #2号池化层
    pool2 = tf.layers.max_pooling2d(inputs=conv2, pool_size=[2, 2], strides=2)

    #对2号池化层的输入变换张量形状
    pool2_flat = tf.reshape(pool2, [-1, 7 * 7 * 64])
    
    #密度层
    dense = tf.layers.dense(inputs=pool2_flat, units=1024, activation=tf.nn.relu)
    
    #丢弃层进行简化
    dropout = tf.layers.dropout(
      inputs=dense, rate=0.4, training=mode == tf.estimator.ModeKeys.TRAIN)

    #使用密度层作为最终输出,unit可能的分类数量
    logits = tf.layers.dense(inputs=dropout, units=10)
    
    #预测和评价使用的输出数据内容
    predictions = {
      #产生预测,argmax输出第一个轴向的最大数值
      "classes": tf.argmax(input=logits, axis=1),
      #输出可能性
      "probabilities": tf.nn.softmax(logits, name="softmax_tensor")
    }

    #以下是根据mode切换的三个不同的方法,都返回tf.estimator.EstimatorSpec对象
  
    #预测
    if mode == tf.estimator.ModeKeys.PREDICT:
        return tf.estimator.EstimatorSpec(mode=mode, predictions=predictions)

    #损失函数(训练与评价使用),稀疏柔性最大值交叉熵
    loss = tf.losses.sparse_softmax_cross_entropy(labels=labels, logits=logits)

    #训练,使用梯度下降优化器,
    if mode == tf.estimator.ModeKeys.TRAIN:
        optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001)
        train_op = optimizer.minimize(
            loss=loss,
            global_step=tf.train.get_global_step())
        return tf.estimator.EstimatorSpec(mode=mode, loss=loss, train_op=train_op)

    #评价函数(上面两个mode之外else)添加评价度量(for EVAL mode)
    eval_metric_ops = {
        "accuracy": tf.metrics.accuracy(
            labels=labels, predictions=predictions["classes"])}
    return tf.estimator.EstimatorSpec(
        mode=mode, loss=loss, eval_metric_ops=eval_metric_ops)



dir_path = os.path.dirname(os.path.realpath(__file__))
data_path=os.path.join(dir_path,'MNIST_data')
def main(args):
  #载入训练和测试数据
    mnist = input_data.read_data_sets(data_path)
    train_data = mnist.train.images #得到np.array
    train_labels = np.asarray(mnist.train.labels, dtype=np.int32)
    eval_data = mnist.test.images #得到np.array
    eval_labels = np.asarray(mnist.test.labels, dtype=np.int32)
    
    #创建估算器
    mnist_classifier = tf.estimator.Estimator(
        model_fn=cnn_model_fn, model_dir="/tmp/mnist_convnet_model")
    
    #设置输出预测的日志
    tensors_to_log = {"probabilities": "softmax_tensor"}
    logging_hook = tf.train.LoggingTensorHook(
        tensors=tensors_to_log, every_n_iter=50)
    
    #训练喂食函数
    train_input_fn = tf.estimator.inputs.numpy_input_fn(
        x={"x": train_data},
        y=train_labels,
        batch_size=100,
        num_epochs=None,
        shuffle=True)
    
    #启动训练
    mnist_classifier.train(
        input_fn=train_input_fn,
        steps=20000,
        hooks=[logging_hook])
    
    #评价喂食函数
    eval_input_fn = tf.estimator.inputs.numpy_input_fn(
        x={"x": eval_data},
        y=eval_labels,
        num_epochs=1,
        shuffle=False)
    
    #启动评价并输出结果
    eval_results = mnist_classifier.evaluate(input_fn=eval_input_fn)
    print(eval_results)    


#这个文件能够直接运行,也可以作为模块被其他文件载入
if __name__== "__main__":
    tf.app.run()

探索人工智能的新边界

如果您发现文章错误,请不吝留言指正;
如果您觉得有用,请点喜欢;
如果您觉得很有用,感谢转发~


END

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

推荐阅读更多精彩内容