深度学习实验——车牌号识别
这次实验可以说是一夜回到解放前,感觉思路没问题但就是各种错误,这个张量维度愣是没搞清楚到底哪里错了,所以精度的曲线还没弄出来,学习了一些怎么把未分类数据制作成自己的数据集,逻辑差不多懂了,但估计离自己能敲出来的距离还远的不行。
- 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
- 🍖 原作者:K同学啊
目录
一、实验
1、实验目的
①学习如何将没有分类的数据制作成数据集进行处理
②尽量做到对单张车牌进行识别
2、相关知识点
① classeNames=[str(path).split('\\')[1].split('_')[1].split('.')[0] for path in data_paths]代码解读
其实就是对path对象转化成字符串,然后利用分割符和索引得到车牌号,完整的字符串如下:
本实验的网络结构

实验结果

3、错误及解决方案
①shape '[2, 7, 69]' is invalid for input of size 1

注意这里fc函数的参数只有两个
②The size of tensor a (16) must match the size of tensor b (7) at non-singleton dimension 1
错误原因:这个错误是 PyTorch 中典型的张量维度不匹配问题,核心是两个张量(a 和 b)在第 1 维(PyTorch 是 0 索引,所以 dimension 1 是第二维)的尺寸不一致(一个是 16,一个是 7),而执行的操作(比如相加、计算损失、矩阵运算等)要求这两个维度必须完全相同
4、总结
这次实验可以说是一夜回到解放前,感觉思路没问题但就是各种错误,这个张量维度愣是没搞清楚到底哪里错了,所以精度的曲线还没弄出来,学习了一些怎么把未分类数据制作成自己的数据集,逻辑差不多懂了,但估计离自己能敲出来的距离还远的不行
二、代码实现
1、前期准备
①导入库并设置GPU
from tkinter import Variable
import torch
import torch.nn as nn
import torchvision
import torchvision.transforms as transforms
from torchvision import datasets,transforms
import matplotlib.pyplot as plt
import torch.nn.functional as F
import torchvision.models as models
from torch.utils.data import DataLoader
import os,PIL,random,pathlib,warnings
#支持中文,主要用于正常显示中文标签和显示负号
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
warnings.filterwarnings('ignore')
device=torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
device
②导入并测试数据集
#导入数据并转化为pathlib对象
data_dir="./data"
data_dir=pathlib.Path(data_dir)
data_paths=list(data_dir.glob('*'))
classeNames=[str(path).split('\\')[1].split('_')[1].split('.')[0] for path in data_paths]
classeNames
data_paths_str
#%%
#数据可视化
plt.figure(figsize=(14,5))
plt.suptitle("数据展示",fontsize=15)
for i in range(18):
plt.subplot(3,6,i+1)
#显示图像
images=plt.imread(data_paths_str[i])
plt.imshow(images)
plt.show()
获得的车牌读取结果和数据可视化结果如下


