相关介绍

  • Python是一种跨平台的计算机程序设计语言。是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越多被用于独立的、大型项目的开发。
  • TensorFlow 是一个端到端开源机器学习平台。它拥有一个全面而灵活的生态系统,其中包含各种工具、库和社区资源,可助力研究人员推动先进机器学习技术的发展,并使开发者能够轻松地构建和部署由机器学习提供支持的应用。
  • Matplotlib是一个综合库,用于在Python中创建静态,动画和交互式可视化。
  • NumPy是使用Python进行数组计算的基本软件包。
  • Glob是python自己带的一个文件操作相关模块,用它可以查找符合自己目的的文件,类似于Windows下的文件搜索,支持通配符操作。

实验环境

  • Python 3.6.2
  • Tensorflow-gpu 2.0.0
  • Matplotlib 3.3.2
  • Numpy 1.18.5
  • Opencv 3.4.2

实验步骤

导入相关库

# 导入相关库
import cv2
import glob  #查找符合特定规则的文件路径名
import random
import tensorflow as tf
from tensorflow import keras
import numpy as np
import matplotlib.pyplot as plt

导入数据集

本文使用自己整理数据集,该数据集包含3个类别的 10,00 多个灰度图像。这些图像以低分辨率(28x28 像素)展示了单个动物,如下所示:

# 导入数据集
def load_data():
    # 训练数据路径
    trainpath = "./train_imgs/*.jpg"
    # 训练数据列表
    trainlist = glob.glob(trainpath)
    # 乱序
    random.shuffle(trainlist)
    # 测试数据路径
    testpath = "./test_imgs/*.jpg"
    # 测试数据列表
    testlist = glob.glob(testpath)
    # 乱序
    random.shuffle(testlist)
    # 用于保存格式化的相关数据
    train_images = []
    train_labels = []
    test_images = []
    test_labels = []
    print(trainlist[:50],testlist[:50])
    for imageFile in trainlist:
        #print(imageFile)
        img = cv2.imread(imageFile,0)
        train_images.append(img)
        if "bird" in imageFile:
            train_labels.append(0)
        elif "dog" in imageFile:
            train_labels.append(1)
        else:
            train_labels.append(2)
    # 将列表转成np的array
    train_images = np.array(train_images)
    train_labels = np.array(train_labels)
    # print(train_images.shape)
    # print(train_labels)

    for imageFile in testlist:
        #print(imageFile)
        img = cv2.imread(imageFile,0)
        test_images.append(img)
        if "bird" in imageFile:
            test_labels.append(0)
        elif "dog" in imageFile:
            test_labels.append(1)
        else:
            test_labels.append(2)
    # 将列表转成np的array
    test_images = np.array(test_images)
    test_labels = np.array(test_labels)
    return (train_images, train_labels), (test_images, test_labels)

加载数据集会返回四个 NumPy 数组:

  • train_images 和 train_labels 数组是训练集,即模型用于学习的数据。
  • 测试集、test_images 和 test_labels 数组会被用来对模型进行测试。
