[自然语言处理]pytorch概述--什么是张量(Tensor)和根本操作 ...

打印 上一主题 下一主题

主题 977|帖子 977|积分 2931

pytorch概述

PyTorch 是⼀个开源的深度学习框架,由 Facebook 的⼈⼯智能研究团队开发和维护,于2017年在GitHub上开源,在学术界和⼯业界都得到了⼴泛应⽤
pytorch能做什么


  • GPU加速
  • 自动求导
  • 常用网络层
pytorch基础

量的概念



  • 标量:数字1,2,3
  • 向量:一维表格[1,2,3]
  • 矩阵:二维表格[(1,2),(3,4)]
通过向量、矩阵形貌的物体最多是H*W维,而生存中许多东西有更高维度,就用张量表示
前面三种量也可以当成张量的一种

张量(Tensor)的根本概念

张量(Tensor)是pytorch中的根本单位,也是深度学习框架构成的重要构成。
我们可以先把张量看做是⼀个容器,⾥⾯承载了必要运算的数据。
tensor 即“张量”。实际上跟numpy数组、向量、矩阵的格式根本一样。但是是专门针对GPU来设计的,可以运行在GPU上来加快计算效率
在PyTorch中,张量Tensor是最基础的运算单位,与NumPy中的NDArray类似,张量表示的是一个多维矩阵。不同的是,PyTorch中的Tensor可以运行在GPU上,而NumPy的NDArray只能运行在CPU上。由于Tensor能在GPU上运行,因此大大加快了运算速率。
一句话总结:一个可以运行在gpu上的多维数据而已

样本和模型 --> Y=WX+B
X:表示样本
W、B:表示变量
Y:表示标签
张量的类型

Data typedtypeLegacy Constructors(type)32-bit floating pointtorch.float32 or torch.floattorch.*.FloatTensor64-bit floating pointtorch.float64 or torch.doubletorch.*.DoubleTensor64-bit complextorch.complex64 or torch.cfloat128-bit complextorch.complex128 or torch.cdouble16-bit floating pointtorch.float16 or torch.halftorch.*.HalfTensor16-bit floating pointtorch.bfloat16torch.*.BFloat16Tensor8-bit integer (无符号)torch.uint8torch.*.ByteTensor8-bit integer (有符号)torch.int8torch.*.CharTensor16-bit integer (有符号)torch.int16 or torch.shorttorch.*.ShortTensor32-bit integer (有符号)torch.int32 or torch.inttorch.*.IntTensor64-bit integer (有符号)torch.int64
or torch.longtorch.*.LongTensorBoolean(布尔型)torch.booltorch.*.BoolTensor 张量的创建

函数功能Tensor(*size)基础构造函数Tensor(data)类似np.arrayones(*size)全1 Tensorzeros(*size)全0 Tensoreye(*size)对角线为1,其他为0arange(s,e,step)从s到e,步长为step的等差数列(不包含e这个值)linspace(s,e,steps)从s到e,匀称切分成steps份,steps是值的个数rand/randn(*size)匀称/尺度分布normal(mean,std)/uniform_(from,to)正态分布/匀称分布randperm(m)随机分列 张量初始化方法

1.直接从数据,张量可以直接从数据中创建。数据类型是⾃动推断的

  1. data = [[1, 2],[3, 4]]
  2. x_data = torch.tensor(data)
  3. x_data
复制代码
  1. tensor([[1, 2],
  2.         [3, 4]])
复制代码
  1. x_data.dtype
复制代码
  1. torch.int64
复制代码
2.从numpy数组中创建张量(反之亦然)

  1. import numpy as np
  2. np_array = np.array(data)
  3. x_np = torch.from_numpy(np_array)
