深度学习本科课程 实验4 卷积神经网络

二维卷积实验

1.1 任务内容

  1. 手写二维卷积的实现,并在至少一个数据集上进行实验,从训练时间、预测精 度、Loss变化等角度分析实验结果(最好使用图表展示)(只用循环几轮即可)
  2. 使用torch.nn实现二维卷积,并在至少一个数据集上进行实验,从训练时间、 预测精度、Loss变化等角度分析实验结果(最好使用图表展示)
  3. 不同超参数的对比分析(包括卷积层数、卷积核大小、batchsize、lr等)选其 中至少1-2个进行分析

1.2 任务思路及代码

# 读取数据
import os
import numpy as np
import torch
import PIL
from PIL import Image
import cv2
from torch import nn
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f'当前使用的device为{device}')data_dir = "./resizedImages"
bus_dir = data_dir + os.sep +'bus'
car_dir = data_dir + os.sep +'car'
truck_dir = data_dir + os.sep +'truck'if not os.path.exists(data_dir):os.mkdir(data_dir)
if not os.path.exists(car_dir):os.mkdir(car_dir)
if not os.path.exists(bus_dir):os.mkdir(bus_dir)
if not os.path.exists(truck_dir):os.mkdir(truck_dir)width = 200
height = width
path = "./车辆分类数据集/bus"
busData =  os.listdir(path)
for img_item in busData:if img_item != "desktop.ini":img = Image.open(path + os.sep + img_item)img = img.resize((width, height), Image.LANCZOS)img.save(bus_dir + os.sep + img_item)path = "./车辆分类数据集/car"
carData =  os.listdir(path)
for img_item in carData:if img_item == "desktop.ini":continueimg = Image.open(path + os.sep + img_item)img = img.resize((width, height), Image.LANCZOS)img.save(car_dir + os.sep + img_item)path = "./车辆分类数据集/truck"
truckData =  os.listdir(path)
for img_item in truckData:if img_item == "desktop.ini":continueimg = Image.open(path + os.sep + img_item)img = img.resize((width, height), Image.LANCZOS)img.save(truck_dir + os.sep + img_item)
# 已缩放处理过,存储在根目录下resizedImages文件夹中各分类下
# 超参数设定
epochs = 10
lr = 0.001
batch_size = 32
# 划分数据集
import random
import shutil
import torchvision
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
from torchvision.datasets import ImageFoldertrain_dir = './Classfication-train_data'
test_dir = './Classfication-test_data'if not os.path.exists(train_dir) or not os.path.exists(test_dir):os.mkdir(train_dir)os.mkdir(test_dir)
vehicles = os.listdir(data_dir)bus_dir = train_dir + os.sep +'bus'
car_dir = train_dir + os.sep +'car'
truck_dir = train_dir + os.sep +'truck'
if not os.path.exists(car_dir):os.mkdir(car_dir)
if not os.path.exists(bus_dir):os.mkdir(bus_dir)
if not os.path.exists(truck_dir):os.mkdir(truck_dir)bus_dir = test_dir + os.sep +'bus'
car_dir = test_dir + os.sep +'car'
truck_dir = test_dir + os.sep +'truck'
if not os.path.exists(car_dir):os.mkdir(car_dir)
if not os.path.exists(bus_dir):os.mkdir(bus_dir)
if not os.path.exists(truck_dir):os.mkdir(truck_dir)
# 项目结构:
# ./(根目录)
#     resizedImages/
#         bus/
#         car/
#         truck/
#     Classfication-train_data/
#         bus/
#         car/
#         truck/
#     Classfication-test_data/
#         bus/
#         car/
#         truck/split_rate = 0.8
# 训练集:测试集=8:2
# 开始拷贝for folder in vehicles: # car, bus, truckprint(folder)file_names = np.array(os.listdir(os.path.join(data_dir,folder)))train_number = int(len(file_names) * split_rate)total_number = list(range(len(file_names)))print(f"训练集数量: {train_number}, 测试集数量{len(file_names) - train_number}")if len(os.listdir(train_dir + os.sep + folder)) != 0:continuerandom.shuffle(total_number)  # 打乱下标# 获得打乱下标后的训练集和测试集的数据train_files = file_names[total_number[0: train_number]]test_files = file_names[total_number[train_number:]]for file in train_files:if file == "desktop.ini":continuepath_train = os.path.join(data_dir, folder) + os.sep + filepath_train_copy = train_dir + os.sep + folder + os.sep + fileshutil.copy(path_train, path_train_copy) # 将文件复制到训练集文件夹for file in test_files:if file == "desktop.ini":continuepath_test = os.path.join(data_dir, folder) + os.sep + filepath_test_copy = test_dir + os.sep + folder + os.sep + fileshutil.copy(path_test, path_test_copy)  # 讲文件复制到测试集文件夹transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5,0.5,0.5), (0.5,0.5,0.5))])# 归一化
# 相关参数
train_data = ImageFolder(root=train_dir, transform=transform)
train_loader = DataLoader(dataset=train_data, shuffle=True, batch_size=batch_size)
test_data = ImageFolder(root=test_dir, transform=transform)
test_loader = DataLoader(dataset=test_data, shuffle=True, batch_size=batch_size)print()
print(f"训练集数量 :{len(train_data)}")
print(f"测试集数量 :{len(test_data)}")
from torch import nn
# 定义卷积
def corr2d(X, K, kernel_size):'''X, shape(batch_size,H,W)kernel_size, shape(k_h, k_w)'''batch_size, H,W = X.shapek_h, k_w = kernel_sizeY = torch.zeros((batch_size, H-k_h+1, W-k_w+1)).to(device)for i in range(Y.shape[0]):for j in range(Y.shape[1]):Y[:, i, j] = (X[:,i: i+k_h, j:j+k_w]*K).sum(dim=2).sum(dim=1)return Y# 多通道输入
# 卷积核通道数 = 输入通道数
def corr2d_multi_in(X, K, kernel_size):res = corr2d(X[:, 0, :, :], K[0, :, :],kernel_size)for i in range(1, X.shape[1]):res += corr2d(X[:,i,:,:], K[i,:,:], kernel_size)return res# 多通道输出
# 输出通道数 = 卷积核个数
def corr2d_multi_in_out(X, K, kernel_size):return torch.stack([corr2d_multi_in(X, k, kernel_size) for k in K])# 将卷积运算封装成卷积层
class myConv2d(nn.Module):def __init__(self, in_channels, out_channels, kernel_size):super(myConv2d, self).__init__()if isinstance(kernel_size, int):  self.kernel_size = (kernel_size, kernel_size)self.weight = nn.Parameter(torch.randn((out_channels, in_channels) + self.kernel_size)).to(device)self.bias = nn.Parameter(torch.randn(out_channels, 1,1))def forward(self, x):return corr2d_multi_in_out(x, self.weight, self.kernel_size) + self.bias
# 手动实现二维 CNN
import torch.nn.functional as Fclass myCNN(torch.nn.Module):def __init__(self, num_classes):super(myCNN, self).__init__()self.conv = nn.Sequential(myConv2d(in_channels=3, out_channels=32, kernel_size=3),torch.nn.BatchNorm2d(32),torch.nn.ReLU(inplace=True) )self.fc = torch.nn.Linear(32, num_classes)def forward(self, X):# 根据实验要求,图片经过一层卷积,输出(batch_size, C_out, H, W)out = self.conv(X)# 使用平均池化层将图片大小变为1*1out = F.avg_pool2d(out, 198) # 图片大小为200*200,卷积后为198out = out.squeeze()# 输入到全连接层out = self.fc(out)return out
# nn实现二维卷积
class nnCNN(nn.Module):def __init__(self, num_classes):super(nnCNN,self).__init__()# 三层卷积self.conv = nn.Sequential(# 这里设置了填充,因为图片大小为 200*200,运算过程出现了小数,这里是考虑不周到的地方nn.Conv2d(in_channels=3,out_channels=32,kernel_size=3,stride=1,padding=1),nn.BatchNorm2d(32),nn.ReLU(inplace=True),nn.Conv2d(in_channels=32,out_channels=64,kernel_size=3,stride=1,padding=1),nn.BatchNorm2d(64),nn.ReLU(inplace=True),nn.Conv2d(in_channels=64,out_channels=128,kernel_size=3,stride=1,padding=1),nn.BatchNorm2d(128),nn.ReLU(inplace=True))self.fc = nn.Linear(128,num_classes)def forward(self,X):out= self.conv(X)out = F.avg_pool2d(out, kernel_size=out.size()[2:])out = out.view(out.size(0), -1)out = self.fc(out)return out
# 定义训练函数
import time
from torch.nn import CrossEntropyLoss
from torch.optim import SGD
criterion = CrossEntropyLoss()
criterion = criterion.to(device)
# 测试加训练
def train_with_test(net, train_loader, test_loader,batch_size=32, epochs=10, lr=0.001, optimizer=None, disp=True, skip=False):if disp:print(net)if optimizer == None:optimizer = SGD(net.parameters(), lr=lr) train_batch_num = len(train_loader)train_loss_list = []train_acc= []train_loss_in_batch, train_acc_in_batch = [], []test_loss_list =[]test_acc=[]begin_time = time.time()for epoch in range(epochs):train_loss, acc = 0, 0train_sample_num = 0# acc_num = 0jmp = 25for batch_idx, (data, target) in enumerate(train_loader):# batch_size = 32if len(data) != batch_size:continue# if batch_idx == 2:#     breakif skip and batch_idx < jmp:continueif skip and batch_idx % 2 == 0:continue # 加快训练,卷积训练太慢,主要看手动卷积的效果tb1 = time.time()data, target = data.to(device), target.to(device)prediction = net(data)loss = criterion(prediction, target)optimizer.zero_grad()loss.backward()optimizer.step()# 循环内损失率train_loss_in_batch.append(loss.to('cpu')/len(prediction))# 循环损失率train_loss += loss.item()# 循环内正确率train_batch_acc_num = (prediction.argmax(dim=1)==target).sum()train_acc_in_batch.append(train_batch_acc_num.to('cpu')/len(prediction))# 循环正确率acc += train_batch_acc_numtrain_sample_num += len(prediction)tb2=time.time()if skip or batch_idx % 4 == 0:print(f"\t|Train-in-batch:{batch_idx+1}/{len(train_loader)}, loss:{train_loss/train_sample_num}, acc:{acc/train_sample_num}, 耗时:{tb2-tb1}s")train_acc.append(acc.to('cpu')/train_sample_num)train_loss_list.append(train_loss/train_sample_num)# 测试test_batch_num = len(test_loader)total_loss = 0sample_num2=0acc2 = 0with torch.no_grad():for batch_idx, (data, target) in enumerate (test_loader):if len(data) != batch_size:continue# if batch_idx == 2:#     breakdata, target = data.to(device), target.to(device)prediction = net(data)loss = criterion(prediction, target)# 循环总损失total_loss += loss.item()sample_num2 += len(prediction)# 循环总正确acc_num2 = (prediction.argmax(dim=1)==target).sum()acc2 += acc_num2test_loss_list.append(total_loss/sample_num2)test_acc.append(acc2.to('cpu')/sample_num2)print('***epoch: %d***train loss: %.5f***train acc:%5f***test loss:%.5f***test acc:%5f' % (epoch + 1, train_loss_list[epoch], train_acc[epoch],test_loss_list[epoch],test_acc[epoch]))print()end_time = time.time()print('%d轮总用时: %.2fs'%(epochs, end_time-begin_time))# 返回全部损失,准确率return train_loss_in_batch, train_acc_in_batch, train_loss_list, train_acc, test_loss_list, test_acc# 测试函数(单独)
def test_epoch(net, data_loader, disp=False):# net.eval()if disp:print(net)test_batch_num = len(data_loader)total_loss = 0acc = 0sample_num = 0with torch.no_grad():for batch_idx, (data, target) in enumerate (data_loader):if len(data) != 32:continue# if batch_idx == 2:#     breaktb1 = time.time()data, target = data.to(device), target.to(device)prediction = net(data)loss = criterion(prediction, target)total_loss += loss.item()sample_num += len(prediction)acc_num = (prediction.argmax(dim=1)==target).sum()acc += acc_numtb2 = time.time()print(f"\t|Test-in-batch:{batch_idx+1}/{len(data_loader)}, loss:{total_loss/sample_num}, acc:{acc/sample_num}, 耗时:{tb2-tb1}s")loss = total_loss/test_batch_numtest_acc = acc/sample_numreturn loss, test_acc
# 小批量数据,减少GPU压力
train_loader16 = DataLoader(dataset=train_data, shuffle=True, batch_size=16)
test_loader16 = DataLoader(dataset=test_data, shuffle=True, batch_size=16)
# 定义画图函数
import matplotlib.pyplot as plt
def plot_batching(train_loss, train_acc):plt.figure(1)plt.xlabel('batch')plt.ylabel('loss')plt.title('Loss-Rate')# plt.plot([i for i in range(len(train_loss))], train_loss[i], 'b-', label=u'train_loss')mylist = []for i in range(len(train_loss)):mylist.append(train_loss[i].detach().numpy())plt.plot([i for i in range(len(train_loss))], mylist, 'b-', label=u'train_loss')plt.legend() plt.figure(2)plt.xlabel("batch")  plt.ylabel("Acc")  plt.title("Accuracy")  plt.plot([i for i in range(len(train_acc))], train_acc, 'r-', label=u'train_acc')plt.legend() def plot_learning(train_loss, train_acc, test_loss, test_acc):plt.figure(1)plt.xlabel('epoch')plt.ylabel('loss')plt.title('Loss-Rate')plt.plot([i for i in range(len(train_loss))], train_loss, 'b-', label=u'train_loss')plt.legend() plt.plot([i for i in range(len(test_loss))], test_loss, 'r-', label=u'test_loss')plt.legend() plt.figure(2)plt.xlabel("epoch")  plt.ylabel("Acc")  plt.title("Accuracy")  plt.plot([i for i in range(len(train_acc))], train_acc, 'b-', label=u'train_acc')plt.legend() plt.plot([i for i in range(len(test_acc))], test_acc, 'r-', label=u'test_acc')plt.legend()  plt.show()
# 手动实现
torch.cuda.empty_cache()
net11 = myCNN(3).to(device)
train_l_111, train_acc_111, train_l_112, train_acc_112, test_l11, test_acc11 = train_with_test(net11, train_loader, test_loader, batch_size=32, epochs=1, lr=0.01, optimizer=None, disp=True, skip=True)

