[tensorflow2笔记七] 网络八股扩展

使用tf.keras搭建全连接网络,实现mnist数据集的模型训练和数字识别。

文章目录

  • 1.自制数据集,解决本领域应用
  • 2.数据增强,扩充数据集
  • 3.断点续训,存取模型
  • 4.参数提取,把参数存入文本
  • 5.acc/loss可视化,查看训练效果
  • 6.应用程序,给图识物
  • 完整代码:(希望自己能背过)
    • 代码1---训练模型
    • 代码2:使用训练好的模型,给图出结果

1.自制数据集,解决本领域应用

(1)数据集结构

两个包含图片的文件夹:
mnist_train_jpg_60000:60000张图片
mnist_test_jpg_10000:10000张图片

0_5.jpg,1_7.jpg等图片都是黑底白字灰度图,28x28个像素点,每个像素点都是0-255之间的整数,纯黑色0,纯白色255。

两个标签文本:
mnist_train_jpg_60000.txt
mnist_test_jpg_10000.txt

文本中有两列:图片名 标签
0_5.jpg 5
2_9.jpg 9

(2)构造函数,替换load_data(),给x_train,y_train,x_test,y_test赋值

def generateds(图片路径,标签文件)
将图片灰度值数据拼接到图片列表,把标签数据拼接到标签列表,顺序一致就可以。

(3)制作并使用数据集的demo

# 1.导入一些模块
import tensorflow as tf
from PIL import Image   # 用于打开一张图片
import numpy as np      # 用于数据格式转换
import os				# 路径

# 2.路径和存储文件
train_path = './mnist_image_label/mnist_train_jpg_60000/'       # 训练集图片路径
train_txt = './mnist_image_label/mnist_train_jpg_60000.txt'     # 训练集标签文件
x_train_savepath = './mnist_image_label/mnist_x_train.npy'      # 训练集输入特征存储文件
y_train_savepath = './mnist_image_label/mnist_y_train.npy'      # 训练集标签存储文件

test_path = './mnist_image_label/mnist_test_jpg_10000/'         # 测试集图片路径
test_txt = './mnist_image_label/mnist_test_jpg_10000.txt'       # 测试集标签文件
x_test_savepath = './mnist_image_label/mnist_x_test.npy'        # 测试集输入特征存储文件
y_test_savepath = './mnist_image_label/mnist_y_test.npy'        # 测试集标签存储文件

# 3.制作数据集的函数
def generateds(path, txt):          # 图片路径,标签文件
    f = open(txt, 'r')              # 以只读的形式打开txt
    contents = f.readlines()        # 读取文件中所有的行,每行为一个单位
    f.close()
    x, y_ = [], []
    for content in contents:                # 逐行读出
        value = content.split()             # 以空格分开
        img_path = path + value[0]
        img = Image.open(img_path)
        img = np.array(img.convert('L'))    # 图片变为8位宽度的灰度值
        img = img / 255.                    # 数据归一化
        x.append(img)
        y_.append(value[1])
        print('load:' + content)

    x = np.array(x)
    y_ = np.array(y_)
    y_ = y_.astype(np.int64)
    return x, y_

# 4.加载数据
if os.path.exists(x_train_savepath) and os.path.exists(y_train_savepath) and os.path.exists(
    x_test_savepath) and os.path.exists(y_test_savepath):   # 判断x_train,y_train,x_test,y_test是否存在
    print("----------------Load Datasets-------------")
    x_train_save = np.load(x_train_savepath)
    y_train = np.load(y_train_savepath)
    x_test_save = np.load(x_test_savepath)
    y_test = np.load(y_test_savepath)
    x_train = np.reshape(x_train_save, (len(x_train_save), 28, 28))
    x_test = np.reshape(x_test_save, (len(x_test_save), 28, 28))

else:   # 不存在,则调用generateds()函数制作数据集
    print('----------------Generate Datasets--------------')
    x_train, y_train = generateds(train_path, train_txt)
    x_test, y_test = generateds(test_path, test_txt)
	
	# 保存制作好的数据集,下次训练可以直接使用
    print('----------------Save Datasets------------------')
    x_train_save = np.reshape(x_train, (len(x_train), -1))
    x_test_save = np.reshape(x_test, (len(x_test), -1))
    np.save(x_train_savepath, x_train_save)
    np.save(y_train_savepath, y_train)
    np.save(x_test_savepath, x_test_save)
    np.save(y_test_savepath, y_test)

