当前位置:   article > 正文

十二、Pytorch复现Residual Block_residualblock

residualblock

一、Residual Network

论文出处:Deep Residual Learning for Image Recognition
其核心模块:在这里插入图片描述

二、复现Residual Block

这里以两层卷积层为例进行设计复现
resnet可以很好的解决梯度消失问题
在这里插入图片描述

Residual Block大致要点:
样本x传入模型,分为两个分支,一个分支进行卷积层、relu层、卷积层、relu层;另一个分支中的x不变
最终两个分支通过相加操作结合到一块,最终再relu激活一次即可

1,数据集

老规矩,还使用MNIST手写数字数据集,详情可参考博文:九、多分类问题

import torch
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F #为了使用relu激活函数
import torch.optim as optim 

batch_size = 64
transform = transforms.Compose([
    transforms.ToTensor(),#把图片变成张量形式
    transforms.Normalize((0.1307,),(0.3081,)) #均值和标准差进行数据标准化,这俩值都是经过整个样本集计算过的
])

train_dataset = datasets.MNIST(root='./',train=True,download=True,transform = transform)
train_loader = DataLoader(train_dataset,shuffle=True,batch_size=batch_size)

test_dataset = datasets.MNIST(root="./",train=False,download=True,transform=transform)
test_loader = DataLoader(test_dataset,shuffle=False,batch_size=batch_size)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

2,测试数据集

这里以训练集中的第1个样本(train_dataset[0])为例进行测试
因为torch中卷积层传入参数格式需要为[B,C,W,H]形式,故通过x.view(-1,1,28,28)进行转换
卷积、relu、卷积、相加、relu
为了保证输入和输出特征大小保持一致,通过加边进行补充

x,y = train_dataset[0]
x.shape
"""
torch.Size([1, 28, 28])
"""
y
"""
5
"""
x = x.view(-1,1,28,28)
x.shape #[B,C,W,H]
"""
torch.Size([1, 1, 28, 28])
"""
channel = x.shape[1] #获取channel


#定义Residual Block,无非就是卷积、relu、卷积、relu然后再相加
conv1 = torch.nn.Conv2d(channel,channel,kernel_size=3,padding=1)
conv2 = torch.nn.Conv2d(channel,channel,kernel_size=3,padding=1)

conv_1 = conv1(x) #第一次卷积
conv_1.shape
"""
torch.Size([1, 1, 28, 28])
"""
relu_1 = F.relu(conv_1) #relu一下
relu_1.shape
"""
torch.Size([1, 1, 28, 28])
"""

H = conv_2 + x
H.shape
"""
torch.Size([1, 1, 28, 28])
"""
final = F.relu(H)
final.shape
"""
torch.Size([1, 1, 28, 28])
"""
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

3,Residual Block完整模块代码

class y_res(torch.nn.Module):
    def __init__(self,channel):
        super(y_res,self).__init__()
        
        self.channels = channel
        self.conv1 = torch.nn.Conv2d(channel,channel,kernel_size=3,padding=1)
        self.conv2 = torch.nn.Conv2d(channel,channel,kernel_size=3,padding=1)
        
    def forward(self,x):
        conv_1 = self.conv1(x)
        relu_1 = F.relu(conv_1)
        conv_2 = self.conv2(relu_1)
        H = conv_2 + x
        final = F.relu(H)
        return final

x,y = train_dataset[0]
x = x.view(-1,1,28,28)
channel = x.shape[1]
yy_res = y_res(channel)
final = yy_res(x)
final.shape
"""
torch.Size([1, 1, 28, 28])
"""
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

三、现学现卖

按照下面的需求进行构建模型
在这里插入图片描述

①准备数据集

数据集使用MNIST手写数字数据集,详细可参考博文:十、CNN卷积神经网络实战

②加载数据集

import torch
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F #为了使用relu激活函数
import torch.optim as optim 

batch_size = 64
transform = transforms.Compose([
    transforms.ToTensor(),#把图片变成张量形式
    transforms.Normalize((0.1307,),(0.3081,)) #均值和标准差进行数据标准化,这俩值都是经过整个样本集计算过的
])

train_dataset = datasets.MNIST(root='./',train=True,download=True,transform = transform)
train_loader = DataLoader(train_dataset,shuffle=True,batch_size=batch_size)