手动实现卷积的结果

# 图表展示以batch为单位的训练结果
plot_batching(train_l_111, train_acc_111)
# nn实现卷积
torch.cuda.empty_cache()
net12 = nnCNN(3).to(device)
train_l_121, train_acc_121, train_l_122, train_acc_122, test_l12, test_acc12 = train_with_test(net12, train_loader, test_loader, epochs=10, lr=0.001)

nn实现卷积的结果

plot_learning(train_l_122, train_acc_122, test_l12, test_acc12)

探究超参数对CNN的影响

# 修改卷积层数
# 只用一层卷积
class nnCNNof1(nn.Module):def __init__(self, num_classes):super(nnCNNof1,self).__init__()# 三层卷积self.conv = nn.Sequential(# 这里设置了填充,因为图片大小为 200*200,运算过程出现了小数,这里是考虑不周到的地方nn.Conv2d(in_channels=3,out_channels=32,kernel_size=3,stride=1,padding=1),nn.BatchNorm2d(32),nn.ReLU(inplace=True),)self.fc = nn.Linear(32,num_classes)def forward(self,X):out= self.conv(X)out = F.avg_pool2d(out, kernel_size=out.size()[2:])out = out.view(out.size(0), -1)out = self.fc(out)return outtorch.cuda.empty_cache()
net13 = nnCNNof1(3).to(device)
train_l_131, train_acc_131, train_l_132, train_acc_132, test_l13, test_acc13 = train_with_test(net13, train_loader, test_loader, epochs=10, lr=lr)
# 作图对比
plot_learning(train_l_122, train_acc_122, test_l12, test_acc12)
plot_learning(train_l_132, train_acc_132, test_l13, test_acc13)
# 修改学习率
lr12 = 0.01
# lr = 0.001
torch.cuda.empty_cache()
net14 = nnCNN(3).to(device)
train_l_141, train_acc_141, train_l_142, train_acc_142, test_l14, test_acc14 = train_with_test(net14, train_loader, test_loader, epochs=10, lr=lr12)
# 作图对比
plot_learning(train_l_122, train_acc_122, test_l12, test_acc12)
plot_learning(train_l_142, train_acc_142, test_l14, test_acc14)

