Pytorch学习记录(一)Tensor及其性质

Pytorch学习记录(一)Tensor及其性质,第1张

Pytorch学习记录(一)Tensor及其性质
  • 什么是Pytorch
  • 1. 张量(Tensors)
    • 新建张量
    • 查看大小和属性
    • 基础运算(Operations)[4]
      • 基础运算
      • 索引和切片
      • 张量拼接
      • 张量的乘积
      • 调整大小
      • 张量降维
      • 非降维求和
      • 与NumPy的转换
      • CUDA张量

什么是Pytorch

这是一个基于Python的科学计算软件包,面向两组受众:

  • 替代NumPy以使用GPU的功能
  • 深度学习研究平台,可提供最大的灵活性和速度1

 

1. 张量(Tensors)

张量如同数组和矩阵一样, 是一种特殊的数据结构。张量的英文是Tensor,它是PyTorch里面基础的运算单位,在PyTorch中, 神经网络的输入、输出以及网络的参数等数据, 都是使用张量来进行描述。

张量与NumPy的ndarrays类似,此外,张量也可以在GPU上使用以加速计算。

在同构的意义下,第零阶张量 (r = 0) 为标量 (Scalar),第一阶张量 (r = 1) 为向量 (Vector), 第二阶张量 (r = 2) 则称为矩阵 (Matrix),第三阶以上的统称为多维张量。1

我们可以使用下标来引用向量的任一元素。2例如,我们可以通过 x i x_i xi来引用第 i i i个元素。注意,元素 x i x_i xi是一个标量,所以我们在引用它时不必加粗。一般认为列向量是向量的默认方向,故在数学中,向量 x \mathbf{x} x可以写为:

x = [ x 1 x 2 ⋮ x n ] , \mathbf{x} =\begin{bmatrix}x_{1} \x_{2} \ \vdots \x_{n}\end{bmatrix}, x=x1x2xn,

矩阵,我们通常用粗体、大写字母来表示(例如, X \mathbf{X} X Y \mathbf{Y} Y Z \mathbf{Z} Z),在代码中表示为具有两个轴的张量。在数学表示法中,我们使用 A ∈ R m × n \mathbf{A} \in \mathbb{R}^{m \times n} ARm×n来表示矩阵 A \mathbf{A} A,其由 m m m行和 n n n列的实值标量组成。我们可以将任意矩阵 A ∈ R m × n \mathbf{A} \in \mathbb{R}^{m \times n} ARm×n视为一个表格,其中每个元素 a i j a_{ij} aij属于第 i i i行第 j j j列:

A = [ a 11 a 12 ⋯ a 1 n a 21 a 22 ⋯ a 2 n ⋮ ⋮ ⋱ ⋮ a m 1 a m 2 ⋯ a m n ] . \mathbf{A}=\begin{bmatrix} a_{11} & a_{12} & \cdots & a_{1n} \ a_{21} & a_{22} & \cdots & a_{2n} \ \vdots & \vdots & \ddots & \vdots \ a_{m1} & a_{m2} & \cdots & a_{mn} \ \end{bmatrix}. A=a11a21am1a12a22am2a1na2namn.

注:区分标量和大小为1的向量

torch.tensor(10)  # 此为标量,其大小为torch.Size([])

torch.tensor([10])  # 此为只有一个数据的向量,其大小为torch.Size(1)

在进行各项 *** 作之前,我们需要导入PyTorch中使用频率最高的数据库Torch:

import torch
新建张量

下面是对新建张量的一些基础 *** 作:

# 创建一个使用未初始化值填满的5x3矩阵,默认为浮点数类型,可能由于精度低而显示为0
x = torch.empty(5, 3)    

# 创建一个 按0~1均匀分布 随机初始化的矩阵,randn()则按均值为0方差为1的标准正态分布
x = torch.rand(5, 3)

# 创建一个包含以0开始的前12个整数的行向量x
x = torch.arange(12)

# 构造一个填充0且dtype为int的矩阵,类似有ones等
x = torch.zeros(5, 3, dtype=torch.long)

# 或者直接按照数据创建2x2张量
x = torch.tensor([[3.14, 3.141],[1, 2]])

# 或基于现有张量创建张量,如*_like方法,这些方法将使用input的属性
x = x.new_ones(5, 3, dtype=torch.double)      # new_*方法允许在与先前存在的张量(带有张量)相同的设备和数据类型上快速创建,ones则是从头创建
x = torch.randn_like(x, dtype=torch.float)    # 提供新的dtype
查看大小和属性

要查看Tensor的大小,可以使用Torch中的Size()函数或是numel()函数,亦可使用NumPy相同的shape属性查看(shape是元组类型, 用来描述张量的维数,故当张量只有一个轴时,其维度就等价于张量的大小):

print(x.size())      # 返回 torch.Size([15])
print(x.numel())     # 返回 15
print(len(x))        # 返回 15
print(x.shape)       # 可以使用与numpy相同的shape属性查看

注:torch.Size 实际上是一个tuple,因此它支持所有tuple *** 作。

要查看Tensor的属性,我们可以得到张量的维数、数据类型以及它们所存储的设备(CPU或GPU):

print(f"Shape of tensor: {x.shape}")                
# 维数 torch.Size([3, 4])
print(f"Datatype of tensor: {x.dtype}")             
# 数据类型 torch.float32
print(f"Device tensor is stored on: {x.device}")    
# 存储设备 cpu

此外有关向量的更多性质,可以查看这里.

基础运算(Operations)4

