小土堆代码暂存 -- 完整的GPU训练

就只是贴了一个代码,部分解释写在代码注释里面了,之后会补上文字解释:

1. 第一种方式:

import torch
import torchvision
import time     #用于计时的
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
from torch.utils.data import DataLoader

"""
方法一:
想要使用GPU训练:那么在 "网络模型的实体" 、 "从Dataoader中加载的数据" 、 "损失函数实体"  都是可以 .cuda()来表明时可以使用GPU的
并且,网络模型的实体 、 损失函数实体 是可以 不去赋值的 
即: 可以写为 z1 = z1.cuda()  也可以直接略写为 z1.cuda()

PS 对于这种方式,其实为了增强容错,可以加一句: 
if torch.cuda.is_available() :
    z1 = z1.cuda()
    loss_fn = loss_fn.cuda()
    imgs = imgs.cuda()
    targets = targets.cuda()
"""


#定义一个名为Zch的神经网络模型的类 ,之所以是神经网络模型的类是因为Zch继承了nn.Module
class Zch(nn.Module):
    def __init__(self):
        super(Zch, self).__init__()
        self.module1 = Sequential(
            Conv2d(3, 32, 5, padding=2) ,
            MaxPool2d(2) ,
            Conv2d(32, 32, 5, padding=2) ,
            MaxPool2d(2) ,
            Conv2d(32, 64, 5, padding=2) ,
            MaxPool2d(2) ,
            Flatten() ,                            # torch对于在nn.Module中也有专门的flatten函数,torch.nn.Flatten()
            Linear(1024, 64) ,
            Linear(64, 10)
        )

    #对于神经网络模型,虽说训练时要一来一回 : (来:)需要前向传播计算loss,grad ; (回:)需要反向传播时修正模型中的参数
    #但显然,通过前想传播就可以构造出计算图了(计算的流程图了) , 所以 ,反向传播写在神经网络类的定以外就可以了(而且反响传播人家pytorch已经集装好了,两条函数调用就可以了)
    def forward(self,x):
        output = self.module1(x)
        return output


#引入(下载)torch官方已经整理好的数据集CIFAR10
train_dataset = torchvision.datasets.CIFAR10("dataset",train=True,transform=torchvision.transforms.ToTensor(),download=True)     # 第二个参数train=True意思是 这是训练数据集;
test_dataset = torchvision.datasets.CIFAR10("dataset",train=False,transform=torchvision.transforms.ToTensor(),download=True)     # 第二个参数train=True意思是 这是测试数据集;
#展示train_dataset 、 test_dataset 的长度
print( len( train_dataset ) )
print( len( test_dataset ) )

#通过DataLoader类实例化训练集数据和测试集数据的Dataloader数据加载器
train_dataloader = DataLoader(train_dataset,batch_size=64)
test_dataloader = DataLoader(test_dataset,batch_size=64)


z1 = Zch()      # 实例化模型,我们得把训练的数据塞到一个实例出来的模型中去
z1 = z1.cuda()  # 将模型变为cuda模式: z1.cuda()

loss_fn = nn.CrossEntropyLoss()     # 定义(实例化) 损失函数,由于CIFAR10是一个10分类问题,所以将损失函数实例化为一个交叉熵计算工具,用于计算预测值和真实值之间的差距loss , 并可以通过调用.backward()来根据loss计算出模型中的各个参数的梯度grad
loss_fn = loss_fn.cuda()    #损失函数也是可以转换为cuda形式的 : loss_fn.cuda()

learning_rate = 1e-2                # 1e-2 就是0.01的意思,这样更好看、直观。并且,learning_rate是一个学习是比较重要的参数,所以,但提出来,方便查找和修改
optim = torch.optim.SGD(z1.parameters() , lr=learning_rate)    #定义(实例化)一个优化器,把模型的实例z1的参数与optim绑定,好让优化器知道 该通过loss_fn.backward()计算出的grad 来去修正谁

