20210608 TensorFlow 实现数字图片分类

Posted ATaburiss

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了20210608 TensorFlow 实现数字图片分类相关的知识,希望对你有一定的参考价值。

0-1 导包

import warnings
warnings.filterwarnings("ignore")

import keras
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt


1-1 构造数据

调用接口去下载数据

mnist = keras.datasets.mnist     # 导入 mnist 
(train_images, train_labels),(test_images,test_labels) = mnist.load_data()

60000条训练集,10000条测试集

print("train image shape:",train_images.shape,"train label",train_labels.shape)
print("test image shape:",test_images.shape,"test label",test_labels.shape)

-->
train image shape: (60000, 28, 28) train label (60000,)
test image shape: (10000, 28, 28) test label (10000,)
60000条训练集分为训练的图片和标签,图片是手写的数字图片,长和宽都是 28,标签就是数字集,测试集是 10000 个图片,测试标签也是 10000

1-1-1 显示数据和标签

print("image data:",train_images[0])
print("label data:",train_labels[0])

# 数据太多太大,这里便不展示了
# label data: 5

1-1-2

defplot_img(img):
    plt.imshow(img.reshape(28,28),cmap="binary")    # camp = "binary" 使用灰度图表示
    plt.show()
# 查看图片
plot_img(train_images[3])
plot_img(train_images[0])


1-1-3 现在进行一个 0 1 的二分类

data_0 = []
data_1 = []
# zip 把里面的子数据 拿出来了,img是(28,28);label 标签是一个值
for img,label in zip(train_images, train_labels):
    if label == 0:
        # 首先需要把图片拍平,现在的训练是一种类似 DNN 神经网络的模式
        # 所以无法传入 28*28 的图片进行训练,reshape(28*28),将二阶变为一阶的 784
        # 除以 255 的作用是,约束到 0 到 1 之间
        img = img.reshape(28*28)/255    
        # 将图片和 label 放一起,变成 785 个数据,赋给 img
        img = np.append(img,label)
        data_0.append(img)  
    if label == 1:
        img = img.reshape(28*28)/255
        img = np.append(img,label)
        data_1.append(img)
data_0 = np.array(data_0)
data_1 = np.array(data_1)
all_data = np.concatenate([data_0,data_1])
print(all_data.shape)

# --> (12665, 785)
# 前 784 是像素,最后的 1 是标签

np.random.shuffle(all_data)     # np.random.shuffle 打乱顺序,避免前面全是0,后面全是 1
# 切分训练集和数据集,按理说 20% 测试集,80%训练集,这里只是简单的 前面的作为训练集,后200个作为测试集
train_data = all_data[:-200]
test_data = all_data[-200:]


2-1 数据分块

