张量

张量概念

什么是张量(Tensor)?

可以先这样理解:

  • 0 维:标量(scalar),比如 3.14
  • 1 维:向量(vector),比如 [ 1 2 3 4 ] \begin{bmatrix} 1 & 2 & 3 & 4 \end{bmatrix} [1234]
  • 2 维:矩阵(matrix),比如 [ 1 2 3 4 ] \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix} [1324]
  • 3 维及以上:统称为 张量(tensor)——元素为同一数据类型的多维矩阵

在 PyTorch 里,核心数据结构就是 torch.Tensor,跟 numpy 里的 ndarray 很像,但多了:

  • 可以在 GPU 上计算
  • 可以记录计算图,自动求导

张量创建方法

PyTorch 框架属于最常用的深度学习框架,无论是 ANN,CNN,RNN 等,都需要使用张量来进行数据的存储和计算。
张量 → \to 存储同一类型元素的容器,且元素值必须是数值才可以。

基本创建方法

torch.tensor()

根据指定的数据创建张量

import torch
import numpy as np

# 1. 定义函数,演示:torch.tensor() -> 根据指定的数据创建张量
def demo01():
    # 场景1:标量 张量
    t1 = torch.tensor(10)
    print(f"t1: {t1},type:{type(t1)}")
    print("-" * 30)
    # 场景2:向量 张量
    t2 = torch.tensor([1, 2, 3])
    print(f"t2: {t2},type:{type(t2)}")
    print("-" * 30)
    # 场景3:矩阵 张量
    t3 = torch.tensor([[1, 2, 3], [4, 5, 6]])
    print(f"t3: {t3},type:{type(t3)}")
    print("-" * 30)
    # 场景4:numpy 数组 -> 张量
    t4 = torch.tensor(
        np.random.randint(0, 10, size=(2, 3)),
        # 指定张量的数据类型为 float32
        dtype=torch.float32)
    print(f"t4: {t4},type:{type(t4)}")
    print("-" * 30)

输出结果如下:

t1: 10,type:<class 'torch.Tensor'>
------------------------------
t2: tensor([1, 2, 3]),type:<class 'torch.Tensor'>
------------------------------
t3: tensor([[1, 2, 3],
        [4, 5, 6]]),type:<class 'torch.Tensor'>
------------------------------
t4: tensor([[5., 9., 1.],
        [8., 0., 9.]]),type:<class 'torch.Tensor'>
------------------------------

当尝试直接创建指定维度张量(例如:2 行 3 列)时:

场景5:尝试直接创建指定维度张量(例如:23列)
t5 = torch.tensor(2, 3)
print(f"t5: {t5},type:{type(t5)}")
print("-" * 30)

程序会报错:

Traceback (most recent call last):
   File "/Users/PycharmProjects/DL_learn/day01/01_张量的基本创建方式.py", line 46, in <module>
     demo01()
   File "/Users/PycharmProjects/DL_learn/day01/01_张量的基本创建方式.py", line 35, in demo01
     t5 = torch.tensor(2, 3)
          ^^^^^^^^^^^^^^^^^^
 TypeError: tensor() takes 1 positional argument but 2 were given

tensor 的函数签名如下:

def tensor(data: Any, # 这是唯一的必需参数,用于提供创建张量的数据
           dtype: dtype | None = None, # 指定所创建张量的数据类型
           device: str | device | int | None = None, # 指定张量存储的设备(CPU 或 GPU)
           requires_grad: bool = False, # 指定张量是否需要计算梯度,这是实现自动求导(Autograd)的关键开关
           pin_memory: bool = False) -> Tensor # 如果为 True,张量的数据将被分配到 “锁定内存”(pinned memory)中,这在使用 GPU 时可以加速数据从 CPU 到 GPU 的传输

所以当尝试指定维度时,参数传递有问题,程序报错。

torch.Tensor()

根据形状创建张量,其也可以根据指定的数据创建张量

# 2. 定义函数,演示:torch.Tensor() -> 根据形状创建张量,其也可以根据指定的数据创建张量
def demo02():
    # 场景1:标量 张量
    t1 = torch.Tensor(10)
    print(f"t1: {t1},type:{type(t1)}")
    print("-" * 30)
    # 场景2:向量 张量
    t2 = torch.Tensor([1, 2, 3])
    print(f"t2: {t2},type:{type(t2)}")
    print("-" * 30)
    # 场景3:矩阵 张量
    t3 = torch.Tensor([[1, 2, 3], [4, 5, 6]])
    print(f"t3: {t3},type:{type(t3)}")
    print("-" * 30)
    # 场景4:numpy 数组 -> 张量
    t4 = torch.Tensor(np.random.randint(0, 10, size=(2, 3)))
    # Tensor 不能直接指定数据类型,只能根据 numpy 数组的 dtype 来确定
    print(f"t4: {t4},type:{type(t4)}")
    print("-" * 30)
    # 场景5:尝试直接创建指定维度张量(例如:2行3列)
    t5 = torch.Tensor(2, 3)
    print(f"t5: {t5},type:{type(t5)}")
    print("-" * 30)

输出结果如下:

t1: tensor([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]),type:<class 'torch.Tensor'>
------------------------------
t2: tensor([1., 2., 3.]),type:<class 'torch.Tensor'>
------------------------------
t3: tensor([[1., 2., 3.],
        [4., 5., 6.]]),type:<class 'torch.Tensor'>
------------------------------
t4: tensor([[1., 6., 7.],
        [9., 4., 5.]]),type:<class 'torch.Tensor'>
------------------------------
t5: tensor([[0., 0., 0.],
        [0., 0., 0.]]),type:<class 'torch.Tensor'>
------------------------------

Tensor 较于 tensor 可以基于形状创建张量,而 tensor 只能基于指定的数据创建张量。

torch.IntTensor()

