如何零基础用tensorflow搭建基本的CNN框架 | 附训练断点续练、图像展示、参数保存模块

2021/5/16 10:25:38

本文主要是介绍如何零基础用tensorflow搭建基本的CNN框架 | 附训练断点续练、图像展示、参数保存模块,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

如何零基础用tensorflow搭建基本的CNN框架 | 附训练断点续练、图像展示、参数保存模块

在这里插入图片描述
嗨,我是error。

这次的笔记是关于tensorflow基本框架的搭建,零基础带你熟悉如何应用keras搭建自己的CNN模型,并训练自己的数据,实现深度学习。

代码主要参考来源自

【国家精品课程】北京大学人工智能实践-TensorFlow2.0

CIFAR10数据集介绍,并使用卷积神经网络训练图像分类模型


Keras的八股文构建方法

这篇文章主要是写给tensorflow零基础但深度学习对CNN结构有一定了解的朋友,故重点会放在详细介绍代码实现CNN结构的方法上面。

首先要了解的是keras最基本的八股文式构建法,即

首先是import各类的库,然后分train和test数据(可以直接使用keras官方的数据也可以使用自己准备的数据,下面会分别讲解)。构建model后compile最后fit就完成了整个训练,最后的summary可有可无,主要是打印网络结构。

下面老师给出了三个主要对象的参数文档说明。
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述


CNN模型的详细模块解说

首先说明下我的数据来源,来自CIFAR10数据集,照片都放在train文件夹内,在根目录下有trainlabels的csv表格标记着每一张图片的标签
在这里插入图片描述
在这里插入图片描述

根目录下面还有x_train和y_train的npy文件,每次运行代码时都检测是否存在这两个文件,若不存在,则从官网下载CIFAR10文件并保存,若存在则直接调用,不再重复下载。

根目录下的checkpoint文件夹存放着每次训练的参数,以便下次训练时沿用上次已经训练好的参数而不是重复计算,实现了断点续训。

import tensorflow as tf
from PIL import Image
import numpy as np
import os
import matplotlib.pyplot as plt
from tensorflow.keras.preprocessing.image import ImageDataGenerator

train_path = './train/'
train_csv = './trainLabels.csv'
x_train_savepath = './x_train.npy'
y_train_savepath = './y_train.npy'

在import完所需要的库后定义需要的路径以便后面传参时方便。

然后我们定义一个generateds的函数来把我们从csv表格标记的每一个图片的标签对应上就好了。

先定义两个空列表,分别是x和y,因为列表是有顺序的,只要我们放入列表的顺序和表格的顺序是一致,那么它们的标签就是对应匹配的。

def generateds(path, csv):
    f = open(csv, 'r')  # 以只读形式打开csv文件
    contents = f.readlines()[1:]  # 读取文件中除了第一行的所有行,因为第一行是id/labels的头
    f.close()  # 关闭csv文件
    x, y_ = [], []  # 建立空列表
    for content in contents:  # 逐行取出
        value = content.split(",")  # 以空格分开,图片路径为value[0] , 标签为value[1] , 存入列表
        img_path = path + value[0] + '.png'  # 拼出图片路径和文件名
        img = Image.open(img_path)  # 读入图片
        img = np.array(img.convert('L'))  # 图片变为8位宽灰度值的np.array格式
        img = img / 255.  # 数据归一化 (实现预处理)
        x.append(img)  # 归一化后的数据,贴到列表x
        y_.append(value[1])  # 标签贴到列表y_
        print('loading : ' + content)  # 打印状态提示

    x = np.array(x)  # 变为np.array格式
    y_ = np.array(y_)  # 变为np.array格式
    y_ = y_.astype(np.int64)  # 变为64位整型
    return x, y_  # 返回输入特征x,返回标签y_

下面这一个part就是实现防止重复处理CIFAR10数据,因为这里的图片都是32x32,所以在第7行reshape的时候就是32x32,如果不是的话要调整否则会报错无法继续运行,因为我们待会训练的时候是直接把train分割成训练集和测试集,不存在一个单独的测试集,所以我们就注释掉老师写的test部分的代码了。

if os.path.exists(x_train_savepath) and os.path.exists(y_train_savepath):
    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), 32, 32, 1))
    # x_test = np.reshape(x_test_save, (len(x_test_save), 28, 28))
