☰
AI工程师必修课:标量、向量、矩阵、张量的工程本质
2026/10/14 5:13:58 网站建设 项目流程

1. 这不是数学课,是AI工程师的“肌肉记忆”训练

你打开任何一本深度学习框架的官方文档,不到三分钟就会撞上这几个词:标量、向量、矩阵、张量。它们不像“卷积”“反向传播”那样自带技术光环,也不像“Transformer”“LoRA”那样刷屏热搜,但它们是你每天写代码时最频繁调用的底层构件——就像厨师对刀工的掌控,不常被提起,却决定每一道菜的成败。

我带过不少刚转行进AI领域的同学,发现一个特别有意思的现象:很多人能讲清楚BERT的注意力机制,却在写torch.matmul(a, b)时报错说size mismatch;能复现ResNet的结构图,却在调试数据加载器时卡在expected 4D input, got 3D。问题出在哪?不是模型不懂,而是对标量、向量、矩阵、张量这四层数据形态的理解,还停留在高中数学课本里——把它们当成抽象符号,而不是内存中真实存在的、有形状、有方向、有维度约束的“活数据”。

这组概念不是理论铺垫,而是AI工程实践的操作界面。你写的每一行x = x + 1,每一次model(x)调用,每一次loss.backward()触发,背后都是这四类数据在内存中按规则搬运、对齐、广播、压缩。它们决定了你的GPU显存能不能装下batch size=32的数据,决定了你的梯度更新是不是真的作用在了正确的权重上,甚至决定了你调试时打印出来的shape到底是(64, 128)还是(128, 64)——而这两个数字顺序颠倒,可能就是模型完全不收敛的根源。

所以这篇内容不叫“线性代数复习”,它是一份面向AI实操者的数据形态手册。它不推导行列式,不证明秩定理,只回答你在Jupyter Notebook里敲下第一行import torch之后,马上会遇到的真实问题:为什么torch.tensor([1, 2, 3])和torch.tensor([[1, 2, 3]])是两种完全不同的东西?为什么np.array([1, 2, 3]) * np.array([4, 5, 6])是逐元素相乘,而torch.matmul()却要求严格对齐?为什么你把一张图片读成(224, 224, 3)传给模型,却总被提示expected 4D tensor?

这些问题的答案,就藏在这四个看似简单的词里。它们是你和AI世界对话的第一套语法,不是选修,是必修;不是前置知识,是运行时环境。接下来,我会用你每天都在写的代码片段、调试时的真实报错、以及GPU内存里数据的实际排布方式,一层层剥开它们的本质。你不需要记住定义,只需要记住:当你看到一个数字、一串列表、一个表格、一张图片,脑子里要立刻条件反射地问——它的shape是什么?它的维度语义是什么?它在计算图里怎么流动?

2. 标量:最不起眼,却最危险的“单点故障”

2.1 标量不是“一个数”,而是“零维空间里的孤岛”

在数学课本里,标量被定义为“只有大小、没有方向的量”。这个定义没错,但在AI工程中,它漏掉了最关键的一点:标量是一个维度为0的张量,是所有高维数据的原子单位,也是最容易引发隐性错误的源头。

我们来看一段再普通不过的PyTorch代码:

import torch x = torch.tensor(5.0) # 标量 y = torch.tensor([1, 2, 3]) # 向量 z = x + y # 广播成功:[6., 7., 8.]

这段代码能跑通,但如果你把x写成torch.tensor(5)(注意没有.0),结果会怎样?答案是:它依然能跑通,但x.dtype变成了torch.int64,而y.dtype是torch.int64,看起来没问题。可一旦你后续做除法或需要梯度计算,比如loss = (z - target) ** 2,整数除法的截断效应就会悄悄污染整个训练过程——而这种错误,不会报错,只会让loss曲线变得诡异平滑,让你花三天时间排查数据预处理。

这就是标量的“危险性”:它太小了,小到你几乎不会给它单独声明变量,小到你习惯性地把它当作“背景板”,但它参与的每一次运算,都会通过类型广播(type broadcasting)和形状广播(shape broadcasting),把它的属性强加给整个计算链。

提示:在PyTorch中,torch.tensor(5)和torch.tensor([5])是本质不同的。前者shape=torch.Size([]),后者shape=torch.Size([1])。前者是标量,后者是一维向量(只有一个元素)。很多初学者在写损失函数时误用后者,导致loss变成一个含单元素的tensor,loss.backward()虽然能执行,但梯度会错误地累积在那个“假向量”的维度上,而不是标量loss该有的无维度梯度。

