tensoflow2.0学习笔记——手写识别(MNIST数据)的两种方法,附代码。

学习环境

电脑Windows10,环境anaconda3,开发语言Python3.7

目标

用tensorflow训练MNIST手写数据,并进行测试

实现方法(两种方法)

一、用tensorflow构建一个基本的神经网络,用于预测手写数字。

         本例为3层神经网,包括一个输入层,两个隐层,一个输出层。

         输入数据大小:28*28dpi的手写图片,即(28*28)的二维数组,展平后为长度784的数组。

         直接上代码,代码后面有解析:

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import datasets
import os
import cv2

# 利用Tensorflow2中的接口加载mnist数据集
(x_train, y_train), (x_test, y_test) = datasets.mnist.load_data() 

# 对数据进行预处理
def preprocess(x, y):
    x = tf.cast(x, dtype=tf.float32) / 255.
    y = tf.cast(y, dtype=tf.int32)
    return x,y

# 构建dataset对象,方便对数据的打乱,批处理等超操作
train_db = tf.data.Dataset.from_tensor_slices((x_train,y_train)).shuffle(1000).batch(128)
train_db = train_db.map(preprocess) # 使用map操作,对单值调用preprocess方法
test_db = tf.data.Dataset.from_tensor_slices((x_test,y_test)).batch(128)
test_db = test_db.map(preprocess)  # 使用map操作,对单值调用preprocess方法

#导入一张测试图片(28*28dpi的手写数字)请修改自己的图片路径
check_x = cv2.imread("D:\\tensorflow\\mnist_0_001.png", cv2.IMREAD_GRAYSCALE)
check_y = 0
check_x,check_y = preprocess(check_x,check_y)
check_x = tf.reshape(check_x, [-1, 28*28]) 

# 构建模型中会用到的权重,3层有3组w和b
w1 = tf.Variable(tf.random.truncated_normal([784, 256], stddev=0.1))
b1 = tf.Variable(tf.zeros([256]))
w2 = tf.Variable(tf.random.truncated_normal([256, 128], stddev=0.1))
b2 = tf.Variable(tf.zeros([128]))
w3 = tf.Variable(tf.random.truncated_normal([128, 10], stddev=0.1))
b3 = tf.Variable(tf.zeros([10]))

# 学习率
lr = 0.01 

# epoch表示整个训练集循环的次数 这里循环10次,次数越多学习时间越长,准确率越高
for epoch in range(10):

    # step表示当前训练到了第几个Batch
    for step, (x, y) in enumerate(train_db):  #enumerate() --以索引-值对的形式迭代序列

        # 把训练集进行打平操作
        x = tf.reshape(x, [-1, 28*28])

        # 构建模型并计算梯度
        with tf.GradientTape() as tape: # tf.Variable

            # 三层非线性模型搭建
            h1 = x@w1 + tf.broadcast_to(b1, [x.shape[0], 256])
            h1 = tf.nn.relu(h1)
            h2 = h1@w2 + b2
            h2 = tf.nn.relu(h2)
            out = h2@w3 + b3

            # 把y转化成one_hot编码,当depth=10,y=3时,y变换为[0,0,0,1,0,0,0,0,0,0]
            y_onehot = tf.one_hot(y, depth=10)

            # 计算MSE
            loss = tf.square(y_onehot - out)
            loss = tf.reduce_mean(loss)

        # 计算梯度
        grads = tape.gradient(loss, [w1, b1, w2, b2, w3, b3])
        
        # w = w - lr * w_grad
        # 利用上述公式进行权重的更新
        w1.assign_sub(lr * grads[0])    #tf.assign_sub(ref, value, use_locking=None, name=None),变量 ref 减去 value值,即 ref = ref - value
        b1.assign_sub(lr * grads[1])
        w2.assign_sub(lr * grads[2])
        b2.assign_sub(lr * grads[3])
        w3.assign_sub(lr * grads[4])
        b3.assign_sub(lr * grads[5])

        # 每训练100个Batch 打印一下当前的loss
        if step % 100 == 0:
            print(epoch, step, 'loss:', float(loss))
    
    # 每训练完一次数据集 测试一下准确率
    total_correct, total_num = 0, 0
    for step, (x,y) in enumerate(test_db):
        x = tf.reshape(x, [-1, 28*28])
        h1 = tf.nn.relu(x@w1 + b1)
        h2 = tf.nn.relu(h1@w2 + b2)
        out = h2@w3 +b3

        # 把输出值映射到[0~1]之间
        prob = tf.nn.softmax(out, axis=1)

        # 获取概率最大值得索引位置
        pred = tf.argmax(prob, axis=1)   #根据axis取值的不同返回每行(0)或者每列(1)最大值的索引
        pred = tf.cast(pred, dtype=tf.int32)  #tf.cast()函数的作用是执行tensorflow中张量数据类型转换
        correct = tf.cast(tf.equal(pred, y), dtype=tf.int32)
        correct = tf.reduce_sum(correct)
 
        # 获取每一个batch中的正确率和batch大小
        total_correct += int(correct)
        total_num += x.shape[0]

    # 计算总的正确率
    acc = total_correct / total_num
    print("y:",y, "predict:",pred)

    # predict check_x,利用获得的权重w和偏置b对手写数字图片数据进行预测
    h1 = tf.nn.relu(check_x@w1 + b1)
    h2 = tf.nn.relu(h1@w2 + b2)
    out = h2@w3 +b3

    # 把输出值映射到[0~1]之间
    prob = tf.nn.softmax(out, axis=1)

    # 获取概率最大值得索引位置
    pred_check = tf.argmax(prob, axis=1)
    pred_check = tf.cast(pred_check, dtype=tf.int32)
    print('test acc:', acc,"pred=",pred_check,"acc=",tf.equal(check_y ,pred_check))

 