小结

  1. 实验一中我将一层卷积与三层卷积进行了对比,前者loss下降的很慢,且预测正确率明显低于三层卷积,说明增加模型层数可以有助于获取更多、更高级别的特征表示,从而提高模型的预测能力;深度不够的模型,参数更新很慢,性能也不尽人意;模型深度提升三倍,训练时间也提升到接近三倍,似乎说明在本问题中模型深度与训练时间成正比
  2. 我将三层卷积模型的学习率由0.001提升至0.01,损失率得到更大幅度的下降且仍呈圆弧状变化,说明该学习率是可被接纳的优秀学习率,初始0.001的学习率有些保守了;但从正确率来看,lr=0.01的曲线趋于平缓,似乎很难再单从学习率调整以达到更好的模型表现

二、空洞卷积实验

2.1 任务内容

  1. 用torch.nn实现空洞卷积,要求dilation满足HDC条件(如1,2,5)且要 堆叠多层并在至少一个数据集上进行实验,从训练时间、预测精度、Loss
    变化等角度分析实验结果(最好使用图表展示)
  2. 将空洞卷积模型的实验结果与卷积模型的结果进行分析比对,训练时间、 预测精度、Loss变化等角度分析
  3. 不同超参数的对比分析(包括卷积层数、卷积核大小、不同dilation的选择, batchsize、lr等)选其中至少1-2个进行分析(选做)

