当前位置: 首页 > news >正文

CV09_深度学习模块之间的缝合教学(4)--调参

深度学习就像炼丹。炉子就是模型,火候就是那些参数,材料就是数据集。

1.1 参数有哪些

调参调参,参数到底是哪些参数?

1.网络相关的参数:(1)神经网络网络层

(2)隐藏层的神经元个数等

(3)卷积核的数量

(4)损失层函数的选择

2.数据预处理的相关参数:(1)batch normalization(2)等等

3.超参数:(1)激活函数(2)初始化(凯明初始化等)

(3)梯度下降(SGD、Adam)

(4)epoch (5)batch size

(6)学习率lr (7)衰减函数、正则化等

1.2 常见的情况及原因

1.通常是在网络训练的结果:(1)过拟合----样本数量太少了

(2)欠拟合----样本多但模型简单

(3)拟合,但是在上下浮动(震荡)

(4)恰好拟合

(5)模型不收敛

1.3 解决方法

(1)过拟合----数据增强、早停法、drop out、降低学习率、调整epoch

(2)欠拟合----加深层数、尽量用非线性的激活函数如relu

(3)拟合但震荡----降低数据增强的程度、学习率

(4)

(5)模型不收敛----数据集有问题、网络模型有问题

1.4 调参的过程

1.搭建网络模型

2.先用小样本进行尝试模型效果

3.根据小样本的效果,进行调参,包括分析损失。

1.5 代码(CPU训练)