#一般会训练多个epoch (1个epoch就是一个全数据集走一遍)
epoch = 10      # 训练的轮数
train_step = 0
test_step = 0

#计算训练时间
start_time = time.time()

for idx in range(epoch):
    #训练开始:
    z1.train()      #对于神经网络中有Dropout层、BatchNorm层等时,在模型训练、测试的时在训练前要明确地加 .train() .eval()标注。 如果网络中没有这两类层结构,那么,.train() .eval()加不加其实没关系不影响模型训练
    for data in train_dataloader :
        imgs,labels = data      #由于CIFAR10是一个10分类问题,所以对于每个图片他都是输出一个数值代表一个类别。由于我们设置batch_size=64 , 所以,labels就算一个长度为64的1维度tensor向量
        imgs = imgs.cuda()      #对于数据来说就必须得赋值了,无法略写为 imgs.cuda() 或 labels.cuda()
        labels = labels.cuda()  #labels同理

        outputs = z1(imgs)
        loss = loss_fn(outputs , labels)    # 计算得到loss
        #接下来准备用优化器根据loss调用backward()函数 求出的 grad 来对模型参数进行更新 。
        #【注意】由于我们是在一套循环里面反复调用优化器对模型参数进行更新,为了避免上一轮的干扰,每次在loss计算相应的grad前,先将优化器的内容清空
        optim.zero_grad()
        loss.backward()     #根据计算得到的loss计算出对应的grad
        optim.step()        #调用优化器,根据 loss.backward()求得的grad 对模型参数进行更新
        train_step += 1
        tt_time = time.time()
        if train_step % 100 == 0 :
            print("第",train_step,"次训练迭代时,loss为:",loss.item())     #loss.item()和loss的区别在于:区别不大,略
            print("到第", train_step, "次训练迭代时,耗时:", tt_time-start_time)

    #测试开始 :
    #如何确认训练的模型是否有效呢? -- 通过测试数据集:测试集数据 传入 刚刚在训练的模型 ,查看其准确率,毕竟loss没有准确率来的直观
    z1.eval()       # 对于神经网络中有Dropout层、BatchNorm层等时,在模型训练、测试的时在训练前要明确地加 .train() .eval()标注。 如果网络中没有这两类层结构,那么,.train() .eval()加不加其实没关系不影响模型训练
    with torch.no_grad() :     #在测试的时候就不需要对模型进行调优了,所以我们需要写明no_grad()
        test_total_loss = 0
        test_total_accuracy = 0     #在一轮epoch中可以正确预测多少个图片分类
        for data in test_dataloader :
            imgs , targets = data
            imgs = imgs.cuda()
            targets = targets.cuda()

            outputs = z1(imgs)
            #计算loss
            loss = loss_fn(outputs , targets)
            test_total_loss += loss
            #计算accuracy
            #labels是一个1维的64元素的tensor,我们的outputs是一个2维的64*10的tensor,64是batchsize大小,而10是因为我们的输出是经网络训练后,该张图片是10分类中的各个分类的概率
            outputs = outputs.argmax(1)     #找到一维array中的最大值,并返回该最大值所在的array的下标 ; 参数为0意味着一列列对比,参数为1意味着一行行对比
            accuracy = (outputs == targets).sum()
            test_total_accuracy += accuracy

        print("第",idx,"轮测试集上的总loss是:",test_total_loss.item())       #不加.item()输出是:tensor(311.6063) 而非 311.6063 就很乱
        print("第", idx, "轮测试集上的总accuracy是:", test_total_accuracy.item())







    # #补充解释一下求解accuracy时的公式:  accuracy = (outputs == targets).sum()
# a1 = torch.tensor([1,3,5,7])
# b1 = torch.tensor([1,36,15,7])
#
# res = (a1 == b1)    #因为两个tensor相 == 就是会返回一个元素是True或者False的tensor阿
# print(res)
# print(res.sum())    #该元素是True或者False的tensor的调用sum()函数返回该tensor中所有的True值的加和

