detach,矩阵运算等知识

本文详细介绍了PyTorch中张量的复制方法,包括.detach()和.clone(),以及它们在梯度计算中的作用。此外,还讲解了矩阵创建、转置、乘法、求和、均值、累积求和、点积和矩阵乘法等基本操作,并探讨了不同维度变化对结果的影响。同时,提到了矩阵范数的概念,如L2范数和L1范数。文章适合对PyTorch有一定基础的读者,帮助加深对张量操作和梯度管理的理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

pytorch中关于detach clone 梯度等一些理解

pytorch中有时需要复制一下张量(tensor),如果在迭代过程中就会涉及到梯度的问题。

我了解的常用的tensor复制方式有两种 .detach()和.clone()

1、.detach()方法,比如已有tensor a ,b=a.detach(),则相当于给a起了个别名b,两个在内存中实际是一个东西,但是在计算梯度时,梯度从后面传到b不会再往前传了,到这就截止了。当只需要tensor数值,不需要往前的梯度或者故意将梯度在这儿截断时可以用这个方法。

2、.clone()方法,与上面正相反,如果c=a.clone(),那么c跟a在内存中是两个tensor,改变其中一个不会对另一个的数值造成影响,但是c拥有与a相同的梯度回传路线,保留了继续回传梯度的功能,但不再共享存储。

3、 开始都对tensor这一数据类型比较熟悉,看博客有时会看到variable,形象地理解为这是另一种数据格式,tensor属于variable的一部分,tensor只包含数值,除了tensor,variable还有梯度值,梯度是否可计算等等属性(维度更广了),在迭代过程中从variable变量中取出tensor的操作时不可逆的,因为已经丢失了有关梯度的一切信息。

A = torch.arange(20, dtype=torch.float32).reshape(5,4)
B = A.clone() # 通过分配新内存,将A的一个副本分配给B
矩阵的创建
A = torch.arange(20).reshape(5, 4)
转置
A.T
矩阵乘法

按元素的乘法又叫做 哈达玛积 (Hadamard product)
数学符号是 ⊙ \odot

# 在pytorch里面很简单
A * B
# 按元素位置相乘,不求和
torch.sum
  • 会发现不同的sum维度会减少
 A = torch.arange(20*2).reshape(2, 5, 4)
 B = A.sum()
 C = A.sum(1)
 
 print(B.shape)
 print(C.shape)
 
>> torch.Size([])
>> torch.Size([2, 4])

torch.mean
  • dtype=torch.float32 很重要
A.mean(), A.sum()/A.numel()
# 平均等价于求和除个数
A.mean(axis=0), A.sum(axis=0) / A.shape[0]
计算总和或均值时保持轴数不变
  • 这时应该被减去的维度就是1
  • 好处就是可以使用广播机制了
sum_A = A.sum(axis=1, keepdims=True)
A / sum_A 
cumsum
a=torch.arange(0,12).reshape(3,4)
print(a)
'''
tensor([[ 0,  1,  2,  3],
        [ 4,  5,  6,  7],
        [ 8,  9, 10, 11]])

'''
b=a.cumsum(0)
print(b)
'''
tensor([[ 0,  1,  2,  3],
        [ 4,  6,  8, 10],
        [12, 15, 18, 21]])
'''
点积是相同位置的按元素乘积的和
x = torch.arange(4, dtype=torch.float32)
y = torch.ones(4, dtype=torch.float32)

print(x.dot(y))  # 和哈达玛积的区别就是多了一个sum操作
print(torch.sum(x*y))

>> tensor(6.)
>> tensor(6.)
矩阵-向量积
x = torch.arange(12,dtype=torch.float32).reshape(3, 4)
y = torch.arange(4,dtype=torch.float32)

print(x)
print(y)

print(x.mv(y))

>> tensor([[ 0.,  1.,  2.,  3.],
        [ 4.,  5.,  6.,  7.],
        [ 8.,  9., 10., 11.]])
>> tensor([0., 1., 2., 3.])
>> tensor([14., 38., 62.])
矩阵矩阵乘法
  • 可以把矩阵-矩阵乘法AB看作是简单的执行m次矩阵-向量积, 并将结果拼接在一起, 形成一个n * m 矩阵
x = torch.arange(12,dtype=torch.float32).reshape(3, 4)
y = torch.ones(4,3)

