- 什么是Pytorch
- 1. 张量(Tensors)
- 新建张量
- 查看大小和属性
- 基础运算(Operations)[4]
- 基础运算
- 索引和切片
- 张量拼接
- 张量的乘积
- 调整大小
- 张量降维
- 非降维求和
- 与NumPy的转换
- CUDA张量
这是一个基于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=⎣⎢⎢⎢⎡x1x2⋮xn⎦⎥⎥⎥⎤,
矩阵,我们通常用粗体、大写字母来表示(例如, X \mathbf{X} X、 Y \mathbf{Y} Y和 Z \mathbf{Z} Z),在代码中表示为具有两个轴的张量。在数学表示法中,我们使用 A ∈ R m × n \mathbf{A} \in \mathbb{R}^{m \times n} A∈Rm×n来表示矩阵 A \mathbf{A} A,其由 m m m行和 n n n列的实值标量组成。我们可以将任意矩阵 A ∈ R m × n \mathbf{A} \in \mathbb{R}^{m \times n} A∈Rm×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=⎣⎢⎢⎢⎡a11a21⋮am1a12a22⋮am2⋯⋯⋱⋯a1na2n⋮amn⎦⎥⎥⎥⎤.
注:区分标量和大小为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的值都改变
CUDA张量注:除CharTensor之外,CPU上的所有张量都支持转换为NumPy并转回。
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
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)