转载自AI Studio
项目链接https://aistudio.baidu.com/aistudio/projectdetail/3171955

赛题名称

交通标志分类识别,https://www.datafountain.cn/competitions/553

赛题背景

目标检测在自动驾驶等方面有着广泛的应用前景,在自动驾驶场景中,需要对交通标志(如限速标志等)进行识别以采取不同的驾驶策略。此赛题旨在使用Oneflow框架识别确定图像中显示的交通标志的类型,并且对不同的环境(如光线、障碍物或标志距离)具有鲁棒性。

赛题任务

此赛题的数据集由云测数据提供。比赛数据集中包含6358张真实场景下行车记录仪采集的图片,我们选取其中95%的图片作为训练集,5%的图片作为测试集。参赛者需对测试集中的交通标志进行分类识别。数据集中共有10种细分的交通标志标签。

数据简介

本赛题的数据集包含6358张人工标注的类别标签。标签包括以下10种类别:“GuideSign”, “M1”, “M4, “M5”, “M6”, “M7”, “P1”, “P10_50”, “P12”, “W1”,分别对应十个不同的交通标识类别。所有数据已经按比例人工划分为了训练集和测试集,并且提供了相关的训练集标注的json文件。

数据说明

数据集包含train和test两个文件夹,以及一个统一的train.json文件用来保存所有训练数据集的标注,图片标签将字典以json格式序列化进行保存,所有的标注都保存在train.json文件中的名为annotations的key下,其中每个训练文件都包含以下属性:

列名示例作用
filename示例“train/W1/00123.jpg”图片
label0 ~ 9的整型数据每张图片对应的类别标注
# 解压数据集
!echo y | unzip test_dataset.zip > log.log
!echo y | unzip train_dataset.zip > log.log
replace test/.DS_Store? [y]es, [n]o, [A]ll, [N]one, [r]ename: replace test/GuideSign/00004.jpg? [y]es, [n]o, [A]ll, [N]one, [r]ename:  NULL
(EOF or read error, treating as "[N]one" ...)
replace train.json? [y]es, [n]o, [A]ll, [N]one, [r]ename: replace train/GuideSign/00001.jpg? [y]es, [n]o, [A]ll, [N]one, [r]ename:  NULL
(EOF or read error, treating as "[N]one" ...)
import io, cv2
import math, json
import numpy as np
import pandas as pd
from PIL import Image

import matplotlib.pyplot as plt
import paddle
import paddle.nn.functional as F
import paddle.vision.transforms as T
from paddle.io import DataLoader, Dataset

import warnings
warnings.filterwarnings("ignore")

paddle.__version__
'2.2.1'

数据读取

# 读取数据集
train_json = pd.read_json('train.json')
train_json = train_json.sample(frac=1.0)

train_json['filename'] = train_json['annotations'].apply(lambda x: x['filename'])
train_json['label'] = train_json['annotations'].apply(lambda x: x['label'])
train_json.head()
annotationsfilenamelabel
4768{'filename': 'train/M4/02884.jpg', 'label': 2}train/M4/02884.jpg2
906{'filename': 'train/M7/00042.jpg', 'label': 5}train/M7/00042.jpg5
2991{'filename': 'train/M4/01997.jpg', 'label': 2}train/M4/01997.jpg2
4515{'filename': 'train/M4/00663.jpg', 'label': 2}train/M4/00663.jpg2
2401{'filename': 'train/M4/01789.jpg', 'label': 2}train/M4/01789.jpg2

标签分析

train_json['label'].value_counts()
2    3206
0    1171
5     469
6     249
1     247
3     213
9     145
4     134
7      95
8      95
Name: label, dtype: int64

数据可视化

plt.figure(figsize=(10, 10))
for idx in range(10):
    plt.subplot(1, 10, idx+1)
    img = cv2.imread(train_json['filename'].iloc[idx])
    plt.imshow(img)
    plt.xticks([]); plt.yticks([])

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LqmPtxIz-1646557139794)(output_8_0.png)]

定义数据集

# 定义数据集
class WeatherDataset(Dataset):
    def __init__(self, df):
        super(WeatherDataset, self).__init__()
        self.df = df
    
        # 数据扩增方法
        self.transform = T.Compose([
            T.Resize(size=(128,128)),
            T.RandomCrop(size=(125, 125)),
            T.RandomRotation(10),
            T.RandomHorizontalFlip(),
            T.RandomVerticalFlip(),
            T.ToTensor(),
            T.Normalize(mean=0.5, std=0.5)
        ])

    def __getitem__(self, index):
        file_name = self.df['filename'].iloc[index]
        img = Image.open(file_name)
        img = self.transform(img)
        return img, paddle.to_tensor(self.df['label'].iloc[index])

    def __len__(self):
        return len(self.df)
# 训练集
train_dataset = WeatherDataset(train_json.iloc[:-500])
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)

# 验证集
val_dataset = WeatherDataset(train_json.iloc[-500:])
val_loader = DataLoader(val_dataset, batch_size=64, shuffle=True)

定义模型

from paddle.vision.models import resnet18

# 定义模型
class WeatherModel(paddle.nn.Layer):
    def __init__(self):
        super(WeatherModel, self).__init__()
        backbone = resnet18(pretrained=True)
        backbone.fc = paddle.nn.Identity()
        self.backbone = backbone
        self.fc1 = paddle.nn.Linear(512, 10)

    def forward(self, x):
        out = self.backbone(x)
        logits1 = self.fc1(out)
        return logits1