将标签数字化并加载
#标签数字化
import numpy as np
char_enum=['京','沪','津','渝','冀','晋','蒙','辽','吉','黑','苏','浙','皖','闽','赣','鲁','豫','鄂','湘','粤',\
'桂','琼','川','贵','云','藏','陕','甘','青','宁','新','军','使']
number=[str(i) for i in range(0,10)]
alphabet=[chr(i) for i in range(65,91)]
char_set=char_enum+number+alphabet
char_set_len=len(char_set)
label_name_len=len(classeNames[0])
#将字符串数字化
def text2vec(text):
vector=np.zeros([label_name_len,char_set_len])
for i,c in enumerate(text):
idx=char_set.index(c)
vector[i][idx]=1.0
return vector
all_labels=[text2vec(i) for i in classeNames]
#开始加载数据文件
import os
import pandas as pd
from torchvision.io import read_image
import torch.utils.data as data
from PIL import Image
class MyDataset(data.Dataset):
def __init__(self,all_labels,data_paths_str,transform):
#获取标签信息、图像目标路径和目标转换函数
self.img_labels=all_labels
self.img_dir=data_paths_str
self.transform=transform
def __len__(self):
return len(self.img_labels)
def __getitem__(self, index):
#将图像转换为RGB格式
image=Image.open(self.img_dir[index]).convert('RGB')
label=self.img_labels[index]
if self.transform:
image=self.transform(image)
#返回图像和标签
return image,label
接下来是一些基本操作,比如利用transforms对数据进行处理,对数据集进行划分、观察数据的数量、形状等等,代码和前几次实验一样,这里就省略了,将重心放在数据集的处理和网络模型的架构
2、构建网络
①了解网络架构
网络结构如前面所展示的一样,这里省略
②实现模型
class Network_bn(nn.Module):
def __init__(self):
super(Network_bn, self).__init__()
self.conv1 = nn.Conv2d(in_channels=3, out_channels=12, kernel_size=5, stride=1, padding=0)
self.bn1 = nn.BatchNorm2d(12)
self.conv2 = nn.Conv2d(in_channels=12, out_channels=12, kernel_size=5, stride=1, padding=0)
self.bn2 = nn.BatchNorm2d(12)
self.pool = nn.MaxPool2d(2,2)
self.conv4 = nn.Conv2d(in_channels=12, out_channels=24, kernel_size=5, stride=1, padding=0)
self.bn4 = nn.BatchNorm2d(24)
self.conv5 = nn.Conv2d(in_channels=24, out_channels=24, kernel_size=5, stride=1, padding=0)
self.bn5 = nn.BatchNorm2d(24)
self.fc1 = nn.Linear(24*50*50, label_name_len*char_set_len)
self.reshape = Reshape([label_name_len,char_set_len])
def forward(self, x):
x = F.relu(self.bn1(self.conv1(x)))
x = F.relu(self.bn2(self.conv2(x)))
x = self.pool(x)
x = F.relu(self.bn4(self.conv4(x)))
x = F.relu(self.bn5(self.conv5(x)))
x = self.pool(x)
x = x.view(-1, 24*50*50)
x = self.fc1(x)
# 最终reshape
x = self.reshape(x)
return x
# 定义Reshape层
class Reshape(nn.Module):
def __init__(self, shape):
super(Reshape, self).__init__()
self.shape = shape
def forward(self, x):
return x.view(x.size(0), *self.shape)
device = "cuda" if torch.cuda.is_available() else "cpu"
print("Using {} device".format(device))
model = Network_bn().to(device)
model
③打印模型(注意这里的参数量可以根据公式进行计算)

3、训练模型
训练函数和测试函数的编写,原理基本上没变,但是真的没想通这个acc为啥会报维度不匹配,这周暂时来不及找出来了,等我找到原因再补充上来
from torch.autograd import Variable
def test(model, test_loader, loss_model):
size = len(test_loader.dataset)
num_batches = len(test_loader)
model.eval()
test_loss, correct = 0, 0
with torch.no_grad():
for X, y in test_loader:
X, y = X.to(device), y.to(device)
pred = model(X)
test_loss += loss_model(pred, y).item()
#correct+=(pred.argmax(1)==y).type(torch.float).sum().item()
test_loss /= num_batches
#correct/=size
print(f"Avg loss: {test_loss:>8f} \n")
return test_loss
def train(model,train_loader,loss_model,optimizer):
model=model.to(device)
model.train()
for i, (images, labels) in enumerate(train_loader, 0): #0是标起始位置的值。
images = Variable(images.to(device))
labels = Variable(labels.to(device))
optimizer.zero_grad()
outputs = model(images)
loss = loss_model(outputs, labels)
loss.backward()
optimizer.step()
if i % 1000 == 0:
print('[%5d] loss: %.3f' % (i, loss))
#%%
test_acc_list = []
test_loss_list = []
epochs = 30
for t in range(epochs):
print(f"Epoch {t+1}\n-------------------------------")
train(model,train_loader,loss_model,optimizer)
#test_acc,test_loss = test(model, test_loader, loss_model)
test_loss = test(model, test_loader, loss_model)
#test_acc_list.append(test_acc)
test_loss_list.append(test_loss)
print("Done!")
得到的部分epoch训练结果如下

4、结果可视化

更多推荐


所有评论(0)