使用 Keras 检测汽车损坏

引言

汽车已成为 21 世纪不可或缺的一部分,每天上路的汽车都比昨天多。这不可避免地伴随着自身的风险,一些司机的疏忽可能会对道路上的财产和其他人的健康造成轻微到严重的损害。

据世界卫生组织称,每年约有 130 万人因道路交通事故而缩短生命。另有 20 至 5000 万人遭受非致命伤害,其中许多人因受伤而致残。就经济损失而言,道路交通事故造成的损失占大多数国家国内生产总值的 3%。

在这些情况下,救护人员和急救人员需要更快的响应时间。

随着深度学习技术的发展,目标检测在图像处理中的新应用正在多个领域出现。图像分析的一个新的应用是检测车辆的外部损伤,然后可以结合目标检测分析框架来实时检测损伤。一旦检测到物联网设备,可以用来发出紧急呼叫,通知附近的服务机构。

在本文中,我们将使用深度学习来完成对车辆是否损坏的检测。

数据集

这个数据集包括从各种不同场景中拍摄的汽车图像,从现实生活中的图像到从互联网或新闻频道拍摄的汽车图像。这些图片被标记为“01-whole”,表示一辆完好无损的车辆,“00-damage”表示一辆受损的车辆,每类都有920张图片。

需要安装的库

Numpy
Pandas
Scikit-image
Matplotlib
Tensorflow
Keras
Cainvas Notebook Server

工作原理

· 我们的输入是一个由 N 个图像组成的训练数据集,每个图像都属于 2 个不同        类别之一。

· 然后,我们使用这个训练集来训练一个 ConvNet 来了解每个类的样子。

· 然后,我们通过要求分类器预测一组它以前从未见过的新图像的标签来评估分

    类器的质量。然后我们将这些图像的真实标签与分类器预测的标签进行比较。

· 最后保存模型及其权重以备将来使用。

代码

让我们从代码开始吧!

我们将使用 matplotlib 绘制图像和标签。Tensorflow 和 Keras 是最常用的深度学习框架之一,我们将使用它们来创建 ConvNet 并设计我们的模型。

import os
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.callbacks import ModelCheckpoint,EarlyStopping,ReduceLROnPlateau,LearningRateScheduler
from tensorflow.keras.preprocessing import image as ig
from tensorflow.keras.preprocessing.image import img_to_array
import random

我们将有两个目录,分别是训练和验证;每个目录下都有两个文件夹,分别对应图像及其标签。我们将使用 Keras 的 ImageDataGenerator 准备数据并获得与文件夹结构相关的适当标签。

train_dir = 'data1a/training'
test_dir = 'data1a/validation'


train_data = ImageDataGenerator(rescale = 1./255,shear_range = 0.2, zoom_range = 0.2, horizontal_flip = True)


#defining training set, here size of image is reduced to 150x150, batch of images is kept as 128 and class is defined as 'categorical'.
training_set = train_data.flow_from_directory(train_dir, batch_size = 32, target_size = (64,64), class_mode = 'categorical')


#applying same scale as training set, but only feature scaling is applied. image augmentation is avoided to prevent leakage of testing data.
test_data = ImageDataGenerator(rescale = 1./255)


#defining testing set
testing_set = test_data.flow_from_directory(test_dir, batch_size = 32, target_size = (64,64), class_mode = 'categorical')

在这里定义了checkpoints,指定何时保存模型并实施提前停止以提高训练过程的效率。

checkpoint = ModelCheckpoint(
    './base.model',
    monitor='val_accuracy',
    verbose=1,
    save_best_only=True,
    mode='max',
    save_weights_only=False,
    save_frequency=1
)
earlystop = EarlyStopping(
    monitor='val_loss',
    min_delta=0.001,
    patience=30,
    verbose=1,
    mode='auto'
)


opt1 = tf.keras.optimizers.Adam()


callbacks = [checkpoint,earlystop]

我们的模型结构由4个 Conv2D 层组成,包括输入层和一个2x2的 MaxPool2D 池层,每层之后是一个紧密的64个神经元层和一个 ReLU 激活函数,最后一层是2个神经元和 softmax 激活函数用于我们的类预测的。

本文中我们使用 Adam 作为优化器,使用交叉熵损失函数,对模型进行了100次迭代训练。

model = tf.keras.Sequential([
    tf.keras.layers.Conv2D(32, 3, activation='relu', input_shape=(64,64,3)),
    tf.keras.layers.MaxPool2D(pool_size=(2,2)),
    tf.keras.layers.Dropout(0.3),
    tf.keras.layers.Conv2D(32, 3, activation='relu'),
    tf.keras.layers.MaxPool2D(pool_size=(2,2)),
    tf.keras.layers.Dropout(0.3),
    tf.keras.layers.Conv2D(32, 3, activation='relu'),
    tf.keras.layers.MaxPool2D(pool_size=(2,2)),
    tf.keras.layers.Dropout(0.3),
    tf.keras.layers.Conv2D(32, 3, activation='relu'),
    tf.keras.layers.MaxPool2D(pool_size=(2,2)),
    tf.keras.layers.Dropout(0.3),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(64, activation='relu'),
    tf.keras.layers.Dropout(0.5),
    tf.keras.layers.Dense(2, activation='softmax')
])


