尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Pytorch实现车牌识别

Pytorch实现车牌识别 我的环境语言环境Python 3.12.7编译器jupyter notebook深度学习环境TensorFlow 2.18.0一、导入数据from torchvision.transforms import transforms from torch.utils.data import DataLoader from torchvision import datasets import torchvision.models as models import torch.nn.functional as F import torch.nn as nn import torch,torchvision device torch.device(cuda if torch.cuda.is_available() else cpu) deviceimport os import pathlib import matplotlib.pyplot as plt # 支持中文 plt.rcParams[font.sans-serif] [SimHei] # 用来正常显示中文标签 plt.rcParams[axes.unicode_minus] False # 用来正常显示负号 data_dir E:/Jupyter/MR_K/10/015_licence_plate/ data_dir pathlib.Path(data_dir) data_paths list(data_dir.glob(*)) classeNames [] for path in data_paths: path_str str(path) parts path_str.split(\\) if len(parts) 1: filename parts[-1] # 获取最后一部分即文件名 filename_parts filename.split(_) if len(filename_parts) 1: class_name filename_parts[1].split(.)[0] classeNames.append(class_name) print(classeNames)import matplotlib.pyplot as plt plt.figure(figsize(14,5)) plt.suptitle(数据示例K同学啊,fontsize15) for i in range(18): plt.subplot(3,6,i1) # plt.xticks([]) # plt.yticks([]) # plt.grid(False) # 显示图片 images plt.imread(data_paths_str[i]) plt.imshow(images) plt.show()字符集定义char_enum定义了车牌号中可能出现的汉字字符包括各省市简称等共32个字符。number通过列表推导式生成0到9的数字字符列表。alphabet通过列表推导式生成A到Z的大写字母字符列表。char_set将上述三个列表合并得到包含所有可能字符的字符集共64个字符。char_set_len计算字符集的长度即64。字符串数字化函数text2vec输入参数为一个车牌号字符串text。首先创建一个形状为(label_name_len, char_set_len)的全零矩阵vector其中label_name_len应为车牌号的长度但代码中未定义该变量这是一个错误。通过遍历车牌号字符串中的每个字符找到该字符在char_set中的索引idx然后将vector中对应位置的值设为1.0最终返回该向量。车牌号向量化all_labels通过列表推导式将classeNames代码中未定义该变量应为一个包含车牌号字符串的列表中的每个车牌号字符串转换为向量形式并存储在列表中。import numpy as np char_enum [京,沪,津,渝,冀,晋,蒙,辽,吉,黑,苏,浙,皖,闽,赣,鲁,\ 豫,鄂,湘,粤,桂,琼,川,贵,云,藏,陕,甘,青,宁,新,军,使] number [str(i) for i in range(0, 10)] # 0 到 9 的数字 alphabet [chr(i) for i in range(65, 91)] # A 到 Z 的字母 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]导入库os用于操作文件和目录。pandas用于数据处理和分析。torchvision.io用于读取图像。torch.utils.data用于构建数据集和数据加载器。PIL用于图像处理。定义数据集类MyDataset__init__方法初始化数据集类接收三个参数all_labels包含图像标签的列表。data_paths_str包含图像路径的列表。transform图像转换函数用于对图像进行预处理。self.img_labels存储图像标签。self.img_dir存储图像路径。self.transform存储图像转换函数。实现__len__方法返回数据集的长度即图像的数量。实现__getitem__方法接收一个索引index返回对应索引的图像和标签。使用PIL.Image.open读取图像并转换为 RGB 格式。获取图像对应的标签。如果定义了transform则对图像进行转换。返回图像和标签。import os import pandas as pd from torchvision.io import read_image from torch.utils.data import Dataset 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): image Image.open(self.img_dir[index]).convert(RGB)#plt.imread(self.img_dir[index]) # 使用 torchvision.io.read_image 读取图像 label self.img_labels[index] # 获取图像对应的标签 if self.transform: image self.transform(image) return image, label # 返回图像和标签定义数据集路径total_datadir定义了数据集的根目录路径。图像变换train_transforms使用torchvision.transforms.Compose组合多个图像变换操作。transforms.Resize([224, 224])将输入图像调整为224x224像素。transforms.ToTensor()将PIL Image或numpy.ndarray转换为Tensor并归一化到[0,1]之间。transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225])对图像进行标准化处理使模型更容易收敛。均值和标准差是从数据集中随机抽样计算得到的。创建数据集实例total_data创建MyDataset实例传入标签列表all_labels、图像路径列表data_paths_str和图像变换train_transforms。total_datadir E:/Jupyter/MR_K/10/03_traffic_sign/ # 关于transforms.Compose的更多介绍可以参考https://blog.csdn.net/qq_38251616/article/details/124878863 train_transforms transforms.Compose([ transforms.Resize([224, 224]), # 将输入图片resize成统一尺寸 transforms.ToTensor(), # 将PIL Image或numpy.ndarray转换为tensor并归一化到[0,1]之间 transforms.Normalize( # 标准化处理--转换为标准正太分布高斯分布使模型更容易收敛 mean[0.485, 0.456, 0.406], std [0.229, 0.224, 0.225]) # 其中 mean[0.485,0.456,0.406]与std[0.229,0.224,0.225] 从数据集中随机抽样计算得到的。 ]) total_data MyDataset(all_labels, data_paths_str, train_transforms) total_datatrain_size int(0.8 * len(total_data)) test_size len(total_data) - train_size train_dataset, test_dataset torch.utils.data.random_split(total_data, [train_size, test_size]) train_size,test_size二、建模步骤1.加载数据train_loader torch.utils.data.DataLoader(train_dataset, batch_size16, shuffleTrue) test_loader torch.utils.data.DataLoader(test_dataset, batch_size16, shuffleTrue) print(The number of images in a training set is: , len(train_loader)*16) print(The number of images in a test set is: , len(test_loader)*16) print(The number of batches per epoch is: , len(train_loader))for X, y in test_loader: print(Shape of X [N, C, H, W]: , X.shape) print(Shape of y: , y.shape, y.dtype) break2.模型搭建定义网络结构Network_bn继承自nn.Module这是PyTorch中所有神经网络模块的基类。__init__方法中定义了网络的各个层self.conv1第一个卷积层输入通道数为3输出通道数为12卷积核大小为5步长为1无填充。self.bn1第一个批量归一化层归一化12个通道。self.conv2第二个卷积层输入通道数为12输出通道数为12卷积核大小为5步长为1无填充。self.bn2第二个批量归一化层归一化12个通道。self.pool最大池化层池化窗口大小为2步长为2。self.conv4第三个卷积层输入通道数为12输出通道数为24卷积核大小为5步长为1无填充。self.bn4第三个批量归一化层归一化24个通道。self.conv5第四个卷积层输入通道数为24输出通道数为24卷积核大小为5步长为1无填充。self.bn5第四个批量归一化层归一化24个通道。self.fc1全连接层输入特征数为245050输出特征数为label_name_len * char_set_len。self.reshape自定义的Reshape层将输出调整为目标形状[label_name_len, char_set_len]。前向传播方法forward输入x依次通过卷积层、批量归一化层、ReLU激活函数、最大池化层。最后通过全连接层self.fc1。使用self.reshape层将输出调整为目标形状。定义Reshape层继承自nn.Module。__init__方法中定义目标形状。forward方法中将输入x调整为目标形状。设备选择检查是否有可用的CUDA设备如果有则使用CUDA设备否则使用CPU。打印使用的设备。创建模型实例并移动到设备创建Network_bn实例。使用.to(device)方法将模型移动到指定设备。class Network_bn(nn.Module): def __init__(self): super(Network_bn, self).__init__() nn.Conv2d()函数 第一个参数in_channels是输入的channel数量 第二个参数out_channels是输出的channel数量 第三个参数kernel_size是卷积核大小 第四个参数stride是步长默认为1 第五个参数padding是填充大小默认为0 self.conv1 nn.Conv2d(in_channels3, out_channels12, kernel_size5, stride1, padding0) self.bn1 nn.BatchNorm2d(12) self.conv2 nn.Conv2d(in_channels12, out_channels12, kernel_size5, stride1, padding0) self.bn2 nn.BatchNorm2d(12) self.pool nn.MaxPool2d(2,2) self.conv4 nn.Conv2d(in_channels12, out_channels24, kernel_size5, stride1, padding0) self.bn4 nn.BatchNorm2d(24) self.conv5 nn.Conv2d(in_channels24, out_channels24, kernel_size5, stride1, padding0) 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 import torchsummary 显示网络结构 torchsummary.summary(model, (3, 224, 224))3.训练函数optimizer torch.optim.Adam(model.parameters(), lr1e-4, weight_decay0.0001) loss_model nn.CrossEntropyLoss() 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() test_loss / num_batches print(fAvg loss: {test_loss:8f} \n) return correct,test_loss def train(model,train_loader,loss_model,optimizer): modelmodel.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))4.正式训练test_acc_list [] test_loss_list [] epochs 30 for t in range(epochs): print(fEpoch {t1}\n-------------------------------) train(model,train_loader,loss_model,optimizer) test_acc,test_loss test(model, test_loader, loss_model) test_acc_list.append(test_acc) test_loss_list.append(test_loss) print(Done!)5.损失展示了测试损失随训练周期Epoch的变化import numpy as np import matplotlib.pyplot as plt from datetime import datetime current_time datetime.now() # 获取当前时间 x [i for i in range(1,31)] plt.plot(x, test_loss_list, labelLoss, alpha0.8) plt.xlabel(Epoch) plt.ylabel(Loss) plt.title(current_time) # 打卡请带上时间戳否则代码截图无效 plt.legend() plt.show()
返回列表