774 lines
45 KiB
Python
774 lines
45 KiB
Python
import random
|
||
|
||
import torch
|
||
# torchvision是PyTorch中专门用来处理图像的库,使用了torchvision就非常方便
|
||
import torchvision
|
||
# transforms是torchvision库用来对图像进行变换的
|
||
import torchvision.transforms as transforms
|
||
#time 是Python自带的库,引入它主要是用于记录训练时间
|
||
import time
|
||
import sys
|
||
from torch.utils.data import random_split
|
||
import numpy as np
|
||
from tqdm import tqdm
|
||
from colorama import Fore, Style, Back
|
||
import os
|
||
|
||
from torchvision.models import resnet18,resnet34,resnet50,resnet101
|
||
import matplotlib.pyplot as plt
|
||
|
||
# print('火山引擎,我来了')
|
||
# 记录开始时间
|
||
start_time = time.time()
|
||
|
||
|
||
# 加上设备,然后准备放到赠送的线上GPU上训练
|
||
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
|
||
|
||
# transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
|
||
transform = transforms.Compose([transforms.ToTensor(),
|
||
transforms.Normalize((0.485, 0.456, 0.406), (0.229, 0.224, 0.225)),
|
||
transforms.RandomHorizontalFlip(), #随机水平翻转
|
||
transforms.RandomCrop(32, padding=4), #随机裁剪
|
||
transforms.RandomErasing(scale=(0.04, 0.2), ratio=(0.5, 2)) #随机遮挡
|
||
])
|
||
# 下载CIFAR10训练集
|
||
trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
|
||
# 加载训练集,训练集需要打乱,每次训练4个样本
|
||
# trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True, num_workers=0)
|
||
# trainloader = torch.utils.data.DataLoader(trainset, batch_size=1, shuffle=True, num_workers=0)
|
||
# train_batch_size = 10
|
||
# 每次给模型扔128张图片
|
||
# train_batch_size = 128
|
||
train_batch_size = 512
|
||
# val_batch_size = 50
|
||
val_batch_size = 512
|
||
# test_batch_size = 30
|
||
test_batch_size = 512
|
||
# train_batch_size = 100
|
||
|
||
|
||
# 假设我们要将数据集划分为90%训练集和10%验证集
|
||
split = int(len(trainset) * 0.9)
|
||
|
||
# 把随机种子固定下来,这样多次训练,就不会变化,从而避免验证集精度虚高
|
||
torch.manual_seed(42)
|
||
np.random.seed(42)
|
||
random.seed(42)
|
||
|
||
|
||
|
||
# 使用random_split函数随机划分数据集,它是torch封装的一个工具
|
||
trainset, valset = random_split(trainset, [split, len(trainset) - split])
|
||
|
||
# 创建数据加载器
|
||
# train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True, num_workers=2)
|
||
# val_loader = DataLoader(val_dataset, batch_size=64, shuffle=False, num_workers=2)
|
||
|
||
|
||
# 打乱数据
|
||
trainloader = torch.utils.data.DataLoader(trainset, batch_size=train_batch_size, shuffle=True, num_workers=0)
|
||
valloader = torch.utils.data.DataLoader(valset, batch_size=val_batch_size, shuffle= False, num_workers=0)
|
||
# trainloader = torch.utils.data.DataLoader(trainset, batch_size=1, shuffle=True, num_workers=2)
|
||
# trainloader = torch.utils.data.DataLoader(trainset, batch_size=9, shuffle=True, num_workers=0)
|
||
# 下载CIFAR10测试集,所以train这个参数这里要设置为False
|
||
testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)
|
||
# 加载测试集,测试集不需要打乱
|
||
# testloader = torch.utils.data.DataLoader(testset, batch_size=4, shuffle=False, num_workers=0)
|
||
# 测试的时候可以不用打乱数据
|
||
# testloader = torch.utils.data.DataLoader(testset, batch_size=1, shuffle=False, num_workers=0)
|
||
# testloader = torch.utils.data.DataLoader(testset, batch_size=10, shuffle=False, num_workers=0)
|
||
testloader = torch.utils.data.DataLoader(testset, batch_size=test_batch_size, shuffle=False, num_workers=0)
|
||
# testloader = torch.utils.data.DataLoader(testset, batch_size=9, shuffle=False, num_workers=0)
|
||
|
||
|
||
|
||
|
||
# 定义CIFAR10数据集的十分类类别
|
||
classes = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
|
||
|
||
import numpy as np
|
||
# import matplotlib.pyplot as plt
|
||
|
||
|
||
|
||
|
||
# 定义一个展示图片的函数
|
||
def imshow(img):
|
||
img = img / 2 + 0.5
|
||
npimg = img.numpy()
|
||
# plt.imshow(np.transpose(npimg, (1, 2, 0)))
|
||
# plt.show()
|
||
|
||
#因为这块只是展示图片,没太多必要,所以先注释掉
|
||
|
||
# 从数据迭代器中读取一张图片
|
||
#dataiter = iter(trainloader)
|
||
|
||
#images, labels = next(dataiter)
|
||
|
||
# # 展开图片
|
||
#imshow(torchvision.utils.make_grid(images))
|
||
|
||
# #打印标签
|
||
#print(''.join('%15s' % classes[labels[j]] for j in range(4)))
|
||
|
||
import torch.nn as nn
|
||
import torch.nn.functional as F
|
||
class Net(nn.Module):
|
||
def __init__(self):
|
||
super(Net,self).__init__()
|
||
#定义两个卷积层
|
||
# self.conv1 = nn.Conv2d(3,6,5)
|
||
# self.conv2 = nn.Conv2d(6,16,5)
|
||
# 第一个卷积层,输入通道数为3(因为是RGB图片,有3个颜色通道),输出通道数为6,这个是可以随意设置,卷积核大小为3*3
|
||
# self.conv1 = nn.Conv2d(3,6,3)
|
||
# 如果卷积核是3*3,那么给周围填充1,刚好尺寸不变
|
||
self.conv1 = nn.Conv2d(3,64,3,padding=1)
|
||
# 第二个卷积层,输入通道数为6,因为上次卷积之后输出是6个特征图,输出通道数为16,这个是可以随意设置,卷积核大小同样为3*3
|
||
self.conv2 = nn.Conv2d(64,64,3,padding=1)
|
||
#新增加一个卷积层,因为上一个卷积层输出是16个特征图,所以输入通道数为16,输出通道数为16,这个是可以随意设置,卷积核大小同样为3*3
|
||
self.conv3 = nn.Conv2d(64,128,3,padding=1)
|
||
self.conv4 = nn.Conv2d(128,128,3,padding=1)
|
||
self.conv5 = nn.Conv2d(128,256,3,padding=1)
|
||
self.conv6 = nn.Conv2d(256,256,3,padding=1)
|
||
self.conv7 = nn.Conv2d(256,256,3,padding=1)
|
||
self.conv8 = nn.Conv2d(256,512,3,padding=1)
|
||
self.conv9 = nn.Conv2d(512,512,3,padding=1)
|
||
self.conv10 = nn.Conv2d(512,512,3,padding=1)
|
||
# self.conv11 = nn.Conv2d(512,512,3,padding=1)
|
||
# self.conv12 = nn.Conv2d(512,512,3,padding=1)
|
||
# self.conv13 = nn.Conv2d(512,512,3,padding=1)
|
||
|
||
# 做了批归一化,能有效避免梯度消失和梯度爆炸
|
||
self.bn64 = nn.BatchNorm2d(64)
|
||
self.bn128 = nn.BatchNorm2d(128)
|
||
self.bn256 = nn.BatchNorm2d(256)
|
||
self.bn8 = nn.BatchNorm2d(512)
|
||
self.bn9 = nn.BatchNorm2d(512)
|
||
self.bn10 = nn.BatchNorm2d(512)
|
||
# self.bn11 = nn.BatchNorm2d(512)
|
||
# self.bn12 = nn.BatchNorm2d(512)
|
||
# self.bn13 = nn.BatchNorm2d(512)
|
||
# self.conv3 = nn.Conv2d(16,9,3)
|
||
#再增加一个卷积层
|
||
# self.conv4 = nn.Conv2d(16,6,1)
|
||
#定义池化层,池化核大小为2*2
|
||
self.pool = nn.MaxPool2d(2,2)
|
||
#定义三个全连接层
|
||
# self.fc1 = nn.Linear(16*5*5,120)
|
||
#每次输入4个样本,每个样本有3个通道,所以输入通道数为4*3*3*3
|
||
# self.fc1 = nn.Linear(16*3*3,120)
|
||
# self.fc1 = nn.Linear(16*4*3*3,120)
|
||
# self.fc1 = nn.Linear(16*4,120)
|
||
# self.fc1 = nn.Linear(16*16*2*169,120)
|
||
# self.fc1 = nn.Linear(73728,120)
|
||
# self.fc1 = nn.Linear(256*22*22,120)
|
||
# self.fc1 = nn.Linear(256*4*4,120)
|
||
# self.fc1 = nn.Linear(512*4*4,120)
|
||
# self.fc1 = nn.Linear(512*4*4,800)
|
||
self.fc1 = nn.Linear(512*2*2,800)
|
||
# self.fc1 = nn.Linear(256*5*5,120)
|
||
# self.fc1 = nn.Linear(144*16*16*2,120)
|
||
# self.fc1 = nn.Linear(6,120)
|
||
# self.fc1 = nn.Linear(4*4*4*3*3,120)
|
||
# self.fc2 = nn.Linear(120,84)
|
||
self.fc2 = nn.Linear(800,84)
|
||
# self.fc4 = nn.Linear(84,84)
|
||
# self.fc5 = nn.Linear(84,84)
|
||
# self.fc2 = nn.Linear(120,84)
|
||
self.fc3 = nn.Linear(84,10)
|
||
# 增加drop-out层,丢弃概率
|
||
# self.dropout = nn.Dropout(0.5)
|
||
|
||
|
||
|
||
# 定义前向传播,模型的关键还在于前向传播
|
||
def forward(self,x):
|
||
# x = self.pool(F.relu(self.conv1(x)))
|
||
x = F.relu(self.bn64(self.conv1(x)))
|
||
x = self.pool(F.relu(self.bn64(self.conv2(x))))
|
||
# x = self.pool(F.relu(self.conv2(x)))
|
||
# x = F.relu(self.conv2(x))
|
||
# x = self.pool(F.relu(self.conv3(x)))
|
||
# x = F.relu(self.conv3(x))
|
||
x = F.relu(self.bn128(self.conv3(x)))
|
||
|
||
# x = F.relu(self.conv4(x))
|
||
# x = self.pool(F.relu(self.conv4(x)))
|
||
x = self.pool(F.relu(self.bn128(self.conv4(x))))
|
||
# x = F.relu(self.conv5(x))
|
||
x = F.relu(self.bn256(self.conv5(x)))
|
||
# x = self.pool(F.relu(self.conv5(x)))
|
||
x = F.relu(self.bn256(self.conv6(x)))
|
||
# x = F.relu(self.conv7(x))
|
||
# x = self.pool(F.relu(self.conv7(x)))
|
||
x = self.pool(F.relu(self.bn256(self.conv7(x))))
|
||
# x = self.pool(F.relu(self.bn8(self.conv8(x))))
|
||
x = F.relu(self.bn8(self.conv8(x)))
|
||
# x = F.relu(self.bn9(self.conv9(x)))
|
||
x = self.pool(F.relu(self.bn9(self.conv9(x))))
|
||
x = F.relu(self.bn10(self.conv10(x)))
|
||
# x = self.pool(F.relu(self.bn10(self.conv10(x))))
|
||
# x = F.relu(self.bn11(self.conv11(x)))
|
||
# x = F.relu(self.bn12(self.conv12(x)))
|
||
# x = F.relu(self.bn13(self.conv13(x)))
|
||
#变换x的形状以适配全连接的输入,因为全连接层输入必须是二维的,所以需要将x的形状变成二维的,因为图片是32*32*3,需要将三维变量拉长
|
||
# x = x.view(-1,16*5*5)
|
||
# x = x.view(-1,16*3*3)
|
||
# x = x.view(-1,16*4*3*3)
|
||
# x = x.view(-1,16*4)
|
||
# x = x.view(-1,16*16*2*169)
|
||
# x = x.view(-1,73728)
|
||
# x = x.view(-1,256*22*22)
|
||
# x = x.view(-1,256*4*4)
|
||
# x = x.view(-1,512*4*4)
|
||
x = x.view(-1,512*2*2)
|
||
# x = x.view(-1,256*5*5)
|
||
# x = x.view(-1,144*16*16*2)
|
||
# x = x.view(-1,6)
|
||
# x = x.view(-1,4*4*4*3*3)
|
||
# x = self.dropout(x)
|
||
x = F.relu(self.fc1(x))
|
||
# x = self.dropout(x)
|
||
x = F.relu(self.fc2(x))
|
||
# x = self.dropout(x)
|
||
# x = F.tanh(self.fc2(x))
|
||
# x = F.sigmoid(self.fc2(x))
|
||
# x = F.relu(self.fc4(x))
|
||
# x = F.relu(self.fc5(x))
|
||
x = self.fc3(x)
|
||
# print(x.shape)
|
||
return x
|
||
|
||
net = Net().to(device)
|
||
# 直接加载训练好的模型,就不需要从头开始训练了。如果不加载,一上来损失就是2.290,很高。如果加载了模型,一上来损失只有0.127,效果太明显了,这就是微调的作用
|
||
# net.load_state_dict(torch.load('./cifar_net56.pth'))
|
||
# num_classes,代表最终分类的数量,因为CIFAR10有10个分类,所以这里要设置为10
|
||
# net = resnet18(pretrained=False, num_classes=10).to(device)
|
||
# net = resnet18(pretrained=True, num_classes=10).to(device)
|
||
# net = resnet18(pretrained=True)
|
||
# net = resnet34(pretrained=True)
|
||
# net = resnet50(pretrained=False)
|
||
# net = resnet101(pretrained=True)
|
||
|
||
# 冻结模型的所有层,除了最后的全连接层
|
||
# for param in net.parameters():
|
||
# param.requires_grad = False
|
||
#
|
||
# last_layer = net.fc
|
||
# # 替换最后一个全连接层
|
||
# num_classes = 10 # CIFAR10的数据类数为10
|
||
# new_last_layer = torch.nn.Linear(last_layer.in_features, num_classes)
|
||
# net.fc = new_last_layer
|
||
|
||
# num_ftrs = net.fc.in_features
|
||
# net.fc = nn.Linear(num_ftrs, 10)
|
||
# 检查是否有可用的GPU,如果有多个GPU,则使用 DataParallel
|
||
if torch.cuda.device_count() > 1:
|
||
print(f"Let's use {torch.cuda.device_count()} GPUs")
|
||
net = nn.DataParallel(net)
|
||
net.to(device)
|
||
print(net)
|
||
|
||
import torch.optim as optim
|
||
# 定义损失函数,CrossEntropyLoss()是交叉熵损失函数
|
||
criterion = nn.CrossEntropyLoss()
|
||
#原本是0。001,改为0.0001
|
||
# optimizer = optim.SGD(net.parameters(),lr = 0.0001, momentum = 0.9)
|
||
optimizer = optim.Adam(net.parameters(),lr = 0.0001)
|
||
# 只更新全连接层的参数,把卷积层的参数冻结,不更新
|
||
# optimizer = optim.SGD(net.fc.parameters(),lr = 0.0001, momentum = 0.9)
|
||
# optimizer = optim.SGD(net.fc.parameters(),lr = 0.0002, momentum = 0.9)
|
||
# optimizer = optim.SGD(net.parameters(),lr = 0.0002, momentum = 0.9)
|
||
# optimizer = optim.SGD(net.parameters(),lr = 0.0001, momentum = 0.9,weight_decay=0.001)
|
||
# optimizer = optim.SGD(net.parameters(),lr = 0.0001, momentum = 0.9,weight_decay=0.01)
|
||
# optimizer = optim.SGD(net.parameters(),lr = 0.0001, momentum = 0.9,weight_decay=0.005)
|
||
# optimizer = optim.SGD(net.parameters(),lr = 0.0005, momentum = 0.9)
|
||
# optimizer = optim.SGD(net.parameters(),lr = 0.00001, momentum = 0.9)
|
||
# optimizer = optim.SGD(net.parameters(),lr = 0.001, momentum = 0.9)
|
||
# optimizer = optim.SGD(net.parameters(),lr = 0.3, momentum = 0.9)
|
||
# optimizer = optim.SGD(net.parameters(),lr = 0.5, momentum = 0.9)
|
||
# optimizer = optim.SGD(net.parameters(),lr = 1, momentum = 0.9)
|
||
# 为了避免过拟合,考虑加入正则化,1e-4
|
||
# optimizer = optim.SGD(net.parameters(),lr = 0.0001, momentum = 0.9, weight_decay=0.003)
|
||
# optimizer = optim.SGD(net.parameters(),lr = 0.0001, momentum = 0.9, weight_decay=0.005)
|
||
# optimizer = optim.SGD(net.parameters(),lr = 0.0001, momentum = 0.9, weight_decay=0.01)
|
||
# optimizer = optim.SGD(net.parameters(),lr = 0.0001, momentum = 0.9, weight_decay=0.001)
|
||
# optimizer = optim.SGD(net.parameters(),lr = 0.0001, momentum = 0.9, weight_decay=0.0001)
|
||
# optimizer = optim.SGD(net.parameters(),lr = 0.001, momentum = 0.9)
|
||
# optimizer = optim.SGD(net.parameters(),lr = 0.01, momentum = 0.9)
|
||
# 使用ADAM梯度下降方法
|
||
# optimizer = optim.Adam(net.parameters(),lr = 0.01)
|
||
|
||
|
||
# min_loss = 0.3
|
||
# min_loss = 0.3
|
||
#
|
||
|
||
midModelPath = './cifar_net103.pth'
|
||
finallPATH = './cifar_net104.pth'
|
||
max_val_score = 0
|
||
break_max_val = False
|
||
epoch_list = []
|
||
val_acc_list = []
|
||
# 每次验证的正确率
|
||
every_val_acc = ''
|
||
|
||
def train(epoch):
|
||
# net = Net().to(device)
|
||
# print(net)
|
||
# net.load_state_dict(torch.load('./cifar_net76.pth'))
|
||
# net.load_state_dict(torch.load('./cifar_net75.pth',map_location= 'cpu'))
|
||
min_loss = 0.3
|
||
for epoch in range(epoch):
|
||
running_loss = 0.0
|
||
# 该代码片段使用enumerate()函数遍历trainloader数据加载器,并为每个数据项提供一个索引。
|
||
# enumerate()函数从0开始计数,并将每个数据项和相应的索引存储在一个元组中,
|
||
# 然后将这些元组传递给循环中的变量i和data。这样可以在遍历数据时轻松地访问每个数据项的索引,
|
||
# 以便执行相应的操作。
|
||
for i,data in enumerate(trainloader,0):
|
||
inputs,labels = data
|
||
# print(inputs)
|
||
|
||
|
||
#将梯度清零,如果不清零,梯度会累加,导致梯度爆炸,或者梯度消失,导致训练效果不好
|
||
optimizer.zero_grad()
|
||
#得到输出张量
|
||
outputs = net(inputs.to(device))
|
||
# print(outputs.shape)
|
||
# print(labels.shape)
|
||
#计算损失值
|
||
loss = criterion(outputs,labels.to(device))
|
||
#进行反向传播
|
||
loss.backward()
|
||
#更新参数
|
||
optimizer.step()
|
||
|
||
#打印训练信息
|
||
running_loss += loss.item()
|
||
# if(i +1)% 2000 == 0:
|
||
# if(i +1)% 100 == 0:
|
||
if(i +1)% 10 == 0:
|
||
|
||
runTime = time.strftime("%H小时%M分%S秒", time.gmtime(time.time() - start_time))
|
||
tqdm.write(f"Runtime:{Fore.GREEN}{runTime}{Style.RESET_ALL}")
|
||
|
||
|
||
# print('[第%d轮, 训练%5d个样本] loss : %.3f' % (epoch +1, (i+1)*train_batch_size,running_loss /2000))
|
||
tqdm.write(
|
||
f"第{Fore.YELLOW}{epoch+1}{Style.RESET_ALL}轮,训练{Fore.YELLOW}{(i+1)*train_batch_size}{Style.RESET_ALL}个样本, loss: {Fore.CYAN}{running_loss/2000}{Style.RESET_ALL}")
|
||
sys.stdout.flush() # 强制刷新输出缓冲区
|
||
# 以时分秒的形式打印下程序运行时长
|
||
# print('Runtime:',time.strftime("%H:%M:%S",time.gmtime(time.time()-start_time)))
|
||
# print('Runtime:',time.strftime("%H小时%M分%S秒",time.gmtime(time.time()-start_time)))
|
||
torch.save(net.state_dict(), midModelPath)
|
||
verify()
|
||
global break_max_val
|
||
if (break_max_val):
|
||
tqdm.write(
|
||
# f"{Back.LIGHTBLUE_EX} {Fore.LIGHTRED_EX}🔥 打破记录了!!!{Back.RESET}{Style.RESET_ALL}")
|
||
f"{Fore.LIGHTRED_EX}🔥 打破记录了!!!{Style.RESET_ALL}")
|
||
mytestTrainSet()
|
||
eval()
|
||
# if running_loss/2000 < min_loss:
|
||
# if running_loss/2000 < min_loss:
|
||
# print('打破记录')
|
||
# min_loss = running_loss/2000
|
||
# # PATH = './cifar_net70.pth'
|
||
# PATH = midModelPath
|
||
# torch.save(net.state_dict(),PATH)
|
||
# # 打印验证集精度
|
||
# verify()
|
||
# # 打印训练集精度
|
||
# testTrainSet()
|
||
# 刷新输出缓冲区,作用是确保输出信息立即显示在控制台上,不然在云服务器上半天显示不出来
|
||
sys.stdout.flush()
|
||
running_loss = 0.0
|
||
print("")
|
||
print('完成训练')
|
||
#
|
||
# PATH = './cifar_net71.pth'
|
||
PATH = finallPATH
|
||
# # # # #保存模型
|
||
torch.save(net.state_dict(),PATH)
|
||
eval()
|
||
|
||
|
||
|
||
def trainResNet(epoch):
|
||
net.load_state_dict(torch.load('./cifar_net101.pth',weights_only=True))
|
||
min_loss = 0.3
|
||
# 加载预训练的ResNet模型(如果需要从头开始训练,则可以去掉预训练权重)
|
||
# net = resnet18(pretrained=False, num_classes=10)
|
||
# print(net)
|
||
for epoch in range(epoch):
|
||
running_loss = 0.0
|
||
# 该代码片段使用enumerate()函数遍历trainloader数据加载器,并为每个数据项提供一个索引。
|
||
# enumerate()函数从0开始计数,并将每个数据项和相应的索引存储在一个元组中,
|
||
# 然后将这些元组传递给循环中的变量i和data。这样可以在遍历数据时轻松地访问每个数据项的索引,
|
||
# 以便执行相应的操作。
|
||
for i,data in enumerate(trainloader,0):
|
||
inputs,labels = data
|
||
|
||
#将梯度清零,如果不清零,梯度会累加,导致梯度爆炸,或者梯度消失,导致训练效果不好
|
||
optimizer.zero_grad()
|
||
#得到输出张量
|
||
outputs = net(inputs.to(device))
|
||
#计算损失值
|
||
loss = criterion(outputs,labels.to(device))
|
||
#进行反向传播
|
||
loss.backward()
|
||
#更新参数
|
||
optimizer.step()
|
||
|
||
#打印训练信息
|
||
running_loss += loss.item()
|
||
if(i +1)% 2000 == 0:
|
||
|
||
runTime = time.strftime("%H小时%M分%S秒", time.gmtime(time.time() - start_time))
|
||
tqdm.write(f"Runtime:{Fore.GREEN}{runTime}{Style.RESET_ALL}")
|
||
|
||
# print('[第%d轮, 训练%5d个样本] loss : %.3f' % (epoch +1, (i+1)*train_batch_size,running_loss /2000))
|
||
|
||
tqdm.write(
|
||
f"第{Fore.YELLOW}{epoch + 1}{Style.RESET_ALL}轮,训练{Fore.YELLOW}{(i + 1) * train_batch_size}{Style.RESET_ALL}个样本, loss: {Fore.CYAN}{running_loss / 2000}{Style.RESET_ALL}")
|
||
|
||
# 以时分秒的形式打印下程序运行时长
|
||
# print('Runtime:',time.strftime("%H:%M:%S",time.gmtime(time.time()-start_time)))
|
||
# print('Runtime:',time.strftime("%H小时%M分%S秒",time.gmtime(time.time()-start_time)))
|
||
|
||
# if running_loss/2000 < min_loss:
|
||
# print('打破记录')
|
||
# min_loss = running_loss/2000
|
||
# PATH = midModelPath
|
||
# # PATH = './cifar_net67.pth'
|
||
# # #保存模型
|
||
# torch.save(net.state_dict(),PATH)
|
||
# verify()
|
||
torch.save(net.state_dict(), midModelPath)
|
||
verify()
|
||
global break_max_val
|
||
if (break_max_val):
|
||
tqdm.write(
|
||
# f"{Back.LIGHTBLUE_EX} {Fore.LIGHTRED_EX}🔥 打破记录了!!!{Back.RESET}{Style.RESET_ALL}")
|
||
f"{Fore.LIGHTRED_EX}🔥 打破记录了!!!{Style.RESET_ALL}")
|
||
mytestTrainSet()
|
||
eval()
|
||
# 刷新输出缓冲区,作用是确保输出信息立即显示在控制台上,不然在云服务器上半天显示不出来
|
||
sys.stdout.flush()
|
||
running_loss = 0.0
|
||
print("")
|
||
epoch_list.append(epoch + 1)
|
||
val_acc_list.append(every_val_acc)
|
||
if (epoch + 1) % 5 == 0:
|
||
draw(epoch_list, val_acc_list)
|
||
|
||
print('完成训练')
|
||
#
|
||
# PATH = './cifar_net68.pth'
|
||
PATH = finallPATH
|
||
# # # # #保存模型
|
||
torch.save(net.state_dict(),PATH)
|
||
eval()
|
||
#
|
||
|
||
|
||
#在整个测试集上测试模型的准确率,53%,比之前55%还降了两个百分点。加了一层,正确率变成了46%,妹的,打算训练十次,看看,训练了十次,正确率变成39%,奶奶个熊
|
||
#直接把学习率改成0.0001,训练了十次,损失变为1.163,降了很多。突然正确率又提升到了56%
|
||
#决定把卷积层又恢复成两层,看看效果。因为batch给了9,一下子就训练完了,loss值为1.455,正确率为48%,效果不佳,
|
||
#加层数反而效果不好,可能加的不够好吧,然后把训练十次,改为30次,试试,第12轮的时候,损失为1.087,感觉正确率一定会超过56%,再训练第30轮的时候,有一次损失才0.793
|
||
#最终的损失是0.854,有点回升了。最终正确率为63%,如果在最低的损失值时,保存模型,那么正确率应该会更高。
|
||
#发现卷积层和全连接层没有必然联系,所以去掉了一个全连接层,试试效果。第12轮的时候,损失为1.027,但是很可惜,没有保存模型。
|
||
# 打算训练100轮,试试效果,这就好比把卷子做50遍,效果可能不太好,那就做100遍,相信效果会好很多。迭代100次太慢了,第42抡,有一次损失是0.727,也不确定会不会降低到0.6以下。
|
||
# 回家路上没有关电脑,不然又要重新训练。电脑烫死了,在59轮时,有一次损失是0.642。感觉100轮下来,还真有可能降低到0.6以下。70论的时候,有一次损失是0.616.第82轮的时候,
|
||
# 有一次降到了0.581,可惜因为之前程序写的不对,没法保存那个模型。最终的损失是0.697.正确率为61%,好气人,竟然降了。然后在训练集上跑了下,正确率为78%。不是很高,也就是说
|
||
#给它开卷考试,满分100分,也只能得到78分,说明学的还是不够。
|
||
#准备采用VGG网络架构,第一层卷积层直接从6个卷积核提升到64个卷积核,第二层也是64个卷积核,第三层128个卷积核,第四层也是128个卷积核。准备训练10轮,看看效果
|
||
# 在第九轮的时候,直接损失降低到0.560,这可是之前从来没有过的好成绩,说明还是得卷积盒多一些才可以。但是因为程序没写好,被多次覆盖掉。第十轮有一次损失是0.482
|
||
# 最终损失是0.565.在训练集上的正确率是84%,显著提升,在测试集上的正确率是73%,很厉害了
|
||
# 现在直接改造成了10层卷积层,哈哈,按照VGG的前十层架构,进行训练,然后把池化层去掉了,因为池化层经过三轮之后,变成2*2大小了,用3*3的卷积核没法计算了
|
||
# 网络层数加深之后,明显计算太慢了。下班也训练不完,打算训练五轮试试,看看一个小时能不能训练完,发现层数太深了,根本就训练不动,可能是由于链式法则,乘的数太多了,
|
||
# 导致每次只往前走一丁点,所以,可以考虑把学习率提高。
|
||
# 还是用三层架构,训练到第13抡,损失为0.019.我的天呐,牛啊,训练到第16抡,有一次损失为0.015,牛逼。训练到第18轮,有一次损失为0.006,不断降低损失,刷新记录。
|
||
# 在第29轮的时候,有一次损失为0.001.太吊了吧。在测试集上的正确率是69%,在训练集上的正确率是99%,很棒,说明是过拟合了。
|
||
#准备加上正则化,看看效果。计划训练30轮,在服务器上训练。
|
||
# 加上正则化后,在测试集上正确率是68%,在训练集上正确率是97%,我的天呐,还是解决不了过拟合的问题。
|
||
# 打算把正则化提升点,试试效果,加入正则化之后,在第17轮的时候,损失降到0.012.在训练集上的正确率是99%,在测试集上的正确率是69%,并且测试了两个模型,
|
||
# 还包括一个损失为0.010的,测试集上正确率也是69%,说明还是过拟合了。决定再次把正则化的系数从0.001,改为0.01,看看效果。
|
||
# 修改成0.01之后,训练了20轮,用时15个小时,最终损失为0.761,降不下去,然后在训练集上正确率为81%,在测试集上正确率是67%,反而效果还差了,
|
||
# 那就又将正则化惩罚项系数改为0.005,看看效果。在第14轮的时候,损失降到0.208.到时候看看结果,如果结果不理想,就继续把系数往下降。
|
||
# 第15轮的时候降到了0.188,看来有机会低于0.1啊。
|
||
# 最终损失是0.303,在测试集上正确率是66%,在训练集上正确率是96%。
|
||
# 打算把正则化惩罚项系数改为0.003,看看效果,最低的损失是0.058,在测试集上的正确率是66%,在训练集上的正确率是96%。过拟合问题太难搞了
|
||
# 加入drop-out,试试效果,给三个卷积层都加入了dropout
|
||
# dropout比例设置为0.5,损失到1.8附近,就不往下降了。调到0.1试试
|
||
# 不知道咋回事,加入dropout效果并不好,训练了三十轮,损失降不下去,也不知道是不是因为学习率为0.001的缘故,
|
||
# 现在把dropout去掉,加入数据增加,平移,反转,遮盖,来试试效果。
|
||
# 不知道咋回事,训练了30抡,损失是0.542,也太差了吧。在训练集上精度是80%,在测试集上精度是75%,竟然不过拟合了,不过损失为什么降不下去
|
||
# 打算再加一层卷积层,一共四个卷积层,试试,最终损失0.482,在训练集上的精度是83%,在测试集上的精度是79%,哇塞,有提升,终于快接近80%了。
|
||
# 打算再加一层,加到五个卷积层,这样,应该就可以上80%了
|
||
# 五层卷积层,最终损失为0.470,在训练集上的精度是84%,在测试集上的精度是80%,哇偶,终于上80%了
|
||
# 五层卷积层,最佳损失为0.422,在训练集上的精度是83%,在测试集上的精度是80%
|
||
# 打算第二层卷积层后面加个池化层,在五层卷积层后面也加个池化层,看看效果。
|
||
# 加入池化层之后,第六轮22000样本,只用了1小时15分钟,没加池化层之前用了1小时17分钟。我以为训练速度会加快的,并没有
|
||
# 训练完30轮,最终只用了7小时4分钟,不加池化层,用了6小时58分钟,我咋记得得二十几个小时呢。训练的模型只需要4.04M,之前都是40M-58M这样
|
||
# 加入两个池化层之后,最终损失是0.512,在训练集上的精度是84%,在测试集上的精度是80%
|
||
# 加入两个池化层之后,最佳损失是0.423,在训练集上的精度是84%,在测试集上的精度是80%
|
||
# 看来加入池化层,对于提高精度作用不大,那就继续增加网络层数吧。
|
||
# 再加上六七两个卷积层,但是加上这两层之后,训练不动了,损失不往下降,试着把学习率从0.0001改为0.00001试试
|
||
# 好像还是不行,那就把学习率提高为0.001,试试,后来发现能训练得动,比较慢而已
|
||
# 再加两个卷积层之后,最终损失是0.461,在训练集上的精度是84%,在测试集上的精度是80%。30轮训练用时12个小时,之前也就7个小时左右,因为网络更复杂了
|
||
# 也不知道是不是因为30轮,还不够,打算再训练20轮,看看效果,看看损失能不能降到0.4以下
|
||
# 在进行到第43轮的时候,损失为0.334,在训练集上的精度是87%,在测试集上的精度是82%,哇塞,果然被自己猜对了,我就是加了两层网络,怎么可能精度没有变化呢。
|
||
# 最佳损失为0.298,在训练集上的精度是89%,在测试集上的精度是83%,哇偶,开心,果然增加模型复杂度,可以提升精度
|
||
# 最终损失为0.371,在训练集上的精度是88%,在测试集上的精度82%
|
||
# 决定再加上三层卷积层,3个512特征图,然后训练轮数从50轮提升到70轮,看看效果。并将学习率从0.0001提高到0.0005,避免训练不动
|
||
# 将学习率提升到0.5,训练了一个晚上,损失还是3.7,根本不往下降。
|
||
# 问了下ai,这种情况应该是属于梯度消失了,可以采用批归一化,试试
|
||
# 哇塞,果然是梯度消失了,给新加的三个卷积层加入批归一化之后,采用0.0001的学习率,明显可以训练得动了。
|
||
# 训练了70轮,用了四五天,第一次花这么长时间用来训练,耗时为什么这么长,主要是因为模型更复杂了,而且batch_size给的太小了
|
||
# 最佳损失0.404,在训练集上的精度是85%,在测试集上的精度是80%
|
||
# 最终损失0.504,在训练集上的精度是84%,在测试集上的精度是79%
|
||
# 加了三层卷积层之后,竟然效果还没有之前好,有点欠拟合。但是我发现好像增加训练轮数,也训练不动了。
|
||
# 弄上阿里云的gpu之后,再训练30轮试试,毕竟用上了GPU,一轮也就6分钟,30轮,也就3小时左右,
|
||
# 在GPU上训练可太快了,而且是英伟达A10的GPU,简直狂飙啊。一轮只用了3分钟,比昨天自己用的那个GPU快多了
|
||
# 而且因为自己的batch_size设置的是1,而且num_workers设置的是0,不然会更快,我的天!
|
||
# 不知道咋搞的,设置了30轮,但是只训练了15轮
|
||
# 最佳损失是0.341,在训练集上的精度是88%,在测试集上的精度是82%
|
||
# 最终损失是0.412,在训练集上的精度是88%,在测试集上的精度是81%
|
||
# 又训练了十轮
|
||
# 最佳损失是0.270,在训练集上的精度是%,在测试集上的精度是81%
|
||
# 最终损失是0.309,在训练集上的精度是%,在测试集上的精度是82%
|
||
|
||
# 还有一点,我觉得最后的全连接,从8192直接到120,是不是120给的太小了,可以给到1000?
|
||
# 发现这里面没有padding层,可以考虑加个padding层,看看效果。
|
||
# 给每个卷积层增加了padding=1,这样卷积过程中尺寸不变,然后弄了三个池化层,最终的特征图尺寸是4*4*512,
|
||
# 增加padding了之后,扫描用的时间可能会多一些。
|
||
# 效果竟然出奇的好,在24轮的时候,损失为0.254,在训练集上的精度是90%,在测试集上的精度是85%
|
||
# 最终损失0.138,在训练集上的精度是95%,在测试集上的精度是87%
|
||
# 最佳损失为0.111,在训练集上的精度是95%,在测试集上的精度是87%
|
||
#打算把第二个全连接层参数从120,换成800,然后把num_workers从0换成2,试试效果
|
||
# 在第44轮的时候,损失为0.113,在训练集上的精度是95%,在测试集上的精度是88%
|
||
# 我的天,太炸裂了,又提升了一个百分点,而且这次因为不急着回去,可以训练70轮,我觉得最终还会涨一点点
|
||
# 最佳损失0.067,在训练集上的精度是%,在测试集上的精度是87%
|
||
# 最终损失0.089,在训练集上的精度是97%,在测试集上的精度是89%,这个就训练的很充分了
|
||
# 我的天,也太牛逼了,果然又提升了一个百分点,哈哈,这真是可喜可贺啊
|
||
# 然后决定再加上三层的512特征图,这样就是完整的VGG16了,看看还能不能提高一两个百分点。冲90%有希望了呀。
|
||
# 训练了46轮,损失是0.154,因为要下班了,所以就暂停,明天继续训练,然后明天再训练30轮,我觉得会破记录的。
|
||
# 最佳损失0.087,在训练集上的精度是96%,在测试集上的精度是87%
|
||
# 最终损失0.109,在训练集上的精度是%,在测试集上的精度是87%
|
||
# 我觉得可能是训练不够充分吧,不然不可能还不如从前了,要么就是过拟合了,现在有两种办法,第一,增加20轮训练,第二,增加dropout。
|
||
# 又训练了20轮
|
||
# 最佳损失0.063,在训练集上的精度是%,在测试集上的精度是88%
|
||
# 最终损失XX,在训练集上的精度是96%,在测试集上的精度是88%
|
||
# 打算增加dropout,看看效果,之前可能dropout加的不对
|
||
# 在第一个全连接层,和第二个全连接层,增加dropout,比例为0.2
|
||
# 训练40轮,试试,之前那个GPU-DSW打不开了,重新弄了个,下载数据集好快啊
|
||
# 后面可以考虑把batch_size调大一些,这样训练更快
|
||
# 训练了40轮,最佳损失为0.212,在训练集上的精度是90%,在测试集上的精度是84%
|
||
# 最终损失0.260,在训练集上的精度是89%,在测试集上的精度是83%
|
||
# 好像泛化能力比之前能好一点,从8-9个点,减少到6个点,
|
||
# 因为今天周六,现在已经晚上八点,训练不了多久,再来十轮,把batch_size设置为10
|
||
# 把batch_size设置为10,现在训练速度更快了,太厉害了
|
||
# 既然训练速度这么快,那就干脆再训练20轮,反正20轮,20分钟就完了,原本每轮得4分钟,需要80分钟,
|
||
# 哈哈,自己太笨了,不然早点把batch_size调大了。
|
||
# 再经过了20轮,相当于总共训练了70轮
|
||
# 最佳损失是0.109,在训练集上的精度是96%,在测试集上的精度是88%
|
||
# 最终损失是0.115,在训练集上的精度是%,在测试集上的精度是88%
|
||
# 再训练20轮,相当于训练了90轮
|
||
# 最佳损失是0.092,在训练集上的精度是96%,在测试集上的精度是88%
|
||
# 最终损失是0.096,在训练集上的精度是%,在测试集上的精度是%
|
||
# 明天打算把dropout丢弃比例设置为0.5,训练100轮试试看
|
||
# 训练了100轮,只用了1小时14分钟,果然batch_size作用很大啊
|
||
# 但是大的batch_size可能需要更多的轮数。因为反向传播的次数相对比较少
|
||
# 最终损失0.159,最佳损失0.149。可能是因为drop-out0.5,所以损失有点大.
|
||
# 打算再训练50轮,看看效果
|
||
# 最佳损失0.088,在训练集上的精度是97%,在测试集上的精度是87%
|
||
# 我晕死,我感觉这个drop-out没有发挥作用啊。
|
||
# 那不要drop-out了,继续搞正则化试试,反正就是炼丹嘛,哈哈
|
||
# 先把正则化惩罚项弄个0.001试试。
|
||
# 直接训练150轮,试试
|
||
# 最佳损失为0.091,在训练集上的精度是96%,在测试集上的精度是87%
|
||
# 真是一个让人失望的结果啊,明天把正则化系数提升下,训练150轮试试
|
||
# 将正则化系数设置为0.01,训练150轮
|
||
# 训练了150轮,最终损失为0.351,在训练集上的精度是89%,在测试集上的精度是84%
|
||
# 再训练上100轮,看看效果,损失不太好往下降。
|
||
# 又训练了50轮,损失还是0.345,降不下去了。
|
||
# 打算把正则化惩罚项系数调整为0.005,训练200轮试试
|
||
# 最终损失为0.200,在训练集上的精度是93%,在测试集上的精度是85%
|
||
# 最佳损失为0.176,在训练集上的精度是94%,在测试集上的精度是86%
|
||
# 效果不明显啊,打算再训练100轮试试,感觉还是没有解决过拟合的问题
|
||
# 又训练了40轮,损失为0.167,在训练集上的精度是%,在测试集上的精度是86%
|
||
# 训练到100轮,最终损失为0.173,没有太大变化,在测试集上的精度是85%
|
||
# 直接把正则化惩罚项系数去掉,然后直接用一个预训练的ResNet18来训练下,看看效果
|
||
# 这一次pretrained=False,是一个空的模型,需要自己训练,下次可以直接pretrained=True,用一下它训练好的参数,试试
|
||
# 训练了100轮,损失降到0.60左右,打算再训练100轮试试
|
||
# 又训练了150轮,共250轮,最终损失为0.355,那就再训练150轮。
|
||
# 为什么要训练那么多轮数,是因为真的Resnet18比自己之前的网络要更复杂。
|
||
# 共训练了400轮,损失为0.233,在训练集上的精度是91%,在测试集上的精度是81%
|
||
# 再训练100轮吧。
|
||
# 这个ResNet18收敛速度太慢了,
|
||
# 共训练了500轮,最佳损失为0.193,模型保存文件为64
|
||
# 打算继续训练下去,但是现在没时间了,只能明天,打算试一下预训练模型,看看效果
|
||
# 把卷积层的参数冻结了,只训练全连接层的参数,看看效果
|
||
# 共训练了700轮,最终损失为0.189,在测试集上的精度是81%
|
||
# 最佳损失为0.167,在训练集上的精度是%,在测试集上的精度是82%
|
||
# 原来这200轮训练的只是全连接层的参数,难怪损失降不下去,重新训练200轮吧。
|
||
# 第648轮的时候,损失为0.145,在训练集上的精度是94%,在测试集上的精度是81%
|
||
# 严重过拟合,干脆先不用ResNet了,先用自己搭建的VGG试试,给每层加上批归一化,说不定可以上90%
|
||
# 第84轮,损失为0.111,在训练集上的精度是95%,在测试集上的精度是87%
|
||
# 第116轮,损失为0.076,在训练集上的精度是97%,在测试集上的精度是88%
|
||
# 第176轮,损失为0.049,在训练集上的精度是98%,在测试集上的精度是88%
|
||
# 最终损失0.050,在测试集上的精度是89%
|
||
# 最佳损失0.044,在训练集上的精度是98%,在测试集上的精度是89%
|
||
# 又训练了60轮,最佳损失为0.031,最终损失为0.038,在测试集上的精度都是89%
|
||
# 又训练了40轮,最佳损失为0.029,在训练集上的精度是98%,在测试集上的精度是90%,明天看看能不能把损失降到0.01以下
|
||
# 我的天,上了90%,对得起自己熬夜到了23:26,哈哈。
|
||
# 再训练100轮试试,看看能降到0.01以下不。
|
||
# 第54轮,损失为0.024,在训练集上的精度是99%,在测试集上的精度是90%,稳稳妥妥的上了90%,看来批归一化效果还是很明显的,之前一直上不来
|
||
# 最佳损失0.021,不训练了,换成Adam试试
|
||
# 明天可以考虑把SGD换成Adam试试,然后也可以在程序中加入在测试集上的精度,随时打印输出
|
||
# 还有一个AdamW,是Adam的变种,也可以试试
|
||
# 换成Adam,然后加入了验证集,训练200轮试试。
|
||
# 带上验证集还挺好的,可以损失监督模型在验证集上的精度
|
||
# 训练了90轮,损失为0.096,在验证集上的精度是88%
|
||
# 明天继续训练,再来200轮,看看会不会上91%
|
||
# 我明白验证集昨天好好的,但是今天突然就很高,就是因为训练集和验证集是随便划分的,今天的验证集中的数据,昨天是出现在训练集里的,所以拟合程度会更高一些。
|
||
# 第261轮,损失为0.042,在训练集上的精度是98%,在测试集上的精度是90%
|
||
# 第300轮,损失为0.047,在测试集上的精度是90%
|
||
# 第414轮,损失为0.035,在训练集上的精度是98%,在测试集上的精度是90%
|
||
# 第459轮,损失为0.034,在测试集上的精度是90%,损失好像也降不下去了。
|
||
# 自从换成彩色的日志之后,训练集的精度小于验证集的精度,这个不合理,可能还是程序写的有问题。
|
||
# 训练到后面,训练集的精度就高于验证集和测试集的了
|
||
# 把网络结构搞简单一点,说不定泛化能力更强呢。去掉后面三个512的卷积层,试试效果
|
||
# 在第123轮时,损失为0.075,在验证集上的精度是90.8%,在训练集上的精度是97.7%,在测试集上的精度是89.54%
|
||
# 在第154轮时,损失为0.064,在验证集上的精度是90.94%,在训练集上的精度是97.97%,在测试集上的精度是90.12%
|
||
# 在第178轮时,损失为0.060,在验证集上的精度是91.14%,在训练集上的精度是98.24%,在测试集上的精度是90.21%
|
||
# 使用预训练ResNet18,加入了验证集,以及验证集精度曲线图
|
||
# 训练到82轮时,损失是为0.285,在验证集上的精度是85.02%,在训练集上的精度是90.92%,在测试集上的精度是84.22%
|
||
# 训练到106轮时,损失为0.2314,在验证集上的精度是85.28%,在训练集上的精度是91.79%,在测试集上的精度是83.95%
|
||
# 直接改用ResNet34试下,因为我感觉ResNet18泛化能力挺强的,但是有点欠拟合,因此要选择更复杂一点的网络结构
|
||
# 使用ResNet50训练
|
||
# 训练到37轮时,损失为0.3688,在验证集上的精度是84.96%,在训练集上的精度是88.33%,在测试集上的精度是84.13%
|
||
# 训练到69轮时,损失为0.265,在验证集上的精度是87.18%,在训练集上的精度是89.01%,在测试集上的精度是84.04%
|
||
# 训练到101轮时,损失为0.198,在验证集上的精度是87.44%,在训练集上的精度是93.75%,在测试集上的精度是86.28%
|
||
# 训练到119轮时,损失为0.174,在验证集上的精度是87.5%,在训练集上的精度是94.51%,在测试集上的精度是86.54%
|
||
# 训练到134轮时,损失为0.1638,在验证集上的精度是87.68%,在训练集上的精度是94.88%,在测试集上的精度是86.00%
|
||
# 训练到143轮时,损失为0.1514,在验证集上的精度是87.9%,在训练集上的精度是95.25%,在测试集上的精度是86.83%
|
||
# 训练到156轮时,损失为0.1493,在验证集上的精度是87.96%,在训练集上的精度是95.41%,在测试集上的精度是86.41%
|
||
# 再继续训练了109轮,损失降为0.104,不过在验证集上的精度是87.4%,不再往下降了
|
||
# 我发现用预训练的效果反而不好,那我就直接只用ResNet50网络结构,而不用它的预训练参数
|
||
# 第120轮时,损失为0.517,在验证集上的精度是80.16%,在训练集上的精度是82.43%,在测试集上的精度是78.76%
|
||
# 第200轮时,损失为0.420,在验证集上的精度是81.84%,在训练集上的精度是86.39%,在测试集上的精度是80.4%
|
||
# 使用ResNet101预训练模型,并且冻结前面的参数,只更新全连接层
|
||
# 训练到100多轮,其中在验证集上的精度达到46%,基本上就上不去了。
|
||
# 二供上云弄了云服务器,有英伟达V100的显卡,训练了2小时35分钟,第174轮的时候,在验证集上89.9%,训练集上98.49%,在测试集上88.08%
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
# 后面还可以加上ResNet,据说ResNet在ImageNet比赛的时候,错误率只有3%,好恐怖
|
||
|
||
def modelInfo():
|
||
params_num = sum(p.numel() for p in net.parameters());
|
||
print("当前模型共有%d个参数",params_num)
|
||
|
||
def verify():
|
||
PATH = midModelPath
|
||
net.load_state_dict(torch.load(PATH, map_location=device,weights_only=True))
|
||
correct = 0
|
||
total = 0
|
||
# 验证的时候,不需要记录梯度,加快速度
|
||
with torch.no_grad():
|
||
for data in valloader:
|
||
images, labels = data
|
||
outputs = net(images.to(device))
|
||
# _, predicted = torch.max(outputs.data.to('cpu'), 1)
|
||
_, predicted = torch.max(outputs.data.to('cpu'), 1)
|
||
total += labels.size(0)
|
||
correct += (predicted == labels).sum().item()
|
||
# print('验证集正确率:%d %%' % (100 * correct / total))
|
||
tqdm.write(
|
||
f"验证集正确率: {Fore.BLUE}{100 * correct / total}{Style.RESET_ALL}%")
|
||
global max_val_score
|
||
global break_max_val
|
||
global every_val_acc
|
||
every_val_acc = np.mean(correct / total)
|
||
if(correct/total > max_val_score):
|
||
max_val_score = correct/total
|
||
break_max_val = True
|
||
else:
|
||
break_max_val = False
|
||
|
||
|
||
def mytestTrainSet():
|
||
PATH = midModelPath
|
||
net.load_state_dict(torch.load(PATH, map_location=device,weights_only=True))
|
||
correct = 0
|
||
total = 0
|
||
# 验证的时候,不需要记录梯度,加快速度
|
||
with torch.no_grad():
|
||
for data in trainloader:
|
||
images, labels = data
|
||
outputs = net(images.to(device))
|
||
_, predicted = torch.max(outputs.data.to(device), 1)
|
||
total += labels.size(0)
|
||
correct += (predicted == labels.to(device)).sum().item()
|
||
tqdm.write(
|
||
f"训练集正确率: {Fore.BLUE}{round(100 * correct / total,2)}{Style.RESET_ALL}%")
|
||
|
||
|
||
def eval():
|
||
# net = Net().to(device)
|
||
# print(net)
|
||
# net = Net()
|
||
# # #加载模型
|
||
PATH = midModelPath
|
||
# PATH = finallPATH
|
||
net.load_state_dict(torch.load(PATH,map_location=device,weights_only=True))
|
||
# net.load_state_dict(torch.load(PATH))
|
||
# for param in net.parameters():
|
||
# print(param)
|
||
correct = 0
|
||
total = 0
|
||
# 测试的时候,不需要记录梯度,加快速度
|
||
with torch.no_grad():
|
||
for data in testloader:
|
||
# for data in trainloader:
|
||
images,labels = data
|
||
outputs = net(images.to(device))
|
||
_,predicted = torch.max(outputs.data.to(device),1)
|
||
total += labels.size(0)
|
||
correct += (predicted == labels.to(device)).sum().item()
|
||
# print('正确率:%d %%'% (100*correct /total))
|
||
tqdm.write(
|
||
f"测试集正确率: {Fore.BLUE}{round(100 * correct / total,2)}{Style.RESET_ALL}%")
|
||
|
||
|
||
def draw(epoch_list,val_acc_list):
|
||
plt.plot(epoch_list, val_acc_list)
|
||
plt.xlabel("epoch")
|
||
plt.ylabel("val_acc")
|
||
plt.show()
|
||
|
||
|
||
|
||
if __name__ == '__main__':
|
||
# eval();
|
||
# verify()
|
||
train(200);
|
||
# trainResNet(300);
|
||
# modelInfo();
|
||
|
||
|
||
|