目录
一、数学运算
1、基本操作
2、三角函数
3、统计学函数
二、生存和加载
三、并行化
四、自动微分
1、相关概念
2、盘算梯度
1.标量梯度盘算
2.向量梯度盘算
3.多标量梯度盘算
4.多向量梯度盘算
5.矩阵梯度盘算
3、梯度上下文控制
1、梯度控制
2、梯度更新
3、叶子节点
导入torch库:
一、数学运算
1、基本操作
- floor: 向下取整;
- ceil:向上取整;
- round:四舍五入;
- trunc:裁剪,只生存整数部分;
- frac:只生存小数部分;
- fix:向零方向舍入;
- %:取余;
- abs:取绝对值。
- data = torch.tensor(
- [
- [1, 2, -3.5], # 1
- [4, 5, 6], # 2
- [10.5, 18.6, 19.6], # 3
- [11.05, 19.3, 20.6], # 4
- ]
- )
- print(data)
- # 向下取整(往小取 返回不大于每个元素的最大整数)
- x1 = torch.floor(data)
- print(x1)
- # 向上取整(往大取 返回不小于每个元素的最小整数)
- x2 = torch.ceil(data)
- print(x2)
- # 四舍五入 与python round()一致 四舍六入五看齐(看个位奇偶,奇进偶舍)
- x3 = torch.round(data)
- print(x3)
- # 截断,只保留整数部分
- x4 = torch.trunc(data)
- print(x4)
- # 截断,只保留小数部分
- x5 = torch.frac(data)
- print(x5)
- # 向零方向舍入(舍入到最接近零的整数)
- x6 = torch.fix(data)
- print(x6)
- # 取余
- x7 = torch.fmod(data, 2)
- print(x7)
- # 绝对值
- x8 = torch.abs(data)
- print(x8)
复制代码 2、三角函数
- torch.cos(input,out=None)
- torch.cosh(input,out=None) # 双曲余弦函数
- torch.sin(input,out=None)
- torch.sinh(input,out=None) # 双曲正弦函数
- torch.tan(input,out=None)
- torch.tanh(input,out=None) # 双曲正切函数
- # torch.set_printoptions(sci_mode=False)
- print(torch.pi) # 圆周率
- deg = torch.pi/180
- data = torch.tensor([0,90*deg,45*deg])
- x1 = torch.sin(data)
- print(x1)
- x2 = torch.cos(data)
- print(x2)
- x3 = torch.sinh(data)
- print(x3)
- x4 = torch.cosh(data)
- print(x4)
- x5 = torch.tan(data)
- print(x5)
- x6 = torch.tanh(data)
- print(x6)
复制代码 3、统计学函数
- torch.mean(): 盘算张量的平均值。
- torch.sum(): 盘算张量的元素之和。
- torch.std(): 盘算张量的尺度差。
- torch.var(): 盘算张量的方差。
- torch.median(): 盘算张量的中位数。
- torch.max(): 盘算张量的最大值。
- torch.min(): 盘算张量的最小值。
- torch.mode(): 盘算张量众数
- torch.sort(): 对张量进行排序。 返回排序后的张量values和索引indices
- torch.topk(): 返回张量中的前 k 个最大值或最小值。
- torch.histc(): 盘算张量的直方图。
- torch.unique(): 返回张量中的唯一值。
- torch.bincount(): 盘算张量中每个元素的出现次数。
- torch.manual_seed(66)
- x = torch.tensor([1,2,2,3,3,3,4,4,5]).type(torch.float32)
- print(x)
- # 平均值
- x1 = x.mean()
- print(x1)
- # 求和
- x2 = x.sum()
- print(x2)
- # 标准差
- x3 = x.std()
- print(x3)
- # 方差
- x4 = x.var()
- print(x4)
- # 中位数
- x5 = x.median()
- print(x5)
- # 最大值
- x6 = x.max()
- print(x6)
- # 最小值
- x7 = x.min()
- print(x7)
- # 众数
- x8 = torch.mode(x)
- print(x8)
- # 排序 返回排序后的张量values和索引indices
- x9 = torch.sort(x)
- print(x9)
- x = torch.tensor([1,2,2,3,3,3,4,4,5,2,3,4,6]).type(torch.float32)
- print(torch.topk(x,3)) # 返回前3个最大值
- print(torch.histc(x,bins=10, min=2,max=4)) # 区间[min,max]分成bins份 表示各个区间的元素计数
- print(torch.unique(x)) # 返回分类的数据集中的数据类型
- x = torch.tensor([1,2,2,3,3,3,4,4,5,2,3,4,6])
- print(torch.bincount(x)) # 返回张量中每个元素的出现次数
复制代码 二、生存和加载
- # 保存
- x = torch.tensor([1,2,3])
- torch.save(x,'./data/tensor01.pth')
- device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
- # 加载
- y = torch.load('./data/tensor01.pth',map_location=device)
- print(y)
- print(y.device)
复制代码 三、并行化
在 PyTorch 中,可以查看和设置用于 CPU 运算的线程数。PyTorch 使用多线程来加速 CPU 运算,但偶尔大概需要调解线程数来优化性能。
- # torch.get_num_threads() 来查看当前 PyTorch 使用的线程数
- def test01():
- count = torch.get_num_threads()
- print(count)
- # torch.set_num_threads() 设置 PyTorch 使用的线程数
- def test02():
- torch.set_num_threads(4)
- count = torch.get_num_threads()
- print(count)
- if __name__ == '__main__':
- test01()
- test02()
复制代码 设置线程数时,确保思量到你的 CPU 核心数和其他历程的资源需求,以得到最佳性能。
注意事项
- 线程数设置过高大概会导致线程竞争,反而低落性能;
- 线程数设置过低大概会导致盘算资源未得到充分使用;
- 当使用 GPU 进行盘算时,线程数设置对性能影响较小,由于 GPU 盘算并不依赖于 CPU 线程数。
四、自动微分
自动微分模块torch.autograd负责自动盘算张量操作的梯度,具有自动求导功能。自动微分模块是构成神经网络训练的须要模块,可以实现网络权重参数的更新,使得反向传播算法的实现变得简单而高效。
1、相关概念
- 张量
Torch中的对象都为张量,属性requires_grad决定是否对其进行梯度盘算。默认是 False,如需盘算梯度则设置为True。
- 盘算图:
torch.autograd通过创建一个动态盘算图来跟踪张量的操作,每个张量是盘算图中的一个节点,节点之间的操作构成图的边。
- 反向传播
使用tensor.backward()方法实行反向传播,从而盘算张量的梯度。这个过程会自动盘算每个张量对损失函数的梯度。
- 梯度
盘算得到的梯度通过tensor.grad访问,这些梯度用于优化模型参数,以最小化损失函数。
2、盘算梯度
使用tensor.backward()方法实行反向传播,以盘算张量的梯度。
1.标量梯度盘算
- # 创建张量:要计算梯度则必须为浮点类型
- x = torch.tensor(3, require_grad=True, dtype=torch.float64)
- # 定义函数
- y = x**2 + 2*x - 5
- # 计算梯度,也就是反向传播
- y.backward() # # 梯度计算 1.y函数对x求导函数 y'=2*x+2 2.代入x的当前值 x=3 3.求出导数值 y'=2*3+2
- # 读取梯度值
- print(x.grad) # tensor(8.)
复制代码 2.向量梯度盘算
- # 向量梯度计算
- x = torch.tensor([1,2,3],requires_grad=True,dtype=torch.float64)
- y = x**2 + 2*x - 5
- print(y) # tensor([-2., 3., 10.], dtype=torch.float64, grad_fn=<SubBackward0>)
- y = y.sum() # y必须是一个标量才能用这个标量对x求导 设置一个复合函数
- y.backward() # y'=2x+2
- print(x.grad) # tensor([4., 6., 8.], dtype=torch.float64)
复制代码 3.多标量梯度盘算
- # 多标量的梯度计算
- x1 = torch.tensor(1,requires_grad=True,dtype=torch.float64)
- x2 = torch.tensor(2,requires_grad=True,dtype=torch.float64)
- y = x1**2 + 3*x2 - 5
- y.backward() # 偏导数
- print(x1.grad)
- print(x2.grad)
复制代码 4.多向量梯度盘算
- # 多向量的梯度计算
- x1 = torch.tensor([1,2,3],requires_grad=True,dtype=torch.float64)
- x2 = torch.tensor([4,5,6],requires_grad=True,dtype=torch.float64)
- y = x1**2 + 3*x2 - 5
- y = y.sum()
- y.backward() # 偏导数
- print(x1.grad) # 2*x1 tensor(2., dtype=torch.float64)
- print(x2.grad) # 3 tensor(3., dtype=torch.float64)
复制代码 5.矩阵梯度盘算
- # 矩阵梯度计算
- x = torch.tensor([[1,2],[3,4]],requires_grad=True,dtype=torch.float64)
- y = x**2 + 2*x - 5
- y = y.sum()
- y.backward()
- print(x.grad)
复制代码 3、梯度上下文控制
梯度盘算的上下文控制和设置对于管理盘算图、内存消耗、以及盘算效率至关重要。
1、梯度控制
梯度盘算是有性能开销的,有些时候只是简单的运算,此时并不需要梯度。
- # 正常情况下
- def test01():
- x = torch.tensor(10.5, requires_grad=True)
- print(x.requires_grad) # True
- # 默认y的requires_grad=True
- y = x**2 + 2 * x + 3
- print(y.requires_grad) # True
- def test02():
- x = torch.tensor(5, requires_grad=True,dtype=torch.float64)
- # 关闭y的梯度计算 使用with进行上下文管理
- with torch.no_grad():
- y = x**2 + 2*x - 5
- print(y.requires_grad) # False
- # 使用装饰器
- @torch.no_grad()
- def test03():
- x = torch.tensor([1,2,3], requires_grad=True,dtype=torch.float64)
- y = x**2 + 2*x - 5
- y = y.sum()
- print(y.requires_grad) # False
-
- # 自己创建装饰器
- def my_no_grad(func):
- def wrapper():
- with torch.no_grad():
- re = func()
- return re
- return wrapper
- @my_no_grad
- def test04():
- x = torch.tensor([1,2,3], requires_grad=True,dtype=torch.float64)
- y = x**2 + 2*x - 5
- y = y.sum()
- print(y.requires_grad) # False
- # 全局设置关闭梯度计算
- def test05():
- x = torch.tensor([1,2,3], requires_grad=True,dtype=torch.float64)
- torch.set_grad_enabled(False)
- y = x**2 + 2*x - 5
- y = y.sum()
- y.backward()
- print(x.requires_grad)
- print(y.requires_grad)
- print(x.grad)
- # 累计梯度
- def test06():
- x = torch.tensor(1, requires_grad=True,dtype=torch.float64)
- y = x**2 + 2*x - 5
- y.backward()
- print(x.grad)
- y = 2*x**2 + 7
- y.backward()
- print(x.grad)
- # 累计梯度02
- def test07():
- x = torch.tensor(4, requires_grad=True,dtype=torch.float64)
- for _ in range(4):
- y = x**2 + 2*x - 5
- y.backward()
- print(x.grad)
- # 梯度清零
- def test08():
- x = torch.tensor(4, requires_grad=True,dtype=torch.float64)
- y = x**2 + 2*x - 5
- y.backward() # 2*x + 2
- print(x.grad)
-
- z = 3*x**2 + 7*x
- # 清零
- x.grad.zero_() # 不清零则为 10+31=41
- z.backward() # 清零后为 6*4+7=31
- print(x.grad)
- # 综合梯度清零操作
- for _ in range(3):
- y = x**2 + 2 * x + 7
- z = y.mean()
- # 反向传播之前先对梯度进行清零
- if x.grad is not None:
- x.grad.zero_()
-
- z.backward()
- print(x.grad)
- if __name__ == '__main__':
- test01()
- test02()
- test03()
- test04()
- test05()
- test06()
- test07()
- test08()
复制代码 2、梯度更新
大多数情况下是不需要梯度累加的,反向传播之前可以先用 .zero_() 对梯度进行清零。
更新梯度时,注意更新的数据应是data,直接改变原tensor会导致其变成新的数据。
- # 标量训练
- def test01():
- # 生成初始化w
- w = torch.tensor(25., requires_grad=True)
- # 训练参数
- lr = 0.01
- epoch = 5
- for i in range(epoch):
- # 生成损失函数
- loss = 3*w**2 + 2*w - 5
- # 梯度清零
- if w.grad is not None:
- w.grad.zero_()
- # 反向传播 求当前w的导数值:梯度值,斜率
- loss.backward()
- # 当前斜率
- print(w.grad)
- # 更新梯度
- # w的tensor不能修改 避免w变成新的数据 应修改w.data
- w.data = w.data - lr*w.grad.data
- print(w)
- # 访问训练后的w的值
- print(w.data)
- # 向量训练
- def test02():
- # 生成初始化w
- w = torch.tensor([10,20,30], requires_grad=True,dtype=torch.float64)
- # 训练参数
- lr = 0.01
- epoch = 5
- for i in range(epoch):
- # 生成损失函数
- loss = 3*w**2 + 2*w - 5
- loss = loss.sum() # 设置一个复合函数
- # 梯度清零
- if w.grad is not None:
- w.grad.zero_()
- # 反向传播 求当前w的导数值:梯度值,斜率
- loss.backward()
- # 当前斜率
- print(w.grad)
- # 更新梯度
- # w的tensor不能修改 避免w变成新的数据 应修改w.data
- w.data = w.data - lr*w.grad.data
- print(w)
- # 访问训练后的w的值
- print(w.data)
- # 保存训练好的权重数据
- torch.save(w.data,'./data/weight.pth')
- # 加载训练好的权重数据
- def detect():
- w = torch.load('./data/weight.pth',map_location='cuda')
- # 使用w
- print(w)
- if __name__ == '__main__':
- # test01()
- test02()
- detect()
复制代码 3、叶子节点
当想使用不含求导功能的tensor时,可以使用detach()创建张量,该张量是作为叶子结点存在的,并且该张量和原张量共享数据,只是该张量不需要盘算梯度。
原因:可以求导的张量不能直接看成平凡的tensor使用,如转换为numpy数组操作: .numpy()
- # detach()产生的张量是作为叶子结点存在的,并且该张量和原张量共享数据,只是该张量不需要计算梯度。
- def test01():
- x = torch.tensor([1, 2, 3], requires_grad=True,dtype=torch.float32)
- # x1 = x.numpy() # 报错 如果x是一个可以求导的张量,那么它就不能直接当作普通的tensor使用
- def test02():
- x = torch.tensor([1, 2, 3], requires_grad=True,dtype=torch.float32)
- x2 = x.detach() # 创建一个叶子结点,并且和x共享数据,但是不需要计算梯度
- print(x) # tensor([1., 2., 3.], requires_grad=True)
- print(x2) # tensor([1., 2., 3.])
-
- print(id(x),id(x2)) # 两个对象
- print(id(x.data),id(x2.data)) # 数据共享
- x2[0] = 5
- print(x,x2)
- if __name__ == '__main__':
- test02()
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |