猫狗大战2.0 使用tensorflow和tfrecord

      距离上次的博客已经过去了半个月两周左右的时间,自己在b站和博客上学习了很多相关的知识,自我感觉自己的tensorflow的水平已经算是到了入门的水平,在博客上有相关的非tensorboard导入数据,实测有效(传送门由于时间久了,暂时找不到了,自己找一下吧)。不过通过tensorboard的可运行资料却十分少,所以自己在此记录一下自己的程序,也算是自己整理一下。

如果感觉有用,可以点一下关注哟!我会不定期更新一些自己学习的东西。

使用的IDE是vscode(python3.5),数据下载可以在其他博客中找一下。

 

 首先工程图如下:

Data文件夹下有train和test两个文件夹,就是下载的数据集。Logs存放咱们所有的程序。

                                          猫狗大战2.0 使用tensorflow和tfrecord_第1张图片

首先我们要建立创建tfrecord的文件:

首先得到文件夹train下的所有文件名称,贴出代码如下:

import tensorflow as tf
import numpy as np
import os

NumClass = 2
ImageWidth = 208
ImageHeight = 208
ImageChannel = 3

def get_files(file_dic):

    cats = []
    dogs = []
    cats_labels = []
    dogs_labels = []

    for file in os.listdir(file_dic):
        #得到文件下所有的文件名称,也就是cat.0jpg....

        name = file.split(sep='.')
        if name[0] == 'cat':
            cats.append(file_dic+'/'+file)
            cats_labels.append(0)
        if name[0] == 'dog':
            dogs.append(file_dic+'/'+file)
            dogs_labels.append(1)

    return cats, cats_labels, dogs, dogs_labels

cats, cats_labels, dogs, dogs_labels = get_files('G:/CatsAndDogs/data/train')
print(cats)

得到的输出为:

