《人工智能实践:Tensorflow笔记》听课笔记23_6.2制作数据集

附:课程链接

第六讲.全连接网络实践
6.2制作数据集

由于个人使用Win7系统,并未完全按照课程所讲,以下记录的也基本是我的结合课程做的Windows系统+PyCharm操作。且本人有python基础,故一些操作可能简略。并未完全按照网课。

记住编写代码时,除注释内容外,字符均使用英文格式。

本节目标
1、实现断点续训
2、输入真实图片,输出预测结果
3、制作数据集,实现特定应用

三、制作数据集,实现特定应用
制作数据集可以使用二进制文件tfrecords来保存对图片的序列化。
在这里插入图片描述
用tf.train.Example协议来存储训练数据。
训练数据的特征用键值对表示,如:
在这里插入图片描述
即:“原始图片:图片的值”、“标签:标签的值”。值可以是字符串、实数列表、整数列表。

用SerializeToString()把数据序列化成字符串存储。

生成tfrecords文件,具体语法:

writer = tf.python_io.TFRecordWriter(tfRecordName)  #新建一个writer,tfRecordName的位置要告知生成的文件在哪里、叫什么名
for循环遍历每张图和标签:
		"""
            把每张图片和标签用tf.train.Example中的feature封装到example中,在tf.feature.Feature中特征会以字典的形式给出,
            img_raw要放入二进制图片,labels放入这张图片所对应的标签
        """
        example = tf.train.Example(features = tf.train.Feature(feature={
            'img_raw':tf.train.Feature(bytes_list=tf.train.BytesList(value=[img_raw])),
            'label':tf.train.Feature(int64_list=tf.train.Int64List(value=labels))
        }))
        writer.write(example.SerialToString())  #把example进行序列化
writer.close()

解析tfrecords文件,具体语法:

filename_queue = tf.train.string_input_producer([tfRecord_path])    #建立文件对列名,
    #tfRecord_path需告知tfrecords文件放到何处,包括路径和文件名
    reader = tf.TFRecordReader()    #新建reader
    _,serialized_example = reader.read(filename_queue)  #读出来的每一个样本保存在serialized_example中
    """
        进行解序列化
    """
    features = tf.parse_single_example(serialized_example,
                                       features={
                                           'label':tf.FixedLenFeature([10],tf.int64),
                                           'img_raw':tf.FixedLenFeature([],tf.string)
                                       })
    img = tf.decode_raw(features['img_raw'],tf.uint8)   #从tfrecords文件中恢复img_raw到img
    img.set_shape([784])    #把img的形状变成1行784列,也就是包含784个元素的一维数组
    img = tf.cast(img,tf.float32) * (1./255)    #把img的每个元素变为浮点数,并且在0-1之间
    label = tf.cast(features['label'],tf.float32)   #把label的每个数也变成浮点数,这样img和label就满足上节课模型的输入要求了

与上节课的程序相比,本节课新增了一个mnist_generateds.py,里面包含了tfrecords文件的生成和标签、图片的批获取。
在这里插入图片描述
在反向传播和测试程序中修改了图片和标签获取的接口、前向传播和应用程序与上节课完全相同。

首先让我们来看mnist_generateds.py文件:

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

image_train_path = './mnist_work/t10k-images-idx3-ubyte.gz/'
label_train_path = './mnist_work/t10k-labels-idx1-ubyte.gz/'
tfRecord_train = './mnist_data/mnist_train.tfrecords/'
image_test_path = './mnist_work/train-images-idx3-ubyte.gz/'
label_test_path = './mnist_work/train-labels-idx1-ubyte.gz/'
tfRecord_test = './mnist_data/mnist_test.tfrecords/'
data_path = './mnist_data'
resize_height = 28
resize_width = 28


