Pytorch
- 张量
- 直接张量创建
- 依据数值创建
- 依据概率创建
- 拼接
- 切分
- 索引
- 变换
- 四则运算
- 自动求导
- 数据
- 如何读取你自己的数据集?
- 如何图像数据预处理及数据增强?
- 模型
- 如何构建神经网络?
- 如何初始化参数?
- 损失函数
- 如何选择损失函数?
- 如何设置损失函数?
- 优化器
- 如何管理参数?
- 如何调整学习率?
- 迭代过程:如何观察训练效果?
- 应用
- 如何进行图像分类?
- 如何进行图像分割?
- 如何进行目标检测?
- 如何进行对抗生成?
张量
张量参数:
import torch
torch.Tensor([1, 2, 3])
# data:data的数据类型可以是列表list、元组tuple、numpy数组ndarray、纯量scalar(又叫标量)和其他的一些数据类型。
# dtype:该参数可选参数,默认为None,如果不进行设置,生成的Tensor数据类型会拷贝data中传入的参数的数据类型,比如data中的数据类型为float,则默认会生成数据类型为torch.FloatTensor的Tensor。
# shape:张量形状
# device:所在设备 cuda or cpu,默认为None,如果不进行设置,会在当前的设备上为生成的Tensor分配内存。
# requires_grad:是否需要梯度,默认为False,在为False的情况下,创建的Tensor不能进行梯度运算,改为True时,则可以计算梯度。
# grad:张量的梯度
# grad_fn:自动求导
# pin_memory:该参数为可选参数,默认为False,如果设置为True,则在固定内存中分配当前Tensor,不过只适用于CPU中的Tensor。
# is_leaf:是否是叶子结点
直接张量创建
torch.tensor(
data, # 数据 list or numpy
dtype=None, # 数据类型
device=None, # 所在设备 cuda or cpu
requires_grad=False, # 是否需要梯度
pin_memory=False # 是否存在锁页内存
)
依据数值创建
torch.full(
*size # 张量的形状 (5,5,5)
fill_value, # 全这个值
out=None, # 输出的张量
dtype=None,
layout=strided, # 内存中布局形式
device=None,
requires_grad=False
)
依据概率创建
torch.normal( # 生成正态分布
mean, # 均值
std, # 标准差
out=None
)
torch.randn( # 生成标准正态分布(均值为0,标准差为1)
*size, # 张量的形状 (5,5,5)
out=None,
dtype=None,
layout=torch.strided,
device=None,
requires_grad=False
)
拼接
torch.cat( # 将张量按照维度dim拼接
tensors, # 张量序列
dim=0 # 拼接维度 dim=0对行进行拼接、dim=1对列进行拼接
out=None
)
切分
torch.split( # 将张量按照维度dim切分
tensor,
split_size_or_sections, # 为int时,表示每一份长度;为list时,按元素分
dim
)
索引
tourch.index_select( # 在维度dim上,按index索引数据
input,
dim,
index,
out=None
)
变换
torch.reshape(
input, # 要变换的张量
shape # 新张量的形状
)
案例:https://www.fke6.com/html/72608.html
四则运算
自动求导
torch.autograd.backward( # 自动求取梯度
tensors,
grad_tensors=None, # 多梯度权重
retain_graph=None, # 保存计算图
create_graph=False # 创建计算图
)
案例:
神经网络通常依赖反向传播求梯度来更新网络参数,Pytorch 的 backward 能自动计算。
w = torch.tensor([1.], requires_grad=True)
x = torch.tensor([2.], requires_grad=True)
a = torch.add(w, x)
b = torch.add(w, 1)
y = torch.mul(a, b)
y.backward()
数据
如何读取你自己的数据集?
PyTorch读取图片,主要是通过Dataset类。
因为Dataset是抽象类,所以继承需要重写三个方法。
class Dataset(object):
def __getitem__(self, index):
# index是图片数据索引(list类型),每个元素包含图片的路径和标签信息。返回图片数据和标签
raise NotImplementedError
def __len__(self):
raise NotImplementedError
def __add__(self, other):
return ConcatDataset([self, other])
读取自己数据的基本流程就是:
- 构建的 Dataset 子类
- 读取存储 图片的路径和标签信息 的 txt
- 将这些信息转化为list,该 list 每一个元素对应一个样本
- 通过 getitem 函数,读取数据和标签,并返回数据和标签
from PIL import Image
from torch.utils.data import Dataset
class Dataset_s(Dataset): # 我们写的读取子类继承父类方法
def __init__(self, txt_path, transform = None, target_transform = None):
fh = open(txt_path, 'r') # 读取-存储图片的路径和标签信息的txt
imgs = []
for line in fh: # 按行读取
line = line.rstrip() # 字符串末尾的空格会被删除
words = line.split() # 以空格为分隔符
imgs.append((words[0], int(words[1]))) # 列表存储图片路径、标签信息
self.imgs = imgs # 初始化赋值 图片路径、标签信息
self.transform = transform # 用于图像数据增强
self.target_transform = target_transform
def __getitem__(self, index):
fn, label = self.imgs[index] # 分别保存 图片路径、标签信息
img = Image.open(fn).convert('L') # 利用Image.open对图片进行读取,img类型为 Image,mode=‘L’、L是灰度图像
if self.transform is not None:
img = self.transform(img) # 对图片进行处理,这个transform里边可以实现加减均值,除标准差,随机裁剪,旋转,翻转,放射变换等操作
return img, label
def __len__(self):
return len(self.imgs)
在项目中数据量很大,内存有限制就不能一次性读入。
也不能用一个进程读入,多进程读入。
DataLoader 有多次读入、多进程读入、数据打乱的迭代器。
DataLoader(dataset, batch_size=1, shuffle=False, sampler=None, num_workers=0, collate_fn=default_collate, pin_memory=False, drop_last=False)
# dataset:加载的数据集(Dataset对象)
# batch_size:一个批量数目大小
# shuffle::是否打乱数据顺序
# sampler: 样本抽样方式
# num_workers:使用多进程加载的进程数,0代表不使用多进程
# collate_fn: 将多个样本数据组成一个batch的方式,一般使用默认的拼接方式,可以通过自定义这个函数来完成一些特殊的读取逻辑
# pin_memory:是否将数据保存在pin memory区,pin memory中的数据转到GPU会快一些
# drop_last:为True时,dataset中的数据个数不是batch_size整数倍时,将多出来不足一个batch的数据丢弃
使用DataLoader批量读取数据:
from torch.utils.data import DataLoader
# 训练数据加载
train_loader = DataLoader(dataset=train_dataset, # 加载的数据集(Dataset对象)
batch_size=3, # 一个批量大小
shuffle=True, # 是否打乱数据顺序
num_workers=4) # 使用多进程加载的进程数,0代表不使用多进程(win系统建议0)
# 测试数据加载
test_loader = DataLoader(dataset=test_dataset,
batch_size=3,
shuffle=True,
num_workers=4)
如何图像数据预处理及数据增强?
产生不同但类似的图片,多做一点模拟题目,有助于提高学习效果。
常见的图像预处理方法:数据中心化、数据标准化、缩放、剪裁、旋转、翻转、填充、噪声添加、灰度变换、线性变换、仿射变换、亮度/饱和度/对比度变换。
transforms.RandomCrop( # 从图片中随机裁剪出尺寸为 size 的图片
size, # 所需裁剪图片尺寸
padding=None, # 设置填充大小
pad_if_needed=False, # 若图像小于size,则填充
fill=0, # 设置填充像素值
padding_mode='constant' # 填充模型有4种,这是像素值填充
)
transforms.RandomResizedCrop( # 随机大小、长宽比裁剪图片
size, # 所需裁剪图片尺寸
scale=(0.08, 1.0), # 随机裁剪面积比例
ratio=(0.75, 1.3333333333333333), # 随机长宽比
interpolation=2 # 插值方法
)
具体案例,请猛击:
- 二十二个方法参数说明
- 图像预处理 transforms 的二十二个方法案例
数据裁剪(Crop):
- transforms.CentorCrop - 中心裁剪
- transforms.RandomCrop - 随机裁剪
- RandomResizedCrop - 随机长宽比裁剪
- FiveCrop - 上下左右中心裁剪
- TenCrop - 上下左右中心裁剪后翻转
翻转和旋转(Flip and Rotation):
- RandomHorizontalFlip - 依概率p水平翻转
- RandomVerticalFlip - 依概率p垂直翻转
- RandomRotation - 随机旋转
图像变换(resize):
- pad - 填充
- ColorJitter - 修改亮度、对比度和饱和度
- Greyscale - 转灰度图
- RandomGreyscale - 依概率p转为灰度图
- RandomAffine - 仿射变换
- ······
具体使用哪些方法呢?
数据增强方向:让训练集逼近测试集分布。
先进行数据标准化,因为卷积神经网络是根据像素值提取特征的,如果一张图所有像素值都-50,那就分不清了。而数据标准化后,会把数据映射到同一区间,变成类似的分布。
再从多个角度观察俩者的差异:空间位置、色彩、形状、上下文场景等,根据差异调整数据。
模型
如何构建神经网络?
net = LeNet( classes = 2 ) # 调用 LeNet 网络
以 LeNet 网络为例:这可能是神经网络 LeNet-5 最详细的解释了
这是 LeNet 网络结构:
这是 LeNet 网络实现:
import torch.nn as nn
import torch.nn.functional as F
class LeNet(nn.Module): # 继承nn.Module
def __init__(self):
super(LeNet, self).__init__() # 调用父类函数的__init__()
self.conv1 = nn.Conv2d(3, 16, 5) # 3通道的输入,16卷积核,5x5的卷积核
self.pool1 = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(16, 32, 5)
self.pool2 = nn.MaxPool2d(2, 2)
self.fc1 = nn.Linear(32*5*5, 120)
self.fc2 = nn.Linear(120, 84)
self.fc3 = nn.Linear(84, 10) # 用的CIFAR10数据集
def forward(self, x): # 正向传播的过程
x = F.relu(self.conv1(x)) # input(3, 32, 32) output(16, 28, 28)
x = self.pool1(x) # output(16, 14, 14)
x = F.relu(self.conv2(x)) # output(32, 10, 10)
x = self.pool2(x) # output(32, 5, 5)
x = x.view(-1, 32*5*5) # output(32*5*5) View函数展平操作,-1代表纬度,自动推理纬度,32*5*5展平后节点个数
x = F.relu(self.fc1(x)) # output(120)
x = F.relu(self.fc2(x)) # output(84)
x = self.fc3(x) # output(10) 最后一层,这里不需要添加softmax层了,train.py在卷网络中,在卷积交叉熵中nn.CrossEntropyLoss(),他的内部实现了分类的功能
return x
一个模型从计算图角度,分为结点、边。
- 结点:张量、网络层 -> 在 LeNet 网络中实现
- 边:卷积运算 -> 在 forward() 中实现
完整网络流程请猛击:Pytorch VGG模型完整使用。
这篇文章多了一个知识点:这个网络会分成两部分包装,特征提取器和分类器。
- 特征提取器:Conv1 -> pool1 -> Conv2 -> pool2(卷积和池化层)
- 分类器:fc1 -> fc2 -> fc3(全链接层)
如何初始化参数?
net.initialize_weights() # 权值初始化
正确的权重初始化加速模型收敛,反之引发梯度消失、爆炸。
为了防止梯度消失、爆炸,我们需要保证每层的值不太大也不太小。
让每个网络层的输出值的方差在 1 附近。
请猛击:pytorch十种初始化方法。
损失函数
如何选择损失函数?
没有一个损失函数可以适用于所有类型的数据损失函数的选择取决于许多因素,包括是否有离群点,机器学习算法的选择,运行梯度下降的时间效率,是否易于找到函数的导数,以及预测结果的置信度。
损失函数大致分为:
- 分类损失函数(预测标签):对数损失函数、焦点损失函数、合页损失函数、指数损失、交叉熵损失函数
- 回归损失函数(预测值):均方误差、平均绝对误差、平滑的平均绝对误差、回归损失函数、分位数损失函数
如何设置损失函数?
优化器
如何管理参数?
如何调整学习率?
迭代过程:如何观察训练效果?
应用
如何进行图像分类?
如何进行图像分割?
如何进行目标检测?
如何进行对抗生成?