使用keras和tensorflow进行minst数据集图像分类

1/18/2020
从word文档整理过来的时候图片复制不进来。
(当时不会用markdown,现在会了,但是图片重新插入略麻烦,建议下载这个笔记.doc进行本地观看,以确保格式正确。
文章一半内容来自于对tf官网tutorial的翻译,另一半就是当时跟着教程做的时候自己被卡住的地方,所以如果你也是第一次学习,那这个文档可能会对你帮助不小。
刚刚开始学习tensorflow,一些自己的理解有错请见谅。
csdn整理文章有点麻烦,公式也不好插入,

下面区域可以不看,是一些说明、问题复现解决和建议

pip安装包只能在命令行下使用,不可以在python交互模式下使用。 我的实验环境是anaconda+tf1.5 keras2.2.4,实验时的fashion minst数据集是在load data()函数下在线下载的。
使用pycharm做编译环境,在编译环境里选上anaconda作为包管理是个很不错的选择,不过新环境的调试总是容易出现很多问题,在安装pycharm的时候要是选择了vim插件,每次输入就都得按一下insert,tools->vim evaluator关掉就好了。
Python是需要对齐的,如果本文档里的代码复现出现各种对齐报错,应该是我直接全局首行缩进的问题,recheck了一遍,但是如果还有问题希望多加包涵ovo。

这个文档指引你训练一个可以分类衣服图像(比如短裤和衬衫)的神经网络模型。即使你不知道任何细节也没有关系;这是一个快节奏的完整的TensorFlow程序的概述,并对您进行详细解释。

from __future__ import absolute_import, division, print_function, unicode_literals

#TensorFlow and tf.keras
import tensorflow as tf
from tensorflow import keras

# Helper libraries
import numpy as np
import matplotlib.pyplot as plt

print(tf.__version__)

1.5.0

使用”fashion minst”数据集开始训练(这个好像是针对服装的数据集)
FASHION MNIST的目的是作为经典MNIST数据的一个完全替代——通常用作计算机视觉机器学习程序的“hello,world”。MNIST数据集包含手写数字(0、1、2等)的图像,其格式与您将在这里使用的衣物相同。
本指南为了多样性使用fashion MNIST,因为它是一个比普通MNIST稍微更具挑战性的问题。这两个数据集都相对较小,用于验证算法是否按预期工作。它们是测试和调试代码的良好起点。这里,使用60,000张图像来训练网络,使用10,000张图像来评估网络学习图像分类的准确性。您可以直接从TensorFlow访问fashion MNIST。直接从TensorFlow导入和加载Fashion MNIST数据:

fashion_mnist = keras.datasets.fashion_mnist

(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()

加载数据集将返回四个NumPy数组:
train_images和train_label数组是训练集——模型用来学习的数据。
模型将根据测试集test_images和test_label数组进行测试。
Images是28x28的NumPy数组,像素值从0到255不等。
Label是一个整数数组,范围从0到9。这些对应于图像所代表的服装类别:

Label Class
0 T恤/上衣
1 裤子
2 套衫、套头毛衣
3 裙子
4 外套
5 凉鞋、便鞋
6 衬衫
7 帆布鞋
8
9 裸靴

每个images都映射到单个label。由于衣服的种类名没有包含在数据集中,所以将它们存储在class_names里面,以便以后绘制图像时使用:

class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
               'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']

探索数据

在训练模型之前,让我们先研究一下数据集的格式。如下图所示,训练集中有60000张images,每张images表示为28x28像素:

train_images.shape

(60000, 28, 28)

len(train_labels)

60000

train_labels

array([9, 0, 0, …, 3, 0, 5], dtype=uint8)

test_images.shape

(10000, 28, 28)

len(test_labels)

10000

数据预处理

在训练网络之前,必须对数据进行预处理。
如果你检查训练集中的第一个图像,你会看到像素值落在0到255的范围内:
以下附输出第一张图片代码

plt.figure()
plt.imshow(train_images[0])/*这是一个插值的方法,就是用colormap来可视化标量数据,重载类型很多,这种就是最少的可接受,(self,X)python里self大概像this,不用在实参里面填写) X是array-like【大概是数组类型的意思】或者PIL(Python image library)image */
plt.colorbar()#给子图添加渐变颜色条的操作
plt.grid(False)#网格线设置成无
plt.show()#展示图像

如果你和我一样先学过C++等面向对象编程语言的话,可能会发现有点奇怪。Plt是import matplotlib.pyplot as plt 得到的。在oop里面好像只见过 对象.方法 这样的情况。但是这个plt如果是对象的话,在程序里并没有得到实例化,所以他可能是接口或者抽象类,查看了源码,里面不包含class这个单词,查看了官方文档,得到了其实是接口的结论。这里我对接口懂得不多,java有interface,python没有具体的实现方法。
经过一堆溯源,发现了大概是这样的结构:pyplot通过global来存储信息,pyplot里只有global variety+函数集合,同时pyplot包含了很多其他的文件,比如一个抽象类Gcf(这个类永远不会被实例化)。

在将这些值输入神经网络模型之前,将这些值缩放到0到1的范围。为此,将这些值除以255。重要的是,训练集和测试集以相同的方式预处理:

train_images = train_images / 255.0

test_images = test_images / 255.0

上面叫归一化处理https://www.zhihu.com/question/20455227/answer/197897298
这样做可以在loss收敛的时候更加平缓
在基于梯度下降的算法中,使用特征归一化方法将特征统一量纲,能够提高模型收敛速度和最终的模型精度
在看subplots的函数原型的时候,发现参数表里有一个**kwargs,在python里与之相似的还有*args,他们的命名只是一个习惯,args会把参数打包成元组tuple传进函数,kwargs会打包成字典dic传进函数。他们可以用来实现可变参数长度。如果需要在一个函数中处理带名字的参数时,此时就应该使用kwargs了。例如:

plt.subplot(223,projection='polar')
plt.figure(figsize=(10,10))
for i in range(25):
    plt.subplot(5,5,i+1)#在5行5列的子图区域占据第i+1个位置
plt.xticks([])#这个属性是用来设置轴上的刻度上的名字。形参是list变量,实参是空list。就是不需要横纵坐标轴
    plt.yticks([])
    plt.grid(False)#不需要网格线
    plt.imshow(train_images[i], cmap=plt.cm.binary)#插值函数,cmap设置了binary是白底黑字的意思。
    plt.xlabel(class_names[train_labels[i]])#每个子图的横标签
plt.show()

接触过一点matplotlib,不过不深,现在学习了一下,不过不是本文的重点,就不再整理了。
https://www.zhihu.com/question/51745620?sort=created这篇讲Axes、Axis和subplots的文章写的挺好
Figure
整个图像。这个图形跟踪所有的 child Axes【子图】,一小部分“特殊”artist【艺术家(不知道怎么翻译了,下面有解释)】(标题,图例,etc),和画布。(不要太关注画布,它是至关重要的,因为它是真正被绘制图形的对象。但作为用户,它或多或少是你看不见的)。一个图像可以有任意数量的Axes,但要有用,至少应该有一个。
创建一个新图形的最简单的方法是用pyplot:

fig = plt.figure()  # 创建一个没有Axes的空图像
fig.suptitle('No axes on this figure')  # 给图像加上一个标题

fig, ax_lst = plt.subplots(2, 2)  # 这个图像拥有2x2的Axes网格
fig.suptitle('No axes on this figure')  # 给图像加上一个标题,这句话要写多一次!不然没有标题,subplots返回的似乎是一个新的figure对象

Axes 这是一个类 【很多教程翻译成了子图,也有人翻译成轴域】
这就是您所认为的“绘图”,它是具有数据空间的图像区域。给定的图形可以包含许多轴,但给定的轴对象只能在一个图形中。Axes包含两个(或3D下三个)轴对象(注意Axes和Axis之间的区别),它们负责数据限制(数据限制也可以通过Axes的方法set_xlim()和set_ylim()来控制)。每个Axes都有一个标题(通过set_title()设置)、一个x标签(通过set_xlabel()设置)和一个y标签集(通过set_ylabel()设置)。
Axes类及其成员函数是使用OO(object oriented面向对象)接口的主要入口点。
Artist
基本上你在图上看到的一切都是艺术家(甚至是图、轴和轴对象)。这包括文本对象、Line2D对象、集合对象、补丁对象……(你懂的)。当图形被渲染时,所有的艺术家都被绘制到画布上。大多数艺术家被绑在an Axes上,这样的艺术家不能由多个轴共享,也不能从一个轴移动到另一个轴。
https://keras.io/zh/activations/这里是keras的中文文档,下面可以对照着看
建立模型
构建神经网络需要配置模型的层,然后编译模型。
配置模型的层(layer)
神经网络的基本构建块是层。层从输入到它们的数据中提取表示。但愿,这些表示对当前的问题是有意义的。
大多数深度学习模型都是由简单的层组成的。大多数层(如tf.keras.layers.Dense)带有训练过程中学到的参数.
下面sequential建立的是顺序模型(多个layer的线性叠加)

model = keras.Sequential([
    keras.layers.Flatten(input_shape=(28, 28)),
    keras.layers.Dense(128, activation='relu'),#relu函数是a(x)=max(x,0)
    keras.layers.Dense(10, activation='softmax')
])

第一层是flatten,他的作用是“铺平”,把图像的格式从二维数组(28×28像素)转换为一维数组(28×28=784像素)。将此层看作是图像中的像素的解堆叠【大概是多维转一维】,并排列它们。这个层没有要学习的参数;它只重新格式化数据。

__init__(
    data_format=None,
    **kwargs
)

可以发现flatten层的初始化参数只需要数据的类型就好。
在像素被展平之后,网络由tf.keras.layers.Dense两层序列组成。这些是密集连接或完全连接的神经层。第一Dense层有128个节点(或神经元)。第二(最后)层是10节点softmax层 - 这返回10个概率分数的数组,其总和为1.每个节点包含指示当前图像属于10个类之一的概率的分数。
Softmax激活函数是在把输入的数据 映射到 0-1之间,并且保证所有输出数据的和是1.做法如下:比如输入数据是1,2,3;那么1的输出数据就是e1/e1+e2+e3;其他输入数据也如此处理。softmax设计的初衷,是希望特征对概率的影响是乘性的。这一个激活函数在多分类问题里面常见。
Dense层的

output = activation(dot(input, kernel) + bias)

__init__(
    units,
    activation=None,#这是个激活函数,如果设置成none,那就是a(x)=x
    use_bias=True,
    kernel_initializer='glorot_uniform',
    bias_initializer='zeros',
    kernel_regularizer=None,
    bias_regularizer=None,
    activity_regularizer=None,
    kernel_constraint=None,
    bias_constraint=None,
    **kwargs
)

编译模型

在模型被准备好用来训练之前,它需要更多的设置。
下面这些是在模型的编译步骤中添加的:
损失函数(loss function)-这衡量了模型在训练过程中的准确性。您希望最小化此函数以“引导”模型朝着正确的方向学习。
优化器(optimizer)-这就是如何根据它看到的数据及其损失函数来更新模型。
度量(metrics)-用于监视训练和测试步骤。下面的示例使用精度,即正确分类的图像的分数。

model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

Adam是一种优化器,不是人名。它的名称来源于适应性矩估计(adaptive moment estimation),是一种可以替代传统随机梯度下降(SGD)过程的一阶优化算法。Adam 算法和传统的随机梯度下降不同。随机梯度下降保持单一的学习率(即 alpha)更新所有的权重,学习率在训练过程中并不会改变。而 Adam 通过计算梯度的一阶矩估计和二阶矩估计而为不同的参数设计独立的自适应性学习率。
sparse_categorical_crossentropy是适用于多分类问题的损失函数,称作稀疏分类交叉熵。Keras文档没有形参表以外的解读。
度量一般有如下几种:(T是true,预测正确,N是negative,反例,P是正例,F是false)在多分类问题里面除了自身的属性其他都是反例
accuracy=;Precision=
recall=sensitivity;specificity=
accuracy指的是正确预测的样本数占总预测样本数的比值,它不考虑预测的样本是正例还是负例。而precision指的是正确预测的正样本数占所有预测为正样本的数量的比值,也就是说所有预测为正样本的样本中有多少是真正的正样本。从这我们可以看出,precision只关注预测为正样本的部分,而accuracy考虑全部样本。
Recall可以称为召回率、查全率等等,它指的是正确预测的正样本数占真实正样本总数的比值,也就是我能从这些样本中能够正确找出多少个正样本。
F-score相当于precision和recall的调和平均,用意是要参考两个指标。从公式我们可以看出,recall和precision任何一个数值减小,F-score都会减小,反之,亦然。
specificity就是负召回率。
训练模型
训练神经网络模型需要以下步骤:
1、将训练数据反馈给模型。在本例中,训练数据在train_images和train_labels数组中。
2、模型学习把图像和标签关联起来
3、要求模型对测试集进行预测-在本例中,测试集是test_images数组。
4、验证预测是否与test_labels数组中的标签匹配。
提供数据给模型
要开始训练,请调用model.fit方法——之所以调用,是因为它将模型与训练数据相匹配:

model.fit(train_images, train_labels, epochs=10)

fit(
x=None,
y=None,
batch_size=None,
epochs=1,
verbose=1,
callbacks=None,
validation_split=0.0,
validation_data=None,
shuffle=True,
class_weight=None,
sample_weight=None,
initial_epoch=0,
steps_per_epoch=None,
validation_steps=None,
validation_freq=1,
max_queue_size=10,
workers=1,
use_multiprocessing=False,
**kwargs )

x是输入数据,可以是:
一个Numpy数组(或类数组),或一个数组列表(如果模型有多个输入的话)…
一个TensorFlow张量,或一个张量列表(如果模型有多个输入)。
一个字典,他的内容是映射(mapping)(即把名字和对应的numpy数组或tensor关联起来,如果这个数据集有名字这个属性的话)dict(mapping,**kwargs) mapping可以用zip([包含了name的列表],[包含key的列表])传入。
y是目标数据:
灰色字是文档叽里呱啦说的,其实我觉得对于数据集来说就是label set
与输入数据x一样,它可以是Numpy数组,也可以是TensorFlow张量。它应该与x相一致(不能输入是numpy数组的时候y是张量,也不能相反)。但如果x是数据集、生成器或keras.utils.sequence实例时,y不应该被指定(因为目标将从x中获得)。
Epochs:
整数,培养模型的迭代总次数。一次epoch是对所提供的整个x和y数据的迭代。请注意,与initial_epoch一起,epoch应该被理解为“最后的epoch”。模型不是针对epochs给出的迭代次数进行训练,而是仅仅训练到达到epochs次迭代次数的时候。[不是目标,只是个卡,大概是这个意思吧]

Train on 60000 samples Epoch 1/10
60000/60000 []- 4s 60us/sample - loss: 0.4940 - accuracy: 0.8258
Epoch 2/10
60000/60000
[
] - 3s 53us/sample - loss: 0.3706 -
accuracy: 0.8663
Epoch 3/10
60000/60000 [
] - 3s 52us/sample - loss: 0.3306 -
accuracy: 0.8787
Epoch 4/10 60000/60000
[
] - 3s 52us/sample - loss: 0.3090 -
accuracy: 0.8871
Epoch 5/10 60000/60000
[
] - 3s 52us/sample - loss: 0.2937 -
accuracy: 0.8921
Epoch 6/10 60000/60000
[
] - 3s 53us/sample - loss: 0.2785 -
accuracy: 0.8967
Epoch 7/10 60000/60000
[
] - 4s 59us/sample - loss: 0.2667 -
accuracy: 0.8999
Epoch 8/10 60000/60000
[
] - 3s 57us/sample - loss: 0.2562 -
accuracy: 0.9050
Epoch 9/10 60000/60000
[
] - 3s 52us/sample - loss: 0.2455 -
accuracy: 0.9083
Epoch 10/10 60000/60000
[
============] - 3s 52us/sample - loss: 0.2365 -
accuracy: 0.9123

随着模型的训练,损失和精度指标被显示出来。该模型对训练数据的准确率约为0.91(或91%)。
评估准确性
接下来,比较模型在测试数据集上的表现:

test_loss, test_acc = model.evaluate(test_images,  test_labels, verbose=2)

print('\nTest accuracy:', test_acc)

evaluate(
x=None,
y=None,
batch_size=None,
verbose=1,
sample_weight=None,
steps=None
)
参数
和fit很像,x是测试数据(numpy list、tensor、dict什么的),y是标签数据。
batch_size: 整数或 None。每次评估的样本数。如果未指定,默认为 32。
verbose: 0 或 1。日志显示模式。 0 = 安静模式,1 = 进度条。
sample_weight: 测试样本的可选 Numpy 权重数组,用于对损失函数进行加权。 您可以传递与输入样本长度相同的扁平(1D)Numpy 数组(权重和样本之间的 1:1 映射), 或者在时序数据的情况下,传递尺寸为 (samples, sequence_length) 的 2D 数组,以对每个样本的每个时间步施加不同的权重。 在这种情况下,你应该确保在 compile() 中指定 sample_weight_mode=“temporal”。
steps: 整数或 None。 声明评估结束之前的总步数(批次样本)。默认值 None。
返回
标量测试误差(如果模型只有一个输出且没有评估标准) 或标量列表(如果模型具有多个输出 和/或 评估指标)。 属性 model.metrics_names 将提供标量输出的显示标签。
10000/10000 - 1s - loss: 0.3415 - accuracy: 0.8785

Test accuracy: 0.8785
结果表明,测试数据集上的精度略低于训练数据集上的精度。训练精度和测试精度之间的这种差距代表着过拟合。过拟合是指机器学习模型在新的、以前看不到的输入上的表现比在训练数据上的表现更差。一个过拟合的模型“记忆”训练数据,使得测试数据的准确性较低。
过拟合就是把训练数据的特征学的太好了,比如训练数据里的树叶全是绿色的,当模型学习了树叶都是绿色这个特征,测试数据里的黄色树叶他就会错判。
Demonstrate过拟合
防止过度拟合最简单的方法是从一个小模型开始:一个具有少量可学习参数的模型(由层数和每层的units数决定)。在深度学习中,模型中可学习参数的数目通常被称为模型的“容量”。
直观地说,一个具有更多参数的模型将具有更多的“记忆能力”,因此能够轻松地学习训练样本和它们的目标之间的完美字典般的映射,一个没有任何泛化能力(指在训练集外的表现)的映射,但这在对非训练集数据进行预测时是无用的。
永远记住这一点:深度学习模型往往善于拟合训练数据,但真正的挑战是泛化,而不是拟合。
另一方面,如果网络记忆资源太有限,它将无法轻松地学习映射。为了尽量减少它的损失,它将不得不学习具有更多预测能力的压缩representation【这个词想不到合适的翻译,上面在layer层的时候直接译作“表示/述”了】。同时,如果你的模型太小,它将在拟合训练数据上有困难。在“容量过大”和“容量不够”之间应该寻找一个平衡。
不幸的是,没有神奇的公式来确定模型的正确大小或体系结构(根据层数,或每一层的正确大小)。您将不得不使用一系列不同的体系结构进行实验。
为了找到合适的模型大小,最好从相对较少的层和参数开始,然后开始增加层的大小或添加新的层,直到您看到验证损失的回报递减。
把一个只使用dense层的简单模型作为基线,然后创建更大的版本,并对它们进行比较。
打住继续往下走。
做出预测
通过对模型的训练,您可以使用它对一些图像进行预测。
predictions = model.predict(test_images)
在这里,模型预测了测试集中每个图像的标签。让我们来看看第一个预测:
predictions[0]
array([5.5488392e-10, 1.5445305e-12, 1.6554838e-10, 2.7955952e-15,
7.5174762e-11, 9.2117226e-04, 9.5213594e-11, 1.7918178e-03,
9.0349452e-09, 9.9728703e-01], dtype=float32)
Predictions中的每个元素是一个由10个数字组成的数组。它们代表了模型的“置信度”,即图像对应于10种不同的服装中的每一种的可能性。您可以看到哪个标签的置信值最高:
Argmax()是取最大值的函数。
np.argmax(predictions[0])
9
因此,模型最有信心的是这个图像是踝靴,或者类名[9]。检查测试标签表明,这一分类是正确的:
test_labels[0]
9
绘制这张图来查看完整的10个类预测。
#绘制图像的函数
def plot_image(i, predictions_array, true_label, img):
predictions_array, true_label, img = predictions_array, true_label[i], img[i]
#不要网格线和x,y上的标签
plt.grid(False)
plt.xticks([])
plt.yticks([])
#黑白插值
plt.imshow(img, cmap=plt.cm.binary)
#取预测数组的最大值作为预测标签
predicted_label = np.argmax(predictions_array)
#猜对标签是蓝色,猜错是红色
if predicted_label == true_label:
color = ‘blue’
else:
color = ‘red’
#按下面的格式输出
class_names[predicted_label] 100np.max(predictions_array)% (class name[true_label])
plt.xlabel("{} {:2.0f}% ({})".format(class_names[predicted_label],
100
np.max(predictions_array),
class_names[true_label]),
color=color)
#绘制数值分布的函数
def plot_value_array(i, predictions_array, true_label):
predictions_array, true_label = predictions_array, true_label[i]
plt.grid(False)
plt.xticks(range(10))#x轴坐标0-9
plt.yticks([])
thisplot = plt.bar(range(10), predictions_array, color="#777777")#绘制条形图”#777777”是灰色
plt.ylim([0, 1])
predicted_label = np.argmax(predictions_array)

thisplot[predicted_label].set_color(‘red’)#把猜测的那一条柱变红
thisplot[true_label].set_color(‘blue’)#把正确的柱子变蓝
#要是没猜对,红蓝会分离,猜对是蓝色

plt.bar:
画一个条形图。(以下斜体是参数)
横杠以给定的对齐方式定位在x处。它们的尺寸由宽度和高度表示。垂直基线是底部(默认为0)。
每个x、高度、宽度和底部可以是应用于所有条的标量,也可以是长度为N的序列,为每个条提供单独的值。
在上面的代码中,3个参数分别是x轴坐标刻度、和一个数组(为每个位置的条形图高度)、颜色。

验证预测
通过训练模型,您可以使用它对一些图像进行预测。
让我们看看第0张图片、预测和预测数组。正确的预测标签是蓝色的,错误的预测标签是红色的。这个数字给出了预测标签的百分比(满分100)。
下面随便抽一个做预测
i = 12
plt.figure(figsize=(6,3))
plt.subplot(1,2,1)
plot_image(i, predictions[i], test_labels, test_images)
plt.subplot(1,2,2)
plot_value_array(i, predictions[i], test_labels)
plt.show()

猜错了,anyway,反正也有88的精度,能抽到错的也不容易哈。
让我们用模型的预测来绘制几幅图像。请注意,即使在非常自信的情况下,模型也可能出错。
下面就抽15张图来画,但是因为一幅图有俩展示子图,所以尺寸是5x6

Plot the first X test images, their predicted labels, and the true labels.

Color correct predictions in blue and incorrect predictions in red.

num_rows = 5
num_cols = 3
num_images = num_rowsnum_cols
plt.figure(figsize=(2
2num_cols, 2num_rows))
for i in range(num_images):
plt.subplot(num_rows, 2num_cols, 2i+1)
plot_image(i, predictions[i], test_labels, test_images)
plt.subplot(num_rows, 2num_cols, 2i+2)
plot_value_array(i, predictions[i], test_labels)
plt.tight_layout()#让每个子图比例扩张,尽可能填满figures(画板)
plt.show()

使用经过训练的模型
最后,利用训练后的模型对单个图像进行预测。

Grab an image from the test dataset.

img = test_images[1]
print(img.shape)
(28, 28)
tf.keras模型经过优化,可以同时对一批或一组示例进行预测。因此,即使你使用的是一张图片,你也需要将它添加到一个列表中:

Add the image to a batch where it’s the only member.

img = (np.expand_dims(img,0))
print(img.shape)
(1, 28, 28)
np.expand_dims返回的是一个ndarray其实就相当于[图片1,图片2……]这样
现在预测这个图像的正确标签:
predictions_single = model.predict(img)
print(predictions_single)
[[1.03612138e-05 1.82498476e-17 9.99670744e-01 4.75684343e-15
3.05626541e-04 6.80431689e-19 1.32566565e-05 6.62287166e-21
2.54848958e-13 2.97173039e-15]]
plot_value_array(1, predictions_single[0], test_labels)
_ = plt.xticks(range(10), class_names, rotation=45)
Model.predict 会返回一个列表的列表[ [ ]、[ ] ]。外层的列表返回的是批量数据的一张图片的每个组的预测值。其实上面好像提过了
np.argmax(predictions_single[0])
2

完整代码如下:
from future import absolute_import, division, print_function, unicode_literals

TensorFlow and tf.keras

import tensorflow as tf
from tensorflow import keras

Helper libraries

import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
#测试装载tf成功没有
print(tf.version)

#下载mnist数据集
fashion_mnist = keras.datasets.fashion_mnist
(train_images, train_labels), (test_images, test_labels) = fashion_mnist.load_data()
class_names = [‘T-shirt/top’, ‘Trouser’, ‘Pullover’, ‘Dress’, ‘Coat’,‘Sandal’, ‘Shirt’, ‘Sneaker’, ‘Bag’, ‘Ankle boot’]

#输出第一张图片看看
plt.figure()
plt.imshow(train_images[0])
plt.colorbar()
plt.grid(False)
plt.show()

#归一化
train_images = train_images / 255.0
test_images = test_images / 255.0

#抽25张图片配上标签
plt.figure(figsize=(10,10))
for i in range(25):
plt.subplot(5,5,i+1)
plt.xticks([])
plt.yticks([])
plt.grid(False)
plt.imshow(train_images[i], cmap=plt.cm.binary)
plt.xlabel(class_names[train_labels[i]])
plt.show()

#构建线性模型,设置layer
model = keras.Sequential([
keras.layers.Flatten(input_shape=(28, 28)),
keras.layers.Dense(128, activation=‘relu’),
keras.layers.Dense(10, activation=‘softmax’)
])

#编译模型,设置优化器、损失函数、精度
model.compile(optimizer=‘adam’,
loss=‘sparse_categorical_crossentropy’,
metrics=[‘accuracy’])

#把训练数据和标签导入,设置迭代次数
model.fit(train_images, train_labels, epochs=10)

#评估,在测试集上的准确度
test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2)
print(’\nTest accuracy:’, test_acc)