根据指定的数据创建张量,且指定张量的数据类型(还有 torch.FloatTensor()torch.DoubleTensor()

# 3. 定义函数,演示:torch.IntTensor() -> 根据指定的数据创建张量,且指定张量的数据类型
def demo03():
    # 场景1:标量 张量
    t1 = torch.IntTensor(10)
    print(f"t1: {t1},type:{type(t1)}")
    print("-" * 30)
    # 场景2:向量 张量
    t2 = torch.IntTensor([1, 2, 3])
    print(f"t2: {t2},type:{type(t2)}")
    print("-" * 30)
    # 场景3:矩阵 张量
    t3 = torch.IntTensor([[1, 2, 3], [4, 5, 6]])
    print(f"t3: {t3},type:{type(t3)}")
    print("-" * 30)
    # 场景4:numpy 数组 -> 张量
    t4 = torch.IntTensor(np.random.randint(0, 10, size=(2, 3)))
    print(f"t4: {t4},type:{type(t4)}")
    print("-" * 30)
    # 场景5:如果类型不匹配,会尝试自动转换
    t5 = torch.IntTensor([1, 2, 3.0])
    print(f"t5: {t5},type:{type(t5)}")
    print("-" * 30)

输出结果如下:

t1: tensor([0, 0, 0, 0, 0, 0, 0, 0, 0, 0], dtype=torch.int32),type:<class 'torch.Tensor'>
------------------------------
t2: tensor([1, 2, 3], dtype=torch.int32),type:<class 'torch.Tensor'>
------------------------------
t3: tensor([[1, 2, 3],
        [4, 5, 6]], dtype=torch.int32),type:<class 'torch.Tensor'>
------------------------------
t4: tensor([[0, 3, 2],
        [9, 5, 9]], dtype=torch.int32),type:<class 'torch.Tensor'>
------------------------------
t5: tensor([1, 2, 3], dtype=torch.int32),type:<class 'torch.Tensor'>
------------------------------

张量的数据类型

在 torch 中 CPU 和 GPU 张量分别有 8 种数据类型

数据类型 dtype CPU tensor GPU tensor
32-bit floating point torch.float32 or torch.float torch.FloatTensor torch.cuda.FloatTensor
64-bit floating point torch.float64 or torch.double torch.DoubleTensor torch.cuda.DoubleTensor
16-bit floating point torch.float16 or torch.half torch.HalfTensor torch.cuda.HalfTensor
8-bit integer (unsigned) torch.uint8 torch.ByteTensor torch.cuda.ByteTensor
8-bit integer (signed) torch.int8 torch.CharTensor torch.cuda.CharTensor
16-bit integer (signed) torch.int16 or torch.short torch.ShortTensor torch.cuda.ShortTensor
32-bit integer (signed) torch.int32 or torch.int torch.IntTensor torch.cuda.IntTensor

张量中默认的数据类型是 float32(torch.FloatTensor)

创建全 0 / 1 / 指定值张量

创建全 0 张量

torch.zeros()torch.zeros_like()

# 场景:torch.zeros() 和 torch.zeros_like() -> 创建全0张量
t1 = torch.zeros(2, 3) # 创建2行3列的全0张量
print(f"t1: {t1},type:{type(t1)}")
print("-" * 30)
# t2: 3行2列
t2 = torch.tensor([[1, 2], [3, 4], [5, 6]])
print(f"t2: {t2},type:{type(t2)}")
print("-" * 30)
# t3 -> 基于t2的形状创建全0张量
t3 = torch.zeros_like(t2)
print(f"t3: {t3},type:{type(t3)}")
print("*" * 30)

输出结果如下:

t1: tensor([[0., 0., 0.],
        [0., 0., 0.]]),type:<class 'torch.Tensor'>
------------------------------
t2: tensor([[1, 2],
        [3, 4],
        [5, 6]]),type:<class 'torch.Tensor'>
------------------------------
t3: tensor([[0, 0],
        [0, 0],
        [0, 0]]),type:<class 'torch.Tensor'>
******************************
创建全 1 张量

torch.ones()torch.ones_like()

# 场景:torch.ones() 和 torch.ones_like() -> 创建全1张量
t1 = torch.ones(2, 3) # 创建2行3列的全1张量
print(f"t1: {t1},type:{type(t1)}")
print("-" * 30)
# t2: 3行2列
t2 = torch.tensor([[1, 2], [3, 4], [5, 6]])
print(f"t2: {t2},type:{type(t2)}")
print("-" * 30)
# t3 -> 基于t2的形状创建全1张量
t3 = torch.ones_like(t2)
print(f"t3: {t3},type:{type(t3)}")
print("*" * 30)

输出结果如下:

t1: tensor([[1., 1., 1.],
        [1., 1., 1.]]),type:<class 'torch.Tensor'>
------------------------------
t2: tensor([[1, 2],
        [3, 4],
        [5, 6]]),type:<class 'torch.Tensor'>
------------------------------
t3: tensor([[1, 1],
        [1, 1],
        [1, 1]]),type:<class 'torch.Tensor'>
******************************
创建全指定值张量

torch.full()torch.full_like()

# 场景:torch.full() 和 torch.full_like() -> 创建指定值张量
t1 = torch.full(size=(2, 3), fill_value=10) # 创建2行3列的全10张量
print(f"t1: {t1},type:{type(t1)}")
print("-" * 30)
# t2: 3行2列
t2 = torch.tensor([[1, 2], [3, 4], [5, 6]])
print(f"t2: {t2},type:{type(t2)}")
print("-" * 30)
# t3 -> 基于t2的形状创建全10张量
t3 = torch.full_like(t2, 10)
print(f"t3: {t3},type:{type(t3)}")
print("*" * 30)

输出结果如下:

t1: tensor([[10, 10, 10],
        [10, 10, 10]]),type:<class 'torch.Tensor'>
------------------------------
t2: tensor([[1, 2],
        [3, 4],
        [5, 6]]),type:<class 'torch.Tensor'>
------------------------------
t3: tensor([[10, 10],
        [10, 10],
        [10, 10]]),type:<class 'torch.Tensor'>
******************************

注意事项

  1. torch.full()size 参数格式

    • 代码中 torch.full(size=(2, 3), fill_value=10) 使用了元组 (2, 3) 作为 size 参数,这是推荐写法
    • 注意:size 必须是整数序列(元组、列表等),不能直接写 size=2, 3(会报参数不匹配错误)。
    • 错误示例:torch.full(2, 3, fill_value=10) → 会把 2size3fill_value,导致形状错误。
  2. 张量的数据类型推断

    • torch.full() 会根据 fill_value 的类型推断张量 dtype:

      • 代码中 fill_value=10 是整数 → 张量 dtype 默认为 torch.int64(PyTorch 中整数默认 int64)。
      • fill_value 是浮点数(如 10.0)→ dtype 默认为 torch.float32(默认浮点类型)。
    • 若需显式指定 dtype,需加 dtype 参数:

      t1 = torch.full(size=(2, 3), fill_value=10, dtype=torch.float32)  # 强制为float32
      
  3. torch.full_like() 的继承特性

    • torch.full_like(input, fill_value)完全继承输入张量 input 的形状、dtype 和设备

      • 代码中 t2torch.int64 类型(从列表 [[1,2],...] 推断),因此 t3 的 dtype 也是 torch.int64,形状与 t2 一致(3 行 2 列)。

      • t2 在 GPU 上,t3 会自动创建在相同 GPU 上(无需额外指定 device),示例:

        t2 = torch.tensor([[1,2],[3,4]], device="cuda:0")  # GPU上的张量
        t3 = torch.full_like(t2, 10)  # t3 也在 cuda:0 上
        
  4. fill_value 与 dtype 的兼容性

    • fill_value 的类型与目标 dtype 不匹配,会发生隐式转换(可能丢失精度):
      • 例:用 fill_value=10.5 填充 int64 类型张量 → 小数部分被截断(结果为 10)。
      • 例:用 fill_value=10 填充 float32 张量 → 自动转为 10.0(安全转换)。
    • 建议:fill_value 类型与目标 dtype 保持一致,避免意外截断。

torch.full():通过指定形状 + 填充值创建张量,需注意 size 格式和 dtype 推断。

torch.full_like():通过继承已有张量的形状 /dtype/ 设备创建张量,适合快速复用张量属性的场景。

创建线性和随机张量

创建线性张量

torch.arange()torch.linspace()

# 定义函数,演示:创建线性张量
def demo01():
    # 场景1:创建指定范围的线性张量
    t1 = torch.arange(0, 10, 2) # 创建0-10之间的偶数张量,包含0不包含10
    """
    参数:
        start: 序列的起始值(包含在序列中)
        end: 序列的结束值(不包含在序列中)
        step: 序列中每个元素之间的步长(默认值为1)
    """
    print(f"t1: {t1},type:{type(t1)}")
    print("-" * 30)
    # 场景2:创建指定范围的线性张量 -> 等差数列
    t2 = torch.linspace(0, 10, 5) # 创建0-10之间的5个点的等差数列张量
    """
    参数:
        start: 序列的起始值(包含在序列中)
        end: 序列的结束值(包含在序列中)
        steps: 序列中元素的个数
    """
    print(f"t2: {t2},type:{type(t2)}")
    print("-" * 30)

输出结果如下:

t1: tensor([0, 2, 4, 6, 8]),type:<class 'torch.Tensor'>
------------------------------
t2: tensor([ 0.0000,  2.5000,  5.0000,  7.5000, 10.0000]),type:<class 'torch.Tensor'>
------------------------------
创建随机张量

torch.random.initial_seed()torch.random.manual_seed() → \to 初始化随机种子

torch.rand()torch.randn() → \to 创建随机浮点类型张量

torch.randint(low, high, size) → \to 创建随机整数类型张量

# 定义函数,演示:创建随机张量
def demo02():
    # step1:设置随机种子
    # torch.initial_seed() # 默认采用当前系统的时间戳作为随机种子
    # print(f"当前的随机种子: {torch.initial_seed()}") # 每次都不一样
    torch.manual_seed(100) # 手动设置随机种子为100
    # 设置一次随机种子后,后续的随机操作都将基于该种子
    print(f"当前的随机种子: {torch.initial_seed()}")

    # step2:创建随机张量
    # 场景1: 均匀分布的(0,1)随机张量
    t1 = torch.rand(2, 3) # 创建2行3列的随机浮点类型张量
    print(f"t1: {t1},type:{type(t1)}")
    print("-" * 30)

    # 场景2: 标准正态分布的随机张量
    t2 = torch.randn(2, 3) # 创建2行3列的随机浮点类型张量
    print(f"t2: {t2},type:{type(t2)}")
    print("-" * 30)

    # 场景3: 随机整数张量
    t3 = torch.randint(low=0, high=10, size=(2, 3)) # 创建2行3列的随机整数类型张量,范围[0, 10)
    print(f"t3: {t3},type:{type(t3)}")
    print("-" * 30)

输出结果如下:

当前的随机种子: 100
t1: tensor([[0.1117, 0.8158, 0.2626],
        [0.4839, 0.6765, 0.7539]]),type:<class 'torch.Tensor'>
------------------------------
t2: tensor([[ 1.1869,  0.8798,  1.5180],
        [-0.2546, -1.5478,  2.2337]]),type:<class 'torch.Tensor'>
------------------------------
t3: tensor([[4, 3, 8],
        [7, 4, 6]]),type:<class 'torch.Tensor'>
------------------------------

张量的类型转换

data.type(torch支持的数据类型)

data.half()/float()/double()/short()/int()/long()

import torch

# 场景1:直接创建指定类型的张量
t1 = torch.tensor([1, 2, 3], dtype=torch.float) # 默认是torch.float32
print(f"t1: {t1},元素类型:{t1.dtype},张量类型:{type(t1)}")
print("-" * 30)

# 场景2:将已有张量转换为指定类型
t2 = t1.type(torch.int32) # 将t1转换为torch.int32类型
print(f"t2: {t2},元素类型:{t2.dtype},张量类型:{type(t2)}")
print("-" * 30)

print(t2.half())        # 转换为torch.float16类型
print(t2.float())       # 转换为torch.float32类型,默认是torch.float32
print(t2.double())      # 转换为torch.float64类型
print(t2.short())       # 转换为torch.int16类型
print(t2.int())         # 转换为torch.int32类型
print(t2.long())        # 转换为torch.int64类型,默认是torch.int64

输出结果如下:

t1: tensor([1., 2., 3.]),元素类型:torch.float32,张量类型:<class 'torch.Tensor'>
------------------------------
t2: tensor([1, 2, 3], dtype=torch.int32),元素类型:torch.int32,张量类型:<class 'torch.Tensor'>
------------------------------
tensor([1., 2., 3.], dtype=torch.float16)
tensor([1., 2., 3.])
tensor([1., 2., 3.], dtype=torch.float64)
tensor([1, 2, 3], dtype=torch.int16)
tensor([1, 2, 3], dtype=torch.int32)
tensor([1, 2, 3])

张量的转换

张量转换为 Numpy 数组

张量.numpy() → \to 共享内存(浅拷贝)

张量.numpy().copy() → \to 不共享内存(深拷贝)

# 1. 定义函数,演示:张量 -> numpy ndarray对象
def demo01():
    # 1. 创建张量
    t1 = torch.tensor([1, 2, 3, 4, 5])
    print(f"t1: {t1},type:{type(t1)}")

    # 2. 张量 -> numpy ndarray对象
    # 2.1 共享内存(浅拷贝)
    ndarray1 = t1.numpy()
    print(f"ndarray1: {ndarray1},type:{type(ndarray1)}")
    # 演示上述方式为共享内存
    ndarray1[0] = 100
    print(f"ndarray1: {ndarray1}")
    print(f"t1: {t1}")

    # 2.2 不共享内存(深拷贝)
    ndarray2 = t1.numpy().copy()
    print(f"ndarray2: {ndarray2},type:{type(ndarray2)}")
    # 演示上述方式为不共享内存
    ndarray2[0] = 200
    print(f"ndarray2: {ndarray2}")
    print(f"t1: {t1}")

输出结果如下:

t1: tensor([1, 2, 3, 4, 5]),type:<class 'torch.Tensor'>
ndarray1: [1 2 3 4 5],type:<class 'numpy.ndarray'>
ndarray1: [100   2   3   4   5]
t1: tensor([100,   2,   3,   4,   5])
ndarray2: [100   2   3   4   5],type:<class 'numpy.ndarray'>
ndarray2: [200   2   3   4   5]
t1: tensor([100,   2,   3,   4,   5])

Numpy 数组转换为张量

torch.from_numpy(ndarray) → \to 共享内存(浅拷贝)

torch.tensor(ndarray) → \to 不共享内存(深拷贝)

# 2. 定义函数,演示:numpy ndarray对象 -> 张量
def demo02():
    # 1. 创建 numpy ndarray 对象
    ndarray1 = np.array([1, 2, 3, 4, 5])
    print(f"ndarray1: {ndarray1},type:{type(ndarray1)}")
    # 2. numpy ndarray对象 -> 张量
    # 2.1 共享内存(浅拷贝)
    t1 = torch.from_numpy(ndarray1)
    print(f"t1: {t1},type:{type(t1)}")
    # 演示上述方式为共享内存
    t1[0] = 100
    print(f"t1: {t1}")
    print(f"ndarray1: {ndarray1}")

    # 2.2 不共享内存(深拷贝)
    t2 = torch.tensor(ndarray1)
    print(f"t2: {t2},type:{type(t2)}")
    # 演示上述方式为不共享内存
    t2[0] = 200
    print(f"t2: {t2}")
    print(f"ndarray1: {ndarray1}")

输出结果如下:

ndarray1: [1 2 3 4 5],type:<class 'numpy.ndarray'>
t1: tensor([1, 2, 3, 4, 5]),type:<class 'torch.Tensor'>
t1: tensor([100,   2,   3,   4,   5])
ndarray1: [100   2   3   4   5]
t2: tensor([100,   2,   3,   4,   5]),type:<class 'torch.Tensor'>
t2: tensor([200,   2,   3,   4,   5])
ndarray1: [100   2   3   4   5]

从标量张量中提取其内容

标量张量.item() 只能是标量张量

# 3. 定义函数,演示:从标量张量中提取其内容
def demo03():
    # 1. 创建标量张量
    t1 = torch.tensor(10)
    print(f"t1: {t1},type:{type(t1)}")
    # 2. 从标量张量中提取其内容
    scalar = t1.item()
    print(f"scalar: {scalar},type:{type(scalar)}")

输出结果如下:

t1: 10,type:<class 'torch.Tensor'>
scalar: 10,type:<class 'int'>

张量的运算

张量的基本运算

add(), sub(), mul(), div(), neg() → \to 加、减、乘、除、取反
add_(), sub_(), mul_(), div_(), neg_() → \to 加、减、乘、除、取反,可以修改源数据,类似于 Pandas 中的 inplace=True

import torch

# 1. 创建张量
t1 = torch.tensor([10, 20, 30], dtype=torch.float)
print(f"t1: {t1}")

# 2. 演示张量的基本运算
# 2.1 加
print("*" * 30)
t2 = t1.add(10) # 不会修改源数据
print(f"t2: {t2}")
t2 = t1 + 10
print(f"t2: {t2}")

print("-" * 30)

t2 = t1.add_(10) # 会修改源数据
print(f"t2: {t2}")
print(f"t1: {t1}") # 源数据被修改了
t1 += 10
print(f"t1: {t1}")
print("*" * 30)

# 2.2 减
print("*" * 30)
t2 = t1.sub(10) # 不会修改源数据
print(f"t2: {t2}")
t2 = t1 - 10
print(f"t2: {t2}")

print("-" * 30)

t2 = t1.sub_(10) # 会修改源数据
print(f"t2: {t2}")
print(f"t1: {t1}") # 源数据被修改了
t1 -= 10
print(f"t1: {t1}")
print("*" * 30)

# 2.3 乘
print("*" * 30)
t2 = t1.mul(10) # 不会修改源数据
print(f"t2: {t2}")
t2 = t1 * 10
print(f"t2: {t2}")

print("-" * 30)

t2 = t1.mul_(10) # 会修改源数据
print(f"t2: {t2}")
print(f"t1: {t1}") # 源数据被修改了
t1 *= 10
print(f"t1: {t1}")
print("*" * 30)

# 2.4 除
print("*" * 30)
t2 = t1.div(10) # 不会修改源数据
print(f"t2: {t2}")
t2 = t1 / 10
print(f"t2: {t2}")

print("-" * 30)

t2 = t1.div_(10) # 会修改源数据
print(f"t2: {t2}")
print(f"t1: {t1}") # 源数据被修改了
t1 /= 10
print(f"t1: {t1}")
print("*" * 30)

# 2.5 取反
print("*" * 30)
t2 = t1.neg() # 不会修改源数据
print(f"t2: {t2}")
t2 = -t1
print(f"t2: {t2}")

print("-" * 30)

t2 = t1.neg_() # 会修改源数据
print(f"t2: {t2}")
print(f"t1: {t1}") # 源数据被修改了
t1 = -t1
print(f"t1: {t1}")
print("*" * 30)

输出结果如下:

t1: tensor([10., 20., 30.])
******************************
t2: tensor([20., 30., 40.])
t2: tensor([20., 30., 40.])
------------------------------
t2: tensor([20., 30., 40.])
t1: tensor([20., 30., 40.])
t1: tensor([30., 40., 50.])
******************************
******************************
t2: tensor([20., 30., 40.])
t2: tensor([20., 30., 40.])
------------------------------
t2: tensor([20., 30., 40.])
t1: tensor([20., 30., 40.])
t1: tensor([10., 20., 30.])
******************************
******************************
t2: tensor([100., 200., 300.])
t2: tensor([100., 200., 300.])
------------------------------
t2: tensor([100., 200., 300.])
t1: tensor([100., 200., 300.])
t1: tensor([1000., 2000., 3000.])
******************************
******************************
t2: tensor([100., 200., 300.])
t2: tensor([100., 200., 300.])
------------------------------
t2: tensor([100., 200., 300.])
t1: tensor([100., 200., 300.])
t1: tensor([10., 20., 30.])
******************************
******************************
t2: tensor([-10., -20., -30.])
t2: tensor([-10., -20., -30.])
------------------------------
t2: tensor([-10., -20., -30.])
t1: tensor([-10., -20., -30.])
t1: tensor([10., 20., 30.])
******************************
  1. 可以用 +-*/+=-=*=/= 来代替函数进行基本运算
  2. 如果是张量和数值运算,则该数值会和张量中的每个值依次进行对应运算

点乘运算和矩阵运算

点乘运算

点乘指的是相同形状的张量对应位置的元素相乘,使用 mul() 和运算符 * 实现

例如: A = [ 1 2 3 4 ] , B = [ 5 6 7 8 ] A =\begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix} ,B=\begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix} A=[1324]B=[5768]