(train_images, train_labels), (test_images, test_labels) = load_data()
['./train_imgs\\bird172.jpg', './train_imgs\\fish335.jpg', './train_imgs\\bird236.jpg', './train_imgs\\bird134.jpg', './train_imgs\\fish427.jpg', './train_imgs\\bird227.jpg', './train_imgs\\dog244.jpg', './train_imgs\\dog177.jpg', './train_imgs\\dog34.jpg', './train_imgs\\fish69.jpg', './train_imgs\\fish50.jpg', './train_imgs\\bird272.jpg', './train_imgs\\bird85.jpg', './train_imgs\\dog25.jpg', './train_imgs\\bird259.jpg', './train_imgs\\bird16.jpg', './train_imgs\\bird136.jpg', './train_imgs\\fish228.jpg', './train_imgs\\dog219.jpg', './train_imgs\\bird123.jpg', './train_imgs\\bird180.jpg', './train_imgs\\dog346.jpg', './train_imgs\\bird3.jpg', './train_imgs\\bird95.jpg', './train_imgs\\bird69.jpg', './train_imgs\\dog399.jpg', './train_imgs\\fish151.jpg', './train_imgs\\fish374.jpg', './train_imgs\\bird14.jpg', './train_imgs\\bird186.jpg', './train_imgs\\fish219.jpg', './train_imgs\\bird289.jpg', './train_imgs\\dog80.jpg', './train_imgs\\bird274.jpg', './train_imgs\\fish197.jpg', './train_imgs\\dog94.jpg', './train_imgs\\bird379.jpg', './train_imgs\\bird120.jpg', './train_imgs\\dog292.jpg', './train_imgs\\bird208.jpg', './train_imgs\\fish247.jpg', './train_imgs\\dog350.jpg', './train_imgs\\bird44.jpg', './train_imgs\\fish152.jpg', './train_imgs\\dog164.jpg', './train_imgs\\fish298.jpg', './train_imgs\\dog180.jpg', './train_imgs\\dog192.jpg', './train_imgs\\dog222.jpg', './train_imgs\\bird15.jpg'] ['./test_imgs\\bird470.jpg', './test_imgs\\dog516.jpg', './test_imgs\\fish461.jpg', './test_imgs\\dog482.jpg', './test_imgs\\dog468.jpg', './test_imgs\\bird397.jpg', './test_imgs\\bird422.jpg', './test_imgs\\dog441.jpg', './test_imgs\\fish512.jpg', './test_imgs\\fish500.jpg', './test_imgs\\fish445.jpg', './test_imgs\\dog509.jpg', './test_imgs\\fish441.jpg', './test_imgs\\fish487.jpg', './test_imgs\\dog491.jpg', './test_imgs\\fish471.jpg', './test_imgs\\fish464.jpg', './test_imgs\\fish470.jpg', './test_imgs\\dog493.jpg', './test_imgs\\fish515.jpg', './test_imgs\\dog511.jpg', './test_imgs\\fish453.jpg', './test_imgs\\fish432.jpg', './test_imgs\\bird406.jpg', './test_imgs\\dog504.jpg', './test_imgs\\fish505.jpg', './test_imgs\\bird428.jpg', './test_imgs\\fish463.jpg', './test_imgs\\bird440.jpg', './test_imgs\\fish504.jpg', './test_imgs\\dog455.jpg', './test_imgs\\dog458.jpg', './test_imgs\\fish516.jpg', './test_imgs\\dog448.jpg', './test_imgs\\dog466.jpg', './test_imgs\\fish451.jpg', './test_imgs\\fish450.jpg', './test_imgs\\fish473.jpg', './test_imgs\\fish438.jpg', './test_imgs\\fish488.jpg', './test_imgs\\fish448.jpg', './test_imgs\\bird419.jpg', './test_imgs\\fish478.jpg', './test_imgs\\fish485.jpg', './test_imgs\\bird449.jpg', './test_imgs\\bird469.jpg', './test_imgs\\dog459.jpg', './test_imgs\\dog503.jpg', './test_imgs\\bird445.jpg', './test_imgs\\bird409.jpg']

图像是 28x28 的 NumPy 数组,像素值介于 0 到 255 之间。标签是整数数组,介于 0 到 2 之间。这些标签对应于图像所代表的动物类:

标签
0bird
1dog
2fish
class_names = ['bird', 'dog', 'fish']

浏览数据

在训练模型之前,先浏览一下数据集的格式。以下代码显示训练集中有 1260 个图像,每个图像由 28 x 28 的像素表示:

train_images.shape
(1260, 28, 28)
len(train_labels)
1260
train_labels
array([0, 2, 0, ..., 0, 1, 1])
test_images.shape
(260, 28, 28)
len(test_labels)
260

预处理数据

在训练网络之前,必须对数据进行预处理。如果您检查训练集中的第一个图像,您会看到像素值处于 0 到 255 之间:

在这里插入图片描述

