【论文阅读】Long-Tailed Recognition via Weight Balancing(CVPR2022)附MaxNorm的代码

目录

  • 论文
  • 使用方法
    • weight decay
    • MaxNorm
  • 如果使用原来的代码报错的可以看下面这个

论文

问题:真实世界中普遍存在长尾识别问题,朴素训练产生的模型在更高准确率方面偏向于普通类,导致稀有的类别准确率偏低。
key:解决LTR的关键是平衡各方面,包括数据分布、训练损失和学习中的梯度。
文章主要讨论了三种方法: L2normalization, weight decay, and MaxNorm
本文提出了一个两阶段训练的范式
a. 利用调节权重衰减的交叉熵损失学习特征。
b. 通过调节权重衰减和Max Norm使用类平衡损失学习分类器。
一些有用的看法

  1. 研究表明,与联合训练特征学习和分类器学习的模型相比,解耦特征学习和分类器学习导致了显著的改进。
  2. 根据基准测试结果,通过集成专家模型或采用主动数据增强技术的自监督预训练来实现最好精度。
  3. 研究发现,SGD动量导致LTR出现问题,阻碍了进一步改善。
  4. 最近,Kang等人令人信服地证明了阶段性训练对LTR很重要。
  5. 权重衰减有助于学习隐藏层的平衡权重。
  6. 重要的是,我们的探索发现,虽然在分类器上使用L2规范化约束进行训练比简单训练有所改进,但它的表现不如下面描述的其他两个正则化。
  7. 与严格将所有滤波器权重的范数值设置为1的L2归一化不同,MaxNorm放松了这一约束,允许权重在训练期间在范数球内移动。
  8. 权重衰减中,不同数据集的最优λ各不相同——较大的数据集需要较小的权重衰减,直观地说,因为在更多数据上学习有助于泛化,因此需要较少的正则化。
    单阶段使用不平衡损失训练效果不好的原因:虽然他们没有解释为什么具有类平衡损失的单阶段训练表现不佳,但直观地说,这是因为类平衡损失人为地放大了从罕见的类训练数据计算的梯度,这损害了特征表示学习,从而损害了最终的LTR性能。
    本文作者使用了weight decay和max norm两种方法结合,因为发现两个结合效果更好。让模型不同类之间权重相差不会很大的同时,还能让这些权重缓慢增加。
    下面这幅图就是解释了这些方法的特点。
    在这里插入图片描述
    第一个就是普通方法训练的,它常见的类别权重增长快。
    第二个是L2 normalization,它把所有类别的权重都限定在一个常数。
    第三个是权重衰减,它的所有类的权重小,而且权重在增长。
    第四个是MaxNorm,它限制最大的权重。
    第五个是权重衰减和MaxNorm,会导致范数中的权重较小且平衡。

使用方法

weight decay

先定义好权重衰减的值。

weight_decay = 0.1 #weight decay value

然后在优化器中调用。Adam还有其他的都有weight_decay。

optimizer = optim.SGD([{'params': active_layers, 'lr': base_lr}], lr=base_lr, momentum=0.9, weight_decay=weight_decay)

MaxNorm

就是这个论文中的regularizers.py中的代码。只要会使用就好。就是要是不是作者代码中的模型的话,model.encoder.fc还需要根据自己的代码修改。

#使用前先定义好初始化好
pgdFunc = MaxNorm_via_PGD(thresh=thresh)
pgdFunc.setPerLayerThresh(model) # set per-layer thresholds这个是计算模型每一层的权重的阈值,这篇论文中只计算最后线性层的权重,并对最后线性层的权重进行限制

当模型训练一个epoch结束后,对已经更新完毕的模型权重进行限制,如果超过阈值就进行更新,让权重在最大范数的约束下。

 if pgdFunc:# Projected Gradient DescentpgdFunc.PGD(model)#对权重进行限制