test_dataset = datasets.MNIST(root="./",train=False,download=True,transform=transform)
test_loader = DataLoader(test_dataset,shuffle=False,batch_size=batch_size)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

③模型构建

残差网络模型架构还是使用上述的模型

class yy_net(torch.nn.Module):
    def __init__(self):
        super(yy_net,self).__init__()
        
        self.conv1 = torch.nn.Conv2d(1,16,kernel_size=5)
        self.conv2 = torch.nn.Conv2d(16,32,kernel_size=5)
        self.maxpool = torch.nn.MaxPool2d(2)
        
        self.resblock1 = y_res(16)
        self.resblock2 = y_res(32)
        
        self.linear = torch.nn.Linear(512,10)
        
    def forward(self,x):
        batch_size = x.shape[0] #[B,C,W,H]
        x = self.maxpool(F.relu(self.conv1(x)))
        x = self.resblock1(x)
        x = self.maxpool(F.relu(self.conv2(x)))
        x = self.resblock2(x)
        x = x.view(batch_size,-1)
        x = self.linear(x)
        return x
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
class y_res(torch.nn.Module):
    def __init__(self,channel):
        super(y_res,self).__init__()
        
        self.channels = channel
        self.conv1 = torch.nn.Conv2d(channel,channel,kernel_size=3,padding=1)
        self.conv2 = torch.nn.Conv2d(channel,channel,kernel_size=3,padding=1)
        
    def forward(self,x):
        conv_1 = self.conv1(x)
        relu_1 = F.relu(conv_1)
        conv_2 = self.conv2(relu_1)
        H = conv_2 + x
        final = F.relu(H)
        return final
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

④损失函数和优化器

lossf = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(),lr=0.0001,momentum=0.5)

  • 1
  • 2
  • 3

⑤训练函数构建

def ytrain(epoch):
    loss_total = 0.0
    for batch_index ,data in enumerate(train_loader,0):
        x,y = data
        #x,y = x.to(device), y.to(device)#GPU加速
        optimizer.zero_grad()
        
        y_hat = model(x)
        loss = lossf(y_hat,y)
        loss.backward()
        optimizer.step()
        
        loss_total += loss.item()
        if batch_index % 300 == 299:# 每300epoch输出一次
            print("epoch:%d, batch_index:%5d \t loss:%.3f"%(epoch+1, batch_index+1, loss_total/300))
            loss_total = 0.0 #每次epoch都将损失清除


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

⑥测试函数构建

def ytest():
    correct = 0#模型预测正确的数量
    total = 0#样本总数
    with torch.no_grad():#测试不需要梯度,减小计算量
        for data in test_loader:#读取测试样本数据
            images, labels = data
            #images, labels = images.to(device), labels.to(device) #GPU加速
            pred = model(images)#预测,每一个样本占一行,每行有十个值,后续需要求每一行中最大值所对应的下标
            pred_maxvalue, pred_maxindex = torch.max(pred.data,dim=1)#沿着第一个维度,一行一行来,去找每行中的最大值,返回每行的最大值和所对应下标
            total += labels.size(0)#labels是一个(N,1)的向量,对应每个样本的正确答案
            correct += (pred_maxindex == labels).sum().item()#使用预测得到的最大值的索引和正确答案labels进行比较,一致就是1,不一致就是0
        print("Accuracy on testset :%d %%"%(100*correct / total))#correct预测正确的样本个数 / 样本总数 * 100 = 模型预测正确率


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

⑦主函数调用

if __name__ == '__main__':
    for epoch in range(10):#训练10次
        ytrain(epoch)#训练一次
        if epoch%10 == 9:
            ytest()#训练10次,测试1次
  • 1
  • 2
  • 3
  • 4
  • 5

⑧完整代码

import torch
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.nn.functional as F #为了使用relu激活函数
import torch.optim as optim 

batch_size = 64
transform = transforms.Compose([
    transforms.ToTensor(),#把图片变成张量形式
    transforms.Normalize((0.1307,),(0.3081,)) #均值和标准差进行数据标准化,这俩值都是经过整个样本集计算过的
])

train_dataset = datasets.MNIST(root='./',train=True,download=True,transform = transform)
train_loader = DataLoader(train_dataset,shuffle=True,batch_size=batch_size)

test_dataset = datasets.MNIST(root="./",train=False,download=True,transform=transform)
test_loader = DataLoader(test_dataset,shuffle=False,batch_size=batch_size)

