PyTorch 的重要组成部分是张量类(Tensor),即N 维数组。
张量是数学中的概念,可以理解为:list是张量在计算机中实现的一种数据结构
引入方式:
它与 Numpy 的 ndarray 类似,然而却能够得到GPU的支持加速计算,并且能支持自动微分。
它包含 data 、 grad(属于 Tensor)

取 Tensor 中的 data,就避免建立计算图(不再计算梯度);同样,取 Tensor 的 grad.item(),也能够避免建立计算图
入门
创建
创建行向量,除非额外指定,否则新张量存储在内存中,并采用基于CPU的计算
在深度学习中,浮点数尽量使用32位
1 2 3 4 5 6
| x = torch.arange(15) print(x)
y = torch.tensor([[2, 1, 4, 3], [0, -2, 3, 4]]) print(y)
|
1 2 3
| tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]) tensor([[ 2, 1, 4, 3], [ 0, -2, 3, 4]])
|
使用全0、全1、其他常量或者从特定分布中随机采样的数字来初始化矩阵:
1 2 3
| print(torch.zeros((2, 3, 4))) print(torch.ones((1, 5))) print(torch.zeros_like(x))
|
1 2 3 4 5 6 7 8 9
| tensor([[[0., 0., 0., 0.], [0., 0., 0., 0.], [0., 0., 0., 0.]],
[[0., 0., 0., 0.], [0., 0., 0., 0.], [0., 0., 0., 0.]]]) tensor([[1., 1., 1., 1., 1.]])
|
创建张量,其每个元素满足都从均值为0、标准差为1的标准高斯分布中随机采样:
1 2
| tensor([[ 0.1094, 0.1251, -0.0131], [ 0.9402, -1.3864, 0.8064]])
|
张量的拷贝,能够使用 .clone(),该方法能够分配新内存,将下面的A 分配给B
1 2 3 4
| A = torch.arange(20, dtype=torch.float32).reshape(5, 4) B = A.clone() A[3][3] = 666666 A, B
|
1 2 3 4 5 6 7 8 9 10
| (tensor([[0.0000e+00, 1.0000e+00, 2.0000e+00, 3.0000e+00], [4.0000e+00, 5.0000e+00, 6.0000e+00, 7.0000e+00], [8.0000e+00, 9.0000e+00, 1.0000e+01, 1.1000e+01], [1.2000e+01, 1.3000e+01, 1.4000e+01, 6.6667e+05], [1.6000e+01, 1.7000e+01, 1.8000e+01, 1.9000e+01]]), tensor([[ 0., 1., 2., 3.], [ 4., 5., 6., 7.], [ 8., 9., 10., 11.], [12., 13., 14., 15.], [16., 17., 18., 19.]]))
|
形状
向量的长度,又称向量的维度,可通过Python内置 len() 来访问:
1 2
| a = torch.arange(3) a, len(a)
|
改变张量的形状而不改变元素数量和元素值:reshape()
1 2 3
| ttt = torch.arange(24).reshape(2, 4, 3) ttt.shape, ttt.size(), ttt.numel()
|
1
| torch.Size([2, 4, 3]), torch.Size([2, 4, 3]), 24
|
⭐.numel() 十分常用!
⭐张量在给出其他部分维度数据后能够传入参数 -1 ,自动计算出另一个维度:
1 2
| X = x.reshape(-1, 4) Y = x.reshape(3, -1)
|
索引与切片
通过指定数组下标索引,能够对元素进行读写操作
1 2 3 4 5 6
| x = torch.arange(15).reshape(3, 5) x[0:2, :] = 23333 x[0, 2] = 66666 print(x) print(x[-1]) print(x[1:3])
|
tensor([[23333, 23333, 23333, 23333, 23333],
[23333, 23333, 23333, 23333, 23333],
[ 10, 11, 12, 13, 14]])
tensor([10, 11, 12, 13, 14])
tensor([[23333, 23333, 23333, 23333, 23333],
[ 10, 11, 12, 13, 14]])
基本运算
标准算术运算符(+、-、*、/、**)均升级为按元素运算 ,即运算符应用于数组中每一个元素。
对于将两个数组作为输⼊的函数,按元素运算将⼆元运算符应⽤于两个数组中的每对位置对应的元素
1 2 3
| x = torch.tensor([1, 9.3232, -3, 0]) y = torch.tensor([8, -2, -3, -3.4]) x + y, x / y, x ** y, x == y
|
(tensor([ 9.0000, 7.3232, -6.0000, -3.4000]),
tensor([ 0.1250, -4.6616, 1.0000, -0.0000]),
tensor([ 1.0000, 0.0115, -0.0370, inf]),
tensor([False, False, True, False]))
当两个张量的形状不同,会调用广播机制(broadcasting mechansim)来执行按元素操作:
1 2 3 4 5
| a = torch.arange(3).reshape((3, 1)) b = torch.arange(2).reshape((1, 2)) print(a) print(b) print(a + b)
|
tensor([[0],
[1],
[2]])
tensor([[0, 1]])
tensor([[0, 1],
[1, 2],
[2, 3]])
此外,还能够调用其他方法进行初等运算
tensor([2.7183e+00, 1.1195e+04, 4.9787e-02, 1.0000e+00]), tensor(7.3232)
矩阵运算
通过两个分量m 和n 来创建一个形状为m×n 的矩阵,通过 .T 即可获得矩阵的转置
若B=AT,则对于任意的i 和j ,都有bij=aji
1 2
| tmp = torch.arange(16).reshape(4, 4) tmp, tmp.T, tmp.T == tmp
|
1 2 3 4 5 6 7 8 9 10 11 12
| tensor([[ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11], [12, 13, 14, 15]]) tensor([[ 0, 4, 8, 12], [ 1, 5, 9, 13], [ 2, 6, 10, 14], [ 3, 7, 11, 15]]) tensor([[ True, False, False, False], [False, True, False, False], [False, False, True, False], [False, False, False, True]])
|
两个矩阵的按元素乘法,称为 哈达玛积(数学符号为⊙)
1 2 3 4 5
| a = torch.arange(6).reshape(2, 3) b = torch.tensor([[3, 5, 3], [9, -3, 0]]) x = -1 a * b, a + x, (a * x).shape
|
1 2 3 4 5
| tensor([[ 0, 5, 6], [ 27, -12, 0]]), tensor([[-1, 0, 1], [ 2, 3, 4]]), torch.Size([2, 3])
|
点积(Dot Product),对于向量而言,即在相同位置上按元素乘积并在最后进行求和,即:
两个向量x,y∈Rd,xTy=∑idxiyi
1 2 3
| x = torch.tensor([0., 1., 2, -9]) y = torch.ones(4, dtype = torch.float32) x, y, torch.dot(x, y)
|
1
| tensor([ 0., 1., 2., -9.]), tensor([1., 1., 1., 1.]), tensor(-6.)
|
两个矩阵进行矩阵-矩阵乘法(matrix-matrix multiplication),简称为矩阵乘法,可使用 .mm():
1 2 3
| A = torch.arange(16, dtype=torch.float32).reshape(4, 4) B = torch.ones(4, 3) A, B, torch.mm(A, B)
|
1 2 3 4 5 6 7 8 9 10 11 12
| tensor([[ 0., 1., 2., 3.], [ 4., 5., 6., 7.], [ 8., 9., 10., 11.], [12., 13., 14., 15.]]), tensor([[1., 1., 1.], [1., 1., 1.], [1., 1., 1.], [1., 1., 1.]]), tensor([[ 6., 6., 6.], [22., 22., 22.], [38., 38., 38.], [54., 54., 54.]])
|
降维
默认情况下,调用求和函数 .sum() 会沿所有的轴降低张量的维度,使它变为一个标量。
此外,我们可以指定张量沿哪一个轴来通过求和降低维度,指定 axis 等于多少,则相当于使该张量在该轴的维数在输出形状中消失。

