第四周作业:卷积神经网络(Part 2)

经典卷积神经网络

AlexNet

从LeNet到AlexNet:
更大的核窗口和步长(图片更大了);更大的池化窗口,使用最大池化层;更多的输出通道;新加了3层卷积层;从FC(120)增加到FC(4096);采用1000类输出。
从LeNet到AlexNet
更多细节:
激活函数从sigmoid变到了ReLU(减缓梯度消失);
隐藏全连接层后加入了丢弃层;
数据增强。
总结
AlexNet是更大更深的LeNet,10×参数个数,260×计算复杂度;
新加入了丢弃法,ReLU,最大池化层和数据增强。

VGG

VGG块: 3×3卷积(填充1)(n层,m通道);2×2最大池化层(步幅2)。
**VGG架构:**多个VGG块后接全连接层;不同次数的重复块得到不同的架构VGG-16、VGG-19等等。
从AlexNet到VGG,它们本质上都是块设计。
总结
VGG使用可重复使用的卷积块来构建深度卷积神经网络;
不同的卷积块个数和超参数可以得到不同复杂度的变种。

NIN

NiN块以一个普通卷积层开始,后面是两个1×1的卷积层。这两个1×1卷积层充当带有ReLU激活函数的逐像素全连接层。第一层的卷积窗口形状通常由用户设置。随后的卷积窗口形状固定为1×1。
对比 VGG 和 NiN 及它们的块之间主要结构差异
总结
NiN块使用卷积层加两个1×1卷积层(后者对每个像素增加了非线性);
NiN使用全局平均池化层来替代VGG和AlexNet中的全连接层(不容易过拟合,更少的参数个数)。

GoogleNet

Inception块
在这里插入图片描述
跟单3×3或5×5卷积层比,Inception块有更少的参数个数和计算复杂度。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
总结
Inception块用4条不同超参数的卷积层和池化层的路来抽取不同的信息(主要优点:模型参数小,计算复杂度低);
GoogleNet使用9个Inception块,是第一个达到上百层的网络。

批量归一化

在这里插入图片描述
μB 是样本均值, σB 是小批量B的样本标准差。 应用标准化后,生成的小批量的平均值为0和单位方差为1。由于单位方差是一个任意的选择,因此我们通常包含拉伸参数(scale)γ 和 偏移参数(shift)β ,它们的形状与x 相同。 请注意,γ和β是需要与其他模型参数一起学习的参数。
批量归一化层
可学习的参数为γ和β;
作用在①全连接层和卷积层输出上,激活函数前②全连接层和卷积层输入上;
对全连接层,作用在特征维;
对于卷积层,作用在通道维。
总结
批量归一化固定小批量中的均值和方差,然后学习出适合的偏移和缩放;
可以加速收敛速度,但一般不改变模型精度。

残差网络ResNet

一个正常块(左图)和一个残差块(右图)
正常块:在 use_1x1conv=False 、应用 ReLU 非线性函数之前,将输入添加到输出。
残差块:在 use_1x1conv=True 时,添加通过 1×1 卷积调整通道和分辨率。
ResNet模型
ResNet 的前两层跟之前介绍的GoogLeNet中的一样:在输出通道数为 64、步幅为2的7×7卷积层后,接步幅为2的3×3的最大汇聚层。不同之处在于ResNet每个卷积层后增加了批量归一化层。
在这里插入图片描述
总结
残差块使得很深的网络更加容易训练;
残差网络对随后的深度神经网络(卷积类网络、全连接类网络)设计产生了深远影响。
ResNet解决梯度消失问题
梯度消失:
在这里插入图片描述
ResNet解决:
在这里插入图片描述

猫狗大战(ResNet迁移学习)

1.导包与数据集

import numpy as np
import matplotlib.pyplot as plt
import torch
import torch.nn as nn
import torchvision
from torchvision import models,transforms,datasets
import torch.nn.functional as F
from PIL import Image
import torch.optim as optim
import json, random
import os
import random

# 判断是否存在GPU设备
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
print('Using gpu: %s ' % torch.cuda.is_available())

!wget https://static.leiphone.com/cat_dog.rar
!unrar x cat_dog.rar
train_path = '/content/cat_dog/train/'