A A A B B B 的点乘运算为:
A ⋅ B = [ 1 × 5 2 × 6 3 × 7 4 × 8 ] = [ 5 12 21 32 ] A \cdot B=\begin{bmatrix} 1 \times 5 & 2 \times 6 \\ 3 \times 7 & 4 \times 8 \end{bmatrix}=\begin{bmatrix} 5 & 12 \\ 21 & 32 \end{bmatrix} AB=[1×53×72×64×8]=[5211232]

# 1. 定义函数,演示张量点乘
def demo01():
    # 1. 定义张量:2行3列
    t1 = torch.tensor([[1, 2, 3], [4, 5, 6]])
    print(f"t1: {t1}")
    # 2. 定义张量:2行3列
    t2 = torch.tensor([[1, 2, 3], [4, 5, 6]])
    print(f"t2: {t2}")
    # 3. 演示点乘
    t3 = t1 * t2
    print(f"t3: {t3}")
    t3 = t1.mul(t2)
    print(f"t3: {t3}")

输出结果如下:

t1: tensor([[1, 2, 3],
        [4, 5, 6]])
t2: tensor([[1, 2, 3],
        [4, 5, 6]])
t3: tensor([[ 1,  4,  9],
        [16, 25, 36]])
t3: tensor([[ 1,  4,  9],
        [16, 25, 36]])
