Tensorflow原始教程链接在官网:
https://tensorflow.google.cn/tutorials/load_data/images
简化版:
https://colab.research.google.com/drive/146IoL0nVN7HOA3sUJ08zAGbngmwTArDp?usp=sharing
但原始教程中比较繁琐,对于想要直接使用的情况的话,本文将如下要点提炼出来。
假设你有如下形式的数据:
每一个类别的名称就是文件夹名称,每个文件夹下面放置该类的图片。
现在我们就想使用tf.data 把数据整合成一个数据集,然后直接用于模型的训练。
使用pathlib包来处理文件夹,包括获取文件夹名称和上一级文件夹
import pathlib
data_root="../../data/kaggle_dog/train_valid_test_tiny"
train_data_root = pathlib.Path(data_root+"/train")
#获取标签名称
label_names = sorted(item.name for item in train_data_root.glob('*/') if item.is_dir())
#标签名称到id的映射
label_to_index = dict((name, index) for index, name in enumerate(label_names))
#获取图片路径
train_all_image_paths = [str(path) for path in list(train_data_root.glob('*/*'))]
#获取对应的labels
train_all_image_labels = [label_to_index[pathlib.Path(path).parent.name] for path in train_all_image_paths]
#展示
print("First 10 images indices: ", train_valid_all_image_labels[:10])
print("First 10 labels indices: ", train_valid_all_image_labels[:10])
如上在../../data/kaggle_dog/train_valid_test_tiny
文件夹下有/train
的训练文件夹,里面又放了很多类别的文件夹,里面包含每个类的图片数据。
通过上面的操作可以获取/train
下的训练图片和类别。
获取了图片的所有路径之后就可以根据路径获取图片,然后根据图片转化为模型可以接受的输入,将这个转化过程整理为transform_train
函数。
def transform_train(imgpath,label):
#从路径中读取图片
feature=tf.io.read_file(imgpath)
#解码图片
feature = tf.image.decode_jpeg(feature,channels=3)
#重新设置大小
feature = tf.image.resize(feature, size=[400, 400])
#随机裁剪
seed=random.randint(8,100)/100
feature = tf.image.random_crop(feature, size=[int(seed*feature.shape[0]), int(seed*feature.shape[1]), 3])
#最终设置为224*224的大小
feature = tf.image.resize(feature, size=[224, 224])
feature = tf.image.random_flip_left_right(feature)
feature = tf.image.random_flip_up_down(feature)
# 标准化
feature = tf.divide(feature, 255.)
# 正则化
mean = tf.convert_to_tensor([0.485, 0.456, 0.406])
std = tf.convert_to_tensor([0.229, 0.224, 0.225])
feature = tf.divide(tf.subtract(feature, mean), std)
#feature = tf.image.per_image_standardization(feature)
return tf.image.convert_image_dtype(feature, tf.float32),label
需要注意的是让整个Dataset来统一应用这个函数的话,传入的path读取成图片后不一定会直接由shape的信息,所以提前调用resize图片。
train_ds = tf.data.Dataset.from_tensor_slices((train_all_image_paths, train_all_image_labels)).map(transform_train).shuffle(len(train_all_image_paths)).batch(batch_size)
这样一个训练使用的 tf.data.Dataset就构建好了,需要注意的是使用了.batch(batch_size)
才能生成(None,224,224,3)
的数据集形式,否则就只是(224,224,3)
的图片形式。
模型定义
from tensorflow.keras.applications import ResNet50
net=ResNet50(
input_shape=(224, 224, 3),
weights='imagenet',
include_top=False
)
model = tf.keras.Sequential([
net,
tf.keras.layers.GlobalAveragePooling2D(),
tf.keras.layers.Dense(len(label_names), activation='softmax',dtype=tf.float32)
])
model.summary()
lr = 0.1
lr_decay = 0.01
def scheduler(epoch):
if epoch < 10:
return lr
else:
return lr * tf.math.exp(lr_decay * (10 - epoch))
callback = tf.keras.callbacks.LearningRateScheduler(scheduler)
model.compile(optimizer=keras.optimizers.SGD(learning_rate=lr, momentum=0.9),
loss='sparse_categorical_crossentropy')
训练模型
model.fit(train_ds, epochs=1 , validation_data=valid_ds, callbacks=[callback])
120/120 [==============================] - 105s 879ms/step - loss: 5.2341 - val_loss: 5.6558 - lr: 0.1000
由于只是测试,所以结果如上所示。