class yy_net(torch.nn.Module):
    def __init__(self):
        super(yy_net,self).__init__()
        
        self.conv1 = torch.nn.Conv2d(1,16,kernel_size=5)
        self.conv2 = torch.nn.Conv2d(16,32,kernel_size=5)
        self.maxpool = torch.nn.MaxPool2d(2)
        
        self.resblock1 = y_res(16)
        self.resblock2 = y_res(32)
        
        self.linear = torch.nn.Linear(512,10)
        
    def forward(self,x):
        batch_size = x.shape[0]
        x = self.maxpool(F.relu(self.conv1(x)))
        x = self.resblock1(x)
        x = self.maxpool(F.relu(self.conv2(x)))
        x = self.resblock2(x)
        x = x.view(batch_size,-1)
        x = self.linear(x)
        return x


class y_res(torch.nn.Module):
    def __init__(self,channel):
        super(y_res,self).__init__()
        
        self.channels = channel
        self.conv1 = torch.nn.Conv2d(channel,channel,kernel_size=3,padding=1)
        self.conv2 = torch.nn.Conv2d(channel,channel,kernel_size=3,padding=1)
        
    def forward(self,x):
        conv_1 = self.conv1(x)
        relu_1 = F.relu(conv_1)
        conv_2 = self.conv2(relu_1)
        H = conv_2 + x
        final = F.relu(H)
        return final
    
model = yy_net()     
lossf = torch.nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(),lr=0.0001,momentum=0.5)   


def ytrain(epoch):
    loss_total = 0.0
    for batch_index ,data in enumerate(train_loader,0):
        x,y = data
        #x,y = x.to(device), y.to(device)#GPU加速
        optimizer.zero_grad()
        
        y_hat = model(x)
        loss = lossf(y_hat,y)
        loss.backward()
        optimizer.step()
        
        loss_total += loss.item()
        if batch_index % 300 == 299:# 每300epoch输出一次
            print("epoch:%d, batch_index:%5d \t loss:%.3f"%(epoch+1, batch_index+1, loss_total/300))
            loss_total = 0.0 #每次epoch都将损失清除
        
        
def ytest():
    correct = 0#模型预测正确的数量
    total = 0#样本总数
    with torch.no_grad():#测试不需要梯度,减小计算量
        for data in test_loader:#读取测试样本数据
            images, labels = data
            #images, labels = images.to(device), labels.to(device) #GPU加速
            pred = model(images)#预测,每一个样本占一行,每行有十个值,后续需要求每一行中最大值所对应的下标
            pred_maxvalue, pred_maxindex = torch.max(pred.data,dim=1)#沿着第一个维度,一行一行来,去找每行中的最大值,返回每行的最大值和所对应下标
            total += labels.size(0)#labels是一个(N,1)的向量,对应每个样本的正确答案
            correct += (pred_maxindex == labels).sum().item()#使用预测得到的最大值的索引和正确答案labels进行比较,一致就是1,不一致就是0
        print("Accuracy on testset :%d %%"%(100*correct / total))#correct预测正确的样本个数 / 样本总数 * 100 = 模型预测正确率

        
if __name__ == '__main__':
    for epoch in range(10):#训练10次
        ytrain(epoch)#训练一次
        if epoch%10 == 9:
            ytest()#训练10次,测试1次
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101

⑨测试

x,y = train_dataset[1]#第1个数据x为图片,对应的结果为0
y
"""
0
"""
x = x.view(-1,1,28,28)#因为tensor需要格式为(B,C,W,H)转换一下格式
y_hat = model(x)#放入模型中进行预测,因为时十分类任务,输出十个值
y_hat 
"""
tensor([[10.9032, -7.9772, -1.3999,  0.1964, -7.2679,  5.5818, -0.2973, -0.2853,
         -0.6460, -1.5026]], grad_fn=<AddmmBackward0>)
"""


pred_maxvalue, pred_maxindex = torch.max(y_hat,dim=1)#选出值最大的,和相对于的下标索引

pred_maxvalue#最大值
"""
tensor([10.9032], grad_fn=<MaxBackward0>)
"""
pred_maxindex#最大值所对应的索引下标值
"""
tensor([0])
"""
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

效果还可以,最起码这个手写数字图片预测对了

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/195905
推荐阅读
相关标签
  

闽ICP备14008679号