else:
    print('-------------Generate Datasets-----------------')
    x_train, y_train = generateds(train_path, train_csv)
    # x_test, y_test = generateds(test_path, test_txt)

    print('-------------Save Datasets-----------------')
    x_train_save = np.reshape(x_train, (len(x_train), -1))
    #  = 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)

最后在正式训练之前,为了加强训练的rubust性,我们选择对数据进行一个预处理,代码如下。

image_gen_train = 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%
)
image_gen_train.fit(x_train)

关于ImageDataGenerator参数的文档说明如下:

在这里插入图片描述

下面就是模型的主要构建部分了,主要选择的是简单的卷积层+最大池化层+dropout的经典搭配模型,最后再更上几个全连接层。

model = tf.keras.Sequential()
##特征提取阶段
#第一层
model.add(tf.keras.layers.Conv2D(16,kernel_size=(3,3),padding='same',activation=tf.nn.relu,data_format='channels_last',input_shape=x_train.shape[1:]))  #卷积层,16个卷积核,大小(3,3),保持原图像大小,relu激活函数,输入形状(28,28,1)
model.add(tf.keras.layers.Conv2D(16,kernel_size=(3,3),padding='same',activation=tf.nn.relu))
model.add(tf.keras.layers.MaxPool2D(pool_size=(2,2)))   #池化层,最大值池化,卷积核(2,2)
model.add(tf.keras.layers.Dropout(0.2))
#第二层
model.add(tf.keras.layers.Conv2D(32,kernel_size=(3,3),padding='same',activation=tf.nn.relu))
model.add(tf.keras.layers.Conv2D(32,kernel_size=(3,3),padding='same',activation=tf.nn.relu))
model.add(tf.keras.layers.MaxPool2D(pool_size=(2,2)))
model.add(tf.keras.layers.Dropout(0.2))
##分类识别阶段
#第三层
model.add(tf.keras.layers.Flatten())    #改变输入形状
#第四层
model.add(tf.keras.layers.Dense(128,activation='relu'))     #全连接网络层,128个神经元,relu激活函数
model.add(tf.keras.layers.Dense(10,activation='softmax'))   #输出层,10个节点

然后直接编译我们写好的模型,这里我们选择adam优化器。

model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),
              metrics=['sparse_categorical_accuracy'])

为了实现下一次训练的时候参数仍调用上次的最优参数,而不是重新重复训练,也就是实现断点续训,我们采用参数保存的方法,保存再checkpoint文件夹内。

checkpoint_save_path = "./checkpoint/ZYB.ckpt"
if os.path.exists(checkpoint_save_path + '.index'):
    print('-------------load the 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)

最后是代码的可视化部分,实现了最后打印出来一个loss和acc的表格方便观察。

history = model.fit(x_train, y_train, batch_size=640, epochs=5, validation_split=0.2, validation_freq=1, callbacks=[cp_callback])
print(history.history)
loss = history.history['loss']          #训练集损失
val_loss = history.history['val_loss']  #测试集损失
acc = history.history['sparse_categorical_accuracy']            #训练集准确率
val_acc = history.history['val_sparse_categorical_accuracy']    #测试集准确率

plt.figure(figsize=(10,3))

plt.subplot(121)
plt.plot(loss,color='b',label='train')
plt.plot(val_loss,color='r',label='test')
plt.ylabel('loss')
plt.legend()

plt.subplot(122)
plt.plot(acc,color='b',label='train')
plt.plot(val_acc,color='r',label='test')
plt.ylabel('Accuracy')
plt.legend()
plt.show()

model.summary()

实际运行情况

最后训练的结果图示
在这里插入图片描述
模型结构
在这里插入图片描述
训练过程
在这里插入图片描述


完整代码

import tensorflow as tf
from PIL import Image
import numpy as np
import os
import matplotlib.pyplot as plt
from tensorflow.keras.preprocessing.image import ImageDataGenerator

train_path = './train/'
train_csv = './trainLabels.csv'
x_train_savepath = './x_train.npy'
y_train_savepath = './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'


def generateds(path, csv):
    f = open(csv, 'r')  # 以只读形式打开txt文件
    contents = f.readlines()[1:]  # 读取文件中所有行
    f.close()  # 关闭txt文件
    x, y_ = [], []  # 建立空列表
    for content in contents:  # 逐行取出
        value = content.split(",")  # 以空格分开,图片路径为value[0] , 标签为value[1] , 存入列表
        img_path = path + value[0] + '.png'  # 拼出图片路径和文件名
        img = Image.open(img_path)  # 读入图片
        img = np.array(img.convert('L'))  # 图片变为8位宽灰度值的np.array格式
        img = img / 255.  # 数据归一化 (实现预处理)
        x.append(img)  # 归一化后的数据,贴到列表x
        y_.append(value[1])  # 标签贴到列表y_
        print('loading : ' + content)  # 打印状态提示

    x = np.array(x)  # 变为np.array格式
    y_ = np.array(y_)  # 变为np.array格式
    y_ = y_.astype(np.int64)  # 变为64位整型
    return x, y_  # 返回输入特征x,返回标签y_


if os.path.exists(x_train_savepath) and os.path.exists(y_train_savepath):
    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), 32, 32, 1))
    # x_test = np.reshape(x_test_save, (len(x_test_save), 28, 28))