plt.figure()
plt.imshow(train_images[0])
plt.colorbar()
plt.grid(False)
plt.show()

将这些值缩小至 0 到 1 之间,然后将其馈送到神经网络模型。为此,将这些值除以 255。以相同的方式对训练集和测试集进行预处理:

# 归一化
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()

在这里插入图片描述

构建模型

构建神经网络需要先配置模型的层,然后再编译模型。

设置层

神经网络的基本组成部分是层。层会从向其馈送的数据中提取表示形式。希望这些表示形式有助于解决手头上的问题。

大多数深度学习都包括将简单的层链接在一起。大多数层(如 tf.keras.layers.Dense)都具有在训练期间才会学习的参数。

# 设置层
model = keras.Sequential([
    keras.layers.Flatten(input_shape=(28, 28)),
    keras.layers.Dense(128, activation='relu'),
    keras.layers.Dense(3)
])
model.summary() # 显示模型结构
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
flatten (Flatten)            (None, 784)               0         
_________________________________________________________________
dense (Dense)                (None, 128)               100480    
_________________________________________________________________
dense_1 (Dense)              (None, 3)                 387       
=================================================================
Total params: 100,867
Trainable params: 100,867
Non-trainable params: 0
_________________________________________________________________

该网络的第一层 tf.keras.layers.Flatten 将图像格式从二维数组(28 x 28 像素)转换成一维数组(28 x 28 = 784 像素)。将该层视为图像中未堆叠的像素行并将其排列起来。该层没有要学习的参数,它只会重新格式化数据。

展平像素后,网络会包括两个 tf.keras.layers.Dense 层的序列。它们是密集连接或全连接神经层。第一个 Dense 层有 128 个节点(或神经元)。第二个(也是最后一个)层会返回一个长度为 3 的 logits 数组。每个节点都包含一个得分,用来表示当前图像属于 3 个类中的哪一类。

编译模型

在准备对模型进行训练之前,还需要再对其进行一些设置。以下内容是在模型的编译步骤中添加的:

  • 损失函数 - 用于测量模型在训练期间的准确率。您会希望最小化此函数,以便将模型“引导”到正确的方向上。
  • 优化器 - 决定模型如何根据其看到的数据和自身的损失函数进行更新。
  • 指标 - 用于监控训练和测试步骤。以下示例使用了准确率,即被正确分类的图像的比率。
# 编译模型
model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])

训练模型

训练神经网络模型需要执行以下步骤:

  • 将训练数据馈送给模型。在本例中,训练数据位于 train_images 和 train_labels 数组中。
  • 模型学习将图像和标签关联起来。
  • 要求模型对测试集(在本例中为 test_images 数组)进行预测。
  • 验证预测是否与 test_labels 数组中的标签相匹配。
向模型馈送数据

要开始训练,请调用 model.fit 方法,这样命名是因为该方法会将模型与训练数据进行“拟合”:

model.fit(train_images, train_labels, epochs=10)
Train on 1260 samples
Epoch 1/10
1260/1260 [==============================] - 1s 508us/sample - loss: 1.1468 - accuracy: 0.4143
Epoch 2/10
1260/1260 [==============================] - 0s 89us/sample - loss: 1.0642 - accuracy: 0.4389
Epoch 3/10
1260/1260 [==============================] - 0s 90us/sample - loss: 1.0220 - accuracy: 0.4817
Epoch 4/10
1260/1260 [==============================] - 0s 89us/sample - loss: 1.0088 - accuracy: 0.4706
Epoch 5/10
1260/1260 [==============================] - 0s 92us/sample - loss: 0.9562 - accuracy: 0.5317
Epoch 6/10
1260/1260 [==============================] - 0s 90us/sample - loss: 0.9411 - accuracy: 0.5230
Epoch 7/10
1260/1260 [==============================] - 0s 85us/sample - loss: 0.8950 - accuracy: 0.5690
Epoch 8/10
1260/1260 [==============================] - 0s 92us/sample - loss: 0.8582 - accuracy: 0.6063
Epoch 9/10
1260/1260 [==============================] - 0s 87us/sample - loss: 0.8597 - accuracy: 0.5929
Epoch 10/10
1260/1260 [==============================] - 0s 93us/sample - loss: 0.8627 - accuracy: 0.6008

