TensorFlow制作自己的数据集,并用神经网络来训练自己制作的数据集【上】

2023-11-13

参考文章:
将数据导入TensorFlow
使用tensorflow训练自己的数据集(一)——制作数据集
用Tensorflow处理自己的数据:制作自己的TFRecords数据集

在用tensorflow来进行网络模型的训练时,我们总是需要先输入数据,这样才能对网络模型进行训练。这就涉及将数据导入TensorFlow的问题了
总共有四种方法将数据导入到TensorFlow中:

  1. 使用数据集API,这是将数据集导入tensorflow最常用的办法
  2. Feeding,python的代码在运行每个步骤时提供数据
  3. 从文件读取,输入管道从tensorflow图的开始处读取文件中的数据
  4. 预加载数据,tensorflow图中的常量或变量保存所有数据(对于小型数据集)

在这里我们使用第三种方法,将自己的数据集先写入TFRecord文件,然后从TFRecord文件将数据导入TensorFlow。

【1】首先编写一个小程序来获取自己的数据,将它放在一个示例协议缓冲区中,将缓冲区序列化为一个字符串,然后使用tf.python_io.TFRecordWriter将该字符串写入TFRecords文件。下面直接上代码,根据代码注释很容易理解:

def create_train_record():
    """创建训练集tfrecord"""
    writer = tf.python_io.TFRecordWriter(train_record_path)     # 创建一个writer
    for index, name in enumerate(classes):       #生成由二元组构成的一个迭代对象,每个二元组由可迭代参数的索引号及其对应的元素组成
        class_path = cwd + "\\" + name + "\\"
        l = int(len(os.listdir(class_path)) * 0.6)      # 取前60%创建训练集
        for img_name in os.listdir(class_path)[:l]:     
            img_path = class_path + img_name
            img = Image.open(img_path)
            img = img.resize((128, 128))                # resize图片大小
            img_raw = img.tobytes()                     # 将图片转化为原生bytes即二进制格式
            example = tf.train.Example(                 # 封装到示例协议缓冲区Example中
                features=tf.train.Features(feature={
                    "label":_int64list(index),          # label必须为整数类型属性
                    'img_raw':_byteslist(img_raw)       # 图片必须为二进制属性
                }))
            writer.write(example.SerializeToString())   #序列化为字符串,将字符串写入TFRecords文件
    writer.close()                                      # 关闭writer
def create_test_record():
    """创建测试集tfrecord"""
    writer = tf.python_io.TFRecordWriter(test_record_path)
    for index, name in enumerate(classes):
        class_path = cwd + "\\" + name + "\\"
        l = int(len(os.listdir(class_path)) * 0.6)
        h = int(len(os.listdir(class_path)) * 0.9)
        for img_name in os.listdir(class_path)[l:h]:     # 中间30%作为测试集
            img_path = class_path + img_name
            img = Image.open(img_path)
            img = img.resize((128, 128))
            img_raw = img.tobytes()  # 将图片转化为原生bytes
            # print(index,img_raw)
            example = tf.train.Example(
                features=tf.train.Features(feature={
                    "label":_int64list(index),
                    'img_raw':_byteslist(img_raw)
                }))
            writer.write(example.SerializeToString())
    writer.close()
def create_val_record():
    """创建验证集tfrecord"""
    writer = tf.python_io.TFRecordWriter(val_record_path)
    for index, name in enumerate(classes):
        class_path = cwd + "\\" + name + "\\"
        h = int(len(os.listdir(class_path)) * 0.9)
        for img_name in os.listdir(class_path)[h:]:     # 剩余10%作为验证集
            img_path = class_path + img_name
            img = Image.open(img_path)
            img = img.resize((128, 128))
            img_raw = img.tobytes()  # 将图片转化为原生bytes
            # print(index,img_raw)
            example = tf.train.Example(
                features=tf.train.Features(feature={
                    "label":_int64list(index),
                    'img_raw':_byteslist(img_raw)
                }))
            writer.write(example.SerializeToString())
    writer.close()

我们将数据集分为训练集+测试集+验证集三部分,占总数据集的比例分别为:60%、30%、10%。根据自己的需要可以自己任意比例的分配自己的数据集,很多时候我们可能只需要将数据集分为训练集+测试集。

【2】再就是读取TFRecords文件,使用tf.TFRecordReader与tf.parse_single_example解码器。tf.parse_single_example操作将示例协议缓冲区解码为张量。