"""
    生成一个tfRecord文件
"""
def write_tfRecord(tfRecordName,image_path,label_path): #write_tfRecord接收到存放tfrecords文件的路径和文件名(tfrecordname)
    #还接收到图像路径(image_path)和标签文件(label_path)
    writer = tf.python_io.TFRecordWriter(tfRecordName)  #新建一个writer,tfRecordName的位置要告知生成的文件在哪里、叫什么名
    num_pic = 0 #为了显示进度,新建一个计数器num_pic
    f = open(label_path,'r')    #以“读”的形式打开标签文件,标签文件是一个txt文件。txt文件每行由图片名和标签组成,中间由空格隔开
    contents = f.readlines()    #用readlines()读取整个文件的内容赋给contents
    f.close()   #关闭文件
    for content in contents:    #for循环遍历每张图和标签
        value = content.split() #用空格分隔每行的内容,分隔后组成列表value
        image_path = image_path + value[0]  #图片文件的路径就变成了image_path接图片名value[0]
        img = Image.open(image_path)    #打开文件
        img_raw = img.tobytes() #将img转换成二进制数据
        labels = [0] * 10   #把labels的每个元素赋值为0
        labels[int(value[1])] = 1   #把labels所对应的标签位赋值为1

        """
            创建一个example
            把每张图片和标签用tf.train.Example中的feature封装到example中,在tf.feature.Feature中特征会以字典的形式给出,
            img_raw要放入二进制图片,labels放入这张图片所对应的标签
        """
        example = tf.train.Example(features = tf.train.Feature(feature={
            'img_raw':tf.train.Feature(bytes_list=tf.train.BytesList(value=[img_raw])),
            'label':tf.train.Feature(int64_list=tf.train.Int64List(value=labels))
        }))
        writer.write(example.SerialToString())  #用writer.write把example进行序列化
        num_pic += 1    #每保存一张图片计数器+1
        print("the number of picture:",num_pic) #打印出进度提示
    writer.close()  #当for循环把所有图片和标签都完成序列化后,关闭writer
    print("write tfrecord successful")  #打印提示

def generate_tfRecord():
    isExists = os.path.exists(data_path)    #判断保存路径是否存在
    if not isExists:    #如果不存在
        os.makedirs(data_path)  #用os.makedirs新建这个路径
        print("The directory was created successfully") #打印出提示
    else:
        print("directory already exists")   #否则告知已经存在目录

    #用自定义函数write_tfRecord()把训练集中的图片(image_train_path)和标签(label_train_path)生成名叫tfRecord_train的tfrecords文件
    write_tfRecord(tfRecord_train,image_train_path,label_train_path)
    #用自定义函数write_tfRecord()把测试集中的图片(image_train_path)和标签(label_train_path)生成名叫tfRecord_train的tfrecords文件
    write_tfRecord(tfRecord_test,image_test_path,label_test_path)

"""
    从tfrecords文件解析出图片和标签
"""
def read_tfRecord(tfRecord_path):   #read_tdrecord接收到待读取的tfrecords文件
    filename_queue = tf.train.string_input_producer([tfRecord_path])
    #用tf.train.string_input_producer建立文件名对列,
    #tfRecord_path需告知tfrecords文件放到何处,包括路径和文件名

    reader = tf.TFRecordReader()    #新建reader
    _,serialized_example = reader.read(filename_queue)  #读出来的每一个样本保存在serialized_example中
    """
        进行解序列化
        标签和图片的键名应该和制作tfrecords的键名相同
        标签要给出是几分类,例如我们的手写数字是十分类,则写10:tf.FixedLenFeature([10],tf.int64)
    """
    features = tf.parse_single_example(serialized_example,
                                       features={
                                           'label':tf.FixedLenFeature([10],tf.int64),
                                           'img_raw':tf.FixedLenFeature([],tf.string)
                                       })
    img = tf.decode_raw(features['img_raw'],tf.uint8)   #decode_raw()函数img_raw字符串转换到无符号8位字符串整形
    img.set_shape([784])    #把img的形状变成1行784列,也就是包含784个元素的一维数组
    img = tf.cast(img,tf.float32) * (1./255)    #把img的每个元素变为浮点数,并且在0-1之间
    label = tf.cast(features['label'],tf.float32)   #把label的每个数也变成浮点数,这样img和label就满足上节课模型的输入要求了
    return img,label    #返回图片和标签

"""
    提或取tfrecord文件的函数
    能够提或取训练集/测试集中的图片和标签,如果读取训练集,参数写True,测试集写False
    还要写出一次读取多少组num
"""

def get_tfrecord(num,isTrain=True):
    if isTrain:
        tfRecord_path = tfRecord_train
    else:
        tfRecord_path = tfRecord_test
    img,label = read_tfRecord(tfRecord_path)    #读取过程用read_tfrecord实现。

    """
    图片和标签分别是img、label,tf.train.shuffle_batch()会从总样本数顺序取出capacity组数据,打乱顺序每次输出batch_size组
    如果capacity少于min_after_dequeue,会从总样本中取数据填满capacity。整个过程使用了两个线程(num_threads=2)
    """
    img_batch,label_batch = tf.train.shuffle_batch([img,label],
                                                   batch_size=num,
                                                   num_threads=2,
                                                   capacity=1000,
                                                   min_after_dequeue=700)
    return img_batch,label_batch    #这个时候返回的图片和标签就是随机抽取出的batch_size组数据了

def main(): #从main函数看进去
    generate_tfRecord() #执行此函数

