赞
踩
本篇文章只是一篇CIFAR-10数据集分类简介,是我的一门课程的大作业,从BP网络进行分类到CNN进行分类。
程序贴在最后!!!
目前主流的神经网络框架有Tensorflow,Pytorch,MXNET,Keras等。本次实验使用Pytroch深度学习框架。PyTorch看作加入了GPU支持的numpy,并且它是一个拥有自动求导功能的强大的深度神经网络。
激活函数的作用是加入非线性因素,从而提高神经网络对模型的表达能力,解决线性模型所不能解决的问题。
上图是sigmoid激活函数。
计算量大,反向传播求误差梯度时,求导涉及除法。
反向传播时,很容易就会出现梯度消失的情况,从而无法完成深层网络的训练。
上图是ReLU激活函数。
ReLU 的收敛速度会比 sigmoid 快很多。
如图,是三层BP网络,使用sigmoid激活函数,将损失函数改为交叉熵损失,而不是使用均方差MSE损失。
上图是确定三层BP网络确定隐藏层神经元个数的经验。
如图,对三层BP网络的隐藏层分别设置为8,2048和10240个神经元。
对于隐藏层设置为8个神经元,神经元个数太少会导致网络表达能力太弱,无法对特征进行正确的表达。
对于隐藏层设置为10240个神经元,神经元个数太多不一定就能够对特征有正确的表达,而且神经元个数过大容易导致模型泛化能力较差。
由上述经验确定的隐藏层设置为2048个神经元,效果最好。
分别选择512,2048,4096个神经元,可以看到512个神经元相对于2048和4096个神经元稍微差一点,而2048和4096个神经元效果相似。
四层BP网络,隐藏层增加一层。隐藏层的神经元个数为2048。
如图所示,粉色和紫色分别表示4层BP网络和3层BP网络,他们使用Sigmoid激活函数。
层数的增加反而训练收敛速度变慢,看测试准确率几乎相似,,说明层数增加并没有对特征有个更好的非线性表示,这有可能是我参数没调好,也有可能是Sigmoid激活函数两端梯度为0,梯度不均匀,训练不稳定。
在上述实验基础上,将Sigmoid函数改为ReLU函数,可以看到,层数增加,模型的收敛速度更快,精度更高,能更好的表示非线性。
def __init__(self): super(CNN, self).__init__() self.conv1 = nn.Sequential( nn.Conv2d(3, 8, 3, 1, 1), nn.ReLU(), nn.MaxPool2d(2) ) self.conv2 = nn.Sequential( nn.Conv2d(8, 16, 3, 1, 1), nn.ReLU(), nn.MaxPool2d(2) ) self.conv3 = nn.Sequential( nn.Conv2d(16, 32, 3, 1, 1), nn.ReLU(), nn.MaxPool2d(2) ) self.conv4 = nn.Sequential( nn.Conv2d(32, 64, 3, 1, 1), nn.ReLU(), nn.MaxPool2d(2) ) self.fc1 = nn.Sequential( nn.Linear(64 * 2 * 2, 120), nn.ReLU() ) self.fc2 = nn.Sequential( nn.Linear(120, 84), nn.ReLU() ) self.fc3 = nn.Linear(84, 10)
import torch from torch.utils import data import torch.nn as nn from tqdm import tqdm import wandb import torchvision.transforms as transforms import torchvision class BP_model(nn.Module): def __init__(self): super(BP_model, self).__init__() self.fc1 = nn.Linear(32 * 32 * 3, 2048) # 线性层 self.fc2 = nn.Linear(2048, 2048) self.fc3 = nn.Linear(2048, 10) def forward(self, x): out = x.view(-1, 32 * 32 * 3) # 展平处理 out = nn.ReLU()(self.fc1(out)) out = nn.ReLU()(self.fc2(out)) out = self.fc3(out) return out class LeNet5(nn.Module): def __init__(self): super(LeNet5, self).__init__() self.conv1 = nn.Sequential( nn.Conv2d(3, 6, 5, 1, 2), # 卷积核 原来通道数 转换后通道数 卷积核大小 步长 填充 nn.ReLU(), # 激活函数 nn.MaxPool2d(2) # 最大池化层 ) self.conv2 = nn.Sequential( nn.Conv2d(6, 16, 5, 1, 0), nn.ReLU(), nn.MaxPool2d(2) ) self.fc1 = nn.Sequential( nn.Linear(16 * 6 * 6, 120), nn.ReLU() ) self.fc2 = nn.Sequential( nn.Linear(120, 84), nn.ReLU() ) self.fc3 = nn.Linear(84, 10) def forward(self, x): x = self.conv1(x) x = self.conv2(x) x = x.view(-1, 16 * 6 * 6) x = self.fc1(x) x = self.fc2(x) x = self.fc3(x) return x class CNN(nn.Module): def __init__(self): super(CNN, self).__init__() self.conv1 = nn.Sequential( nn.Conv2d(3, 8, 3, 1, 1), nn.ReLU(), nn.MaxPool2d(2) ) self.conv2 = nn.Sequential( nn.Conv2d(8, 16, 3, 1, 1), nn.ReLU(), nn.MaxPool2d(2) ) self.conv3 = nn.Sequential( nn.Conv2d(16, 32, 3, 1, 1), nn.ReLU(), nn.MaxPool2d(2) ) self.conv4 = nn.Sequential( nn.Conv2d(32, 64, 3, 1, 1), nn.ReLU(), nn.MaxPool2d(2) ) self.fc1 = nn.Sequential( nn.Linear(64 * 2 * 2, 120), nn.ReLU() ) self.fc2 = nn.Sequential( nn.Linear(120, 84), nn.ReLU() ) self.fc3 = nn.Linear(84, 10) def forward(self, x): x = self.conv1(x) x = self.conv2(x) x = self.conv3(x) x = self.conv4(x) x = x.view(-1, 64 * 2 * 2) x = self.fc1(x) x = self.fc2(x) x = self.fc3(x) return x if __name__ == '__main__': wandb.init(project="BP") wandb.config.dropout = 0.2 wandb.config.hidden_layer_size = 128 # 读取数据,数据预处理 transform = transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010))]) # totensor是将0-255转到0-1,normalize是将0-1转换到-1-1 trainset = torchvision.datasets.CIFAR10(root='./data', train=True, download=False, transform=transform) # 读取数据集,数据预处理 trainloader = torch.utils.data.DataLoader(trainset, batch_size=128, shuffle=True, num_workers=1, pin_memory=True) # 打乱,包装成batchsize testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=False, transform=transform) testloader = torch.utils.data.DataLoader(testset, batch_size=128, shuffle=False, num_workers=1, pin_memory=True) device = torch.device("cuda:0") # 选择cpu或者GPU # model = BP_model() # model = LeNet5() # 用哪个模型,打开哪个,屏蔽另外两个 model = CNN() model.to(device) # 选择cpu或者gpu criterion = nn.CrossEntropyLoss() # 交叉熵损失 optimizer = torch.optim.SGD([{'params': model.parameters()}], lr=0.005, weight_decay=5e-4, momentum=0.9) # 随机梯度优化策略 scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=200) # CNN训练使用该学习率优化策略,bp网络也可以使用试试 for epoch in range(80): # 训练 model.train() for i, (img, label) in tqdm(enumerate(trainloader)): img, label = img.to(device, non_blocking=True), label.to(device, non_blocking=True).long() # 加载数据 output = model(img) # 计算结果 loss = criterion(output, label) # 计算损失 optimizer.zero_grad() loss.backward() # 反向传播 optimizer.step() # 优化器更新 iters = epoch * len(trainloader) + i if iters % 10 == 0: wandb.log({'loss': loss}) # 可视化 # 测试 accuracy = 0 model.eval() for i, (img, label) in enumerate(testloader): img, label = img.to(device), label.to(device).long() output = model(img) output = output.max(dim=1)[1] # 预测是哪一类 accuracy += (output==label).sum().item() # 准确率计算 accuracy = accuracy / 10000 # 准确率计算 print(accuracy) wandb.log({'accuracy': accuracy}) # 可视化 scheduler.step() # 学习率更新
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。