数据集 ??
图片简介
这项任务是预测树叶图像的类别。?该数据集包含176个类别,18353幅图像。?每个类别至少有50幅图像用于训练。
图片样品
代码实现
引入相关类库
import pandas as pd
import tensorflow as tf
import matplotlib.pyplot as plt
?使用pandas读取csv文件,csv有两列,一列是图片位置,另一列是对应的标签。
df = pd.read_csv('../input/classify-leaves/train.csv')
df
?
csv的图像位置不完全正确,需要改成正确的相对位置(以当前运行目录为基准)。
df["image"] = "../input/classify-leaves/" + df["image"]
df
?
使用sample对dataframe文件进行打乱,frac=1是全选的意思,并重置索引,丢弃原索引。因为dataframe的真实排列是以索引为准,如果不更正索引,即使表面上看行被打乱,实际数据的排列也会跟原来一样。
df = df.sample(frac=1).reset_index(drop = True)
取90%的数据集作为训练数据,取另外10%作为测试数据。
train_df = df[1800:]
test_df = df[:1800]
构建训练数据集和验证数据集的迭代器,preprocessing_function使用tf.keras的mobilenet_v2,对数据集进行归一化处理,使用了preprocessing_function之后就不能再使用rescale,不然会重复处理。这里的validation_split=0.11是把训练集切11%出来作为验证集,这样整体的训练集:验证集:测试集 = 8: 1: 1。rotation_range、width_shift_range等操作是数据增强的方法,这里暂时不用,因为会大大增大训练的量。
train_generator = tf.keras.preprocessing.image.ImageDataGenerator(
preprocessing_function=tf.keras.applications.mobilenet_v2.preprocess_input,
validation_split=0.11,
# rotation_range=360,
# width_shift_range=0.1,
# height_shift_range=0.1,
# shear_range=0.1,
# zoom_range=0.1,
# horizontal_flip=True,
# vertical_flip=True,
)
同样,也需要一个测试集的迭代器。因为要用真实的数据测试,所以不会使用数据增强。
test_generator = tf.keras.preprocessing.image.ImageDataGenerator(
preprocessing_function=tf.keras.applications.resnet50.preprocess_input
)
?训练批量为 128。
BATCH_SIZE = 128
使用train_generator,从dataframe中产生对应的训练集和验证集。
train_images = train_generator.flow_from_dataframe(
dataframe=train_df,
x_col='image',
y_col='label',
color_mode='rgb',
class_mode='categorical',
target_size=(224, 224),
batch_size=BATCH_SIZE,
shuffle=True,
subset='training'
)
//Found 14733 validated image filenames belonging to 176 classes.
val_images = train_generator.flow_from_dataframe(
dataframe=train_df,
x_col='image',
y_col='label',
color_mode='rgb',
class_mode='categorical',
target_size=(224, 224),
batch_size=BATCH_SIZE,
shuffle=True,
subset='validation'
)
//Found 1820 validated image filenames belonging to 176 classes.
同样,使用 test_generator 产生测试集。
test_images = test_generator.flow_from_dataframe(
dataframe=test_df,
x_col='image',
y_col='label',
color_mode='rgb',
class_mode='categorical',
target_size=(224, 224),
batch_size=BATCH_SIZE,
shuffle=True,
)
//Found 1800 validated image filenames belonging to 176 classes.
?模型搭建,使用迁移学习,以ResNet50为主模型。
def create_model(input_shape=(224, 224, 3)):
inputs = tf.keras.layers.Input(input_shape)
base_model = tf.keras.applications.ResNet50(
input_shape=(224, 224, 3), # 图片尺寸是 224 x 224 , 3 频道(RGB)。
weights='imagenet', # imagenet权重
pooling='avg', # 平均池化
include_top=False
)
base_model.trainable = False # 只训练最后一层的参数,其他保持不动。
x = base_model(inputs)
x = tf.keras.layers.Dense(256, activation='relu')(x) # 全连接层
x = tf.keras.layers.Dropout(0.25)(x) # dropout层
outputs = tf.keras.layers.Dense(176, activation='softmax')(x) # 输出176种树叶分类情况
model = tf.keras.models.Model(inputs, outputs)
return model
实例化模型
model = create_model(input_shape = (224, 224, 3))
?模型的编译,使用adam优化器,使用交叉熵,标尺是准确率。
model.compile(
optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy']
)
?模型概况
model.summary()
Model: "functional_1"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_3 (InputLayer) [(None, 224, 224, 3)] 0
_________________________________________________________________
resnet50 (Functional) (None, 2048) 23587712
_________________________________________________________________
dense_1 (Dense) (None, 256) 524544
_________________________________________________________________
dropout (Dropout) (None, 256) 0
_________________________________________________________________
dense_2 (Dense) (None, 176) 45232
=================================================================
Total params: 24,157,488
Trainable params: 569,776
Non-trainable params: 23,587,712
正式训练
history = model.fit(
train_images,
validation_data=val_images,
epochs=150,
callbacks=[
tf.keras.callbacks.EarlyStopping( # 提前停止,防止过拟合
monitor='val_loss', # 监控验证集的损失
patience=5, # 最多忍耐5个epoch
restore_best_weights=True # 当停止时,恢复最佳的权重参数
)
]
)
?展示前5个epoch
Epoch 1/150
116/116 [==============================] - 45s 390ms/step - loss: 3.3070 - accuracy: 0.2583 - val_loss: 1.7681 - val_accuracy: 0.5522
Epoch 2/150
116/116 [==============================] - 43s 373ms/step - loss: 1.5507 - accuracy: 0.5736 - val_loss: 1.1069 - val_accuracy: 0.7082
Epoch 3/150
116/116 [==============================] - 44s 375ms/step - loss: 1.0763 - accuracy: 0.6924 - val_loss: 0.8298 - val_accuracy: 0.7846
Epoch 4/150
116/116 [==============================] - 44s 375ms/step - loss: 0.8250 - accuracy: 0.7579 - val_loss: 0.7166 - val_accuracy: 0.8033
Epoch 5/150
116/116 [==============================] - 44s 378ms/step - loss: 0.6627 - accuracy: 0.8061 - val_loss: 0.6385 - val_accuracy: 0.8143
?使用测试集对模型进行测试
results = model.evaluate(test_images)
|