if __name__ == '__main__':
    main()

【备注,有人可能会对这段代码有疑惑,应该怎么设置呢?

image_train_path = './mnist_work/t10k-images-idx3-ubyte.gz/'
label_train_path = './mnist_work/t10k-labels-idx1-ubyte.gz/'
tfRecord_train = './mnist_data/mnist_train.tfrecords/'
image_test_path = './mnist_work/train-images-idx3-ubyte.gz/'
label_test_path = './mnist_work/train-labels-idx1-ubyte.gz/'
tfRecord_test = './mnist_data/mnist_test.tfrecords/'
data_path = './mnist_data'

让我们来查阅相关资料,发现:
在这里插入图片描述
截图来源:【代码】详解IDX-Ubyte文件格式 及 python读取
其他几个文件路径的设置大家可以根据自己的需求设置了】

我们来具体看下代码,在反向传播中,代码与上节课的变动:
①由于在梯度下降学习率中需要计算多少轮更新一次学习率(train.num_examples / BATCH_SIZE)即总样本数/BATCH_SIZE,以前用mnist.train.num_examples可以得到总样本数,现在我们必须手动给出总样本数是60000(即下图第15行和第31行发生了改变):
在这里插入图片描述
②以前用xs, ys = mnist.train.next_batch(BATCH_SIZE) 可以直接图片和标签喂给网络,现在要用自己写的get_tfrecord替换:img_batch , label_batch = mnist_generateds.get_tfrecord(BATCH_SIZE,isTrain=True),一次批获取BATCH组,因为从训练集中获取,所以isTrain参数为True。
③因为涉及到计算,故采用sess.run: xs, ys = sess.run([img_batch,label_batch]),为了提高图片和标签的批获取处理效率,调用了线程协调器,后又关闭线程协调器。
②③如图:
在这里插入图片描述
在测试的代码中更改的方法,和反向传播的很像:
需要手动给出测试的总样本数是10000:
在这里插入图片描述
以及其他类似改变:
在这里插入图片描述
执行相关代码看一下,当准确率达到95%以上,运行mnist_app.py。

运行mnist_app结果:
在这里插入图片描述
在这里插入图片描述
可以看到,仍有数字识别不准确。让我们来看看老师的解释:

如果测试集跑出的准确率很高、应用程序准确率上不去,要考虑图片噪声是否过大,从图片预处理进行优化,使优化后的输入图片尽量接近测试集中的图片,因为测试集和训练集是相对独立的,测试集跑出的准确率对模型是有意义的。

如果电脑运行这段代码非常慢,可以把每1000轮显示loss改为每200轮显示loss,这样显示的速度就会相对快一些。

以下我将把有改动的代码mnist_backward.py、mnist_test.py附上:

mnist_backward.py:

"""
    反向传播
"""
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import mnist_forward
import mnist_generateds
import os   #os模块

BATCH_SIZE = 200    #定义每轮喂入神经网络多少张图片
LEARNING_RATE_BASE = 0.1    #最开始的学习率
LEARNING_RATE_DECAY = 0.99  #学习率衰减率
REGULARIZER = 0.0001    #正则化系数
STEPS = 50000   #共训练多少轮
MOVING_AVERAGE_DECAY = 0.99 #滑动平均衰减率
MODEL_SAVE_PATH = "mnist_model" #模型的保存路径
#MODEL_SAVE_PATH = "./model/"
MODEL_NAME = "mnist_model"  #模型保存的文件名
train_num_examples = 60000

