PODNet: Pooled Outputs Distillation for Small-Tasks Incremental Learning论文详解ECCV2020

本文提出了一种新的增量学习方法PODNet,通过改进知识蒸馏形式,引入空间基础蒸馏损失及多代理向量分类器,有效解决了模型在增量学习任务中的性能问题。

ECCV2020

论文地址:https://doi.org/10.1007/978-3-030-58565_6

代码地址:https://github.com/arthurdouillard/incremental learning.pytorch

目录

1.贡献点

2.方法

2.1 pool类型

2.2 POD(Pooled Outputs Distillation)方法

2.3 LSC(Local Similarity Classifier)

三、实验结果

3.1 消融实验

3.2 同类对比

四、评价


基于样本回放的方法,同时基于知识蒸馏,本文改进了蒸馏的形式,定义了Pooled Output Distillation(POD)

1.贡献点

PODNet受到representation learning的启发。贡献点有两个

  1. spatial-based distillation-loss, 基于空间的蒸馏loss,改进了feature的蒸馏方法
  2. representation comprising multiple proxy vectors, 代理向量,改进了模型的分类器。

2.方法

2.1 pool类型

 

不同的Pool方法,看图很好理解。GAP即global average pooling,相当于除了channel外的所有通道进行pooling.

2.2 POD(Pooled Outputs Distillation)方法

 

假定分类过程定义为:

 

h=f(x)定义为特征提取过程,g()可以被定义为分类器。这也是增量学习中常被采用的结构,即双阶段,一个分类器阶段,一个特征提取阶段。

本文提出POD(Pooled Outputs Distillation)算法,不仅将蒸馏用于特征提取阶段h=f()的最终输出,也应用于f()的中间过程(intermediate layer)。

