pytorch学习日志——张量,广播机制,索引与切片

14 篇文章 1 订阅
10 篇文章 0 订阅
文章介绍了PyTorch中的张量概念,包括张量的多维数组特性、数学运算、自动求导功能以及在GPU上的计算支持。广播机制允许不同形状的张量进行运算,而张量的索引和切片提供了灵活的数据访问方式。此外,文章强调了内存管理的重要性,原地操作能有效节省内存,避免频繁创建新对象。
摘要由CSDN通过智能技术生成

一.张量  

        在 PyTorch 中,张量(Tensor)是一种多维数组,可以用来表示各种类型的数据,例如图像、音频、文本等。张量具有以下特点:

  1. 多维数组:张量可以表示任意维度的多维数组,例如标量(0 维)、向量(1 维)、矩阵(2 维)等。

  2. 张量运算:张量支持各种数学运算,例如加法、减法、乘法、除法等,还支持逐元素运算、矩阵运算、广播运算等。

  3. 自动求导:张量支持自动求导,可以方便地进行反向传播算法,用于训练深度学习模型。

  4. 支持 GPU 计算:张量支持在 GPU 上进行计算,可以大幅提高计算速度。

        在 PyTorch 中,可以使用 torch.Tensor() 函数创建一个空的张量,也可以使用 torch.tensor() 函数从 Python 列表、NumPy 数组或其他的张量中创建张量,还可以使用其他的函数创建特定类型的张量,例如 torch.zeros()、torch.ones()、torch.rand() 等。

例如,创建一个形状为 (3, 4) 的随机初始化的张量:

import torch

x = torch.rand(3, 4)
print(x)
#输出结果
tensor([[1.0236, 1.2137, 1.1852, 1.3366],
        [1.5170, 1.9903, 1.9027, 1.8600],
        [1.5812, 1.9834, 1.0563, 1.9288]])

二.Tensor

        在 PyTorch 中,Tensor 是一个用于表示多维数组的类,类似于 NumPy 中的 ndarray。Tensor 是 PyTorch 中最基本的数据结构,可以用来表示各种类型的数据,例如图像、音频、文本等。

Tensor 有以下特点:

  1. 多维数组:Tensor 可以表示任意维度的多维数组,例如标量(0 维)、向量(1 维)、矩阵(2 维)等。

  2. 张量运算:Tensor 支持各种数学运算,例如加法、减法、乘法、除法等,还支持逐元素运算、矩阵运算、广播运算等。

  3. 自动求导:Tensor 支持自动求导,可以方便地进行反向传播算法,用于训练深度学习模型。

  4. 支持 GPU 计算:Tensor 支持在 GPU 上进行计算,可以大幅提高计算速度。

 三.广播机制

        pytorch中的广播机制是指在运算时,自动扩展张量的形状,使得他们能够逐元素操作,不需要额外对其进行形状转换或者复制数据。

在pytorch中广播机制如下:

        1.如果两个维度的张量不同,则将维度较小的张量通过在前面加1来扩展其形状,直到两个张量维度数相同。(见例子1)

        2.如果两个张量在某个维度数的形状不同,但其中一个张量的形状在这个维度上是1,则将这个张量通过复制数据来扩展其形状,使得他们在这个维度上的形状相同。(详情见例子2)

        3.如果两个张量在某个维度上的形状不同,且两个张量在这个维度的形状都不是1,则无法进行广播,会抛出形状不兼容的异常。(见例子3)

import torch

# 创建形状为 (3, 1) 的张量 a,值为 0、1、2
a = torch.arange(3).reshape((3, 1))

# 创建形状为 (1, 2) 的张量 b,值为 0、1
b = torch.arange(2).reshape((1, 2))

# 输出张量 a 和 b 的值
print(a, b)

# 对张量 a 和 b 进行逐元素相加
# 由于张量 a 和 b 在第一维和第二维上的形状分别为 (3, 1) 和 (1, 2),是兼容的
# 因此 PyTorch 会自动对 a 和 b 进行扩展,使得它们的形状相同,然后进行逐元素相加
# 扩展后的 a 的形状为 (3, 2),值为 [[0, 0], [1, 1], [2, 2]]
# 扩展后的 b 的形状为 (3, 2),值为 [[0, 1], [0, 1], [0, 1]]
# a 和 b 逐元素相加得到形状为 (3, 2) 的张量,值为 [[0, 1], [1, 2], [2, 3]]
print(a + b)

