TensorFlow2实战-系列教程9:TFRecords数据源制作2

TensorFlow2实战-系列教程 总目录

有任何问题欢迎在下面留言
本篇文章的代码运行界面均在Jupyter Notebook中进行
本篇文章配套的代码资源已经上传

5、图像数据处理实例

5.1 读数据

import os
import glob
from datetime import datetime

import cv2
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
%matplotlib inline
image_path = '../img/'
images = glob.glob(image_path + '*.jpg')

for fname in images:
    image = mpimg.imread(fname)
    f, (ax1) = plt.subplots(1, 1, figsize=(8,8))
    f.subplots_adjust(hspace = .2, wspace = .05)
    
    ax1.imshow(image)
    ax1.set_title('Image', fontsize=20)

image_labels = {
    'dog': 0,
    'kangaroo': 1,
}

5.2 制作TFRecord

# 读数据,binary格式
image_string = open('./img/dog.jpg', 'rb').read()
label = image_labels['dog']

打开一张图像和它对应的标签

def _bytes_feature(value):
    """Returns a bytes_list from a string/byte."""
    if isinstance(value, type(tf.constant(0))):
        value = value.numpy() # BytesList won't unpack a string from an EagerTensor.
    return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))

def _float_feature(value):
    """Return a float_list form a float/double."""
    return tf.train.Feature(float_list=tf.train.FloatList(value=[value]))

def _int64_feature(value):
    """Return a int64_list from a bool/enum/int/uint."""
    return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))

前面3个处理字符、浮点数、整型的函数

# 创建图像数据的Example
def image_example(image_string, label):
    image_shape = tf.image.decode_jpeg(image_string).shape

    feature = {
        'height': _int64_feature(image_shape[0]),
        'width': _int64_feature(image_shape[1]),
        'depth': _int64_feature(image_shape[2]),
        'label': _int64_feature(label),
        'image_raw': _bytes_feature(image_string),
    }

    return tf.train.Example(features=tf.train.Features(feature=feature))

定义一个函数,指定要保存的指标,以及要用什么格式存这批数据
image_shape 就是图像长、宽、通道数
feature 中定义了图像h、w、c、标签、矩阵特征
最后构建Example返回一条数据

#打印部分信息
image_example_proto = image_example(image_string, label)

for line in str(image_example_proto).split('\n')[:15]:
    print(line)
print('...')

调用刚刚的函数,传进实际的数据和标签
把转换的数据打印出来

# 制作 `images.tfrecords`.

image_path = './img/'
images = glob.glob(image_path + '*.jpg')
record_file = 'images.tfrecord'
counter = 0

with tf.io.TFRecordWriter(record_file) as writer:
    for fname in images:
        with open(fname, 'rb') as f:
            image_string = f.read()
            label = image_labels[os.path.basename(fname).replace('.jpg', '')]
            tf_example = image_example(image_string, label)
            writer.write(tf_example.SerializeToString())
            
            counter += 1
            print('Processed {:d} of {:d} images.'.format(
                counter, len(images)))

print(' Wrote {} images to {}'.format(counter, record_file))
  1. 指定所有数据的路径
  2. 指定最后保存的数据的路径和名称
  3. 计数器
  4. 打开TFRecordWriter,准备写数据
  5. 遍历所有的图像数据路径
  6. 打开当前路径的文件
  7. 读取图像
  8. 映射图像文件名(无扩展名)到标签
  9. 使用 image_example 函数(需要事先定义)创建 tf.Example 对象
  10. 将其序列化后写入 TFRecord 文件
  11. 每处理一个图像文件,计数器增加
  12. 并打印出已处理的图像数量
  13. 所有图像处理完成后,打印出写入 TFRecord 文件的总图像数量

打印结果:

Processed 1 of 2 images.
Processed 2 of 2 images.
Wrote 2 images to images.tfrecord

5.3 加载制作好的TFRecord

raw_train_dataset = tf.data.TFRecordDataset('images.tfrecord')
raw_train_dataset

example数据都进行了序列化,还需要解析以下之前写入的序列化string,即反序列化

  • tf.io.parse_single_example(example_proto, feature_description)函数可以解析单条example

这个函数是专门用来解析图像数据的

# 解析的格式需要跟之前创建example时一致
image_feature_description = {
    'height': tf.io.FixedLenFeature([], tf.int64),
    'width': tf.io.FixedLenFeature([], tf.int64),
    'depth': tf.io.FixedLenFeature([], tf.int64),
    'label': tf.io.FixedLenFeature([], tf.int64),
    'image_raw': tf.io.FixedLenFeature([], tf.string),
}

现在看起来仅仅完成了一个样本的解析,实际数据不可能一个个来写吧,可以定义一个映射规则map函数

解析的格式,要和原来一致

def parse_tf_example(example_proto):
    parsed_example = tf.io.parse_single_example(example_proto, image_feature_description)
    x_train = tf.image.decode_jpeg(parsed_example['image_raw'], channels=3)
    x_train = tf.image.resize(x_train, (416, 416))
    x_train /= 255.
    lebel = parsed_example['label']
    y_train = lebel
    
    return x_train, y_train

train_dataset = raw_train_dataset.map(parse_tf_example)
train_dataset
  1. 定义一个专门用来解析的函数
  2. 传进解析的样本、解析的对照关系image_feature_description
  3. 进行预处理操作,将原始的二进制 JPEG 图像数据解码为Tensor
  4. 将图像大小调整为 416x416 像素
  5. 将图像数据归一化到 0 到 1 的范围
  6. 提取 label 字段并赋值给 y_train
  7. 返回处理后的图像数据和标签
  8. 将 parse_tf_example 函数应用于原始的训练数据集 raw_train_dataset,map 函数会对数据集中的每个元素应用 parse_tf_example 函数

打印结果:

5.4 制作训练集

num_epochs = 10

train_ds = train_dataset.shuffle(buffer_size=10000).batch(2).repeat(num_epochs)
for batch, (x, y) in enumerate(train_ds):
    print(batch, x.shape, y)

把数据转换成batch形式,然后把转换的数据打印出来
打印结果:

0 (2, 416, 416, 3) tf.Tensor([0 1], shape=(2,), dtype=int64)
1 (2, 416, 416, 3) tf.Tensor([0 1], shape=(2,), dtype=int64)

8 (2, 416, 416, 3) tf.Tensor([1 0], shape=(2,), dtype=int64)
9 (2, 416, 416, 3) tf.Tensor([1 0], shape=(2,), dtype=int64)

model = tf.keras.Sequential([
  tf.keras.layers.Flatten(),
  tf.keras.layers.Dense(2, activation='softmax')
])
model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(),
              metrics=['accuracy'])
model.fit(train_ds, epochs=num_epochs)

定义一个简单的模型、训练器,然后进行训练
打印结果:

Epoch 1/10 10/10 1s 51ms/step - loss: 55.1923 - accuracy: 0.6500

Epoch 9/10 10/10 0s 19ms/step - loss: 0.0000e+00 - accuracy: 1.0000
Epoch 10/10 10/10 0s 19ms/step - loss: 0.0000e+00 - accuracy: 1.0000

你可能感兴趣的:(TensorFlow,tensorflow,人工智能,python,TFRecords)