矩阵运算

矩阵乘法运算要求第一个矩阵 shape:(n, m),第二个矩阵 shape:(m, p),两个矩阵点积运算 shape 为:(n, p)

  1. 运算符 @ 用于进行两个矩阵的乘积运算
  2. torch.matmul 对进行乘积运算的两个矩阵形状没有限定。对于输入的 shape 不同的张量,对应的最后几个维度必须符合矩阵运算规则
# 2. 定义函数,演示矩阵运算
def demo02():
    # 1. 定义张量:2行3列
    t1 = torch.tensor([[1, 2, 3], [4, 5, 6]])
    print(f"t1: {t1}")
    # 2. 定义张量:3行2列
    t2 = torch.tensor([[1, 2], [3, 4], [5, 6]])
    print(f"t2: {t2}")
    # 3. 演示矩阵运算
    t3 = t1 @ t2
    print(f"t3: {t3}")
    t3 = t1.matmul(t2)
    print(f"t3: {t3}")

输出结果如下:

t1: tensor([[1, 2, 3],
        [4, 5, 6]])
t2: tensor([[1, 2],
        [3, 4],
        [5, 6]])
t3: tensor([[22, 28],
        [49, 64]])
t3: tensor([[22, 28],
        [49, 64]])

张量运算函数

sum(), max(), min(), mean()
→ \to 对张量进行求和、求最大值、求最小值、求平均值,都有 dim 参数,0表示按列运算,1表示按行运算
pow(), sqrt(), exp(), log(), log2(), log10()
→ \to 对张量进行幂运算、开方运算、指数运算、自然对数运算、以2为底的对数运算、以10为底的对数运算,没有 dim 参数