#做出预测
predictions = model.predict(test_images)
predictions[0]
np.argmax(predictions[0])
test_labels[0]

#绘制测试图的函数
def plot_image(i, predictions_array, true_label, img):
predictions_array, true_label, img = predictions_array, true_label[i], img[i]
plt.grid(False)
plt.xticks([])
plt.yticks([])

plt.imshow(img, cmap=plt.cm.binary)

predicted_label = np.argmax(predictions_array)
if predicted_label == true_label:
color = ‘blue’
else:
color = ‘red’

plt.xlabel("{} {:2.0f}% ({})".format(class_names[predicted_label],
100*np.max(predictions_array),
class_names[true_label]),
color=color)
#绘制概率分布情况条形图
def plot_value_array(i, predictions_array, true_label):
predictions_array, true_label = predictions_array, true_label[i]
plt.grid(False)
plt.xticks(range(10))
plt.yticks([])
thisplot = plt.bar(range(10), predictions_array, color="#777777")
plt.ylim([0, 1])
predicted_label = np.argmax(predictions_array)

thisplot[predicted_label].set_color(‘red’)
thisplot[true_label].set_color(‘blue’)

#抽两个倒霉鬼看看
i = 0
plt.figure(figsize=(6,3))
plt.subplot(1,2,1)
plot_image(i, predictions[i], test_labels, test_images)
plt.subplot(1,2,2)
plot_value_array(i, predictions[i], test_labels)
plt.show()