2.2 标量的三大工程陷阱与避坑实操

陷阱一:隐式类型转换导致的梯度消失

这是我在某次模型调试中踩过的坑。当时训练一个回归任务,loss始终不下降。最后发现是标签数据用了np.int32读入,经过torch.from_numpy()后变成torch.int32,而模型输出是float32。当计算loss = F.mse_loss(pred, label)时,PyTorch会尝试将label转为float,但这个转换发生在loss计算内部,梯度回传时,int32部分的梯度直接丢失。解决方案极其简单,但必须刻进DNA:

# ✅ 正确:从源头确保标量/标签是浮点型 label = torch.tensor(label, dtype=torch.float32) # ❌ 危险:依赖框架自动转换 label = torch.from_numpy(label_np) # dtype由numpy数组决定,不可控

陷阱二:标量作为索引引发的维度错乱

另一个高频场景是数据切片。比如你想取batch中第一个样本:

batch = torch.randn(32, 3, 224, 224) # [B, C, H, W] first_sample = batch[0] # shape: [3, 224, 224] —— 正确! # 但如果你写成: first_sample = batch[torch.tensor(0)] # shape: [3, 224, 224] —— 看似一样?

表面上结果相同,但batch[torch.tensor(0)]在PyTorch中触发的是高级索引(advanced indexing),它会强制在结果中新增一个维度,实际得到的是[1, 3, 224, 224],只是因为torch.tensor(0)是标量,PyTorch做了特殊优化才“看起来”一样。一旦你换成batch[torch.tensor([0, 1])],区别就暴露了:前者是[2, 3, 224, 224],后者是[2, 3, 224, 224],但内部计算图完全不同。在复杂模型中,这种差异会导致view()或reshape()操作失败。

陷阱三:标量loss的.item()调用时机错误

这是性能杀手。loss.item()会把GPU tensor同步回CPU并转为Python原生数值,这个操作代价极高。新手常犯的错误是:

# ❌ 每次迭代都取.item(),严重拖慢训练 for epoch in range(10): for x, y in dataloader: loss = criterion(model(x), y) print(f"Loss: {loss.item()}") # 每步都同步! loss.backward()

正确做法是只在需要日志或监控时批量取值:

# ✅ 每10个batch取一次,用.detach()避免计算图 if i % 10 == 0: print(f"Batch {i}, Loss: {loss.detach().cpu().item()}")

注意:.item()只能用于标量tensor。如果你对一个shape为[1]的tensor调用.item(),它也能工作,但这是一种“危险的宽容”。真正的标量是[],而[1]是向量。这种混淆是很多维度bug的温床。

2.3 标量的底层真相:它在内存里根本“不存在”

这可能是最反直觉的一点:一个标量tensor,在GPU显存里并不占据独立的存储块。它只是一个指向某个内存地址的“指针+元数据”结构。当你创建a = torch.tensor(3.14),PyTorch分配的不是4字节(float32)的连续空间,而是一个包含data_ptr(指向某块已分配内存)、shape=[]、dtype=torch.float32的轻量级对象。它的值要么是寄存器里的立即数,要么是某个大tensor的某个元素的引用。

这意味着什么?意味着标量的“计算”几乎不耗时,但它的语义绑定(semantic binding)至关重要。torch.tensor(3.14)和torch.tensor(3.14).requires_grad_(True)在内存布局上可能完全一致,但后者会在计算图中注册一个叶子节点,前者则不会。这种差异,全靠标量对象携带的元数据(metadata)来区分。

所以,标量的工程本质是:一个携带完整类型、形状、梯度需求元信息的零维数据句柄。它不是数字,是数据世界的“身份证”。

3. 向量:一维数据的“方向感”与维度幻觉

3.1 向量不是“一串数字”,而是“有方向的线段”在计算图中的投影

高中物理里,向量是有大小和方向的量。在AI中,这个“方向”被翻译成了维度语义(dimensional semantics)。[1, 2, 3]和[[1], [2], [3]]在数学上都可以表示三维向量,但在PyTorch/TensorFlow中,它们是两种完全不同的对象:

  • torch.tensor([1, 2, 3])→shape=torch.Size([3]),一维,行向量(row vector)
  • torch.tensor([[1], [2], [3]])→shape=torch.Size([3, 1]),二维,列向量(column vector)