import torch
import torch.nn as nn
import math
# The classes below wrap core functions to impose weight regurlarization constraints in training or finetuning a network.class MaxNorm_via_PGD():def __init__(self, thresh=1.0, LpNorm=1, tau=1):self.thresh = threshself.LpNorm = LpNormself.tau = tauself.perLayerThresh = []def setPerLayerThresh(self, model):#根据指定的模型设置每层的阈值#set pre-layer thresholdsself.perLayerThresh = []for curLayer in [model.encoder.fc.weight, model.encoder.fc.bias]:#遍历模型的最后两层curparam = curLayer.data#获取当前层的数据if len(curparam.shape) <= 1:#如果层只有一个维度,是一个偏置或者是一个1D的向量,则设置这一层的阈值为无穷大,继续下一层self.perLayerThresh.append(float('inf'))continuecurparam_vec = curparam.reshape((curparam.shape[0], -1))#如果不是,把权重张量展开neuronNorm_curparam = torch.linalg.norm(curparam_vec, ord=self.LpNorm, dim=1).detach().unsqueeze(-1)#沿着第一维计算P番薯,结果存储curLayerThresh = neuronNorm_curparam.min() + self.thresh*(neuronNorm_curparam.max() - neuronNorm_curparam.min())#计算每一层的阈值及神经元范数的最小值加上最大值和最小值之间的缩放差self.perLayerThresh.append(curLayerThresh)#每层阈值存储def PGD(self, model):#定义PGD函数,用于在模型的参数上执行投影梯度下降,试试最大范数约束if len(self.perLayerThresh) == 0:#如果每层的阈值是空,用setPerLayerThresh方法初始化self.setPerLayerThresh(model)for i, curLayer in enumerate([model.encoder.fc.weight, model.encoder.fc.bias]):#遍历模型的最后两层curparam = curLayer.data#获取当前层的数据张量值curparam_vec = curparam.reshape((curparam.shape[0], -1))#变成一维neuronNorm_curparam = (torch.linalg.norm(curparam_vec, ord=self.LpNorm, dim=1)**self.tau).detach().unsqueeze(-1)#在最后加一维#计算权重张量中每行神经元番薯的tau次方scalingVect = torch.ones_like(curparam)#创建一个形状与当前层数据相同的张量,用1初始化curLayerThresh = self.perLayerThresh[i]#获取阈值idx = neuronNorm_curparam > curLayerThresh#创建bool保存超过阈值的神经元idx = idx.squeeze()#tmp = curLayerThresh / (neuronNorm_curparam[idx].squeeze())**(self.tau)#根据每层的阈值和超过阈值的神经元番薯计算缩放因子for _ in range(len(scalingVect.shape)-1):#扩展缩放因子以匹配当前层数据的维度tmp = tmp.unsqueeze(-1)scalingVect[idx] = torch.mul(scalingVect[idx],tmp)curparam[idx] = scalingVect[idx] * curparam[idx]curparam[idx] = scalingVect[idx] * curparam[idx]#通过缩放值更新当前层的数据,以便对超过阈值的神经元进行缩放。完成权重更新

如果使用原来的代码报错的可以看下面这个

我的网络只有一层是线性层idx = idx.squeeze(),idx是(1,1)形状的,squeeze就没了,所以报错,如果有这个原因的可以改成idx = idx.squeeze(1)。maxnorm只改最后两层/一层权重所以,定义了一个列表存储线性层只取最后两层或者一层。

class MaxNorm_via_PGD():# learning a max-norm constrainted network via projected gradient descent (PGD)def __init__(self, thresh=1.0, LpNorm=2, tau=1):self.thresh = threshself.LpNorm = LpNormself.tau = tauself.perLayerThresh = []def setPerLayerThresh(self, model):# set per-layer thresholdsself.perLayerThresh = []#存储每一层的阈值self.last_two_linear_layers = []#提取线性层for name, module in model.named_children():if isinstance(module, nn.Linear):self.last_two_linear_layers.append(module)for linear_layer in self.last_two_linear_layers[-min(2, len(self.last_two_linear_layers)):]:  # here we only apply MaxNorm over the last two layerscurparam = linear_layer.weight.dataif len(curparam.shape) <= 1:self.perLayerThresh.append(float('inf'))continuecurparam_vec = curparam.reshape((curparam.shape[0], -1))neuronNorm_curparam = torch.linalg.norm(curparam_vec, ord=self.LpNorm, dim=1).detach().unsqueeze(-1)curLayerThresh = neuronNorm_curparam.min() + self.thresh * (neuronNorm_curparam.max() - neuronNorm_curparam.min())self.perLayerThresh.append(curLayerThresh)def PGD(self, model):if len(self.perLayerThresh) == 0:self.setPerLayerThresh(model)for i, curLayer in enumerate([self.last_two_linear_layers[-min(2,len(self.last_two_linear_layers))]]):  # here we only apply MaxNorm over the last two layerscurparam = curLayer.weight.datacurparam_vec = curparam.reshape((curparam.shape[0], -1))neuronNorm_curparam = (torch.linalg.norm(curparam_vec, ord=self.LpNorm, dim=1) ** self.tau).detach().unsqueeze(-1)scalingVect = torch.ones_like(curparam)curLayerThresh = self.perLayerThresh[i]idx = neuronNorm_curparam > curLayerThreshidx = idx.squeeze(1)tmp = curLayerThresh / (neuronNorm_curparam[idx].squeeze()) ** (self.tau)for _ in range(len(scalingVect.shape) - 1):tmp = tmp.unsqueeze(-1)scalingVect[idx] = torch.mul(scalingVect[idx], tmp)curparam[idx] = scalingVect[idx] * curparam[idx]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/656721.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android 12 系统开机动画

一、查找Android系统提供的开机动画 在Android系统源码目录下输入 find ./ -name "bootanimation.zip" 如图所示 所输出的路劲即为bootanimation.zip所在路径&#xff0c;每个系统都不一样&#xff0c;建议用命令查找 二、复制到对应目录下 android12\out\target\…

AIGC,ChatGPT4 实际需求效办公自动化函数应用

用实际需求来给大家演示一下ChatGPT如何助力办应用。 首先我们来提取年份值 我们将公式复制到表格即可。 接下来进行向下填充。 就得到了所有年份&#xff0c; 接下来我们完成第二个需求&#xff0c;按年份统计销售额。 Prompt&#xff1a;有一个表格C列是年份&#xff0c;D列…

【干货】【常用电子元器件介绍】【电容】(二)--电容器的主要参数、测量、选择与应用

声明&#xff1a;本人水平有限&#xff0c;博客可能存在部分错误的地方&#xff0c;请广大读者谅解并向本人反馈错误。 一、 电容器的主要参数 1.1 耐压 耐压(Voltage Rating)是指电容器在电路中长期有效地工作而不被击穿所能承受的最大直流电压。对于结构、介质、容量相同的…

【计算机网络】网络的网络

网络的网络 客户 customer 接入ISP提供商 provider 全球承载ISP多个ISP的层级结构 第一层ISP &#xff08;tier-1 ISP &#xff09; 位于顶部 区域ISP &#xff08;reginal ISP&#xff09;Level 3通信 &#xff0c;AT&T&#xff0c;Sprint &#xff0c;NTT存在点&#x…

Spring AOP实现

Spring AOP实现 AOP概述什么是AOP什么是Spring AOP Spring AOP快速入门引入依赖实现计时器 Spring AOP详解Spring AOP核心概念切点(Pointcut)连接点(Join Point)通知(Advice)切面(Aspect) 通知类型注意事项 PointCut多个切面切面优先级 Order切点表达式execution表达式annotati…

Ubuntu 隐藏Telnet主机SSH服务时显示版本信息问题

一、背景 默认情况下&#xff0c;我们通过telnet服务器的22端口&#xff0c;能够获取OpenSSH服务的banner信息(如下图所示)。而低版本的OpenSSH存在许多高危漏洞。。为了安全我们要隐藏这个信息。 二、隐藏Telnet版本信息 当使用telnet命令&#xff0c;telnet 192.168.31.20…

前缀和、差分

0x03前缀和、差分 文章目录 0x03前缀和、差分一维前缀和二维前缀和差分一维差分二维差分 习题T1T2T3 一维前缀和 数组前n项和 s [ k ] ∑ i 1 k a [ i ] s[k]\sum_{i1}^ka[i] s[k]∑i1k​a[i] s[i]s[i-1]a[i];二维前缀和 设s[i][j]表示以(1&#xff0c;1)为顶点&#xff0…

【Python实战】Python多线程批量采集图片

前言 本文来介绍如何多线程采集图片&#xff0c;多线程效率更快&#xff0c;但是&#xff0c;我们单一IP请求过于频繁&#xff0c;可能会被反爬&#xff0c;被封IP&#xff0c;所以&#xff0c;我们就要用到IP代理池&#xff0c;这里&#xff0c;我给大家推荐一个&#xff0c;可…

5.10 动态优先级模式

动态优先级模式与静态优先级模式类似&#xff0c;但动态优先级模式会随着任务运行时条件的改变自动调整任务优先级。调整任务优先级的策略有很多种&#xff0c;最常见的是“最早截止期优先”(Earliest Deadline First)&#xff0c;即优先级最高的任务是离截止时间最近的任务。动…

11个技巧让你的Python性能起飞

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com Python 是一门非常强大且易于学习的编程语言&#xff0c;但在处理大规模数据或复杂任务时&#xff0c;可能会遇到性能瓶颈。为了让你的 Python 代码运行更快&#xff0c;本文将介绍一些提高 Python 性能的技巧和…

uniapp如何添加多个表单数组?

目录 一、实现思路 二、实现步骤 ①view部分展示 ②JavaScript 内容 ③css中样式展示 三、效果展示 四、小结 注意事项 总结模板&#xff1a; 一、实现思路 1.在 data 中定义一个数组&#xff0c;用于存储表单项的数据 2.在模板中使用 v-for 指令渲染表单项 3.在 methods 中…

如何快速搭建个人博客

说明&#xff1a;本文介绍如何使用Halo框架快速搭建个人博客&#xff0c;我用的是阿里云的云服务器&#xff0c;操作系统是CentOS 7.0。 安装Docker&DockerCompose &#xff08;1&#xff09;Docker安装 Docker的安装参考&#xff0c;Docker安装&卸载&#xff1b; …

AI算力专题:算力系列之四-各省算力规划建设梳理-绿色低碳高质量发展-部署算力建设AI产业研究

今天分享的是AI算力系列深度研究报告&#xff1a;《AI算力专题&#xff1a;算力系列之四-各省算力规划建设梳理-绿色低碳高质量发展-部署算力建设AI产业研究》。 &#xff08;报告出品方&#xff1a;中泰证券&#xff09; 报告共计&#xff1a;40页 数据中心能耗情况 随着越…

【Docker】linux、nginx、容器镜像三者基本概念

欢迎来到《小5讲堂》&#xff0c;大家好&#xff0c;我是全栈小5。 这是《Docker容器》序列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对…

PCB设计10条重要布线原则(学习笔记)

文章目录 一、连线精简二、避免走直角线三、差分走线四、蛇形走线五、圆滑走线六、数字与模拟分开七、3W原则八、20H原则九、铜箔承载电流十、过孔承载电流 一、连线精简 尽量用最短的路径去布线 1、可以省资源 2、信号差损少 3、线能不拐弯就不拐弯 4、能不换层就不换层 二…

SQL中实现行列转换

目录 方法一&#xff1a;sum case when 方法二&#xff1a;sum if 方法三&#xff1a;pivot 现在有一张表class_gender&#xff0c;内容如下&#xff1a; classgender一年级女一年级女一年级男一年级男二年级女二年级女二年级男 现在我们要根据上表&#xff0c;统计得到下…

初识attention

近年来&#xff0c;attention机制在机器视觉和机器翻译领域受到了广泛的关注&#xff0c;有很多文章都是融合attention来提高性能。attention受启发于人类的视觉系统&#xff0c;最先应用于序列化的机器翻译(NLP)后又推广到计算机视觉中&#xff0c;本篇文章就来简单学习一下at…

JS基础 - 遍历对象方法(6种)

初始值&#xff1a; var obj {a: 1,b: 2,c: 3,d: 4,e: 5,}; 第一种&#xff1a;for in for (let key in obj) {console.log(key ":" obj[key]);} 第二种&#xff1a;Object.keys 获取key Object.keys(obj).forEach((key) > {console.log(key ":" …

AI绘画:PhotoMaker Win11本地安装记录!

昨天介绍一个叫PhotoMaker的AI绘画开源项目。挺不错的&#xff01; 通过这个项目可以快速制作特定人脸的AI绘画作品&#xff0c;相比传统的技术效果会好很多&#xff0c;效率也高很多。 今天趁热打铁&#xff0c;本地电脑装装看&#xff0c;并且记录&#xff0c;分享一下&#…

js padEnd方法介绍笔记

padEnd() 是 JavaScript 字符串的方法之一&#xff0c;它用于在当前字符串的末尾添加指定数量的字符&#xff0c;直到字符串达到指定的长度。 padEnd() 方法接受两个参数&#xff1a; 目标长度和要添加的填充字符。 如果当前字符串的长度已经等于或超过目标长度&#xff0c;则不…