# 5.搭建网络
model = tf.keras.models.Sequential([
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(10, activation='softmax')
])

# 6.配置参数
model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),
              metrics=['sparse_categorical_accuracy'])

# 7.训练
model.fit(x_train, y_train,batch_size=32,epochs=5,validation_data=(x_test, y_test),validation_freq=1)

# 8.打印网络参数
model.summary()

2.数据增强,扩充数据集

(1)理解

对图像的增强,就是对图像的简单形变,用来应对因拍照角度不同引起的图片变形。

数据增强在小数据量上可以增加模型泛化性。

(2)函数

# 1.设置数据增强参数
image_gen_train = tf.keras.preprocessing.image.ImageDataGenerator(
    rescale=所有数据乘以该数值
    rotation_range=随机旋转角度数范围
    width_shift_range=随机宽度偏移量
    height_shift_range=随机高度偏移量
    horizontal_flip=是否随机水平翻转
    zoom_range=随机缩放的范围[1-n, 1+n]
)
# 2.对输入特征进行数据增强
x_train = x_train.reshape(x_train.shape[0], 28, 28 ,1) # 增加一个维度,使数据与网络结构匹配
image_gen_train.fit(x_train)		# 此处的x_train要输入一个四维数据

# 3.变动model.fit
# 将x_train,y_train,batch打包,其余相同
model.fit(image_gen_train.flow(x_train,y_train,batch=32),...)

例子:

image_gen_train = tf.keras.preprocessing.image.ImageDataGenerator(
    rescale=1. / 1.,          # 如果是图像,分母为255,可以归一化到0-1
    rotation_range=45,        # 随机45度旋转
    width_shift_range=.15,    # 宽度偏移
    height_shift_range=.15,   # 高度偏移
    horizontal_flip=False,    # 水平翻转
    zoom_range=0.5            # 将图像随机缩放阈量50%
)

3.断点续训,存取模型

(1)读取模型:model.load_weights(路径文件名)

checkpoint_save_path = "./mnist.ckpt"				# 定义存放模型的路径和文件名
if os.path.exists(checkpoint_save_path + '.index'):	# 判断是否有索引表 因为生成ckpt文件时,会同步生成索引表
	print('--------load the model---------')
	model.load_weights(checkpoint_save_path)

(2)保存模型:使用回调函数