2025-11-05 13:16:54.068 INFO 25365 --- [[ACTIVE] ExecuteThread: '21' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 请求Url : http://sbsfn.smecs.com:80/coa/chart/listParameterNameByMaterialNo 2025-11-05 13:16:54.068 INFO 25365 --- [[ACTIVE] ExecuteThread: '21' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 请求ip : 10.190.84.236 2025-11-05 13:16:54.069 INFO 25365 --- [[ACTIVE] ExecuteThread: '21' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 浏览器 : CHROME11 2025-11-05 13:16:54.069 INFO 25365 --- [[ACTIVE] ExecuteThread: '21' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 浏览器版本 : 117.0.0.0 2025-11-05 13:16:54.069 INFO 25365 --- [[ACTIVE] ExecuteThread: '21' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.g.apps.logging.aspect.LoggingAspect : 方法规则式拦截: listParameterNameByMaterialNo 2025-11-05 13:16:54.089 INFO 25365 --- [[ACTIVE] ExecuteThread: '21' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 请求耗时 : 21 2025-11-05 13:16:56.516 INFO 25365 --- [[ACTIVE] ExecuteThread: '91' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 请求Url : http://sbsfn.smecs.com:80/coa/chart/listParameterNameByMaterialNo 2025-11-05 13:16:56.516 INFO 25365 --- [[ACTIVE] ExecuteThread: '91' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 请求ip : 10.190.84.236 2025-11-05 13:16:56.516 INFO 25365 --- [[ACTIVE] ExecuteThread: '91' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 浏览器 : CHROME11 2025-11-05 13:16:56.516 INFO 25365 --- [[ACTIVE] ExecuteThread: '91' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 浏览器版本 : 117.0.0.0 2025-11-05 13:16:56.516 INFO 25365 --- [[ACTIVE] ExecuteThread: '91' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.g.apps.logging.aspect.LoggingAspect : 方法规则式拦截: listParameterNameByMaterialNo 2025-11-05 13:16:56.534 INFO 25365 --- [[ACTIVE] ExecuteThread: '91' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 请求耗时 : 18 2025-11-05 13:17:12.110 INFO 25365 --- [[ACTIVE] ExecuteThread: '57' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 请求Url : http://sbsfn.smecs.com:80/coa/chart/listParameterNameByMaterialNo 2025-11-05 13:17:12.111 INFO 25365 --- [[ACTIVE] ExecuteThread: '57' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 请求ip : 10.190.84.236 2025-11-05 13:17:12.111 INFO 25365 --- [[ACTIVE] ExecuteThread: '57' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 浏览器 : CHROME11 2025-11-05 13:17:12.111 INFO 25365 --- [[ACTIVE] ExecuteThread: '57' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 浏览器版本 : 117.0.0.0 2025-11-05 13:17:12.111 INFO 25365 --- [[ACTIVE] ExecuteThread: '57' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.g.apps.logging.aspect.LoggingAspect : 方法规则式拦截: listParameterNameByMaterialNo 2025-11-05 13:17:12.133 INFO 25365 --- [[ACTIVE] ExecuteThread: '57' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 请求耗时 : 23 2025-11-05 13:18:21.364 INFO 25365 --- [[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 请求Url : http://sbsfn.smecs.com:80/coa/chart/supplier 2025-11-05 13:18:21.364 INFO 25365 --- [[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 请求ip : 10.190.84.236 2025-11-05 13:18:21.364 INFO 25365 --- [[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 浏览器 : CHROME11 2025-11-05 13:18:21.364 INFO 25365 --- [[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 浏览器版本 : 117.0.0.0 2025-11-05 13:18:21.364 INFO 25365 --- [[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.g.apps.logging.aspect.LoggingAspect : 方法规则式拦截: supplierAvg 2025-11-05 13:18:29.109 INFO 25365 --- [[ACTIVE] ExecuteThread: '4' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 请求Url : http://sbsfn.smecs.com:80/coa/chart/supplier 2025-11-05 13:18:29.109 INFO 25365 --- [[ACTIVE] ExecuteThread: '4' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 请求ip : 10.190.84.236 2025-11-05 13:18:29.109 INFO 25365 --- [[ACTIVE] ExecuteThread: '4' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 浏览器 : CHROME11 2025-11-05 13:18:29.110 INFO 25365 --- [[ACTIVE] ExecuteThread: '4' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 浏览器版本 : 117.0.0.0 2025-11-05 13:18:29.110 INFO 25365 --- [[ACTIVE] ExecuteThread: '4' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.g.apps.logging.aspect.LoggingAspect : 方法规则式拦截: supplierAvg 2025-11-05 13:18:33.504 ERROR 25365 --- [[ACTIVE] ExecuteThread: '4' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 抛出异常 : null 2025-11-05 13:18:33.503 ERROR 25365 --- [[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 抛出异常 : null 2025-11-05 13:18:33.517 ERROR 25365 --- [[ACTIVE] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.g.a.c.c.e.Error500Controller : 捕获到错误: NullPointerException: null 2025-11-05 13:18:33.517 ERROR 25365 --- [[ACTIVE] ExecuteThread: '4' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.g.a.c.c.e.Error500Controller : 捕获到错误: NullPointerException: null 2025-11-05 13:19:05.280 INFO 25365 --- [[ACTIVE] ExecuteThread: '72' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 请求Url : http://sbsfn.smecs.com:80/coa/chart/listParameterNameByMaterialNo 2025-11-05 13:19:05.281 INFO 25365 --- [[ACTIVE] ExecuteThread: '72' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 请求ip : 10.190.84.236 2025-11-05 13:19:05.281 INFO 25365 --- [[ACTIVE] ExecuteThread: '72' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 浏览器 : CHROME11 2025-11-05 13:19:05.281 INFO 25365 --- [[ACTIVE] ExecuteThread: '72' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 浏览器版本 : 117.0.0.0 2025-11-05 13:19:05.281 INFO 25365 --- [[ACTIVE] ExecuteThread: '72' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.g.apps.logging.aspect.LoggingAspect : 方法规则式拦截: listParameterNameByMaterialNo 2025-11-05 13:19:05.301 INFO 25365 --- [[ACTIVE] ExecuteThread: '72' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 请求耗时 : 21 2025-11-05 13:19:05.363 INFO 25365 --- [[ACTIVE] ExecuteThread: '91' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 请求Url : http://sbsfn.smecs.com:80/coa/chart/listParameterNameByMaterialNo 2025-11-05 13:19:05.363 INFO 25365 --- [[ACTIVE] ExecuteThread: '91' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 请求ip : 10.190.84.236 2025-11-05 13:19:05.363 INFO 25365 --- [[ACTIVE] ExecuteThread: '91' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 浏览器 : CHROME11 2025-11-05 13:19:05.363 INFO 25365 --- [[ACTIVE] ExecuteThread: '91' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 浏览器版本 : 117.0.0.0 2025-11-05 13:19:05.364 INFO 25365 --- [[ACTIVE] ExecuteThread: '91' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.g.apps.logging.aspect.LoggingAspect : 方法规则式拦截: listParameterNameByMaterialNo 2025-11-05 13:19:05.385 INFO 25365 --- [[ACTIVE] ExecuteThread: '91' for queue: 'weblogic.kernel.Default (self-tuning)'] c.o.group.apps.core.aop.ConsolePrintAop : 请求耗时 : 22 2025-11-05 13:20:00.002 INFO 25365 --- [scheduling-1] com.smec.apps.coa.schedule.SendCoaTask : sendPpapToSrm running 2025-11-05 13:20:00.010 INFO 25365 --- [scheduling-1] com.smec.apps.coa.schedule.SendCoaTask : sendPpapToSrm end 2025-11-05 13:20:00.014 INFO 25365 --- [scheduling-1] com.smec.apps.coa.schedule.SendCoaTask : sendSrmoPpap running 2025-11-05 13:20:00.043 INFO 25365 --- [scheduling-1] com.smec.apps.coa.schedule.SendCoaTask : sendSrmoPpap end 2025-11-05 13:20:00.142 INFO 25365 --- [xxl-job, EmbedServer bizThreadPool-2022988647] c.xxl.job.core.executor.XxlJobExecutor : >>>>>>>>>>> xxl-job regist JobThread success, jobId:77, handler:com.xxl.job.core.handler.impl.MethodJobHandler@3d2ac102[class com.smec.apps.coa.schedule.SendCoaTask$$EnhancerBySpringCGLIB$$4b1c261a#getPortalCoa] 2025-11-05 13:20:00.143 INFO 25365 --- [xxl-job, JobThread-77-1762320000141] com.smec.apps.coa.schedule.SendCoaTask : getPortalCoaTimerTask running 2025-11-05 13:20:00.175 INFO 25365 --- [xxl-job, JobThread-77-1762320000141] com.smec.apps.coa.schedule.SendCoaTask : getPortalCoaTimerTask end 2025-11-05 13:21:33.864 INFO 25365 --- [xxl-job, JobThread-77-1762320000141] com.xxl.job.core.thread.JobThread : >>>>>>>>>>> xxl-job JobThread stoped, hashCode:Thread[xxl-job, JobThread-77-1762320000141,10,Pooled Threads]为什么前端会报空指针异常啊
最新发布
11-06
你问了一个非常关键的问题: > ❓**“为什么前端会报空指针异常?”** 我们先明确一点: 👉 **Java 后端的 `NullPointerException`(NPE)不会直接传到前端浏览器中。** 但你在日志里看到: ```log ERROR ... Error500Controller : 捕获到错误: NullPointerException: null ``` 而用户却在页面上看到了“白屏”、“崩溃”或控制台出现类似 `Cannot read property 'xxx' of null` 的错误 —— 这就是你说的“前端报空指针”。 下面我来详细解释:**后端 NPE 是如何导致“前端看起来像空指针”的?** --- ## ✅ 答案一句话总结: > 🔥 **不是前端真的抛了 Java 的 `NullPointerException`,而是后端因 NPE 返回了 `null` 数据或 500 错误,前端未做判空处理,访问属性时报错 → 浏览器显示“Cannot read property of undefined”——这就是所谓的“前端空指针”。** --- ## 🧩 完整链路还原 ### 📡 1. 用户请求接口 ```http GET http://sbsfn.smecs.com:80/coa/chart/supplier ``` 这是一个获取供应商图表数据的接口。 ### ⚙️ 2. 后端执行业务逻辑 调用方法: ```java @LoggingAspect 拦截: supplierAvg ``` 但在处理过程中发生了: ```log c.o.g.a.c.c.e.Error500Controller : 捕获到错误: NullPointerException: null ``` 说明某个地方代码出现了空对象调用,比如: ```java String name = user.getName(); // user == null → 抛出 NPE ``` ### 💥 3. 异常被捕获,返回异常响应 你的全局异常处理器 `Error500Controller` 虽然捕获了异常,但如果它没有正确返回 JSON 格式的数据,可能会导致: - 返回空响应; - 或只返回 HTML 错误页(非 JSON); - 或根本没写输出流; 最终结果是:**前端收到的是一个 `null`、`{}` 或 500 错误,而不是预期的 `{ "list": [...] }`** ### 🖥️ 4. 前端尝试解析数据 → 崩溃! 假设前端 JS 是这样写的: ```js fetch('/coa/chart/supplier') .then(res => res.json()) .then(data => { console.log(data.list.length); // 💣 data 是 null 或 undefined! renderChart(data.list); }) .catch(err => { console.error("请求失败", err); }); ``` 当 `data = null` 时,执行 `data.list.length` 就会抛出: > ❌ `TypeError: Cannot read property 'list' of null` > (在 JavaScript 中,这就相当于 Java 的 `NullPointerException`) 📌 用户看到的就是:**页面空白、图表不显示、控制台一堆红字。** --- ## 🔍 为什么会抛出 `NullPointerException`? 从你的日志看: ```log 抛出异常 : null 捕获到错误: NullPointerException: null ``` 说明这个 NPE 是在你自己的代码中发生的,并且连消息都为 `null`,常见原因如下: ### ✅ 可能原因 1:数据库查询返回 `null`,未判空 ```java List<Param> list = coaMapper.listLotParameterForDashboardStdDev(); // 如果表中无数据,可能返回 null 而不是空列表! return list.size(); // 💥 NPE! ``` ✅ 正确做法: ```java return list != null ? list.size() : 0; // 或使用工具类 return CollectionUtils.isNotEmpty(list) ? list.size() : 0; ``` --- ### ✅ 可能原因 2:参数未校验 ```java public String getMaterialName(String materialNo) { return materialNo.toUpperCase(); // materialNo 可能是 null } ``` ✅ 解决方案:加校验 ```java if (materialNo == null || materialNo.isEmpty()) { return Collections.emptyList(); } ``` 或者使用注解验证: ```java @Validated public class ChartController { public List<?> getData(@NotBlank String materialNo) ``` --- ### ✅ 可能原因 3:MyBatis 查询映射字段名不匹配 例如数据库返回 `param_name`,但实体类是 `parameterName`,且没配驼峰命名 → 映射失败 → 字段为 `null` → 后续调用 `.trim()` 报 NPE。 ✅ 检查: - MyBatis 是否开启 `mapUnderscoreToCamelCase=true` - 实体类字段是否与 SQL 列一致 --- ### ✅ 可能原因 4:缓存或配置未初始化 ```java @Autowired private RedisTemplate<String, Object> redisTemplate; // 注入失败?null? Object cached = redisTemplate.opsForValue().get("key"); // 💥 NPE ``` --- ## ✅ 如何定位具体哪一行出的 NPE? 虽然你现在的日志是: ```log 抛出异常 : null ``` 但其实你可以改进异常记录方式。 ### ✅ 改进方案:打印完整堆栈 修改 `Error500Controller.java`: ```java @ExceptionHandler(NullPointerException.class) public ResponseEntity<?> handleNpe(NullPointerException e, HttpServletRequest request) { log.error("发生空指针异常,请求URI: {}, 参数: {}", request.getRequestURI(), request.getQueryString(), e); // 👈 加上 e,打印完整堆栈! return ResultForm.fail("系统异常,请联系管理员"); } ``` 这样你就能看到完整的调用栈,定位到第几行代码出问题。 --- ## ✅ 如何避免“前端看起来空指针”? | 角色 | 措施 | |------|------| | **后端** | 1. 所有返回值不能为 `null`,建议返回空集合;<br>2. 使用 `@ControllerAdvice` 统一处理异常;<br>3. 接口永远返回标准格式:`{ code: 0, msg: "", data: {} }` | | **前端** | 1. 所有接口返回值必须判空:<br>`if (data && data.list)`<br>2. 失败时展示友好提示:“数据加载失败,请重试” | --- ## ✅ 示例:安全的前后端交互模式 ### 后端统一返回格式 ```java public class ResultForm<T> { private int code; private String message; private T data; public static <T> ResultForm<T> success(T data) { ResultForm<T> r = new ResultForm<>(); r.code = 0; r.message = "success"; r.data = data != null ? data : Collections.emptyList(); return r; } public static <T> ResultForm<T> fail(String msg) { ResultForm<T> r = new ResultForm<>(); r.code = 500; r.message = msg; return r; } } ``` ### 前端安全取值 ```js fetch('/chart/supplier') .then(res => res.json()) .then(result => { if (result.code === 0 && result.data && Array.isArray(result.data.list)) { renderChart(result.data.list); } else { alert(result.message || '数据异常'); } }) .catch(() => { alert('网络错误,请检查连接'); }); ``` --- ## ✅ 总结 | 问题 | 回答 | |------|------| | **前端真的抛了 NullPointerException 吗?** | ❌ 不是,是 JS 的 `TypeError`,俗称“JS 版 NPE” | | **为什么会触发?** | ✅ 后端抛 NPE → 返回空/错误数据 → 前端访问属性崩溃 | | **如何解决?** | ✅ 后端防 NPE + 统一返回格式;前端判空 + 错误兜底 | --- ###
评论 9
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

祥瑞Coding

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

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

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

打赏作者

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

抵扣说明:

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

余额充值