pytorch基础入门

pytorch官方手册:https://pytorch.org/docs/stable/index.html

1.基础的网络模型框架

import torch.nn as nn
import torch.nn.functional as F

class Model(nn.Module):
    def __init__(self):
        super(Model, self).__init__()
        # 搭建自己的网络结构,其中不包括输入层与输出层
        self.covn1 = nn.Conv2d(1,10,5)
        self.covn2 = nn.Conv2d(20,20,5)

    def forward(self,input):   #前向传播
        x = F.relu(self.covn1(input))  # 将输入的数据先进行卷积操作,然后进行一个非线性变化
        return F.relu(self.covn2(x))

2.CIFAR10与DataLoader的使用

import torchvision
from torch import nn
from torch.nn import Conv2d
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

#获得数据 train=False:创建的是一个训练集   download=True:自己会下载数据集到本地文件
# torchvision.transforms.ToTensor():将数据类型转化为tensor类型
dataset = torchvision.datasets.CIFAR10("./data", train=False,transform=torchvision.transforms.ToTensor(), download=True)
#加载器   shuffle:是否打乱顺序     drop_last:是否删除掉除最后不尽的样本
dataloader = DataLoader(dataset, batch_size=64, shuffle=False,drop_last=False)

class Tudui(nn.Module):
    def __init__(self):
        super(Tudui, self).__init__()
        # 输入通道3,因为图片为彩色的,输出通道为6,卷积核是6个,卷积核的大小为3*3的,步长为1   ,不进行卷积填充
        self.conv1 = Conv2d(in_channels=3, out_channels=6, kernel_size=3, stride=1, padding=0)

    def forward(self,input):
        #将输入数据进行卷积操作
        x = self.conv1(input)
        return x

#初始化网络
tudui = Tudui()
#输出网络结构
# print(tudui)
for data in dataloader:
    imgs, targets = data
    output = tudui(imgs)
    print(imgs.shape)
    print(output.shape)

#./ 表示当前目录下的
#../ 表示当前文件的上一级目录所在的目录

3.TensorBoard

import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

"""
writer = SummaryWriter("./logs")
for i in range(100):
    #tag 图像的标题   scalar_value  表示y轴的数据    global_step 表示x轴的数据
    writer.add_scalar("y=2x",2*i,i)
"""

#获得数据 train=False 创建的是一个训练集   download=True  自己会下载数据集到本地文件
dataset = torchvision.datasets.CIFAR10("./data",train=False,transform=torchvision.transforms.ToTensor(),download=True)
#加载器   shuffle 是否打乱顺序     drop_last  是否删除掉除最后不尽的样本
dataloader = DataLoader(dataset,batch_size=64,shuffle=False,drop_last=False)
writer = SummaryWriter("./logs")  # 实例化一个类,文件存放在logs文件夹下
step = 0
for data in dataloader:
    imgs, targets = data
    print(imgs.shape)
    # torch.Size([64,3,32,32])     imgs 为tensor类型
    writer.add_images("input", imgs, step)  # 将图片存入writer类中
    step = step + 1
writer.close()   # 最后关闭writer类

"""
tensorboard --logdir=logs    启动文件查看
每次运行之前如果图像有问题可删除logs文件夹下的文件再启动
指定查看的端口号 tensorboard --logdir=logs --port=6007
"""

4. Sequential的作用

定义一个有序的容器,神经网络将根据定义的层顺序执行,并且也有效简化代码

import torch
from torch import nn
from torch.nn import Sequential

"""
class Tudui(nn.Module):
    def __init__(self):
        super(Tudui, self).__init__()
        self.conv1 = nn.Conv2d(in_channels=3, out_channels=32, kernel_size=5,padding=2)
        self.maxpool1 = nn.MaxPool2d(kernel_size=2)
        self.conv2 = nn.Conv2d(in_channels=32, out_channels=32, kernel_size=5, padding=2)
        self.maxpool2 = nn.MaxPool2d(kernel_size=2)
        self.conv3 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=5, padding=2)
        self.maxpool3 = nn.MaxPool2d(kernel_size=2)
        self.flatter = nn.Flatten()
        self.linear1 = nn.Linear(in_features=1024, out_features=64)
        self.linear2 = nn.Linear(in_features=64, out_features=10)
    def forward(self,input):
        x = self.conv1(input)
        x = self.maxpool1(x)
        x = self.conv2(x)
        x = self.maxpool2(x)
        x = self.conv3(x)
        x = self.maxpool3(x)
        x = self.flatter(x)
        x = self.linear1(x)
        x = self.linear2(x)
        return x
"""
class Tudui(nn.Module):
    def __init__(self):
        super(Tudui, self).__init__()
        self.model = Sequential(
            nn.Conv2d(in_channels=3, out_channels=32, kernel_size=5, padding=2),
            nn.MaxPool2d(kernel_size=2),
            nn.Conv2d(in_channels=32, out_channels=32, kernel_size=5, padding=2),
            nn.MaxPool2d(kernel_size=2),
            nn.Conv2d(in_channels=32, out_channels=64, kernel_size=5, padding=2),
            nn.MaxPool2d(kernel_size=2),
            nn.Flatten(),
            nn.Linear(in_features=1024, out_features=64),
            nn.Linear(in_features=64, out_features=10),
        )
    def forward(self,input):
        x = self.model(input)
        return x