2.2 任务思路及代码

# nn实现空洞卷积  
class nnDCNN(nn.Module):  def __init__(self,num_classes):  super(nnDCNN,self).__init__()  # 三层卷积self.conv=nn.Sequential(  # 添加padding,否则出现小数,下次一定要把图片缩放成2的幂nn.Conv2d(in_channels=3,out_channels=32,kernel_size=3,stride=1,padding=1,dilation=1),  nn.BatchNorm2d(32),  nn.ReLU(inplace=True),  nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, stride=1, padding=2,dilation=2),  nn.BatchNorm2d(64),  nn.ReLU(inplace=True),  nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, stride=1, padding=4,dilation=5),  nn.BatchNorm2d(128),  nn.ReLU(inplace=True),  )#输出层,将通道数变为分类数量  self.fc = nn.Linear(128,num_classes)  def forward(self,x):  out = self.conv(x)  out = F.avg_pool2d(out, kernel_size=out.size()[2:])  out = out.squeeze()  out = self.fc(out)  return out 
torch.cuda.empty_cache()
net21 = nnDCNN(num_classes=3).to(device)
train_l_211, train_acc_211, train_l_212, train_acc_212, test_l21, test_acc21 = train_with_test(net21, train_loader, test_loader, epochs=10, lr=0.001)

