张量类型
- 类型
- - /torch.float32:单精度浮点型tensor,即32位浮点型。 - /torch.float64:双精度浮点型tensor,即64位浮点型。 - /torch.float16:半精度浮点型tensor,即16位浮点型。 - /torch.uint8:无符号8位整型tensor。 - /torch.int8:有符号8位整型tensor。 - /torch.int16:有符号16位整型tensor。 - /torch.int32:有符号32位整型tensor。 - /torch.int64:有符号64位整型tensor。
- 方法
- 查看类型:
- 修改默认类型:torch.set_default_tensor_type() 此法仅修改本次文件,若注释掉后,再重启恢复float32类型。
- 转换类型: ---------------- () () () ---------------- type()方法:() to()方法:() type_as()方法:C=A.type_as(B)
- 注意
创建张量
- ()函数方法:
- 语法:(data, dtype=None, device=None, requires_grad=False) 其中data可以是:list, tuple, NumPy ndarray, scalar和其他类型
- A=([1,2,3,4])
- B=((1.0,2,3,4),dtype=torch.float32,requires_grad=True) # 注意数据是用()括起来的,而不是[]。
- ()类方法:
- 根据已有数据创建张量: C=([1,2,3,4])
- 根据形状创建: C=(2,3)
- 特殊数值
- (3,4)
- (3,4)
- (3)
- (3,4)
- ((3,4),fill_value=0.25)
- torch.**_like(A张量)
- B=torch.ones_like(A_tensor)
- B=torch.zeros_like(A_tensor)
- B=torch.rand_like(A_tensor)
- numpy与tensor相互转换
- torch.as_tensor(ndarray)
- torch.from_numpy(ndarray)
- (tensor)
- 陷阱: pytorch考虑共享内存,对tensor修改j时会触发复制机会,不会影响numpy; 对numpy修改会同时改变tensor,但numpy不使用替换内存操作时,不会改变tensor。即nparray=nparray+1,表示会额外复制一份内存给nparray
- 随机数
- 种子:torch.manual_seed(数值)
- 正态分布: A=(mean=0.0, std=(1.0))
- 在[0,1]区间生成均匀分布: (形状,如3,4) ()
- 特殊间隔
- A=(start=0,end=10,step=2)
- 固定数量的等间隔: A=(start=1,end=10,steps=5)
- 以对数为间隔: A=(start=0.1,end=1.0,steps=5)
- 和的区别
- ()是Python类,更明确的说,是默认张量类型()的别名,([1,2]) 会调用Tensor类的构造函数__init__,生成单精度浮点类型的张量。 而且可以生成空张量,但是()不可以生成空张量。
- ()仅仅是Python的函数,根据原始数据类型生成相应的类型
张量操作
- 操作分类
- 改变形状
- 查看形状: ()
- 元素的个数: ()
- reshape():并不改变本身形状 A=(0,8) A=(2,4) A=(input=A,shape=(2,-1))
- (2,4) :改变形状:未改变自身。 比reshape更底层,但更不智能,只能作用于整块内存中的张量,但有些张量由不同数据块组成。
- resize_():改变自身形状 A.resize_(2,4),但是参数不接受-1,如(2,-1)
- 维度提升:指定维度插入新的维度。 B=(A,dim=0)
- 维度减小:移除指定或者所有维度大小为1的维度。 B=(A,dim=1)
- 扩展张量
- expand()方法
- ## 使用.expand()方法拓展张量 A = (3) B = (3,-1) ---------------- tensor([[0, 1, 2], [0, 1, 2], [0, 1, 2]])
- expand_as()
- ## 使用.expand_as()方法拓展张量 C = (6).reshape(2,3) B = A.expand_as(C) ------------------ tensor([[0, 1, 2], [0, 1, 2]])
- repeat()方法
- 把张量A看成整体,按形状进行重复填充: ## 使用.repeat()方法拓展张量 D = (1,2,2) print(D) print() --------------- tensor([[[0, 1, 2, 0, 1, 2], [0, 1, 2, 0, 1, 2], [0, 1, 2, 0, 1, 2], [0, 1, 2, 0, 1, 2]]]) ([1, 4, 6])
- 获取张量元素
- 同numpy切片
- 根据筛选条件:(condition, x, y) 。 共有三个输入参数,第一个是condition判断条件,第二个是符合条件时取设置值x,第三个是不满足条件的设置值y。 (b>5, b, c) # 将b中值大于5和c中值不大于5的元素取出。
- 拼接
- (): C=((A,B),dim=n):在n维度连接张量AB
- ():将多个张量按指定维度进行拼接。 D=((A,B),dim=n)
- 拆分
- ():将张量分割特定数量的块。 (A,2,dim=0)
- ():分割为特定数量块时,可以指定每个块的大小。
- ## 将张量切分为块,指定每个块的大小 D1,D2,D3 = (D,[1,2,3],dim=1) print(D1) print(D2) print(D3) ------------------- tensor([[0.], [3.]]) tensor([[1., 2.], [4., 5.]]) tensor([[ 0., 2., 4.], [ 6., 8., 10.]])
- 张量剪裁
- 根据范围:(A,2,4)
- A = (6.0).reshape(2,3) (A,2.5,4) -------------- 若定义的区间,在原数据范围内,保留其定义值,若在之外,保留原数据边界值 tensor([[2.5000, 2.5000, 2.5000], [3.0000, 4.0000, 4.0000]])
- 根据最大值:torch.clamp_max(A,5)
- A = (6.0).reshape(2,3) torch.clamp_max(A,4) -------------- 保留最大值以下数值 tensor([[0., 1., 2.], [3., 4., 4.]])
- 根据最小值:torch.clamp_min(A,3)
- A = (6.0).reshape(2,3) torch.clamp_min(A,3) -------------- 保留最小值以上数值 tensor([[3., 3., 3.], [3., 4., 5.]])
- 即保留最大值以下,或最小值以上的,包含此值。
- 常用在梯度计算过程中,根据阈值进行数据截断,避免“梯度爆炸”
Variable与自动微分
- 自动微分步骤
- 步骤
- # 输入数据是标量情况下: import torch # 创建需要进行求导的张量 x x = ([2.0], requires_grad=True) # 定义计算图 y = x^2 y = x ** 2 # 对计算图进行反向传播 () # backward()只能在当前变量是标量的情况下使用 # 访问张量 x 的梯度 print()
- # 当输入数据不是标量时: # 需要使用聚合操作,转换成标量 import torch from import Variable x = (1,5,dtype=torch.float32, requires_grad=True).reshape(2,2) # 使用.reshape(2,2)后,则生成的是非叶子节点 print(x.is_leaf) # False x = Variable(x, requires_grad=True) # 将x转换成叶子节点,之后才能梯度计算 print(x.is_leaf) # True y = (x**2 + 2*x+1) # 聚合操作,才能使张量最后变成标量,才能使用backward ()
- backward():当梯度计算的张量经过一系列计算最终生成一个标量,便可用“标量的backward()”方法进行自动求导。
- 控制梯度方法
- torch.no_grad()
- 使用with torch.no_grad()控制requires_grad属性的作用域
- 使用装饰器@torch.no_grad()控制requires_grad作用域,限制函数级别的运算梯度,使张量的requires_grad失效
- torch.enable_grad()
- 可恢复被no_grad设置不需要计算的梯度。
- 使用with torch.enable_grad()方式
- 使用 装饰器 @torch.enable_grad()装饰函数后,该函数不再受with torch.no_grad()的影响
- torch.set_grad_enabled()
- Variable对象
- Variable内部结构
- 分为头信息区(Tensor)和存储区(Storage)
- 大多数操作只修改头信息。高级索引一般不共享storage,而普通索引共享storage.
- 方法可将不连续数据变成连续。
- grad_fn
- 该属性用于记录在回传计算中使用的计算图。 backward后自动销毁。
- 只能经过计算,才有grad_fn。 没有梯度的张量,即使计算,也无grad_fn。
- 语法:x.grad_fn, 返回True False
- 作用:当使用标量的backward()方法进行自动求导时,该方法会自动调用每个变量的grad_fn属性,并将结果放到该变量的grad属性中。
- 梯度函数grad_fn()可以被调用
- import torch x = (2,2,requires_grad=True) y = x ** 3 print(x.grad_fn) # 没有经过计算的tensor无此属性 print(y.grad_fn(x)) # 计算x的梯度,每一个值都将被计算,但可能不是此点的梯度 print(y.grad_fn)
- import torch x = (2.0,requires_grad=True) y = x ** 3 print(x.grad_fn) # 没有经过计算的tensor无此属性 print(y.grad_fn(x)) # 计算x的梯度,但梯度不是x的导数,而是3*x**3,输出24 print(y.grad_fn) () print() # 计算x的梯度,是3*x**2,输出12 print(y.grad_fn)
- is_leaf
- 在定义Variable对象时,属性requires_grad设为True时,则该对象被称为“叶子节点”。如果不是用此法生成的,均不是叶子节点。 叶子节点的grad_fn是None,因没有计算。
- 作用:在反向链式求导过程中,为递归循环提供信号指示。如果反向链接求导遇到叶子节点,则终止递归。
- 语法:x.is_leaf,返回True False
- #当requires_grad=False,计算后的张量仍然是叶子节点 bb=(10,requires_grad=False) print(bb.is_leaf) #True cc = bb + 3 print(cc.is_leaf) #True
- #当requires_grad=True,计算后的张量不再是叶子节点 bb=(10,requires_grad=True) print(bb.is_leaf) #True cc = bb + 3 print(cc.is_leaf) #False
- detach()
- (1)将对象分离成叶子节点
- #当张量 requires_grad=True时,无法转换为numpy
- import torch bb=(10,requires_grad=True) # print(()) # 报错 print(().numpy()) # 正确
- (2)指定模型中参数的梯度
张量计算
- 基本运算
- 幂:(),或者**运算 B=(A,3) B=A**3
- 指数:()
- 对数:()
- 平方根:()
- 平方根倒数:()
- 比较大小
- gt/lt/ge/le/eq/ne:大于/小于/大于等于/小于等于/等于/不等
- 统计相关计算
- ():
- ():输出最大值所在位置. 处理分类结果时常用,用于统计每个分类数据中的最大值,从而得到模型最终的预测结果。
- ():
- ():
- ():排序,输出结果和值在的原始位置。 降序:(A,descending=True)
- ():根据指定维度求平均值。(B,dim=1,keepdim=True)
- ()
- ():标准差
- ():方差
- cumsum/cumprod:累加/累乘
- 线性代数
- t:转置
- dot:内积
- svd:奇异值分解
- mm:矩阵乘法
- inverse:矩阵的逆
- ## 计算矩阵的逆 C = (3,3) D = (C)
- diag:矩阵对角线元素
- ## 获取矩阵张量的上三角部分,input,需要是一个二维的张量 C = (3,4) print(C) print((C,diagonal=0)) print((C,diagonal=1)) ------------------------------ tensor([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11]]) tensor([ 0, 5, 10]) tensor([ 1, 6, 11])
- ## 提供对角线元素生成矩阵张量 (([1,2,3])) ----------------------- tensor([[1, 0, 0], [0, 2, 0], [0, 0, 3]])
- triu/tril:矩阵上三角/下三角
- upper triangular matrix
- ## 获取矩阵张量的上三角部分 (A,diagonal=0)
- lower triangular matrix
- ## 获取矩阵张量的下三角部分 (A,diagonal=0)
CPU和GPU
- (1)b = () : 将CPU内存复制到GPU中
- (2) a = ([2],device="cuda"): 直接在GPU中定义
- (3) (device)方法。推荐此法。 a = ([1, 2, 3]) device = ("cuda:0" if .is_available() else "cpu") a = (device)
- (4) 使用环境变量 CUDA_VISIBLE_DEVICES 来指定设备
- 需要注意的是,使用GPU进行Tensor运算可能会比在CPU上慢,特别是在处理小型Tensor时。因此,建议仅在处理大型Tensor时使用GPU。
广播法则
- 广播是指在进行张量运算时,自动扩展张量的形状以匹配需要进行运算的张量的形状
- 代码示例
- import torch a = (0,3).reshape(3, 1) b = (10,14).reshape(1, 4) c = a + b print(a) print(b) print(c)
- import torch a = (0,6).reshape(2,3) b = (10,14).reshape(4, 1, 1) c = a + b print(a) print(b) print(c)
- 建议使用手动广播
- unsqueeze/view
- expand/expand_as
钩子函数hook
- 步骤
- 要使用钩子函数, 首先需要定义一个钩子函数, 然后将其注册到需要监视的层中, 最后移除钩子。
- 模型正向数据流处理结构中注册钩子函数hook。 每次 forward 时被调用。
- import torch class MyModel(): def __init__(self): super(MyModel, self).__init__() self.conv1 = .Conv2d(3, 16, 3) self.conv2 = .Conv2d(16, 32, 3) self.conv3 = .Conv2d(32, 64, 3) = (64*2*2, 10) def forward(self, x): out = (self.conv1(x)) out = (self.conv2(out)) out = (self.conv3(out)) out = (-1, 64*2*2) out = (out) return out # 定义钩子函数,必须三个参数 def hook_fn(module, input, output): print(module) print('input:', input) print('output:', output) print('------------------------') model = MyModel() # 注册:在model.conv2层中使用register_forward_hook注册正向数据流处理hook hook = model.conv2.register_forward_hook(hook_fn) input = (1, 3, 32, 32) output = model(input) # 移除钩子 ()
- 模型反向结构中注册钩子函数hook。 每次 backward 时被调用。
- import torch class MyModel(): def __init__(self): super(MyModel, self).__init__() self.conv1 = .Conv2d(3, 16, 3) self.conv2 = .Conv2d(16, 32, 3) self.conv3 = .Conv2d(32, 64, 3) = (64*2*2, 10) def forward(self, x): out = (self.conv1(x)) out = (self.conv2(out)) out = (self.conv3(out)) out = (-1, 64*2*2) out = (out) return out def hook_fn(module, grad_input, grad_output): print(module) print('grad_input:', grad_input) print('grad_output:', grad_output) print('------------------------') model = MyModel() hook = model.conv2.register_backward_hook(hook_fn) input = (1, 3, 32, 32) output = model(input) ().backward() ()
关于维度
- 归并操作,会沿着某个维度进行,形状可能发生变化。 指定dim,相当于对dim所指的维度进行操作。 或不指定,即对所有数进行操作。如() ------------------------- 假设形状是(m, n, k) 指定dim=0,输出形状是(1, n, k)或(n,k); 指定dim=1,输出形状是(m, 1, k)或(m,k); 指定dim=2,输出形状是(m, n, 1)或(m,n)。 ------------------------------------ 形状中是否有1,取决于参数keepdim,默认为False,不保留1,True,则保留1。
乘法运算
- 点积/内积
- :矩阵乘法。只适用于二维矩阵,要求第一个矩阵(nxm),第二个矩阵(mxp)。
- a = ([[5.,2.]]) b = ([[2.,3.]]).view(2,1) print((a, b)) # 只适用于二维 print((a, b)) # 适用于二维和多维 print(a @ b) # 与matmul等价
- :张量乘法。可以适用于高维。 (a,b) 与 a @ b 等价。
- :批量矩阵乘法。 要求第一个矩阵(bxnxm),第二个矩阵(bxmxp)。
- input = (10, 3, 4) mat2 = (10, 4, 5) res = (input, mat2) () ([10, 3, 5])
- : 对应位置相乘后再相加求和。 不同于 NumPy’s dot,仅支持一维数据。
- a = ([5.,2.]) b = ([2.,3.]) print((b)) 输出:tensor(16.)
- 阿达玛积
- 对应元素相乘,不再相加,要求矩阵行列相同,返回与原元素相同形状。 * 和 等价。
- a = ([5,2]) b = ([2,3]) print(a*b) print((a,b)) 输出: tensor([10, 6]) tensor([10, 6])
- 计算乘积
- 乘积:prod
- ## 按照行计算乘积 print((B,dim = 1,keepdim = True)) ## 按照列计算乘积 print((B,dim = 0,keepdim = True))
- 累乘积:cumprod
- ## 按照行计算累乘积 print((B,dim = 1)) ## 按照列计算累乘积 print((B,dim = 0))
- 其它乘法
- 除了上述常见的张量乘法运算,PyTorch还提供了很多其他的张量运算,如叉积运算(cross)、内积运算(dot)、外积运算(outer)、广播运算(broadcasting)等。
- mul、mm、dot、mv
- /weixin_42010722/article/details/122333051