#对于反向传播而言,要训练网络参数
def backward(mnist):    #在backward函数中读入mnist
    x = tf.placeholder(tf.float32, [None, mnist_forward.INPUT_NODE])  #给x占位
    y_ = tf.placeholder(tf.float32, [None, mnist_forward.OUTPUT_NODE])    #给y_占位
    y = mnist_forward.forward(x, REGULARIZER)    #调用前向传播程序计算输出y

    global_step = tf.Variable(0,trainable=False)    #给轮数计数器赋初值,设定为不可训练

    ce = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(y_, 1))  # 实现softmax和交叉熵的协同使用
    cem = tf.reduce_mean(ce)
    loss = cem + tf.add_n(tf.get_collection('losses'))  #调用包含正则化的损失函数loss

    #定义指数衰减学习率
    learning_rate = tf.train.exponential_decay(
        LEARNING_RATE_BASE,
        global_step,
        train_num_examples / BATCH_SIZE,
        LEARNING_RATE_DECAY,
        staircase=True)

    #定义训练过程
    train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss,global_step=global_step)

    #定义滑动平均
    ema = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY, global_step)
    ema_op = ema.apply(tf.trainable_variables())
    with tf.control_dependencies([train_step, ema_op]):
        train_op = tf.no_op(name='train')

    #实例化saver
    saver = tf.train.Saver() #tf.compat.v1.train.Saver

    img_batch , label_batch = mnist_generateds.get_tfrecord(BATCH_SIZE,isTrain=True)

    #在with结构中初始化所有变量
    with tf.Session() as sess:
        init_op = tf.global_variables_initializer()
        sess.run(init_op)

        ckpt = tf.train.get_checkpoint_state(MODEL_SAVE_PATH)
        if ckpt and ckpt.model_checkpoint_path:
            saver.restore(sess, ckpt.model_checkpoint_path)

        """
            开启线程协调器
        """
        coord = tf.train.Coordinator()
        threads = tf.train.start_queue_runners(sess=sess, coord=coord)

        #在for循环中迭代STEPS轮
        for i in range(STEPS):
            xs, ys = sess.run([img_batch,label_batch])  #每次读入BATCH_SIZE组图片和标签
            _,loss_value,step = sess.run([train_op,loss,global_step],feed_dict={x:xs,y_:ys})    #喂入神经网络,执行相关过程
            if i % 1000 == 0:   #每1000轮打印loss值
                print("After %d training steps(s),loss on training batch is %g"%(step,loss_value))
                saver.save(sess,os.path.join(MODEL_SAVE_PATH,MODEL_NAME),global_step=global_step)   #保存模型到当前会话

        """
            关闭线程协调器
        """
        coord.request_stop()
        coord.join(threads)

def main():
    mnist = input_data.read_data_sets("mnist_work/", one_hot=True)
#mnist = input_data.read_data_sets("./data/", one_hot=True)
    backward(mnist)

if __name__ == '__main__':
    main()

mnist_test.py:

import time #为了延时,导入了time模块
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import mnist_forward
import mnist_backward
import mnist_generateds
TEST_INTERVAL_SECS = 5  #定义程序循环的间隔时间是5s
TEST_NUM = 10000

def test():
    with tf.Graph().as_default() as g:  #绘制计算图中的节点
        #给输入图像x和y_占位
        x = tf.placeholder(tf.float32, [None, mnist_forward.INPUT_NODE])
        y_ = tf.placeholder(tf.float32, [None, mnist_forward.OUTPUT_NODE])
        #用前向传播过程计算出y的值
        y = mnist_forward.forward(x, None)

        #实例化可还原滑动平均的saver,这样所有参数在会话中北加载时会被赋值为各自的滑动平均值
        ema = tf.train.ExponentialMovingAverage(mnist_backward.MOVING_AVERAGE_DECAY)
        ema_restore = ema.variables_to_restore()
        saver = tf.train.Saver(ema_restore)

        #计算正确率
        correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
        accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))

        img_batch,label_batch = mnist_generateds.get_tfrecord(TEST_NUM,isTrain=False)
        #用get_tfrecord()读取所有测试集10000张图片。由于从测试集中取数据,所以isTrain参数选择False

        while True:
            with tf.Session() as sess:
                #加载训练好的模型ckpt,也就是把滑动平均值赋给各个参数
                ckpt = tf.train.get_checkpoint_state(mnist_backward.MODEL_SAVE_PATH)
                #如果已有ckpt模型则恢复
                if ckpt and ckpt.model_checkpoint_path:
                    #恢复会话
                    saver.restore(sess,ckpt.model_checkpoint_path)
                    #恢复轮数
                    global_step = int(ckpt.model_checkpoint_path.split('/')[-1].split('-')[-1])

                    """
                        开启线程协调器
                    """
                    coord = tf.train.Coordinator()
                    threads = tf.train.start_queue_runners(sess=sess, coord=coord)
                    #执行批获取图片和标签
                    xs, ys = sess.run([img_batch, label_batch])

                    #计算准确率
                    accuracy_score = sess.run(accuracy,feed_dict = {x:mnist.test.images,y_:mnist.test.labels})
                    #打印提示
                    print("After %s training step(s),test accuracy = %g"%(global_step,accuracy_score))

                    """
                        关闭线程协调器
                    """
                    coord.request_stop()
                    coord.join(threads)

                #如果没有模型
                else:
                    print('No checkpoint file found')   #模型不存在提示
                    return

            time.sleep(TEST_INTERVAL_SECS)

def main():
    mnist = input_data.read_data_sets("mnist_work/", one_hot=True)
    test(mnist)

if __name__ == '__main__':
    main()

第六讲至此结束。

附:助教的Tensorflow笔记6

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值