与CNN进行比对

plot_learning(train_l_212, train_acc_212, test_l21, test_acc21)
plot_learning(train_l_122, train_acc_122, test_l12, test_acc12)

探究超参数

# 修改层数
class nnDCNNof6(nn.Module):  def __init__(self, num_classes):  super(nnDCNNof6, self).__init__()  # 六层卷积self.conv = nn.Sequential(  nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, stride=1, padding=1, dilation=1),  nn.BatchNorm2d(32),  nn.ReLU(inplace=True),  nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, stride=1, padding=2, dilation=2),  nn.BatchNorm2d(64),  nn.ReLU(inplace=True),  nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, stride=1, padding=4, dilation=5),  nn.BatchNorm2d(128),  nn.ReLU(inplace=True),nn.Conv2d(in_channels=128, out_channels=256, kernel_size=3, stride=1, padding=8, dilation=10),  nn.BatchNorm2d(256),  nn.ReLU(inplace=True),nn.Conv2d(in_channels=256, out_channels=512, kernel_size=3, stride=1, padding=16, dilation=15),  nn.BatchNorm2d(512),  nn.ReLU(inplace=True),nn.Conv2d(in_channels=512, out_channels=1024, kernel_size=3, stride=1, padding=32, dilation=20),  nn.BatchNorm2d(1024),  nn.ReLU(inplace=True),nn.Conv2d(in_channels=1024, out_channels=2048, kernel_size=3, stride=1, padding=64, dilation=25),  nn.BatchNorm2d(2048),  nn.ReLU(inplace=True),)# 输出层,将通道数变为分类数量  self.fc = nn.Linear(2048, num_classes)  def forward(self, x):  out = self.conv(x)  out = F.avg_pool2d(out, kernel_size=out.size()[2:])  out = out.squeeze()  out = self.fc(out)  return outtorch.cuda.empty_cache()
net22 = nnDCNNof6(num_classes=3).to(device)
train_l_221, train_acc_221, train_l_222, train_acc_222, test_l22, test_acc22 = train_with_test(net22, train_loader, test_loader, epochs=10, lr=0.001)
# 作图比对
plot_learning(train_l_212, train_acc_212, test_l21, test_acc21)
plot_learning(train_l_222, train_acc_222, test_l22, test_acc22)
# 修改batch_size
torch.cuda.empty_cache()
net23 = nnDCNN(num_classes=3).to(device)
train_l_231, train_acc_231, train_l_232, train_acc_232, test_l23, test_acc23 = train_with_test(net23, train_loader16, test_loader16,batch_size=16, epochs=10, lr=0.001)
# 作图比对
plot_learning(train_l_212, train_acc_212, test_l21, test_acc21)
plot_learning(train_l_232, train_acc_232, test_l23, test_acc23)