# Author:SiZhen
# Create: 2024/7/14
# Description: 调参练习-以手写数字集为例import  torch
import torch.nn as nn
import torchvision
import torch.utils
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
#设置超参数
from torch import optim
from torch.nn import initbatch_size = 64
hidden_size = 128
learning_rate = 0.001
num_epoch = 10#将图片进行预处理转换成pytorch张量
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5,),(0.5,),)]) #mnist是单通道,所以括号内只有一个0.5#下载训练集
train_set = torchvision.datasets.MNIST(root="./data",train=True,download=True,transform=transform)#下载测试集
test_set = torchvision.datasets.MNIST(root="./data",train=False,download=True,transform=transform)#加载数据集
train_loader= torch.utils.data.DataLoader(train_set,batch_size=batch_size,shuffle=True)test_loader = torch.utils.data.DataLoader(test_set,batch_size=batch_size,shuffle=False)#测试不shuffleinput_size = 784 #mnist,28x28像素
num_classes = 10class SEAttention(nn.Module):# 初始化SE模块,channel为通道数,reduction为降维比率def __init__(self, channel=1, reduction=8):super().__init__()self.avg_pool = nn.AdaptiveAvgPool2d(1)  # 自适应平均池化层,将特征图的空间维度压缩为1x1self.fc = nn.Sequential(  # 定义两个全连接层作为激励操作,通过降维和升维调整通道重要性nn.Linear(channel, channel // reduction, bias=False),  # 降维,减少参数数量和计算量nn.ReLU(inplace=True),  # ReLU激活函数,引入非线性nn.Linear(channel // reduction, channel, bias=False),  # 升维,恢复到原始通道数nn.Sigmoid(),  # Sigmoid激活函数,输出每个通道的重要性系数)# 权重初始化方法def init_weights(self):for m in self.modules():  # 遍历模块中的所有子模块if isinstance(m, nn.Conv2d):  # 对于卷积层init.kaiming_normal_(m.weight, mode='fan_out')  # 使用Kaiming初始化方法初始化权重if m.bias is not None:init.constant_(m.bias, 0)  # 如果有偏置项,则初始化为0elif isinstance(m, nn.BatchNorm2d):  # 对于批归一化层init.constant_(m.weight, 1)  # 权重初始化为1init.constant_(m.bias, 0)  # 偏置初始化为0elif isinstance(m, nn.Linear):  # 对于全连接层init.normal_(m.weight, std=0.001)  # 权重使用正态分布初始化if m.bias is not None:init.constant_(m.bias, 0)  # 偏置初始化为0# 前向传播方法def forward(self, x):b, c, _, _ = x.size()  # 获取输入x的批量大小b和通道数cy = self.avg_pool(x).view(b, c)  # 通过自适应平均池化层后,调整形状以匹配全连接层的输入y = self.fc(y).view(b, c, 1, 1)  # 通过全连接层计算通道重要性,调整形状以匹配原始特征图的形状return x * y.expand_as(x)  # 将通道重要性系数应用到原始特征图上,进行特征重新校准
import torch
import torch.nn as nn
from torch.nn import Softmax# 定义一个无限小的矩阵,用于在注意力矩阵中屏蔽特定位置
def INF(B, H, W):return -torch.diag(torch.tensor(float("inf")).repeat(H), 0).unsqueeze(0).repeat(B * W, 1, 1)class CrissCrossAttention(nn.Module):""" Criss-Cross Attention Module"""def __init__(self, in_dim):super(CrissCrossAttention, self).__init__()# Q, K, V转换层self.query_conv = nn.Conv2d(in_channels=in_dim, out_channels=in_dim // 8, kernel_size=1)self.key_conv = nn.Conv2d(in_channels=in_dim, out_channels=in_dim // 8, kernel_size=1)self.value_conv = nn.Conv2d(in_channels=in_dim, out_channels=in_dim, kernel_size=1)# 使用softmax对注意力分数进行归一化self.softmax = Softmax(dim=3)self.INF = INF# 学习一个缩放参数,用于调节注意力的影响self.gamma = nn.Parameter(torch.zeros(1))def forward(self, x):m_batchsize, _, height, width = x.size()# 计算查询(Q)、键(K)、值(V)矩阵proj_query = self.query_conv(x)proj_query_H = proj_query.permute(0, 3, 1, 2).contiguous().view(m_batchsize * width, -1, height).permute(0, 2, 1)proj_query_W = proj_query.permute(0, 2, 1, 3).contiguous().view(m_batchsize * height, -1, width).permute(0, 2, 1)proj_key = self.key_conv(x)proj_key_H = proj_key.permute(0, 3, 1, 2).contiguous().view(m_batchsize * width, -1, height)proj_key_W = proj_key.permute(0, 2, 1, 3).contiguous().view(m_batchsize * height, -1, width)proj_value = self.value_conv(x)proj_value_H = proj_value.permute(0, 3, 1, 2).contiguous().view(m_batchsize * width, -1, height)proj_value_W = proj_value.permute(0, 2, 1, 3).contiguous().view(m_batchsize * height, -1, width)# 计算垂直和水平方向上的注意力分数,并应用无穷小掩码屏蔽自注意energy_H = (torch.bmm(proj_query_H, proj_key_H) + self.INF(m_batchsize, height, width)).view(m_batchsize, width, height, height).permute(0, 2, 1, 3)energy_W = torch.bmm(proj_query_W, proj_key_W).view(m_batchsize, height, width, width)# 在垂直和水平方向上应用softmax归一化concate = self.softmax(torch.cat([energy_H, energy_W], 3))# 分离垂直和水平方向上的注意力,应用到值(V)矩阵上att_H = concate[:, :, :, 0:height].permute(0, 2, 1, 3).contiguous().view(m_batchsize * width, height, height)att_W = concate[:, :, :, height:height + width].contiguous().view(m_batchsize * height, width, width)# 计算最终的输出,加上输入x以应用残差连接out_H = torch.bmm(proj_value_H, att_H.permute(0, 2, 1)).view(m_batchsize, width, -1, height).permute(0, 2, 3, 1)out_W = torch.bmm(proj_value_W, att_W.permute(0, 2, 1)).view(m_batchsize, height, -1, width).permute(0, 2, 1, 3)return self.gamma * (out_H + out_W) + xclass Net(nn.Module):def __init__(self, input_size, hidden_size, num_classes):super(Net, self).__init__()self.fc1 = nn.Linear(input_size, hidden_size)self.relu = nn.ReLU()self.fc2 = nn.Linear(hidden_size, num_classes)self.conv1 =nn.Conv2d(1,64,kernel_size=1)self.se = SEAttention(channel=1)self.cca = CrissCrossAttention(64)self.conv2 = nn.Conv2d(64,1,kernel_size=1)def forward(self, x):x = self.se(x)x = self.conv1(x)x = self.cca(x)x = self.conv2(x)out = self.fc1(x.view(-1, input_size))out = self.relu(out)out = self.fc2(out)return outmodel = Net(input_size,hidden_size,num_classes)
criterion = nn.CrossEntropyLoss()optimizer = optim.Adam(model.parameters(),lr=learning_rate)train_loss_list = []
test_loss_list = []#训练
total_step = len(train_loader)
for epoch in range(num_epoch):for i,(images,labels) in enumerate(train_loader):outputs = model(images) #获取模型分类后的结果loss = criterion(outputs,labels) #计算损失optimizer.zero_grad() #反向传播前,梯度清零loss.backward() #反向传播optimizer.step() #更新参数train_loss_list.append(loss.item())if (i+1)%100 ==0:print('Epoch[{}/{}],Step[{}/{}],Train Loss:{:.4f}'.format(epoch+1,num_epoch,i+1,total_step,loss.item()))model.eval()with torch.no_grad(): #禁止梯度计算test_loss = 0.0for images,labels in test_loader:outputs = model(images)loss = criterion(outputs,labels)test_loss +=loss.item()*images.size(0) #累加每个批次总损失得到总损失test_loss /=len(test_loader.dataset) #整个测试集的平均损失# 将计算得到的单个平均测试损失值扩展到一个列表中,长度为total_step# 这样做可能是为了在绘图时每个step都有一个对应的测试损失值,尽管实际测试损失在整个epoch内是恒定的test_loss_list.extend([test_loss]*total_step) #方便可视化model.train()print("Epoch[{}/{}],Test Loss:{:.4f}".format(epoch+1,num_epoch,test_loss))plt.plot(train_loss_list,label='Train Loss')
plt.plot(test_loss_list,label='Test Loss')
plt.title('model loss')
plt.xlabel('iterations')
plt.ylabel('Loss')
plt.legend()
plt.show()

