外观
pytorch 张量
介绍
pytorch 是深度学习的框架,Python 的第三方包,数据以张量形式存在。
张量可以看作是矩阵,涵盖了常数、向量、矩阵等对象。深度学习中,数据都是通过张量表示的,无论是常数、向量,还是矩阵。
张量创建
torch.tensor(data, dtype, device): 根据数据创建张量,不能指定维度。torch.Tensor(data, size): 可以指定数据或形状创建张量。torch.IntTensor(data)、torch.FloatTensor():指定类型。
import torch
import numpy as np
list1 = [[1, 2, 3], [4, 5, 6]]
t1 = torch.tensor(list1)
print(t1, type(t1))
# tensor([[1, 2, 3],
# [4, 5, 6]]) <class 'torch.Tensor'>
int1 = 10
t2 = torch.tensor(int1)
print(t2, type(t2)) # tensor(10) <class 'torch.Tensor'>
n1 = np.array([[1., 2., 3.], [4., 5., 6.]])
t3 = torch.tensor(n1)
print(t3, type(t3))
# tensor([[1., 2., 3.],
# [4., 5., 6.]], dtype=torch.float64) <class 'torch.Tensor'>
t4 = torch.Tensor(list1)
print(t4, type(t4))
# tensor([[1., 2., 3.],
# [4., 5., 6.]]) <class 'torch.Tensor'>
t5 = torch.Tensor(size=(2, 3))
print(t5, type(t5))
# tensor([[-2.2507e+12, 1.4111e-42, 0.0000e+00],
# [ 0.0000e+00, 0.0000e+00, 0.0000e+00]]) <class 'torch.Tensor'>
t6 = torch.IntTensor([[1.1, 2, 3.7], [4, 5, 6]])
print(t6, type(t6))
# tensor([[1, 2, 3],
# [4, 5, 6]], dtype=torch.int32) <class 'torch.Tensor'>
t7 = torch.FloatTensor([[1.1, 2, 3.7], [4, 5, 6]])
print(t7, type(t7))
# tensor([[1.1000, 2.0000, 3.7000],
# [4.0000, 5.0000, 6.0000]]) <class 'torch.Tensor'>线性和随机张量
torch.arange(start=, end=, step=):创建指定步长的线性张量,左闭右开。torch.linspace(start=, end=, steps=):创建指定元素个数的线性张量,左闭右闭。torch.rand(size=)/randn(size=):创建指定形状的随机浮点类型张量。torch.randint(low=, high=, size=):创建指定形状指定范围随机整数类型张量,左闭右开。
import torch
t1 = torch.arange(0, 10, 2)
print(t1, type(t1)) # tensor([0, 2, 4, 6, 8]) <class 'torch.Tensor'>
t2 = torch.linspace(0, 10, 5)
print(t2, type(t2))
# tensor([ 0.0000, 2.5000, 5.0000, 7.5000, 10.0000]) <class 'torch.Tensor'>
t3 = torch.rand(size=(2, 1))
print(t3, type(t3))
# tensor([[0.3208],
# [0.5004]]) <class 'torch.Tensor'>
t4 = torch.randint(0, 10, (2, 3))
print(t4, type(t4))
# tensor([[9, 3, 4],
# [8, 7, 8]]) <class 'torch.Tensor'>0/1/指定值张量
torch.ones(size=):创建全 1 张量。torch.zeros(size=):创建全 0 张量。torch.full(size=, fill_value=):创建指定值张量。torch.ones_like(input=tensor):创建与输入张量形状相同的全 1 张量。torch.zeros_like(input=tensor):创建与输入张量形状相同的全 0 张量。torch.full_like(input=tensor, fill_value=):创建与输入张量形状相同的指定值张量。
import torch
t1 = torch.ones(size=(2, 3))
print(t1, type(t1))
# tensor([[1., 1., 1.],
# [1., 1., 1.]]) <class 'torch.Tensor'>
t2 = torch.zeros(size=(2, 3))
print(t2, type(t2))
# tensor([[0., 0., 0.],
# [0., 0., 0.]]) <class 'torch.Tensor'>
t3 = torch.full(size=(2, 3), fill_value=5)
print(t3, type(t3))
# tensor([[5, 5, 5],
# [5, 5, 5]]) <class 'torch.Tensor'>
t4 = torch.zeros_like(t1)
print(t4, type(t4))
# tensor([[0., 0., 0.],
# [0., 0., 0.]]) <class 'torch.Tensor'>
t5 = torch.full_like(t1, fill_value=8)
print(t5, type(t5))
# tensor([[8., 8., 8.],
# [8., 8., 8.]]) <class 'torch.Tensor'>指定元素类型张量
tensor.type(dtype):返回指定数据类型的张量。tensor.half():转换为float16类型张量。tensor.float():转换为float32类型张量。tensor.double():转换为float64类型张量。tensor.short():转换为int16类型张量。tensor.int():转换为int32类型张量。tensor.long():转换为int64类型张量。
import torch
t1 = torch.tensor([[1, 2], [3, 4]])
print(t1, t1.dtype) # tensor([[1, 2],[3, 4]]) torch.int64
t2 = t1.float()
print(t2, t2.dtype) # tensor([[1., 2.],[3., 4.]]) torch.float32
t3 = t1.double()
print(t3, t3.dtype) # tensor([[1., 2.],[3., 4.]]) torch.float64
t4 = t1.half()
print(t4, t4.dtype) # tensor([[1., 2.],[3., 4.]], dtype=torch.float16)
t5 = t1.short()
print(t5, t5.dtype) # tensor([[1, 2],[3, 4]], dtype=torch.int16)
t6 = t1.int()
print(t6, t6.dtype) # tensor([[1, 2],[3, 4]], dtype=torch.int32)
t7 = t1.long()
print(t7, t7.dtype) # tensor([[1, 2],[3, 4]], dtype=torch.int64)
half指的是 16 位浮点数类型,也就是float16。
张量类型转换
与 NumPy 的互相转化
张量 → NumPy
tensor.numpy():转换为 NumPy 数组,共享内存,修改一个会影响另一个。tensor.numpy().copy():生成不共享内存的副本。
NumPy → 张量
torch.from_numpy(ndarray):NumPy 数组转换为张量,共享内存。torch.tensor(data=ndarray):NumPy 数组转换为张量,不共享内存。
import torch
import numpy as np
# 张量转换为 NumPy
t1 = torch.tensor([[1, 2, 3], [4, 5, 6]])
print('t1->', t1)
n1 = t1.numpy().copy() # 不共享内存
print('n1->', n1)
print('n1类型->', type(n1))
n1[0][0] = 100
print('n1修改后->', n1)
print('t1->', t1)
# NumPy 转换为张量
n2 = np.array([[1, 2, 3], [4, 5, 6]])
t2 = torch.from_numpy(n2) # 共享内存
# t2 = torch.tensor(n2) # 不共享内存
print('t2->', t2)
print('t2类型->', type(t2))
t2[0][0] = 8888
print('t2修改后->', t2)
print('n2->', n2)提取标量张量的数值
tensor.item():提取 单元素张量 的数值。- 张量可以是 标量 / 一维 / 二维 / 多维,只要 元素数量为 1 即可使用。
import torch
# 标量张量
t1 = torch.tensor(10)
print(t1) # tensor(10)
print(t1.shape) # torch.Size([])
print(t1.item()) # 10
# 一维单元素张量
t2 = torch.tensor([10])
print(t2) # tensor([10])
print(t2.shape) # torch.Size([1])
print(t2.item()) # 10
# 二维单元素张量
t3 = torch.tensor([[10]])
print(t3) # tensor([[10]])
print(t3.shape) # torch.Size([1, 1])
print(t3.item()) # 10张量的运算
基本运算
+ - * / -:张量支持基本算术运算。tensor/torch.add():加法。tensor/torch.sub():减法。tensor/torch.mul():乘法。tensor/torch.div():除法。tensor/torch.neg():取负。tensor.add_():原地加法。tensor.sub_():原地减法。tensor.mul_():原地乘法。tensor.div_():原地除法。tensor.neg_():原地取负。
import torch
t1 = torch.tensor([1, 2, 3])
t2 = torch.tensor([4, 5, 6])
# 基本运算
print(t1 + t2) # tensor([5, 7, 9])
print(t1 - t2) # tensor([-3, -3, -3])
print(t1 * t2) # tensor([ 4, 10, 18])
print(t1 / t2) # tensor([0.2500, 0.4000, 0.5000])
# 函数形式
print(torch.add(t1, t2)) # tensor([5, 7, 9])
print(torch.sub(t1, t2)) # tensor([-3, -3, -3])
print(torch.mul(t1, t2)) # tensor([ 4, 10, 18])
print(torch.div(t1, t2)) # tensor([0.2500, 0.4000, 0.5000])
print(torch.neg(t1)) # tensor([-1, -2, -3])
# 原地运算
t3 = torch.tensor([1, 2, 3])
t3.add_(1)
print(t3) # tensor([2, 3, 4])点乘运算(逐元素乘)
*:张量对应位置元素相乘(逐元素乘)。torch.mul():逐元素乘函数形式。tensor.mul():逐元素乘方法形式。- 一般要求 张量形状相同,或者满足 广播机制(broadcasting)。
- 返回的新张量形状与参与计算的张量一致。
import torch
t1 = torch.tensor([[1, 2, 3],
[4, 5, 6]])
t2 = torch.tensor([[10, 20, 30],
[40, 50, 60]])
# 运算符形式
t3 = t1 * t2
print(t3)
# tensor([[ 10, 40, 90],
# [160, 250, 360]])
# 函数形式
t4 = torch.mul(t1, t2)
print(t4)
# tensor([[ 10, 40, 90],
# [160, 250, 360]])
# 方法形式
t5 = t1.mul(t2)
print(t5)
# tensor([[ 10, 40, 90],
# [160, 250, 360]])矩阵乘法运算
@:矩阵乘法运算符。torch.matmul():矩阵乘法函数形式。tensor.matmul():矩阵乘法方法形式。torch.mm():二维矩阵乘法。- 计算规则:第一个矩阵的 行 与第二个矩阵的 列 进行乘法并求和。
- 维度要求:
(m × n) · (n × p) → (m × p),即第一个矩阵的列数必须等于第二个矩阵的行数。
import torch
t1 = torch.tensor([[1, 2, 3],
[4, 5, 6]])
t2 = torch.tensor([[1, 2],
[3, 4],
[5, 6]])
# 运算符形式
t3 = t1 @ t2
print(t3)
# tensor([[22, 28],
# [49, 64]])
# 函数形式
t4 = torch.matmul(t1, t2)
print(t4)
# tensor([[22, 28],
# [49, 64]])
# 二维矩阵乘法
t5 = torch.mm(t1, t2)
print(t5)
# tensor([[22, 28],
# [49, 64]])统计与数学运算
tensor.mean():计算张量所有元素的平均值。tensor.sum():计算张量所有元素的和。tensor.min()/tensor.max():计算最小值 / 最大值。dim=:按指定维度进行计算。tensor.exp():指数运算 (e^x)。tensor.sqrt():平方根。tensor.pow():幂次方。tensor.log()/tensor.log2()/tensor.log10():对数运算。
import torch
t1 = torch.tensor([[1., 2., 3.],
[4., 5., 6.]])
print(t1.mean()) # tensor(3.5000)
print(t1.sum()) # tensor(21.)
print(t1.min()) # tensor(1.)
print(t1.max()) # tensor(6.)
# 按维度计算
print(t1.sum(dim=0)) # tensor([5., 7., 9.])
print(t1.sum(dim=1)) # tensor([ 6., 15.])
# 数学运算
print(t1.exp())
# tensor([[ 2.7183, 7.3891, 20.0855],
# [ 54.5982, 148.4132, 403.4288]])
print(t1.sqrt())
# tensor([[1.0000, 1.4142, 1.7321],
# [2.0000, 2.2361, 2.4495]])
print(t1.pow(2))
# tensor([[ 1., 4., 9.],
# [16., 25., 36.]])
print(t1.log())
print(t1.log2())
print(t1.log10())张量索引操作
张量下标 从左到右从 0 开始,从右到左从 -1 开始。
多维张量索引格式:data[行下标, 列下标]。
更高维张量:data[0轴下标, 1轴下标, 2轴下标]。
data[i]:取第i行。data[:, j]:取第j列。data[[...], [...]]:按索引列表取值。data[条件]:按布尔条件筛选。data[start:end:step]:切片取值。
import torch
torch.manual_seed(0)
# 创建张量
data = torch.randint(0, 10, (4, 5))
print('data->', data)
# 行数据(第一行)
print('data[0]->', data[0])
# 列数据(第一列)
print('data[:,0]->', data[:, 0])
# 根据下标列表取值
# 第二行第三列 和 第四行第五列
print('data[[1,3],[2,4]]->', data[[1, 3], [2, 4]])
# 组合索引
print('data[[[1],[3]],[2,4]]->', data[[[1], [3]], [2, 4]])
# 布尔索引
# 第二列大于6的所有行
print(data[:, 1] > 6)
print('data[data[:,1]>6]->', data[data[:, 1] > 6])
# 第三行大于6的列
print('data[:,data[2]>6]->', data[:, data[2] > 6])
# 切片
# 第一行第三行 + 第二列第四列
print('data[::2,1::2]->', data[::2, 1::2])
# 三维张量
data2 = torch.randint(0, 10, (3, 4, 5))
print('data2->', data2)
# 0轴第一个
print(data2[0, :, :])
# 1轴第一个
print(data2[:, 0, :])
# 2轴第一个
print(data2[:, :, 0])张量的形状操作
reshape
用于 重新调整张量形状,元素总数必须保持一致。
tensor.reshape(shape):返回新的张量,自动判断是否需要复制数据。- 可以使用
-1自动推断某一维大小。 - 不要求张量必须是 内存连续。
demo.py
import torch
# 创建张量
t = torch.arange(12)
print("t->", t)
print("shape->", t.shape)
# 改变形状
t2 = t.reshape(3, 4)
print("reshape(3, 4)->")
print(t2)
print("shape->", t2.shape)
# 使用 -1 自动推断维度
t3 = t.reshape(3, -1)
print("reshape(3, -1)->")
print(t3)
print("shape->", t3.shape)运行结果.txt
t-> tensor([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])
shape-> torch.Size([12])
reshape(3, 4)->
tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
shape-> torch.Size([3, 4])
reshape(3, -1)->
tensor([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
shape-> torch.Size([3, 4])squeeze / unsqueeze
用于 删除或增加维度,常用于处理批次维度或通道维度。
tensor.squeeze():删除所有 大小为 1 的维度。tensor.squeeze(dim):删除指定维度(该维度必须为1)。tensor.unsqueeze(dim):在指定位置 增加一个维度。
demo.py
import torch
# 创建张量
t = torch.randn(1, 3, 1, 5)
print("t.shape->", t.shape)
# 删除所有为1的维度
t2 = t.squeeze()
print("squeeze()->", t2.shape)
# 删除指定维度
t3 = t.squeeze(2)
print("squeeze(2)->", t3.shape)
# 增加维度
t4 = torch.randn(3, 4)
print("t4.shape->", t4.shape)
t5 = t4.unsqueeze(0)
print("unsqueeze(0)->", t5.shape)
t6 = t4.unsqueeze(2)
print("unsqueeze(2)->", t6.shape)运行结果.txt
t.shape-> torch.Size([1, 3, 1, 5])
squeeze()-> torch.Size([3, 5])
squeeze(2)-> torch.Size([1, 3, 5])
t4.shape-> torch.Size([3, 4])
unsqueeze(0)-> torch.Size([1, 3, 4])
unsqueeze(2)-> torch.Size([3, 4, 1])transpose / permute
用于 交换或重新排列张量维度。
tensor.transpose(dim0, dim1):交换两个维度。tensor.permute(dims):按指定顺序 重新排列所有维度。
demo.py
import torch
# 二维张量
t = torch.randn(2, 3)
print("t.shape->", t.shape)
# 交换两个维度
t2 = t.transpose(0, 1)
print("transpose(0,1)->")
print(t2)
print("shape->", t2.shape)
# 三维张量
t3 = torch.randn(2, 3, 4)
print("t3.shape->", t3.shape)
# 重新排列维度
t4 = t3.permute(2, 0, 1)
print("permute(2,0,1)->", t4.shape)运行结果.txt
t.shape-> torch.Size([2, 3])
transpose(0,1)->
tensor([[ 1.6709, -0.3964],
[-0.4608, 0.9617],
[-1.4908, -0.7886]])
shape-> torch.Size([3, 2])
t3.shape-> torch.Size([2, 3, 4])
permute(2,0,1)-> torch.Size([4, 2, 3])view / contiguous
用于 改变张量形状并保证内存布局正确。
tensor.view(shape):改变张量形状,但要求 张量内存连续。tensor.contiguous():返回一个 内存连续的张量副本。transpose或permute后张量通常 不是连续内存。
demo.py
import torch
x = torch.arange(12).reshape(3, 4)
print("x.shape->", x.shape)
# 转置后张量
y = x.transpose(0, 1)
print("y.shape->", y.shape)
print("is_contiguous->", y.is_contiguous())
# 需要先变为连续内存
z = y.contiguous().view(12)
print("z->", z)
print("z.shape->", z.shape)运行结果.txt
x.shape-> torch.Size([3, 4])
y.shape-> torch.Size([4, 3])
is_contiguous-> False
z-> tensor([ 0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11])
z.shape-> torch.Size([12])你好。