小结

  1. 空洞卷积和普通卷积的基本操作相同,都是通过卷积核与输入进行卷积操作。但它具有的扩展感受野、共享参数等性质,使得网络能更好地捕捉样本中的信息,因此获得了更好的正确率;空洞卷积的稀疏性也使得它比普通卷积的训练更快
  2. 在超参数实验中,我大胆尝试了将空洞卷积的模型深度翻倍:这造成了严重后果,我的电脑的GPU(显存16GB)根本无法负担这样的训练任务,说明模型深度的增加不仅会加大时间开销,更会造成GPU空间的更大占用,并增大算力负担;模型深度每增大k倍,造成的时间空间开销会增大p倍,p大于等于k。
  3. 结果上来看,小批量的训练(74.87s)要慢于大批量的训练(66.99s),但小批量的性能略微更优,因为它可以更频繁地更新模型参数,提供更多的随机性,对模型的泛化性能更有益。

三、残差网络实验

3.1 任务内容

实现给定结构的残差网络,在 至少一个数据集上进行实验, 从训练时间、预测精度、Loss 变化等角度分析实验结果(最
好使用图表展示)

3.2 任务思路及代码

class ResBlock(nn.Module):def __init__(self, in_channels, out_channels, stride=[1, 1], padding=1):super(ResBlock, self).__init__()self.layer = nn.Sequential(nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride[0], padding=padding, bias=False),nn.BatchNorm2d(out_channels),nn.ReLU(inplace=True),nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=stride[1], padding=padding, bias=False),nn.BatchNorm2d(out_channels))self.shortcut = nn.Sequential()if stride[0] != 1 or in_channels != out_channels:self.shortcut = nn.Sequential(nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride[0], bias=False),nn.BatchNorm2d(out_channels))def forward(self, x):out = self.layer(x)shortcut = self.shortcut(x)if shortcut.size(1) != out.size(1):shortcut = F.pad(shortcut, (0, 0, 0, 0, 0, out.size(1) - shortcut.size(1)))out += shortcutout = F.relu(out)return out
class nnResNet(nn.Module):def __init__(self, num_classes=3) -> None:super(nnResNet, self).__init__()self.in_channels = 64self.conv1 = nn.Sequential(nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False),nn.BatchNorm2d(64))self.conv2 = self.set_layer(64, [[1, 1], [1, 1]])self.conv3 = self.set_layer(128, [[2, 1], [1, 1]])  self.conv4 = self.set_layer(256, [[2, 1], [1, 1]])  self.conv5 = self.set_layer(512, [[2, 1], [1, 1]])  self.avgpool = nn.AdaptiveAvgPool2d((1, 1))self.fc = nn.Sequential(nn.Linear(512, 256),nn.Linear(256, 128),nn.Linear(128, num_classes))def set_layer(self, out_channels, strides):layers = []for stride in strides:layers.append(BasicBlock(self.in_channels, out_channels, stride))self.in_channels = out_channelsreturn nn.Sequential(*layers)# 图片的大小为 200*200def forward(self, x):out = self.conv1(x)  # [32, 64, 200, 200]out = self.conv2(out)  # [32, 64, 200, 200]out = self.conv3(out)  # [32, 128, 100, 100]out = self.conv4(out)  # [32, 256, 50, 50]out = self.conv5(out)  # [32, 512, 25, 25]out = F.avg_pool2d(out, 25)  # [32, 512, 1, 1]out = out.squeeze()  # [32, 512]out = self.fc(out)return out
torch.cuda.empty_cache()
net31=nnResNet(num_classes=3).to(device)
train_l_311, train_acc_311, train_l_312, train_acc_312, test_l31, test_acc31 = train_with_test(net31, train_loader16, test_loader16, batch_size=16, epochs=10, lr=0.001, disp=True, skip=True)
# 绘制训练过程
plot_learning(train_l_312, train_acc_312, test_l31, test_acc31)

小结

  1. 从训练结果来看,首先,由loss曲线,知本次训练的学习率过低,应使它接近于一个凹函数。
  2. 其次,从正确率来看,残差模型达到了本次实验的最高正确度(>0.8)。
  3. 从训练时间来看,残差网络的效率也很高,并没有比卷积和空洞卷积慢出很多;而残差网络的深度远远高于卷积网络,说明它具有更强的学习能力,能够学习更复杂的特征。
  4. test_acc与train_acc平齐甚至更高,说明模型没有过拟合,残差网络具有更优异的优化和收敛性质。