这个区别绝非形式主义。它直接决定了矩阵乘法的结果:

v_row = torch.tensor([1, 2, 3]) # [3] v_col = torch.tensor([[1], [2], [3]]) # [3, 1] W = torch.randn(3, 4) # [3, 4] # ✅ 正确:行向量 × 权重矩阵 = [1, 4] 输出 output1 = torch.matmul(v_row.unsqueeze(0), W) # [1, 3] @ [3, 4] = [1, 4] # ✅ 正确:列向量 × 权重矩阵的转置 = [3, 1] @ [4, 3] 不匹配! # 必须先转置W:v_col @ W.T → [3, 1] @ [4, 3] 仍不匹配 output2 = torch.matmul(W, v_col) # [3, 4] @ [3, 1] → shape mismatch! # 正确写法: output2 = torch.matmul(W, v_col) # [3, 4] @ [3, 1] → error # 应该是: output2 = torch.matmul(W, v_col) # 错!W是[3,4],v_col是[3,1],内维3≠4 # 正确是:v_col.T @ W → [1,3] @ [3,4] = [1,4]

看出来了吗?向量的形状,本质上是在告诉计算引擎:“我的哪个维度代表‘样本’,哪个代表‘特征’”。[3]这个shape,隐含了一个约定:一维向量默认是特征向量(feature vector),其长度即特征数。所以当你把它喂给一个[in_features, out_features]的线性层时,框架会自动在前面补一个batch维度,变成[1, 3],然后做矩阵乘。

这就是向量的“维度幻觉”——它看起来只有一维,但AI框架在背后为你做了大量隐形的维度管理。这种便利性是双刃剑:它让你少写几行unsqueeze(),但也让你在debug时一头雾水。

3.2 向量的四大实操痛点与现场解决方案

痛点一:squeeze()和unsqueeze()的“维度迷宫”

新手最常问的问题:“为什么我x.squeeze()没效果?”答案永远是:squeeze()只去掉长度为1的维度。如果x.shape = [3, 1, 4],x.squeeze()后是[3, 4];但如果x.shape = [3, 2, 4],squeeze()毫无反应。更危险的是,squeeze(0)只去掉第0维(batch维),如果第0维长度不是1,它会直接报错。

实操心得:永远用x.unsqueeze(-1)代替x.unsqueeze(0),除非你100%确定batch维度在最前。-1代表最后一个维度,这是最安全的“追加维度”方式,因为它不依赖你对当前shape的先验判断。

# ✅ 安全:无论x是[3]还是[3,4],都追加最后一个维度 x_2d = x.unsqueeze(-1) # [3]→[3,1]; [3,4]→[3,4,1] # ❌ 危险:假设x是[3],但实际是[3,4],则x.unsqueeze(0)=[1,3,4],语义全变 x_wrong = x.unsqueeze(0) # 可能引入错误的batch维度

痛点二:向量拼接(concat)时的维度对齐灾难

torch.cat([a, b], dim=0)要求a和b除了dim=0外,其他维度必须完全一致。但新手常把两个[3]向量拼成[6],却忘了如果其中一个其实是[1, 3],cat就会失败。

解决方案:在拼接前,用view(-1)强制拉平,再unsqueeze(0)统一为行向量:

# ✅ 统一范式:不管原始shape,先拉平再拼 a_flat = a.view(-1) # [3] or [1,3] or [3,1] → 都变成[3] b_flat = b.view(-1) combined = torch.cat([a_flat, b_flat], dim=0) # [6]

痛点三:向量归一化(L2 norm)的维度陷阱

torch.nn.functional.normalize(x, p=2, dim=0)是对第0维做归一化,即把每个“列”当成一个向量来归一。但如果你的x是[3](一维),dim=0就是对整个向量归一,结果是一个标量。而你真正想要的,往往是“对特征维度归一”,即dim=-1(最后一个维度)。

# ✅ 正确:对特征维度归一(无论x是[3]还是[32,3]) x_norm = F.normalize(x, p=2, dim=-1) # ❌ 错误:在batched数据上用dim=0,会把每个特征通道单独归一,破坏样本间关系 x_wrong = F.normalize(x, p=2, dim=0) # [32,3] → 对32个样本的同一特征归一,错误!