#结果
tensor([[0],
        [1],
        [2]]) tensor([[0, 1]])
tensor([[0, 1],
        [1, 2],
        [2, 3]])
#例子二
import torch

# 创建一个形状为 (2, 3) 的张量 x
x = torch.tensor([[1, 2, 3], [4, 5, 6]])

# 创建一个形状为 (2,) 的张量 y
y = torch.tensor([10, 20])

# 在第二个维度上插入一个新的维度,形状变为 (2, 1) 的张量
y = y.unsqueeze(1)

# 输出 y 的形状和值
print(y)

# 对 x 和 y 逐元素相加
# 由于 y 在第二个维度上的形状为 1,会被自动广播为形状为 (2, 3) 的张量(将张量为1的元素复制)
# 然后再和 x 逐元素相加得到形状为 (2, 3) 的张量
print(x + y)

#输出结果
tensor([[10],
        [20]])
tensor([[11, 12, 13],
        [24, 25, 26]])

#例子三
demo1=torch.zeros(2,3,4)
demo2=torch.ones(2,2)
demo1,demo2
demo1+demo2
#输出结果
RuntimeError                              Traceback (most recent call last)
 in ()
      2 demo2=torch.ones(2,2)
      3 demo1,demo2
----> 4 demo1+demo2

RuntimeError: The size of tensor a (4) must match the size of tensor b (2) at non-singleton dimension 2

 三.索引和切片

3.1索引

        张量中的元素也能通过索引访问:与python中的列表一样,第⼀个元素 的索引是0,最后⼀个元素索引是-1;可以指定范围以包含第⼀个元素和最后⼀个之前的元素。

import torch

# 创建一个形状为 (3, 4) 的张量 x
x = torch.tensor([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])

# 通过整数索引获取张量中的单个元素
print(x[1, 2])  # 输出 7

# 通过切片索引获取张量中的多个元素
print(x[:, 1:3])  # 输出 [[2, 3], [6, 7], [10, 11]]

3.2切片

        注意:张量的切片是基于原张量的视图进行的(与python列表的不同之处),即切片操作不会创建新的张量,而是返回原张量的一个子集。因此,在对切片结果进行修改时,原张量的相应位置也会被修改。如果需要创建一个新的张量,可以使用 clone() 函数创建一个复制。

import torch

# 创建一个形状为 (3, 4) 的张量 x
x = torch.tensor([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])

# 使用一个切片符号 : 表示所有元素
print(x[:])  # 输出 [[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]

# 使用一个整数和一个切片符号 : 表示从指定位置开始的所有元素
print(x[1:])  # 输出 [[5, 6, 7, 8], [9, 10, 11, 12]]

# 使用两个整数和一个切片符号 : 表示从指定位置开始到结束位置的所有元素
print(x[1:2, 0:2])  # 输出 [[5, 6]]

四.节省内存

        深度学习模型通常需要处理大量的数据,因此内存占用是一个重要的问题。在实际应用中,通常需要训练大型的深度学习模型,这些模型需要占用大量的内存才能运行。因此,节省内存是深度学习中一个非常重要的问题。

        运⾏⼀些操作可能会导致为新结果分配内存。例如,如果我们⽤Y = X + Y,我们将取消引⽤Y指向的张量, ⽽是指向新分配的内存处的张量。

  x = x + y 不是原地操作,因为它会创建一个新的张量,而不是直接在原有的张量上进行修改。在执行 x = x + y 操作时,会首先计算 x + y 得到一个新的张量,然后将这个新的张量赋值给变量 x。由于赋值操作会创建一个新的对象,并将变量指向这个新的对象,因此 x 现在指向了一个新的张量,而不是原有的张量。

        相反,原地操作是指在原有的张量上进行修改,而不是创建一个新的张量。例如,x += y 和x[:]=x+y 就是一个原地操作,它会将 y 的值直接加到 x 上,而不创建一个新的张量。

        使用原地操作可以减少内存开销,并且能够避免创建新的对象可能带来的一些问题,例如可能会导致 Python 垃圾回收机制的频繁调用,从而影响程序的性能。因此,在实际编程中,应该尽可能地使用原地操作。

before = id(Y)
Y = Y + X
id(Y) == before
#结果
False

before = id(X)
X += Y
id(X) == before
#结果
True

before = id(X)
X [:]=X+Y
id(X) == before
#结果
True

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只小百里

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值