# 生成器
def gen_batch(data,batch_size):
    np.random.shuffle(data)     # 打乱,增加随机性
    for i in range(len(data) // batch_size):
        cursor = batch_size * i
        batch_data = data[cursor : cursor + batch_size]
        x = batch_data[:, 0:784]    # 第一维度全取,第二维度取前 784 个像素,最后一个是标签
        y = batch_data[:, 784]
        yield x,y.reshape(-1,1)
    remainder = len(data) % batch_size
    if remainder != 0:
        x, y = data[-remainder:, 0:784], data[-remainder:, 784]
        yield x, y.reshape(-1,1)
for x_,y_ in gen_batch(train_data,128):
    print(x_.shape)
    print(y_.shape)
    print(\'-------\')
    break

# -->
# (128, 784)
# (128, 1)
# -------

3-1 超参数

learing_rate = 0.01
num_train_epochs = 50      # 循环训练集总轮数
display_per_step = 100
batch_size = 128


4-1 计算图

graph = tf.Graph()
with graph.as_default():
    x = tf.placeholder(shape=[None,784], dtype=tf.float32, name=\'x\')
    y = tf.placeholder(shape=[None,1], dtype=tf.float32, name=\'y\')
    w =  tf.Variable(tf.ones(shape=[784,1]), dtype=tf.float32)
    b =  tf.Variable(0, dtype=tf.float32)
    logits = tf.matmul(x, w) + b    
    y_pred = tf.sigmoid(logits)
    # 定义loss
    with tf.name_scope("loss"):
        loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(labels=y, logits=logits), name="calculate_loss")
    # 定义优化器
    with tf.name_scope("SGD"):
        optimizer = tf.train.GradientDescentOptimizer(learing_rate)
        train_step = optimizer.minimize(loss)
    # 定义正确率
    with tf.name_scope("calculation_accuracy"):
        res_pred = tf.cast(tf.greater_equal(y_pred, 0.5), dtype=tf.float32)
        acc = tf.reduce_mean(tf.cast(tf.equal(res_pred, y), dtype=tf.float32))


5-1 运行计算图

with tf.Session(graph=graph) as sess:
    init = tf.global_variables_initializer()
    sess.run(init)
    step = 0
    for epoch in range(num_train_epochs):
        for x_, y_ in gen_batch(train_data, batch_size):
            step += 1
            _, l, acc_ = sess.run([train_step, loss, acc], feed_dict={x: x_, y: y_})
            if step % display_per_step == 0:
                print("step: {:>4}, loss: {:.4}, acc: {:.4%}".format(step, l, acc_))
    print(\'training over\')
    x_test,y_test = next(gen_batch(test_data,200))   # 取出全部测试集数据
    # 查看测试集的 loss 和正确率
    loss_test, acc_test = sess.run([loss, acc],feed_dict={x: x_test, y: y_test})
    print("test loss is {:.4}, acc is {:.4%}".format(loss_test, acc_test))
    res_weights = sess.run([w, b])
    # res_weights 存在的目的是进行模型的预测,给出一张图片,判断能否正确预测

-->
step:  100, loss: 43.14, acc: 60.1562%
step:  200, loss: 34.86, acc: 50.7812%
step:  300, loss: 19.21, acc: 52.3438%
……
step: 4700, loss: 0.09711, acc: 96.8750%
step: 4800, loss: 0.1117, acc: 97.6562%
step: 4900, loss: 0.0001993, acc: 100.0000%
training over
test loss is 0.04518, acc is 99.0000%

6-1 模型预测

def plot_img(img):
    plt.imshow(img.reshape(28,28),cmap="binary")
    plt.show()
test_img = test_data[7,:784]
plot_img(test_img)


6-2

graph = tf.Graph()
with graph.as_default():
    x = tf.placeholder(shape=[None,784], dtype=tf.float32, name=\'x\')
    y = tf.placeholder(shape=[None,1], dtype=tf.float32, name=\'y\')
    # w 和 b 是前面训练好的值
    w =  tf.Variable(res_weights[0], dtype=tf.float32)
    b =  tf.Variable(res_weights[1], dtype=tf.float32)
    logits = tf.matmul(x, w) + b
    y_pred = tf.sigmoid(logits)
    # 定义loss
    with tf.name_scope("loss"):
        loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(labels=y, logits=logits), name="calculate_loss")
    # 定义优化器
    with tf.name_scope("SGD"):
        optimizer = tf.train.GradientDescentOptimizer(learing_rate)
        train_step = optimizer.minimize(loss)
    # 定义正确率
    with tf.name_scope("calculation_accuracy"):
        res_pred = tf.cast(tf.greater_equal(y_pred, 0.5), dtype=tf.float32)
        acc = tf.reduce_mean(tf.cast(tf.equal(res_pred, y), dtype=tf.float32))
with tf.Session(graph=graph) as sess:
    # 初始化权重,将前面训练好的权重,放到计算图里
    init = tf.global_variables_initializer()
    sess.run(init)
    # test_data[7,:784].shape 是 (784,)
    # 但是   x = tf.placeholder(shape=[None,784], dtype=tf.float32, name=\'x\')
    # 所以需要 reshape 成为 (1,-1),也就是第一维是 1,第二维就是 784/1
    # 所以 当前这里图片 的 shape 就是 (1,784)
    x_ = test_data[7,:784].reshape(1,-1)
    # 从这地方可以看出,预测输出的时候,并没有使用标签,所以传参时只传 x 就可以
    res_p = sess.run(res_pred, feed_dict={x: x_})
    print(res_p)

# --> [[0.]]
预测出的结果是 0,所以简单的网络结构确实可以对测试集的手写数字图片进行预测,这就是一个数字的图片分类

部分代码解释:
1. 1-1-3 中的 zip()
https://blog.51cto.com/u_15149862/2847102
2. 1-1-3 中列表的使用,比如 train_data = all_data[:-200]
https://blog.51cto.com/u_15149862/2704954
3. 2-1 中的生成器
https://blog.51cto.com/u_15149862/2844458
4. TensorFlow 基本用法
https://blog.51cto.com/u_15149862/2825353

以上是关于20210608 TensorFlow 实现数字图片分类的主要内容,如果未能解决你的问题,请参考以下文章

20210608 由永久代到元空间

基本概念——张量会话计算图

AI常用框架和工具丨10. TensorFlow实现基于LeNet5的手写数字识别

AI常用框架和工具丨10. TensorFlow实现基于LeNet5的手写数字识别

20210608记第一次申请域名

阿里巴巴2021实习生笔试题20210608