1.6 代码(GPU训练)

要想模型在GPU上训练,需要两点:

(1)模型在GPU上

(2)所有参与运算的张量在GPU上

# Author:SiZhen
# Create: 2024/7/14
# Description: 调参练习-以手写数字集为例import  torch
import torch.nn as nn
import torchvision
import torch.utils
import torchvision.transforms as transforms
import matplotlib.pyplot as plt
#设置超参数
from torch import optim
from torch.nn import initdevice = torch.device("cuda" if torch.cuda.is_available() else "cpu")batch_size = 64
hidden_size = 128
learning_rate = 0.001
num_epoch = 10#将图片进行预处理转换成pytorch张量
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5,),(0.5,),)]) #mnist是单通道,所以括号内只有一个0.5#下载训练集
train_set = torchvision.datasets.MNIST(root="./data",train=True,download=True,transform=transform)#下载测试集
test_set = torchvision.datasets.MNIST(root="./data",train=False,download=True,transform=transform)#加载数据集
train_loader= torch.utils.data.DataLoader(train_set,batch_size=batch_size,shuffle=True,pin_memory=True)test_loader = torch.utils.data.DataLoader(test_set,batch_size=batch_size,shuffle=False,pin_memory=True)#测试不shuffleinput_size = 784 #mnist,28x28像素
num_classes = 10class SEAttention(nn.Module):# 初始化SE模块,channel为通道数,reduction为降维比率def __init__(self, channel=1, reduction=8):super().__init__()self.avg_pool = nn.AdaptiveAvgPool2d(1)  # 自适应平均池化层,将特征图的空间维度压缩为1x1self.fc = nn.Sequential(  # 定义两个全连接层作为激励操作,通过降维和升维调整通道重要性nn.Linear(channel, channel // reduction, bias=False),  # 降维,减少参数数量和计算量nn.ReLU(inplace=True),  # ReLU激活函数,引入非线性nn.Linear(channel // reduction, channel, bias=False),  # 升维,恢复到原始通道数nn.Sigmoid(),  # Sigmoid激活函数,输出每个通道的重要性系数)# 权重初始化方法def init_weights(self):for m in self.modules():  # 遍历模块中的所有子模块if isinstance(m, nn.Conv2d):  # 对于卷积层init.kaiming_normal_(m.weight, mode='fan_out')  # 使用Kaiming初始化方法初始化权重if m.bias is not None:init.constant_(m.bias, 0)  # 如果有偏置项,则初始化为0elif isinstance(m, nn.BatchNorm2d):  # 对于批归一化层init.constant_(m.weight, 1)  # 权重初始化为1init.constant_(m.bias, 0)  # 偏置初始化为0elif isinstance(m, nn.Linear):  # 对于全连接层init.normal_(m.weight, std=0.001)  # 权重使用正态分布初始化if m.bias is not None:init.constant_(m.bias, 0)  # 偏置初始化为0# 前向传播方法def forward(self, x):b, c, _, _ = x.size()  # 获取输入x的批量大小b和通道数cy = self.avg_pool(x).view(b, c)  # 通过自适应平均池化层后,调整形状以匹配全连接层的输入y = self.fc(y).view(b, c, 1, 1)  # 通过全连接层计算通道重要性,调整形状以匹配原始特征图的形状return x * y.expand_as(x)  # 将通道重要性系数应用到原始特征图上,进行特征重新校准
import torch
import torch.nn as nn
from torch.nn import Softmax# 定义一个无限小的矩阵,用于在注意力矩阵中屏蔽特定位置
def INF(B, H, W):return -torch.diag(torch.tensor(float("inf")).repeat(H), 0).unsqueeze(0).repeat(B * W, 1, 1)class CrissCrossAttention(nn.Module):""" Criss-Cross Attention Module"""def __init__(self, in_dim):super(CrissCrossAttention, self).__init__()# Q, K, V转换层self.query_conv = nn.Conv2d(in_channels=in_dim, out_channels=in_dim // 8, kernel_size=1)self.key_conv = nn.Conv2d(in_channels=in_dim, out_channels=in_dim // 8, kernel_size=1)self.value_conv = nn.Conv2d(in_channels=in_dim, out_channels=in_dim, kernel_size=1)# 使用softmax对注意力分数进行归一化self.softmax = Softmax(dim=3)self.INF = INF# 学习一个缩放参数,用于调节注意力的影响self.gamma = nn.Parameter(torch.zeros(1))def forward(self, x):m_batchsize, _, height, width = x.size()# 计算查询(Q)、键(K)、值(V)矩阵proj_query = self.query_conv(x)proj_query_H = proj_query.permute(0, 3, 1, 2).contiguous().view(m_batchsize * width, -1, height).permute(0, 2, 1)proj_query_W = proj_query.permute(0, 2, 1, 3).contiguous().view(m_batchsize * height, -1, width).permute(0, 2, 1)proj_key = self.key_conv(x)proj_key_H = proj_key.permute(0, 3, 1, 2).contiguous().view(m_batchsize * width, -1, height)proj_key_W = proj_key.permute(0, 2, 1, 3).contiguous().view(m_batchsize * height, -1, width)proj_value = self.value_conv(x)proj_value_H = proj_value.permute(0, 3, 1, 2).contiguous().view(m_batchsize * width, -1, height)proj_value_W = proj_value.permute(0, 2, 1, 3).contiguous().view(m_batchsize * height, -1, width)# 计算垂直和水平方向上的注意力分数,并应用无穷小掩码屏蔽自注意energy_H = (torch.bmm(proj_query_H, proj_key_H)+ self.INF(m_batchsize, height, width).to(device)).view(m_batchsize, width, height, height).permute(0, 2, 1, 3).to(device)energy_W = torch.bmm(proj_query_W, proj_key_W).view(m_batchsize, height, width, width)# 在垂直和水平方向上应用softmax归一化concate = self.softmax(torch.cat([energy_H, energy_W], 3))# 分离垂直和水平方向上的注意力,应用到值(V)矩阵上att_H = concate[:, :, :, 0:height].permute(0, 2, 1, 3).contiguous().view(m_batchsize * width, height, height)att_W = concate[:, :, :, height:height + width].contiguous().view(m_batchsize * height, width, width)# 计算最终的输出,加上输入x以应用残差连接out_H = torch.bmm(proj_value_H, att_H.permute(0, 2, 1)).view(m_batchsize, width, -1, height).permute(0, 2, 3, 1)out_W = torch.bmm(proj_value_W, att_W.permute(0, 2, 1)).view(m_batchsize, height, -1, width).permute(0, 2, 1, 3)return self.gamma * (out_H + out_W) + xclass Net(nn.Module):def __init__(self, input_size, hidden_size, num_classes):super(Net, self).__init__()self.fc1 = nn.Linear(input_size, hidden_size)self.relu = nn.ReLU()self.fc2 = nn.Linear(hidden_size, num_classes)self.conv1 =nn.Conv2d(1,64,kernel_size=1)self.se = SEAttention(channel=1)self.cca = CrissCrossAttention(64)self.conv2 = nn.Conv2d(64,1,kernel_size=1)def forward(self, x):x = self.se(x)x = self.conv1(x)x = self.cca(x)x = self.conv2(x)out = self.fc1(x.view(-1, input_size))out = self.relu(out)out = self.fc2(out)return outmodel = Net(input_size,hidden_size,num_classes)model.to(device)criterion = nn.CrossEntropyLoss().to(device)optimizer = optim.Adam(model.parameters(),lr=learning_rate)
train_loss_list = []
test_loss_list = []#训练
total_step = len(train_loader)
for epoch in range(num_epoch):for i,(images,labels) in enumerate(train_loader):images,labels = images.to(device),labels.to(device)outputs = model(images).to(device) #获取模型分类后的结果loss = criterion(outputs,labels).to(device) #计算损失optimizer.zero_grad() #反向传播前,梯度清零loss.backward() #反向传播optimizer.step() #更新参数train_loss_list.append(loss.item())if (i+1)%100 ==0:print('Epoch[{}/{}],Step[{}/{}],Train Loss:{:.4f}'.format(epoch+1,num_epoch,i+1,total_step,loss.item()))model.eval()with torch.no_grad(): #禁止梯度计算test_loss = 0.0for images,labels in test_loader:images, labels = images.to(device), labels.to(device)outputs = model(images).to(device)loss = criterion(outputs,labels).to(device)test_loss +=loss.item()*images.size(0) #累加每个批次总损失得到总损失test_loss /=len(test_loader.dataset) #整个测试集的平均损失# 将计算得到的单个平均测试损失值扩展到一个列表中,长度为total_step# 这样做可能是为了在绘图时每个step都有一个对应的测试损失值,尽管实际测试损失在整个epoch内是恒定的test_loss_list.extend([test_loss]*total_step) #方便可视化model.train()print("Epoch[{}/{}],Test Loss:{:.4f}".format(epoch+1,num_epoch,test_loss))plt.plot(train_loss_list,label='Train Loss')
plt.plot(test_loss_list,label='Test Loss')
plt.title('model loss')
plt.xlabel('iterations')
plt.ylabel('Loss')
plt.legend()
plt.show()

