【pytorch阅读笔记】pytorch基础知识

本部分共分为5部分:

  • 基本数据
  • Autograd与计算图
  • 神经网络工具箱:torch.nn
  • 模型处理 torchvision.model
  • 数据处理

pytorch最大的优势是可以使用tensor代替numpy进行对应的矩阵操作并且支持对应的GPU加速。

1.pytorch基本数据: tensor

tensor的使用类似于numpy

  • tensor创建与维度的查看

    • torch.tensor()
    • torch.zeros()
    • torch.ones()
    • torch.randn()
    • torch.arrange()
    • a.shape
    • a.size()
  • tensor的组合与分块

    • torch.cat()
    • torch.stack()
    • torch.chunk()
    • torch.split()
  • tensor索引与变形

    • torch.view()
    • torch.resize()
    • torch.reshape()
      (上述三者功能一致,自由变形)
    • torch.transpose()
    • torch.permute()
      (各维度之间变换)
    • torch.squeeze()
    • torch.unsqueeze()
      (增加某全1维度,或删除全1维度)
  • tensor的排序与取极值

    • a.sort( 0, true) [0]
      (按0维排序,true为降序,[0] 表示值,[1]表示索引)
    • a.max(0)
      (按0维度选取最大值,将每列最大值选出)
  • 自动广播机制与向量化
    自动广播:表示不同形状的tensor(向量)能自动扩展到较大的形状,并进行相应的计算

广播机制前提:

  1. 任一tensor至少有一个维度
    2.从尾部开始遍历(非从头对应),两者维度必须相等,要不其中为1,要不不存在
a = torch.one (3,1,2)
b = torch.one(2,1)
c = torch.one(2,3)
a + b 虽形状不同但可以相加
a + c 不行,尾部为23
  • tensor的内存共享
    即当原始数据改变时,拷贝得到的tensor也会进行相应的改变
  • tensor直接初始化另一个: a = b , c = a.view
  • 原地运算操作符 :a = b.add_()
  • tensor与numpy可以互相转换: a.numpy() | b.from_numpy(a)

2.Autograd与计算图

默认为不求导,需要参数

a = torch.randn(2,2, requires_grad = True)

即可进行求导

3.神经网络工具箱 torch.nn

nn.model

  • nn.parameter 函数默认需要求导,即requires_grad = True
  • nn.Model自动利用反向传播,Autograd机制。
  • nn.functional :也提供网络层和函数,但区别于nn.model,不可自动学习参数,需要用nn.parameter封装。
    • nn.functional : 设计初衷针对不需要自动求导的网络层,如BN, 激活等
    • nn.Model: 设计针对需要自动求导的网络层,如池化,卷积,全连接等
  • nn.Sequential :不考虑中间结果的线性无脑搭建,类似keras

损失函数

主要的损失函数在nn 和nn.functional 库中
举例:
loss_functional = F.cross_entropy(output, label)

实践举例

用我基友的一个例子

import torch
from torch.autograd import Variable #自动求导
import torch.nn.functional as F 
import matplotlib.pyplot as plt

x = torch.unsqueeze(torch.linspace(-1,1,100),dim=1) 
#linspace : 线性生成器,从-1 到1,一共平均生成100个数,
#dim = 1 以第二维度,行维度,全部增加1 (0无法进行求导,大部分情况自动补1,作为可学习参数的初始化,这里指二分类的初始化)
y = x.pow(2) + 0.2*torch.rand(x.size()) 
# 以x的维度尺寸,随机数和x平方相加

x,y = Variable(x),Variable(y)
#打印图片
plt.scatter(x.data.numpy(),y.data.numpy())
plt.show()


