DataFountain-交通标志分类识别:CNN多分类 精度0.97
https://aistudio.baidu.com/aistudio/projectdetail/3171955
转载自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” | 图片 |
label | 0 ~ 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()
annotations | filename | label | |
---|---|---|---|
4768 | {'filename': 'train/M4/02884.jpg', 'label': 2} | train/M4/02884.jpg | 2 |
906 | {'filename': 'train/M7/00042.jpg', 'label': 5} | train/M7/00042.jpg | 5 |
2991 | {'filename': 'train/M4/01997.jpg', 'label': 2} | train/M4/01997.jpg | 2 |
4515 | {'filename': 'train/M4/00663.jpg', 'label': 2} | train/M4/00663.jpg | 2 |
2401 | {'filename': 'train/M4/01789.jpg', 'label': 2} | train/M4/01789.jpg | 2 |
标签分析
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([])
定义数据集
# 定义数据集
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)
总结和展望
- 本文使用预训练模型完成交通标注分类。
- 可以考虑加入交叉验证训练多个模型,以此增加模型精度。
更多推荐
所有评论(0)