赞
踩
坑洼道路检测和识别是一种计算机视觉任务,旨在通过数字图像(通常是地表坑洼图像)识别出存在坑洼的道路。这对于地.质勘探、航天科学和自然灾害等领域的研究和应用具有重要意义。例如,它可以帮助在地球轨道上识别坑洼,以及分析和模拟地球表面的形态。
在坑洼道路检测任务中,传统的分类算法往往不能取得很好的效果,因为坑洼图像的特征往往是非常复杂和多变的。然而,近年来深度学习技术的发展,为坑洼道路检测提供了新的解决方案。
深度学习具有很强的特征提取和表示能力,可以从图像中自动提取出最重要的特征。在坑洼图像分类任务中,利用深度学习可以提取到坑洼的轮廓、纹理和形态等特征,并将其转换为更容易分类的表示形式。同时,还可以通过迁移学习和知识蒸馏等技术进一步提升分类性能。例如,一些研究者使用基于深度学习的方法对路图像进行分类,将其分为正常、坑洼两类;另外,一些研究者还使用基于迁移学习的方法,从通用的预训练模型中学习坑洼图像的特征,并利用这些特征来分类坑洼图像。
本赛题希望通过对已标记的道路图像进行分析、特征提取与建模,从而对于一张新的道路图像能够自动识别坑洼状态。具体任务如下:
初赛问题
问题1: 结合给出的图像文件,提取图像特征,建立一个识别率高、速度快、分类准确的模型,用于识别图像中的道路是正常或者坑洼。
问題2: 对问题1中构建的模型进行训练,并从不同维度进行模型评估。
问题3: 利用已训练的模型识别测试集中的坑洼图像,并将识别结果放在“test_result.csv’'中。(注:测试集将在竞赛结束前48小时公布下载链接,请及时关注报名网站)
附件说明:
附件1:data.zip;
训练数据集,文件中共包含301张图片。
文件名中包含“normal’'字符表示正常道路,否则为坑洼道路。
图1:正常道路示例
图2:坑洼道路示例
附件2:test_result.csv;
测试结果提交文件,文件中表头保持不变,数据仅做示例,提交的时候删除后重新填写,字段描述见下表。
表1:test_result表字段说明
字段 | 说明 |
---|---|
fnames | 测试图片的文件名 |
label | 分类标识:填写 1 和 0,1 表示正常道路 ;0 表示坑洼道路 |
附件3:test_data.zip
测试数据集,文件中包含几千张图片,具体数量以公布的数据为准。
测试数据集在竞赛结束前48小时公布下载链接,请及时关注报名网站。
首先,训练集只有301张图片,说明这个一个小样本问题。按照以下流程去建立baseline,之后再在每个部分,逐步优化。
(1)数据预处理:
(2)特征提取:
(3)可视化分析数据集:
(4)建立深度学习模型:
(5)模型评估和优化:
import os
import numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Activation, Dropout, Flatten, Dense
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.layers import Convolution2D, MaxPooling2D, ZeroPadding2D
from tensorflow.keras import optimizers
from tensorflow.keras import applications
from tensorflow.keras.models import Model
from IPython.display import Image
from tensorflow.keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img
import os
from sklearn.model_selection import train_test_split
from tensorflow.keras.preprocessing.image import ImageDataGenerator
import pandas as pd
from PIL import Image
import os
# 将图片统一像素格式,并分别存储到文件夹中
# 创建文件夹
processed_normal_dir = "data/processed_normal"
processed_wavy_dir = "data/processed_wavy"
os.makedirs(processed_normal_dir, exist_ok=True)
os.makedirs(processed_wavy_dir, exist_ok=True)
# 处理图像
data_dir = "data"
for filename in os.listdir(data_dir):
img_path = os.path.join(data_dir, filename)
img = Image.open(img_path)
# 对图像进行缩放
img = img.resize((224, 224))
# 决定图像应该存储在哪个文件夹中
if "normal" in filename:
save_dir = processed_normal_dir
else:
save_dir = processed_wavy_dir
# 保存图像
save_path = os.path.join(save_dir, filename)
img.save(save_path)
(2)数据加载
总共301张图片,选择30张图片作为测试集,1张图片单独拿出来测试,否则不好整数划分。
img_width, img_height = 224, 224
num_classes = 2
batch_size = 10
datagen = ImageDataGenerator(rescale=1./255)
X = []
y = []
normal_dir = "data/processed_normal"
wavy_dir = "data/processed_wavy"
for img_name in os.listdir(normal_dir):
img_path = os.path.join(normal_dir, img_name)
X.append(img_path)
y.append('0')
for img_name in os.listdir(wavy_dir):
img_path = os.path.join(wavy_dir, img_name)
X.append(img_path)
y.append('1')
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.1, random_state=42)
train_df = pd.DataFrame(data={'filename': X_train, 'class': y_train})
val_df = pd.DataFrame(data={'filename': X_val, 'class': y_val})
train_generator = datagen.flow_from_dataframe(
...略
validation_generator = datagen.flow_from_dataframe(
...略
Found 270 validated image filenames belonging to 2 classes.
Found 30 validated image filenames belonging to 2 classes.
(1)定义卷积网络
model = Sequential()
model.add(Convolution2D(32, (3, 3), input_shape=(img_width, img_height,3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Convolution2D(32, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Convolution2D(64, (3, 3)))
model.add(Activation('relu'))
model.add(MaxPooling2D(pool_size=(2, 2)))
model.add(Flatten())
model.add(Dense(64))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(1))
model.add(Activation('sigmoid'))
model.compile(loss='binary_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
(2)模型训练
epochs = 20
train_samples = 270
validation_samples = 30
batch_size =10
model.fit_generator(
train_generator,
steps_per_epoch=train_samples // batch_size,
epochs=epochs,
validation_data=validation_generator,
validation_steps=validation_samples// batch_size,)
model.save_weights('models/basic_cnn_20_epochs.h5')
model.load_weights('models_trained/basic_cnn_30_epochs.h5')
(3)模型验证
# 将多余出来的一张图片拿出来预测
img = load_img('data/normal1.jpg')
x = img_to_array(img)
prediction = model.predict(x.reshape((1,img_width, img_height,3)),batch_size=10, verbose=0)
print(prediction)
0
model.evaluate_generator(validation_generator, validation_samples)
[0.7280968427658081, 0.8999999761581421]
(1)数据增强
通过对训练集应用随机变换,用新的未见过的图像人为地增强了的数据集。减少过拟合,并为我们的网络提供更好的泛化能力。
train_datagen_augmented = ImageDataGenerator(
rescale=1./255, # normalize pixel values to [0,1]
shear_range=0.2, # randomly applies shearing transformation
zoom_range=0.2, # randomly applies shearing transformation
horizontal_flip=True) # randomly flip the images
train_generator_augmented = train_datagen_augmented.flow_from_dataframe(
...略
(2)模型训练
model.fit_generator(
train_generator_augmented,
steps_per_epoch=train_samples // batch_size,
epochs=epochs,
validation_data=validation_generator,
validation_steps=validation_samples // batch_size,)
(3)模型评估
model.save_weights('models/augmented_20_epochs.h5')
#model.load_weights('models_trained/augmented_30_epochs.h5')
model.evaluate_generator(validation_generator, validation_samples)
[0.2453145980834961, 0.8666666746139526]
通过使用通用的、预训练的图像分类器,可以在性能和效率方面超越以前的模型。这个例子使用了VGG16,一个在ImageNet数据集上训练的模型,该数据集包含了被分类为1000个类别的数百万张图像。
(1)加载VGG模型的权重
model_vgg =
train_generator_bottleneck = datagen.flow_from_dataframe(
dataframe=train_df,
directory=None,
x_col='filename',
y_col='class',
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='binary')
validation_generator_bottleneck = datagen.flow_from_dataframe(
dataframe=val_df,
directory=None,
x_col='filename',
y_col='class',
target_size=(img_width, img_height),
batch_size=batch_size,
class_mode='binary')
(2)用模型提取特征
bottleneck_features_train = model_vgg.predict_generator(train_generator_bottleneck, train_samples // batch_size)
np.save(open('models/bottleneck_features_train.npy', 'wb'), bottleneck_features_train)
bottleneck_features_validation = model_vgg.predict_generator(validation_generator_bottleneck, validation_samples // batch_size)
np.save(open('models/bottleneck_features_validation.npy', 'wb'), bottleneck_features_validation)
(3)读取预处理的数据
train_data = np.load(open('models/bottleneck_features_train.npy', 'rb'))
train_labels = np.array([0] * (train_samples // 2) + [1] * (train_samples // 2))
validation_data = np.load(open('models/bottleneck_features_validation.npy', 'rb'))
validation_labels = np.array([0] * (validation_samples // 2) + [1] * (validation_samples // 2))
(4)全连接网络模型训练
model_top = Sequential()
model_top.add(Flatten(input_shape=train_data.shape[1:]))
model_top.add(Dense(256, activation='relu'))
model_top.add(Dropout(0.5))
model_top.add(Dense(1, activation='sigmoid'))
model_top.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['accuracy'])
model_top.fit(train_data, train_labels,
epochs=epochs,
batch_size=batch_size,
validation_data=(validation_data, validation_labels))
model_top.save_weights('models/bottleneck_20_epochs.h5')
(5)模型评估
model_top.evaluate(validation_data, validation_labels)
[2.3494818210601807, 0.4333333373069763]
在卷积模型之上建立一个分类器模型。为了进行微调,从一个经过充分训练的分类器开始。将使用早期模型中的权重。然后把这个模型加到卷积基上
weights_path = 'weight/vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5'
model_vgg = applications.VGG16(include_top=False, weights=weights_path, input_shape=(224, 224, 3))
top_model = Sequential()
top_model.add(Flatten(input_shape=model_vgg.output_shape[1:]))
top_model.add(Dense(256, activation='relu'))
top_model.add(Dropout(0.5))
top_model.add(Dense(1, activation='sigmoid'))
top_model.load_weights('models/bottleneck_20_epochs.h5')
#model_vgg.add(top_model)
model = Model(inputs = model_vgg.input, outputs = top_model(model_vgg.output))
# 微调,只需要训练几层。这一行将设置前25层(直到conv块)为不可训练的。
for layer in model_vgg.layers[:15]:
layer.trainable = False
model.compile(loss='binary_crossentropy',
optimizer=optimizers.SGD(lr=1e-4, momentum=0.9),
metrics=['accuracy'])
数据增强
# 数据增强
train_datagen = ImageDataGenerator(
rescale=1./255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True)
test_datagen = ImageDataGenerator(rescale=1./255)
train_generator = datagen.flow_from_dataframe(
...略
validation_generator = datagen.flow_from_dataframe(
...略
模型微调
# 微调模型
model.fit_generator(
train_generator,
steps_per_epoch=train_samples // batch_size,
epochs=epochs,
validation_data=validation_generator,
validation_steps=validation_samples // batch_size)
model.save_weights('models/finetuning_20epochs_vgg.h5')
model.load_weights('models/finetuning_20epochs_vgg.h5')
模型评估
model.evaluate_generator(validation_generator, validation_samples)
[nan, 0.8666666746139526]
最后这种方式模型不收敛,说明这个网络设置过程中存在不合理的地方,比如冻结参数的层数,使用的网络模型,是否需要数据增强等因素都会影响。提供这种方式,有待同学们去改进。
以上代码是不完整的,需要完整的请下载后源文件
包括训练好的模型和权重文件
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。