欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 维修 > AlexNet项目图片分类通用模型代码

AlexNet项目图片分类通用模型代码

2024/10/25 4:14:26 来源:https://blog.csdn.net/m0_73426548/article/details/142363691  浏览:    关键词:AlexNet项目图片分类通用模型代码

目录

一:建立AlexNet模型(在model文件中写)

1.构造5层卷积层

2.构造3层神经网络层

3.forward函数

4.模型最终代码

二:训练数据(在train中写)

1.读出数据

2.训练

3. 测试模型更新参数

4.完整的训练代码:

三:预测和模型评分(在predict文件中写)

 四:代码使用:

点个赞呗!!!!!!


 

一:建立AlexNet模型(在model文件中写)

AlexNet网络结构相对简单,使用了8层卷积神经网络,前5层是卷积层,剩下的3层是全连接层

1.构造5层卷积层

Conv2d:构造卷积层,参数:(输入通道数,输出通道数等价于卷积核个数,卷积核大小,步长,加0)

ReLU:激活函数,inplace设置是否改变数据

MaxPool2d:池化操作,参数:(核大小,步长)

import torch
import torch.nn as nnclass AlexNet(nn.Module):def __init__(self,num_classes=1000):super().__init__()self.features = nn.Sequential(nn.Conv2d(3, 48, kernel_size=11, stride=4, padding=2),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=3, stride=2),nn.Conv2d(48, 128, kernel_size=5, padding=2),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=3, stride=2),nn.Conv2d(128, 192, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(192, 192, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(192, 128, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=3, stride=2) # output [128, 6, 6])

2.构造3层神经网络层

Dropout:将比例数据置空,比如数据为(1,2,3,4,5,6),当参数p=0.5时,数据会变成:(1,0,3,0,5,0)。p代表置空的比例,当然这个置空是随机的

Linear:线性变换,参数:(输入数据的通道数,输出数据的通道数)

ReLu:和上面一样

self.classifier = nn.Sequential(nn.Dropout(p=0.5),nn.Linear(128 * 6 * 6, 2048),nn.ReLU(inplace=True),nn.Dropout(p=0.5),nn.Linear(2048, 2048),nn.ReLU(inplace=True),nn.Linear(2048, num_classes),)

3.forward函数

torch.nn.Flatten(start_dim=1, end_dim=-1)
start_dim与end_dim代表合并的维度,开始的默认值为1,结束的默认值为 - 1,因此常被使用在神经网络当中,将每个batch的数据拉伸成一维

forward的作用:先让数据经过5层卷积,在经过3层全连接层

    def forward(self, x):x = self.features(x)x = torch.flatten(x, start_dim=1)x = self.classifier(x)return x

4.模型最终代码

import torch
import torch.nn as nnclass AlexNet(nn.Module):def __init__(self, num_classes=1000):super().__init__()self.features = nn.Sequential(nn.Conv2d(3, 48, kernel_size=11, stride=4, padding=2),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=3, stride=2),nn.Conv2d(48, 128, kernel_size=5, padding=2),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=3, stride=2),nn.Conv2d(128, 192, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(192, 192, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(192, 128, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=3, stride=2) # output [128, 6, 6])self.classifier = nn.Sequential(nn.Dropout(p=0.5),nn.Linear(128 * 6 * 6, 2048),nn.ReLU(inplace=True),nn.Dropout(p=0.5),nn.Linear(2048, 2048),nn.ReLU(inplace=True),nn.Linear(2048, num_classes),)def forward(self, x):torch.nn.Flatten(start_dim=1, end_dim=-1)x = self.features(x)x = torch.flatten(x, start_dim=1)x = self.classifier(x)return x

二:训练数据(在train中写)

1.读出数据

RandomResizedCrop:对图片的区域随机改变图片的大小

RandomHorizontalFlip:对图片进行随机翻转

ToTensor:将图片转为Tensor数据类型

Normalize:对数据进行标准化,参数:(标准化的平均值元组,方差元组)

datasets.ImageFolder:读数据类别返回一个字典{0:类别一,1:类别二}, 这行代码可以获取数据的类别数以及对应的类别标签。以字典的形式保存

        参数:(root:读取文件的路径(注意:路径文件中不能直接放图片,应该放各个图片类别的文件),transfrom:对图片进行预处理函数)

torch.utils.data.DataLoader:读取数据:参数(dataset:数据加载的数据集,batch_size:每次加载多少样本数,suffle:是否打乱数据,num_workers:最多并行加载数量)

import os
import sys
import jsonfrom tqdm import tqdm
import torch
import torch.nn as nn
from torchvision import transforms,datasetsfrom model import AlexNetdef main():# 看看是否使用cpudevice=torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')print(f'using:',{device})# 要读入图片的目录路径,以下代码假设你这个路径下有文件(train训练集, val测试集)image_path=os.path.join('./','训练集和测试集的图片路径')# print(image_path)# 判断这个路径是否存在,若不存在则报错image path done nit existassert os.path.exists(image_path),'image path done ont exist'# 创建读入数据后对数据处理的方法集合data_transform={# 将训练数据和测试数据的处理集使用对象的方法,以便后面使用'train':transforms.Compose([transforms.RandomResizedCrop(224),transforms.RandomHorizontalFlip(),transforms.ToTensor(),transforms.Normalize((0.485, 0.456, 0.406),(0.229, 0.224, 0.225))]),'val':transforms.Compose([transforms.Resize((224, 224)),transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])}train_dataset=datasets.ImageFolder(root=os.path.join(image_path,'train'),transform=data_transform['train'])train_num=len(train_dataset)# print(train_num)flower_list=train_dataset.class_to_idx# print(flower_list)cla_dict=dict((val,key) for key,val in flower_list.items())# print(cla_dict)json_str=json.dumps(cla_dict,indent=4)with open('class_indices.json','w') as json_file:json_file.write(json_str)# print(json_str)batch_size=32# 这行代码可以得到你电脑的cpu最大进程数量,如果大于16那么就按照16来nw=min([os.cpu_count(),batch_size if batch_size>1 else 0,16])print(f'using {nw} dataloader workers every process')# 读取训练集数据train_loader=torch.utils.data.DataLoader(train_dataset,batch_size=batch_size,shuffle=True,num_workers=nw)validata_dataset=datasets.ImageFolder(root=os.path.join(image_path,'val'),transform=data_transform['val'])val_num = len(validata_dataset)# 读取测试集数据validata_loader=torch.utils.data.DataLoader(validata_dataset,batch_size=batch_size,shuffle=False,num_workers=nw)

2.训练

每行代码都要注释哦!!!

    net.to(device)# 使用交叉熵损失函数loss_fn=nn.CrossEntropyLoss()# 使用优化器类,这里使用Adam优化器optimizer=torch.optim.Adam(net.parameters(),lr=0.0002)# 迭代数量epochs=10# 训练后的参数保存地址save_path='./AlexNet.pth'best_acc=0.0# 训练样本数train_step=len(train_loader)for epoch in range(epochs):# 开启训练模式net.train()# 初始化每次迭代的总损失running_loss=0.0# tqdm是一个进度条,将要迭代的数据放入,可以查看迭代的进度# stdout :它使用其参数直接显示在控制台窗口上。train_bar=tqdm(train_loader,file=sys.stdout)for step,data in enumerate(train_bar):# images是要训练的图片,labels是这张图片的类别images,labels=data# 将优化器的梯度置零optimizer.zero_grad()# 将图片加入到cpu中训练后返回outputsoutputs=net(images.to(device))# 计算损失loss=loss_fn(outputs,labels.to(device))# 反向传播计算参数loss.backward()# 跟新优化器中的参数optimizer.step()# 累加损失running_loss+=loss.item()# 输出语句train_bar.desc = f'train epoch {epoch + 1}/ {epochs} loss: {loss:.3f}'

3. 测试模型更新参数

       # 开启预测模型net.eval()acc=0.0# 关闭torch中的梯度记录with torch.no_grad():# 开启进度条val_bar=tqdm(validata_loader,file=sys.stdout)# 开始迭代for val_data in val_bar:# 测试集图片,测试集目标值val_images,val_labels=val_data# 开始预测outputs=net(val_images.to(device))# 获取预测的结果集,因为用的是softmax,所以取没张图片的结果集的最大值就是这张图片的预测结果predict_y=torch.max(outputs,dim=1)[1]# 计算总损失acc+=torch.eq(predict_y,val_labels.to(device)).sum().item()# 计算平均损失val_accuracy=acc/val_num# 打印结果print(f'[epoch {epoch + 1}] train_loss: {running_loss / train_step:.3f},         val_accuracy:{val_accuracy:.3f}')# 如果这次的结果比上次的好,就更新参数,否则不变if val_accuracy>best_acc:best_acc=val_accuracytorch.save(net.state_dict(),save_path)

4.完整的训练代码:

import os
import sys
import jsonfrom tqdm import tqdm
import torch
import torch.nn as nn
from torchvision import transforms,datasetsfrom model import AlexNetdef main():# 看看是否使用cpudevice=torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')print(f'using:',{device})# 要读入图片的目录路径,以下代码假设你这个路径下有文件(train训练集, val测试集)image_path=os.path.join('./','训练集和测试集的图片路径')# print(image_path)# 判断这个路径是否存在,若不存在则报错image path done nit existassert os.path.exists(image_path),'image path done ont exist'# 创建读入数据后对数据处理的方法集合data_transform={# 将训练数据和测试数据的处理集使用对象的方法,以便后面使用'train':transforms.Compose([transforms.RandomResizedCrop(224),transforms.RandomHorizontalFlip(),transforms.ToTensor(),transforms.Normalize((0.485, 0.456, 0.406),(0.229, 0.224, 0.225))]),'val':transforms.Compose([transforms.Resize((224, 224)),transforms.ToTensor(),transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])}train_dataset=datasets.ImageFolder(root=os.path.join(image_path,'train'),transform=data_transform['train'])train_num=len(train_dataset)# print(train_num)flower_list=train_dataset.class_to_idx# print(flower_list)cla_dict=dict((val,key) for key,val in flower_list.items())# print(cla_dict)json_str=json.dumps(cla_dict,indent=4)with open('class_indices.json','w') as json_file:json_file.write(json_str)# print(json_str)batch_size=32nw=min([os.cpu_count(),batch_size if batch_size>1 else 0,16])print(f'using {nw} dataloader workers every process')train_loader=torch.utils.data.DataLoader(train_dataset,batch_size=batch_size,shuffle=True,num_workers=nw)validata_dataset=datasets.ImageFolder(root=os.path.join(image_path,'val'),transform=data_transform['val'])val_num = len(validata_dataset)validata_loader=torch.utils.data.DataLoader(validata_dataset,batch_size=batch_size,shuffle=False,num_workers=nw)net=AlexNet(num_classes=5)net.to(device)# 使用交叉熵损失函数loss_fn = nn.CrossEntropyLoss()# 使用优化器类,这里使用Adam优化器optimizer = torch.optim.Adam(net.parameters(), lr=0.0002)# 迭代数量epochs = 10#  训练后的参数保存地址save_path = './AlexNet.pth'best_acc = 0.0# 训练样本数train_step = len(train_loader)for epoch in range(epochs):# 开启训练模式net.train()# 初始化每次迭代的总损失running_loss = 0.0# tqdm是一个进度条,将要迭代的数据放入,可以查看迭代的进度# stdout :它使用其参数直接显示在控制台窗口上。train_bar = tqdm(train_loader, file=sys.stdout)for step, data in enumerate(train_bar):# images是要训练的图片,labels是这张图片的类别images, labels = data# 将优化器的梯度置零optimizer.zero_grad()# 将图片加入到cpu中训练后返回outputsoutputs = net(images.to(device))# 计算损失loss = loss_fn(outputs, labels.to(device))# 反向传播计算参数loss.backward()# 跟新优化器中的参数optimizer.step()# 累加损失running_loss += loss.item()# 输出语句train_bar.desc = f'train epoch {epoch + 1}/ {epochs} loss: {loss:.3f}'# 开启预测模型net.eval()acc = 0.0# 关闭torch中的梯度记录with torch.no_grad():# 开启进度条val_bar = tqdm(validata_loader, file=sys.stdout)# 开始迭代for val_data in val_bar:# 测试集图片,测试集目标值val_images, val_labels = val_data# 开始预测outputs = net(val_images.to(device))# 获取预测的结果集,因为用的是softmax,所以取没张图片的结果集的最大值就是这张图片的预测结果predict_y = torch.max(outputs, dim=1)[1]# 计算总损失acc += torch.eq(predict_y, val_labels.to(device)).sum().item()# 计算平均损失val_accuracy = acc / val_num# 打印结果print(f'[epoch {epoch + 1}] train_loss: {running_loss / train_step:.3f},         val_accuracy:{val_accuracy:.3f}')# 如果这次的结果比上次的好,就更新参数,否则不变if val_accuracy > best_acc:best_acc = val_accuracytorch.save(net.state_dict(), save_path)

三:预测和模型评分(在predict文件中写)

import os
import jsonimport torch
from PIL import Image
from torchvision import transforms
import matplotlib.pyplot as pltfrom model import AlexNetdef main():device=torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')# 处理图片函数data_transform=transforms.Compose([transforms.Resize((224,224)),transforms.ToTensor(),transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))])# 测试图片的路径img_path='./1.jpeg'# 判断这张图片是否存在assert os.path.exists(img_path),f'{img_path} does not exist'# 读取图片img=Image.open(img_path)# 将图片展示出来plt.imshow(img)# 使用上面的函数处理图片img=data_transform(img)# print(img.shape)# 对图片维度进行扩充img=torch.unsqueeze(img,dim=0)print(img.shape)# 训练的时候生成的图片类别文件json_path='./class_indices.json'# 判断类别文件是否存在assert os.path.exists(json_path),f'{json_path} done not exist'# 读取文件with open(json_path,'r') as f:class_dict=json.load(f)print(class_dict)# 建立模型model=AlexNet(num_classes=5).to(device)# 训练后的参数文件weights_path='./AlexNet.pth'# 判断参数文件是否存在assert os.path.exists(weights_path),f'file {weights_path} does not exist'# 模型加载参数model.load_state_dict(torch.load(weights_path))# 开启预测模式model.eval()# 关闭梯度with torch.no_grad():# 预测output=model(img.to(device))print(output)# 对图片维度压缩回来output=torch.squeeze(output).cpu()# 使用softmax函数分类predict=torch.softmax(output,dim=0)# 获得图片的预测概率最大的那个就是这张图片的类别predict_class=torch.argmax(predict).numpy()# 完成打印print_res = f"class: {class_dict[str(predict_class)]}, prob: {predict[predict_class].numpy():.3f}"# 将图片类别写在图片上plt.title(print_res)# 展示图片plt.show()if __name__ == '__main__':main()

 四:代码使用:

准备好需要训练和预测的数据集比如:

 文件中有训练集和测试集

 

将flower_data这个路径写到image_path这个变量中就可以

点个赞呗!!!!!!

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com