import torch

# 1. 定义张量,记录初值
t1 = torch.tensor([
    [1, 2, 3],
    [4, 5, 6]],
    dtype=torch.float)
print(f"t1: {t1}")

# 2. 演示有 dim 参数的函数
# 2.1 演示 sum() 函数
print(f"t1.sum(): {t1.sum()}")              # 对所有元素求和
print(f"t1.sum(dim=0): {t1.sum(dim=0)}")    # 对每列元素求和
print(f"t1.sum(dim=1): {t1.sum(dim=1)}")    # 对每行元素求和
print("-" * 30)

# 2.2 演示 max() 函数
print(f"t1.max(): {t1.max()}")              # 对所有元素求最大值
print(f"t1.max(dim=0): {t1.max(dim=0)}")    # 对每列元素求最大值
print(f"t1.max(dim=1): {t1.max(dim=1)}")    # 对每行元素求最大值
print("-" * 30)

# 2.3 演示 min() 函数
print(f"t1.min(): {t1.min()}")              # 对所有元素求最小值
print(f"t1.min(dim=0): {t1.min(dim=0)}")    # 对每列元素求最小值
print(f"t1.min(dim=1): {t1.min(dim=1)}")    # 对每行元素求最小值
print("-" * 30)

# 2.4 演示 mean() 函数
print(f"t1.mean(): {t1.mean()}")            # 对所有元素求平均值
print(f"t1.mean(dim=0): {t1.mean(dim=0)}")  # 对每列元素求平均值
print(f"t1.mean(dim=1): {t1.mean(dim=1)}")  # 对每行元素求平均值
print("*" * 30)

# 3. 演示无 dim 参数的函数
# 3.1 演示 pow() 函数
print(f"t1.pow(2): {t1.pow(2)}")            # 对所有元素求平方
print(f"t1.pow(0.5): {t1.pow(0.5)}")        # 对所有元素求平方根
print(f"t1.pow(3): {t1.pow(3)}")            # 对所有元素求立方
print("-" * 30)
# 3.2 演示 sqrt() 函数
print(f"t1.sqrt(): {t1.sqrt()}")            # 对所有元素求平方根
print("-" * 30)
# 3.3 演示 exp() 函数
print(f"t1.exp(): {t1.exp()}")              # 对所有元素求指数
print("-" * 30)
# 3.4 演示 log() 函数
print(f"t1.log(): {t1.log()}")              # 对所有元素求自然对数
print("-" * 30)
# 3.5 演示 log2() 函数
print(f"t1.log2(): {t1.log2()}")            # 对所有元素求以2为底的对数
print("-" * 30)
# 3.6 演示 log10() 函数
print(f"t1.log10(): {t1.log10()}")          # 对所有元素求以10为底的对数
print("-" * 30)

输出结果如下:

t1: tensor([[1., 2., 3.],
        [4., 5., 6.]])
t1.sum(): 21.0
t1.sum(dim=0): tensor([5., 7., 9.])
t1.sum(dim=1): tensor([ 6., 15.])
------------------------------
t1.max(): 6.0
t1.max(dim=0): torch.return_types.max(
values=tensor([4., 5., 6.]),
indices=tensor([1, 1, 1]))
t1.max(dim=1): torch.return_types.max(
values=tensor([3., 6.]),
indices=tensor([2, 2]))
------------------------------
t1.min(): 1.0
t1.min(dim=0): torch.return_types.min(
values=tensor([1., 2., 3.]),
indices=tensor([0, 0, 0]))
t1.min(dim=1): torch.return_types.min(
values=tensor([1., 4.]),
indices=tensor([0, 0]))
------------------------------
t1.mean(): 3.5
t1.mean(dim=0): tensor([2.5000, 3.5000, 4.5000])
t1.mean(dim=1): tensor([2., 5.])
******************************
t1.pow(2): tensor([[ 1.,  4.,  9.],
        [16., 25., 36.]])