#建立网络模型类
class Net(torch.nn.Module):
    def __init__(self,n_features,n_hidden,n_output): 
        super(Net,self).__init__() 
        # 继承nn.module的构造函数初始化
        
        self.hidden=torch.nn.Linear(n_features,n_hidden)
        #建立线性层,输入,输出(隐藏层)
        self.predit=torch.nn.Linear(n_hidden,n_output)

    #建立向前传播的图(由于pytorch动态生成前向图的缘故)
    def forward(self,x):  
        x = F.relu(self.hidden(x))
        x = self.predit(x)  
        return x

optimizer = torch.optim.SGD(net.parameters(),lr=0.5)
loss_func = torch.nn.MSELoss()
#定义对应的优化器和损失函数




net = Net(1,10,1)
#构建对应的网络类,内部参数 n_features =1,n_hidden= 10 ,n_output =1
#故为二分类问题,隐藏层有10个

for t in range(100):
#迭代100次进行训练
    prediction =net(x)
    loss = loss_func(prediction,y) 
    # 损失函数参数: prediction 前向值,y 标签值
    optimizer.zero_grad() #将所有参数的梯度全部降为0,梯度值保留在这个里面
    loss.backward()   
    #自动反向传播过程
    optimizer.step()   
    #优化器更新


    if t%5==0:
    #每5次打印
        plt.cla()
        plt.scatter(x.data.numpy(),y.data.numpy())
        plt.plot(x.data.numpy(),prediction.data.numpy(),'r-',lw=5)
        plt.text(0.5,0,'Loss=%.4f' % loss.data,fontdict={'size':20,'color':'red'})
        plt.pause(0.1)

4.模型处理 torchvision.models

torchvision是一个独立的库,作用为可以快速搭物体检测网络并含有大量封装模型,例如:VGG.Resnet,Inception等等

加载自己的模型

加载模型,即加载对应的state_dict()
state_dict():记录模型状态的字典。由于在保存模型时不需要把所有代码都进行保存,仅需要保存可学习的参数即可,(例如卷积层,全连接等),所以需要有存在保存模型可学习参数(状态)的字典。

  • key:每个模型层名字
  • value: 该层对应的参数w,b等

每个模型都可以有自己的state_dict(),(优化器也有)

应用于模型加载的常用函数:
(1) torch.save(): 可保存模型,优化器等
(2) torch.load(‘你的模型路径’): 加载模型
(3) torch.nn.Model.load_state_dict():通过去序列化的state_dict来加载模型权重(去掉键值关系的key value)

5.数据加载

pytorch提供了标准化的数据集处理框架

继承Dataset 类 -------》增加数据变换 -------》继承Dataloader

Dataset继承

提供了torch.utils.data.Dataset 类 ,使用时需要重写_len_( ) 和 _ getitem _( )

from torch.utils.data import Dataset
import torch
class MyDateset(Dataset):
    def __init__(self,num=10000,transform=None):  #这里就可以写你的参数了,比如文件夹什么的。
        self.len=num
        self.transform=transform
    def __len__(self):
        return self.len
    def __getitem__(self,idx): #用于按照索引读取每个元素的具体内容
        data=torch.rand(3,3,5)  #这里就是你的数据图像的话就是C*M*N的tensor,这里创建了一个3*3*5的张量
        label=torch.LongTensor([1])   #label也是需要一个张量
        if self.transform:    #这里就是数据预处理的部分 、
            data=self.transform(data)  #处理完必须要返回torch.Tensor类型
        return data,label

数据增强

提供了torchvision.transforms

dataloader

之前所说的Dataset类是读入数据集数据并且对读入的数据进行了索引。但是光有这个功能是不够用的,在实际的加载数据集的过程中,我们的数据量往往都很大,对此我们还需要一下几个功能:

  • 可以分批次读取:batch-size
  • 可以对数据进行随机读取,可以对数据进行洗牌操作(shuffling),打乱数据集内数据分布的顺序
  • 可以并行加载数据(利用多核处理器加快载入数据的效率)

这时候就需要Dataloader类了,Dataloader这个类并不需要我们自己设计代码,我们只需要利用DataLoader类读取我们设计好的ShipDataset即可:

