PyTorch了解与安装
PyTorch是利用深度学习进行科学研究的重要工具,学术界常用的深度学习框架,简洁、高效、扩展性好。
PyTorch的安装
- 安装Anaconda
- 创建虚拟环境(Windows在Anaconda Prompt进行)
conda create -n pytorch python=3.8
- 查看环境是否安装成功
conda info --envs
- 进入创建的pytorch环境
conda activate pytorch
- 安装pytorch,在PyTorch官网https://pytorch.org/寻找安装命令代码(根据自己的安装版本选择)
- 测试PyTorch
安装的是CPU版本的话会返回False,能够调用GPU的会返回True
但之后用jutpter notebook时出现了以下问题: 解决方法:参考了安装PyTorch后jupyter notebook中仍出现“No module named torch“, Anaconda虚拟环境安装PyTorch并使用Spyder ,操作之后即可成功运行
激活环境命令
conda activate pytorch
退出当前环境
conda deactivate
安装包
conda install package_name
卸载包
conda remove package_name
显示所有安装的包
conda list
PyTorch基础知识
张量(Tensor)
- 任何维度的数据表示
- PyTorch运算的基本单元,但并非是PyTorch中才有的概念
- 在基础数据定义和运算中会频繁用到张量
- 在PyTorch中支持GPU运算,自动求导等操作
创建tensor
import torch
x = torch.rand(4,3)
y = torch.zeros(4,3,dtype = torch.long)
z = torch.zero_(x)
x = torch.tensor([5,6])
print(x)
x = x.new_ones(4, 3, dtype=torch.double)
print(x)
x = torch.randn_like(x, dtype=torch.float)
print(x)
常见的构造Tensor方法:
函数 | 功能 |
---|
Tensor(sizes) | 基础构造函数 | tensor(data) | 类似于np.array | ones(size) | 全1 | zeros(size) | 全0 | eye(sizes) | 对角为1,其余为0 | arange(s,e,step) | 从s到e,步长为step | linspace(s,e,steps) | 从s到e,均匀分成step份 | rand/randn(sizes) | rand是[0,1)均匀分布;randn是服从N(0,1)的正态分布 | normal(mean,std) | 正态分布(均值为mean,标准差是std) | randperm(m) | 随机排列 |
张量的操作
print(x+y)
print(torch.add(x,y))
y.add_(x)
x = torch.randn(4, 4)
y = x.view(16)
z = x.view(-1, 8)
print(x.size(), y.size(), z.size())
torch.view() 返回的新tensor与源tensor共享内存(其实是同一个tensor),更改其中的一个,另外一个也会跟着改变。 为了使创建的张量和原始张量不共享内存,我们先用 clone() 创造一个张量副本然后再使用 torch.view()进行函数维度变换 。
- 取值操作
可以使用 .item() 来获得这个 value,而不获得其他性质
广播机制
当对两个形状不同的 Tensor 按元素运算时,可能会触发广播(broadcasting)机制:先适当复制元素使这两个 Tensor 形状相同后再按元素运算。
自动求导
- 所有神经网络的核心是autograd包,为张量上的所有操作提供了自动求导机制。
- torch.Tensor 是autograd包的核心类。如果设置它的属性 .requires_grad 为 True(默认为False),那么它将会追踪对于该张量的所有操作。
- 当完成计算后可以通过调用 .backward(),来自动计算所有的梯度。这个张量的所有梯度将会自动累加到.grad属性
from __future__ import print_function
import torch
x = torch.randn(3,3,requires_grad=True)
print(x.grad_fn)
y == x**2
y.backward(gradient=torch.randn(3,3))
z = y * y * 3
out = z.mean()
out.backward()
print(x.grad)
out2 = x.sum()
out2.backward()
print(x.grad)
out3 = x.sum()
x.grad.data.zero_()
out3.backward()
print(x.grad)
with torch.no_grad():
print((x**2).requires_grad)
x = torch.ones(1,requires_grad=True)
print(x.data)
print(x.data.requires_grad)
y = 2 * x
x.data *= 100
y.backward()
print(x.data)
print(x.grad)
并行计算简介
- CUDA是NVIDIA提供的GPU并行计算框架
- 在PyTorch使用 CUDA表示要开始要求我们的模型或者数据开始使用GPU了。
- .cuda() 时,其功能是让我们的模型或者数据从CPU迁移到GPU(0)当中,通过GPU开始计算。
- 数据在GPU和CPU之间进行传递时会比较耗时,应尽量避免数据的切换
- 当我们的服务器上有多个GPU,我们应该指明我们使用的GPU是哪一块,如果我们不设置的话,tensor.cuda()方法会默认将tensor保存到第一块GPU上,等价于tensor.cuda(0),这将会导致爆出out of memory的错误。我们可以通过以下两种方式继续设置。
import os
os.environ["CUDA_VISIBLE_DEVICE"] = "2"
CUDA_VISBLE_DEVICE=0,1 python train.py
常见的并行方法
- 网络结构分布到不同的设备中(Network partitioning):将模型的各个部分拆分,将不同的部分放入到GPU来做不同任务的计算。但是GPU之间的通信在这种密集任务中很难办到,所以这个方式慢慢淡出了视野
- 同一层的任务分布到不同数据中(Layer-wise partitioning):同一层的模型做一个拆分,让不同的GPU去训练同一层模型的部分任务。但是在我们需要大量的训练,同步任务加重的情况下,会出现和第一种方式一样的问题。
- 不同的数据分布到不同的设备中,执行相同的任务(Data parallelism):同一个模型在不同GPU中训练一部分数据,然后再分别计算一部分数据之后,只需要将输出的数据做一个汇总,然后再反传。
PyTorch的主要组成模块
深度学习中训练和验证过程最大的特点在于读入数据是按批的,每次读入一个批次的数据,放入GPU中训练,然后将损失函数反向传播回网络最前面的层,同时使用优化器调整网络参数。这里会涉及到各个模块配合的问题。训练/验证后还需要根据设定好的指标计算模型表现。
参数设置
batch_size = 16
lr = 1e-4
max_epochs = 100
GPU的设置有两种常见的方式:
os.environ['CUDA_VISIBLE_DEVICES'] = '0,1'
device = torch.device("cuda:1" if torch.cuda.is_available() else "cpu")
数据读入
PyTorch数据读入是通过Dataset(定义好数据的格式和数据变换形式)+DataLoader(用iterative的方式不断读入批次数据)的方式完成的 主要包含三个函数:
构建Dataset类的方式:
import torch
from torchvision import datasets
train_data = datasets.ImageFolder(train_path, transform=data_transform)
val_data = datasets.ImageFolder(val_path, transform=data_transform)
需要自己来定义Dataset类:
class MyDataset(Dataset):
def __init__(self, data_dir, info_csv, image_list, transform=None):
"""
Args:
data_dir: path to image directory.
info_csv: path to the csv file containing image indexes
with corresponding labels.
image_list: path to the txt file contains image names to training/validation set
transform: optional transform to be applied on a sample.
"""
label_info = pd.read_csv(info_csv)
image_file = open(image_list).readlines()
self.data_dir = data_dir
self.image_file = image_file
self.label_info = label_info
self.transform = transform
def __getitem__(self, index):
"""
Args:
index: the index of item
Returns:
image and its labels
"""
image_name = self.image_file[index].strip('\n')
raw_label = self.label_info.loc[self.label_info['Image_index'] == image_name]
label = raw_label.iloc[:,0]
image_name = os.path.join(self.data_dir, image_name)
image = Image.open(image_name).convert('RGB')
if self.transform is not None:
image = self.transform(image)
return image, label
def __len__(self):
return len(self.image_file)
构建好Dataset后,就可以使用DataLoader来按批次读入数据了:
from torch.utils.data import DataLoader
train_loader = torch.utils.data.DataLoader(train_data, batch_size=batch_size, num_workers=4, shuffle=True, drop_last=True)
val_loader = torch.utils.data.DataLoader(val_data, batch_size=batch_size, num_workers=4, shuffle=False)
PyTorch中的DataLoader的读取可以使用next和iter来完成:
import matplotlib.pyplot as plt
images, labels = next(iter(val_loader))
print(images.shape)
plt.imshow(images[0].transpose(1,2,0))
plt.show()
模型构建
构造多层感知机:
import torch
from torch import nn
class MLP(nn.Module):
def __init__(self, **kwargs):
super(MLP, self).__init__(**kwargs)
self.hidden = nn.Linear(784, 256)
self.act = nn.ReLU()
self.output = nn.Linear(256,10)
def forward(self, x):
o = self.act(self.hidden(x))
return self.output(o)
|