有任何问题欢迎在下面留言
本篇文章的代码运行界面均在Jupyter Notebook中进行
本篇文章配套的代码资源已经上传
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,
}
# 读数据,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))
打印结果:
Processed 1 of 2 images.
Processed 2 of 2 images.
Wrote 2 images to images.tfrecord
raw_train_dataset = tf.data.TFRecordDataset('images.tfrecord')
raw_train_dataset
example数据都进行了序列化,还需要解析以下之前写入的序列化string,即反序列化
这个函数是专门用来解析图像数据的
# 解析的格式需要跟之前创建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
打印结果:
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