痛点四:向量索引的“静默降维”

x[0]从[3]向量中取第一个元素,返回的是一个标量tensor(1),shape=torch.Size([])。这个操作叫静默降维(silent squeeze)。它很便利,但也埋雷:如果你期望返回的还是一个向量(比如要继续做sum()或mean()),这个标量会让你的代码在后续步骤崩溃。

解决方案:用x[0:1]代替x[0],它返回的是[1],保持了一维性:

# ✅ 保持维度:x[0:1] 返回 shape=[1],可安全参与向量运算 first_elem_vec = x[0:1] # [3] → [1] # ❌ 静默降维:x[0] 返回 shape=[],后续运算可能报错 first_elem_scalar = x[0] # [3] → []

3.3 向量的物理隐喻:它是“特征空间里的坐标轴”

你可以把一个[n]向量想象成n维空间里的一条射线,它的每个元素,就是这条射线在对应坐标轴上的投影长度。[1, 0, 0]是x轴方向的单位向量,[0.707, 0.707, 0]是xy平面45度方向的向量。

在AI中,这个空间就是特征空间(feature space)。模型的每一层,都在学习如何旋转、缩放、平移这个空间,让同类样本的向量彼此靠近,异类样本的向量彼此远离。所以,当你看到embedding = model.get_embedding(text)返回一个[768]向量时,你看到的不是一个数字列表,而是文本在768维语义空间里的一个精确坐标。

理解这一点,你就明白为什么cosine_similarity(a, b)比euclidean_distance(a, b)更适合衡量文本相似性——余弦相似度只关心方向(角度),不关心长度(模长),而文本的语义方向,远比它的绝对强度重要。

4. 矩阵:二维数据的“结构骨架”与计算引擎

4.1 矩阵不是“表格”,而是“线性变换的操作符”

教科书说矩阵是m×n个数的矩形排列。在AI工程中,矩阵是线性变换(linear transformation)的具象化表达。W = torch.randn(768, 128)这个矩阵,不是一个静态的数据表,而是一个“指令集”:它告诉计算引擎,“把一个768维的输入向量,通过768×128次乘加运算,映射成一个128维的输出向量”。

这个视角彻底改变了你对矩阵维度的理解。W.shape = [768, 128],其中:

  • 768是输入维度(in_features):它必须和输入向量的长度严格匹配。
  • 128是输出维度(out_features):它决定了下一层能接收多少个特征。

所以,矩阵乘法y = W @ x的合法性检查,本质上是维度契约(dimensional contract)的校验:W的列数(128)必须等于x的行数(768)?不,恰恰相反!是W的行数(768)必须等于x的长度(768)。因为x是一维向量[768],W @ x要求W的列数等于x的长度,即W必须是[?, 768]。等等,这和上面说的[768, 128]矛盾?

不矛盾。这里的关键是:向量x在矩阵乘法中,总是被当作列向量(column vector)来对待。所以x.shape = [768],在计算时被隐式视为[768, 1]。那么W @ x就要求W的列数(第二个维度)等于x的行数(768),因此W必须是[?, 768]。但我们的W是[768, 128],列数是128,不等于768!

啊哈!这就是新手最大的困惑来源。真相是:@运算符要求左矩阵的列数等于右矩阵的行数。所以W @ x中,W是左矩阵,x是右矩阵。x是[768],被当作[768, 1],所以W的列数必须是768。因此,W应该是[128, 768],而不是[768, 128]!

但PyTorch的nn.Linear层,weight参数确实是[out_features, in_features],即[128, 768]。所以W @ x是合法的:[128, 768] @ [768, 1] = [128, 1],再squeeze(-1)得到[128]。

这个绕口令般的逻辑,正是矩阵作为“操作符”的核心:它的形状,编码了它能接受什么输入、能产生什么输出的全部契约。你不需要背公式,只需要记住:矩阵的“输入端”是它的列,“输出端”是它的行。

4.2 矩阵的五大工程挑战与硬核解法

挑战一:torch.matmul()vstorch.bmm()vs*(逐元素乘)

这三个操作经常被混用,但语义天差地别:

操作输入A输入B运算类型典型用途
A * B[2,3][2,3]逐元素乘(Hadamard)Masking, gating
torch.matmul(A, B)[2,3][3,4]矩阵乘(batch支持)Linear layer, attention
torch.bmm(A, B)[N,2,3][N,3,4]批量矩阵乘(严格3D)Attention scores