model.summary()


# Compile the model
model.compile(loss=tf.keras.losses.CategoricalCrossentropy(),
              optimizer=opt1,
              metrics=['accuracy'])


# Fit the model
history = model.fit(training_set,
                    epochs=100,
                    steps_per_epoch=len(training_set),
                    validation_data=testing_set,
                    validation_steps=len(testing_set),
                    callbacks=callbacks)

下面是模型的架构。

Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 62, 62, 32)        896       
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 31, 31, 32)        0         
_________________________________________________________________
dropout (Dropout)            (None, 31, 31, 32)        0         
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 29, 29, 32)        9248      
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 14, 14, 32)        0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 14, 14, 32)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 12, 12, 32)        9248      
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 6, 6, 32)          0         
_________________________________________________________________
dropout_2 (Dropout)          (None, 6, 6, 32)          0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 4, 4, 32)          9248      
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 2, 2, 32)          0         
_________________________________________________________________
dropout_3 (Dropout)          (None, 2, 2, 32)          0         
_________________________________________________________________
flatten (Flatten)            (None, 128)               0         
_________________________________________________________________
dense (Dense)                (None, 64)                8256      
_________________________________________________________________
dropout_4 (Dropout)          (None, 64)                0         
_________________________________________________________________
dense_1 (Dense)              (None, 2)                 130       
=================================================================
Total params: 37,026
Trainable params: 37,026
Non-trainable params: 0
_________________________________________________________________

这是一个绘制损失和准确度的函数,我们将在训练模型后得到它。保存模型并使用定义的函数绘制结果。

def show_final_history(history):
    fig, ax = plt.subplots(1, 2, figsize=(15,5))
    ax[0].set_title('loss')
    ax[0].plot(history.epoch, history.history["loss"], label="Train loss")
    ax[0].plot(history.epoch, history.history["val_loss"], label="Validation loss")
    ax[1].set_title('acc')
    ax[1].plot(history.epoch, history.history["accuracy"], label="Train acc")
    ax[1].plot(history.epoch, history.history["val_accuracy"], label="Validation acc")
    ax[0].legend()
    ax[1].legend()
    
show_final_history(history)
model.save("model.h5")
print("Weights Saved")

结果

损失和精度随时间的变化。

该模型达到了 87.174% 的验证准确率,还是不错的。

Epoch 00065: val_accuracy did not improve from 0.86304
58/58 [==============================] - 8s 146ms/step - loss: 0.3591 - accuracy: 0.8387 - val_loss: 0.3900 - val_accuracy: 0.8500
Epoch 66/100
58/58 [==============================] - ETA: 0s - loss: 0.3876 - accuracy: 0.8301
Epoch 00066: val_accuracy improved from 0.86304 to 0.87174, saving model to ./base.model
INFO:tensorflow:Assets written to: ./base.model/assets
58/58 [==============================] - 10s 164ms/step - loss: 0.3876 - accuracy: 0.8301 - val_loss: 0.3700 - val_accuracy: 0.8717
Epoch 67/100
58/58 [==============================] - ETA: 0s - loss: 0.3760 - accuracy: 0.8436
Epoch 00067: val_accuracy did not improve from 0.87174
58/58 [==============================] - 8s 145ms/step - loss: 0.3760 - accuracy: 0.8436 - val_loss: 0.3672 - val_accuracy: 0.8630

预测

从测试图片中选取了16张图片,并在使用模型进行预测之后,将其中的9张图片与相应的真实和预测标签一起绘制出来。

labels = ["00-damage","01-whole"]


it = iter(testing_set)
batch = next(it) # Gets a batch of 16 test images


fig, axes = plt.subplots(3, 3, figsize=(10,10))
fig.tight_layout()
fig.subplots_adjust(hspace=.25)


for i in range(3):
    for j in range(3):
        ax = axes[i,j]
        image = batch[0][i*3+j]
        net_input = image.reshape((1, 64, 64, 3))
        truth = np.argmax(batch[1][i*3+j])
        prediction = np.argmax(model.predict(net_input))
        ax.set_title('Label: %s\nPrediction: %s' % (labels[truth].capitalize(), labels[prediction].capitalize()))
        ax.imshow(image)

在这里,我定义了一个函数,它对用户可以提供的自定义图像进行预测。该算法以图像路径为参数,在模型预测完成后,用预测标签对图像进行标记。

def custom_predictions(path):
    img = ig.load_img(path, target_size=(64, 64))
    plt.imshow(img)
    img = np.expand_dims(img, axis=0)
    img.reshape(1,64,64,3)
    prediction = np.argmax(model.predict(img))
    plt.title(labels[prediction])
    plt.show()

下面是模型的一些预测:

总结

在本文中我们学习了如何使用从头构建的ConvNet模型来检测车辆是否损坏。这个简单的用例可以作为一个模块加入到目标检测和嵌入式设备中,想想还是不错的呢~

·  END  ·

HAPPY LIFE

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值