<tensorflow.python.keras.callbacks.History at 0x1b19eadca58>

在模型训练期间,会显示损失和准确率指标。此模型在训练数据上的准确率达到了 0.55(或 55%)左右。

本文旨在学习思路,不对准确率做任何的要求,低准确率可能会导致模型预测能力不佳!

评估准确率

接下来,比较模型在测试数据集上的表现:

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

print('\nTest accuracy:', test_acc)
260/1 - 0s - loss: 1.4137 - accuracy: 0.4308

Test accuracy: 0.43076923

进行预测

在模型经过训练后,您可以使用它对一些图像进行预测。模型具有线性输出,即 logits。您可以附加一个 softmax 层,将 logits 转换成更容易理解的概率。

probability_model = tf.keras.Sequential([model, 
                                         tf.keras.layers.Softmax()])
# 模型预测了测试集中每个图像的标签
predictions = probability_model.predict(test_images)
predictions[0] # 第一个预测结果
array([0.15625006, 0.6530249 , 0.190725  ], dtype=float32)

预测结果是一个包含 3 个数字的数组。它们代表模型对 3 种不同动物的“置信度”。您可以看到哪个标签的置信度值最大:

np.argmax(predictions[0])
1

因此,该模型非常确信这个图像是fish,或 class_names[2]。通过检查测试标签发现这个分类是错误的(训练的模型准确率不高):

test_labels[0]
0
# 将其绘制成图表,看看模型对于全部 3 个类的预测
def plot_image(i, predictions_array, true_label, img):
    '''
        params:
            i(int):第i张图片;
            predictions_array(array):预测数组
            true_label(int):正确标签
            img(array):图片数组
    '''
    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):
    '''
        params:
            predictions_array(array):预测数组
            true_label(int):正确标签
    '''
    predictions_array, true_label = predictions_array, true_label[i]
    plt.grid(False)
    plt.xticks(range(len(class_names)))
    plt.yticks([])
    thisplot = plt.bar(range(len(class_names)), 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')

验证预测结果

第 0 个图像、预测结果和预测数组。正确的预测标签为蓝色,错误的预测标签为红色。数字表示预测标签的百分比(总计为 100)。

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()

在这里插入图片描述

用模型的预测绘制几张图像。请注意,即使置信度很高,模型也可能出错。

# 正确的预测标签为蓝色,错误的预测标签为红色。
num_rows = 5
num_cols = 3
num_images = num_rows*num_cols
plt.figure(figsize=(2*2*num_cols, 2*num_rows))
for i in range(num_images):
    plt.subplot(num_rows, 2*num_cols, 2*i+1)
    plot_image(i, predictions[i], test_labels, test_images)
    plt.subplot(num_rows, 2*num_cols, 2*i+2)
    plot_value_array(i, predictions[i], test_labels)
plt.tight_layout()
plt.show()

在这里插入图片描述

使用训练好的模型

# 从测试数据集中获取一个图像。
img = test_images[1]
print(img.shape)
(28, 28)

tf.keras 模型经过了优化,可同时对一个批或一组样本进行预测。因此,即便您只使用一个图像,您也需要将其添加到列表中:

# 将图像添加到批处理中,其中它是唯一的成员。
img = (np.expand_dims(img,0))

print(img.shape)
(1, 28, 28)

预测这个图像的正确标签:

predictions_single = probability_model.predict(img)

print(predictions_single)
[[0.02041672 0.96835506 0.01122819]]
plot_value_array(1, predictions_single[0], test_labels)
_ = plt.xticks(range(3), class_names, rotation=45)

在这里插入图片描述

np.argmax(predictions_single[0])
1

参考文献

[1]Tesorflow官方文档(https://tensorflow.google.cn/tutorials)

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