实验总结

首先,本次实验学习了卷积、空洞卷积和残差网络三种模型,掌握了手动实现它们的训练过程,了解了它们的性质和优势。

其次,实验中有很多模型训练的地方值得优化,例如处理数据集图像时索性取最大值,将每张图片都缩放至200*200,这一点造成了维数降低时出现了小数,通过引入padding解决了这一问题。更加妥善的做法是采用2的幂,而不是随便一个数字。

最后,使用超参数的能力有所提升,包括对batch、学习率和模型深度的理解,增加了对机器学习实践的经验。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/667932.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ShardingSphere 5.x 系列【5】Spring Boot 3.1 集成Sharding Sphere-JDBC并实现读写分离

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Spring Boot 版本 3.1.0 本系列ShardingSphere 版本 5.4.0 源码地址&#xff1a;https://gitee.com/pearl-organization/study-sharding-sphere-demo 文章目录 1. 概述2. 使用限制3. 案例演示3.…

[Angular 基础] - 数据绑定(databinding)

[Angular 基础] - 数据绑定(databinding) 上篇笔记&#xff0c;关于 Angular 的渲染过程及组件的创建&简单学习&#xff1a;[Angular 基础] - Angular 渲染过程 & 组件的创建 Angular 之中的 databinding 是一个相对而言更加复杂&#xff0c;以及我个人觉得相对而言比…

算法笔记刷题日记——3.简单入门模拟 3.1简单模拟

刷题日记 3.1 简单模拟 此类题型根据题目描述进行代码的编写&#xff0c;考察代码能力&#xff0c;刷题记录如下&#xff1a; B1001 B1032 B1016 B1026 B1046 B1008 B1012 B1018 A1042 A1046 A1065 B1010 A1002 A1009 错题记录 B1008 数组元素循环右移问题 一个数组_A_中存有…

[机缘参悟-145] :一个软件架构师对佛学的理解 -9- 修行的目标和层次:净心、智慧和解脱

目录 前言&#xff1a; 第一层次&#xff08;小乘&#xff09;&#xff1a;净心&#xff0c;摆脱痛苦和烦扰&#xff0c;进入平静和安宁 1.1 什么是净心 1.2 如何达到净心的状态 1.3 "常乐我净" 第二层次&#xff08;中乘&#xff09;&#xff1a;智慧&#xf…

【Spring连载】使用Spring Data访问Redis(十三)----支持类Support Classes

【Spring连载】使用Spring Data访问Redis&#xff08;十三&#xff09;----支持类Support Classes org.springframework.data.redis.support包提供了各种可重复使用的组件&#xff0c;这些组件依赖Redis作为后端存储。目前&#xff0c;该包包含Redis之上的各种基于JDK的接口实现…

SpringMVC精简知识点

SpringMVC 数据格式化基本数据类型和字符串自动转换特殊数据类型和字符串自动转换 验证及国际化应用实例注意事项和使用细节注解的结合使用数据类型转换校验核心类-DatBinder取消某个属性的绑定中文乱码解决处理json和HttpMessageConverter<T>作业布置SpringMVC文件上传自…

day19 初始HTML

什么是HTML HTML&#xff08;Hyper Text Markup Language&#xff09;超文本标记语言 超文本包括&#xff1a;文字、图片、音频、视频、动画等 HTML5&#xff0c;提供了一些新的元素和一些有趣的新特性&#xff0c;同时也建立了一些新的规则。这些元素、特性和规则的建立&…

【Linux】进程间通信 --管道通信

Halo&#xff0c;这里是Ppeua。平时主要更新C语言&#xff0c;C&#xff0c;数据结构算法…感兴趣就关注我吧&#xff01;你定不会失望。 本篇导航 0. 进程间通信原理1. 匿名管道1.1 通信原理1.2 接口介绍 2. 命名管道2.1 接口介绍 3. 共享内存3.1 通信原理3.2 接口介绍 0. 进…

用户访问一个购物网站时TCP/IP五层参考模型中每一层的功能

当用户访问一个购物网站时&#xff0c;网络上的每一层都会涉及不同的协议&#xff0c;具体网络模型如下图所示。 以下是每个网络层及其相关的协议示例&#xff1a; 物理层&#xff1a;负责将比特流传输到物理媒介上&#xff0c;例如电缆或无线信号。所以在物理层&#xff0c;可…