tudui = Tudui()
input = torch.ones((64,3,32,32))
output = tudui(input)
print(output)

5.损失函数loss

# 交叉熵损失函数
loss = nn.CrossEntropyLoss()
tudui = Tudui()
for data in dataloader:
    imgs,target = data
    output = tudui(imgs)  #output.shape = [64,10]    target.shape = [64]
    result_loss = loss(output,target)
    result_loss.backward()  #反向传播  (只是进行反向传播  并没有进行梯度的优化)

6.优化器 optimizer进行参数优化

#交叉熵损失函数
loss = nn.CrossEntropyLoss()
tudui = Tudui()
# 采用随机梯度下降算法
optim = torch.optim.SGD(tudui.parameters(), lr=0.01)  # 第一个参数为优化的对象   第二个为学习率
for _ in range(20):
    loss_sum = 0.0
    for data in dataloader:
        imgs, target = data
        output = tudui(imgs)
        result_loss = loss(output, target)
        loss_sum = loss_sum + result_loss
        
        optim.zero_grad()   # 将优化器中的梯度全部重置为0
        result_loss.backward()  # 反向传播
        optim.step()       # 进行梯度更新
        
    print(loss_sum)

7.模型的保存与加载

import torch
import torchvision
# pretrained=False 表示不使用vgg16训练imgesNet数据集训练好的参数,只是一个vgg16的网络架构
vgg16 = torchvision.models.vgg16(pretrained=False)

# 保存方式1
torch.save(vgg16, "./model/vgg16_1.pth")  # 不仅保存了网络模型的结构 也保存了内部的参数

# 加载方式1  加载模型
model1 = torch.load("./model/vgg16_1.pth")
print(model1)



# 保存方式2  (官方推荐的方式)
torch.save(vgg16.state_dict(),"./model/vgg16_2.pth")  #只保存vgg16里面的参数 保存在一个字典的形式

# 加载方式2  加载模型(此方式需要先获得一个网路架构,然后再将参数加载进去)
vgg16 = torchvision.models.vgg16(pretrained=False)
vgg16.load_state_dict(torch.load("./model/vgg16_2.pth"))   # 将参数加载入模型中
print(vgg16)

8.修改定义好的模型架构

拿vgg16网络模型架构为例

方法1

import torchvision
from torch import nn

vgg16_false = torchvision.models.vgg16(pretrained=False) 

#在原有的vgg16模型结构中添加一层网络结构    add_linear1:新加的网络层的名字
vgg16_false.add_module("add_linear1", nn.Linear(in_features=1000, out_features=10))

运行结果:
······
在vgg16网络架构中新加入一层
in_features 为上层输出 out_features 为输出 bias=True表示需要一个偏置变量

方法2

加入到名为classifier层的网络结构内部
vgg16_false.classifier.add_module("add_linear2", nn.Linear(in_features=1000, out_features=10))

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

修改vgg16网络架构的参数

# 修改的是classifier[name]的第六层网络的参数
vgg16_false.classifier[6] = nn.Linear(in_features=1000, out_features=9) 

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

9.完整的训练步骤

from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

from  model import *
from torch import nn
import torch
import torchvision

# 加载数据集
train_data = torchvision.datasets.CIFAR10("../data", train=True, transform=torchvision.transforms.ToTensor(), download=True)
test_data = torchvision.datasets.CIFAR10("../data", train=False, transform=torchvision.transforms.ToTensor(), download=True)

# 使用dataloader加载数据
train = DataLoader(train_data, batch_size=64)
test = DataLoader(test_data, batch_size=64)

# 初始化模型
tudui = Tudui()
loss_function = nn.CrossEntropyLoss()  # 损失函数

learning_rate = 0.01
optim = torch.optim.SGD(tudui.parameters(), lr=learning_rate)  # 优化器

# tensorboard
writer = SummaryWriter("./logs")

epochs = 10
train_step = 0
test_step = 0

