PyTorch有各种组件:
PyTorch中使用的数据结构是基于图和张量的,因此理解基本运算和定义张量非常重要。
让我们看一下以下张量和张量运算基础的例子,包括数学运算。
对象x是一个列表。我们可以使用下面的语法来检查Python中的一个对象是否是一个张量对象。通常,is_tensor函数和is_storage函数检查对象是否被存储为张量对象。
import torch
x = [12, 13, 14, 15, 56,57,58]
print(torch.is_tensor(x))
# False
print(torch.is_storage(x))
# False
现在,让我们创建一个包含来自Torch的随机数的对象,类似于NumPy库。我们可以检查张量和存储类型。
import torch
x = torch.randn(1,2,3,4,5)
print(torch.is_tensor(x))
# True
print(torch.is_storage(x))
# False
print(torch.numel(x))
# 120
x是一个张量;但是,它不会被存储。为了检查输入张量对象中的元素总数,可以使用数值元素函数。
像NumPy操作一样,eye函数创建一个对角矩阵,其中对角元素为1,非对角元素为0。eye函數可以通过提供形状选项进行操作。下面的示例演示如何提供形状参数。
import torch
print(torch.eye(3,4))
# tensor([[1., 0., 0., 0.],
# [0., 1., 0., 0.],
# [0., 0., 1., 0.]])
线性空间和线性空间之间的点可以用张量操作来创建。让我们使用一个例子,在一个线性空间中创建25个点,从值2开始,以10结束。Torch可以讀取一个NumPy数组格式。
import torch
import numpy as np
x = torch.randn(1,2,3)
x1=np.array(x)
print(x)
x2 = torch.from_numpy(x1)
print(x2)
x3 = torch.linspace(2,10,steps=25)
print(x3)
# tensor([[[-1.1404, 1.7232, 0.3831],
# [-0.0787, -0.7935, -0.4067]]])
# tensor([[[-1.1404, 1.7232, 0.3831],
# [-0.0787, -0.7935, -0.4067]]])
# tensor([ 2.0000, 2.3333, 2.6667, 3.0000, 3.3333, 3.6667, 4.0000, 4.3333,
# 4.6667, 5.0000, 5.3333, 5.6667, 6.0000, 6.3333, 6.6667, 7.0000,
# 7.3333, 7.6667, 8.0000, 8.3333, 8.6667, 9.0000, 9.3333, 9.6667,
# 10.0000])
随机数生成是数据科学中常见的生成或收集空间样本数据点以模拟数据中的结构的过程。随机数可以由统计分布、任意两个值或预定义的分布生成。与NumPy函数一样,可以使用以下示例生成随机数。均匀分布是指每个结果发生的概率相等的分布;因此,事件概率是常数。
import torch
print(torch.rand(10))
# tensor([0.2826, 0.6338, 0.7633, 0.8168, 0.7536, 0.3857, 0.5816,
# 0.6116, 0.1355,0.3790])
算术平均值为0,标准差为1的正态分布的随机数也可以如下创建。
import torch
print(torch.randn(2,3))
print(torch.randn(5))
# tensor([[ 0.8980, -0.5173, 0.4493],
# [-0.4232, -0.4060, -0.0471]])
# tensor([-0.4057, -0.0752, -1.2323, -0.3223, -0.0600])
要使用随机排列从值的范围中选择随机值,需要首先定义范围。这个范围可以通过使用arrange函数创建。在使用arrange函数时,必须定义步长,将所有值放置在相等的距离空间中。缺省情况下,步长为1。
import torch
print(torch.randperm(10))
print(torch.arange(10,40,2))
print(torch.arange(10,20))
# tensor([4, 3, 9, 6, 0, 5, 8, 2, 7, 1])
# tensor([10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38])
# tensor([10, 11, 12, 13, 14, 15, 16, 17, 18, 19])
为了求一维张量的最小值和最大值,可以使用argmin和argmax。如果输入是一个矩阵,以便沿着行或列搜索最小值,则需要提到维数。
import torch
d = torch.randn(2,3)
print(d)
print(torch.argmin(d,dim=1))
print(torch.argmax(d,dim=1))
# tensor([[-0.8461, 0.6282, -0.0616],
# [-0.2727, 0.6879, -0.7773]])
# tensor([0, 2])
# tensor([1, 1])
如果它是行或列,则它是一个维度,称为一维张量。如果输入是一个矩阵,其中有行和列,它被称为2D张量。如果它大于二维,就称为多维张量。
现在,让我们创建一个二维张量样本,并通过对张量的连接操作来执行索引和连接。
import torch
x = torch.randn(2,3)
print(x)
print(torch.cat((x,x)))
# tensor([[-0.6394, -1.7363, -0.9337],
# [-0.4853, -0.5483, 0.9684]])
# tensor([[-0.6394, -1.7363, -0.9337],
# [-0.4853, -0.5483, 0.9684],
# [-0.6394, -1.7363, -0.9337],
# [-0.4853, -0.5483, 0.9684]])
print(torch.cat((x,x,x), 1))
# tensor([[-0.6394, -1.7363, -0.9337, -0.6394, -1.7363, -0.9337, -0.6394, -1.7363, -0.9337],
# [-0.4853, -0.5483, 0.9684, -0.4853, -0.5483, 0.9684, -0.4853, -0.5483, 0.9684]])
print(torch.cat((x,x), 0))
# tensor([[-0.6394, -1.7363, -0.9337],
# [-0.4853, -0.5483, 0.9684]])
# tensor([[-0.6394, -1.7363, -0.9337],
# [-0.4853, -0.5483, 0.9684],
# [-0.6394, -1.7363, -0.9337],
# [-0.4853, -0.5483, 0.9684]])
张量可以被分割成多个块。这些小块可以沿着行和列创建。下面的例子显示了一个大小为(4,4)的样本张量。块是使用函数中的第三个参数创建的,如0或1。
import torch
a = torch.randn(3,4)
print(a)
print(torch.chunk(a,2))
# tensor([[-1.1775, -0.4398, -0.7885, -0.3994],
# [-0.0575, 1.0633, 0.0104, -1.1750],
# [ 0.9005, 0.5154, 0.2212, 2.0248]])
# (tensor([[-1.1775, -0.4398, -0.7885, -0.3994],
# [-0.0575, 1.0633, 0.0104, -1.1750]]),
# tensor([[0.9005, 0.5154, 0.2212, 2.0248]]))
print(torch.chunk(a,2, 0))
# tensor([[-1.1775, -0.4398, -0.7885, -0.3994],
# [-0.0575, 1.0633, 0.0104, -1.1750],
# [ 0.9005, 0.5154, 0.2212, 2.0248]])
# (tensor([[-1.1775, -0.4398, -0.7885, -0.3994],
# [-0.0575, 1.0633, 0.0104, -1.1750]]),
# tensor([[0.9005, 0.5154, 0.2212, 2.0248]]))
print(torch.chunk(a,2, 1))
# (tensor([[-1.1775, -0.4398],
# [-0.0575, 1.0633],
# [ 0.9005, 0.5154]]),
# tensor([[-0.7885, -0.3994],
# [ 0.0104, -1.1750],
# [ 0.2212, 2.0248]]))
gather函数从一个张量中收集元素,并使用索引参数将其放到另一个张量中。指标位置由PyTorch中的LongTensor张量函数确定。
# input(tensor): 待操作数。不妨设其维度为(x1, x2, …, xn)
# dim(int): 待操作的维度。
# index(LongTensor): 如何对input进行操作。其维度有限定,例如当dim=i时,# index的维度为(x1, x2, …y, …,xn),既是将input的第i维的大小更改为y,且
# 要满足y>=1(除了第i维之外的其他维度,大小要和input保持一致)。
# out: 注意输出和index的维度是一致的
# out[i][j][k] = input[index[i][j][k]][j][k] # if dim == 0
# out[i][j][k] = input[i][index[i][j][k]][k] # if dim == 1
# out[i][j][k] = input[i][j][index[i][j][k]] # if dim == 2
import torch
x = torch.Tensor([[11,12],[23,24]])
print(x)
y = torch.gather(x, 1, torch.LongTensor([[0,0],[1,0]]))
print(y)
# tensor([[11., 12.],
# [23., 24.]])
# tensor([[11., 11.],
# [24., 23.]])
LongTensor张量函数或index选择函数可用于从张量获取相关值。下面的示例代码显示了两个选项:沿行选择和沿列选择。如果第二个参数为0,则它用于行。如果它是1,那么它沿着列。
import torch
a = torch.randn(4, 4)
print(a)
indices=torch.LongTensor([0,2])
print(torch.index_select(a,0,indices))
# tensor([[-0.5025, 0.4290, -1.6302, 0.1779],
# [ 2.6009, 0.1825, -0.6760, 1.2428],
# [ 0.7389, -0.3886, 0.3135, 1.5179],
# [-0.5978, -1.2262, 1.0765, -0.0700]])
# tensor([[-0.5025, 0.4290, -1.6302, 0.1779],
# [ 0.7389, -0.3886, 0.3135, 1.5179]])
print(torch.index_select(a,1,indices))
# tensor([[-0.5025, -1.6302],
# [ 2.6009, -0.6760],
# [ 0.7389, 0.3135],
# [-0.5978, 1.0765]])
检查张量中的非零元素是一种常见的方法,其目的是确定一个张量中的非零元素。
import torch
print(torch.nonzero(torch.tensor([10,00,23,0,0.0])))
# tensor([[0],
# [2]])
print(torch.nonzero(torch.Tensor([10,00,23,0,0.0])))
# tensor([[0],
# [2]])
将输入张量重构为更小的张量不仅可以简化计算过程,而且有助于分布式计算。split函数把一个张量分裂成更小的张量。
import torch
print(torch.split(torch.tensor([12,23,34,56,78,78,89]), 2))
# (tensor([12, 23]), tensor([34, 56]), tensor([78, 78]), tensor([89]))
print(torch.split(torch.tensor([12,23,34,56,78,78,89]), 3))
# (tensor([12, 23, 34]), tensor([56, 78, 78]), tensor([89]))
现在,让我们看一个例子,看看输入张量如何在计算困难的情况下调整大小。转置函数主要用于重塑张量。转置函数有两种写法.t和.transpose 。
import torch
x = torch.randn(2, 3)
print(x)
print(x.t())
print(x.transpose(1,0))
# tensor([[ 0.7303, -0.5896, -0.5453],
# [-0.3005, -0.3102, -1.3666]])
# tensor([[ 0.7303, -0.3005],
# [-0.5896, -0.3102],
# [-0.5453, -1.3666]])
# tensor([[ 0.7303, -0.3005],
# [-0.5896, -0.3102],
# [-0.5453, -1.3666]])
解绑定函数从张量中除去一个维数。要删除维度行,需要传递0值。要删除列,需要传递1值。
import torch
x = torch.randn(2, 3)
print(x)
print(torch.unbind(x,1))
# tensor([[ 0.8387, 0.3207, -0.1184],
# [-1.0266, -1.1429, -0.4148]])
# (tensor([ 0.8387, -1.0266]),
# tensor([ 0.3207, -1.1429]),
# tensor([-0.1184, -0.4148]))
print(torch.unbind(x,0))
# (tensor([ 0.8387, 0.3207, -0.1184]),
# tensor([-1.0266, -1.1429, -0.4148]))
算術運算
import torch
x = torch.randn(2, 3)
print(x)
print(torch.add(x, 20))
# tensor([[ 0.2973, 0.0619, -0.8902],
# [-0.5823, 1.7563, -0.7741]])
# tensor([[20.2973, 20.0619, 19.1098],
# [19.4177, 21.7563, 19.2259]])
print(torch.mul(x,2))
# tensor([[ 0.5946, 0.1237, -1.7804],
# [-1.1646, 3.5126, -1.5481]])
组合数学运算,例如将线性方程表示为张量运算,可以使用下面的示例脚本完成。这里我们将结果y表示为值乘以独立的x的线性组合,加上常数项。
import torch
intercept = torch.randn(1)
print(intercept)
x = torch.randn(2,2)
print(x)
beta=0.7
# OUTPUT=Constant + (beta*Independent)
print(torch.mul(intercept,x))
# y = intercept + (beta * x)
print(torch.add(intercept, torch.mul(x,beta)))
# tensor([-2.4064])
# tensor([[ 0.5145, 0.3955],
# [ 2.8828, -1.9659]])
# tensor([[-1.2381, -0.9517],
# [-6.9371, 4.7307]])
# tensor([[-2.0462, -2.1295],
# [-0.3884, -3.7825]])
与NumPy操作一样,张量必须通过使用ceiling或flooring函数进行四舍五入。
import torch
torch.manual_seed(1234)
x = torch.randn(5,5)
print(x)
# tensor([[-0.1117, -0.4966, 0.1631, -0.8817, 0.0539],
# [ 0.6684, -0.0597, -0.4675, -0.2153, -0.7141],
# [-1.0831, -0.5547, 0.9717, -0.5150, 1.4255],
# [ 0.7987, -1.4949, 1.4778, -0.1696, -0.9919],
# [-1.4569, 0.2563, -0.4030, 0.4195, 0.9380]])
torch.manual_seed(1234)
x = torch.ceil(torch.randn(5,5))
print(x)
# tensor([[-0., -0., 1., -0., 1.],
# [ 1., -0., -0., -0., -0.],
# [-1., -0., 1., -0., 2.],
# [ 1., -1., 2., -0., -0.],
# [-1., 1., -0., 1., 1.]])
torch.manual_seed(1234)
x = torch.floor(torch.randn(5,5))
print(x)
# tensor([[-1., -1., 0., -1., 0.],
# [ 0., -1., -1., -1., -1.],
# [-2., -1., 0., -1., 1.],
# [ 0., -2., 1., -1., -1.],
# [-2., 0., -1., 0., 0.]])
在一定范围内限制任何张量的值可以使用最小和最大参数以及使用clamp函数来完成。下面的示例显示了2D场景中的实现。
import torch
torch.manual_seed(1234)
y = torch.clamp(torch.floor(torch.randn(5,5)), min=0.3, max=0.4)
print(y)
# tensor([[0.3000, 0.3000, 0.3000, 0.3000, 0.3000],
# [0.3000, 0.3000, 0.3000, 0.3000, 0.3000],
# [0.3000, 0.3000, 0.3000, 0.3000, 0.4000],
# [0.3000, 0.3000, 0.4000, 0.3000, 0.3000],
# [0.3000, 0.3000, 0.3000, 0.3000, 0.3000]])
torch.manual_seed(1234)
y = torch.clamp(torch.floor(torch.randn(5,5)), min=0.3)
print(y)
# tensor([[0.3000, 0.3000, 0.3000, 0.3000, 0.3000],
# [0.3000, 0.3000, 0.3000, 0.3000, 0.3000],
# [0.3000, 0.3000, 0.3000, 0.3000, 1.0000],
# [0.3000, 0.3000, 1.0000, 0.3000, 0.3000],
# [0.3000, 0.3000, 0.3000, 0.3000, 0.3000]])
torch.manual_seed(1234)
y = torch.clamp(torch.floor(torch.randn(5,5)), max=0.3)
print(y)
# tensor([[-1.0000, -1.0000, 0.0000, -1.0000, 0.0000],
# [ 0.0000, -1.0000, -1.0000, -1.0000, -1.0000],
# [-2.0000, -1.0000, 0.0000, -1.0000, 0.3000],
# [ 0.0000, -2.0000, 0.3000, -1.0000, -1.0000],
# [-2.0000, 0.0000, -1.0000, 0.0000, 0.0000]])
我们如何得到一个张量的指数?如果张量有小数位,我们如何得到它的小数部分并且被定义为浮点数据类型?
import torch
torch.manual_seed(1234)
x = torch.randn(2,3)
print(x)
# tensor([[ 0.0461, 0.4024, -1.0115],
# [ 0.2167, -0.6123, 0.5036]])
print(torch.exp(x))
# tensor([[1.0472, 1.4954, 0.3637],
# [1.2420, 0.5421, 1.6547]])
import numpy as np
print(np.exp(x))
# tensor([[1.0472, 1.4954, 0.3637],
# [1.2420, 0.5421, 1.6547]])
print(np.exp(np.array(x)))
# [[1.0472, 1.4954, 0.3637],
# [1.2420, 0.5421, 1.6547]]
print(torch.add(x,10))
# tensor([[10.0461, 10.4024, 8.9885],
# [10.2167, 9.3877, 10.5036]])
print(torch.frac(torch.add(x,10)))
# tensor([[0.0461, 0.4024, 0.9885],
# [0.2167, 0.3877, 0.5036]])
下面的语法解释了张量中的对数值。带负号的值被转换为nan。幂函数计算张量中任意值的指数。
import torch
torch.manual_seed(1234)
x = torch.randn(2,3)
print(x)
print(torch.log(x))
print(torch.pow(x,2))
# tensor([[ 0.0461, 0.4024, -1.0115],
# [ 0.2167, -0.6123, 0.5036]])
# tensor([[-3.0763, -0.9103, nan],
# [-1.5291, nan, -0.6860]])
# tensor([[0.0021, 0.1619, 1.0232],
# [0.0470, 0.3749, 0.2536]])
为了计算变换函数(即s形、双曲正切、径向基函数等,它们是深度学习中最常用的传递函数),你必须构造张量。下面的示例脚本展示了如何创建一个s形函数并将其应用于一个张量。
import torch
torch.manual_seed(1234)
x = torch.randn(2,3)
print(x)
# tensor([[ 0.0461, 0.4024, -1.0115],
# [ 0.2167, -0.6123, 0.5036]])
print(torch.sigmoid(x))
# tensor([[0.5115, 0.5993, 0.2667],
# [0.5540, 0.3515, 0.6233]])
print(torch.sqrt(x))
# tensor([[0.2148, 0.6344, nan],
# [0.4656, nan, 0.7097]])
对于有PyTorch和Python经验的人来说,本章是复习。但是本章对新入行人来说,是学习PyTorch框架的的基本组成部分。在开始高级主题之前,熟悉术语和基本语法是很重要的。下一章将介绍如何使用PyTorch实现概率模型,其中包括创建随机变量、应用统计分布和进行统计推断。