Dell服务器iDRAC9忘记密码, 通过RACADM工具不重启 重置密码

系列文章目录 文章目录 系列文章目录前言一、RACADM工具二、linux环境1.解压安装RACADM工具测试RACADM工具重置iDRAC密码 Windows环境 前言 一、RACADM工具 RACADM工具 官网参考信息 https://www.dell.com/support/kbdoc/zh-cn/000126703/%E5%A6%82%E4%BD%95-%E9%87%8D%E7%BD…

异步八种方式提高性能

异步的八种实现方式 线程ThreadFuture异步框架CompletableFutureSpring注解AsyncSpring ApplicationEvent事件消息队列第三方异步框架&#xff0c;比如Hutool的ThreadUtilGuava异步 一、线程异步 public class AsyncThread extends Thread{Overridepublic void run(){System…

东方博宜1126:英文翻译

题目描述 请将一个数字&#xff0c;翻译成对应的英文。 输入 一个自然数 n。&#xff08;0≤n≤2^31−1&#xff09; 输出 输出这个数的英文&#xff0c;最后不要有多余的空格。 输入样例&#xff1a; 1111111111 输出样例&#xff1a; one billion one hundred and e…

计算机网络-封装成帧透明传输(组帧方法)

文章目录 数据链路层功能概述封装成帧透明传输组帧方法字符计数法字符填充法零比特填充法违规编码法 字符填充法为啥复杂和不兼容 数据链路层功能概述 类似老板让小秘书送文件给别的公司&#xff0c;小秘书告诉傻子怎么把该文件送到别的公司的小秘书&#xff0c;然后别的公司的…

c# File.WriteAllLines 和 File.WriteAllText

File.WriteAllLines 和 File.WriteAllText 都是 C# 中用于写入文本文件的方法&#xff0c;但它们有一些区别。 1. File.WriteAllLines 方法&#xff1a; File.WriteAllLines 方法用于将字符串数组的内容按行写入文本文件。每个数组元素都被写入文件的一行&#xff0c;且方法会…

探索边缘计算的未来:MobileNetV3Small及其在高效图像处理中的创新应用

引言 在不断发展的计算机视觉和深度学习领域中&#xff0c;对于更高效、更强大的神经网络的追求从未停止。在这个领域的领跑者之一是MobileNetV3Small架构&#xff0c;这是MobileNetV3家族的一个变体&#xff0c;以其在处理图像任务方面的高效率和有效性而闻名。本文深入探讨了…

Blender 的重拓扑功能中的参数,

关于 Blender 的重拓扑功能中的一个参数&#xff0c;叫做 Voxel Size R。我会尽量用简单的语言来解释它的含义和作用。 Voxel Size R 是指重拓扑后的网格的分辨率或细节程度。它用来定义 Voxel 的大小&#xff0c;Voxel 是一种用来表示三维空间中的体积元素的单位。重拓扑的过…

Hello 2024C. Grouping Increases(贪心、分类讨论)

我们只需要记录每个数结尾的数是多少&#xff08;有点最长上升子序列的味道&#xff09; 这种子序列的题目很多都是这样的&#xff0c;因为不需要连续很多时候我们只记录最后一个元素是多少。 记 s 为较大子序列结尾当前的数&#xff0c; t 为较小子序列结尾的数&#xff0c;下…

Symbol.toStringTag用法

Symbol.toStringTag 作用 对象上的Symbol.toStringTag属性用于对象toString类型标识 Symbol.toStringTag 解释 对象调用toString方法&#xff0c;如果这个属性存在&#xff0c;它的返回值会出现在toString方法返回的字符串之中&#xff0c;表示对象的类型。 webpack中也有使…

Spring面试

文章目录 Spring面试Spring框架用了什么设计模式&#xff1f;Spring Bean的作用域Spring如何解决循环依赖什么样的循环依赖无法处理构造方法注入 VS setter注入 Spring框架中有哪些不同类型的事件&#xff1f;AOP (Aspect Oriented Program) 切面编程IOC容器BeanFactory 与 App…

修改UnityEngine dll

修改UnityEngine dll 由于有些版本的dll与热重载并不兼容&#xff0c;需要小幅修改代码。 使用dnspy工具 我们使用 dnspy 来修改 dll文件。而dnspy只能在Win下运行&#xff0c;故哪怕是mac版本dll&#xff0c; 你也得先将相应dll复制到Win下后再修改。下载 dnspy&#xff0c…