#2 上传文件至 'thorough-pytorch/study-notes'

Merged
thomas-yanxin merged 1 commits from zby/pytorch_note:master into master 1 year ago
  1. +335
    -0
      thorough-pytorch/study-notes/thorough-pytorch-第二三章-zby.md

+ 335
- 0
thorough-pytorch/study-notes/thorough-pytorch-第二三章-zby.md View File

@@ -0,0 +1,335 @@
# pytorch学习笔记

来自datawhale的深入浅出pytorch教程的笔记。主要对第二章和第三章的常用函数和方法进行梳理,方便要用的时候查找和复习,同时巩固对pytorch实现深度学习基本流程的认识。
**教程链接:** [深入浅出pytorch](https://datawhalechina.github.io/thorough-pytorch/index.html)

### 第二章:pytorch基础知识

#### 2.1张量

1. 生成tensor

| 函数 | 功能 |
| ------------------- | ---------------------------------- |
| Tensor(sizes) | 基础构造函数 |
| tensor(data) | 类似于np.array |
| ones(sizes) | 全1 |
| zeros(sizes) | 全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) | 随机排列 |
| 2. 加法 | |

1. x+y
2. x.add_(y)
3. torch.add(x,y)

3. 索引:类似numpy,如x[3:5,:]

4. x.view(-1,3):改变形状,填-1表示由其他维度决定,view只改变观察角度不改tensor本身

5. y=x.clone():复制x,二者内存独立

6. x.item():x 的数值,不涉及其他性质

7. 广播机制:两个形状不同的tensor按元素计算(如加法)时会先适当复制元素使这两个 Tensor 形状相同后再按元素运算。

#### 2.2自动求导

- requires_grad:布尔值,在创建张量时设置,表示是否计算梯度,若训练需要用到梯度为true,某些情况例如评估时为false。

- grad_fn:布尔值。将y看作x的函数。这样创建的张量的grad_fn为true,如果是赋值给自身则为false。

- out.backward():对out反向传播,对于标量out.backward()和 out.backward(torch.tensor(1.)) 等价,对于张量必须在括号内传入一个张量。每次传播梯度都会叠加

- x.grad:x的梯度,返回的也是一个tensor对象

- x.data:x的值,对x.data的操作会影响x的值但不影响梯度计算

- x.grad.data.zero_():令梯度为0,防止梯度的累加

- with torch.no_grad()::其后面的代码不会跟踪梯度的变化

一个例子

```python
import torch
x = torch.ones(2, 2, requires_grad=True)
print(x)
y = x**2
print(y)
print(y.grad_fn)
z = y * y * 3
out = z.mean()
print(z, out)
out.backward()
print(x.grad)
```

最后一项输出为tensor([[3., 3.], [3., 3.]])

----------

### 第三章:pytorch主要组成模块

#### 3.2基本配置

必须导入的包

```python
import os
import numpy as np
import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader
import torch.optim as optimizer
```

一些基础配置

- batch size

- 初始学习率(初始)

- 训练次数(max_epochs)

- GPU配置
```python
batch_size = 16
# 批次的大小
lr = 1e-4
# 优化器的学习率
max_epochs = 100
```

GPU的设置有两种常见的方式:

```python
# 方案一:使用os.environ,这种情况如果使用GPU不需要设置
os.environ['CUDA_VISIBLE_DEVICES'] = '0,1'
方案二:使用“device”,后续对要使用GPU的变量用.to(device)即可
device = torch.device("cuda:1" if torch.cuda.is_available() else "cpu")
```

我们可以定义自己的Dataset类来实现灵活的数据读取,定义的类需要继承PyTorch自身的Dataset类。主要包含三个函数:

- __init__: 用于向类中传入外部参数,同时定义样本集

- __getitem__: 用于逐个读取样本集合中的元素,可以进行一定的变换,并将返回训练/验证所需的数据

- __len__: 用于返回数据集的样本数
```python
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)
```

#### 3.3数据读入

构建好Dataset后,就可以使用DataLoader来按批次读入数据了,实现代码如下:

```python
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)
```

其中:

- batch_size:样本是按“批”读入的,batch_size就是每次读入的样本数

- num_workers:有多少个进程用于读取数据

- shuffle:是否将读入的数据打乱

- drop_last:对于样本最后一部分没有达到批次数的样本,使其不再参与训练

#### 3.4模型构建

定义MLP类:_init_:用于初始化和定义前向计算的基础函数(如全连接层,relu);forward:调用_init_中的函数形成前向计算函数,无需定义backward,系统会自动计算。类的输入可以是模型的任意一个组件。
神经网络的层可分为有参数与无参数两种,无参数例如标准化,有参数的有多种,包括:

- 二维卷积层:Conv2D,参数有输入通道数in_channels,输出通道数out_channels,卷积核宽度kernel_size,卷积核长宽不一致的填充数字padding