model = WeatherModel()
model(paddle.to_tensor(np.random.rand(10, 3, 125, 125).astype(np.float32)))
INFO:paddle.utils.download:unique_endpoints {''}
INFO:paddle.utils.download:File /home/aistudio/.cache/paddle/hapi/weights/resnet18.pdparams md5 checking...
INFO:paddle.utils.download:Found /home/aistudio/.cache/paddle/hapi/weights/resnet18.pdparams





Tensor(shape=[10, 10], dtype=float32, place=CUDAPlace(0), stop_gradient=False,
       [[-0.37282717, -1.44410491,  2.63437510, -2.81383824, -3.12258291,
         -1.17227054,  3.59805036, -2.73812771,  0.46290591, -0.74933529],
        [ 1.36500943,  1.45059299,  2.27306843,  0.33235925,  1.15991616,
         -1.78793478,  0.65021646,  2.09286666, -0.61341429, -0.42210904],
        [ 0.61555719,  0.34572032,  2.55454969, -1.62235689, -1.28327560,
         -0.76703298,  2.29388309,  0.41048735,  0.47739795, -0.02906127],
        [ 3.28041601, -1.32344878,  1.24475110, -0.38508305, -1.90133715,
         -2.13186669,  1.96412265,  0.56901968,  0.11999279, -3.88312984],
        [ 0.58628517,  0.27162051,  5.21392012, -0.03644732, -1.84573472,
         -2.29608774,  2.66224504, -2.59478736,  1.21246040, -2.77956533],
        [ 1.14719808,  0.56146049,  4.02925348, -0.96473879, -1.80537641,
         -0.79135138,  1.91566205, -1.61635399,  0.07024387,  0.13627818],
        [ 1.09440255,  0.84373224,  1.67031145,  0.70455575, -1.37957299,
         -0.15965174,  1.96834600, -1.22551548, -0.72369385, -1.81768537],
        [-0.91374534,  1.19498718,  2.74177504, -0.39666989, -1.70040941,
         -2.80885339,  1.87275720,  0.26069462,  0.21966812, -0.10263307],
        [-0.23659694,  2.50902963,  2.50226021, -2.54580498, -1.76611364,
          0.73048246,  1.79844737, -1.29317212, -0.16357461, -0.59135598],
        [-2.66113043,  3.61094975,  4.15898514, -3.46278071, -0.68496394,
          1.77502155,  2.48067760, -0.90750027,  1.63268077,  1.54329979]])

模型训练与验证

# 优化器与损失函数
optimizer = paddle.optimizer.Adam(parameters=model.parameters(), learning_rate=0.0001)
criterion = paddle.nn.CrossEntropyLoss()

# 模型训练与验证
for epoch in range(0, 4):
    Train_Loss, Val_Loss = [], []
    Train_ACC1 = []
    Val_ACC1 = []
    
    model.train()
    for i, (x, y1) in enumerate(train_loader):
        pred1 = model(x)
        loss = criterion(pred1, y1)
        Train_Loss.append(loss.item())
        loss.backward()
        optimizer.step()
        optimizer.clear_grad()

        Train_ACC1.append((pred1.argmax(1) == y1.flatten()).numpy().mean())

    model.eval()
    for i, (x, y1) in enumerate(val_loader):
        pred1 = model(x)
        loss = criterion(pred1, y1)
        Val_Loss.append(loss.item())
        Val_ACC1.append((pred1.argmax(1) == y1.flatten()).numpy().mean())

    if epoch % 1 == 0:
        print(f'\nEpoch: {epoch}')
        print(f'Loss {np.mean(Train_Loss):3.5f}/{np.mean(Val_Loss):3.5f}')
        print(f'ACC {np.mean(Train_ACC1):3.5f}/{np.mean(Val_ACC1):3.5f}')

Epoch: 0
Loss 0.18275/0.13563
ACC 0.94767/0.96439

Epoch: 1
Loss 0.10761/0.10419
ACC 0.96875/0.96980

Epoch: 2
Loss 0.07932/0.09877
ACC 0.97927/0.97912

Epoch: 3
Loss 0.06132/0.10136
ACC 0.98272/0.97566

模型预测

import glob
test_df = pd.DataFrame({'filename': glob.glob('./test/*/*.jpg')})
test_df['label'] = 0
test_df = test_df.sort_values(by='filename')
test_dataset = WeatherDataset(test_df)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False)
model.eval()
pred = []

# 模型预测
for i, (x, y1) in enumerate(test_loader):
    pred1 = model(x)
    pred += pred1.argmax(1).numpy().tolist()

test_df['label'] = pred

test_df['label'].value_counts()
2    171
0     65
5     25
6     15
3     11
1     11
9      8
8      6
7      6
4      6
Name: label, dtype: int64
submit_json = {
    'annotations':[]
}

# 生成提交结果文件
for row in test_df.iterrows():
    submit_json['annotations'].append({
        'filename': 'test_images/' + row[1].filename.split('/')[-1],
        'label': row[1].label,
    })

with open('submit.json', 'w') as up:
    json.dump(submit_json, up)

总结和展望

  1. 本文使用预训练模型完成交通标注分类。
  2. 可以考虑加入交叉验证训练多个模型,以此增加模型精度。

Logo

学大模型,用大模型上飞桨星河社区!每天8点V100G算力免费领!免费领取ERNIE 4.0 100w Token >>>

更多推荐