i = 12
plt.figure(figsize=(6,3))
plt.subplot(1,2,1)
plot_image(i, predictions[i], test_labels, test_images)
plt.subplot(1,2,2)
plot_value_array(i, predictions[i], test_labels)
plt.show()
print()

抽15张测试集的图片

num_rows = 5
num_cols = 3
num_images = num_rowsnum_cols
plt.figure(figsize=(2
2num_cols, 2num_rows))
for i in range(num_images):
plt.subplot(num_rows, 2num_cols, 2i+1)
plot_image(i, predictions[i], test_labels, test_images)
plt.subplot(num_rows, 2num_cols, 2i+2)
plot_value_array(i, predictions[i], test_labels)
plt.tight_layout()
plt.show()

path=“E:/1/test.jpg”
img=Image.open(path)
img=img.convert(“L”)
img=img.resize((28,28),Image.ANTIALIAS)
img = np.asarray(img).reshape(28,28)
print(img.shape)
img = (np.expand_dims(img,0))
print(img.shape)
predictions_single = model.predict(img)
print(predictions_single)
plt.xticks(range(10), class_names, rotation=45)
plot_value_array(1, predictions_single[0], test_labels)
np.argmax(predictions_single[0])
我尝试导入自己的图片,用手机拍照,接着用PIL导入,转化成灰度图,接着改变尺寸,接着转化成numpy array类型然后塞进模型。我发现实际上不太可行,因为过于剧烈的尺寸变化造成了图像的失真,他把我的凉鞋当成了包。
同时我也发现每一次运行这段代码,出来的模型效果总会有细微的差别,体现在一些特定的图片上,比如样例给的12,在多次反复运行中有失败也有正确预测的。我猜测是因为dense层的线性变换张量初始化是随机的或者反向迭代的时候这个张量的更新也比较随机。但是每次做完迭代十次的精度差不多都在88左右,又好像不是这样,这个问题等我多学一点再回来解决。

你可能感兴趣的:(使用keras和tensorflow进行minst数据集图像分类)