复制代码
3.从另一个张量创建张量[除非明确覆盖,否则新张量保留参数张量的属性]

  1. x_ones = torch.ones_like(x_data) # 保留x_data的属性
  2. print(f"Ones Tensor: \n {x_ones} \n")
  3. #由于x_data的数据类型是int64,rand_like函数会生成一个随机张量,数据类型与x_data相同
  4. #而torch.rand()方法是创建一个服从均匀分布的随机张量,值在 [0, 1),数据类型是float32,所以需要强制转换
  5. x_rand = torch.rand_like(x_data, dtype=torch.float) # 重写x_data的数据类型
  6. print(f"Random Tensor: \n {x_rand} \n")
复制代码
  1. Ones Tensor:
  2. tensor([[1, 1],
  3.         [1, 1]])
  4. Random Tensor:
  5. tensor([[0.3156, 0.5076],
  6.         [0.8555, 0.4440]])
复制代码
4.使用随机值或常量值

shape 是张量维度的元组。在下⾯的函数中,它决定了输出张量的维度
  1. shape = (2,3,) # 一个标量
  2. rand_tensor = torch.rand(shape)
  3. ones_tensor = torch.ones(shape)
  4. zeros_tensor = torch.zeros(shape)
  5. print(f"Random Tensor: \n {rand_tensor} \n")
  6. print(f"Ones Tensor: \n {ones_tensor} \n")
  7. print(f"Zeros Tensor: \n {zeros_tensor}")
复制代码
  1. Random Tensor:
  2. tensor([[0.5733, 0.8237, 0.1398],
  3.         [0.9530, 0.9231, 0.2764]])
  4. Ones Tensor:
  5. tensor([[1., 1., 1.],
  6.         [1., 1., 1.]])
  7. Zeros Tensor:
  8. tensor([[0., 0., 0.],
  9.         [0., 0., 0.]])
复制代码
5.其他一些创建方法

基于现有tensor构建,但使⽤新值添补
  1. m = torch.ones(5,3, dtype=torch.double)
  2. n = torch.rand_like(m, dtype=torch.float)
  3. # 获取tensor的⼤⼩
  4. print(m.size()) # torch.Size([5,3])
  5. # 均匀分布
  6. torch.rand(5,3)
  7. # 标准正态分布
  8. torch.randn(5,3)
  9. # 离散正态分布
  10. torch.normal(mean=.0,std=1.0,size=([5,3]))
  11. # 线性间隔向量(返回⼀个1维张量,包含在区间start和end上均匀间隔的steps个点) 等差数列
  12. torch.linspace(start=1,end=10,steps=20)
复制代码
  1. torch.Size([5, 3])
  2. tensor([ 1.0000,  1.4737,  1.9474,  2.4211,  2.8947,  3.3684,  3.8421,  4.3158,
  3.          4.7895,  5.2632,  5.7368,  6.2105,  6.6842,  7.1579,  7.6316,  8.1053,
  4.          8.5789,  9.0526,  9.5263, 10.0000])
复制代码
张量的属性

每个Tensor有torch.dtype、torch.device、torch.layout三种属性
torch.device标识了torch.Tensor对象在创建之后所存储在的设备名称(cpu照旧GPU)
torch.layout表示torch.Tensor内存布局的对象
张量的属性形貌了张量的形状、数据类型和存储它们的设备。
以对象的⻆度来判断,张量可以看做是具有特性和⽅法的对象
  1. tensor = torch.rand(3,4)
  2. print(f"Shape of tensor: {tensor.shape}")
  3. print(f"Datatype of tensor: {tensor.dtype}")
  4. print(f"Device tensor is stored on: {tensor.device}")
复制代码
  1. Shape of tensor: torch.Size([3, 4])
  2. Datatype of tensor: torch.float32
  3. Device tensor is stored on: cpu
复制代码
张量运算

官网总结的100多种张量运算包括算术、线性代数、矩阵操作(转置、索引、切⽚)、采样等等
这些操作中的每⼀个都可以在 GPU 上运⾏(速率通常⽐在 CPU 上更快)
   默认情况下,张量是在 CPU 上创建的。
  我们可以使⽤使⽤ .to() ⽅法明确地将张量移动到 GPU (GPU可⽤的情况下)。