关键区别:matmul会自动处理batch维度,bmm要求输入必须是3D且batch size相同。*是广播乘,matmul是线性代数乘。

# ✅ 正确:用matmul处理不同batch size的输入 q = torch.randn(32, 64) # [B, D] k = torch.randn(16, 64) # [B', D],B'≠B # 不能直接bmm,但matmul可以(通过广播) attn = torch.matmul(q, k.T) # [32, 64] @ [64, 16] = [32, 16] # ❌ 错误:用*代替matmul attn_wrong = q * k.T # [32,64] * [64,16] → broadcast to [32,64,16],完全错误!

挑战二:矩阵转置(transpose)的“维度交换”本质

W.T不是简单的“翻转”,而是交换最后两个维度。对于2D矩阵[m,n],T就是[n,m];但对于3D张量[b,m,n],T是[b,n,m],不是[n,m,b]!后者需要用permute(2,0,1)。

实操技巧:永远用W.transpose(-2, -1)代替W.T,因为-2,-1明确指定交换最后两维,对任意维度张量都安全。

# ✅ 安全:适用于2D、3D、4D张量 W_trans = W.transpose(-2, -1) # ❌ 危险:W.T对3D张量行为不符合直觉 W_3d = torch.randn(32, 64, 128) # [B, M, N] W_3d_T = W_3d.T # 结果是 [128, 64, 32],不是 [32, 128, 64]!

挑战三:矩阵填充(padding)引发的“形状污染”

在NLP中,句子长度不一,必须padding到统一长度。pad_sequence()生成的矩阵[B, T, D],其中T是最大长度。但padding的0向量,会污染后续的LayerNorm或attention计算。

解决方案:使用attention_mask,并在计算中显式屏蔽padding位置:

# ✅ 正确:用mask控制attention范围 attn_weights = torch.matmul(q, k.transpose(-2, -1)) # [B, T, T] attn_weights = attn_weights.masked_fill(mask == 0, float('-inf')) # mask是[B,T] attn_probs = F.softmax(attn_weights, dim=-1)

挑战四:矩阵分解(SVD)的轻量化替代

全矩阵SVD计算昂贵。在模型压缩中,常用torch.svd_lowrank()或torch.pca_lowrank()进行近似分解,它们直接返回U、S、V,无需完整矩阵。

# ✅ 轻量:对大矩阵做低秩近似 U, S, V = torch.pca_lowrank(W, q=64) # W是[768,128],q=64表示保留64个主成分 W_approx = U @ torch.diag(S) @ V.T # [768,64] @ [64,64] @ [64,128] ≈ [768,128]

挑战五:矩阵内存布局:C-contiguous vs Fortran-contiguous

PyTorch默认使用C-contiguous(行优先)存储。当你频繁对矩阵的列做操作(如W[:, 0]),效率会低于对行操作(W[0, :]),因为列元素在内存中不连续。

优化技巧:如果模型中大量使用列操作,可在初始化时用W = torch.randn(128, 768).t()创建,让常用维度成为连续的。

# ✅ 优化:让特征维度(128)成为连续内存块 W_opt = torch.randn(128, 768).t() # [768,128],但内存布局是列优先 # 现在 W_opt[:, 0] 是连续内存访问,更快

4.3 矩阵的终极形态:它是模型的“可学习参数本体”

当你调用model = nn.Linear(768, 128),你创建的不是一个函数,而是一个封装了可学习矩阵W和偏置向量b的参数容器。model.weight就是那个[128, 768]矩阵,model.bias就是那个[128]向量。

这个矩阵,就是模型的“知识”。训练过程,就是通过反向传播,不断微调这个矩阵里的768×128=98,304个数字,让它们能最好地完成你设定的任务。所以,理解矩阵,就是理解模型如何存储和运用知识。

这也是为什么剪枝(pruning)、量化(quantization)、知识蒸馏(distillation)等技术,都围绕着这个矩阵展开。剪枝是把矩阵里不重要的数字设为0,量化是把32位浮点数压缩成8位整数,蒸馏是用一个大矩阵(teacher)去指导一个小矩阵(student)的学习。

矩阵,是AI模型的DNA。