def read_record(filename):
    """读取tfrecord"""
    filename_queue = tf.train.string_input_producer([filename])     # 创建文件队列
    reader = tf.TFRecordReader()                                    # 创建reader
    _, serialized_example = reader.read(filename_queue)
    features = tf.parse_single_example(
        serialized_example,
        features={
            'label': tf.FixedLenFeature([], tf.int64),
            'img_raw': tf.FixedLenFeature([], tf.string)
        }
    )
    label = features['label']
    img = features['img_raw']
    img = tf.decode_raw(img, tf.uint8)   #tf.decode_raw函数的意思是将原来编码为字符串类型的变量重新变回来
    img = tf.reshape(img, [128, 128, 3])
#    img = tf.cast(img, tf.float32) * (1. / 255) - 0.5       # 归一化   归一化之后图片会变成那种看不清的图片,未归一化的话则是完好的图片
    label = tf.cast(label, tf.int32)  #这个函数主要用于数据类型的转变,不会改变原始数据的值还有形状的,
    return img, label

【3】在管道的最后,使用一个队列来作为训练,评估或判断一起批处理示例。为此,在这里使用一个随机化的示例顺序的队列:tf.train.shuffle_batch。

def get_batch_record(filename,batch_size):
    """获取batch"""
    image,label = read_record(filename)
    image_batch,label_batch = tf.train.shuffle_batch([image,label],     # 随机抽取batch size个image、label
                                                     batch_size=batch_size,
                                                     capacity=2000,
                                                     min_after_dequeue=1000)
    return image_batch,label_batch#tf.reshape(label_batch,[batch_size])

【4】调用以上函数,制作数据集并用自己制作的数据集进行训练

create_train_record() 
create_test_record()
create_val_record()
image_batch,label_batch = get_batch_record(train_record_path,32)
init = tf.global_variables_initializer()

with tf.Session() as sess:
    sess.run(init)
    coord = tf.train.Coordinator() #1
    threads = tf.train.start_queue_runners(sess=sess,coord=coord) #2
    for i in range(1):
        image,label = sess.run([image_batch,label_batch])
        print(image.shape,1)
    coord.request_stop() #3
    coord.join(threads) #4

【5】整合以上的代码,写入dateset.py模块

#coding="utf-8"
import os
import tensorflow as tf
from PIL import Image
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
# 源数据地址
cwd = os.getcwd() + "\\train"
# 生成record路径及文件名
train_record_path = os.getcwd() + "\\train.tfrecords"
test_record_path = os.getcwd() + "\\test.tfrecords"
val_record_path = os.getcwd() + "\\val.tfrecords"
# 分类 根据自己的需求进行分类
classes = {'0-gjfd','1-gjqzm','2-gjxbs','3-cmj','4-gjsjj','5-hlj','6-gjhyj','7-hdjqc','8-dlfj','9-hcfs','10-gjdsy','11-jxsy','12-mjdsy'
,'13-xwye','14-kyye','15-gjqye','16-hjyc','17-jecy','18-xxjy'}
def _byteslist(value):
    """二进制属性"""
    return tf.train.Feature(bytes_list = tf.train.BytesList(value = [value]))

def _int64list(value):
    """整数属性"""
    return tf.train.Feature(int64_list = tf.train.Int64List(value = [value]))

def create_train_record():
    """创建训练集tfrecord"""
    writer = tf.python_io.TFRecordWriter(train_record_path)     # 创建一个writer
    for index, name in enumerate(classes):       #生成由二元组构成的一个迭代对象,每个二元组由可迭代参数的索引号及其对应的元素组成
        class_path = cwd + "\\" + name + "\\"
        l = int(len(os.listdir(class_path)) * 0.6)      # 取前60%创建训练集
        for img_name in os.listdir(class_path)[:l]:     
            img_path = class_path + img_name
            img = Image.open(img_path)
            img = img.resize((128, 128))                # resize图片大小
            img_raw = img.tobytes()                     # 将图片转化为原生bytes即二进制格式
            example = tf.train.Example(                 # 封装到示例协议缓冲区Example中
                features=tf.train.Features(feature={
                    "label":_int64list(index),          # label必须为整数类型属性
                    'img_raw':_byteslist(img_raw)       # 图片必须为二进制属性
                }))
            writer.write(example.SerializeToString())   #序列化为字符串,将字符串写入TFRecords文件
    writer.close()                                      # 关闭writer