2. 第二种方法 :

import torch
import torchvision
import time     #用于计时的
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
from torch.utils.data import DataLoader

"""
方法二:
使用.to(device)来定义训练的设备

方法二 和 方法一 相同,想要使用GPU训练:也是只能在 "网络模型的实体" 、 "从Dataoader中加载的数据" 、 "损失函数实体"  上做文章,将其通过.to()传送至对应的device上
并且,网络模型的实体 、 损失函数实体 是可以 不去赋值的 
即: 可以写为 z1 = z1.to(device)  也可以直接略写为 z1.to(device)


PS 对于这种方式,其实为了增强容错,更合适的做法是:
if torch.cuda.is_available() :
    device = torch.device("cuda:0")     # 和 device = torch.device("cuda") 在只有一个GPU时是完全没有差别的
else :
    device = torch.device("cpu")

或者利用语法糖,简单地写为:
device = torch.drvice( "cuda" if torch.cuda.is_availabel()  else "cpu" )

"""



#定义一个名为Zch的神经网络模型的类 ,之所以是神经网络模型的类是因为Zch继承了nn.Module
class Zch(nn.Module):
    def __init__(self):
        super(Zch, self).__init__()
        self.module1 = Sequential(
            Conv2d(3, 32, 5, padding=2) ,
            MaxPool2d(2) ,
            Conv2d(32, 32, 5, padding=2) ,
            MaxPool2d(2) ,
            Conv2d(32, 64, 5, padding=2) ,
            MaxPool2d(2) ,
            Flatten() ,                            # torch对于在nn.Module中也有专门的flatten函数,torch.nn.Flatten()
            Linear(1024, 64) ,
            Linear(64, 10)
        )

    #对于神经网络模型,虽说训练时要一来一回 : (来:)需要前向传播计算loss,grad ; (回:)需要反向传播时修正模型中的参数
    #但显然,通过前想传播就可以构造出计算图了(计算的流程图了) , 所以 ,反向传播写在神经网络类的定以外就可以了(而且反响传播人家pytorch已经集装好了,两条函数调用就可以了)
    def forward(self,x):
        output = self.module1(x)
        return output


#引入(下载)torch官方已经整理好的数据集CIFAR10
train_dataset = torchvision.datasets.CIFAR10("dataset",train=True,transform=torchvision.transforms.ToTensor(),download=True)     # 第二个参数train=True意思是 这是训练数据集;
test_dataset = torchvision.datasets.CIFAR10("dataset",train=False,transform=torchvision.transforms.ToTensor(),download=True)     # 第二个参数train=True意思是 这是测试数据集;
#展示train_dataset 、 test_dataset 的长度
print( len( train_dataset ) )
print( len( test_dataset ) )

#通过DataLoader类实例化训练集数据和测试集数据的Dataloader数据加载器
train_dataloader = DataLoader(train_dataset,batch_size=64)
test_dataloader = DataLoader(test_dataset,batch_size=64)

#定义训练的设备:
device_cpu = torch.device("cpu")
device_gpu = torch.device("cuda:0")


z1 = Zch()      # 实例化模型,我们得把训练的数据塞到一个实例出来的模型中去
z1 = z1.to(device_gpu)  # 将模型发送到device上执行

loss_fn = nn.CrossEntropyLoss()     # 定义(实例化) 损失函数,由于CIFAR10是一个10分类问题,所以将损失函数实例化为一个交叉熵计算工具,用于计算预测值和真实值之间的差距loss , 并可以通过调用.backward()来根据loss计算出模型中的各个参数的梯度grad
loss_fn = loss_fn.to(device_gpu)    # 将损失函数发送到device上执行