t1.pow(0.5): tensor([[1.0000, 1.4142, 1.7321],
        [2.0000, 2.2361, 2.4495]])
t1.pow(3): tensor([[  1.,   8.,  27.],
        [ 64., 125., 216.]])
------------------------------
t1.sqrt(): tensor([[1.0000, 1.4142, 1.7321],
        [2.0000, 2.2361, 2.4495]])
------------------------------
t1.exp(): tensor([[  2.7183,   7.3891,  20.0855],
        [ 54.5982, 148.4132, 403.4288]])
------------------------------
t1.log(): tensor([[0.0000, 0.6931, 1.0986],
        [1.3863, 1.6094, 1.7918]])
------------------------------
t1.log2(): tensor([[0.0000, 1.0000, 1.5850],
        [2.0000, 2.3219, 2.5850]])
------------------------------
t1.log10(): tensor([[0.0000, 0.3010, 0.4771],
        [0.6021, 0.6990, 0.7782]])
------------------------------

张量的操作

索引操作

简单行列索引

import torch

# 1. 设置随机种子
torch.manual_seed(24)

# 2. 创建随机张量
t1 = torch.randint(1, 10, (5, 5))
print(f"t1: {t1}")
print("-" * 30)

# 3. 演示张量的索引操作
# 3.1 简单行列索引,张量对象[行, 列]
# 场景1: 获取第2行的数据
print(t1[1])
print(t1[1, :]) # 效果同上,":"表示所有列
# 场景2: 获取第3列的数据
print(t1[:, 2])
print("-" * 30)

输出结果如下:

t1: tensor([[6, 9, 9, 2, 8],
        [7, 8, 5, 8, 4],
        [7, 4, 3, 9, 3],
        [6, 1, 4, 2, 8],
        [1, 2, 5, 7, 4]])
------------------------------
tensor([7, 8, 5, 8, 4])
tensor([7, 8, 5, 8, 4])
tensor([9, 5, 3, 4, 5])
------------------------------

列表索引

# 3.2 列表索引,张量对象[[行列表], [列列表]]
# 场景1: 获取(0,1)和(1,2)位置上的元素
print(t1[[0, 1], [1, 2]])
# 场景2: 获取(1,2)和(3,4)位置上的元素
print(t1[[1, 3], [2, 4]])
# 场景3: 获取第1,2行的2,3列共4个元素
print(t1[[[0], [1]], [1, 2]])
# print(t1[[1, 2, 3], [1, 2]]),行列表和列列表长度必须相同,不然会报错
print("-" * 30)

输出结果如下:

tensor([9, 5])
tensor([5, 8])
tensor([[9, 9],
        [8, 5]])
------------------------------

范围索引

# 3.3 范围索引
# 场景1: 获取前3行,前2列
print(t1[:3, :2])
# 场景2: 获取第2行到最后一行,前2列
print(t1[1:, :2])
# 场景3: 获取所有奇数行,偶数列
print(t1[::2, 1::2]) # 第1行到最后一行,每隔2行取1行,第0列到最后一列,每隔2列取1列
print("-" * 30)

输出结果如下:

tensor([[6, 9],
        [7, 8],
        [7, 4]])
tensor([[7, 8],
        [7, 4],
        [6, 1],
        [1, 2]])
tensor([[9, 2],
        [4, 9],
        [2, 7]])
------------------------------

布尔索引

# 3.4 布尔索引
# 演示布尔写法
# print(t1[torch.tensor([True, False, True, False, True]), :])
# 场景1: 获取第3列大于5的行数据
# 理解1: 在第3列的基础上,找到该列中大于5的元素
print(t1[t1[:, 2]>5, 2])
# 理解2: 在第3列的基础上,找到该列中大于5的元素的行索引,返回该行的所有元素
print(t1[t1[:, 2]>5])
# 场景2: 获取第2行大于5的列数据
# 理解1: 在第2行基础上,找到该行中大于5的列索引,返回该列的所有元素
print(t1[1, t1[1, :]>5]) # print(t1[1, t1[1]>5])
# 理解2: 在第2行的基础上,找该行所有列中大于5的元素
print(t1[1, t1[1, :]>5]) # print(t1[1, t1[1]>5])
print("-" * 30)

输出结果如下:

tensor([9])
tensor([[6, 9, 9, 2, 8]])
tensor([7, 8, 8])
tensor([7, 8, 8])
------------------------------

多维索引

# 3.5 多维索引
# 创建3维张量:2个3行4列的张量
t2 = torch.randint(1, 10, (2, 3, 4))
# (2, 3, 4) 分别对应0轴、1轴、2轴
print(f"t2: {t2}")
# 需求1: 获取0轴上的第1个元素
print(t2[0, :, :]) # print(t2[0])
# 需求2: 获取1轴上的第1个元素
print(t2[:, 0, :]) # print(t2[:, 1])
# 需求3: 获取2轴上的第1个元素
print(t2[:, :, 0])
print("-" * 30)

输出结果如下:

t2: tensor([[[3, 4, 6, 5],
         [8, 8, 8, 3],
         [4, 9, 6, 7]],

        [[2, 8, 8, 5],
         [6, 4, 2, 2],
         [2, 7, 9, 4]]])
tensor([[3, 4, 6, 5],
        [8, 8, 8, 3],
        [4, 9, 6, 7]])
tensor([[3, 4, 6, 5],
        [2, 8, 8, 5]])
tensor([[3, 8, 4],
        [2, 6, 2]])
------------------------------

0 轴、1 轴、2 轴解释:

[0轴,2个元素
	[1轴,3个元素
		[2轴,4个元素
			3, 
			4, 
			6, 
			5],
  	[8, 8, 8, 3],
  	[4, 9, 6, 7]
  ],
  [
  	[2, 8, 8, 5],
    [6, 4, 2, 2],
    [2, 7, 9, 4]
  ]
]

形状操作

reshape()

可以在保证张量数据不变的前提下改变数据的维度,将其转换成指定的形状。

import torch  
  
torch.manual_seed(42)  
  