else:
    print('-------------Generate Datasets-----------------')
    x_train, y_train = generateds(train_path, train_csv)
    # x_test, y_test = generateds(test_path, test_txt)

    print('-------------Save Datasets-----------------')
    x_train_save = np.reshape(x_train, (len(x_train), -1))
    #  = 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)

image_gen_train = 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%
)
image_gen_train.fit(x_train)

model = tf.keras.Sequential()
##特征提取阶段
#第一层
model.add(tf.keras.layers.Conv2D(16,kernel_size=(3,3),padding='same',activation=tf.nn.relu,data_format='channels_last',input_shape=x_train.shape[1:]))  #卷积层,16个卷积核,大小(3,3),保持原图像大小,relu激活函数,输入形状(28,28,1)
model.add(tf.keras.layers.Conv2D(16,kernel_size=(3,3),padding='same',activation=tf.nn.relu))
model.add(tf.keras.layers.MaxPool2D(pool_size=(2,2)))   #池化层,最大值池化,卷积核(2,2)
model.add(tf.keras.layers.Dropout(0.2))
#第二层
model.add(tf.keras.layers.Conv2D(32,kernel_size=(3,3),padding='same',activation=tf.nn.relu))
model.add(tf.keras.layers.Conv2D(32,kernel_size=(3,3),padding='same',activation=tf.nn.relu))
model.add(tf.keras.layers.MaxPool2D(pool_size=(2,2)))
model.add(tf.keras.layers.Dropout(0.2))
##分类识别阶段
#第三层
model.add(tf.keras.layers.Flatten())    #改变输入形状
#第四层
model.add(tf.keras.layers.Dense(128,activation='relu'))     #全连接网络层,128个神经元,relu激活函数
model.add(tf.keras.layers.Dense(10,activation='softmax'))   #输出层,10个节点

model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),
              metrics=['sparse_categorical_accuracy'])

checkpoint_save_path = "./checkpoint/ZYB.ckpt"
if os.path.exists(checkpoint_save_path + '.index'):
    print('-------------load the 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)

history = model.fit(x_train, y_train, batch_size=640, epochs=5, validation_split=0.2, validation_freq=1, callbacks=[cp_callback])
print(history.history)
loss = history.history['loss']          #训练集损失
val_loss = history.history['val_loss']  #测试集损失
acc = history.history['sparse_categorical_accuracy']            #训练集准确率
val_acc = history.history['val_sparse_categorical_accuracy']    #测试集准确率

plt.figure(figsize=(10,3))

plt.subplot(121)
plt.plot(loss,color='b',label='train')
plt.plot(val_loss,color='r',label='test')
plt.ylabel('loss')
plt.legend()

plt.subplot(122)
plt.plot(acc,color='b',label='train')
plt.plot(val_acc,color='r',label='test')
plt.ylabel('Accuracy')
plt.legend()
plt.show()

model.summary()

完整模型打包下载

照顾到部分朋友是完全零基础学习tenserflow,我这里将我的文件夹压缩打包,只要你配置好了python环境,直接解压就可以运行,同时还可以自己调整超参数多次训练寻找最优模型。因为数据庞大,我只能打包上传百度云,为防止链接经常挂的问题,关注微信公众号【error13】,后台回复【CIFAR】免费获得链接。
在这里插入图片描述

在这里插入图片描述



这篇关于如何零基础用tensorflow搭建基本的CNN框架 | 附训练断点续练、图像展示、参数保存模块的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程