# 1.设置保存方法
cp_callback = tf.keras.callbacks.ModelCheckpoint(
	filepath=路径文件名,
	save_weights_only=True/False 		# 是否只保留模型参数
	save_best_only=True/False# 是否只保留最有结果
	
# 2.训练时加入callbacks选项,记录到history中
history = model.fit(...,callbacks=[cp_callback])

4.参数提取,把参数存入文本

(1)理解:将模型的参数保存在文本中。

(2)函数:model.trainable_variables可以返回模型中可训练的参数,使用print函数打印出来。

但是,直接print中间很多数据会被省略号代替,所以要设置print输出格式。

np.set_printoptions(threshold=超出多少省略显示)

例子:

# 1.设置print格式
import numpy as np
np.set_printoptions(threshold=np.inf) 		# np.inf表示无限大,打印所有内容

# 2.打印参数
print(model.trainable_variables)

# 3.将参数写入文本
file = open('./weights.txt', 'w')
for v in model.trainable_variables:
	file.write(str(v.name) + '\n')
	file.write(str(v.shape) + '\n')
	file.write(str(v.numpy()) + '\n')
file.close()

5.acc/loss可视化,查看训练效果

(1)说明:

history = model.fit()。其实,在执行训练过程中,同步记录了
训练集loss(loss)、
测试集loss(val_loss)、
训练集准确率(sparse_categorical_accuracy)、
测试集准确率(val_sparse_categorical_accuracy)。

可以使用history.history[]提取出来。

(2)方法:

# 提取acc和loss
acc = history.history['sparse_categorical_accuracy']
val_acc = history.history['val_sparse_categorical_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']

# 绘制acc和loss曲线
plt.subplot(1, 2, 1)
plt.plot(acc, label='Training Accuracy')
plt.plot(val_acc, label='Validation Accuracy')
plt.title('Training and Validation Accuracy')
plt.legend()

plt.subplot(1, 2, 2)
plt.plot(loss, label='Training Loss')
plt.plot(val_loss, label='Validation Loss')
plt.title('Training and Validation Loss')
plt.legend()
plt.show()

6.应用程序,给图识物

(1)说明:编写一个前向传播算法,使用训练好的模型,将输入图片识别出来。

(2)函数:predict(输入特征,batch_size=整数),可以返回前向传播的计算结果。

(3)程序

# 1.复现模型(前向传播)
model = tf.keras.models.Sequential([
	tf.keras.layers.Flatten(),
	tf.keras.layers.Dense(128,activation='relu'),
	tf.keras.layers.Dense(10,activation='softmax')
])

# 2.加载参数
model.load_weights(model_save_path)

# 3.数据预处理

# 4.预测结果
result = model.predict(x_predict)

完整代码:(希望自己能背过)

代码1—训练模型

# 1.导入一些模块
import tensorflow as tf
from PIL import Image                   # 用于打开一张图片
import os                               # 路径
from matplotlib import pyplot as plt    # 绘图
from tensorflow.keras.preprocessing.image import ImageDataGenerator     # 数据增强
import numpy as np                      # 用于数据格式转换

# 2.路径
train_path = './mnist_image_label/mnist_train_jpg_60000/'       # 训练集图片路径
train_txt = './mnist_image_label/mnist_train_jpg_60000.txt'     # 训练集标签文件
x_train_savepath = './mnist_image_label/mnist_x_train.npy'      # 训练集输入特征存储文件
y_train_savepath = './mnist_image_label/mnist_y_train.npy'      # 训练集标签存储文件

test_path = './mnist_image_label/mnist_test_jpg_10000/'         # 测试集图片路径
test_txt = './mnist_image_label/mnist_test_jpg_10000.txt'       # 测试集标签文件
x_test_savepath = './mnist_image_label/mnist_x_test.npy'        # 测试集输入特征存储文件
y_test_savepath = './mnist_image_label/mnist_y_test.npy'        # 测试集标签存储文件

# 3.制作数据集的函数
def generateds(path, txt):          # 图片路径,标签文件
    f = open(txt, 'r')              # 以只读的形式打开txt
    contents = f.readlines()        # 读取文件中所有的行,每行为一个单位
    f.close()
    x, y_ = [], []
    for content in contents:                # 逐行读出
        value = content.split()             # 以空格分开
        img_path = path + value[0]
        img = Image.open(img_path)
        img = np.array(img.convert('L'))    # 图片变为8位宽度的灰度值
        img = img / 255.                    # 数据归一化
        x.append(img)
        y_.append(value[1])
        print('load:' + content)

    x = np.array(x)
    y_ = np.array(y_)
    y_ = y_.astype(np.int64)
    return x, y_


# 4.加载数据
if os.path.exists(x_train_savepath) and os.path.exists(y_train_savepath) and os.path.exists(
    x_test_savepath) and os.path.exists(y_test_savepath):   # 判断x_train,y_train,x_test,y_test是否存在
    print("----------------Load Datasets-------------")
    x_train_save = np.load(x_train_savepath)
    y_train = np.load(y_train_savepath)
    x_test_save = np.load(x_test_savepath)
    y_test = np.load(y_test_savepath)
    x_train = np.reshape(x_train_save, (len(x_train_save), 28, 28))
    x_test = np.reshape(x_test_save, (len(x_test_save), 28, 28))

else:   # 不存在,则调用generateds()函数制作数据集
    print('----------------Generate Datasets--------------')
    x_train, y_train = generateds(train_path, train_txt)
    x_test, y_test = generateds(test_path, test_txt)

    print('----------------Save Datasets------------------')
    x_train_save = np.reshape(x_train, (len(x_train), -1))
    x_test_save = np.reshape(x_test, (len(x_test), -1))
    np.save(x_train_savepath, x_train_save)
    np.save(y_train_savepath, y_train)
    np.save(x_test_savepath, x_test_save)
    np.save(y_test_savepath, y_test)

# 5.数据增强
x_train = x_train.reshape(x_train.shape[0], 28, 28, 1)
image_gen_train = ImageDataGenerator(
    rescale=1. / 1.,  # 如果是图像,分母为255,可以归一化到0-1
    rotation_range=45,  # 随机45度旋转
    width_shift_range=.15,   # 宽度偏移
    height_shift_range=.15,  # 高度偏移
    horizontal_flip=True,    # 水平翻转
    zoom_range=0.5  # 将图像随机缩放阈量50%
)
image_gen_train.fit(x_train)

# 6.搭建网络
model = tf.keras.models.Sequential([
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(10, activation='softmax')
])

# 7.配置参数
model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),
              metrics=['sparse_categorical_accuracy'])

