赞
踩
目录
2. torch.utils.data.TensorDataset
3. torch.utils.data.DataLoader
4. torchvision.datasets.ImageFolder
PyTorch 是 Torch7 团队开发的,从它的名字就可以看出,其与 Torch 的不同之处在于 PyTorch 使用了 Python 作为开发语言。
PyTorch 既可以看做加入了 GPU 支持的 numpy,同时也可以看 成一个拥有自动求导功能的强大的深度神经网络,除了 Facebook之外,它还已经被 Twitter、CMU 和 Salesforce 等机构采用。
PyTorch的特点:
安装GPU版本的Pytorch链接:
https://blog.csdn.net/weixin_40431584/article/details/105119633
PyTorch 里面处理的最基本的操作对象就是 Tensor,Tensor 是张量的英文,表示的是一个多维的矩阵,比如零维就是一个点,一维就是向量,二维就是一般的矩阵,多维就相当于一个多维的数组,这和 numpy 是对应的,而且 PyTorch 的 Tensor 可以和 numpy的ndarray相互转换,唯一不同的是PyTorch可以在GPU上运行,而numpy的ndarray只能在CPU上运行。
常用的不同数据类型的Tensor:
- import torch
-
- # 定义一个三行两列给定元素的矩阵,并且显示出矩阵的元素和大小
- a = torch.Tensor([[2, 3], [4, 8], [7, 9]])
- print('a is: {}'.format(a))
- print('a size is: {}'.format(a.size()))
- a is: tensor([[2., 3.],
- [4., 8.],
- [7., 9.]])
- a size is: torch.Size([3, 2])
torch.Tensor默认的是torch.FloatTensor数据类型,也可以定义我们想要的数据类型,如下:
- b = torch.LongTensor([[2, 3], [4, 8], [7, 9]])
- print('b is: {}'.format(b))
- b is: tensor([[2, 3],
- [4, 8],
- [7, 9]])
也可以创建一个全是0的空Tensor或者取一个正态分布作为随机初始值:
- c = torch.zeros((3, 2))
- print('zero tensor: {}'.format(c))
-
- d = torch.randn((3, 2))
- print('normal random is:{}'.format(d))
- zero tensor: tensor([[0., 0.],
- [0., 0.],
- [0., 0.]])
- normal random is:tensor([[-0.7224, 0.6373],
- [-0.0982, 0.1669],
- [-1.4247, 0.5982]])
我们也可以像numpy一样通过索引的方式取得其中的元素,同时也可以改变它的值,比如将a的第一行第二列改变为100。
- a[0, 1] = 100
- print('changed a is: {}'.format(a))
- changed a is: tensor([[ 2., 100.],
- [ 4., 8.],
- [ 7., 9.]])
除此之外,还可以在Tensor与numpy.ndarray之间相互转换:
- import numpy as np
-
- numpy_b = b.numpy()
- print('conver to numpy is \n {}'.format(numpy_b))
-
- e = np.array([[2, 3], [4, 5]])
- torch_e = torch.from_numpy(e)
- print('from numpy to torch.Tensor is \n {}'.format(torch_e))
- f_torch_e = torch_e.float()
- print('cahnge data type to float tensor \n {}'.format(f_torch_e))
- conver to numpy is
- [[2 3]
- [4 8]
- [7 9]]
- from numpy to torch.Tensor is
- tensor([[2, 3],
- [4, 5]], dtype=torch.int32)
- cahnge data type to float tensor
- tensor([[2., 3.],
- [4., 5.]])
通过简单的b.numpy(),就能将b转换为numpy数据类型,同时使用 torch.from_numpy()就能将numpy转换为tensor,如果需要更改tensor的数据类型,只需要在转换后的tensor后面加上你需要的类型,比如想将a的类型转换成float,只需a.float()就可以了。
如果你的电脑支持GPU加速,还可以将Tensor放到GPU上。首先通过torch.cuda.is_available()判断一下是否支持GPU,如果想把tensor a放到GPU上,只需a.cuda()就能够将tensor a放到GPU上了。
- if torch.cuda.is_available():
- a_cuda = a.cuda()
- print(a_cuda)
- tensor([[ 2., 100.],
- [ 4., 8.],
- [ 7., 9.]], device='cuda:0')
这个在numpy里面就没有了,是神经网络计算图里特有的一个概念,就是Variable提供了自动求导的功能。
Variable和Tensor本质上没有区别,不过Variable会被放入一个计算图中,然后进行前向传播,反向传播,自动求导。首先Variable是在torch.autograd.Variable中,要将一个tensor变成Variable也非常简单,比如想让一个tensor a变成Variable,只需要 Variable(a)就可以了。
Variable有三个比较重要的组成属性:
下面通过例子来具体说明一下:
- from torch.autograd import Variable # torch中Variable模块
-
- # 创建变量
- x = Variable(torch.Tensor([1]), requires_grad=True)
- w = Variable(torch.Tensor([2]), requires_grad=True)
- b = Variable(torch.Tensor([3]), requires_grad=True)
-
- # 建立一个计算图
- y = w * x + b
-
- # 计算梯度
- y.backward()
-
- print(x.grad)
- print(w.grad)
- print(b.grad)
- tensor([2.])
- tensor([1.])
- tensor([1.])
构建Variable,要注意得传入一个参数requires_grad=True,这个参数表示是否对这个变量求梯度,默认的是False,也就是不对这个变量求梯度,这里我们希望得到这些变量的梯度,所以需要传入这个参数。
从上面的代码中,我们注意到了一行y.backward(),这一行代码就是所谓的自动求导,这其实等价y.backward(torch.FloatTensor([1])),只不过对于标量求导里面的参数就可以不写了,自动求导不需要你再去明确地写明哪个函数对哪个函数求导,直接通过这行代码就能对所有的需要梯度的变量进行求导,得到它们的梯度,然后通过x.grad可以得到x的梯度。
上面是标量的求导,同时也可以做矩阵求导,比如:
- x = torch.randn(3)
- x = Variable(x, requires_grad=True)
-
- y = x * 2
- print(y)
-
- y.backward(torch.FloatTensor([1, 0.1, 0.01]))
- print(x.grad)
- tensor([ 2.3863, 1.3822, -2.5512], grad_fn=<MulBackward0>)
- tensor([2.0000, 0.2000, 0.0200])
相当于给出了一个三维向量去做运算,这时候得到的结果y就是一个向量,这里对这个向量求导就不能直接写成 y.backward(),这样程序是会报错的。这个时候需要传入参数声明,比如y.backward(torch.FloatTensor([1, 1, 1])),这样得到的结果就是它们每个分量的梯度,或者可以传入y.backward(torch.FloatTensor([1, 0.1, 0.01])),这样得到的梯度就是它们原本的梯度分别乘上1,0.1和0.01。
在处理任何机器学习问题之前都需要数据读取,并进行预处理。PyTorch提供了很多工具使得数据的读取和预处理变得很容易。接下来介绍 Dataset,TensorDataset,DataLoader,ImageFolder的简单用法。
它是代表这一数据的抽象类。你可以自己定义你的数据类,继承和重写这个抽象类,非常简单,只需要定义__len__和__getitem__这两个函数:
- from torch.utils.data import Dataset
- import pandas as pd
-
- class myDataset(Dataset):
- def __init__(self, csv_file, txt_file, root_dir, other_file):
- self.csv_data = pd.read_csv(csv_file)
- with open(txt_file, 'r') as f:
- data_list = f.readlines()
- self.txt_data = data_list
- self.root_dir = root_dir
-
- def __len__(self):
- return len(self.csv_data)
-
- def __getitem__(self, idx):
- data = (self.csv_data[idx], self.txt_data[idx])
- return data
通过上面的方式,可以定义我们需要的数据类,可以通过迭代的方式来取得每一个数据,但是这样很难实现取batch,shuffle或者是多线程去读取数据。
它继承自Dataset,新版把之前的data_tensor和target_tensor去掉了,输入变成了可变参数,也就是我们平常使用*args。
- # 原版使用方法
-
- train_dataset = Data.TensorDataset(data_tensor=x, target_tensor=y)
-
- # 新版使用方法
-
- train_dataset = Data.TensorDataset(x, y)
- import torch
- import torch.utils.data as Data
-
- BATCH_SIZE = 5
-
- x = torch.linspace(1, 10, 10)
- y = torch.linspace(10, 1, 10)
-
- torch_dataset = Data.TensorDataset(x, y)
- loader = Data.DataLoader(
- dataset=torch_dataset,
- batch_size=BATCH_SIZE,
- shuffle=True,
- num_workers=0,
- )
-
- for epoch in range(3):
- for step, (batch_x, batch_y) in enumerate(loader):
- print('Epoch: ', epoch, '| Step: ', step, '| batch x: ', batch_x.numpy(), '| batch y: ', batch_y.numpy())
- Epoch: 0 | Step: 0 | batch x: [6. 8. 9. 2. 5.] | batch y: [5. 3. 2. 9. 6.]
- Epoch: 0 | Step: 1 | batch x: [10. 4. 7. 3. 1.] | batch y: [ 1. 7. 4. 8. 10.]
- Epoch: 1 | Step: 0 | batch x: [ 5. 10. 2. 6. 7.] | batch y: [6. 1. 9. 5. 4.]
- Epoch: 1 | Step: 1 | batch x: [9. 1. 8. 4. 3.] | batch y: [ 2. 10. 3. 7. 8.]
- Epoch: 2 | Step: 0 | batch x: [ 5. 7. 1. 10. 9.] | batch y: [ 6. 4. 10. 1. 2.]
- Epoch: 2 | Step: 1 | batch x: [6. 8. 2. 4. 3.] | batch y: [5. 3. 9. 7. 8.]
PyTorch中提供了一个简单的办法来做这个事情,通过torch.utils.data.DataLoader来定义一个新的迭代器,如下:
- from torch.utils.data import DataLoader
-
- dataiter = DataLoader(myDataset,batch_size=32,shuffle=True,collate_fn=defaulf_collate)
其中的参数都很清楚,只有collate_fn是标识如何取样本的,我们可以定义自己的函数来准确地实现想要的功能,默认的函数在一般情况下都是可以使用的。
(需要注意的是,Dataset类只相当于一个打包工具,包含了数据的地址。真正把数据读入内存的过程是由Dataloader进行批迭代输入的时候进行的。)
另外在torchvison这个包中还有一个更高级的有关于计算机视觉的数据读取类:ImageFolder,主要功能是处理图片,且要求图片是下面这种存放形式:
- root/dog/xxx.png
-
- root/dog/xxy.png
-
- root/dog/xxz.png
-
- root/cat/123.png
-
- root/cat/asd/png
-
- root/cat/zxc.png
之后这样来调用这个类:
- from torchvision.datasets import ImageFolder
-
- dset = ImageFolder(root='root_path', transform=None, loader=default_loader)
其中 root 需要是根目录,在这个目录下有几个文件夹,每个文件夹表示一个类别:transform 和 target_transform 是图片增强,后面我们会详细介绍;loader是图片读取的办法,因为我们读取的是图片的名字,然后通过 loader 将图片转换成我们需要的图片类型进入神经网络。
在PyTorch里面编写神经网络,所有的层结构和损失函数都来自于torch.nn,所有的模型构建都是从这个基类nn.Module继承的,于是有了下面这个模板。
- import torch.nn as nn
-
- class net_name(nn.Module):
- def __init__(self, other_arguments):
- super(net_name, self).__init__()
- self.convl = nn.Conv2d(in_channels, out_channels, kernel_size)
- # 其他网路层
-
- def forward(self, x):
- x = self.convl(x)
- return x
这样就建立了一个计算图,并且这个结构可以复用多次,每次调用就相当于用该计算图定义的相同参数做一次前向传播,这得益于PyTorch的自动求导功能,所以我们不需要自己编写反向传播,而所有的网络层都是由nn这个包得到的,比如线性层nn.Linear。
定义完模型之后,我们需要通过nn这个包来定义损失函数。常见的损失函数都已经定义在了nn中,比如均方误差、多分类的交叉熵,以及二分类的交叉熵等等,调用这些已经定义好的损失函数也很简单:
- criterion = nn.CrossEntropyLoss()
-
- loss = criterion(output, target)
-
- criterion = nn.CrossEntropyLoss() loss = criterion(output, target)
在机器学习或者深度学习中,我们需要通过修改参数使得损失函数最小化(或最大化),优化算法就是一种调整模型参数更新的策略。优化算法分为两大类。
这种算法使用各个参数的梯度值来更新参数,最常用的一阶优化算法是梯度下降。所谓的梯度就是导数的多变量表达式,函数的梯度形成了一个向量场,同时也是一个方向,这个方向上方向导数最大,且等于梯度。梯度下降的功能是通过寻找最小值,控制方差,更新模型参数,最终使模型收敛,网络的参数更新公式是:
其中
二阶优化算法使用了二阶导数(也叫做Hessian方法)来最小化或最大化损失函数,主要基于牛顿法,但是由于二阶导数的计算成本很高,所以这种方法并没有广泛使用。torch.optim是一个实现各种优化算法的包,大多数常见的算法都能够直接通过这个包来调用,比如随机梯度下降,以及添加动量的随机梯度下降,自适应学习率等。在调用的时候将需要优化的参数传入,这些参数都必须是Variable,然后传入一些基本的设定,比如学习率和动量等。
optimizer = optim.SGD(model.parameters(), lr = 0.01, momentum=0.9)
这样我们就将模型的参数作为需要更新的参数传入优化器,设定学习率是0.01,动量是0.9随机梯度下降,在优化之前需要先将梯度归零,即optimizer.zeros(),然后通过loss.backward()反向传播,自动求导得到每个参数的梯度,最后只需要optimizer.step()就可以通过梯度作一步参数更新。
- import torch
- import torch.utils.data as Data
- import torch.nn.functional as F
- from torch.autograd import Variable
- import matplotlib.pyplot as plt
-
- torch.manual_seed(1)
-
- LR = 0.01
- BATCH_SIZE = 32
- EPOCH = 12
-
- # 模拟数据
- x = torch.unsqueeze(torch.linspace(-1, 1, 1000), dim=1)
- y = x.pow(2) + 0.1*torch.normal(torch.zeros(*x.size()))
-
- # 绘制数据集
- plt.scatter(x.numpy(), y.numpy())
- plt.show()
在PyTorch里面使用torch.save来保存模型的结构和参数,有两种保存方式:
可以这样保存,save的第一个参数是保存对象,第二个参数是保存路径及名称:
- torch.save(model, './model.pth')
-
- torch.save(model.state_dict(), './model_state.pth')
加载模型有两种方式对应于保存模型的方式:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。