print(x.mm(y))
矩阵范数
  • L2范数是向量元素平方和的平方根:
    在这里插入图片描述
u = torch.tensor([3.0, -4.0])
print(torch.norm(u)

tensor(5.)
  • L1范数, 它表示为向量元素的绝对值之和:

在这里插入图片描述

u = torch.tensor([3, 4], dtype=torch.float32)

norm1 = torch.abs(u).sum()
  • F范数, 矩阵的弗洛贝尼乌斯范数(Frobenius norm), 是矩阵元素的平方和的平方根, 类似于把矩阵展平然后计算L2 norm
a = torch.ones((4, 9))
print(a.norm())

>> tensor(6.)
按轴计算
  • 以最简单的举例
    假设有个向量是5*4, axis 0 对应5, axis 1 对应4
  • 按行就是轴为0, 按列就是轴为1
    在这里插入图片描述
    注意keepdims这个参数, 会把应该消除的轴变为1
### YOLOv8 知识蒸馏代码实现与解释 #### 1. 环境配置 为了确保能够顺利运行YOLOv8的知识蒸馏代码,环境配置至关重要。建议使用Python虚拟环境来管理依赖项,并安装必要的库和工具[^1]。 ```bash conda create -n yolov8_distillation python=3.9 conda activate yolov8_distillation pip install ultralytics torch torchvision torchaudio --extra-index-url https://download.pytorch.org/whl/cu117 ``` #### 2. 数据准备 数据集对于训练模型非常重要,在进行知识蒸馏之前需准备好相应的图像分类或目标检测数据集并按照指定格式整理好文件结构。 #### 3. Logits-Based 蒸馏方法 Logits-Based 方法是最简单的知识蒸馏形式之一,通过让小型学生网络模仿大型教师网络的输出分布来进行学习。具体来说就是最小化两者之间的差异损失函数: \[ L_{distill} = \frac{1}{N}\sum_i^N KL(\text{softmax}(T\cdot s(x_i)) || \text{softmax}(T\cdot t(x_i))) \] 其中\(s(x)\)表示学生模型预测值;\(t(x)\)代表老师模型预测结果;\(KL\)指代Kullback-Leibler散度;而参数\(T>0\)则用来调整温度以控制软概率分布的程度。 ```python import torch.nn.functional as F def logits_based_loss(student_logits, teacher_logits, temperature=4): """计算基于logits的知识蒸馏损失""" soft_student = F.log_softmax(student_logits / temperature, dim=-1) soft_teacher = F.softmax(teacher_logits / temperature, dim=-1) return F.kl_div( soft_student, soft_teacher, reduction="batchmean" ) * (temperature ** 2) ``` #### 4. Feature-Based 蒸馏方法 Feature-Based 方式则是提取中间层特征图作为监督信号传递给学生网路,从而使得其内部表征更加接近于教师模型。通常采用均方误差(MSE)或其他相似性测度衡量两者的差距: \[ L_{feat\_distill}=\left \| f_s(X)-f_t(X) \right \|_F^{2} \] 这里\(f_s()\) 和 \(f_t()\),分别对应着学生和老师的某一层激活响应矩阵; 符号\(||\cdot||_F\) 表明 Frobenius范数运算操作。 ```python from functools import partial class FeatureDistiller(nn.Module): def __init__(self, student_model, teacher_model, layers=('layer2', 'layer3')): super().__init__() self.student_features = [] self.teacher_features = [] # 注册钩子获取特定层的特征图 for layer_name in layers: getattr(student_model.model[layer_name], "register_forward_hook")(partial(self._hook_fn, is_student=True)) getattr(teacher_model.model[layer_name], "register_forward_hook")(partial(self._hook_fn, is_student=False)) def _hook_fn(self, module, input, output, is_student): if is_student: self.student_features.append(output.detach()) else: self.teacher_features.append(output.detach()) def forward(self, inputs): outputs = {} with torch.no_grad(): _ = self.teacher(inputs) _ = self.student(inputs) feature_losses = [ F.mse_loss(s_feat, t_feat) for s_feat, t_feat in zip(self.student_features, self.teacher_features) ] total_feature_loss = sum(feature_losses)/len(feature_losses) outputs['total_feature_loss'] = total_feature_loss return outputs ```
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

live_for_myself

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

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

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

打赏作者

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

抵扣说明:

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

余额充值