请留意!跨设备复制内容量较⼤的张量,在时间和内存⽅⾯大概成本很⾼!
  1. # 设置张量在GPU上运算
  2. # We move our tensor to the GPU if available
  3. if torch.cuda.is_available():
  4.     tensor = tensor.to('cuda')
复制代码
张量的索引和切片

  1. tensor = torch.ones(4, 4) # 创建一个4x4的张量
  2. print('First row: ', tensor[0]) # 打印第一行
  3. print('First column: ', tensor[:, 0]) # 打印第一列
  4. print('Last column:', tensor[..., -1]) # 打印最后一列
  5. tensor[:,1] = 0 # 第二列赋值为0
  6. print(tensor)
复制代码
  1. First row:  tensor([1., 1., 1., 1.])
  2. First column:  tensor([1., 1., 1., 1.])
  3. Last column: tensor([1., 1., 1., 1.])
  4. tensor([[1., 0., 1., 1.],
  5.         [1., 0., 1., 1.],
  6.         [1., 0., 1., 1.],
  7.         [1., 0., 1., 1.]])
复制代码
张量的拼接

可以使⽤ torch.cat ⽤来连接指定维度的⼀系列张量。另⼀个和 torch.cat 功能类似的函数是torch.stack
方法含义格式torch.cat沿现有维度连接给定的序列torch.cat(tensor, dim = 0 , *, out = None )torch.stack沿新维度连接一系列张量torch.stack(张量, dim = 0, *, out = None)
  1. print(tensor) # 打印原始张量
  2. t1 = torch.cat([tensor, tensor, tensor], dim=1) # 按列拼接
  3. # dim 参数决定了拼接操作沿着哪个维度进行。具体来说:
  4. #         •        dim=-1 表示沿着最后一个维度拼接
  5. #         •        dim=0 表示沿着第一个维度(行的方向)拼接。
  6. #         •        dim=1 表示沿着第二个维度(列的方向)拼接。
  7. #         •        dim=2 表示沿着第三个维度(深度方向,通常是针对三维张量)拼接,以此类推。
  8. print(t1)
复制代码
  1. tensor([[1., 0., 1., 1.],
  2.         [1., 0., 1., 1.],
  3.         [1., 0., 1., 1.],
  4.         [1., 0., 1., 1.]])
  5. tensor([[1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],
  6.         [1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],
  7.         [1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.],
  8.         [1., 0., 1., 1., 1., 0., 1., 1., 1., 0., 1., 1.]])
复制代码
算数运算

加法运算

  1. # 加法运算
  2. t1 = torch.tensor([[1,2],[3,4]])
  3. print(t1)
  4. t2 = torch.tensor([[5,6],[7,6]])
  5. print(t2)
  6. t3 = t1 + t2
  7. print(t3)
  8. t4 = torch.add(t1, t2)
  9. print(t4)
  10. print(t1.add(t2))  
  11. print(t1)
  12. #t1.add_(t2) # 会改变t1的值
复制代码
  1. tensor([[1, 2],
  2.         [3, 4]])
  3. tensor([[5, 6],        [7, 6]])tensor([[ 6,  8],        [10, 10]])tensor([[ 6,  8],        [10, 10]])tensor([[ 6,  8],        [10, 10]])tensor([[1, 2],
  4.         [3, 4]])
复制代码
减法运算

  1. #减法运算
  2. print(t1 - t2)
  3. print(torch.sub(t1, t2))
  4. print(t1.sub(t2))
  5. print(t1)
复制代码
  1. tensor([[-4, -4],        [-4, -2]])tensor([[-4, -4],        [-4, -2]])tensor([[-4, -4],        [-4, -2]])tensor([[1, 2],
  2.         [3, 4]])
复制代码
乘法运算