5. 张量:高维数据的“时空连续体”与框架心智模型

5.1 张量不是“多维数组”,而是“数据在时空中的流形”

如果说标量是点,向量是线,矩阵是面,那么张量就是立体的、有时序的、有结构的时空连续体。[32, 3, 224, 224]这个shape,不是一个抽象的四维超立方体,而是一个精确的物理描述:

  • 32:时间维度(batch time)—— 32个独立样本,它们在计算图中是并行处理的“时间切片”。
  • 3:通道维度(channel space)—— RGB三个颜色通道,是图像的“感官维度”。
  • 224, 224:空间维度(spatial grid)—— 图像的像素网格,是视觉信息的“地理坐标”。

这四个数字,共同定义了一个数据流形(data manifold)。在这个流形上,卷积核像一个移动的探针,在空间维度上滑动,在通道维度上聚合,在时间维度上并行扫描。理解这一点,你就明白为什么Conv2d的kernel_size=(3,3)只作用于最后两个维度,而groups=3会把通道维度切成三份独立处理。

张量的shape,就是它的物理定律。改变任何一个数字,都相当于修改了这个数据宇宙的基本常数。

5.2 张量的六大维度操作与实战心法

心法一:view()vsreshape()vspermute()—— 何时该用谁?

  • view():要求新shape的元素总数不变,且内存必须是连续的(contiguous)。如果x是非连续的(比如经过transpose后),view()会报错。
  • reshape():更智能,如果内存不连续,它会自动contiguous()后再view(),是view()的安全版。
  • permute():纯粹的维度重排,不改变数据,只改变shape解释。x.permute(0,2,3,1)把[B,C,H,W]变成[B,H,W,C]。
# ✅ 推荐:用reshape代替view,避免contiguous问题 x_reshaped = x.reshape(B, -1) # 安全 # ✅ 必须用permute:改变维度语义 x_nhwc = x.permute(0, 2, 3, 1) # [B,C,H,W] -> [B,H,W,C],为某些CUDA kernel优化

心法二:expand()的“零拷贝广播”魔法

expand()不复制数据,只创建一个新视图(view),让张量在指定维度上“看起来”更大。x.expand(32, -1)让一个[1, 768]的向量,变成[32, 768]的视图,内存占用仍是768个数。

# ✅ 高效:为batch添加共享bias bias = torch.randn(768) # [768] bias_expanded = bias.expand(32, -1) # [32, 768],零内存开销 output = hidden + bias_expanded # [32,768] + [32,768]

心法三:narrow()的“精准切片”艺术

narrow(dim, start, length)比x[start:start+length]更精确,因为它明确指定在哪个维度上切,且不触发高级索引。

# ✅ 精准:只在时间维度(dim=1)上切前10个token x_short = x.narrow(1, 0, 10) # [B, T, D] -> [B, 10, D]

心法四:index_select()的“非连续采样”利器

当你需要从一个维度上,按不连续的索引采样(比如取第0、5、10个样本),index_select()比布尔索引更高效、更清晰。

# ✅ 清晰:按索引采样 indices = torch.tensor([0, 5, 10]) x_sampled = torch.index_select(x, dim=0, index=indices) # [3, ...]

心法五:scatter_()的“原子级写入”

在实现自定义聚合(如Graph Neural Network中的消息传递)时,scatter_add_()能将源张量的值,按索引“原子地”加到目标张量的指定位置,是GPU上最高效的聚合原语。

# ✅ GNN核心:将邻居消息聚合到中心节点 src = torch.randn(100, 64) # 100条消息 index = torch.randint(0, 32, (100,)) # 每条消息归属的节点ID (0~31) dst = torch.zeros(32, 64) # 32个节点的聚合槽 dst.scatter_add_(0, index.unsqueeze(1).expand(-1, 64), src) # 原子加

心法六:as_strided()的“内存透视”黑科技

这是最危险也最强大的操作。它允许你用任意的size和stride(步长)去“解读”一块内存。stride表示在该维度上移动一个单位,内存地址要跳多少个元素。

# ⚠️ 高级:创建一个“虚拟”的对角矩阵视图(不占额外内存) x = torch.randn(5) # 创建一个5x5的视图,其对角线是x的元素 # stride = (6, 1) 表示:行方向跳6个元素(跳过一行),列方向跳1个 diag_view = torch.as_strided(x, size=(5,5),

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询