Pytorch介绍以及基本使用深入了解案例分析。
Posted ㄣ知冷煖★
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Pytorch介绍以及基本使用深入了解案例分析。相关的知识,希望对你有一定的参考价值。
目录
- 前言
- 一、为什么选择Pytorch
- 二、Pytorch的基本使用
- 三、深入了解Pytorch
- 四、数据读取机制Dataloader与Dataset
- 五、数据预处理transforms模块机制
- 六、如何使用CIFAR10数据集
- 总结
前言
Pytorch是torch的python版本,是由Facebook开源的神经网络框架,专门针对 GPU 加速的深度神经网络(DNN)编程,相比于Tensorflow,Pytorch简介易用。一、为什么选择Pytorch
简洁:PyTorch的设计追求最少的封装,尽量避免重复造轮子。PyTorch的源码只有TensorFlow的十分之一左右,更少的抽象、更直观的设计使得PyTorch的源码十分易于阅读。
速度:PyTorch 的灵活性不以速度为代价,在许多评测中,PyTorch 的速度表现胜过 TensorFlow和Keras 等框架。
易用:PyTorch 是所有的框架中面向对象设计的最优雅的一个。PyTorch的面向对象的接口设计来源于Torch,而Torch的接口设计以灵活易用而著称。
生态丰富:PyTorch 提供了完整的文档,循序渐进的指南,此外 ,相关社区还在逐渐壮大。
二、Pytorch的基本使用
2-0、张量的定义
张量:张量是一种特殊的数据结构,与Numpy中的arrays非常相似,在Pytorch中,我们使用张量对模型的输入和输出以及模型的参数进行编码。最重要的是,数据转化为张量可以方便在GPU上运行,这样运行速度可以大大加快。
注意:Tensors和Numpy中的数组具有底层内存共享,意味着不需要进行复制直接就可以相互转化。
2-1、直接创建张量
2-1-1、torch.Tensor()
import torch
torch.Tensor([1, 2, 3])
# 涉及到的参数
# data:data的数据类型可以是列表list、元组tuple、numpy数组ndarray、纯量scalar(又叫标量)和其他的一些数据类型。
# dtype:该参数可选参数,默认为None,如果不进行设置,生成的Tensor数据类型会拷贝data中传入的参数的数据类型,比如data中的数据类型为float,则默认会生成数据类型为torch.FloatTensor的Tensor。
# device:该参数可选参数,默认为None,如果不进行设置,会在当前的设备上为生成的Tensor分配内存。
# requires_grad:该参数为可选参数,默认为False,在为False的情况下,创建的Tensor不能进行梯度运算,改为True时,则可以计算梯度。
# pin_memory:该参数为可选参数,默认为False,如果设置为True,则在固定内存中分配当前Tensor,不过只适用于CPU中的Tensor。
输出:
2-1-2、torch.from_numpy()
# notice: 当然我们也可以直接将numpy数组直接转化为Tensor
import torch
import numpy as np
t1 = [1, 2, 3]
np_array = np.array(t1)
data = torch.from_numpy(np_array)
print(data)
输出:
2-2、创建数值张量
2-2-1、torch.ones()
# 创建全1张量。
torch.ones((2,4))
输出:
2-2-2、torch.full()
torch.full([2,3],2.0)
参数:
# size: 定义了输出张量的形状。
# full_value: 定义填充的值。
输出:
2-2-3、torch.arange()
# 创建等差数列
torch.arange(0, 10, 2)
参数:
start: 等差数列开始。
end: 等差数列结束。
steps: 等差数列的差是多少。
输出:
2-2-4、torch.linespace()
# 创建线性间距向量
torch.linspace(2, 10, 5)
# 参数:
# start: 起始位置
# end: 结束位置
# steps: 步长
# out: 结果张量
输出:
2-2-5、torch.eye()
# 创建对角矩阵
# 即生成对角线全为1,其余部分全为0的二维数组
torch.eye(10,3)
# 参数:
# n: 行数
# m: 列数
# out: 输出类型,即输出到哪个矩阵。
输出:
2-3、根据概率创建张量
2-3-1、torch.randn()
# 创建随机值
# 与rand不同的是,它创建的是包含了从标准正态分布(均值为0,方差为1)中取出的一组随机值。
torch.randn(4)
# 参数
# size: 定义了输出张量的形状
# out: 结果张量
输出:
2-3-2、torch.randint()
# 返回一个填充了随机整数的张量,这些整数在low和high之间均匀生成。张量的shape由参数size定义。
torch.randint(100,size=(10,10))
# 参数说明:
# 常用参数:
# low ( int , optional ) – 要从分布中提取的最小整数。默认值:0。
# high ( int ) – 高于要从分布中提取的最高整数。
# size ( tuple ) – 定义输出张量形状的元组。
# 关键字参数:
# generator ( torch.Generator, optional) – 用于采样的伪随机数生成器
# out ( Tensor , optional ) – 输出张量。
# dtype ( torch.dtype , optional) – 如果是None,这个函数返回一个带有 dtype 的张量torch.int64。
# layout ( torch.layout, optional) – 返回张量的所需布局。默认值:torch.strided。
# device ( torch.device, optional) – 返回张量的所需设备。默认值:如果None,则使用当前设备作为默认张量类型(请参阅torch.set_default_tensor_type())。device将是 CPU 张量类型的 CPU 和 CUDA 张量类型的当前 CUDA 设备。
# requires_grad ( bool , optional ) – 如果 autograd 应该在返回的张量上记录操作。默认值:False。
输出:
2-3-3、torch.rand()
# 创建随机值,包含了从区间(0,1)的均匀分布中抽取的一组随机数
# 均匀分布
# torch.rand(*sizes, out=None)
torch.rand(4)
输出:
2-3-4、torch.normal()
torch.normal: 生成正态分布
四种模式:
1、mean为标量,std为标量。
2、mean为标量,std为张量。
3、mean为张量,std为标量。
4、mean为张量,std为张量。
# mean为标量,std为标量,这种模式必须加size参数
torch.normal(0, 1, size=(4,5))
输出:
2-4、张量的一些运算操作:拼接、切分索引变换
2-4-0、判断电脑是否有GPU
# 如果没有这一步可以直接略过
# 判断当前环境GPU是否可用, 然后将tensor导入GPU内运行
if torch.cuda.is_available():
tensor = tensor.to('cuda')
2-4-1、torch.ones_like函数和torch.zeros_like函数
input = torch.rand(4, 6)
print(input)
# 生成与input形状相同、元素全为1的张量
a = torch.ones_like(input)
print(a)
# 生成与input形状相同、元素全为0的张量
b = torch.zeros_like(input)
print(b)
输出:
2-4-2、torch.cat函数
# 生成一个两行三列的全1张量。
t = torch.ones((2,3))
# 拼接函数cat
# 在给定维度上对输入的张量进行连接操作
torch.cat([t,t], dim=0)
# 参数
# inputs : 待连接的张量序列,可以是任意相同Tensor类型的python 序列
# dim : 选择的扩维, 必须在0到len(inputs[0])之间,沿着此维连接张量序列。
输出:
tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]])
2-4-3、torch.stack函数
# 拼接函数stack
# 与cat不同的是,stack会增加维度。 简单来说就是增加新的维度进行堆叠。
# 扩维拼接!
torch.stack([t,t], dim=1)
# 参数
# inputs : 待连接的张量序列,可以是任意相同Tensor类型的python 序列
# dim : 选择的扩维, 必须在0到len(inputs[0])之间,沿着此维连接张量序列。
输出:
2-4-4、torch.chunk函数
t = torch.ones((2,5))
# 在给定维度上将输入张量进行分块
torch.chunk(t, dim=1, chunks=5)
# input:被分块的张量。
# chunks:要切的份数。
# dim:在哪个维度上切分。
输出:
2-4-5、torch.split函数
# 将tensor分成块结构
torch.split(t, [1,1,3], dim=1)
# input:待输入张量
# split_size_or_sections: 需要切分的大小,可以为列表或者数字。
# dim:切分维度
输出:
2-4-6、torch.squeeze函数
# 返回一个删除了所有大小为1的输入维度的张量。
# 例如:如果输入为(A✖B✖1✖C),则输出张量为(A✖B✖C)
# input: 输入张量
# dim: 如果给定,则输入只会在这个维度上挤压。
2-4-7、自动赋值运算
# 自动赋值运算通常在方法后有 _ 作为后缀, 例如: x.copy_(y), x.t_()操作会改变 x 的取值。
print(tensor, "\\n")
tensor.add_(5)
print(tensor)
2-5、其他常用函数
2-5-1、torch.manual_seed
# 设置生成随机数的种子
# 为了使得结果可以复现。
# 参数:seed,设置的种子。
三、深入了解Pytorch
3-0、训练神经网络
背景:神经网络(NN:Neutral NetWork)是在某些输入数据上执行的嵌套函数的集合。 这些函数由参数(由权重和偏差组成)定义,这些参数在 PyTorch 中存储在张量中。
训练 NN 分为两个步骤:
正向传播:在正向传播中,NN 对正确的输出进行最佳猜测。 它通过其每个函数运行输入数据以进行猜测。即通过模型的每一层运行输入数据以进行预测。 这是正向传播。
反向传播:在反向传播中,NN 根据其猜测中的误差调整其参数。 它通过从输出向后遍历,收集有关函数参数(梯度)的误差导数并使用梯度下降来优化参数来实现。
3-1、叶子节点
叶子节点:用户创建的节点被称之为叶子节点。(即Tensor有一个属性,叫is_leaf。) 所以可以Tensor调用is_leaf属性来判断是否为叶子节点,只有叶子节点才有梯度。非叶子节点的梯度在运行后会被直接释放掉。依赖于叶子节点的节点 requires_grad默认为True。
requires_grad:即是否需要计算梯度,当这个值为True时,我们将会记录tensor的运算过程并为自动求导做准备。,但是并不是每个requires_grad()设为True的值都会在backward的时候得到相应的grad.它还必须为leaf。只有是叶子张量的tensor在反向传播时才会将本身的grad传入到backward的运算中,如果想得到其他tensor在反向传播时的grad,可以使用retain_grad()这个属性。
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()
print(a.requires_grad, b.requires_grad, y.requires_grad)
# True True True
# last 计算w的梯度
w.grad
# tensor([5.])
计算图:
3-2、动态图与静态图
1、动态图:运算与搭建同时进行,容易调节。 Pytorch采用动态图机制。
2、静态图:先搭建图,后运算,高效,但是不灵活。 Tensorflow采用静态图机制。
3-3、自动求梯度(autograd)
前言:神经网络通常依赖反向传播求梯度来更新网络参数,深度学习框架可以帮助我们自动地完成这种梯度运算。 Pytorch一般通过反向传播方法backward来实现梯度计算。除此以外,也可以调用torch.autograd.grad函数来实现梯度计算。
注意:backward方法通常在一个标量张量上调用,该方法求得的梯度将存在对应自变量张量的grad属性下。如果调用的张量非标量,则要传入一个和它同形状的gradient参数张量。相当于用该gradient参数张量与调用张量作向量点乘,得到的标量结果再反向传播。
案例一: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()
print(a.requires_grad, b.requires_grad, y.requires_grad)
# True True True
# last 计算w的梯度
w.grad
# tensor([5.])
案例二:backward方法在非标量的反向传播
# 如果调用的张量非标量,则要传入一个和它同形状的gradient参数张量。相当于用该gradient参数张量与调用张量作向量点乘,得到的标量结果再反向传播。
import numpy as np
import torch
# f(x) = a*x**2 + b*x + c
x = torch.tensor([[0.0,0.0],[1.0,2.0]],requires_grad = True) # x需要被求导
a = torch.tensor(1.0)
b = torch.tensor(-2.0)
c = torch.tensor(1.0)
y = a*torch.pow(x,2) + b*x + c
gradient = torch.tensor([[1.0,1.0],[1.0,1.0]])
print("x:",x)
print("y:",y)
y.backward(gradient = gradient)
x_grad = x.grad
print("x_grad:",x_grad)
输出:
x: tensor([[0., 0.],
[1., 2.]], requires_grad=True)
y: tensor([[1., 1.],
[0., 1.]], grad_fn=)
x_grad: tensor([[-2., -2.],
[ 0., 2.]])
案例三:使用autograd.grad方法来求导数。
torch.autograd.backward: 求梯度。
参数:
outputs:用于求导的张量
inputs:需要梯度的张量
create_graph: 创建导数计算图,用于高阶求导
retain_graph: 保存计算图
grad_outputs: 多梯度权重
import numpy as np
import torch
# f(x) = a*x**2 + b*x + c的导数
x = torch.tensor(0.0,requires_grad = True) # x需要被求导
a = torch.tensor(1.0)
b = torch.tensor(-2.0)
c = torch.tensor(1.0)
y = a*torch.pow(x,2) + b*x + c
# create_graph 设置为 True 将允许创建更高阶的导数
dy_dx = torch.autograd.grad(y,x,create_graph=True)[0]
print(dy_dx.data)
# 求二阶导数
dy2_dx2 = torch.autograd.grad(dy_dx,x)[0]
print(dy2_dx2.data)
输出:
tensor(-2.)
tensor(2.)
3-4、前向传播、损失和反向传播(Numpy实现)
# 为了加深对于前向传播、损失和反向传播的理解,我们使用Numpy来实现这个流程
import numpy as np
import math
# Create random input and output data
# 用于在线性空间中以均匀步长生成数字序列。
x = np.linspace(-math.pi, math.pi, 2000)
y = np.sin(x)
# 随机初始化权重
# Randomly initialize weights
a = np.random.randn()
b = np.random.randn()
c = np.random.randn()
d = np.random.randn()
# 学习率设置为1e-6
learning_rate = 1e-6
for t in range(5000):
# Forward pass: compute predicted y
# y = a + b x + c x^2 + d x^3
# 预测函数,结果呢,就是得到a、b、c、d四个值使得预测值y_pred尽可能接近y
y_pred = a + b * x + c * x ** 2 + d * x ** 3
# Compute and print loss
# 损失函数,就是预测值减去真实值求和,再开方。
loss = np.square(y_pred - y).sum()
# 每100次,输出轮次和损失
if t % 100 == 99:
print(t, loss)
# Backprop to compute gradients of a, b, c, d with respect to loss
grad_y_pred = 2.0 * (y_pred - y)
# 分别计算a、b、c、d的梯度。
grad_a = grad_y_pred.sum()
grad_b = (grad_y_pred * x).sum()
grad_c = (grad_y_pred * x ** 2).sum()
grad_d = (grad_y_pred * x ** 3).sum()
# Update weights
# 更新a、b、c、d四个参数
a -= learning_rate * grad_a
b -= learning_rate * grad_b
c -= learning_rate * grad_c
d -= learning_rate * grad_d
print(f'Result: y = a + b x + c x^2 + d x^3')
3-5、前向传播、损失和反向传播(Pytorch实现)
import torch
import math
dtype = torch.float
device = torch.device("cpu")
# device = torch.device("cuda:0") # Uncomment this to run on GPU
# Create random input and output data
x = torch.linspace(-math深入了解Redis源码下载与参考资料准备
引言
一直在使用redis,但是却没有系统的了解过它的底层实现,准备边学习边记录,深入了解redis。
打算分析以下几个方面:
- redis的基本类型及底层原理与java对比,每种数据类型的使用场景
- redis底层对象
- key的一致性Hash算法
- 单线程的redis“快”
- redis的过期策略以及内存淘汰机制
- redis分布式锁原理
- redis备份方式
- 多机环境下主从赋值、哨兵、集群的优缺点
- 哨兵机制与选举算法
- 集群机制的分片原理
- 缓存的key并发竞争问题
- 缓存和数据库双写一致性问题
- 缓存雪崩问题
- 缓存击穿问题
这只是暂时列举出来,最后有可能删减。
前期准备:
带注释的源码
参考资料
《Redis设计与实现》PDF
关注下方公众号,回复redis
索要。
Redis 源码日志
参考的博客文章将在每一篇文章下方给出。
以上是关于Pytorch介绍以及基本使用深入了解案例分析。的主要内容,如果未能解决你的问题,请参考以下文章
深入浅出Spring原理及实战「开发实战系列」SpringSecurity原理以及实战认证分析开发指南
翻译: 3.线性神经网络 概览 深入神经网络 pytorch