learning_rate = 1e-2                # 1e-2 就是0.01的意思,这样更好看、直观。并且,learning_rate是一个学习是比较重要的参数,所以,但提出来,方便查找和修改
optim = torch.optim.SGD(z1.parameters() , lr=learning_rate)    #定义(实例化)一个优化器,把模型的实例z1的参数与optim绑定,好让优化器知道 该通过loss_fn.backward()计算出的grad 来去修正谁

#一般会训练多个epoch (1个epoch就是一个全数据集走一遍)
epoch = 10      # 训练的轮数
train_step = 0
test_step = 0

#计算训练时间
start_time = time.time()

for idx in range(epoch):
    #训练开始:
    z1.train()      #对于神经网络中有Dropout层、BatchNorm层等时,在模型训练、测试的时在训练前要明确地加 .train() .eval()标注。 如果网络中没有这两类层结构,那么,.train() .eval()加不加其实没关系不影响模型训练
    for data in train_dataloader :
        imgs,labels = data              #由于CIFAR10是一个10分类问题,所以对于每个图片他都是输出一个数值代表一个类别。由于我们设置batch_size=64 , 所以,labels就算一个长度为64的1维度tensor向量
        imgs = imgs.to(device_gpu)      #对于数据来说就必须得赋值了,无法略写为 imgs.cuda() 或 labels.cuda()
        labels = labels.to(device_gpu)  #labels同理

        outputs = z1(imgs)
        loss = loss_fn(outputs , labels)    # 计算得到loss
        #接下来准备用优化器根据loss调用backward()函数 求出的 grad 来对模型参数进行更新 。
        #【注意】由于我们是在一套循环里面反复调用优化器对模型参数进行更新,为了避免上一轮的干扰,每次在loss计算相应的grad前,先将优化器的内容清空
        optim.zero_grad()
        loss.backward()     #根据计算得到的loss计算出对应的grad
        optim.step()        #调用优化器,根据 loss.backward()求得的grad 对模型参数进行更新
        train_step += 1
        tt_time = time.time()
        if train_step % 100 == 0 :
            print("第",train_step,"次训练迭代时,loss为:",loss.item())     #loss.item()和loss的区别在于:区别不大,略
            print("到第", train_step, "次训练迭代时,耗时:", tt_time-start_time)

    #测试开始 :
    #如何确认训练的模型是否有效呢? -- 通过测试数据集:测试集数据 传入 刚刚在训练的模型 ,查看其准确率,毕竟loss没有准确率来的直观
    z1.eval()       # 对于神经网络中有Dropout层、BatchNorm层等时,在模型训练、测试的时在训练前要明确地加 .train() .eval()标注。 如果网络中没有这两类层结构,那么,.train() .eval()加不加其实没关系不影响模型训练
    with torch.no_grad() :     #在测试的时候就不需要对模型进行调优了,所以我们需要写明no_grad()
        test_total_loss = 0
        test_total_accuracy = 0     #在一轮epoch中可以正确预测多少个图片分类
        for data in test_dataloader :
            imgs , targets = data
            imgs = imgs.to(device_gpu)
            targets = targets.to(device_gpu)

            outputs = z1(imgs)
            #计算loss
            loss = loss_fn(outputs , targets)
            test_total_loss += loss
            #计算accuracy
            #labels是一个1维的64元素的tensor,我们的outputs是一个2维的64*10的tensor,64是batchsize大小,而10是因为我们的输出是经网络训练后,该张图片是10分类中的各个分类的概率
            outputs = outputs.argmax(1)     #找到一维array中的最大值,并返回该最大值所在的array的下标 ; 参数为0意味着一列列对比,参数为1意味着一行行对比
            accuracy = (outputs == targets).sum()
            test_total_accuracy += accuracy

        print("第",idx,"轮测试集上的总loss是:",test_total_loss.item())       #不加.item()输出是:tensor(311.6063) 而非 311.6063 就很乱
        print("第", idx, "轮测试集上的总accuracy是:", test_total_accuracy.item())


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值