二、直接用tensorflow的Keras创建神经网络模型。

这里利用tensorflow 的Keras.model 类创建模型,练习模型,评估模型,预测模型。

本例创建了2层神经网络,其中隐层有512个神经元,输出层为10。模型完成学习后,将通过model.save_weights()保存训练好的权重和偏置参数,之后就可以通过model.load_weights()导出已存的权重和偏置,然后就可以用学习好的模型进行预测了。

训练数据的保存还有一种方法:model.save()和model.load()。具体可以在网上找到,这里不再演示。

模型创建/训练/评估代码如下:

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import datasets, layers, optimizers
 
# step1 加载训练集和测试集合
mnist = tf.keras.datasets.mnist
(x_train, y_train),(x_test, y_test) = mnist.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

# step2 创建模型
def create_model():
  return tf.keras.models.Sequential([                #堆叠式创建层
    tf.keras.layers.Flatten(input_shape=(28, 28)),   #将28*28的输入数组展平为784的一维数据
    tf.keras.layers.Dense(512, activation='relu'),   #512个神经元,激活函数:relu
    tf.keras.layers.Dropout(0.2),                    #设定20%的随机扔掉,为避免过拟合
    tf.keras.layers.Dense(10, activation='softmax')  #输出层为10,激活函数:softmax
  ])
model = create_model()
 
# step3 编译模型 主要是确定优化方法,损失函数等
model.compile(optimizer='adam',    #优化器:'adam',损失函数:'sparse_categorical_crossentropy'
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

# step4 模型训练  训练1个epochs ,batch_size=256(可以为None),可以自己修改数字,看看运行结果及耗时情况
model.fit(x=x_train,
          y=y_train,
          epochs=1,
          batch_size=256
          )
 
# step5 用model.evaluate进行模型测试
loss, acc = model.evaluate(x_test, y_test)  #model.evaluate输入数据(data)和金标准(label),然后将预测结果与金标准相比较,得到两者误差并输出.
print("train model, accuracy:{:5.2f}%".format(100 * acc))
 
# step6 保存模型的权重和偏置
model.save_weights('./save_weights/my_save_weights')

# step7 删除模型
del model

# step8 重新创建模型
model = create_model()
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

# step9 恢复权重
model.load_weights('./save_weights/my_save_weights')

# step10 测试模型
loss, acc = model.evaluate(x_test, y_test)
print("Restored model, accuracy:{:5.2f}%".format(100 * acc))

以下代码为检测图片,输入图片文件名,输出预测结果。注意:输入的手写体如果与MNIST的图片类似识别率还是很高的,如果是自己用画图软件做的手写数字则识别成功率很低。

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import datasets, layers, optimizers
import cv2
 
# step1 重新创建模型
def create_model():
  return tf.keras.models.Sequential([
    tf.keras.layers.Flatten(input_shape=(28, 28)),
    tf.keras.layers.Dense(512, activation='relu'),
    tf.keras.layers.Dropout(0.2),
    tf.keras.layers.Dense(10, activation='softmax')
  ])
model = create_model()
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

# step2 恢复权重
model.load_weights('./save_weights/my_save_weights')

imgDir = "D:\\tensorflow\\"
imgFile = input("请输入待检测的文件名:")
while imgFile != "q":              #输入q则退出程序

    #导入测试图片
    check_x = cv2.imread(imgDir+imgFile, cv2.IMREAD_GRAYSCALE)
    check_x = check_x / 255.0
    check_x = tf.reshape(check_x, [1, 28, 28])

    #用model.predict对一个手写图片进行预测,显示预测结果
    prob = model.predict(check_x, batch_size=None) #model.predict输入数据(data),输出预测结果
    pred_check = tf.argmax(prob, axis=1)
    pred_check = tf.cast(pred_check, dtype=tf.int32)
    print(imgFile,"预测结果:",pred_check)
    imgFile = input("请输入待检测的文件名:")

 

你可能感兴趣的:(tensorflow,Python)