小土堆Pytorch快速入门-ch02

1.卷积层设计

卷积层的具体设计参数如下。
其中对于2维得数据,也是最常用的是使用卷积函数torch.nn.conv2d()。代码中TuDui网络仅仅构建了一层卷积层

'''
注意本文件与P16的区别
P16中使用的是torch.nn.functional.conv2d(),这为了更加理解函数内部结构
而本节中讲解的是更常使用、也更加方便的torch.nn.conv2d()
torch.nn.Conv2d(in_channels, 输入层通道数
                out_channels, 输出层通道数
                 kernel_size, 卷积核形状大小
                 stride=1,   步长
                 padding=0)  填充大小
'''
import torch
import torchvision
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
dataset = torchvision.datasets.CIFAR10(root="./dataset/CIFAR10",train=False,transform=torchvision.transforms.ToTensor(),download=True)
dataloader = DataLoader(dataset,batch_size=64,shuffle=True)
class TuDui(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        #定义一个卷积层
        self.conv1 = nn.Conv2d(in_channels=3,#彩色图像,输入需要3个通道
                               out_channels=6,#自定义的
                               kernel_size=3,#卷积核定义为3*3
                               stride=1,
                               padding=0)
    def forward(self,x):
        x = self.conv1(x)
        return x

tudui = TuDui()
#print(tudui)

writer = SummaryWriter("logs")

step = 0
for data in dataloader:
    imgs,targets = data
    output = tudui(imgs)
    print(imgs.shape)   #torch.Size([64, 3, 32, 32])
    print(output.shape) #torch.Size([64, 6, 30, 30])
    writer.add_images("input",imgs,step)
    output = torch.reshape(output,(-1,3,30,30))  #重新改变形状时,-1的值可以自动根据重新改变后的大小进行自动赋值
    writer.add_images("output",output,step)
    step = step+1
writer.close()

2.最大池化层设计

为什么要进行最大池化?最大池化的作用是什么?
目的就是为了保留数据的输入特征,并将数据量减少
本例中:
池化前:torch.Size([1, 1, 5, 5])
池化后:torch.Size([1, 1, 2, 2])

池化时也需要一个池化核,与卷积核得使用嘞是,只不过这里是将与池化核相对应得最大值保留,即保留最具有特征值。
其中池化时也会遇到一个问题是边缘问题,ceil_model=True要保留把边缘,为False则不保留边缘。
在这里插入图片描述

import torch
from torch import nn
input = torch.tensor([[1,2,0,3,1],
                     [0,1,2,3,1],
                     [1,2,1,0,0],
                     [5,2,3,1,1],
                     [2,1,0,1,1]],dtype=torch.float32)
                    #这里最后为数据为浮点数类型,目的在进行池化时,是需要输入浮点型

input = torch.reshape(input,(-1,1,5,5))
print(input.shape)

class Tudui(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        self.maxpool1 = nn.MaxPool2d(kernel_size=3,
                                     ceil_mode=True)

    def forward(self,input):
        output = self.maxpool1(input)
        return output
print(input.shape)
tudui = Tudui()
output = tudui(input)
print(output)
print(output.shape)

3.非线性激活层设计

给神经网络当中引入一些非线性的特质,增强拟合能力(滤波器)。
其中有几个常用的激活函数:ReLU,Sigmoid等,区别就是几个处理公式不同而已

'''
ReLU
Non-linear Activations

给神经网络当中引入一些非线性的特质,增强拟合能力(滤波器)
有很多非线性激活函数,ReLU,Sigmoid等,区别就是几个处理公式不同而已
'''
import torch
import torchvision.datasets
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

input = torch.tensor([[1,-0.5],
                      [-1,3]])
input = torch.reshape(input,(-1,1,2,2))
print(input.shape)
dataset = torchvision.datasets.CIFAR10(root="./dataset//CIFAR10",
                                       train=False,
                                       transform=torchvision.transforms.ToTensor())
dataloader = DataLoader(dataset,batch_size=64,shuffle=True)

class Tudui(nn.Module):
    def __init__(self):
        super().__init__()
        #创建ReLU
        self.relu1 = nn.ReLU()  #ReLU激活函数
        self.sigmoid1 = nn.Sigmoid()    #sigmoid激活函数
    def forward(self,input):
        output = self.sigmoid1(input)
        return output

tudui = Tudui()
output = tudui(input)
print(output)

writer = SummaryWriter("logs")
step=0
for data in dataloader:
    imgs, targets = data
    writer.add_images("input",imgs,global_step=step)
    output = tudui(imgs)
    writer.add_images("output",output,global_step=step)
    step += 1
writer.close()

3.线性层设计

本层就是一个线性的拟合,其中输入的为输入维度和输出维度,最终训练的是直线(线性)的斜率k和截距b。即训练的是参数k和b。
在这里插入图片描述

import torch
import torchvision
from torch import nn
from torch.utils.data import DataLoader
dataset = torchvision.datasets.CIFAR10("./dataset/CIFAR10",train=False,
                                       transform=torchvision.transforms.ToTensor())
dataloader = DataLoader(dataset,batch_size=64,drop_last=True)#舍去最后不完整的一组数据
class Tudui(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        self.liner1 = nn.Linear(196608,10)

    def forward(self,input):
        output = self.liner1(input)
        return output
#writer = SummaryWriter("logs")
tudui = Tudui()
for data in dataloader:
    imgs, targets = data
    print(imgs.shape)
    input = torch.flatten(imgs) #摊平,即变成一维
    print(input.shape)
    output = tudui(input)
    print(output.shape)

4.完整的神经网络模型实战

依据下图的一个网络模型进行构造一个神经网络框架。
在这里插入图片描述

未使用Sequential

import torch
import torchvision
from torch import nn
from torch.utils.tensorboard import SummaryWriter
class Tudui(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        self.conv1 = nn.Conv2d(3,32,5,padding=2)
        self.maxpool1 = nn.MaxPool2d(2)
        self.conv2 =  nn.Conv2d(32,32,5,padding=2)
        self.maxpool2 = nn.MaxPool2d(2)
        self.conv3 = nn.Conv2d(32,64,5,padding=2)
        self.maxpool3 = nn.MaxPool2d(2)
        self.flatten = nn.Flatten()
        self.linear1 = nn.Linear(1024,64)
        self.linear2 = nn.Linear(64,10)
       
    def forward(self,input):
        input = self.conv1(input)
        input = self.maxpool1(input)
        input = self.conv2(input)
        input = self.maxpool2(input)
        input = self.conv3(input)
        input = self.maxpool3(input)
        input = self.flatten(input)
        input = self.linear1(input)
        input = self.linear2(input)
        return input

tudui = Tudui()
print(tudui)

#以下利用torch.ones数据来验证神经网络模型的正确性,输入输出维度等
input = torch.ones((64,3,32,32))
output = tudui(input)
print(output.shape)

#利用tensorboard来显示网络结构
writer = SummaryWriter("logs")
writer.add_graph(tudui,input)
writer.close()

使用了Sequential

import torch
import torchvision
from torch import nn
from torch.utils.tensorboard import SummaryWriter
class Tudui(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        #Sequential的作用
        self.model1 = nn.Sequential(
            nn.Conv2d(3, 32, 5, padding=2),
            nn.MaxPool2d(2),
            nn.Conv2d(32, 32, 5, padding=2),
            nn.MaxPool2d(2),
            nn.Conv2d(32, 64, 5, padding=2),
            nn.MaxPool2d(2),
            nn.Flatten(),
            nn.Linear(1024, 64),
            nn.Linear(64, 10)
        )

    def forward(self,input):
        input = self.model1(input)
        return input

tudui = Tudui()
print(tudui)

#以下利用torch.ones数据来验证神经网络模型的正确性,输入输出维度等
input = torch.ones((64,3,32,32))
output = tudui(input)
print(output.shape)

#利用tensorboard来显示网络结构
writer = SummaryWriter("logs")
writer.add_graph(tudui,input)
writer.close()

5.损失函数和反向传播

损失函数作用:计算实际输出和目标输出之间的差距,为我们更新输出一定的依据。
这里使用了一些常见的损失函数,损失和nn.L1Loss(reduction=“sum”)、损失平均nn.L1Loss(reduction=“mean”)、差的平方求和再去平均nn.MSELoss()、交叉熵nn.CrossEntropyLoss()

import torch
from torch import nn
inputs = torch.tensor([1,2,3],dtype=torch.float32)
targets = torch.tensor([1,2,5],dtype=torch.float32)

inputs = torch.reshape(inputs,(1,1,1,3))
targets = torch.reshape(targets,(1,1,1,3))
loss1 = nn.L1Loss(reduction="sum")#损失和
loss2 = nn.L1Loss(reduction="mean")#损失平均

loss_mse = nn.MSELoss()#差的平方求和再去平均

result1 = loss1(inputs,targets)
result2 = loss2(inputs,targets)
result3 = loss_mse(inputs,targets)

print(result1,result2,result3)

x = torch.tensor([0.1,0.2,0.3])
y = torch.tensor([1])#只有1个batch_size,所以元素为一个,又因为dog位于label下表1,所以数值是1
x = torch.reshape(x,(1,3))#修改成CrossEntropyLoss满足的输入类型,1代表batch_size
loss_cross = nn.CrossEntropyLoss()
result_cross = loss_cross(x,y)
print(result_cross)

1.当利用交叉熵损失函数进行对神经网络的损失值进行计算。
2.另外对于计算反向传播使用函数loss_cross.backward(),求出每个需要调节参数的梯度(获取每层的梯度)。如果不适用该函数,则梯度无法计算。
3.对于神经网络中的参数修改需要使用优化器,以达到损失减少的目的,本例使用的为梯度下降法。

大致流程为首先1进行正向计算出损失值,2利用这些损失值进行反向传播计算出梯度,3利用梯度更新参数

import torch
import torchvision
from torch import nn
from torch.utils.data import DataLoader
dataset = torchvision.datasets.CIFAR10(root="./dataset/CIFAR10",train=False,
                                       transform=torchvision.transforms.ToTensor())
dataloader = DataLoader(dataset,batch_size=64)

class Tudui(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        #Sequential的作用
        self.model1 = nn.Sequential(
            nn.Conv2d(3, 32, 5, padding=2),
            nn.MaxPool2d(2),
            nn.Conv2d(32, 32, 5, padding=2),
            nn.MaxPool2d(2),
            nn.Conv2d(32, 64, 5, padding=2),
            nn.MaxPool2d(2),
            nn.Flatten(),
            nn.Linear(1024, 64),
            nn.Linear(64, 10)
        )

    def forward(self,input):
        input = self.model1(input)
        return input

tudui = Tudui()
loss = nn.CrossEntropyLoss()
optim = torch.optim.SGD(tudui.parameters(),lr=0.01)#优化器

for epoch in range(10):
    running_loss = 0.0
    '''
    由于通过计算对整个数据一轮次的学习,并没有看到weight变化多少,
    需要多轮次,重复之前数据时,与之前该数据时对比loss的减小程度才明显。
    因为对于同一轮次来说,数据不同,对比不同数据的loss变化并没有什么意义
    要想不同轮次的对比明显,则使用running_loss来记录每轮的loss总数,对比每轮的running_loss即可
    '''
    for data in dataloader:
        imgs, targets = data
        outputs = tudui(imgs)#outputs为神经网络输出
        loss_cross = loss(outputs,targets)#计算神经网络输出和真实target输出的误差
        optim.zero_grad()#首先将梯度调零
        loss_cross.backward()#反向传播,求出每个需要调节参数的梯度(获取每层的梯度)
        optim.step()#依据backward计算出来的梯度,来进行更新网络中的权重weight
        running_loss += loss_cross
    print(running_loss)
'''
由于电脑性能,所有仅计算了轮次,我就结束了
tensor(360.4226, grad_fn=<AddBackward0>)
tensor(356.6039, grad_fn=<AddBackward0>)
tensor(344.1981, grad_fn=<AddBackward0>)
tensor(321.3732, grad_fn=<AddBackward0>)
tensor(311.2141, grad_fn=<AddBackward0>)
'''

6.现有模型的使用和修改

主要在PyTroch的官网,可以找到与torchaudio语音相关、torchtext文字相关、torchvision图像相关的训练好的模型,本例中使用的是vgg16模型

import scipy
import torchvision.datasets

'''
vgg中参数pretrain参数
1.当为True时代表该模型不仅有网络模型框架,还有已经对框架中的参数进行了预训练,即参数已经训练好了
2.当为False时代表该模型仅仅加载网络模型框架,并未进行预训练参数,参数是默认的
'''
# vgg16_false = torchvision.models.vgg16(pretrained=False)
# vgg16_true = torchvision.models.vgg16(pretrained=True)

7.模型的保存和加载

import torch
import torchvision
from torch import nn

vgg16 = torchvision.models.vgg16(pretrained=False)
#保存方式1
torch.save(vgg16,"vgg16_method1.pdh")

#对应保存方式2的加载方式
vgg16_load1 = torch.load("vgg16_method1.pdh")
print(vgg16_load1)


#保存方式2 (官方推荐的保存方式)
#将vgg16保存为字典形式,并不保存网络的结构,而只是保存网络的参数
torch.save(vgg16.state_dict(),"vgg16_method2.pdh")
#对应保存方式2的加载方式
'''
vgg16_load2 = torch.load("vgg16_method2.pdh")
print(vgg16_load2)#保存的是一个字典的形式
'''
vgg16_load2 = torchvision.models.vgg16(pretrained=False)#先加载框架
vgg16_load2.load_state_dict(torch.load("vgg16_method2.pdh"))#再导入参数
#通过以上两个步骤才算加载成功
print(vgg16_load2)

8.模型的完整训练套路

首先构建一个网络模型,放在model.py文件中

import torch
from torch import nn
#搭建神经网络
class Tudui(nn.Module):
    def __init__(self):
        super().__init__()
        self.model1 = nn.Sequential(
            nn.Conv2d(3, 32, 5, stride=1, padding=2),
            nn.MaxPool2d(2),
            nn.Conv2d(32,32,5,stride=1,padding=2),
            nn.MaxPool2d(2),
            nn.Conv2d(32,64,5,stride=1,padding=2),
            nn.MaxPool2d(2),
            nn.Flatten(),
            nn.Linear(1024, 64),
            nn.Linear(64, 10)
        )


    def forward(self,x):
        x = self.model1(x)
        return x

if __name__ =='__main__':
    tudui = Tudui()
    input = torch.ones(64,3,32,32)
    output = tudui(input)
    print(output.shape)

再完成训练套路train.py

import torch
from torch import nn
#搭建神经网络
class Tudui(nn.Module):
    def __init__(self):
        super().__init__()
        self.model1 = nn.Sequential(
            nn.Conv2d(3, 32, 5, stride=1, padding=2),
            nn.MaxPool2d(2),
            nn.Conv2d(32,32,5,stride=1,padding=2),
            nn.MaxPool2d(2),
            nn.Conv2d(32,64,5,stride=1,padding=2),
            nn.MaxPool2d(2),
            nn.Flatten(),
            nn.Linear(1024, 64),
            nn.Linear(64, 10)
        )


    def forward(self,x):
        x = self.model1(x)
        return x

if __name__ =='__main__':
    tudui = Tudui()
    input = torch.ones(64,3,32,32)
    output = tudui(input)
    print(output.shape)

以上训练好之后并保存了模型,则接下来就是使用训练好的模型了

import torch
import torchvision
from PIL import Image
from torch import nn

img_path = "./dataset/dog.png"
image = Image.open(img_path)
print(image)
image = image.convert('RGB')
transform = torchvision.transforms.Compose([torchvision.transforms.Resize((32,32)),
                                            torchvision.transforms.ToTensor()])
image = transform(image)
print(image)

class Tudui(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        #Sequential的作用
        self.model1 = nn.Sequential(
            nn.Conv2d(3, 32, 5, padding=2),
            nn.MaxPool2d(2),
            nn.Conv2d(32, 32, 5, padding=2),
            nn.MaxPool2d(2),
            nn.Conv2d(32, 64, 5, padding=2),
            nn.MaxPool2d(2),
            nn.Flatten(),
            nn.Linear(1024, 64),
            nn.Linear(64, 10)
        )

    def forward(self,input):
        input = self.model1(input)
        return input

model = torch.load("./models/tudui_2.pth")
print(model)
image = torch.reshape(image,(1,3,32,32))
model.eval()
with torch.no_grad():
    output = model(image)
print(output)
print(output.argmax(1))

完成训练之后,利用训练好的模型进行预测train.py

import torch
import torchvision.transforms
from PIL import Image

img_path = "./dataset/dog.png"
image = Image.open(img_path)
print(image)
image = image.convert('RGB')
transform = torchvision.transforms.Compose([torchvision.transforms.Resize((32,32)),
                                            torchvision.transforms.ToTensor()])

image = transform(image)
print(image)

model = torch.load("./models/tudui_6.pth")
print(model)

image = torch.reshape(image,(1,3,32,32))
model.eval()
with torch.no_grad():
    output = model(image)
print(output)
print(output.argmax(1))
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值