计算两个张量之间矩阵乘法的⼏种⽅式。 y1, y2, y3 末了的值是⼀样的
二维矩阵乘法运算包括torch.mm(),torch.matmul()(高维度仅支持),@
   对于高维度的Tensor(dim>2),界说其矩阵乘法仅在末了的两个维度上,要求前面的维度必须保持同等,就像矩阵的索引一样并且运算操作只有torch.matul()
  1. print(tensor) # 打印原始张量
  2. y1 = tensor @ tensor.T
  3. print(y1) # 等价于 tensor.matmul(tensor.T)
  4. y2 = tensor.matmul(tensor.T)
  5. print(y2) # 等价于 tensor @ tensor.T
  6. y3 = torch.rand_like(tensor) # 与tensor形状相同的随机张量(初始化y3)
  7. torch.matmul(tensor, tensor.T, out=y3) # 输出到y3
  8. print(y3)
复制代码
  1. tensor([[1., 0., 1., 1.],
  2.         [1., 0., 1., 1.],
  3.         [1., 0., 1., 1.],
  4.         [1., 0., 1., 1.]])
  5. tensor([[3., 3., 3., 3.],
  6.         [3., 3., 3., 3.],
  7.         [3., 3., 3., 3.],
  8.         [3., 3., 3., 3.]])
  9. tensor([[3., 3., 3., 3.],
  10.         [3., 3., 3., 3.],
  11.         [3., 3., 3., 3.],
  12.         [3., 3., 3., 3.]])
  13. tensor([[3., 3., 3., 3.],
  14.         [3., 3., 3., 3.],
  15.         [3., 3., 3., 3.],
  16.         [3., 3., 3., 3.]])
复制代码
  1. #高维度矩阵运算
  2. t5 = torch.ones(1,2,3,4)
  3. print(t5)
  4. t6 = torch.ones(1,2,4,3)
  5. print(t6)
  6. print(t5.matmul(t6)) # torch.Size([1, 2, 3, 1, 2, 3])
  7. print(torch.matmul(t5, t6)) # torch.Size([1, 2, 3, 1, 2, 3])
复制代码
  1. tensor([[[[1., 1., 1., 1.],
  2.           [1., 1., 1., 1.],
  3.           [1., 1., 1., 1.]],
  4.          [[1., 1., 1., 1.],
  5.           [1., 1., 1., 1.],
  6.           [1., 1., 1., 1.]]]])
  7. tensor([[[[1., 1., 1.],
  8.           [1., 1., 1.],
  9.           [1., 1., 1.],
  10.           [1., 1., 1.]],
  11.          [[1., 1., 1.],
  12.           [1., 1., 1.],
  13.           [1., 1., 1.],
  14.           [1., 1., 1.]]]])
  15. tensor([[[[4., 4., 4.],
  16.           [4., 4., 4.],
  17.           [4., 4., 4.]],
  18.          [[4., 4., 4.],
  19.           [4., 4., 4.],
  20.           [4., 4., 4.]]]])
  21. tensor([[[[4., 4., 4.],
  22.           [4., 4., 4.],
  23.           [4., 4., 4.]],
  24.          [[4., 4., 4.],
  25.           [4., 4., 4.],
  26.           [4., 4., 4.]]]])
复制代码
计算张量逐元素相乘的⼏种⽅法。 z1, z2, z3 末了的值是⼀样的
哈达码积(element wise,对应元素相乘)
  1. print(tensor) # 打印原始张量
  2. z1 = tensor * tensor # 逐元素相乘
  3. print(z1) # 等价于 tensor.mul(tensor)
  4. z2 = tensor.mul(tensor) # 逐元素相乘
  5. print(z2) # 等价于 tensor * tensor
  6. z3 = torch.rand_like(tensor) # 与tensor形状相同的随机张量(初始化z3)
  7. torch.mul(tensor, tensor, out=z3) # 输出到z3
  8. print(z3)