1 2 3 4 5 6 7 8 9 10
| b_sum_0 = b.sum(axis = 0)
b_sum_1 = b.sum(axis = 1)
b_sum_kpt = b.sum(axis = 1, keepdims = True)
b, b_sum_0, b_sum_1, b_sum_kpt, b / b_sum_kpt
|
1 2 3 4 5 6 7 8
| tensor([[ 3, 5, 3], [ 9, -3, 0]]), tensor([12, 2, 3]), tensor([11, 6]), tensor([[11], [ 6]]), tensor([[ 0.2727, 0.4545, 0.2727], [ 1.5000, -0.5000, 0.0000]])
|
范数
L2范数是向量元素平方和的平方根:
∥x∥2=i=1∑nxi2
L1范数是向量元素的绝对值之和:
∥x∥1=i=1∑n∣xi∣
对于矩阵而言,弗罗贝尼乌斯范数,是矩阵元素的平方和的平方根(类似于L2范数):
∥X∥F=i=1∑mj=1∑nxij2
1 2 3 4
| u = torch.tensor([3.0, -4.0]) print(torch.norm(u)) print(torch.abs(u).sum()) print(torch.norm(torch.ones(2, 3)))
|
1 2 3
| tensor(5.) tensor(7.) tensor(2.4495)
|
连接
将多个张量连接在一起,即将其端对端地叠起来形成一个更大的张量
1 2 3 4 5 6 7 8
| x = torch.arange(12, dtype = torch.float32).reshape((3, 4)) print(x) y = torch.tensor([[2, 0, 4, 3], [1, 2, 3, 4], [2, -3, 2, 0]]) print(y) torch.cat((x, y), dim = 0), torch.cat((x, y), dim = 1)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| tensor([[ 0., 1., 2., 3.], [ 4., 5., 6., 7.], [ 8., 9., 10., 11.]]) tensor([[ 2, 0, 4, 3], [ 1, 2, 3, 4], [ 2, -3, 2, 0]]) tensor([[ 0., 1., 2., 3.], [ 4., 5., 6., 7.], [ 8., 9., 10., 11.], [ 2., 0., 4., 3.], [ 1., 2., 3., 4.], [ 2., -3., 2., 0.]]), tensor([[ 0., 1., 2., 3., 2., 0., 4., 3.], [ 4., 5., 6., 7., 1., 2., 3., 4.], [ 8., 9., 10., 11., 2., -3., 2., 0.]])
|
转换为其他Python对象
Tensor与Numpy张量的转换:
1 2 3
| q = x.numpy() p = torch.tensor(q) type(q), type(p)
|
(numpy.ndarray, torch.Tensor)
将大小为1的张量转化Python的标量,可以调用 item() 或者 Python的内置函数
1 2
| tmp = torch.tensor([2.33333]) tmp, tmp.item(), float(tmp)
|
(tensor([2.3333]), 2.333329916000366, 2.333329916000366)
⭐.item() 十分常用
数据预处理
创建数据集
创建一个人工数据集,并存储在CSV(逗号分隔值)文件
1 2 3 4 5 6 7 8 9
| import os os.makedirs(os.path.join('..', 'data'), exist_ok=True) data_file = os.path.join('..', 'data', 'house_tiny.csv') with open(data_file, 'w') as f: f.write('NumRooms,Alley,Price\n') f.write('NA,Pave,127500\n') f.write('2,NA,106000\n') f.write('4,NA,178100\n') f.write('NA,NA,140000\n')
|
读取数据集
从创建的CSV文件中加载原始数据集,可以通过 pandas 包调用 read_csv 函数
1 2
| import pandas as pd data = pd.read_csv(data_file)
|
为处理缺失(NaN项)的数据,方法有:插值(即用替代值来代替缺失值)、删除(忽略缺失值)
批量加载数据集⭐
在机器学习中,若要使用批量随机梯度下降法(SGD),使用数据加载器是必不可少的,它能够按照需要批量地加载数据至内存,而不是直接加载数据集所有数据。

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| import torch from torch.utils.data import Dataset from torch.utils.data import DataLoader
class DiabetesDataset(Dataset): def __init__(self, filepath): xy = np.loadtxt(filepath, delimiter=',', dtype=np.float32) self.len = xy.shape[0] self.x_data = torch.from_numpy(xy[:, :-1]) self.y_data = torch.from_numpy(xy[:, [-1]]) def __getitem__(self, index): return self.x_data[index], self.y_data[index] def __len__(self): return self.len dataset = DiabetesDataset('...') train_loader = DataLoader(dataset = dataset, batch_size=32, shuffle=True, num_workers=2)
|
如何通过 DataLoader 遍历数据集所有数据 ?
1 2 3 4 5 6
| next(iter(train_loader))
for i, data in enumerate (train_loader, 0):
|
enumerate() 能将可遍历的数据对象组合为一个带索引的序列,即同时返回数据和数据下标。此外,通过其下标索引,还能够批量修改列表内的元素
若要使用一些标准数据集,如MNIST、Fashion-MNIST等,可通过PyTorch框架中的内置函数将其下载并读取到内存中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| batch_size = 64
train_dataset = datasets.MNIST(root = '../dataset/mnist/', train= True, download = True, transform = transform) test_dataset = datasets.MNIST(root = '../dataset/mnist', train = False, download = True, transform = transform) train_loader = DataLoader(train_dataset, shuffle = True, batch_size = batch_size) test_loader = DataLoader(test_dataset, shuffle = False, batch_size = batch_size)
|