def create_test_record():
    """创建测试tfrecord"""
    writer = tf.python_io.TFRecordWriter(test_record_path)
    for index, name in enumerate(classes):
        class_path = cwd + "\\" + name + "\\"
        l = int(len(os.listdir(class_path)) * 0.6)
        h = int(len(os.listdir(class_path)) * 0.9)
        for img_name in os.listdir(class_path)[l:h]:     #取中间30%作为测试集
            img_path = class_path + img_name
            img = Image.open(img_path)
            img = img.resize((128, 128))
            img_raw = img.tobytes()  # 将图片转化为原生bytes
            # print(index,img_raw)
            example = tf.train.Example(
                features=tf.train.Features(feature={
                    "label":_int64list(index),
                    'img_raw':_byteslist(img_raw)
                }))
            writer.write(example.SerializeToString())
    writer.close()

def create_val_record():
    """创建验证集tfrecord"""
    writer = tf.python_io.TFRecordWriter(val_record_path)
    for index, name in enumerate(classes):
        class_path = cwd + "\\" + name + "\\"
        h = int(len(os.listdir(class_path)) * 0.9)
        for img_name in os.listdir(class_path)[h:]:     # 剩余10%作为验证集
            img_path = class_path + img_name
            img = Image.open(img_path)
            img = img.resize((128, 128))
            img_raw = img.tobytes()  # 将图片转化为原生bytes
            # print(index,img_raw)
            example = tf.train.Example(
                features=tf.train.Features(feature={
                    "label":_int64list(index),
                    'img_raw':_byteslist(img_raw)
                }))
            writer.write(example.SerializeToString())
    writer.close()

def read_record(filename):
    """读取tfrecord"""
    filename_queue = tf.train.string_input_producer([filename])     # 创建文件队列
    reader = tf.TFRecordReader()                                    # 创建reader
    _, serialized_example = reader.read(filename_queue)
    features = tf.parse_single_example(
        serialized_example,
        features={
            'label': tf.FixedLenFeature([], tf.int64),
            'img_raw': tf.FixedLenFeature([], tf.string)
        }
    )
    label = features['label']
    img = features['img_raw']
    img = tf.decode_raw(img, tf.uint8)   #tf.decode_raw函数的意思是将原来编码为字符串类型的变量重新变回来
    img = tf.reshape(img, [128, 128, 3])
#    img = tf.cast(img, tf.float32) * (1. / 255) - 0.5       # 归一化   归一化之后图片会变成那种看不清的图片,未归一化的话则是完好的图片
    label = tf.cast(label, tf.int32)  #这个函数主要用于数据类型的转变,不会改变原始数据的值还有形状的,
    return img, label

def get_batch_record(filename,batch_size):
    """获取batch"""
    image,label = read_record(filename)
    image_batch,label_batch = tf.train.shuffle_batch([image,label],     # 随机抽取batch size个image、label
                                                     batch_size=batch_size,
                                                     capacity=2000,
                                                     min_after_dequeue=1000)
    return image_batch,label_batch#tf.reshape(label_batch,[batch_size])

def main():
    create_train_record()
    create_test_record()
    create_val_record()
if __name__ == '__main__':
    main()
                             
#create_train_record()
#create_test_record()
#create_val_record()
image_batch,label_batch = get_batch_record(train_record_path,32) #此处是调用的train.tfrcord文件,根据需要进行调用tfrecord文件

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    coord = tf.train.Coordinator() #1
    threads = tf.train.start_queue_runners(sess=sess,coord=coord) #2
    for i in range(1):
        image,label = sess.run([image_batch,label_batch])
        print(image.shape,label.shape)
    coord.request_stop() #3
    coord.join(threads) #4

在下篇文章中,我们将会把我们制作好的数据集用于神经网络的训练

附:
在运行代码时可能会出现如下错误:
【UnicodeEncodeError】: ‘utf-8’ codec can’t encode character ‘\udcd5’ in position 2189: surrogates not allowed
这个错误是因为编码方式不一致造成的,但是解决这个问题的办法,是检查路径,仔细检查一下文件路径,看看是否正确。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

TensorFlow制作自己的数据集,并用神经网络来训练自己制作的数据集【上】 的相关文章

随机推荐