复制代码
  1. tensor([[1., 0., 1., 1.],
  2.         [1., 0., 1., 1.],
  3.         [1., 0., 1., 1.],
  4.         [1., 0., 1., 1.]])
  5. tensor([[1., 0., 1., 1.],
  6.         [1., 0., 1., 1.],
  7.         [1., 0., 1., 1.],
  8.         [1., 0., 1., 1.]])
  9. tensor([[1., 0., 1., 1.],
  10.         [1., 0., 1., 1.],
  11.         [1., 0., 1., 1.],
  12.         [1., 0., 1., 1.]])
  13. tensor([[1., 0., 1., 1.],
  14.         [1., 0., 1., 1.],
  15.         [1., 0., 1., 1.],
  16.         [1., 0., 1., 1.]])
复制代码
除法运算

  1. #除法运算
  2. print(t1 / t2)
  3. print(torch.div(t1, t2))
  4. print(t1.div(t2))
  5. print(t1)
复制代码
  1. tensor([[0.2000, 0.3333],        [0.4286, 0.6667]])tensor([[0.2000, 0.3333],        [0.4286, 0.6667]])tensor([[0.2000, 0.3333],        [0.4286, 0.6667]])tensor([[1, 2],
  2.         [3, 4]])
复制代码
幂运算

使用torch.pow(tensor,2);**;两种方法
e指函数:torch.exp(tensor)
  1. print(t1)
  2. print(torch.pow(t1, 2)) # 每个元素平方
  3. print(t1.pow(2)) # 每个元素平方
  4. print(t1**2) # 每个元素平方
  5. #print(t1.pow_(2)) # 每个元素平方
复制代码
  1. tensor([[1, 2],
  2.         [3, 4]])
  3. tensor([[ 1,  4],        [ 9, 16]])tensor([[ 1,  4],        [ 9, 16]])tensor([[ 1,  4],        [ 9, 16]])
复制代码
开方运算

tensor.sqrt()
tensor.sqrt_()
对数运算

torch.log2(tensor)
torch.log10(tensor)
torch.log(tensor)
torch.log_(tensor)
单位素张量

如果⼀个单位素张量,比方将张量的值聚合计算,可以使⽤ item() ⽅法将其转换为Python 数值
  1. print(tensor) # 打印原始张量
  2. agg = tensor.sum() # 求和
  3. print(agg)
  4. agg_item = agg.item() # 将张量的值转换为Python数值
  5. print(agg_item, type(agg_item)) # 打印agg_item的值和类型
复制代码
  1. tensor([[1., 0., 1., 1.],
  2.         [1., 0., 1., 1.],
  3.         [1., 0., 1., 1.],
  4.         [1., 0., 1., 1.]])
  5. tensor(12.)
  6. 12.0 <class 'float'>
复制代码
In-place操作

把计算效果存储到当前操作数中的操作就称为就地操作。含义和pandas中inPlace参数的含义⼀样。pytorch中,这些操作是由带有下划线 _ 后缀的函数表⽰。
比方:x.copy_(y) , x.t_() , 将改变 x ⾃⾝的值
   In-place操作虽然节省了⼀部分内存,但在计算导数时大概会出现问题,因为它会⽴即丢失历史记载。因此,不⿎励使⽤它们。
  1. x = torch.tensor([(1, 2, 3), (4, 5, 6), (7, 8, 9)])
  2. print(x)
  3. x.add_(2) # 逐元素加2
  4. print(x) # 打印x的值
  5. # 注意:任何以`_`结尾的操作都会用结果替换原始张量。例如:x.copy_(y), x.t_() , 将更改 `x`.
复制代码
  1. tensor([[1, 2, 3],
  2.         [4, 5, 6],
  3.         [7, 8, 9]])
  4. tensor([[ 3,  4,  5],
  5.         [ 6,  7,  8],
  6.         [ 9, 10, 11]])
复制代码
与numpy之间的转换

CPU 和 NumPy 数组上的张量共享底层内存位置,以是改变⼀个另⼀个也会变
张量到numpy数组

  1. t1 = torch.ones(6) # 创建一个张量
  2. print(f"t1:{t1}") #这里的f是格式化张量的内容到字符串中
  3. n1 = t1.numpy() # 张量转numpy数组
  4. print(f"n1:{n1}") # 打印numpy数组