for i in range(epochs):
    print("第{}轮训练开始".format(i+1))

    tudui.train()  # 把网络设置为训练状态
    for data in train:
        imgs, targets = data
        output = tudui(imgs)
        loss = loss_function(output, targets)

        # 优化器优化模型
        optim.zero_grad()
        loss.backward()
        optim.step()

        # 写入tensorboard
        train_step = train_step + 1
        if train_step %100 == 0:
            print("训练{}次,loss为{}".format(train_step, loss.item()))
            writer.add_scalar("train", loss.item(), train_step)

    # 进行模型的测试
    tudui.eval()  # 把网络设置为测试状态
    total_test_loss = 0
    total_accuracy = 0
    with torch.no_grad():   # 使梯度不再发生变化
        for data in test:
            imgs, targets = data
            output = tudui(imgs)
            loss = loss_function(output, targets)
            total_test_loss = total_test_loss + loss.item()
            # argmax(axis=1) 跨列找最大值 并返回下标
            accuracy = (output.argmax(axis=1) == targets).sum()   # 预测正确的个数和
            total_accuracy = total_accuracy + accuracy

        print("整体的正确率为{}".format(total_accuracy/len(test_data)))
        print("整体测试集上的loss为{}".format(total_test_loss))
        writer.add_scalar("test", total_test_loss, test_step)
        test_step = test_step + 1

    # 进行每epochs参数保存
    torch.save(tudui.state_dict(), "./model/tudui_{}.pth".format(i))
    print("tudui_{}.pth模型已保存".format(i))
writer.close()

10. 使用训练好的参数进行验证

import torch
from PIL import Image
from torch import nn

class Tudui(nn.Module):
    def __init__(self):
        super(Tudui, self).__init__()
        self.model = nn.Sequential(
            nn.Conv2d(in_channels=3, out_channels=32, kernel_size=5, padding=2),
            nn.MaxPool2d(kernel_size=2),
            nn.Conv2d(in_channels=32, out_channels=32, kernel_size=5, padding=2),
            nn.MaxPool2d(kernel_size=2),
            nn.Conv2d(in_channels=32, out_channels=64, kernel_size=5, padding=2),
            nn.MaxPool2d(kernel_size=2),
            nn.Flatten(),
            nn.Linear(in_features=1024, out_features=64),
            nn.Linear(in_features=64, out_features=10)
        )
    def forward(self, input):
        x = self.model(input)
        return x

tudui = Tudui()

image_path = "imgs/bird.png"
img = Image.open(image_path)

# 将图片转换为32*32的,然后转化为tensor类型
Compose函数是依次执行列表中操作并返回
transform = torchvision.transforms.Compose([torchvision.transforms.Resize((32,32)),
                                            torchvision.transforms.ToTensor()])
image = transform(img)
# 将图片转化为Tensor型
image = torch.reshape(image, (1, 3 ,32, 32))
# print(image.shape)

# 加载训练好的模型  然后告诉程序用gpu训练好的数据在cpu上运行
tudui.load_state_dict(torch.load("./model/tudui_29.pth", map_location=torch.device("cpu")))
print(tudui)
tudui.eval()
with torch.no_grad():
    output = tudui(image)
target = output.argmax(axis=1)
print(target)

11.使用gpu进行训练模型

方法1

"""
调用gpu要用电脑显卡对应的版本的cuda
1.网络模型  tudui.cuda()
2.数据(输入,标注) imgs.cuda()   target.cuda()
3.损失函数  loss.cuda()

为提高代码的健壮性,可以加上判断
if torch.cuda.is_available():   //如果显卡可用
    tudui.cuda()
    imgs.cuda
    target.cuda()
    loss.cuda()

可以使用Google colab实验室环境进行跑实验
"""
# 加载数据集

# 使用dataloader加载数据

# 创建模型

# 初始化模型

loss_function = nn.CrossEntropyLoss() 
loss.cuda()    # 新加

# tensorboard

tudui.train()
for data in train:
    imgs, targets = data
    imgs = imgs.cuda()   # 新加
    targets = targets.cuda()   # 新加

......

tudui.eval()  
with torch.no_grad():  
    for data in test:
        imgs, targets = data
        imgs = imgs.cuda()    # 新加
    	targets = targets.cuda()   # 新加

方法2

"""
常用的方法: 开头加入
device = torch.device("cuda")   # 表示使用gpu运行实验

调用gpu要用电脑显卡对应的版本的cuda
1.网络模型  tudui.to(device)
2.数据(输入,标注) imgs = imgs.to(device)     targets = targets.to(device)
3.损失函数  loss.to(device)

可以使用Google colab实验室环境进行跑实验
"""
# device = torch.device("cpu")  # 表示使用cpu运行实验
device = torch.device("cuda")   # 表示使用gpu运行实验
# 加载数据集

# 使用dataloader加载数据

# 创建模型

# 初始化模型
......
tudui.to(device)   # 新加

loss_function = nn.CrossEntropyLoss() 
loss_function.to(device)  # 新加

# tensorboard
......

    tudui.train() 
    for data in train:
        imgs, targets = data
        imgs = imgs.to(device)     # 新加
        targets = targets.to(device)  # 新加
.....

    tudui.eval()  
    with torch.no_grad(): 
        for data in test:
            imgs, targets = data
            imgs = imgs.to(device)     # 新加
        	targets = targets.to(device)  # 新加
......

猜你喜欢

转载自blog.csdn.net/qq_40529151/article/details/123595411