#最近开始看沐神的《动手学深度学习》,陆续记录学习笔记#
tensor是什么
tensor,n维向量,也称为张量,是机器学习的重要数据结构。
深度学习框架中通常会提供一个张量类,张量类支持自动微分,良好支持GPU加速计算。
tensor的创建
第一步:导入torch
import torch
第二步:创建,此处介绍四种创建方法
方法1:直接初始化x。张量x中包含4个元素。
data = [[1, 2], [3, 4]]
x = torch.tensor(data)
方法2:使用随机数和常数初始化。
使用arange创建一个行向量x。张量x中包含12个元素,即0-11共12个整数。
x = torch.arange(12)
使用zeros创建一个元素均为0的张量x。(2,3,4)是一个元组,表示了张量x的维度。
x = torch.zeros((2, 3, 4))
使用ones创建一个元素均为1的张量x。
x = torch.ones((2, 3, 4))
创建元素为随机数的张量x。(rand:[0,1)的均匀分布;randn:均值为0,方差为1的标准正态分布;)
x1 = torch.randn(3, 4)
x2 = torch.rand(2, 3)
tensor([[-0.0135, 0.0665, 0.0912, 0.3212], [ 1.4653, 0.1843, -1.6995, -0.3036], [ 1.7646, 1.0450, 0.2457, -0.7732]]) |
tensor([[0.9041, 0.7120, 0.7389], [0.1606, 0.3994, 0.3293]]) |
方法3:从Numpy数组初始化。
import numpy as np
data = [[1, 2], [3, 4]]
np_array = np.array(data)
x = torch.from_numpy(np_array)
方法4:从其他tensor中初始化。
data = [[1, 2], [3, 4]]
x_data = torch.tensor(data)
x_ones = torch.ones_like(x_data)
x_rand = torch.rand_like(x_data, dtype=torch.float)
tensor([[1, 1], [1, 1]]) |
tensor([[0.6941, 0.0369], [0.0227, 0.6394]]) |
tensor类 的 属性
shape:描述了tensor的形状
dtype:描述了tensor的数据类型
device:描述了存储tensor的设备
tensor = torch.rand(3,4)
print(f"Shape of tensor: {tensor.shape}")
print(f"Datatype of tensor: {tensor.dtype}")
print(f"Device tensor is stored on: {tensor.device}")
Shape of tensor: torch.Size([3, 4]) Datatype of tensor: torch.float32 Device tensor is stored on: cpu |
tensor类的操作
常用基本操作
获取张量形状。size()
与shape属性的功能一致,size()方法也可以获得张量的形状,以及某一个维度
a = torch.tensor([[1, 2, 3], [4, 5, 6]])
print(a.shape)
print(a.size())
print(a.shape[0])
print(a.shape[1])
print(a.size(0))
print(a.size(1))
torch.Size([2, 3]) torch.Size([2, 3]) 2 3 2 3 |
修改张量形状。reshape()、view()、flatten()
reshape(input, shape)->Tensor
按照指定的形状修改输入的张量的形状
详细的内容可以参照官方指南:
torch.reshape — PyTorch 2.1 documentation
或如下博客:
view(*shape)->Tensor
可以根据输入的形状重构或调整张量维度。
详细的内容可以参照如下博客:
torch:)——PyTorch: view( )用法详解_torch.view-CSDN博客
flatten(input, start_dim=0, end_dim=-1)->Tensor
可以按照指定的维度范围将张量进行扁平化。
详细的内容可以参照如下博客:
PyTorch基础(15)-- torch.flatten()方法_底层研究生的博客-CSDN博客
求最大最小值。max()、min()
torch.max(input, dim, keepdim=False, *, out=None) -> (Tensor, LongTensor)
可以求输入张量的最大值元素或在指定维度上的最大值
详细的内容可以参照如下博客:
Pytorch最大值最小值函数:torch.max()、torch.min()-CSDN博客
torch.min(input, dim, keepdim=False, *, out=None) -> (Tensor, LongTensor)
可以求输入张量的最小值元素或在指定维度上的最小值
详细的内容可以参照官方指南:
torch.min — PyTorch 2.1 documentation
或如下博客:
torch.min()的使用举例_敲代码的小风的博客-CSDN博客
运算符
Element-wise 标准运算符。对于任意具有相同形状的张量,常见的标准算术运算符(+、-、*、/和**,以及exp)都可以被升级为按元素(element-wise)运算。
x = torch.tensor([1.0, 2, 4, 8])
y = torch.tensor([2, 2, 2, 2])
x + y, x - y, x * y, x / y, x ** y # **运算符是求幂运算
torch.exp(x)
tensor([ 3., 4., 6., 10.]), tensor([-1., 0., 2., 6.]), tensor([ 2., 4., 8., 16.]), tensor([0.5000, 1.0000, 2.0000, 4.0000]), tensor([ 1., 4., 16., 64.]) |
张量连结(concatenate)。将两个张量按照指定的维度连结在一起。
X = torch.arange(12, dtype=torch.float32).reshape((3,4))
Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
torch.cat((X, Y), dim=0), torch.cat((X, Y), dim=1)
tensor([[ 0., 1., 2., 3.], [ 4., 5., 6., 7.], [ 8., 9., 10., 11.], [ 2., 1., 4., 3.], [ 1., 2., 3., 4.], [ 4., 3., 2., 1.]]), tensor([[ 0., 1., 2., 3., 2., 1., 4., 3.], [ 4., 5., 6., 7., 1., 2., 3., 4.], [ 8., 9., 10., 11., 4., 3., 2., 1.]]) |
Element-wise 逻辑运算符。对于任意具有相同形状的张量,常见的逻辑算术运算符(==、>、<、>=、<=和!=)都可以被升级为按元素(element-wise)运算。
X = torch.arange(12, dtype=torch.float32).reshape((3,4))
Y = torch.tensor([[2.0, 1, 4, 3], [1, 2, 3, 4], [4, 3, 2, 1]])
X == Y
tensor([[False, True, False, True], [False, False, False, False], [False, False, False, False]]) |
求和。对张量中所有元素进行求和,产生一个单元素张量。
X.sum()
tensor(66.) |
广播机制(broadcasting mechanism)
在一些情况下,我们需要将形状不同的两个张量执行element-wise操作,此时就需要用到广播机制。广播机制中首先通过适当复制元素来扩展一个或两个张量,使得扩展后的两个张量具有相同的形状,然后再用扩展后的张量执行element-wise操作。
a = torch.arange(3).reshape((3, 1))
b = torch.arange(2).reshape((1, 2))
a + b
a和b分别是,a为3x1张量,b为1x2张量: tensor([[0], [1], [2]]), tensor([[0, 1]]) 使用广播机制进行element-wise相加,第一步先扩展a和b,其中a复制列形成3x2张量,b复制行形成3x2张量。 tensor([[0, 0], [1, 1], [2, 2]]), tensor([[0, 1] [0, 1] [0, 1]]) 然后使用扩展后的两个张量执行element-wise相加,可得 tensor([[0, 1], [1, 2], [2, 3]]), |
索引和切片
通过索引访问元素。与Python中通过索引访问数组的方法一样,张量的第一个元素索引是0,最后一个元素的索引是-1,可以通过指定范围来得到范围内的元素。
X = torch.arange(12, dtype=torch.float32).reshape((3,4))
X[-1]
X[1:3]
X[1, 2]
X[1, 2] = 9
X[0:2, :] = 12
创建张量X为: tensor([[ 0., 1., 2., 3.], [ 4., 5., 6., 7.], [ 8., 9., 10., 11.]]) X[-1]表示取X第0维度(行)的最后一个元素(最后一行,即第3行) tensor([ 8., 9., 10., 11.]) X[1 : 3]表示取X第0维度(行)的第1个和第2个元素 tensor([[ 4., 5., 6., 7.], [ 8., 9., 10., 11.]]) X[1, 2]表示取X第0维度的第一个元素内的对应X第1维度的第2个元素 tensor(6.) X[1, 2] = 9 表示将指定的值写入指定的索引位置,修改后的X为 tensor([[ 0., 1., 2., 3.], [ 4., 5., 9., 7.], [ 8., 9., 10., 11.]]) X[0:2, :] = 12 表示为X的第0维度的第0个元素和第1个元素的内对应X第1维度的所有元素修改为值为12 tensor([[ 12., 12., 12., 12.], [ 12., 12., 12., 12.], [ 8., 9., 10., 11.]]) |
转换为其他Python对象
torch张量和numpy数组可以共享它们的底层内存,就地操作更改一个张量也会同时更改另一个张量
A = X.numpy()
B = torch.tensor(A)
type(A), type(B)
(numpy.ndarray, torch.Tensor) |
若要将大小为1的张量转换为Python标量,可以使用item函数或Python内置函数。
a = torch.tensor([3.5])
a, a.item(), float(a), int(a)
(tensor([3.5000]), 3.5, 3.5, 3) |
节省内存
在编码的过程中需要注意一些计算中的内存开销问题。设有两个张量分别为X和Y,那么当我们想要将X+Y的结果仍旧由X来表示时,可能会写成X=X+Y,这种方法下重新赋值前后的X在内存中的地址是不一样的,这意味着,X在重新赋值的过程中重新分配了内存,造成了一定的内存开销。
#使用Python中id()方法来查看X重新赋值前后的内存地址
before = id(X)
X = X + Y
id(X) == before #此时为False
原地更新张量:当我们想要原地更新一个张量时,我们可以使用如下三种方式
- 切片表示法:
before = id(X)
X[:] = X+Y
id(X) == before #此时为True
- 使用+=、-=等类似操作符:
before = id(X)
X += Y
id(X) == before #此时为True
- 使用中间变量:
Z = torch.zeros_like(Y)
Z[:] = X + Y
了解更多tensor类的操作,可以参考pytorch官方文档torch — PyTorch 2.1 documentation