TensorFlow相关教程:使用tf.data加载图片

# 使用tf.data加载图片
# 使用的数据集分布在图片文件夹中,一个文件夹含有一类图片

import tensorflow as tf

AUTOTUNE = tf.data.experimental.AUTOTUNE

# 下载并检查数据集:花卉照片
# 检索图片:训练之前需要一组图片来教会网络想要训练的新类别。
import pathlib
data_root_orig = tf.keras.utils.get_file(
    origin='https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz',
    fname='E://.keras//datasets//flower_photos', untar=True
)
data_root = pathlib.Path(data_root_orig)
print(data_root)

for item in data_root.iterdir():
    print(item)

import random
all_image_paths = list(data_root.glob('*/*'))
all_image_paths = [str(path)for path in all_image_paths]
random.shuffle(all_image_paths)
image_count = len(all_image_paths)
print(image_count)
print(all_image_paths[:10])

#检查图片
import os
attributions = (data_root/"LICENSE.txt").open(encoding='utf-8').readlines()[4:]
attributions = [line.split(' CC-BY') for line in attributions]
attributions = dict(attributions)
import IPython.display as display
def caption_image(image_path):
    image_rel = pathlib.Path(image_path).relative_to(data_root)
    # return "Image (CC BY 2.0) " + ' -  '.join(attributions[str(image_rel)].split(' -  ')[:-1])
    return image_rel

for n in range(3):
  image_path = random.choice(all_image_paths)
  display.display(display.Image(image_path))
  print(caption_image(image_path))
  print()

# 确定每张图片的标签:列出可用的标签
label_name = sorted(item.name for item in data_root.glob('*/')if item.is_dir())
print(label_name)
# 为每个标签分配索引
label_to_index = dict((name, index) for index, name in enumerate(label_name))
print(label_to_index)
# 创建一个列表,包含每个文件的标签索引
all_image_labels = [label_to_index[pathlib.Path(path).parent.name]
                    for path in all_image_paths]
print("First 10 labels indices:", all_image_labels[:10])
# 加载和格式化图片
img_path = all_image_paths[0]
print(img_path)
img_raw = tf.io.read_file(img_path)
print(repr(img_raw)[:100]+"...")
# 解码为图像tensor(张量)
img_tensor = tf.image.decode_image(img_raw)
print(img_tensor.shape)
print(img_tensor.dtype)
# 根据模型调整其大小
img_final = tf.image.resize(img_tensor, [192, 192])
img_final = img_final/255.0
print(img_final.shape)
print(img_final.numpy().min())
print(img_final.numpy().max())

# 将这些包装在一个简单的函数里,以备后用
def preprocess_image(image):
    image = tf.image.decode_jpeg(image, channels=3)
    image = tf.image.resize(image, [192, 192])
    image/= 255.0 # 正则化在[0,1]范围内
    return image
def load_and_preprocess_image(path):
    image = tf.io.read_file(path)
    return preprocess_image(image)

import matplotlib.pyplot as plt

image_path = all_image_paths[0]
label = all_image_labels[0]

plt.imshow(load_and_preprocess_image(image_path))
plt.grid(False)
plt.xlabel(caption_image(img_path))
plt.title(label_name[label].title())
# plt.show()
print()

# 构建一个tf.data.Dataset
# 将字符串数组切片,得到一个字符串数据集
path_ds = tf.data.Dataset.from_tensor_slices(all_image_paths)
# shapes(维数)和types(类型)描述数据集里每个数据项的内容
print(path_ds)

# 创建一个新的数据集
image_ds = path_ds.map(load_and_preprocess_image, num_parallel_calls=AUTOTUNE)

plt.figure(figsize=(8,8))
for n,image in enumerate(image_ds.take(4)):
    plt.subplot(2,2,n+1)
    plt.imshow(image)
    plt.grid(False)
    plt.xticks([])
    plt.yticks([])
    plt.xlabel(caption_image(all_image_paths[n]))
    # plt.show()
# 创建一个标签数据集
label_ds = tf.data.Dataset.from_tensor_slices(tf.cast(all_image_labels,tf.int64))
for label in label_ds.take(10):
    print(label_name[label.numpy()])

# 打包成(图片,标签)对数据集
image_label_ds = tf.data.Dataset.zip((image_ds,label_ds))
# 这个新数据集的shapes(维数)和types(类型)也是维数和类型的元组
print(image_label_ds)

ds = tf.data.Dataset.from_tensor_slices((all_image_paths,all_image_labels))
# 元组被解压到映射函数的位置参数中
def load_and_preprocess_from_path_label(path, label):
    return load_and_preprocess_image(path), label
image_label_ds = ds.map(load_and_preprocess_from_path_label)
print(image_label_ds)

BATCH_SIZE = 32
# 设置一个和数据集大小一致的shuffle buffer size(随机缓冲区大小)以保证数据
# 被充分打乱
ds = image_label_ds.shuffle(buffer_size=image_count)
ds = ds.repeat()
ds = ds.batch(BATCH_SIZE)
# 当模型在训练的时候,‘prefetch’使数据集在后台取得batch
ds = ds.prefetch(buffer_size=AUTOTUNE)
print(ds)
print('----------------------------------------')
ds = image_label_ds.apply(
    tf.data.experimental.shuffle_and_repeat(buffer_size=image_count)
)
ds = ds.batch(BATCH_SIZE)
ds = ds.prefetch(buffer_size=AUTOTUNE)
print(ds)