2.创建数据集(采用齐昊代码)

def get_data(file_path):
    file_lst = os.listdir(file_path) #获得所有文件名称 xxxx.jpg
    data_lst = []
    for i in range(len(file_lst)):
        clas = file_lst[i][:3] #cat和dog在文件名的开头
        img_path = os.path.join(file_path,file_lst[i])#将文件名与路径合并得到完整路径,以备读取
        if clas == 'cat':
            data_lst.append((img_path, 0))
        else:
            data_lst.append((img_path, 1))
    return data_lst
class catdog_set(torch.utils.data.Dataset):
    def __init__(self, path, transform):
        super(catdog_set).__init__()
        self.data_lst = get_data(path)#调用刚才的函数获得数据列表
        self.trans = torchvision.transforms.Compose(transform)
    def __len__(self):
        return len(self.data_lst)
    def __getitem__(self,index):
        (img,cls) = self.data_lst[index]
        image = self.trans(Image.open(img))
        label = torch.tensor(cls,dtype=torch.float32)
        return image,label
train_loader = torch.utils.data.DataLoader(
    catdog_set(train_path, [transforms.Resize((224,224)),transforms.ToTensor()]), 
    batch_size=128, shuffle=True)

3.定义网络

model_ResNet = torchvision.models.resnet18(pretrained=True)
model_ResNet.fc = nn.Linear(512, 2,bias=True)
#将网络放在GPU上
model_ResNet = model_ResNet.to(device)
#定义优化器
optimizer = torch.optim.SGD(model_ResNet.parameters(), lr=0.001, momentum=0.9, weight_decay=5e-4)  # 设置训练细节
#定义损失函数
criterion = nn.CrossEntropyLoss()

4.网络训练

def accurate(y_hat,y):
  pred = torch.argmax(y_hat,axis=-1).view(-1,1)
  y = y.view(-1,1)
  pred.type(y.dtype)
  return torch.sum(pred==y)

for epoch in range(30):  # 重复多轮训练
  hits = 0
  total = 0
  for i, (inputs, labels) in enumerate(train_loader):
      inputs = inputs.to(device)
      labels = labels.to(device)
      # 优化器梯度归零
      optimizer.zero_grad()
      # 正向传播 + 反向传播 + 优化 
      outputs = model_ResNet(inputs)
      loss = criterion(outputs, labels.long())
      loss.backward()
      optimizer.step() 
  print('Epoch: %d loss: %.6f' %(epoch + 1, loss.item()))
  with torch.no_grad():  
    for X,y in train_loader:
      X = X.to(device)
      y = y.to(device)
      out = model_ResNet(X)
      hit = accurate(out,y)
      hits += hit
      total += len(y)
    #print(out)
    print(hits/total)
print('Finished Training')

在这里插入图片描述
5.测试并输出结果

test_datapath='/content/test/'
resfile = open('/content/res.csv', 'w')
for i in range(0,2000): 
    img_PIL = Image.open(test_datapath+str(i)+'.jpg')
    img_tensor = transforms.Compose([transforms.Resize((224,224)),transforms.ToTensor()])(img_PIL)
    img_tensor = img_tensor.reshape(-1, img_tensor.shape[0], img_tensor.shape[1], img_tensor.shape[2])
    img_tensor = img_tensor.to(device)
    out = model_ResNet(img_tensor).cpu().detach().numpy()
    if out[0, 0] < out[0, 1]:
        resfile.write(str(i)+','+str(1)+'\n')
    else:
        resfile.write(str(i)+','+str(0)+'\n')
resfile.close()

结果:
在这里插入图片描述

问题与感想

问题
1.第一次使用2000张小数据集时,上传结果只有50,改用原始数据集后得分与准确率相符,准确率较高有运气成分,具体网络细节仍需进一步研究。
2.训练网络部分代码遇到过困难,怀疑与transfrom.Compose()有关,需要继续搞清楚。
感想
跟第一次摸不到头绪相比,这次对于整体思路更加清晰,网络设计部分搜集了不少资料,对课程内容有了更加具体的理解,代码仍需加强,框架明晰后细节也不容忽视。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值