- 池化层:pool2d,参数有池化层边长pool_size,和池化方式mode
一个神经网络的典型训练过程如下:
1. 定义包含一些可学习参数(或者叫权重)的神经网络
2. 在输入数据集上迭代
3. 通过网络处理输入
4. 计算 loss (输出和正确答案的距离)
5. 将梯度反向传播给网络的参数
6. 更新网络的权重,一般使用一个简单的规则:weight = weight - learning_rate * gradient(梯度下降)

使用torch.nn包来构建神经网络,nn包则依赖于autograd包来定义模型并对它们求导。一个nn.Module包含各个层和一个forward(input)方法,该方法返回output。

- torch.Tensor - 一个多维数组,支持诸如backward()等的自动求导操作,同时也保存了张量的梯度。

- nn.Module - 神经网络模块。是一种方便封装参数的方式,具有将参数移动到GPU、导出、加载等功能。

- nn.Parameter - 张量的一种,当它作为一个属性分配给一个Module时,它会被自动注册为一个参数。

- autograd.Function - 实现了自动求导前向和反向传播的定义,每个Tensor至少创建一个Function节点,该节点连接到创建Tensor的函数并对其历史进行编码。

- net.parameters() -网络的可学习参数

#### 3.5模型初始化

使用torch初始化conv和linear

```python
torch.nn.init.kaiming_normal_(conv.weight.data)
torch.nn.init.constant_(linear.weight.data,0.3)
```

#### 3.6损失函数

常用损失函数:

1. 二分类交叉熵损失函数
torch.nn.BCELoss(weight=None, size_average=None, reduce=None, reduction='mean')
- weight:每个类别的loss设置权值

- size_average:数据为bool,为True时,返回的loss为平均值;为False时,返回的各样本的loss之和。

- reduce:数据类型为bool,为True时,loss的返回是标量。
2. 交叉熵损失函数
torch.nn.CrossEntropyLoss(weight=None, size_average=None, ignore_index=-100, reduce=None, reduction='mean')
ignore_index:忽略某个类的损失函数。

3. L1损失函数
torch.nn.L1Loss(size_average=None, reduce=None, reduction='mean')
reduction参数决定了计算模式。有三种计算模式可选:none:逐个元素计算。 sum:所有元素求和,返回标量。 mean:加权平均,返回标量。 如果选择none,那么返回的结果是和输入元素相同尺寸的。默认计算方式是求平均。

4. MSE损失函数
torch.nn.MSELoss(size_average=None, reduce=None, reduction='mean')

5. 平滑L1 (Smooth L1)损失函数
torch.nn.SmoothL1Loss(size_average=None, reduce=None, reduction='mean', beta=1.0)

6. 二分类logistic损失函数
torch.nn.SoftMarginLoss(size_average=None, reduce=None, reduction='mean')

#### 3.7 训练与评估

切换模型的状态:

```python
model.train() # 训练状态
model.eval() # 验证/测试状态
```

一个完整的训练过程:
用for循环读取DataLoader中的全部数据。
for data, label in train_loader:

后将数据放到GPU上用于后续计算,此处以.cuda()为例
data, label = data.cuda(), label.cuda()

开始用当前批次数据做训练时,应当先将优化器的梯度置零:
optimizer.zero_grad()

之后将data送入模型中训练:
output = model(data)

根据预先定义的criterion计算损失函数:
loss = criterion(output, label)

将loss反向传播回网络:
loss.backward()

使用优化器更新模型参数:
optimizer.step()

#### 3.9 pytorch优化器

共十种,均来自pytorch.optim。先实例化再step一下即可更新参数。

```python
optimizer = torch.optim.SGD([weight], lr=0.1, momentum=0.9)
optimizer.step()
```

---

### 其他

#### 模型定义与修改

有三种方式定义模型:Sequential,ModuleList和ModuleDict,他们的方法大致相同。以Sequential为例:

```python
import torch.nn as nn
net = nn.Sequential(
nn.Linear(784, 256),
nn.ReLU(),
nn.Linear(256, 10),
)
print(net)
```

通过net.fc(某一模型层)=classifier(替换层)可以修改模型的某一层。

在forward函数里可以给模型增加输入输出

```python
def forward(self, x, add_variable):
x1000 = self.net(x)
x10 = self.dropout(self.relu(x1000))
x10 = self.fc1(x10)
x10 = self.output(x10)
return x10, x1000
```

#### 模型保存与读取

```python
# 保存+读取整个模型
torch.save(model, save_dir)
loaded_model = torch.load(save_dir)
loaded_model.cuda()
```

#### torchvision

torchvision包含了在计算机视觉中常常用到的数据集,模型和图像处理的方式。常用模块:

- torchvision.datasets 常见数据集
- torchvision.models 预训练模型
- torchvision.tramsforms 图像处理方法

Loading…
Cancel
Save