# 传递数据集至模型
mobile_net = tf.keras.applications.MobileNetV2(input_shape=(192, 192, 3), include_top=False)
mobile_net.trainable=False

def change_range(image,label):
    return 2*image-1,label
keras_ds = ds.map(change_range)

# 数据集可能需要几秒来启动,因为要填满其随机缓冲区
image_batch, label_batch = next(iter(keras_ds))
feature_map_batch = mobile_net(image_batch)
print(feature_map_batch.shape)

model = tf.keras.Sequential([
    mobile_net,
    tf.keras.layers.GlobalAveragePooling2D(),
    tf.keras.layers.Dense(len(label_name), activation='softmax')
])
# 输出预期的shape(维数)
logit_batch = model(image_batch).numpy()
print("min logit:", logit_batch.min())
print("max logit:", logit_batch.max())
print()
print("Shape:", logit_batch.shape)
model.compile(
    optimizer = tf.keras.optimizers.Adam(),
    loss = 'sparse_categorical_crossentropy',
    metrics=["accuracy"]
)
# 此处有两个可训练的变量--Dense层中的weights(权重)和bias(偏差)
print(model.trainable_variables)
model.summary()

steps_per_epoch = tf.math.ceil(len(all_image_paths)/BATCH_SIZE).numpy()
print(steps_per_epoch)
model.fit(ds, epochs=1, steps_per_epoch=3)

# 性能:提升性能的技巧pipeline(管道)
import time
default_timeit_steps = 2*steps_per_epoch+1
def timeit(ds, steps=default_timeit_steps):
    overall_start = time.time()
    # 在开始计时之前,取得单个batch来填充pipeline(管道)(填充随机缓冲区)
    it = iter(ds.take(steps+1))
    next(it)
    start = time.time()
    for i,(image,labels) in enumerate(it):
        if i%10 == 0:
            print('.',end='')
    print()
    end = time.time()
    duration = end-start
    print("{}batches:{}s".format(steps, duration))
    print("{:0.5f}Images/s".format(BATCH_SIZE*steps/duration))
    print("Total time:{}s".format(end-overall_start))

# 当前数据集的性能
ds = image_label_ds.apply(
    tf.data.experimental.shuffle_and_repeat(buffer_size=image_count)
)
ds = ds.batch(BATCH_SIZE).prefetch(buffer_size=AUTOTUNE)
print(ds)
print(timeit(ds))

# 缓存:使用 tf.data.Dataset.cache 在 epoch 之间轻松缓存计算结果。这是非常高效的,特别是当内存能容纳全部数据时
ds = image_label_ds.cache()
ds = ds.apply(
     tf.data.experimental.shuffle_and_repeat(buffer_size=image_count)
 )
ds = ds.batch(BATCH_SIZE).prefetch(buffer_size=AUTOTUNE)
print(ds)
print(timeit(ds))

# 如果内存不够容纳数据,使用一个缓存文件
ds = image_label_ds.cache(filename='./cache.tf-data')
ds = ds.apply(
    tf.data.experimental.shuffle_and_repeat(buffer_size=image_count)
)
ds = ds.batch(BATCH_SIZE).prefetch(1)
print(ds)
print(timeit(ds))

# TFRecord文件:是一种用来存储一串二进制blob的简单格式
image_ds = tf.data.Dataset.from_tensor_slices(all_image_paths).map(tf.io.read_file)
tfrec = tf.data.experimental.TFRecordWriter('images.tfrec')
tfrec.write(image_ds)
# 接着,构建一个从TFRecord文件读取的数据集,并使用preprocess_image函数对图片进行解码、重新格式化
image_ds = tf.data.TFRecordDataset('images.tfrec').map(preprocess_image)
# 压缩该数据集和之前定义的标签数据集得到期望的(图片,标签)对
ds = tf.data.Dataset.zip((image_ds,label_ds))
ds = ds.apply(
    tf.data.experimental.shuffle_and_repeat(buffer_size=image_count)
)
ds = ds.batch(BATCH_SIZE).prefetch(AUTOTUNE)
print(ds)
print(timeit(ds))

# 序列化Tensor
paths_ds = tf.data.Dataset.from_tensor_slices(all_image_paths)
image_ds = path_ds.map(load_and_preprocess_image)
print(image_ds)
# 将tensor数据集转化为一个字符串数据集
ds = image_ds.map(tf.io.serialize_tensor)
print(ds)
tfrec = tf.data.experimental.TFRecordWriter('images.tfrec')
tfrec.write(ds)

ds = tf.data.TFRecordDataset('images.tfrec')
def parse(x):
    result = tf.io.parse_tensor(x, out_type=tf.float32)
    result = tf.reshape(result, [192,192,3])
    return result

ds = ds.map(parse, num_parallel_calls=AUTOTUNE)
print(ds)

ds = tf.data.Dataset.zip((ds,label_ds))
ds = ds.apply(
    tf.data.experimental.shuffle_and_repeat(buffer_size=image_count)
)
ds = ds.batch(BATCH_SIZE).prefetch(AUTOTUNE)
print(ds)
print(timeit(ds))

你可能感兴趣的:(tensorflow,深度学习,神经网络)