# 定义函数,演示 reshape()def demo01():  
    # 1. 创建张量  
    t1 = torch.randint(1, 10, size = (2, 3))  
    print(f"t1: {t1}, shape: {t1.shape}, row: {t1.shape[0]}, col: {t1.shape[1]}, {t1.shape[-1]}")  
  
    # 2. 形状操作:reshape(),把t1->3行2列、1行6列、6行1列  
    t2 = t1.reshape(3, 2)  
    print(f"t2: {t2}, shape: {t2.shape}, row: {t2.shape[0]}, col: {t2.shape[1]}, {t2.shape[-1]}")  
    t2 = t1.reshape(1, 6)  
    print(f"t2: {t2}, shape: {t2.shape}, row: {t2.shape[0]}, col: {t2.shape[1]}, {t2.shape[-1]}")  
    t2 = t1.reshape(6, 1)  
    print(f"t2: {t2}, shape: {t2.shape}, row: {t2.shape[0]}, col: {t2.shape[1]}, {t2.shape[-1]}")  
    # 用reshape转换需要转换前与转换后的元素个数一致

输出结果如下:

t1: tensor([[7, 6, 8],
        [5, 1, 3]]), shape: torch.Size([2, 3]), row: 2, col: 3, 3
t2: tensor([[7, 6],
        [8, 5],
        [1, 3]]), shape: torch.Size([3, 2]), row: 3, col: 2, 2
t2: tensor([[7, 6, 8, 5, 1, 3]]), shape: torch.Size([1, 6]), row: 1, col: 6, 6
t2: tensor([[7],
        [6],
        [8],
        [5],
        [1],
        [3]]), shape: torch.Size([6, 1]), row: 6, col: 1, 1

squeeze()

删除形状为 1 的维度(降维)

# 定义函数,演示 squeeze()
def demo03():
    # 定义2行3列的张量
    t1 = torch.randint(1, 10, size=(2, 1, 3, 1, 1))
    print(f"t1: {t1}, shape: {t1.shape}, row: {t1.shape[0]}, col: {t1.shape[1]}")  # (2, 3)
    t2 = t1.squeeze()
    print(f"t2: {t2}, shape: {t2.shape}, row: {t2.shape[0]}, col: {t2.shape[1]}")  # (2, 3)

输出结果如下:

t1: tensor([[[[[7]],

          [[6]],

          [[8]]]],



        [[[[5]],

          [[1]],

          [[3]]]]]), shape: torch.Size([2, 1, 3, 1, 1]), row: 2, col: 1
t2: tensor([[7, 6, 8],
        [5, 1, 3]]), shape: torch.Size([2, 3]), row: 2, col: 3

unsqueeze()

添加形状为 1 的维度(升维)

# 定义函数,演示 unsqueeze()
def demo02():
    # 定义2行3列的张量
    t1 = torch.randint(1, 10, size = (2, 3))
    print(f"t1: {t1}, shape: {t1.shape}, row: {t1.shape[0]}, col: {t1.shape[1]}") # (2, 3)

    # 在0维(轴)添加一个维度
    t2 = t1.unsqueeze(0)
    print(f"t2: {t2}, "
          f"shape: {t2.shape}, "
          f"row: {t2.shape[0]}, "
          f"col: {t2.shape[1]}") # (1, 2, 3),在0维(最前面)添加一个维度,变成了“1个批次 × 2行 × 3列”的3维张量

    # 在1维(轴)添加一个维度
    t3 = t1.unsqueeze(1)
    print(f"t3: {t3}, "
          f"shape: {t3.shape}, "
          f"row: {t3.shape[0]}, "
          f"col: {t3.shape[1]}") # (2, 1, 3),在1维(行和列之间)添加一个维度,变成了“2个批次 × 1行 × 3列”的3维张量

    # 在2维(轴)添加一个维度
    t4 = t1.unsqueeze(2)
    print(f"t4: {t4}, "
          f"shape: {t4.shape}, "
          f"row: {t4.shape[0]}, "
          f"col: {t4.shape[1]}") # (2, 3, 1),在2维(最后面)添加一个维度,变成了“2个批次 × 3行 × 1列”的3维张量

输出结果如下:

t1: tensor([[7, 6, 8],
        [5, 1, 3]]), shape: torch.Size([2, 3]), row: 2, col: 3
t2: tensor([[[7, 6, 8],
         [5, 1, 3]]]), shape: torch.Size([1, 2, 3]), row: 1, col: 2
t3: tensor([[[7, 6, 8]],

        [[5, 1, 3]]]), shape: torch.Size([2, 1, 3]), row: 2, col: 1
t4: tensor([[[7],
         [6],
         [8]],

        [[5],
         [1],
         [3]]]), shape: torch.Size([2, 3, 1]), row: 2, col: 3

transpose()

可以实现交换张量形状的指定维度

# 定义函数,演示 transpose()
def demo04():
    # 创建张量
    t1 = torch.randint(1, 10, size=(2, 3, 4))
    print(f"t1: {t1}, shape: {t1.shape}")
    print("-" * 30)

    # 改变维度从(2, 3, 4) -> (3, 2, 4)
    t2 = t1.transpose(0, 1)
    print(f"t1: {t1}, shape: {t1.shape}")
    print(f"t2: {t2}, shape: {t2.shape}")

输出结果如下:

t1: tensor([[[7, 6, 8, 5],
         [1, 3, 8, 6],
         [5, 3, 5, 5]],

        [[9, 1, 1, 5],
         [3, 5, 4, 5],
         [5, 9, 2, 6]]]), shape: torch.Size([2, 3, 4])
------------------------------
t1: tensor([[[7, 6, 8, 5],
         [1, 3, 8, 6],
         [5, 3, 5, 5]],

        [[9, 1, 1, 5],
         [3, 5, 4, 5],
         [5, 9, 2, 6]]]), shape: torch.Size([2, 3, 4])
t2: tensor([[[7, 6, 8, 5],
         [9, 1, 1, 5]],

        [[1, 3, 8, 6],
         [3, 5, 4, 5]],

        [[5, 3, 5, 5],
         [5, 9, 2, 6]]]), shape: torch.Size([3, 2, 4])

permute()

可以一次交换更多的维度

# 定义函数,演示 permute()
def demo05():
    # 创建张量
    t1 = torch.randint(1, 10, size=(2, 3, 4))
    print(f"t1: {t1}, shape: {t1.shape}")
    print("-" * 30)

    # 改变维度从(2, 3, 4) -> (4, 3, 2)
    t2 = t1.permute(2, 1, 0)
    print(f"t1: {t1}, shape: {t1.shape}")
    print(f"t2: {t2}, shape: {t2.shape}")

输出结果如下:

t1: tensor([[[7, 6, 8, 5],
         [1, 3, 8, 6],
         [5, 3, 5, 5]],

        [[9, 1, 1, 5],
         [3, 5, 4, 5],
         [5, 9, 2, 6]]]), shape: torch.Size([2, 3, 4])