# 8.设置调用和保存模型
# 调用模型
checkpoint_save_path = "./checkpoint/mnist.ckpt"
if os.path.exists(checkpoint_save_path + '.index'):
    print("--------------load model--------------")
    model.load_weights(checkpoint_save_path)
# 保存模型
cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_save_path,
                                                 save_weights_only=True,
                                                 save_best_only=True)

# 9.训练
history = model.fit(image_gen_train.flow(x_train, y_train, batch_size=32),
                    epochs=5, validation_data=(x_test, y_test), validation_freq=1,
                    callbacks=[cp_callback])
# 提取acc和loss
acc = history.history['sparse_categorical_accuracy']
val_acc = history.history['val_sparse_categorical_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']

# 10.模型参数
# 打印网络参数
model.summary()
# 保存训练好的模型参数
np.set_printoptions(threshold=np.inf)
print(model.trainable_variables)
file = open('./weights.txt', 'w')
for v in model.trainable_variables:
    file.write(str(v.name) + '\n')
    file.write(str(v.shape) + '\n')
    file.write(str(v.numpy()) + '\n')
file.close()

# 11.绘制acc和loss曲线
plt.subplot(1, 2, 1)
plt.plot(acc, label='Training Accuracy')
plt.plot(val_acc, label='Validation Accuracy')
plt.title('Training and Validation Accuracy')
plt.legend()

plt.subplot(1, 2, 2)
plt.plot(loss, label='Training Loss')
plt.plot(val_loss, label='Validation Loss')
plt.title('Training and Validation Loss')
plt.legend()
plt.show()

代码2:使用训练好的模型,给图出结果

import tensorflow as tf
import numpy as np
from PIL import Image

# 模型参数存储的路径
model_save_path = './checkpoint/mnist.ckpt'

# 1.复现模型(前向传播)
model = tf.keras.models.Sequential([
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(128, activation='relu'),
    tf.keras.layers.Dense(10, activation='softmax')
])

# 2.加载参数
model.load_weights(model_save_path)

# 3.数据预处理
preNum = int(input("要执行多少次图像识别任务:"))
for i in range(preNum):
    image_path = input("请输入图像路径:\n")
    img = Image.open(image_path)
    img = img.resize((28, 28), Image.ANTIALIAS)     # resize成28*28的标准尺寸
    img_arr = np.array(img.convert('L'))            # 转换为灰度图---和训练集图片一致

    ###  方法1
    # 训练集图片是黑底白字,输入的图片是白底黑字
    # 所以,要让每个像素点等于255减去当前值,相当于颜色取反
    # img_arr = 255 - img_arr

    ### 方法2
    # 让输入图片变为只有黑色和白色的高对比度图片,滤去了图片噪声,图片更干净
    for i in range(28):
        for j in range(28):
            if img_arr[i][j] < 200:             # 选择合理的阈值效果会更好
                img_arr[i][j] = 255
            else:
                img_arr[i][j] = 0

    img_arr = img_arr / 255.0                    # 图片归一化
    # 神经网络训练都是batch送入网络的,所以在img_array的前面添加一个维度
    # 28*28的二位数据--->1*28*28的三维数据
    x_predict = img_arr[tf.newaxis, ...]

    # 4.预测结果
    result = model.predict(x_predict)
    pred = tf.argmax(result, axis=1)
    print('识别结果是:%d' % pred.numpy())

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