在TensorFlow官网的加载和预处理Notebook页面进行学习时,发现配置环境的版本太低,代码没有办法完全实现。期间也尝试了重装,改环境,改源码,总有一部分难以解决。属实才疏学浅,便在代码部分借鉴了CSDN博主(永恒的星河)的代码。在此基础上完成了代码运行,并做出了注释。
import tensorflow as tf
import pathlib
import random
import matplotlib.pyplot as plt
from PIL import Image
# pillow 图像处理模块
import numpy as np
# 数据集下载
DATA_URL = "https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz"
# 文件的URL地址
path = tf.keras.utils.get_file(fname='flower_photos', origin=DATA_URL, untar=True)
# get_file:创建文件,fname:文件名,origin:来源 untar:解压
data_root = pathlib.Path(path)
# 利用pathlib中的path使path文件形成一个路径
# 获取每个类别下的图片路径
all_image_paths = list(data_root.glob('*/*'))
# glob获取data_root文件夹下所有文件夹下的所有内容 list 形成列表
all_image_paths = [str(path) for path in all_image_paths]
# 对all_image_paths中的文件,使其形成字符形式
random.shuffle(all_image_paths)
# 打乱all_image_paths中的内容
image_count = len(all_image_paths)
# 获取图像描述
attributions = (data_root / "LICENSE.txt").open(encoding="utf-8").readlines()[4:]
# 以utf-8的格式打开data_root下的LICENSE.txt文件,按行读取
attributions = [line.split('CC-BY') for line in attributions]
# 拆分
attributions = dict(attributions)
print(attributions)
def caption_image(image_path):
image_rel = pathlib.Path(image_path).relative_to(data_root)
image_rel = str(image_rel).replace("\\", "/")
image_rel = image_rel + " "
return "Image (CC BY 2.0) " + " - ".join(attributions[image_rel].split(" - ")[:-1])
# 随机显示四张图片
plt.figure(figsize=(10,10))
for n in range(1,5):
image_path = random.choice(all_image_paths)
img_data = np.asarray(Image.open(image_path))
# display.display(display.Image(image_path))
plt.subplot(2,2,n)
plt.grid(False)
plt.xticks([])
plt.yticks([])
plt.xlabel(caption_image(image_path))
plt.imshow(img_data)
plt.show()
# 获取具体类别,将其数值化处理
label_names = sorted(item.name for item in data_root.glob("*/") if item.is_dir())
# 对于所有data_root下的文件夹进行排序
label_to_index = dict((name, index) for index, name in enumerate(label_names))
# 将一个可遍历对象组合为一个索引序列,同时列出数据和数据下标
print(label_to_index)
# 打印类别和索引对应字典
all_image_labels = [label_to_index[pathlib.Path(impath).parent.name] for impath in all_image_paths]
print("First 10 labels indices: ", all_image_labels[:10])
# 打印前十个标签索引
# 解析图像数据,将其归一化
def process_image(image):
image = tf.image.decode_jpeg(image, channels=3)
# 定义图片的通道数
image = tf.image.resize(image, (192, 192))
# 定义图片大小
image /= 255.0
# 归一化
return image
def load_and_process_image(path):
image = tf.io.read_file(path)
return process_image(image)
# 将图片转化为datasets处理,方便模型训练和数据处理
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_process_image(path), label
image_label_ds = ds.map(load_and_preprocess_from_path_label)
# map 对指定的序列做映射
print(image_label_ds)
# 使用 tf.data.Dataset.cache 在 epoch 之间轻松缓存计算结果。
# 这是非常高效的,特别是当内存能容纳全部数据时。
# 在被预处理之后(解码和调整大小),图片在此被缓存:
BATCH_SIZE=12
ds = image_label_ds.cache()
# 设置一个和数据集大小一致的 shuffle buffer size(随机缓冲区大小)以保证数据被充分打乱
ds = ds.apply(
tf.data.experimental.shuffle_and_repeat(buffer_size=image_count))
ds = ds.batch(BATCH_SIZE)
# 当模型在训练的时候,`prefetch` 使数据集在后台取得 batch。
ds = ds.prefetch(buffer_size=tf.data.experimental.AUTOTUNE)
# 模型迁移、模型构建及训练
mobile_net = tf.keras.applications.MobileNetV2(input_shape=(192, 192, 3), include_top=False)
mobile_net.trainable = False
help(tf.keras.applications.mobilenet_v2.preprocess_input)
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_names), activation='softmax')])
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"])
steps_per_epoch = int(tf.math.ceil(len(all_image_paths) / BATCH_SIZE).numpy())
model.fit(ds, epochs=10, steps_per_epoch=steps_per_epoch)