1.7 调参对比

可以看到,该模型原始状态下损失值已经非常小了。

现在我把隐藏层神经元数量从原来的128改为256,学习率进一步减小为0.0005,我们看一下效果:

效果略微提升,但是我们可以看到在后面测试集的表现产生了一些波动,没有之前的模型稳定。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 自定义 Java ClassLoader:深入探索
  • 13 IP层协议-网际控制报文协议ICMP
  • 人工智能算法工程师(中级)课程13-神经网络的优化与设计之梯度问题及优化与代码详解
  • 【正点原子i.MX93开发板试用连载体验】录音小程序采集语料
  • C++客户端Qt开发——常用控件(多元素控件)
  • 数据库管理1
  • 【Linux】centos7安装PHP7.4报错:libzip版本过低
  • 计算机网络入门
  • Ubuntu 磁盘扩容
  • PHP全功能微信投票迷你平台系统小程序源码
  • [web]-图片上传、文件包含-图片上传
  • GNSS技术干货(34):天灵灵 地灵灵 不如C/N0灵
  • Python酷库之旅-第三方库Pandas(026)
  • C++ --> 类和对象(二)
  • Mysql:解决CPU飙升至100%问题的系统诊断与优化策略
  • $translatePartialLoader加载失败及解决方式
  • angular学习第一篇-----环境搭建
  • git 常用命令
  • magento2项目上线注意事项
  • MySQL几个简单SQL的优化
  • Python语法速览与机器学习开发环境搭建
  • spark本地环境的搭建到运行第一个spark程序
  • 阿里云ubuntu14.04 Nginx反向代理Nodejs
  • 好的网址,关于.net 4.0 ,vs 2010
  • 如何使用 OAuth 2.0 将 LinkedIn 集成入 iOS 应用
  • 使用 Xcode 的 Target 区分开发和生产环境
  • 数据科学 第 3 章 11 字符串处理
  • 我的业余项目总结
  • [地铁译]使用SSD缓存应用数据——Moneta项目: 低成本优化的下一代EVCache ...
  • 关于Kubernetes Dashboard漏洞CVE-2018-18264的修复公告
  • # 服务治理中间件详解:Spring Cloud与Dubbo
  • # 再次尝试 连接失败_无线WiFi无法连接到网络怎么办【解决方法】
  • ### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTr
  • #gStore-weekly | gStore最新版本1.0之三角形计数函数的使用
  • #if等命令的学习
  • #我与Java虚拟机的故事#连载06:收获颇多的经典之作
  • $HTTP_POST_VARS['']和$_POST['']的区别
  • (2)空速传感器
  • (2024,RWKV-5/6,RNN,矩阵值注意力状态,数据依赖线性插值,LoRA,多语言分词器)Eagle 和 Finch
  • (4)事件处理——(2)在页面加载的时候执行任务(Performing tasks on page load)...
  • (AtCoder Beginner Contest 340) -- F - S = 1 -- 题解
  • (react踩过的坑)antd 如何同时获取一个select 的value和 label值
  • (带教程)商业版SEO关键词按天计费系统:关键词排名优化、代理服务、手机自适应及搭建教程
  • (二)构建dubbo分布式平台-平台功能导图
  • (仿QQ聊天消息列表加载)wp7 listbox 列表项逐一加载的一种实现方式,以及加入渐显动画...
  • (附源码)php新闻发布平台 毕业设计 141646
  • (附源码)springboot美食分享系统 毕业设计 612231
  • (六) ES6 新特性 —— 迭代器(iterator)
  • (七)MySQL是如何将LRU链表的使用性能优化到极致的?
  • (四)opengl函数加载和错误处理
  • (四)搭建容器云管理平台笔记—安装ETCD(不使用证书)
  • (转)http协议
  • (转)PlayerPrefs在Windows下存到哪里去了?
  • (转)德国人的记事本
  • (轉貼) UML中文FAQ (OO) (UML)