# 利用之前创建好的ShipDataset类去创建数据对象
ship_train_dataset = ShipDataset(data_path, augment=transform)
# 利用dataloader读取我们的数据对象,并设定batch-size和工作现场
ship_train_loader = DataLoader(ship_train_dataset, batch_size=16, num_workers=4, shuffle=False, **kwargs)

完整代码

dataset加载图片和标签,做成一个类,并完成迭代方法

from PIL import Image
import torch
 
class MyDataset(torch.utils.data.Dataset): #创建自己的类:MyDataset,这个类是继承的torch.utils.data.Dataset
    def __init__(self,root, datatxt, transform=None, target_transform=None): #初始化一些需要传入的参数
        super(MyDataset,self).__init__()
        fh = open(root + datatxt, 'r') #按照传入的路径和txt文本参数,打开这个文本,并读取内容
        imgs = []                      #创建一个名为img的空列表,一会儿用来装东西
        for line in fh:                #按行循环txt文本中的内容
            line = line.rstrip()       # 删除 本行string 字符串末尾的指定字符,这个方法的详细介绍自己查询python
            words = line.split()   #通过指定分隔符对字符串进行切片,默认为所有的空字符,包括空格、换行、制表符等
            imgs.append((words[0],int(words[1]))) #把txt里的内容读入imgs列表保存,具体是words几要看txt内容而定
                                        # 很显然,根据我刚才截图所示txt的内容,words[0]是图片信息,words[1]是lable
        self.imgs = imgs
        self.transform = transform
        self.target_transform = target_transform
 
    def __getitem__(self, index):    #这个方法是必须要有的,用于按照索引读取每个元素的具体内容
        fn, label = self.imgs[index] #fn是图片path #fn和label分别获得imgs[index]也即是刚才每行中word[0]和word[1]的信息
        img = Image.open(root+fn).convert('RGB') #按照path读入图片from PIL import Image # 按照路径读取图片
 
        if self.transform is not None:
            img = self.transform(img) #是否进行transform
        return img,label  #return很关键,return回哪些内容,那么我们在训练时循环读取每个batch时,就能获得哪些内容
 
    def __len__(self): #这个函数也必须要写,它返回的是数据集的长度,也就是多少张图片,要和loader的长度作区分
        return len(self.imgs)
 
#根据自己定义的那个MyDataset来创建数据集!注意是数据集!而不是loader迭代器
train_data=MyDataset(txt=root+'train.txt', transform=transforms.ToTensor())
test_data=MyDataset(txt=root+'test.txt', transform=transforms.ToTensor())

使用Dataloader,进行对应的batch读入,是否洗牌等

#然后就是调用DataLoader和刚刚创建的数据集,来创建dataloader,这里提一句,loader的长度是有多少个batch,所以和batch_size有关
train_loader = DataLoader(dataset=train_data, batch_size=64, shuffle=True)
test_loader = DataLoader(dataset=test_data, batch_size=64)
 

使用数据集时:

for batch_index, data, target in test_loader:
        if use_cuda:
            data, target = data.cuda(), target.cuda()
        data, target = Variable(data, volatile=True), Variable(target)

_ getitem _( ) 作为迭代器,能直接进行使用
python迭代器:

  • iter 创建对应迭代器
  • next 给出下一个数据

tips : 在用 for…in… 迭代对象时,如果对象没有实现 __ iter __ , __ next __ 迭代器协议,Python的解释器就会去寻找__getitem__ 来迭代对象.

6.GPU加速

  • torch.cuda.is_available() 判断GPU是否可用
  • device = torch.device(“cuda : 1”) 指定转移到哪块GPU上
  • CUDA_VISIBLE_DEVICES = 2 全局指定使用哪块GPU

码字不易,如果对你有用,点个赞再走呗~

发布了68 篇原创文章 · 获赞 31 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_35307005/article/details/104052917