['G:/CatsAndDogs/data/train/cat.0.jpg', 'G:/CatsAndDogs/data/train/cat.1.jpg'...

可以看到文件名称都已导入cats等列表当中,那么接下来的操作就是把image和label的列表连接起来并打乱数据。代码贴出如下。

    #将文件打乱顺序
    image_list = np.hstack((cats, dogs)) #将两个列表连接起来
    labels_list = np.hstack((cats_labels, dogs_labels))
    temp = np.array([image_list, labels_list])
    temp = temp.transpose() #转置矩阵
    np.random.shuffle(temp) #打乱数据,下面的图片是temp现在的数据


    ##从打乱的temp中再取出list,相当于洗牌之后的重新摸牌
    image_list = list(temp[:, 0])
    label_list = list(temp[:, 1])
    label_list = [int(i) for i in label_list]  # 字符串类型转换为int类型

现在temp程序跑到这的数据结果如下图所示:

猫狗大战2.0 使用tensorflow和tfrecord_第2张图片

嗯,到现在为止也很成功,那我们接下来继续操作,这个时候又变成了需要对整个列表的操作,所以我们需要整个列表的长度,再把相片的解码出来。

from scipy.misc import imread,imresize #注意是得重新加载一个model

    #首先要确定整个列表的长度并且初始化相片的格式
    num_file = len(cats_labels) + len(dogs_labels)
    images = np.zeros((num_file, ImageHeight, ImageWidth, ImageChannel), dtype = np.uint8)

    for index in range(num_file):
        img = imread(image_list[index])
        img = imresize(img, (ImageWidth, ImageHeight))
        images[index] = img
        

接下来我们可以把这些相片,labels等信息传入一个类中,用来建立接下来的tdrecord文件。

    class ImgData(object):
        pass
    
    result = ImgData()
    result.images = images
    result.labels = label_list
    result.num = num_file

到此我们就完成了第一个函数。此时得到了文件夹中乱序的所有照片及相应的标签,暂时完成了第一步的工作。接下来我们就开始第二部的工作,完成tfrecord文件的完成。

def convert(data, destination, destination1):
    """将图片存储为.tfrecords文件
    参数:
        data: 上述函数返回的ImageData对象
        destination: 目标文件名
    """
 
    images = data.images
    labels = data.labels
    num_examples = data.num - 3000
                #使用上面使用的类进行下面的tfreord建立,照片标签以及数据
 
    # 存储的文件名
    filename = destination
                #储存时的文件名(带路径的)
    
    # 使用TFRecordWriter来写入数据
    writer = tf.python_io.TFRecordWriter(filename)
                #使用tfrecord进行写入
    # 遍历图片
    for index in range(num_examples):
        # 转为二进制
        image = images[index].tostring()
        label = labels[index]
                #直接使用上面所建立的类进行输入
                
        # tf.train下有Feature和Features,需要注意其区别
        # 层级关系为Example->Features->Feature(很重要)
        #注意图片一般的类型为ByteList,其他的有Int64List和FloatList型
        example = tf.train.Example(features=tf.train.Features(feature={
            'image': tf.train.Feature(bytes_list=tf.train.BytesList(value=[image])),
            'label': tf.train.Feature(int64_list=tf.train.Int64List(value=[label]))
        }))
        # 写入建立的example
        writer.write(example.SerializeToString())
    writer.close()
            
    filename1 = destination1
    writer = tf.python_io.TFRecordWriter(filename1)
    for index in range(3000):
        # 转为二进制
        image = images[index+num_examples].tostring()
        label = labels[index+num_examples]
        example = tf.train.Example(features=tf.train.Features(feature={
            'image': tf.train.Feature(bytes_list=tf.train.BytesList(value=[image])),
            'label': tf.train.Feature(int64_list=tf.train.Int64List(value=[label]))
        }))
        writer.write(example.SerializeToString())
    writer.close()    

convert(result, 'G:/CatsAndDogs/logs/traintfrecord', 'G:/CatsAndDogs/logs/testtfrecord')

上面的注释很清楚,应该可以看懂,主要是有train和test两个部分,不太懂的也可以百度查一下,应该可以找到相关的资料。接下来的就是解码一下数据。

def read_and_decode(filename_queue, batch_size, capacity):
    """读取.tfrecords文件
    参数:
        filename_queue: 文件名, 一个列表
    返回:
        img, label: **单张图片和对应标签**
    """
    # 创建一个图节点,该节点负责数据输入
    filename_queue = tf.train.string_input_producer([filename_queue])
                # tf.train.string_input_producer函数把我们需要的全部文件打包为一个tf内部的queue类型
                # 之后tf开文件就从这个queue中取目录了,要注意一点的是这个函数的shuffle参数默认是True
                # 所以读取的顺序可能不一样
    reader = tf.TFRecordReader()
    _, serialized_example = reader.read(filename_queue)
                # 读取前面所建立的数据目录
    
    # 解析单个example
            # 暂时不大清楚下面的操作,不过感觉应该是得到各个features
    features = tf.parse_single_example(serialized_example, features={
        'image': tf.FixedLenFeature([], tf.string),
        'label': tf.FixedLenFeature([], tf.int64)
    })
            # tf.decode_raw函数的意思是将原来编码为字符串类型的变量重新变回来
            # 这个方法在数据集dataset中很常用,因为制作图片源数据一般写进tfrecord里用to_bytes的形式,也就是字符串
            # 这里将原始数据取出来,必须制定原始数据的格式,原始数据是什么格式这里解析必须是什么格式!!
            # tf.cast这个函数主要用于数据类型的转变,不会改变原始数据的值还有形状的
    image = tf.decode_raw(features['image'], tf.uint8)
    image = tf.reshape(image, [ImageHeight, ImageWidth, ImageChannel])
    image = tf.cast(image, tf.float32)
    label = tf.cast(features['label'], tf.int32)
    
    image_batch, label_batch = tf.train.batch([image, label],
                                              batch_size=batch_size,
                                              num_threads=64,  # 线程
                                              capacity=capacity)
    
    return image, label

上面是解析tfrecord的函数,那么可以利用下面的程序进行train和test数据的获得。

image, label = read_and_decode('G:/CatsAndDogs/logs/traintfrecord', 16, 2000) 
image1, label1 = read_and_decode('G:/CatsAndDogs/logs/testtfrecord', 16, 2000)  

整体的函数如下:

import tensorflow as tf
import numpy as np
import os
from scipy.misc import imread,imresize

NumClass = 2
ImageWidth = 208
ImageHeight = 208
ImageChannel = 3

def get_files(file_dic):

    cats = []
    dogs = []
    cats_labels = []
    dogs_labels = []

    #得到文件下所有的文件名称,也就是cat.0jpg....
    for file in os.listdir(file_dic):   

        name = file.split(sep='.')
        if name[0] == 'cat':
            cats.append(file_dic+'/'+file)
            cats_labels.append(0)
        if name[0] == 'dog':
            dogs.append(file_dic+'/'+file)
            dogs_labels.append(1)
            
    num_file = len(cats_labels) + len(dogs_labels)
    images = np.zeros((num_file, ImageHeight, ImageWidth, ImageChannel), dtype = np.uint8)
    print("There are %d cats\nThere are %d dogs" % (len(cats), len(dogs)))

    #将文件打乱顺序
    image_list = np.hstack((cats, dogs))
    labels_list = np.hstack((cats_labels, dogs_labels))
    temp = np.array([image_list, labels_list])
    temp = temp.transpose()
    np.random.shuffle(temp)

    ##从打乱的temp中再取出list(img和lab)
    image_list = list(temp[:, 0])
    label_list = list(temp[:, 1])
    label_list = [int(i) for i in label_list]  # 字符串类型转换为int类型
    
    for index in range(num_file):
        img = imread(image_list[index])
        img = imresize(img, (ImageWidth, ImageHeight))
        images[index] = img
        
    class ImgData(object):
        pass
    
    result = ImgData()
    result.images = images
    result.labels = label_list
    result.num = num_file
    
    return result

def convert(data, destination, destination1):
    """将图片存储为.tfrecords文件
    参数:
        data: 上述函数返回的ImageData对象
        destination: 目标文件名
    """
 
    images = data.images
    labels = data.labels
    num_examples = data.num - 3000
                #使用上面使用的类进行下面的tfreord建立,照片标签以及数据
 
    # 存储的文件名
    filename = destination
                #储存时的文件名(带路径的)
    
    # 使用TFRecordWriter来写入数据
    writer = tf.python_io.TFRecordWriter(filename)
                #使用tfrecord进行写入
    # 遍历图片
    for index in range(num_examples):
        # 转为二进制
        image = images[index].tostring()
        label = labels[index]
                #直接使用上面所建立的类进行输入
                
        # tf.train下有Feature和Features,需要注意其区别
        # 层级关系为Example->Features->Feature(很重要)
        #注意图片一般的类型为ByteList,其他的有Int64List和FloatList型
        example = tf.train.Example(features=tf.train.Features(feature={
            'image': tf.train.Feature(bytes_list=tf.train.BytesList(value=[image])),
            'label': tf.train.Feature(int64_list=tf.train.Int64List(value=[label]))
        }))
        # 写入建立的example
        writer.write(example.SerializeToString())
    writer.close()
            
    filename1 = destination1
    writer = tf.python_io.TFRecordWriter(filename1)
    for index in range(3000):
        # 转为二进制
        image = images[index+num_examples].tostring()
        label = labels[index+num_examples]
        example = tf.train.Example(features=tf.train.Features(feature={
            'image': tf.train.Feature(bytes_list=tf.train.BytesList(value=[image])),
            'label': tf.train.Feature(int64_list=tf.train.Int64List(value=[label]))
        }))
        writer.write(example.SerializeToString())
    writer.close()    

convert(result, 'G:/CatsAndDogs/logs/traintfrecord', 'G:/CatsAndDogs/logs/testtfrecord')


def read_and_decode(filename_queue, batch_size, capacity):
    """读取.tfrecords文件
    参数:
        filename_queue: 文件名, 一个列表
    返回:
        img, label: **单张图片和对应标签**
    """
    # 创建一个图节点,该节点负责数据输入
    filename_queue = tf.train.string_input_producer([filename_queue])
                # tf.train.string_input_producer函数把我们需要的全部文件打包为一个tf内部的queue类型
                # 之后tf开文件就从这个queue中取目录了,要注意一点的是这个函数的shuffle参数默认是True
                # 所以读取的顺序可能不一样
    reader = tf.TFRecordReader()
    _, serialized_example = reader.read(filename_queue)
                # 读取前面所建立的数据目录
    
    # 解析单个example
            # 暂时不大清楚下面的操作,不过感觉应该是得到各个features
    features = tf.parse_single_example(serialized_example, features={
        'image': tf.FixedLenFeature([], tf.string),
        'label': tf.FixedLenFeature([], tf.int64)
    })
            # tf.decode_raw函数的意思是将原来编码为字符串类型的变量重新变回来
            # 这个方法在数据集dataset中很常用,因为制作图片源数据一般写进tfrecord里用to_bytes的形式,也就是字符串
            # 这里将原始数据取出来,必须制定原始数据的格式,原始数据是什么格式这里解析必须是什么格式!!
            # tf.cast这个函数主要用于数据类型的转变,不会改变原始数据的值还有形状的
    image = tf.decode_raw(features['image'], tf.uint8)
    image = tf.reshape(image, [ImageHeight, ImageWidth, ImageChannel])
    image = tf.cast(image, tf.float32)
    label = tf.cast(features['label'], tf.int32)
    
    image_batch, label_batch = tf.train.batch([image, label],
                                              batch_size=batch_size,
                                              num_threads=64,  # 线程
                                              capacity=capacity)
    
    return image, label

image, label = read_and_decode('G:/CatsAndDogs/logs/traintfrecord', 16, 2000) 
image1, label1 = read_and_decode('G:/CatsAndDogs/logs/testtfrecord', 16, 2000)  

不过要注意先用前两个函数生成所需的tfrecord文件才能跑第三个函数。

明天继续剩下的部分。

你可能感兴趣的:(tensorflow,猫狗大战,tfrecord,python)