------------------------------
t1: tensor([[[7, 6, 8, 5],
         [1, 3, 8, 6],
         [5, 3, 5, 5]],

        [[9, 1, 1, 5],
         [3, 5, 4, 5],
         [5, 9, 2, 6]]]), shape: torch.Size([2, 3, 4])
t2: tensor([[[7, 9],
         [1, 3],
         [5, 5]],

        [[6, 1],
         [3, 5],
         [3, 9]],

        [[8, 1],
         [8, 4],
         [5, 2]],

        [[5, 5],
         [6, 5],
         [5, 6]]]), shape: torch.Size([4, 3, 2])

view()contiguous()is_contiguous()

view() 也可以用于修改张量的形状,只能用于修改连续的张量。在 PyTorch 中,有些张量的底层数据在内存中存储顺序与其在张量中的逻辑顺序不一致,view() 无法对这样的张量进行变形处理,例如:一个张量经过了 transpose() 或者 permute() 的处理之后,就无法使用 view() 进行形状操作。

# 定义函数,演示 view()、contiguous()、is_contiguous()
def demo06():
    # 创建张量
    t1 = torch.randint(1, 10, size=(2, 3))
    print(f"t1: {t1}, shape: {t1.shape}")
    # 判断张量是否连续,即张量中的顺序和内存中存储顺序是否一致
    print(f"t1 是否连续: {t1.is_contiguous()}")

     # 改变维度从(2, 3) -> (3, 2)
    t2 = t1.view(3, 2)
    print(f"t2: {t2}, shape: {t2.shape}")
    # 判断张量是否连续,即张量中的顺序和内存中存储顺序是否一致
    print(f"t2 是否连续: {t2.is_contiguous()}")

    # 通过transpose()交换维度,从(2, 3) -> (3, 2)
    t3 = t1.transpose(0, 1)
    print(f"t3: {t3}, shape: {t3.shape}")
    # 判断张量是否连续,即张量中的顺序和内存中存储顺序是否一致
    print(f"t3 是否连续: {t3.is_contiguous()}")

    # 尝试改变 t3 的维度从(3, 2) -> (2, 3)
    # t4 = t3.view(2, 3)
    # print(f"t4: {t4}, shape: {t4.shape}")
    # # 判断张量是否连续,即张量中的顺序和内存中存储顺序是否一致
    # print(f"t4 是否连续: {t4.is_contiguous()}")
    # 报错:RuntimeError: view size is not compatible with input tensor's size and stride (at least one dimension spans across two contiguous subspaces). Use .reshape(...) instead.

    # 通过contiguous()方法,将 t3 转换为连续张量
    t3_contiguous = t3.contiguous()
    print(f"t3_contiguous: {t3_contiguous}, shape: {t3_contiguous.shape}")
    # 判断张量是否连续,即张量中的顺序和内存中存储顺序是否一致
    print(f"t3_contiguous 是否连续: {t3_contiguous.is_contiguous()}")

输出结果如下:

t1: tensor([[7, 6, 8],
        [5, 1, 3]]), shape: torch.Size([2, 3])
t1 是否连续: True
t2: tensor([[7, 6],
        [8, 5],
        [1, 3]]), shape: torch.Size([3, 2])
t2 是否连续: True
t3: tensor([[7, 5],
        [6, 1],
        [8, 3]]), shape: torch.Size([3, 2])
t3 是否连续: False
t3_contiguous: tensor([[7, 5],
        [6, 1],
        [8, 3]]), shape: torch.Size([3, 2])
t3_contiguous 是否连续: True

拼接操作

torch.cat()

可以将多个张量根据指定的维度拼接起来,不改变维度数,除了拼接的那个维度外,其它维度数必须保持一致

import torch

# 创建两个张量
t1 = torch.randint(1, 10, (2, 3))
print(f"t1: {t1}, shape: {t1.shape}")

t2 = torch.randint(1, 10, (2, 3))
print(f"t2: {t2}, shape: {t2.shape}")

# 演示张量拼接
t3 = torch.cat([t1, t2], dim=0)
print(f"t3: {t3}, shape: {t3.shape}")

输出结果如下:

t1: tensor([[2, 4, 7],
        [4, 4, 8]]), shape: torch.Size([2, 3])
t2: tensor([[9, 3, 8],
        [5, 4, 8]]), shape: torch.Size([2, 3])
t3: tensor([[2, 4, 7],
        [4, 4, 8],
        [9, 3, 8],
        [5, 4, 8]]), shape: torch.Size([4, 3])

但是由于拼接的维度是 0,如果其他维度不一致就会报错:

t1 = torch.randint(1, 10, (2, 3))
print(f"t1: {t1}, shape: {t1.shape}")

t2 = torch.randint(1, 10, (2, 4))
print(f"t2: {t2}, shape: {t2.shape}")

报错:

RuntimeError: Sizes of tensors must match except in dimension 0. Expected size 3 but got size 4 for tensor number 1 in the list.

torch.stack()

会在一个新的维度上连续一系列张量,这会增加一个新维度,并且所有输入张量的形状必须完全相同

import torch

# 创建两个张量
t1 = torch.randint(1, 10, (2, 3))
print(f"t1: {t1}, shape: {t1.shape}")

t2 = torch.randint(1, 10, (2, 3))
print(f"t2: {t2}, shape: {t2.shape}")

# 演示张量拼接
t3 = torch.stack([t1, t2], dim=0) # (2, 3) + (2, 3) -> (2, 2, 3)
print(f"t3: {t3}, shape: {t3.shape}")
t3 = torch.stack([t1, t2], dim=1) # (2, 3) + (2, 3) -> (2, 2, 3)
print(f"t3: {t3}, shape: {t3.shape}")
t3 = torch.stack([t1, t2], dim=2) # (2, 3) + (2, 3) -> (2, 3, 2)
print(f"t3: {t3}, shape: {t3.shape}")

输出结果如下:

t1: tensor([[5, 5, 3],
        [6, 9, 9]]), shape: torch.Size([2, 3])
t2: tensor([[4, 3, 7],
        [8, 9, 4]]), shape: torch.Size([2, 3])
t3: tensor([[[5, 5, 3],
         [6, 9, 9]],

        [[4, 3, 7],
         [8, 9, 4]]]), shape: torch.Size([2, 2, 3])
t3: tensor([[[5, 5, 3],
         [4, 3, 7]],

        [[6, 9, 9],
         [8, 9, 4]]]), shape: torch.Size([2, 2, 3])
t3: tensor([[[5, 4],
         [5, 3],
         [3, 7]],

        [[6, 8],
         [9, 9],
         [9, 4]]]), shape: torch.Size([2, 3, 2])
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