第5讲讲解了keras制作mnist数据集的流程,进一步的,有时候我们需要构建自己的数据集。
以flower分类为例,见参考3(这里直接用别人的数据,也可以自己整理,只是比较耗时间,脚本也做了改写,方便理解)
step1:下载flower数据集
数据下载地址见参考3,下载完成后得到5个文件夹,分别存放5种不同花的jpg图像:
flower_photos# tree -L 1
.
├── LICENSE.txt
├── daisy # 雏菊,编号0
├── dandelion # 蒲公英,编号1
├── roses # 玫瑰,编号2
├── sunflowers # 向日葵,编号3
└── tulips # 郁金香,编号4
step2:制作图像-标签字典
我们需要给图像打上标签,比如0代表daisy,1代表dandelion,等,神经网络训练完成后,输入一个上述5种花的一种,经过模型处理后,得到标签[0-4],这个标签表示花的种类。
# create_image2label.py
import os, glob, json, random
def create_image2label(root, jsonname):
'''
root:images文件夹路径
jsonname:写入的json文件名
'''
name2label = {}
# step1: 将flower_photos文件夹依次编号
for name in sorted(os.listdir(root)):
# 如果flower_photos/name不是文件夹,跳过
if not os.path.isdir(os.path.join(root, name)):
continue
else:
# 依次编号
name2label[name] = len(name2label.keys())
# 这样得到 name2label = {'daisy': 0, 'dandelion': 1, 'roses': 2, 'sunflowers': 3, 'tulips': 4}
# step2: 将image-label对应关系写入到json中
if not os.path.exists(os.path.join(root, jsonname)):
images = []
for name in name2label.keys():
# 返回图片路径:flower_photos/xxx/xxx, 支持jpg/png等格式
images += glob.glob(os.path.join(root, name, "*.*g"))
# 图片按类别写入列表,需要打乱顺序,原位打乱
random.shuffle(images)
# 用来保存图片路径-label对应关系
path_label = {}
for img in images:
# 将路径按/或\分离[flower_photos, daisy, **.jpg]取出类别名
name = img.split(os.sep)[-2]
# 根据字典key,对应value找出对应标签
label = name2label[name]
path_label[img] = label
# 将路径,标签信息写入json文件
with open(os.path.join(root, jsonname), 'w', newline="") as js:
json.dump(path_label, js)
if __name__ == '__main__':
cwd = './flower_photos'
jsonname = 'images.json'
create_image2label(cwd, jsonname)
在当前路径下得到images.json文件,里面记录了图片路径与标签,如下(截取部分)。
{ "./flower_photos/daisy/7133935763_82b17c8e1b_n.jpg": 0,
"./flower_photos/sunflowers/5020805135_1219d7523d.jpg": 3,
"./flower_photos/roses/10090824183_d02c613f10_m.jpg": 2,
"./flower_photos/daisy/9346508462_f0af3163f4.jpg": 0,
"./flower_photos/sunflowers/9655029591_7a77f87500.jpg": 3,
"./flower_photos/sunflowers/22255608949_172d7c8d22_m.jpg": 3,
"./flower_photos/tulips/113291410_1bdc718ed8_n.jpg": 4,
}
step3:load数据以及数据的预处理
import os, glob, json, random
import tensorflow as tf
import numpy as np
def load_json(root, jsonname):
images, labels = [], []
with open(os.path.join(root, jsonname)) as js:
jscontent = json.load(js)
for key, value in jscontent.items():
label = int(value)
images.append(key)
labels.append(label)
assert len(images) == len(labels)
return images, labels
def load_data(root, mode='train'):
jsonname = 'images.json'
images, labels = load_json(root, jsonname)
# 训练集
if mode == 'train': # 60%
images = images[:int(0.6 * len(images))]
labels = labels[:int(0.6 * len(labels))]
# 验证集
elif mode == 'val': # 20% = 60%->80%
images = images[int(0.6 * len(images)):int(0.8 * len(images))]
labels = labels[int(0.6 * len(labels)):int(0.8 * len(labels))]
# 测试集
else: # 20% = 80%->100%
images = images[int(0.8 * len(images)):]
labels = labels[int(0.8 * len(labels)):]
return images, labels
def preprocess(x, y):
x = tf.io.read_file(x)
x = tf.image.decode_jpeg(x, channels=3)
x = tf.image.resize(x, [244, 244])
x = tf.cast(x, dtype=tf.float32) / 255.0
y = tf.convert_to_tensor(y)
y = tf.one_hot(y, depth=5)
return x, y
if __name__ == '__main__':
cwd = './flower_photos'
batchsz = 32
# 创建训练集Datset对象
images, labels = load_data(cwd, mode='train')
db_train = tf.data.Dataset.from_tensor_slices((images, labels))
db_train = db_train.shuffle(1000).map(preprocess).batch(batchsz)
# 创建验证集Datset对象
images2, labels2 = load_data(cwd, mode='val')
db_val = tf.data.Dataset.from_tensor_slices((images2, labels2))
db_val = db_val.map(preprocess).batch(batchsz)
# 创建测试集Datset对象
images3, labels3 = load_data(cwd, mode='test')
db_test = tf.data.Dataset.from_tensor_slices((images3, labels3))
db_test = db_test.map(preprocess).batch(batchsz)
这样得到训练数据集db_train,验证数据集db_val,测试数据集db_test
step4:训练验证
# train.py
import os
import tensorflow as tf
import numpy as np
from tensorflow import keras
from tensorflow.keras import layers,optimizers,losses
from tensorflow.keras.callbacks import EarlyStopping
from load_data import load_data, preprocess
if __name__ == '__main__':
cwd = './flower_photos'
batchsz = 32
# 创建训练集Datset对象
images, labels = load_data(cwd, mode='train')
db_train = tf.data.Dataset.from_tensor_slices((images, labels))
db_train = db_train.shuffle(1000).map(preprocess).batch(batchsz)
# 创建验证集Datset对象
images2, labels2 = load_data(cwd, mode='val')
db_val = tf.data.Dataset.from_tensor_slices((images2, labels2))
db_val = db_val.map(preprocess).batch(batchsz)
# 创建测试集Datset对象
images3, labels3 = load_data(cwd, mode='test')
db_test = tf.data.Dataset.from_tensor_slices((images3, labels3))
db_test = db_test.map(preprocess).batch(batchsz)
#创建网络模型
net = keras.applications.VGG16(weights='imagenet',include_top=False,pooling='max')
net.trainable = False
newnet = keras.Sequential([
net,
layers.Dense(128),
layers.Dense(64),
layers.Dense(5)
])
newnet.build(input_shape=(4, 224, 224, 3))
newnet.summary()
early_stopping = EarlyStopping(
monitor='val_accuracy',
min_delta=0.001,
patience=5
)
newnet.compile(optimizer=optimizers.Adam(lr=1e-3),
loss=losses.CategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
# 为了节省时间,epochs取5,为了提高识别率,这里可以增大epochs
newnet.fit(db_train, validation_data=db_val, validation_freq=1, epochs=5,
callbacks=[early_stopping])
# 用测试集测试模型准确率
newnet.evaluate(db_test)
测试log如下:
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
vgg16 (Functional) (None, 512) 14714688
dense (Dense) (None, 128) 65664
dense_1 (Dense) (None, 64) 8256
dense_2 (Dense) (None, 5) 325
=================================================================
Total params: 14,788,933
Trainable params: 74,245
Non-trainable params: 14,714,688
_________________________________________________________________
/usr/local/lib/python3.8/dist-packages/keras/optimizers/optimizer_v2/adam.py:110: UserWarning: The `lr` argument is deprecated, use `learning_rate` instead.
super(Adam, self).__init__(name, **kwargs)
Epoch 1/5
69/69 [==============================] - 181s 3s/step - loss: 1.0423 - accuracy: 0.6190 - val_loss: 0.6405 - val_accuracy: 0.7684
Epoch 2/5
69/69 [==============================] - 188s 3s/step - loss: 0.5819 - accuracy: 0.7929 - val_loss: 0.5232 - val_accuracy: 0.8147
Epoch 3/5
69/69 [==============================] - 169s 2s/step - loss: 0.4582 - accuracy: 0.8361 - val_loss: 0.5095 - val_accuracy: 0.8256
Epoch 4/5
69/69 [==============================] - 187s 3s/step - loss: 0.3972 - accuracy: 0.8615 - val_loss: 0.5235 - val_accuracy: 0.8134
Epoch 5/5
69/69 [==============================] - 190s 3s/step - loss: 0.3540 - accuracy: 0.8747 - val_loss: 0.5412 - val_accuracy: 0.8202
23/23 [==============================] - 51s 2s/step - loss: 0.5609 - accuracy: 0.8202
可见识别效率为0.82,也可以调参搭建更加复杂的模型。
参考: