非常感谢,datawhale提供的课程资源:https://www.bilibili.com/video/BV1e341127Lt?p=2
以下是这个课程的笔记
一、tensor的属性:
type:float,long,
device的属性:用什么卡,比如CPU,GPU
requires_grad属性:是否支持求导
pin_memory属性:是否塞到内存里面,运算快,但是内存高
is_leaf:是否是叶子节点,不是就继续往前传,是就终止
创建tensor,用dtype指定类型。注意类型要匹配
> a = torch.tensor(1.0, dtype=torch.float)
> b = torch.tensor(1,dtype=torch.long)
> #这个int和1.0显然是不匹配的,最好不要这么写
> c = torch.tensor(1.0, dtype=torch.int8)
> print(a, b,c)
使用指定类型函数随机初始化指定大小的tensor
d = torch.FloatTensor(2,3)
e = torch.IntTensor(2)
#对于python已经定义好的数据结构可以直接转换.下面的这个是一个列表,
#list转成整型tensor.只是数据存储的格式变了,但实际还是个List
f = torch.IntTensor([1,2,3,4])
print(d, '\n', e, '\n', f)
tensor和numpy array之间的相互转换
import numpy as np
g = np.array([[1,2,3],[4,5,6]])
h = torch.tensor(g)
print(h)
i = torch.from_numpy(g)
print(i)
j = h.numpy()
print(j)
常见的构造Tensor的函数
k = torch.rand(2, 3)
l = torch.ones(2, 3)
m = torch.zeros(2, 3)
#arange就是一个步长之类的,起始点0,步骤2,终点10
#这里是1维的张量
n = torch.arange(0, 10, 2)
print(k, '\n', l, '\n', m, '\n', n)
查看tensor的维度信息(两种方式)
print(k.shape)
print(k.size())
tensor的运算
o = torch.add(k,l)
print(o)
tensor的索引方式与numpy类似
print(o[:,1])
print(o[0,:])
重要:改变tensor形状的神器:view
#就是想看3行两列,怎么排列的呢,就是o矩阵从第一行开始排列过来的
print(o.view((3,2)))
#这里的-1表示不确定行数,但是我知道列数,计算机帮你排列
print(o.view(-1,2))
tensor的广播机制(使用时要注意这个特性)
我们注意最后一行,它是p+q。按道理是没办法相加的,但是我们可以自己复制粘贴,凑好数
p = torch.arange(1, 3).view(1, 2)
print(p)
q = torch.arange(1, 4).view(3, 1)
print(q)
print(p + q)
重要:扩展&压缩tensor的维度:squeeze
unsqueeze是增加维度,加的维度是空的,1代表第二个维度,0代表第一个维度
squeeze表示的是压缩维度,只能压缩之前增加的维度
print(o)
r = o.unsqueeze(1)
print(r)
print(r.shape)
二、自动求导
1.PyTorch实现模型训练
2.输入数据,正向传播
3同时创建计算图
4计算损失函数
5损失函数反向传播
6更新模型参数
●Tensor数据结构是实现自动求导的基础
PyTorch自动求导提供了计算雅克比乘积的工具
损失函数l对输出y的导数是:
那么l对输入x的导数就是:
2.2自动求导一动态计算图 (DCG)
张量和运算结合起来创建动态计算图
就是由这样的一个计算图,知道z是由哪里算来的
2.2自动求导-扩展
静态图和动态图
主要区别在是否需要预先定义计算图的结构
下面的图,左边是静态的,就是说模型是固定好的,再计算。右边是不需要预先定义,边计算边定义图。
第二部分:自动求导示例
import torch
x1 = torch.tensor(1.0, requires_grad=True)
x2 = torch.tensor(2.0, requires_grad=True)
y = x1 + 2*x2
print(y)
首先查看每个变量是否需要求导
print(x1.requires_grad)
print(x2.requires_grad)
print(y.requires_grad)
查看每个变量导数大小。此时因为还没有反向传播,因此导数都不存在
print(x1.grad.data)
print(x2.grad.data)
print(y.grad.data)
out:
AttributeError: ‘NoneType’ object has no attribute ‘data’
反向传播后看导数大小
y = x1 + 2*x2
y.backward()
print(x1.grad.data)
print(x2.grad.data)
out:
tensor(1.)
tensor(2.)
导数是会累积的,重复运行相同命令,grad会增加,会影响你的值。所以要注意不要重复运行命令,到后面可以利用一个函数进行清零,不会有累加(每次计算前需要清除当前导数值避免累积,这一功能可以通过pytorch的optimizer实现。后续会讲到)
y = x1 + 2*x2
y.backward()
print(x1.grad.data)
print(x2.grad.data)
尝试,如果不允许求导,会出现什么情况?
就会报错,因为不让求导,反向传播不能进行
#
x1 = torch.tensor(1.0, requires_grad=False)
x2 = torch.tensor(2.0, requires_grad=False)
y = x1 + 2*x2
y.backward()
out:
untimeError: element 0 of tensors does not require grad and does not have a grad_fn
并行计算:
(1)优点:
能计算-显存占用
算得快-计算速度
效果好-大batch提升训练效果
(2)怎么并行?一CUDA
GPU厂商NVIDIA提供的GPU计算框架
GPU本身的编程基于CUDA语言实现
在PyTorch中,CUDA的含义有所不同
更多的指使用GPU进行计算(而不是CPU )
(3)并行的方法
网络结构分布到不同设备中(Network Partitioning)
同一层的任务分布到不同数据中(Layer-wise Partitioning)
(常用的)不同数据分布到不同的设备中(Data Parallelism)
(4)cuDNN与CUDA
cuDNN是用于深度神经网络的加速库
cuDNN基于CUDA完成深度学习的加速