pytorch api文档:张量的 .view()形状变换方法

介绍

.view() 方法,这个方法是张量形状变换的核心工具,用于在不改变张量数据的前提下,调整张量的维度结构(如将一维张量转为二维、将四维特征图展平为二维等)。

作用

返回一个与原张量共享内存的新视图(新形状),张量的 总元素数必须保持不变(即形状的乘积相等),数据本身不复制、不修改,仅改变维度的解读方式。

关键特征

新张量与原张量共享内存,修改其中一个,另一个也会同步变化。

语法

Tensor.view(*shape) → Tensor

参数:

  • *shape:指定新的形状,可以是单个整数、多个整数,或包含 -1(自动计算该维度的大小,且只能有一个 -1);

对比 .reshape()

.reshape() 是 .view() 的升级版,功能类似,但 .view() 仅支持连续内存的张量,.reshape() 可自动处理非连续张量(必要时复制数据)。

例子

通过不同场景的示例,演示 .view() 的核心用法:

import torch


# 原张量:shape [2, 3](总元素数=6)
x = torch.tensor([[1, 2, 3], 
                  [4, 5, 6]])
print("原张量形状:", x.shape)  # torch.Size([2, 3])

示例1:基础形状变换(总元素数不变)

转为 [3, 2]

x_view1 = x.view(3, 2)
print("\nview(3, 2) 结果:")
print(x_view1)
# 输出:
# tensor([[1, 2],
#         [3, 4],
#         [5, 6]])

示例2:使用-1自动计算维度(常用!)

# -1 表示“自动计算该维度的大小”,仅能出现一次
x_view2 = x.view(-1)  # 展平为一维(6个元素)
print("\nview(-1) 结果(展平):", x_view2)  # tensor([1, 2, 3, 4, 5, 6])

x_view3 = x.view(2, -1)  # 固定第一维为2,第二维自动算(3)
print("view(2, -1) 形状:", x_view3.shape)  # torch.Size([2, 3])

x_view4 = x.view(-1, 3)  # 固定第二维为3,第一维自动算(2)
print("view(-1, 3) 形状:", x_view4.shape)  # torch.Size([2, 3])

示例3:高维张量变换(如CNN特征图展平)

# 模拟CNN输出:[batch_size=2, channel=3, height=4, width=4](总元素=2*3*4*4=96)
feat = torch.randn(2, 3, 4, 4)
# 展平为 [2, 3*4*4](batch保留,特征展平)
feat_flat = feat.view(2, -1)
print("\n高维张量view后形状:", feat_flat.shape)  # torch.Size([2, 48])

示例4:共享内存特性(修改新视图,原张量也变)

x_view1[0, 0] = 100  # 修改view后的张量
print("\n修改view张量后,原张量:")
print(x)  # 原张量[0,0]也变为100!
# 输出:
# tensor([[100,   2,   3],
#         [  4,   5,   6]])

使用场景

.view() 是深度学习中高频使用的操作,典型场景包括:

全连接层前的特征展平

CNN模型中,卷积层输出的四维张量([batch, channel, h, w])需展平为二维([batch, channel*h*w])才能输入全连接层:

class CNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv = nn.Conv2d(3, 16, 3)  # 输出[batch,16,30,30](假设输入224x224)
        self.fc = nn.Linear(16*30*30, 10)  # 全连接层需要一维特征

    def forward(self, x):
        x = self.conv(x)
        # 展平:保留batch维度,其余展平
        x = x.view(x.size(0), -1)  # x.size(0) = batch_size,-1自动计算16*30*30
        x = self.fc(x)
        return x

调整批量数据形状

将一维的批量数据(如 [batch*seq_len, dim])恢复为二维([batch, seq_len, dim]):

# 输入:[8, 768](batch=2, seq_len=4,总长度=8)
x = torch.randn(8, 768)
# 恢复为 [2, 4, 768]
x_reshaped = x.view(2, 4, 768)

维度压缩/扩展

临时调整维度以适配层的输入要求(如将 [batch, dim] 转为 [batch, 1, dim] 适配卷积层):

x = torch.randn(32, 64)  # [batch=32, dim=64]
# 转为 [32, 1, 64](适配Conv1d的输入格式)
x_expand = x.view(32, 1, 64)

注意事项

总元素数必须相等

新形状的乘积必须等于原张量的总元素数,否则报错。例如:

x = torch.randn(2, 3)
x.view(4, 2)  # 报错!2*3=6 ≠ 4*2=8

仅支持连续内存张量

如果张量经过转置(.t())、切片等操作后内存不连续,.view() 会报错,此时需用 .contiguous() 先整理内存,或直接用 .reshape():

x = torch.randn(2, 3).t()  # 转置后内存不连续
# x.view(6)  # 报错!
x_contig = x.contiguous()
x_contig.view(6)  # 正常
# 更简单:用reshape
x.reshape(6)  # 自动处理非连续内存

共享内存的风险

修改 .view() 返回的张量会同步修改原张量,若需独立张量,需用 .clone() 复制:

x = torch.tensor([1,2,3])
x_view = x.view(3,1).clone()  # 复制后不再共享内存
x_view[0,0] = 100
print(x)  # 仍为[1,2,3],不受影响

-1的使用限制

.view() 中 -1 只能出现一次,用于自动计算维度,多次出现会报错:

x.view(-1, -1)  # 报错!只能有一个-1

总结

  1. .view() 核心是共享内存的形状变换,总元素数必须不变,常用 -1 自动计算维度;
  2. 典型场景:CNN特征展平、批量数据形状调整、维度适配;
  3. 注意内存连续性问题(报错时用 .contiguous() 或 .reshape()),以及共享内存的修改风险。

原文出处:/show_1GW2dKE8Ksnx.html