可以对生成的Tensor有超过100种张量相关的运算 *** 作, 包括转置(transposing)、索引(indexing)、分割(slicing)、数学运算(mathematical operations)、线性代数(linear algebra)、随机数(random numbers)等,下面将列举几个运算。

基础运算
y = torch.arange(15).resharp(5, 3)
x + y, x - y, x * y, x / y, x ** y         # **运算符是求幂运算,指x的y次幂

# 两张量相加,提供输出张量作为参数(argument),等同于输出torch.add(x, y)
result = torch.empty(5, 3)
torch.add(x, y, out=result)

# 两张量相加,就地(in-place)赋值运算 将x加给y
y.add_(x)

注:任何张量自动赋值运算的 *** 作都将使用 “_”,如: x.copy_(y)x.t_(),都会改变 x \mathbf{x} x.

若直接使用 y = x + y \mathbf{y = x + y} y=x+y,则将取消引用 y \mathbf{y} y指向的张量,而是指向新分配的内存处的 y \mathbf{y} y

索引和切片

张量中的元素可以通过索引访问。 与任何Python数组一样:第一个元素的索引是0,最后一个元素索引是-1; 可以指定范围以包含第一个元素和最后一个之前的元素。对Tensor可以使用类似NumPy的标准索引,如:

x = torch.ones(5, 3)
print(x[-1])          # 输出最后一行数据
print(x[1:3])         # 输出第2行~第3行全部数据(从1算起,3前为止)
x[:,1] = 0            # 将第2列(0为第1列)的数据全部赋值为0
张量拼接

可以通过torch.cat方法将一组张量按照指定的维度进行拼接, 也可以参考torch.stack方法:

t1 = torch.cat([x, x, x], dim=1)            # 将3个5x3矩阵x 按轴-1拼接为1个5x9矩阵
张量的乘积

张量的乘积代表张量内逐个元素相乘的结果,两个矩阵的按元素乘法称为Hadamard积(Hadamard product)(数学符号 ⊙ \odot ):

# Hadamard积
xx = tensor.mul(x)
xx = x * x                # 等价写法

而张量的乘法则按照矩阵乘法的原则进行计算:

# 向量点积
xy = torch.dot(x, y)      # 向量x和y求点积
xy = torch.sum(x * y)     # 等价写法

# 矩阵向量积
Ax = torch.mv(A, x)       # 求矩阵A和向量x的向量积

# 矩阵乘法
xx = x.matmul(x.T)   # .t方法可转置维度小于等于 2 的张量,.T方法可以把整个张量的维度进行颠倒
xx = torch.mm(x, x.T)     # 等价写法
xx = x @ x.T              # 等价写法
调整大小

可以使用 torch.view来调整Tensor的大小/形状,这与NumPy中的resharp方法等价,但必须要求调整后的形状和原来一致:

x = torch.randn(4, 4)    # 原始张量x为4x4矩阵
y = x.view(16)           # 将x拉伸为16的向量y
z = x.view(-1, 8)        # 拓宽x轴-1的size为8,输入-1代表自动计算轴-0的size,最终变为2x8矩阵z
张量降维

默认情况下,调用求和函数会沿所有的轴降低张量的维度,使它变为一个标量。 我们还可以指定张量沿哪一个轴来通过求和降低维度。 以矩阵为例,为了通过求和所有行的元素来降维(轴0),使轴0的维数在输出形状中消失,我们可以这样调用函数:

x_sum_axis0 = x.sum(axis=0)          # 在调用时指定 axis=0
x_sum_axis0, x_sum_axis0.shape       # 此时x_sum_axis0降为向量

x.sum(axis=[0, 1])                   # 将矩阵x降为标量 

同样我们可以使用求平均值(mean或average)的方法对张量进行降维,可以通过以下两种方法:

x.mean()
x.sum() / A.numel()                  # 等价写法

# 沿指定轴降低张量的维度为平均值
x.mean(axis=0)                       
x.sum(axis=0) / x.shape[0]
非降维求和

有时在调用函数来计算总和或均值时需要保持轴数不变,可以通过在属性中保持轴的方式处理,或是直接使用cumsum()方法:

sum_x = x.sum(axis=0, keepdims=True)

x.cumsum(axis=0)
与NumPy的转换

Tensor和Numpy array数组在CPU上共用一块内存区域, 修改其中任何一个,另一个也会随之改变:

import numpy as np

# 将Torch张量转换为NumPy数组
a = torch.ones(5)
b = a.numpy()            # a和b都为[1, 1, 1, 1, 1]
a.add_(1)                # 改变a的值,a和b的值都变为[2, 2, 2, 2, 2]

# 将NumPy数组转换为Torch张量
a = np.ones(5)
b = torch.from_numpy(a)           # 将nparray数组a赋给张量b
np.add(a, 1, out=a)               # 改变a的值,a和b的值都改变

注:除CharTensor之外,CPU上的所有张量都支持转换为NumPy并转回。

CUDA张量

Tensor可以使用.to方法移动到任何设备上。

# 仅在可用CUDA时运行
# 我们用torch.device对象将张量移入和移出GPU
if torch.cuda.is_available():
    device = torch.device("cuda")          # CUDA设备对象
    y = torch.ones_like(x, device=device)  # 在GPU上直接创建张量
    x = x.to(device)                       # 或只使用字符串 .to("cuda")
    z = x + y
    print(z)
    print(z.to("cpu", torch.double))       # .to 可同时改变device和dtype

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/758517.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-01
下一篇 2022-05-01

发表评论

登录后才能评论

评论列表(0条)

保存