复制代码
  1. t1:tensor([1., 1., 1., 1., 1., 1.])
  2. n1:[1. 1. 1. 1. 1. 1.]
复制代码
  1. t1.add_(1) # 逐元素加1
  2. print(f"t1:{t1}") # 打印张量
  3. print(f"n1:{n1}") # 打印numpy数组
复制代码
  1. t1:tensor([2., 2., 2., 2., 2., 2.])
  2. n1:[2. 2. 2. 2. 2. 2.]
复制代码
Numpy数组到张量

  1. n2 = np.ones(5) # 创建一个numpy数组
  2. print(f"n2:{n2}") # 打印numpy数组
  3. t2 = torch.from_numpy(n2) # numpy数组转张量
  4. print(f"t2:{t2}") # 打印张量
  5. #Numpy数组和PyTorch张量将共享它们的底层内存位置,因此对一个进行更改将导致另一个也发生更改。
  6. np.add(n2,1,out=n2) # 逐元素加1
  7. print(f"t2:{t2}") # 打印张量
  8. print(f"n2:{n2}") # 打印numpy数组
复制代码
  1. n2:[1. 1. 1. 1. 1.]
  2. t2:tensor([1., 1., 1., 1., 1.], dtype=torch.float64)
  3. t2:tensor([2., 2., 2., 2., 2.], dtype=torch.float64)
  4. n2:[2. 2. 2. 2. 2.]
复制代码
计算图

在进⼀步学习pytorch之前,先要相识⼀个概念 —— 计算图( Computation graph)所有的深度学习框架都依赖于计算图来完成梯度降落、优化梯度值等计算。
⽽计算图的创建和应⽤,通常包含如下两个部分:

  • 用户构前向传播图
  • 框架处理后向传播(梯度更新)
模型从简单到复杂,pytorch和tensorflow都使⽤计算图来完成⼯作。
但是,这两个框架所使⽤的计算图也却有所不同:
tensorflow1.x 使⽤的是静态计算图,tensorflow2.x和pytorch使⽤的是动态计算图
静态计算图

先搭建计算图,后运行;允许编译器举行优化
通常包括以下两个阶段。

  • 界说⼀个架构(可以使⽤⼀些根本的流控制⽅法,⽐如循环和条件指令)
  • 运⾏⼀组数据来训练模型,进⾏推理


  • 优点:允许对图进⾏强⼤的离线优化/调度,以是速率相对较快。
  • 缺点:难以调试,对代码中处理布局化或者可变⼤⼩的数据处理⽐较复杂
动态计算图

编好程序即可执行
在执⾏正向计算时,隐式地界说图(动态构建)。


  • 优点:机动,侵⼊性⼩,允许动态构建和评估
  • 缺点:难以优化
   两种计算图⽐较起来,可以看出:动态图是对调试友好的(对程序员友好)。它允许逐⾏执⾏代码,并可以访问所有张量。这样更便于发现和找到我们计算或逻辑中的问题
  pytorch计算图可视化

通过torchviz可以实现
  1. import torch
  2. from torchviz import make_dot
  3. # 定义矩阵 A,向量 b 和常数 c
  4. A = torch.randn(10, 10,requires_grad=True)   #requires_grad=True表示需要计算梯度,对A求导
  5. b = torch.randn(10,requires_grad=True)
  6. c = torch.randn(1,requires_grad=True)
  7. x = torch.randn(10, requires_grad=True)
  8. # 计算 x^T * A + b * x + c
  9. result = torch.matmul(A, x.T) + torch.matmul(b, x) + c
  10. # ⽣成计算图节点
  11. dot = make_dot(result, params={'A': A, 'b': b, 'c': c, 'x': x})
  12. # 绘制计算图
  13. dot.render('expression', format='png', cleanup=True, view=False)
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

耶耶耶耶耶

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表