1.你必须了解的 Go 历史:Go 的设计思想和每个版本的优劣
对每一个开发者来说,Go 的发展历史是必须知道的知识。了解几年来每个发行版本的主要变化,有助于理解 Go 的设计思想和每个版本的优势/弱点。想了解特定版本的更详细信息,可以点击每个版本号的链接来查看修改记录。
Go 1.0[1] — 2012 年 3 月:
Go 的第一个版本,带着一份兼容性说明文档[2]来保证与未来发布版本的兼容性,进而不会破坏已有的程序。
第一个版本已经有 go tool pprof 命令和 go vet 命令。go tool pprof 与 Google 的 pprof C++ profiler[3] 稍微有些差异。go vet(前身是 go tool vet)命令可以检查包中潜在的错误。
Go 1.1[4] — 2013 年 5 月:
这个 Go 版本专注于优化语言(编译器,gc,map,go 调度器)和提升它的性能。下面是一些提升的例子
https://dave.cheney.net/2013/05/21/go-11-performance-improvements
这个版本也嵌入了竞争检测[5],在语言中是一个很强大的工具。
你可以在我的文章 ThreadSanitizer 竞争检测[6]中发现更多的信息。
重写了 Go 调度器[7] 显著地提升了性能。Go 调度器现在被设计成这样
https://rakyll.org/scheduler/
M 是一个 OS 线程,P 表示一个处理器(P 的数量不能大于 GOMAXPROCS),每个 P 作为一个本地协程队列。在 1.1 之前 P 不存在,协程是用一个全局的 mutex 在全局范围内管理的。随着这些优化,工作窃取也被实现了,允许一个 P 窃取另一个 P 的协程:
https://rakyll.org/scheduler/
阅读 Jaana B.Dogan[8] 的 Go 的工作窃取调度器[9] 可以查看更多关于 Go 调度器和工作窃取的信息。
Go 1.2[10] — 2013 年 12 月:
本版本中 test 命令支持测试代码覆盖范围并提供了一个新命令 go tool cover ,此命令能测试代码覆盖率:
https://blog.golang.org/cover
这个命令也能提供覆盖信息:
https://blog.golang.org/cover
Go 1.3[11] — 2014 年 6 月:
这个版本对栈管理做了重要的改进。栈可以申请连续的内存片段[12],提高了分配的效率,使下一个版本的栈空间降到 2KB。
栈频繁申请/释放栈片段会导致某些元素变慢,本版本也改进了一些由于上述场景糟糕的分配导致变慢的元素。下面是一个 json 包的例子,展示了它对栈空间的敏感程度:
https://docs.google.com/document/d/1wAaf1rYoM4S4gtnPh0zOlGzWtrZFQ5suE8qr2sD8uWQ/pub
使用连续的栈修复了这个元素效率低下的问题。下面是另一个例子,html/template 包的性能对栈大小也很敏感:
图 7
阅读我的Go 协程栈空间的发展[13]查看更多信息。
这个版本在 sync 包中发布了 Pool。这个元素允许我们复用结构体,减少了申请的内存的次数,同时也是很多 Go 生态获得改进的根源,如标准库或包里的 encoding/json 或 net/http,还有 Go 社区里的 zap。
可以在我的文章 Sync.Pool 设计理解[14] 中查看更多关于 Pool 的信息。
Go 团队也对通道作了改进[15],让它们变得更快。下面是以 Go 1.2 和 Go 1.3 作对比运行的基准:
图 8
Go 1.4[16] — 2014 年 12 月:
此版本带来了官方对 Android 的支持,[golang.org/x/mobile](Go 1.4[17] ) 让我们可以只用 Go 代码就能写出简单的 Android 程序。
归功于更高效的 gc,之前用 C 和汇编写的运行时代码被翻译成 Go 后,堆的大小降低了 10% 到 30%。
与版本无关的一个巧合是,Go 项目管理从 Mercurial 移植到了 Git,代码从 Google Code 移到了 Github。
Go 也提供了 go generate 命令通过扫描用 //go:generate 指示的代码来简化代码生成过程。
在 Go 博客[18] 和文章生成代码[19]中可以查看更多信息。
Go 1.5[20] — 2015 年 8 月:
这个新版本,发布时间推迟[21]了两个月,目的是在以后每年八月和二月发布新版本:
https://github.com/golang/go/wiki/Go-Release-Cycle
这个版本对 gc[22] 进行了重新设计[23]。归功于并发的回收,在回收期间的等待时间大大减少。下面是一个 Twitter 生产环境的服务器的例子,等待时间由 300ms 降到 30ms:
https://blog.golang.org/ismmkeynote
这个版本也发布了运行时追踪,用命令 go tool trace 可以查看。测试过程或运行时生成的追踪信息可以用浏览器窗口展示:
Original Go Execution Tracer Document
Go 1.6[24] — 2016 年 2 月:
这个版本最重大的变化是使用 HTTPS 时默认支持 HTTP/2。
在这个版本中 gc 等待时间也降低了:
https://blog.golang.org/ismmkeynote
Go 1.7[25] — 2016 年 8 月:
这个版本发布了 context 包[26],为用户提供了处理超时和任务取消的方法。
阅读我的文章 传递上下文和取消[27]来获取更多关于 context 的信息。
对编译工具链也作了优化,编译速度更快,生成的二进制文件更小,有时甚至可以减小 20% 到 30%。
Go 1.8[28] — 2017 年 2 月:
把 gc 的停顿时间减少到了 1 毫秒以下:
https://blog.golang.org/ismmkeynote
其他的停顿时间已知,并会在下一个版本中降到 100 微秒以内。
这个版本也改进了 defer 函数:
https://medium.com/@blanchon.vincent/go-how-does-defer-statement-work-1a9492689b6e
我的文章 defer 语句工作机制[29]中有更多信息。
Go 1.9[30] — 2017 年 8 月:
这个版本支持下面的别名声明:
type byte = uint8
这里 byte 是 uint8 的一个别名。
sync 包新增了一个 Map[31] 类型,是并发写安全的。
我的文章 Map 与并发写[32] 中有更多信息。
Go 1.10[33] — 2018 年 2 月:
test 包引进了一个新的智能 cache,运行会测试后会缓存测试结果。如果运行完一次后没有做任何修改,那么开发者就不需要重复运行测试,节省时间。
first run:
ok /go/src/retro 0.027s
second run:
ok /go/src/retro (cached)
为了加快构建速度,go build 命令现在也维持了一份最近构建包的缓存。
这个版本没有对 gc 做实际的改变,但是确定了一个新的 SLO(Service-Level Objective):
https://blog.golang.org/ismmkeynote
Go 1.11[34] — 2018 年 8 月:
Go 1.11 带来了一个重要的新功能:Go modules[35]。去年的调查显示,Go modules 是 Go 社区遭遇重大挑战后的产物:
https://blog.golang.org/survey2018-results
第二个特性是实验性的 WebAssembly[36],为开发者提供了把 Go 程序编译成一个可兼容四大主流 Web 浏览器的二进制格式的能力。
Go 1.12[37] — 2019 年 2 月:
基于 analysis 包重写了 go vet 命令,为开发者写自己的检查器提供了更大的灵活性。
我的文章构建自己的分析器[38]中有更多信息。
Go 1.13[39] — 2019 年 9 月:
改进了 sync 包中的 Pool,在 gc 运行时不会清除 pool。它引进了一个缓存来清理两次 gc 运行时都没有被引用的 pool 中的实例。
重写了逃逸分析,减少了 Go 程序中堆上的内存申请的空间。下面是对这个新的逃逸分析运行基准的结果:
https://github.com/golang/go/issues/23109
Go1.14[40] - 2020 年 2 月:
现在 Go Module 已经可以用于生产环境,鼓励所有用户迁移到 Module。该版本支持嵌入具有重叠方法集的接口。性能方面做了较大的改进,包括:进一步提升 defer 性能、页分配器更高效,同时 timer 也更高效。
现在,Goroutine 支持异步抢占。
Go1.15[41] - 2020 年 8 月:
受疫情影响,这次版本变化的内容不太多,但如期发布了。
它的大部分更改在工具链、运行时和库的实现。与往常一样,该版本保留了 Go 1 兼容性的承诺。这几乎保证所有的 Go 程序都能像以前一样正常编译和运行。
Go 1.15 包括对链接器的重大改进,改进了对具有大量内核的小对象的分配,并弃用了 X.509 CommonName。GOPROXY 现在支持跳过返回错误的代理,并添加了新的嵌入式 tzdata 包。
via: https://medium.com/a-journey-with-go/go-retrospective-b9723352e9b0
作者:Vincent Blanchon[42]译者:lxbwolf[43]校对:polaris1119[44]
本文由 GCTT[45] 原创编译,Go 中文网[46] 荣誉推出
参考资料
[1]
Go 1.0: https://blog.golang.org/go-version-1-is-released
[2]
兼容性说明文档: https://golang.org/doc/go1compat
[3]
pprof C++ profiler: https://github.com/gperftools/gperftools
[4]
Go 1.1: https://blog.golang.org/go-11-is-released
[5]
竞争检测: https://blog.golang.org/race-detector
[6]
ThreadSanitizer 竞争检测: https://medium.com/a-journey-with-go/go-race-detector-with-threadsanitizer-8e497f9e42db
[7]
重写了 Go 调度器: https://docs.google.com/document/d/1TTj4T2JO42uD5ID9e89oa0sLKhJYD0Y_kqxDv3I3XMw/edit
[8]
Jaana B.Dogan: https://twitter.com/rakyll
[9]
Go 的工作窃取调度器: https://rakyll.org/scheduler/
[10]
Go 1.2: https://blog.golang.org/go12
[11]
Go 1.3: https://blog.golang.org/go1.3
[12]
连续的内存片段: https://docs.google.com/document/d/1wAaf1rYoM4S4gtnPh0zOlGzWtrZFQ5suE8qr2sD8uWQ/pub
[13]
Go 协程栈空间的发展: https://medium.com/a-journey-with-go/go-how-does-the-goroutine-stack-size-evolve-447fc02085e5
[14]
Sync.Pool 设计理解: https://medium.com/@blanchon.vincent/go-understand-the-design-of-sync-pool-2dde3024e277
[15]
对通道作了改进: https://docs.google.com/document/d/1yIAYmbvL3JxOKOjuCyon7JhW4cSv1wy5hC0ApeGMV9s/pub
[16]
Go 1.4: https://blog.golang.org/go1.4
[17]
golang.org/x/mobile: https://blog.golang.org/go1.4
[18]
Go 博客: https://blog.golang.org/
[19]
生成代码: https://blog.golang.org/generate
[20]
Go 1.5: https://blog.golang.org/go1.5
[21]
发布时间推迟: https://docs.google.com/document/d/106hMEZj58L9nq9N9p7Zll_WKfo-oyZHFyI6MttuZmBU/edit#
[22]
gc: https://golang.org/doc/go1.5#gc
[23]
重新设计: https://docs.google.com/document/d/1wmjrocXIWTr1JxU-3EQBI6BK6KgtiFArkG47XK73xIQ/edit#
[24]
Go 1.6: https://blog.golang.org/go1.6
[25]
Go 1.7: https://blog.golang.org/go1.7
[26]
context 包: https://medium.com/a-journey-with-go/go-context-and-cancellation-by-propagation-7a808bbc889c
[27]
传递上下文和取消: https://medium.com/a-journey-with-go/go-context-and-cancellation-by-propagation-7a808bbc889c
[28]
Go 1.8: https://blog.golang.org/go1.8
[29]
defer 语句工作机制: https://medium.com/a-journey-with-go/go-how-does-defer-statement-work-1a9492689b6e
[30]
Go 1.9: https://blog.golang.org/go1.9
[31]
Map: https://golang.org/pkg/sync/#Map
[32]
Map 与并发写: https://medium.com/a-journey-with-go/go-concurrency-access-with-maps-part-iii-8c0a0e4eb27e
[33]
Go 1.10: https://blog.golang.org/go1.10
[34]
Go 1.11: https://blog.golang.org/go1.11
[35]
Go modules: https://blog.golang.org/using-go-modules
[36]
WebAssembly: https://webassembly.org/
[37]
Go 1.12: https://blog.golang.org/go1.12
[38]
构建自己的分析器: https://medium.com/@blanchon.vincent/go-how-to-build-your-own-analyzer-f6d83315586f
[39]
Go 1.13: https://blog.golang.org/go1.13
[40]
Go1.14: https://blog.golang.org/go1.14
[41]
Go1.15: https://blog.golang.org/go1.15
[42]
Vincent Blanchon: https://medium.com/@blanchon.vincent
[43]
lxbwolf: https://github.com/lxbwolf
[44]
polaris1119: https://github.com/polaris1119
[45]
GCTT: https://github.com/studygolang/GCTT
[46]
Go 中文网: https://studygolang.com/
2.用实例告诉你用于梯度提升的自定义损失函数有多重要!
点击上方关注,All in AI中国
作者:Prince Grover 和 Sourav Dey
介绍
梯度提升技术在工业中得到了广泛的应用,并赢得了许多Kaggle比赛。(https://github.com/Microsoft/LightGBM/blob/master/examples/README.md#machine-learning-challenge-winning-solutions)互联网已经有很多关于梯度提升的很好的解释,但我们注意到关于自定义损失函数的信息缺乏:比如原因,时间和方式。这篇文章是我们尝试总结自定义损失函数在许多实际问题中的重要性,以及如何使用LightGBM梯度提升包实现它们。
常见的ML库中有许多常用的损失函数。如果你想进一步了解这方面的知识,请阅读这篇文章,这是Prince在攻读数据科学硕士时写的。(https://heartbeat.fritz.ai/5-regression-loss-functions-all-machine-learners-should-know-4fb140e9d4b0)在现实世界中,这些"现成的"损失函数通常无法很好地适应我们试图解决的业务问题。输入自定义损失函数。
自定义损失函数
使用自定义损失函数的一个例子是机场准时的风险不对称。问题是决定何时离开家,以便在合适的时间到达机场。我们不想太早离开,在机场等几个小时。与此同时,我们更不想错过我们的航班。任何一方的损失都是非常不同的:如果我们提前到达,情况真的不是那么糟糕;如果我们来得太晚而错过航班,那真的很糟糕。如果我们使用机器学习来决定何时离开房子,我们可能希望直接在我们的模型中处理这种风险不对称,通过使用自定义损失函数来"惩罚"晚期错误而不是早期错误。
另一个常见的例子是分类问题。例如,对于疾病检测,我们可能认为假阴性比假阳性要严重得多,因为给予健康人的药物通常比未治疗病人的危害小。在这种情况下,我们可能希望优化F-beta评分,其中β取决于我们想要给予误报的权重大小。这有时被称为Neyman-Pearson标准。
在Manifold,我们最近遇到了一个需要自定义损失函数的问题。我们的客户之一Cortex Building Intelligence提供的应用程序可帮助工程师更精确地操作建筑物供暖,通风和空调(HVAC)系统。大多数商业建筑物具有"租赁义务",以在工作日期间的工作时间内将建筑物室内温度调节在"舒适"温度范围内,例如在上午9点至下午6点期间在华氏70和74度之间。与此同时,HVAC是建筑物的最大运营成本。高效HVAC运行的关键是在不需要时关闭系统,如夜间,并在清晨再次开启以满足"租赁义务"。为此,Manifold帮助Cortex建立了一个预测模型,以建议在建筑物中打开HVAC系统的确切时间。
然而,错误预测的惩罚是不对称的。如果我们预测的启动时间早于实际所需的启动时间,那么建筑物将过早地达到舒适的温度并且会浪费一些能量。但是如果预测的时间晚于实际所需的开始时间,那么建筑物的温度就会升温较晚,租户也不会感到高兴——没有人想在冰冷的建筑物中工作,购物或学习。因此,晚开比早开更糟糕,因为我们不希望租户不开心。我们通过创建自定义非对称Huber损失函数将业务知识编码到我们的模型中,当残差为正与负时,该函数具有更高的误差。有关此问题的更多详细信息,请参阅此文章。(https://www.manifold.ai/blog/data-science-at-cortex)
结论:找到一个与你的业务目标紧密匹配的损失函数。通常,这些损失函数在流行的机器学习库中没有默认的实现。没关系:定义自己的损失函数并用它来解决你的问题并不难。
自定义训练损失和验证损失
在进一步讨论之前,让我们在定义中明确一点。ML文献中使用了许多术语来指代不同的东西。我们将选择一组我们认为最清晰的定义:
·训练损失。这是在训练数据上进行优化的函数。例如,在神经网络二进制分类器中,这通常是二进制交叉熵。对于随机森林分类器,这是基尼系数。训练损失通常也称为"目标函数"。
·验证损失。这是我们用来评估我们训练模型在看不见的数据上的性能的函数。这通常与训练损失不同。例如,在分类器的情况下,这通常是接收器工作特性(ROC)曲线下的区域——尽管这从未直接优化,因为它是不可微分。这通常称为"性能或评估指标"。
在许多情况下,自定义这些损失对于构建更好的模型非常有效。这对于梯度提升特别简单,如下所示。
训练损失
在训练期间优化训练损失。很难为某些算法自定义,比如随机森林(见这里:https://github.com/scikit-learn/scikit-learn/issues/3071),但对其他算法来说比较容易,比如梯度提升和神经网络。因为梯度下降的一些变体通常是优化方法,所以训练损失通常需要一个具有凸梯度(一阶导数)和海森(二阶导数)的函数。它最好是连续的,有限的和非零的。最后一个很重要,因为函数为零的部分可以冻结梯度下降。
在梯度提升的背景下,训练损失是使用梯度下降优化的函数,例如梯度提升模型的"梯度"部分。具体地,训练损失的梯度用于改变每个连续树的目标变量。(如果你对更多细节感兴趣,请参阅此文章。https://medium.com/mlreview/gradient-boosting-from-scratch-1e317ae4587d)请注意,即使训练损失定义了"梯度",每个树仍然使用与此自定义损失函数无关的贪婪分割算法生长。
定义自定义训练损失通常需要我们做一些微积分来找到梯度和海森。正如我们接下来将要看到的,首先更改验证损失更容易一些,因为它不需要那么多的开销。
验证损失
验证损失用于调整超参数。它通常更容易自定义,因为它没有像训练损失那样多的功能要求。验证损失可以是非凸的,不可微分的和不连续的。因此,从自定义开始通常是一个更容易的地方。
例如,在LightGBM中,一个重要的超参数是boosting的数量。验证损失可用于找到最佳数量的boosting次数。 LightGBM中的验证损失称为eval_metric。我们可以使用库中可用的验证损失之一,也可以定义我们自己的自定义函数。(https://github.com/Microsoft/LightGBM/blob/master/docs/Parameters.rst/#metric-parameters)由于它非常简单,如果它对你的业务问题很重要,那么你一定要自定义。
具体而言,我们通常使用early_stopping_rounds变量,而不是直接优化num boosting的轮数。当给定数量的早期停止轮次的验证损失开始增加时,它会停止提升。实际上,它通过监视样本外验证集的验证损失来防止过度拟合。如下图所示,设置更高的停止轮次会导致模型运行更多boosting 轮次。
蓝色:训练损失。橙色:验证损失。训练和验证都使用相同的自定义损失功能
k折交叉验证。每个测试折叠都有验证损失
请记住,验证策略也非常重要。上面列出的训练/验证是许多可能的验证策略之一。它可能不适合你的问题。其他包括k-fold交叉验证和嵌套交叉验证,我们在HVAC启动时建模问题中使用了这些验证。
如果适用于业务问题,我们希望使用自定义函数来进行训练和验证损失。在某些情况下,由于自定义损失的函数形式,可能无法将其用作训练损失。在这种情况下,仅更新验证损失并使用像MSE这样的默认训练损失可能是有意义的。你仍然可以获益,因为超参数将使用所需的自定义损失进行调整。
在LightGBM中实现自定义损失功能
让我们来看看它在实践中的样子,并对模拟数据进行一些实验。首先,让我们假设过高估计比低估更糟糕。另外,假设平方损失是我们在任一方向上的误差的良好模型。为了对其进行编码,我们定义了一个自定义MSE函数,它对正残差的惩罚比负残差多10倍。下图说明了我们的自定义损失函数与标准MSE损失函数的对比情况。
根据定义,非对称MSE很好,因为它具有易于计算的梯度和海森度,如下图所示。请注意,海森在两个不同的值上是常量,左边是2,右边是20,尽管在下面的图中很难看到。
LightGBM提供了一种直接的方式来实现自定义训练和验证损失。其他梯度提升包,包括XGBoost和Catboost,也提供此选项。这是一个Jupyter笔记本(https://github.com/manifoldai/mf-eng-public/blob/master/notebooks/custom_loss_lightgbm.ipynb),展示了如何实现自定义训练和验证损失功能。细节在笔记本中,但在较高的层次上,实现略有不同:
- 训练损失:在LightGBM中自定义训练损失需要定义一个函数,该函数包含两个数组,即目标及其预测。反过来,该函数应该返回每个观察的两个梯度和海森的数组。如上所述,我们需要使用微积分来导出梯度和海森,然后在Python中实现它。
- 验证损失:自定义LightGBM中的验证损失需要定义一个函数,该函数接受相同的两个数组,但返回三个值:一个字符串,其名称为metric的字符串,损失本身,以及关于更高是否更好的布尔值。
用于在LightGBM中实现自定义损失的代码
定义自定义验证和训练损失功能
在LightGBM中结合训练和验证损失(包括Python和scikit-learn API示例)
自定义损失函数的实验
Jupyter笔记本还对默认随机森林,默认LightGBM和MSE以及LightGBM与自定义训练和验损失函数进行了深入比较。(https://github.com/manifoldai/mf-eng-public/blob/master/notebooks/custom_loss_lightgbm.ipynb)我们使用Friedman 1合成数据集,进行了8,000次训练观察,2,000次验证观察和5,000次测试观察。验证集用于查找优化验证损失的最佳超参数集。下面报告的分数在测试观察结果上进行评估,以评估我们模型的普遍性。
我们已经完成了下表中总结的一系列实验。请注意,我们关心的最重要的分数是非对称MSE,因为它明确定义了我们的不对称惩罚问题。
我们的实验和结果
让我们详细看一些比较。
随机森林→LightGBM
使用默认设置,LightGBM在此数据集上的性能优于Random Forest。随着更多树和超参数的更好组合,随机森林也可能会给出好的结果,但这不是重点。
LightGBM→LightGBM,具有自定义的训练损失
这表明我们可以使我们的模型优化我们关心的内容。默认的LightGBM正在优化MSE,因此它可以降低MSE损失(0.24 vs 0.33)。具有自定义训练损失的LightGBM优化了非对称MSE,因此对于非对称MSE(1.31 vs. 0.81)表现更好。
LightGBM→LightGBM使用MSE调整早期停止轮次
两种LightGBM模型都在优化MSE。我们看到默认的MSE分数有了很大改善,只需稍微调整一下使用早期停止轮次(MSE:0.24 vs 0.14)。因此,我们应该让模型使用早期停止超参数来确定最佳提升次数,而不是将提升次数限制为默认值(即100)。超参数优化很重要!
LightGBM使用MSE→LightGBM调整早期停止轮次,并使用自定义MSE进行早期停止调整
这两个模型的得分非常接近,没有实质性差异。这是因为验证损失仅用于决定何时停止提升。梯度是在两种情况下优化默认MSE。每个后续树为两个模型生成相同的输出。唯一的区别是具有自定义验证损失的模型在742次增强迭代时停止,而其他的则运行多次。
LightGBM使用自定义MSE→LightGBM通过自定义损失进行调整,并使用MSE进行早期停止调整
仅在不改变验证损失的情况下自定义训练损失会损害模型性能。只有自定义训练损失的模型比其他情况增加了更多轮次(1848)。如果我们仔细观察,这个模型的训练损失非常低(0.013)并且在训练集上高度过度拟合。每个梯度提升迭代都是使用训练误差作为目标变量来创建新树,但仅当验证数据的损失开始增加时,提升才会停止。当模型开始过度拟合时,验证损失通常开始增加,这是停止构建更多树的信号。在这种情况下,由于验证和训练损失彼此不一致,因此模型似乎没有"得到消息"而导致过度拟合。这个配置只是为了完整而包含在内,并不是人们在实践中应该使用的。
LightGBM具有经过调整的早期停止轮次,MSE→LightGBM训练自定义训练损失,并通过自定义验证损失调整早期停止轮次最终模型使用自定义训练和验证损失。它通过相对较少的提升迭代次数给出最佳的非对称MSE分数。损失与我们关心的一致!
让我们仔细看看残差直方图以获得更多细节。
请注意,使用LightGBM(即使使用默认的超参数),与随机森林模型相比,预测性能也有所提高。具有自定义验证损失的最终模型似乎在直方图的右侧进行更多预测,即实际值大于预测值。 这是由于不对称的自定义损失函数的缘故。使用残差的核密度图可以更好地可视化残差的右侧偏移。
LightGBM模型的预测与对称和非对称评估的比较
结论
没有哪个模型是完美无缺的,但许多商业问题并没有不平等的对待低估和过高估。有时,我们有意地希望我们的模型将错误偏向某个方向,但这具体取决于哪些错误的成本更高。因此,我们不应该限制自己使用普通ML库中的"现成"对称损失函数。
LightGBM提供了一个简单的界面,可以合并自定义训练和验证损失函数。在适当的时候,我们应该利用这个功能来做出更好的预测。但是,你不应立即跳转到使用自定义损失函数。最好采用精益的、迭代的方法,首先从像随机森林这样的简单基线模型开始。在下一次迭代中,你可以移动更复杂的模型,如LightGBM,并进行超参数优化。只有在这些基线稳定后,才有必要进行自定义验证和训练损失函数。
更多推荐读物
如果你不清楚一般梯度提升的工作原理,我建议你阅读如何解释Terence Parr的梯度提升(http://explained.ai/gradient-boosting/index.html),以及Prince从头开始的梯度提升(https://medium.com/mlreview/gradient-boosting-from-scratch-1e317ae4587d)。
关于如何在不同的GBM框架中调整超参数,有很多文章。如果你想使用其中一个软件包,可以花些时间了解要搜索的超参数范围。 LightGBM GitHub问题可以大致了解要使用的值范围。(https://github.com/Microsoft/LightGBM/issues/695) Aarshay Jainhas写了一篇关于调整XGBoost和sklearn梯度提升的博客。(https://www.analyticsvidhya.com/blog/2016/03/complete-guide-parameter-tuning-xgboost-with-codes-python/)
要了解哪种梯度提升包适合你的情况,请阅读Alvira Swalin的CatBoost vs. Light GBM vs. XGBoost(https://towardsdatascience.com/catboost-vs-light-gbm-vs-xgboost-5f93620723db),以及Pranjan Khandelwal的哪种算法取得冠军:Light GBM vs XGBOOST?。(https://www.analyticsvidhya.com/blog/2017/06/which-algorithm-takes-the-crown-light-gbm-vs-xgboost/)
3.RecyclerView实现横向滚动
我相信很久以前,大家在谈横向图片轮播是时候,优先会选择具有HorizontalScrollView效果和ViewPager来做,不过自从Google大会之后,系统为我们提供了另一个控件RecyclerView。RecyclerView是listview之后的又一利器,它可以实现高度的定制。今天就利用RecyclerView实现我们需要的相册效果。
先上一个图:
主要实现就是一个RecyclerView+RecyclerView.Adapter实现。
Activity的布局文件:
[html] view plain copy print?
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:scrollbars="none"/>
我这里是自定义的控件,主要代码:
[html] view plain copy print?
public class SimpleLinearLayout extends LinearLayout {
protected Context mContext;
protected View contentView;
protected AtomicBoolean isPreparingData;
public SimpleLinearLayout(Context context) {
super(context);
this.mContext = context;
isPreparingData = new AtomicBoolean(false);
initViews();
}
public SimpleLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
this.mContext = context;
isPreparingData = new AtomicBoolean(false);
initViews();
}
protected void initViews() {
}
}
主页面代码:
[html] view plain copy print?
public class SpeedHourView extends SimpleLinearLayout {
@BindView(R.id.recycler_view)
RecyclerView recyclerView;
private SpeedHourAdapter speedHourAdapter=null;
private SpeedHourEntity entity=null;
public SpeedHourView(Context context) {
this(context, null);
}
public SpeedHourView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void initViews() {
contentView = inflate(mContext, R.layout.layout_speed_per_hour, this);
ButterKnife.bind(this);
init();
}
private void init() {
initData();
initView();
initAdapter();
}
private void initData() {
String data = FileUtils.readAssert(mContext, "speenhour.txt");
entity = JsonUtils.parseJson(data, SpeedHourEntity.class);
}
private void initView() {
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(mContext);
linearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(linearLayoutManager);
}
private void initAdapter() {
speedHourAdapter=new SpeedHourAdapter(mContext);
recyclerView.setAdapter(speedHourAdapter);
if (entity!=null&&entity.topic!=null&&entity.topic.items!=null&&entity.topic.items.size()>0){
List<SpeedHourEntity.TopicBean.ItemsBean.ListBean>listBeen=entity.topic.items.get(0).list;
if (listBeen!=null&&listBeen.size()>0)
speedHourAdapter.setList(listBeen);
}
speedHourAdapter.setOnItemClickListener(new SpeedHourAdapter.OnItemClickListener() {
@Override
public void onItemClick(View view, int position) {
ProductDetailsActivity.open(mContext);
}
});
}
@OnClick(R.id.more_view)
public void moreClick() {
ToastUtils.showToast("更多时速达");
}
}
adapter布局:
[html] view plain copy print?
<?xmlversion="1.0"encoding="utf-8"?>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
xmlns:ptr="http://schemas.android.com/apk/res-auto"
android:id="@+id/speed_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp"
android:gravity="center">
<ImageView
android:id="@+id/speed_image"
android:layout_width="85dp"
android:layout_height="85dp"
android:scaleType="fitXY"
/>
<TextView
android:id="@+id/speed_name"
android:layout_marginTop="5dp"
android:text="蜂蜜柚子茶"
android:maxLines="1"/>
<TextView
android:id="@+id/speed_price"
android:layout_marginTop="5dp"
android:text="¥30.0"
android:maxLength="6"
android:maxLines="1"/>
</LinearLayout>
adapter代码:
[html] view plain copy print?
public class SpeedHourAdapter extends RecyclerView.Adapter<SpeedHourHolder> {
private List<ListBean> specailList;
private LayoutInflater mInflater;
private Context mContext=null;
public SpeedHourAdapter(Context context) {
this.mContext=context;
mInflater = LayoutInflater.from(context);
}
public void setList(List<ListBean> list) {
this.specailList = list;
notifyDataSetChanged();
}
public OnItemClickListener mOnItemClickListener;
public interface OnItemClickListener {
void onItemClick(View view, int position);
}
public void setOnItemClickListener(OnItemClickListener mOnItemClickLitener) {
this.mOnItemClickListener = mOnItemClickLitener;
}
@Override
public SpeedHourHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.item_speedhour_layout, parent, false);
SpeedHourHolder holder = new SpeedHourHolder(view);
return holder;
}
@Override
public void onBindViewHolder(final SpeedHourHolder holder, final int position) {
ListBean bean = specailList.get(position);
if (bean != null) {
holder.speedImage.setScaleType(ImageView.ScaleType.FIT_XY);
Glide.with(mContext).load(bean.pic).error(R.drawable.welfare_default_icon).into(holder.speedImage);
holder.speedName.setText("同仁堂枸杞茶");
holder.speedPrice.setText("¥"+Math.random()*100);
}
holder.speedView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mOnItemClickListener!=null){
mOnItemClickListener.onItemClick(holder.speedView,position);
}
}
});
}
@Override
public int getItemCount() {
return specailList.size();
}
}
class SpeedHourHolder extends RecyclerView.ViewHolder {
@BindView(R.id.speed_view)
LinearLayout speedView;
@BindView(R.id.speed_image)
ImageView speedImage;
@BindView(R.id.speed_name)
TextView speedName;
@BindView(R.id.speed_price)
TextView speedPrice;
public SpeedHourHolder(View itemView) {
super(itemView);
ButterKnife.bind(this,itemView);
itemView.setTag(this);
}
}
代码中用到的实体类:
[html] view plain copy print?
public class SpeedHourEntity {
public TopicBean topic;
public static class TopicBean {
public long nextupdatetime;
public List<ItemsBean> items;
public static class ItemsBean {
public int id;
public String theme;
public int products;
public int users;
public String href;
public boolean follow;
public int topictype;
public List<ListBean> list;
public static class ListBean {
public String id;
public int price;
public String pic;
}
}
}
}
用到的 Json工具类也给大家
[html] view plain copy print?
public class JsonUtils {
private static Gson gson = new Gson();
public static <T> T parseJson(String response, Class<T> clazz) {
try {
return gson.fromJson(response, clazz);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static <T> T parseJson(String response, Type type) {
try {
return gson.fromJson(response, type);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static String toJson(Object object) {
try {
return gson.toJson(object);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
public static <T> List<T> jsonToList(final String jsonString, final Type type) {
try {
return gson.fromJson(jsonString, type);
} catch (Exception e) {
return null;
}
}
public static <T> List<T> jsonToList(final JsonArray jsonArray, final Class<T> classOfT) {
List<T>list = new ArrayList<T>();
for (int i = 0, size = jsonArray.size(); i <size; i++) {
list.add(gson.fromJson(jsonArray.get(i), classOfT));
}
return list;
}
public static <T> T parseJson(final JsonObject jsonObject, final Class<T> classOfT) {
try {
return gson.fromJson(jsonObject, classOfT);
} catch (Exception e) {
return null;
}
}
public static Map toMap(Object jsonString) {
if (TextUtils.isEmpty(jsonString.toString())) {
return new HashMap();
}
String js = jsonString.toString();
Gson gson = new Gson();
Type type = new TypeToken<Map>(){
}.getType();
Map map = gson.fromJson(js,type);
return map;
}
}
为了方便测试,给大家提供一段数据,大家放在assert就好了,然后读到实体类就好了:
[html] view plain copy print?
{
topic: {
nextupdatetime: 1472699607850,
items: [
{
id: 1000010,
theme: "追韩剧不能少“美眸”心机",
products: 793,
users: 325,
href: "",
list: [
{
id: "50119e86-8d67-4919-a41f-be8202b62b7e",
price: 288,
pic: "http://pc1.img.ymatou.com/G02/shangou/M08/D4/59/CgvUBVeW2oOAJZOgAAChvNt-3Yc332_n_w_l.jpg"
},
{
id: "936f2615-10bb-4831-8674-9bea0b43b486",
price: 79,
pic: "http://pc1.img.ymatou.com/G02/shangou/M01/79/BE/CgvUA1eMo0iAL9yhAAOEN7artTM830_n_w_l.jpg"
},
{
id: "24f2be35-ba6e-4bb7-b60d-47d9c2a5bb7d",
price: 35,
pic: "http://pc1.img.ymatou.com/G02/shangou/M0B/BA/86/CgvUBFdXdlKAJs8WAAhZYEeKhCI758_w_ls.jpg"
},
{
id: "6e43adf2-18b0-40aa-a95d-84ad3cf352f7",
price: 29,
pic: "http://pc2.img.ymatou.com/G02/upload/product/original/M07/13/22/CgvUA1eADhCAHWyQAAHAnGAUtm4799_n_w_l.jpg"
},
{
id: "c082d977-e06f-4f24-bf3e-7768b839170c",
price: 758,
pic: "http://pc2.img.ymatou.com/G02/shangou/M07/B5/D4/CgvUA1dW4XWALArJAACZadCCJ5Q293_w_ls.jpg"
},
{
id: "7737d9eb-ae85-4911-8f80-939c4d805b0a",
price: 29,
pic: "http://pc1.img.ymatou.com/G02/shangou/M0B/56/B2/CgvUBFeoq9iAXyveAAPoUP0-kYA656_n_w_l.jpg"
},
{
id: "bcc4517e-20d5-48da-ae46-708d2e8d03af",
price: 288,
pic: "http://pc1.img.ymatou.com/G02/shangou/M07/CC/8F/CgvUA1d6N7yASvgPAAMymJaT5yQ96_n_w_l.jpeg"
},
{
id: "c717e1bd-7a3b-4f92-9317-84b4147ede71",
price: 78,
pic: "http://pc1.img.ymatou.com/G02/upload/product/original/M07/8B/12/CgvUBFeOSB2AD_7dAAGNl3gl_gU541_n_w_l.jpg"
},
{
id: "139594cb-833c-4ade-b547-3a9a056b193e",
price: 69,
pic: "http://pc1.img.ymatou.com/G02/shangou/M0B/9D/5D/CgvUA1dWSM6AYn7hAAWcHrWn_90648_w_ls.png"
},
{
id: "4414e81f-fc3b-427c-b1ee-37b03883e0dc",
price: 88,
pic: "http://pc1.img.ymatou.com/G02/shangou/M09/02/76/CgvUBFeHQLSALvfLAAHccf91md4006_n_w_l.jpg"
}
],
follow: false,
topictype: 106
},
{
id: 1001185,
theme: "Tommy Hilfiger男女服饰精选",
products: 553,
users: 111,
href: "",
list: [
{
id: "bd128bbf-243b-4c2e-a1d4-ea698b06142e",
price: 99,
pic: "http://pc1.img.ymatou.com/G02/shangou/M08/16/8A/CgvUBFfGh_SADrC8AALybC7Xmv8091_n_w_l.jpg"
},
{
id: "ea044aaf-32da-4c6e-b867-755fa780036d",
price: 229,
pic: "http://pc1.img.ymatou.com/G02/shangou/M08/13/4F/CgvUBFfGA0-AFbQsAALknGVeqU8444_n_w_l.jpg"
},
{
id: "5b5730a9-3343-4ef6-b78b-8b585c0b78f2",
price: 168,
pic: "http://pc1.img.ymatou.com/G02/shangou/M07/38/1D/CgvUBFekEIOAc8EdAAEHlzPTZWw039_n_w_l.jpg"
},
{
id: "e956417a-e476-486b-be19-8fd64c6fe551",
price: 199,
pic: "http://pc1.img.ymatou.com/G02/shangou/M09/D9/DC/CgvUA1d7vRqAGFxnAADXh3zHBn4743_n_w_l.jpg"
},
{
id: "1d3e6f9b-d5f5-436c-a0d4-2e04a9e08c0d",
price: 299,
pic: "http://pc1.img.ymatou.com/G02/shangou/M07/D9/C2/CgvUBVe8dPCAMcc8AAJ6-rOnfWA070_n_w_l.jpg"
},
{
id: "d44ca918-3e73-4b24-a81b-f88813be057e",
price: 258,
pic: "http://pc1.img.ymatou.com/G02/shangou/M01/C1/EF/CgvUBVe4txiAIkmjAAMYwUZonWk554_n_w_l.jpg"
},
{
id: "9f9b285a-bd18-409e-a66a-d05c717898d0",
price: 179,
pic: "http://pc1.img.ymatou.com/G02/shangou/M03/45/84/CgvUBFeIhXGANzZpAADWX4O6_Xc860_n_w_l.jpg"
},
{
id: "c13e8714-e1a8-48a7-b47b-7c165aa63c34",
price: 178,
pic: "http://pc1.img.ymatou.com/G02/shangou/M0A/9E/4B/CgvUA1ezz_yALQtFAAHeUOJ-DcY945_n_w_l.jpg"
},
{
id: "29aa1c5a-5f6e-4a80-9305-84e83cf652fc",
price: 299,
pic: "http://pc1.img.ymatou.com/G02/shangou/M0B/EB/44/CgvUBFeZslCADHsjAAPW3Sy2qj8675_n_w_l.jpg"
},
{
id: "d8120a37-aa93-4e4f-934a-4245c4f42c71",
price: 388,
pic: "http://pc1.img.ymatou.com/G02/shangou/M02/50/3A/CgvUBVen9AKAOZLHAAFhQsWjV14609_n_w_l.jpg"
}
],
follow: false,
topictype: 106
},
{
id: 1002054,
theme: "每个都市白领都有一只时尚腕表",
products: 310,
users: 68,
href: "",
list: [
{
id: "386ebe00-cdd0-4324-92f7-6a25179fe557",
price: 1999,
pic: "http://pc1.img.ymatou.com/G02/shangou/M05/7E/4D/CgvUBVeNHI6APdp3AAFZgOkl-XU821_n_w_l.jpg"
},
{
id: "4d93b2e6-7bf6-4878-830f-6ed22c380731",
price: 1550,
pic: "http://pc1.img.ymatou.com/G02/shangou/M04/6B/D1/CgvUBVer7BSAE7tTAAGD0sdyEp4918_n_w_l.jpg"
},
{
id: "e6b2eaef-e8ea-4ca1-b9cb-fba630e79572",
price: 398,
pic: "http://pc1.img.ymatou.com/G02/upload/product/original/M00/EC/53/CgvUBFd-GgWAZ0hWAAHuCzGVzlE002_n_w_l.jpg"
},
{
id: "0bf2584d-52eb-403e-b668-fc59eddf7b35",
price: 899,
pic: "http://pc1.img.ymatou.com/G02/shangou/M0A/50/9C/CgvUBFeoBtaAVRJaAAPRD_cW1jI986_n_w_l.jpg"
},
{
id: "756ca0ed-b128-4b72-a308-f5cde1a31fbb",
price: 1788,
pic: "http://pc2.img.ymatou.com/G02/upload/product/original/M04/13/FE/CgvUBFeAGCiAeyEgAAOoCajEei0337_n_w_l.jpg"
},
{
id: "c5c95dd3-0585-4ccd-b34b-b2a1b0c98915",
price: 1460,
pic: "http://pc1.img.ymatou.com/G02/shangou/M04/ED/CF/CgvUA1eZ0Y2AQV2gAAJMchT1mjY462_n_w_l.jpg"
},
{
id: "c5a664db-aa70-47d1-b0e6-15ad1faafcbe",
price: 1299,
pic: "http://pc1.img.ymatou.com/G02/shangou/M08/15/40/CgvUA1egLnyAZo-IAAIVAvK1Hxw422_n_w_l.jpg"
},
{
id: "a3449aef-fdec-4344-9bca-f98b27a8a3de",
price: 2380,
pic: "http://pc1.img.ymatou.com/G02/shangou/M01/FB/EB/CgvUBVfBjXOAZiOhAAJILon5PNE706_n_w_l.jpg"
},
{
id: "cb473f7e-3a40-4eb5-8778-043308c80ad4",
price: 299,
pic: "http://pc1.img.ymatou.com/G02/shangou/M03/99/BF/CgvUBVePNzOAR5inAAFt690zWtA662_n_w_l.jpg"
},
{
id: "2ad9f10e-ee94-49a7-95e8-b37104b86dc4",
price: 699,
pic: "http://pc1.img.ymatou.com/G02/shangou/M07/06/F6/CgvUA1eHRaGAL-WUAACUnFlglbU914_n_w_l.jpg"
}
],
follow: false,
topictype: 106
},
{
id: 1000691,
theme: "工薪族必备 一只FURLA手袋",
products: 369,
users: 81,
href: "",
list: [
{
id: "326d57e0-e202-45c9-a418-1f7c5c6cee37",
price: 1599,
pic: "http://pc1.img.ymatou.com/G02/shangou/M07/99/9B/CgvUBFezGJmAf-gQAAH98NQDroc227_n_w_l.jpg"
},
{
id: "8c0aa3ec-0fba-4ee8-8952-74ebca2dd260",
price: 799,
pic: "http://pc1.img.ymatou.com/G02/shangou/M04/7C/AD/CgvUBVeM506AGvgHAAEYWxTXLXc839_n_w_l.jpg"
},
{
id: "3e04f95c-4b0f-4b9f-ae44-0391ab2f1616",
price: 1880,
pic: "http://pc1.img.ymatou.com/G02/shangou/M05/A5/E7/CgvUA1eQVrKAXqQVAALdAABuInM554_n_w_l.jpg"
},
{
id: "05059f48-a6bb-48c1-88df-7ecabe65bd4a",
price: 799,
pic: "http://pc1.img.ymatou.com/G02/shangou/M02/7C/8A/CgvUBVeM5E2ABWGgAAJ_9inEqjQ669_n_w_l.jpg"
},
{
id: "0962bf25-c417-409d-b39b-daf84c9a4e9d",
price: 988,
pic: "http://pc1.img.ymatou.com/G02/shangou/M04/C3/0F/CgvUA1e4-vmAZpGRAAH_XdWHcGE171_n_w_l.jpg"
},
{
id: "5c960ae1-27e3-4c94-8233-7456dc9e82b6",
price: 850,
pic: "http://pc1.img.ymatou.com/G02/shangou/M08/AF/1A/CgvUA1e1xIGASjQqAAIsrHq1TpY720_n_w_l.jpg"
},
{
id: "52184a55-e7e5-4e43-9a11-7b9fcc737136",
price: 1590,
pic: "http://pc1.img.ymatou.com/G02/shangou/M0A/79/E6/CgvUBFety5GASYSLAAJeGTYNSgQ032_n_w_l.jpg"
},
{
id: "f11bbaf9-64eb-44ce-9bd3-07e8c8c6d1b3",
price: 2099,
pic: "http://pc1.img.ymatou.com/G02/shangou/M03/36/F6/CgvUBVej7UuABhdEAAGb2YixMaY568_n_w_l.jpg"
},
{
id: "6dbd4793-2b34-43b5-8b81-7432d301bc34",
price: 2088,
pic: "http://pc1.img.ymatou.com/G02/shangou/M0A/6C/81/CgvUA1er7guALEOhAAFI7ymRkME838_n_w_l.jpg"
},
{
id: "1d6f1747-a292-4821-98a0-becc67381f98",
price: 1450,
pic: "http://pc1.img.ymatou.com/G02/shangou/M09/0D/1C/CgvUBVfE91SASW_GAAHV3WPdWSU789_n_w_l.jpg"
}
],
follow: false,
topictype: 106
},
{
id: 1000335,
theme: "你不穿,怎么知道尖头鞋有多美",
products: 262,
users: 61,
href: "",
list: [
{
id: "5dc85724-e39b-4d29-bb33-bea45910d64e",
price: 795,
pic: "http://pc1.img.ymatou.com/G02/shangou/M02/0C/2B/CgvUA1fEoT2AX5jGAAOIddgXk2s232_n_w_l.jpg"
},
{
id: "b47bcbea-e115-41be-94d7-a81d012997d9",
price: 699,
pic: "http://pc1.img.ymatou.com/G02/shangou/M01/A7/91/CgvUA1dWePGAbtnBAACpSJlaJJI503_w_ls.jpg"
},
{
id: "1b27c7c2-e996-4039-b403-505425c7c661",
price: 799,
pic: "http://pc1.img.ymatou.com/G02/shangou/M07/F4/B2/CgvUBVfASQmAfqPkAAJ5Y5NW4DU258_n_w_l.jpg"
},
{
id: "86c2f638-f8cb-4e41-9165-b186b90de522",
price: 799,
pic: "http://pc1.img.ymatou.com/G02/shangou/M07/41/2D/CgvUBFeIW0SAGrUQAAdZ8pOEVPU386_n_w_l.JPG"
},
{
id: "93251a4a-9265-47e8-a108-b790250ca5eb",
price: 599,
pic: "http://pc1.img.ymatou.com/G02/shangou/M0A/4D/53/CgvUBVeGEjSAHP8rAADp5SupP3A653_n_w_l.jpg"
},
{
id: "522bcfb0-540e-4765-b391-6928e0a63afd",
price: 259,
pic: "http://pc1.img.ymatou.com/G02/shangou/M09/B9/2B/CgvUBFeS2B-AXOelAAKE2I31Jxk211_n_w_l.jpg"
},
{
id: "565a3590-f8e2-467a-b5ec-a7e648e3da05",
price: 399,
pic: "http://pc1.img.ymatou.com/G02/shangou/M02/C9/C9/CgvUBFe6W8eAaV7fAADdh7847PY900_n_w_l.jpg"
},
{
id: "f0f11042-9d05-4b69-82c2-a8c614025b7c",
price: 699,
pic: "http://pc1.img.ymatou.com/G02/shangou/M0B/CA/32/CgvUBVe6Wi-AFdLaAAIhgT3Z4Zw873_n_w_l.jpg"
},
{
id: "2099167d-39bf-4949-b5ae-fd156d49a38f",
price: 299,
pic: "http://pc1.img.ymatou.com/G02/shangou/M0A/E5/4F/CgvUBVe-TXmABZ7JAAFIlZ70s98657_n_w_l.jpg"
},
{
id: "5314a6cc-1ade-4fac-80ba-c32e2d43d839",
price: 599,
pic: "http://pc1.img.ymatou.com/G02/shangou/M01/F2/D6/CgvUA1eaj5aAH0JHAADbLN5GWzI823_n_w_l.jpg"
}
],
follow: false,
topictype: 106
},
{
id: 1000981,
theme: "职场男的钱包就应该这么选",
products: 708,
users: 210,
href: "",
list: [
{
id: "0b5d3386-bb9f-46d3-bd4a-826f926c9073",
price: 499,
pic: "http://pc1.img.ymatou.com/G02/shangou/M01/0D/00/CgvUA1ee6ZyAPdqtAAKbDUt68dw320_n_w_l.jpg"
},
{
id: "d558cf02-35a6-45a9-a84d-90930f85b204",
price: 480,
pic: "http://pc1.img.ymatou.com/G02/shangou/M07/5D/1F/CgvUBFepp3qAEzN8AANrv-wGJEE984_n_w_l.jpg"
},
{
id: "b9074e54-190e-491d-8e73-21a94884d252",
price: 499,
pic: "http://pc1.img.ymatou.com/G02/shangou/M03/61/5D/CgvUBVeqe6yASqhuAAP6jd0k0E4643_n_w_l.jpg"
},
{
id: "96c9711e-5655-4de2-994e-4a6baa61df8b",
price: 1380,
pic: "http://pc1.img.ymatou.com/G02/shangou/M05/9A/03/CgvUBVezF6CAIHYxAAKT5rHhHSw992_n_w_l.jpg"
},
{
id: "62de6949-d5e0-4d60-a6f0-34901ba6a7ce",
price: 1300,
pic: "http://pc1.img.ymatou.com/G02/shangou/M03/6A/90/CgvUBVerwt6AS6jJAAUc50dRQYw030_n_w_l.jpg"
},
{
id: "1cbc7f2e-af91-4c29-9ba8-5609ce3263a5",
price: 189,
pic: "http://pc1.img.ymatou.com/G02/shangou/M0A/A9/ED/CgvUBVe1WyaARpI7AAIrPYzQMWk137_n_w_l.jpg"
},
{
id: "b7531635-edd8-4c83-93e6-196e73fcd7b5",
price: 299,
pic: "http://pc1.img.ymatou.com/G02/shangou/M06/C2/C4/CgvUBVe4_uSAFbPRAALWCg7g2k4590_n_w_l.jpg"
},
{
id: "731575af-0031-4211-8d3a-75ef19a04d51",
price: 800,
pic: "http://pc1.img.ymatou.com/G02/shangou/M01/B9/F4/CgvUA1e3ZHmAF3_xAAJinKN4FpE421_n_w_l.jpg"
},
{
id: "506225eb-5135-4a8d-8f9a-dedc4d69af57",
price: 488,
pic: "http://pc1.img.ymatou.com/G02/shangou/M07/D3/33/CgvUA1eWl-iANn4pAARnRxR7FKE211_n_w_l.jpg"
},
{
id: "ae673d4e-59c6-4ae3-a7bd-6f4ff7ec0484",
price: 399,
pic: "http://pc1.img.ymatou.com/G02/shangou/M06/42/4D/CgvUBFeIZ9aAcfTXAASRR__3Ns4881_n_w_l.jpg"
}
],
follow: false,
topictype: 106
},
{
id: 1001855,
theme: "少女派最该入手的唇膏盘点",
products: 221,
users: 121,
href: "",
list: [
{
id: "dd59aefa-0619-40a9-8f44-33b7b980e7e7",
price: 36,
pic: "http://pc1.img.ymatou.com/G02/shangou/M01/44/92/CgvUBVelr-mARWRMAAL0-pzS8GQ614_n_w_l.jpg"
},
{
id: "85b8ce98-b7e6-4323-83b7-ba891f0a0da3",
price: 249,
pic: "http://pc1.img.ymatou.com/G02/shangou/M07/F6/9E/CgvUBVfAv0CAYFwEAAHpgOwVRgw908_n_w_l.jpg"
},
{
id: "9dfe69a1-fc6d-4652-941b-3e1140ef50ec",
price: 199,
pic: "http://pc1.img.ymatou.com/G02/shangou/M0A/98/FC/CgvUBVePKD2AXj_uAAGhr-ddlCs021_n_w_l.jpg"
},
{
id: "db7ea83c-90a2-4569-a063-2580e4bbe586",
price: 149,
pic: "http://pc1.img.ymatou.com/G02/shangou/M05/08/4B/CgvUBFeeBECASewiAAFv5dozLqQ743_n_w_l.jpg"
},
{
id: "7e702512-bc7c-49a7-894c-7f79e08635b6",
price: 209,
pic: "http://pc1.img.ymatou.com/G02/upload/product/original/M0A/22/F6/CgvUBFeAcu-ADZbNAAbBZzsCMZo894_n_w_l.jpg"
},
{
id: "8aa440ee-b99c-4047-ad6b-669b0c864266",
price: 85,
pic: "http://pc1.img.ymatou.com/G02/upload/product/original/M0B/8E/DC/CgvUA1eOS5KABSC4AAE47YcX0yo815_n_w_l.jpg"
},
{
id: "4b845bc6-dde2-4d83-b3cb-5c2aba1629ee",
price: 68,
pic: "http://pc1.img.ymatou.com/G02/shangou/M0B/72/E9/CgvUBFeMM6qABb7rAAe2r7x1tQQ859_n_w_l.jpg"
},
{
id: "43c635e7-01e8-4dfc-be38-5d11d9bd67bd",
price: 195,
pic: "http://pc1.img.ymatou.com/G02/shangou/M07/9D/DE/CgvUA1ePZEOAQ1kZAAY-lRjPbzQ155_n_w_l.JPG"
},
{
id: "3689fe6f-fc0d-4a4a-a5b1-0553038e154f",
price: 218,
pic: "http://pc1.img.ymatou.com/G02/shangou/M09/50/76/CgvUBVeI4T-AOjh-AALGBDOtN9w821_n_w_l.jpg"
},
{
id: "9a1aa6ec-fcab-4206-bce3-75b0eed4a331",
price: 199,
pic: "http://pc1.img.ymatou.com/G02/shangou/M07/DC/0C/CgvUBFe9ExSAAxj-AALHgxQqlcY432_n_w_l.jpg"
}
],
follow: false,
topictype: 106
},
{
id: 1002012,
theme: "Kate spade的甜心少女风",
products: 1125,
users: 157,
href: "",
list: [
{
id: "a92b1158-d8cc-4bfc-bba1-8e269a597fc2",
price: 1380,
pic: "http://pc1.img.ymatou.com/G02/shangou/M08/5F/46/CgvUBVep3VWAeqi5AAIJ0LKNigk289_n_w_l.jpg"
},
{
id: "5a388eb3-e696-4c78-9b5a-4a6cefb54e2f",
price: 1088,
pic: "http://pc1.img.ymatou.com/G02/shangou/M07/4F/4A/CgvUBFen5TSAPn2PAAI_RpcB9qM096_n_w_l.jpg"
},
{
id: "c788ead9-44b1-47da-86db-f520e871a959",
price: 875,
pic: "http://pc1.img.ymatou.com/G02/shangou/M09/B9/A7/CgvUA1eSypCAHLxPAALzOv-BEHo743_n_w_l.jpg"
},
{
id: "2a8d3aac-0991-41db-bfcc-c89026f92756",
price: 760,
pic: "http://pc1.img.ymatou.com/G02/shangou/M06/9B/E3/CgvUBFezohaAJuKgAAOQlbLJBiU608_n_w_l.jpg"
},
{
id: "f13dd52f-b3ae-46cb-b4fc-c3eaeaac6a7e",
price: 498,
pic: "http://pc1.img.ymatou.com/G02/shangou/M01/CF/DF/CgvUBVd6qWiAJg6HAADCi9bKFak394_n_w_l.jpg"
},
{
id: "bfa91c51-57a2-46c4-a6de-a420852be9ca",
price: 429,
pic: "http://pc1.img.ymatou.com/G02/shangou/M06/8E/3A/CgvUA1dyasWAT8sCAADksewcyQ0275_n_w_l.jpg"
},
{
id: "16462c30-454d-4566-a40c-1c9af6d066eb",
price: 560,
pic: "http://pc1.img.ymatou.com/G02/shangou/M05/F1/CF/CgvUBVe__PSARr-9AANZ07utoWA217_n_w_l.JPG"
},
{
id: "6a9d0e09-6d7f-42c1-bfd7-50adb12473a2",
price: 1249,
pic: "http://pc1.img.ymatou.com/G02/shangou/M01/97/B9/CgvUBVePEcaADHj-AAHcUtVj1OA401_n_w_l.jpg"
},
{
id: "484a8967-c843-4d34-8876-4afca275cd58",
price: 1250,
pic: "http://pc1.img.ymatou.com/G02/shangou/M01/B3/0B/CgvUBVe2lp2AVGDtAAGFyOb9OhI144_n_w_l.jpg"
},
{
id: "5e32fbce-be90-4c55-b3ba-2bd05de10f3a",
price: 998,
pic: "http://pc1.img.ymatou.com/G02/shangou/M08/C3/0F/CgvUBVe5CL6ABP0CAAGc6XBDq5c140_n_w_l.jpg"
}
],
follow: false,
topictype: 106
},
{
id: 1000657,
theme: "施华洛世奇 奢华之最",
products: 1284,
users: 147,
href: "",
list: [
{
id: "68775149-2996-40d3-8164-fe51ebaeb247",
price: 390,
pic: "http://pc1.img.ymatou.com/G02/shangou/M01/B5/40/CgvUA1e2usGAGMiOAAIeoEq4_8k942_n_w_l.jpg"
},
{
id: "f4ea3d67-957b-44b1-824a-aca71b191975",
price: 290,
pic: "http://pc1.img.ymatou.com/G02/shangou/M06/48/C1/CgvUBFemkpKAQimhAAIVTLA1TnM821_n_w_l.jpg"
},
{
id: "608f9cea-865a-403f-a064-b7020d8b9151",
price: 500,
pic: "http://pc1.img.ymatou.com/G02/shangou/M0A/C1/9B/CgvUBFe407aAVwHsAAEVmeaH0Wo087_n_w_l.jpg"
},
{
id: "5f74f137-6b06-412f-92b0-6ccfabc5e4ff",
price: 990,
pic: "http://pc1.img.ymatou.com/G02/shangou/M03/05/31/CgvUBFedjnOAeJW5AALIA4EvnDY776_n_w_l.jpg"
},
{
id: "207db2b4-d7b7-40af-b769-a51384030781",
price: 358,
pic: "http://pc3.img.ymatou.com/G02/shangou/M08/9B/A9/CgvUA1dWP5KAKz_nAASY1zfAp2Q998_w_ls.jpg"
},
{
id: "61e75f97-934f-480a-a253-c4401a692c2f",
price: 799,
pic: "http://pc1.img.ymatou.com/G02/shangou/M01/61/16/CgvUA1eJ5eSAeljEAAMXM9aiJWo944_n_w_l.jpg"
},
{
id: "f60f6587-e557-4261-b58f-31f5719df5ba",
price: 580,
pic: "http://pc1.img.ymatou.com/G02/shangou/M06/50/97/CgvUBFeI4xKAQHy7AAEVKIt--A0224_n_w_l.jpg"
},
{
id: "630d7893-6a9e-4fc8-8a93-098fce056920",
price: 659,
pic: "http://pc1.img.ymatou.com/G02/shangou/M0B/A3/34/CgvUBVeQI_CAZkjQAAEm1d4A2xE253_n_w_l.jpg"
},
{
id: "1e52e01f-335e-440b-99d6-7cd79ba6d1ae",
price: 959,
pic: "http://pc1.img.ymatou.com/G02/shangou/M02/B4/CC/CgvUBFd3Ik2AazqrAACZbtZm554683_n_w_l.jpg"
},
{
id: "3b5663c3-c694-4a68-a02f-c6bda164427a",
price: 515,
pic: "http://pc1.img.ymatou.com/G02/shangou/M03/A1/42/CgvUBVe0J1KAczpWAAG7JrvcS2w388_n_w_l.jpg"
}
],
follow: false,
topictype: 106
},
{
id: 1002418,
theme: "爆款再见,饰品我只要独一无二",
products: 113,
users: 33,
href: "",
list: [
{
id: "dfff8751-775c-437f-8fa7-5aec934a5ef0",
price: 89,
pic: "http://pc1.img.ymatou.com/G02/shangou/M0A/49/84/CgvUA1emjwCAYqSnAAGVFiRPoW4269_n_w_l.jpg"
},
{
id: "ad098f8a-5fcd-42ab-afdd-3ff580a1ac0b",
price: 350,
pic: "http://pc1.img.ymatou.com/G02/shangou/M03/41/AB/CgvUBFelUceAJv-yAAFqX0aWyWE901_n_w_l.jpg"
},
{
id: "bda09ca7-56cb-4458-b6d1-9f988c9f326d",
price: 450,
pic: "http://pc1.img.ymatou.com/G02/shangou/M08/98/7F/CgvUA1ey5bOAYkHaAAJFbg6Ji3M944_n_w_l.jpg"
},
{
id: "23fc3728-a706-42ce-9e5f-7ce742474a73",
price: 680,
pic: "http://pc1.img.ymatou.com/G02/shangou/M05/07/03/CgvUA1edweiAfoO3AAFmKdmzk3c556_n_w_l.jpg"
},
{
id: "f8ea5393-7972-40b0-90b2-32b22378cb35",
price: 290,
pic: "http://pc1.img.ymatou.com/G02/shangou/M0B/BE/92/CgvUA1e4G0uAEDW7AAIHW5H3aC8568_n_w_l.jpg"
},
{
id: "f249ae53-750e-4237-a53d-7deb1c5102e5",
price: 468,
pic: "http://pc1.img.ymatou.com/G02/shangou/M0A/C3/9F/CgvUBFeUZn6ATpvdAAWmCLN-aEk844_n_w_l.jpg"
},
{
id: "460b5d5c-6b6e-4c03-aefa-a56c7a2df8d4",
price: 3100,
pic: "http://pc1.img.ymatou.com/G02/shangou/M05/CF/AC/CgvUBVe6-jOAZ7w4AALCedzhGMQ665_n_w_l.jpg"
},
{
id: "60040ecd-23f4-44e7-a3e9-81e36327a2ca",
price: 129,
pic: "http://pc1.img.ymatou.com/G02/shangou/M01/42/37/CgvUBVelXh2AHgrnAAHXOIwMgKw041_n_w_l.jpg"
},
{
id: "83f60817-e22c-42e9-94cf-331e8ffc1ce3",
price: 3350,
pic: "http://pc1.img.ymatou.com/G02/shangou/M06/60/38/CgvUBFeJ5Q6AD0MwAAKY-Ou9erk199_n_w_l.jpg"
},
{
id: "0e816cf1-4c0d-4ced-a356-45620fbda1b8",
price: 199,
pic: "http://pc1.img.ymatou.com/G02/upload/product/original/M07/FC/C3/CgvUBVd_rEqAHMPBAAOCO_DMoCM554_n_w_l.jpg"
}
],
follow: false,
topictype: 106
},
{
id: 1003396,
theme: "清新淑女的露肩裙美到没朋友",
products: 50,
users: 34,
href: "",
list: [
{
id: "548c381a-2be7-4a6c-9344-b898f18e331e",
price: 650,
pic: "http://pc1.img.ymatou.com/G02/shangou/M05/56/70/CgvUBVeomK2AOJWXAAKfQ3-H1DQ245_n_w_l.jpg"
},
{
id: "8ca2ca1a-3f7b-4826-9b17-a339f4c4cbf3",
price: 560,
pic: "http://pc1.img.ymatou.com/G02/shangou/M06/AE/6B/CgvUBVe1v6uAOOlwAAIW5S9SjFo614_n_w_l.jpg"
},
{
id: "aed17646-dfe8-4969-bbd4-cfaab80000db",
price: 1899,
pic: "http://pc1.img.ymatou.com/G02/shangou/M02/DF/4F/CgvUBFe9ZWWAGrIwAAIQZS0wRbY838_n_w_l.jpg"
},
{
id: "d77c9628-84aa-4e51-861f-f3674d195bd3",
price: 200,
pic: "http://pc1.img.ymatou.com/G02/shangou/M02/3A/DA/CgvUBFeIBgyAJubQAASBrt5UyVc044_n_w_l.jpg"
},
{
id: "dee59eeb-d82c-4ff4-838c-c492b3d001ab",
price: 218,
pic: "http://pc1.img.ymatou.com/G02/shangou/M01/F1/F7/CgvUA1eaQR6AEQ61AAIW-fqc7Vo838_n_w_l.jpg"
},
{
id: "994f9376-8e3b-4e27-b393-d4ca05fa046a",
price: 229,
pic: "http://pc1.img.ymatou.com/G02/shangou/M0B/73/6A/CgvUBFes-HSANU0pAAPrzMLamgQ538_n_w_l.jpg"
},
{
id: "af6efa07-6853-4d6c-acfc-a3043eb24988",
price: 399,
pic: "http://pc1.img.ymatou.com/G02/shangou/M09/58/0D/CgvUBFepI7-AGrqWAAG-mCgD8Nc129_n_w_l.jpg"
},
{
id: "5a721e93-2ea9-4155-8678-f5c09e518514",
price: 369,
pic: "http://pc1.img.ymatou.com/G02/shangou/M08/B2/43/CgvUBVe2fWSAOSUaAADtD35Mn34794_n_w_l.jpg"
},
{
id: "a878b978-31c0-4284-a6de-f63aafd61312",
price: 1999,
pic: "http://pc1.img.ymatou.com/G02/shangou/M0B/D6/AF/CgvUBFe8L7SAMnTMAAG-UvVKf8U384_n_w_l.jpg"
},
{
id: "2215cbde-97a6-46d5-aea2-9440e115f251",
price: 468,
pic: "http://pc1.img.ymatou.com/G02/shangou/M02/2F/6C/CgvUA1eiylCAfjIDAAGBiNPRRUM031_n_w_l.jpg"
}
],
follow: false,
topictype: 106
},
{
id: 1000302,
theme: "Tod's:无法抗拒的经典舒适",
products: 179,
users: 30,
href: "",
list: [
{
id: "f6c50028-9211-4080-ae58-3beed3728e50",
price: 1850,
pic: "http://pc1.img.ymatou.com/G02/shangou/M02/94/32/CgvUBVeygneAchtNAAEXO9Cv9Ro827_n_w_l.jpg"
},
{
id: "49c37f83-2bdd-473c-b712-610fa642f849",
price: 1800,
pic: "http://pc1.img.ymatou.com/G02/shangou/M01/B8/15/CgvUBVe3FXeAd5MoAAGsnxuqdHA352_n_w_l.jpg"
},
{
id: "a92f93d6-2ce6-40b2-87cf-19d34cbb03d0",
price: 1250,
pic: "http://pc1.img.ymatou.com/G02/shangou/M04/09/68/CgvUBVfEHHOAB1h_AAIwSBEZVVg530_n_w_l.jpg"
},
{
id: "908cc4d0-1e9a-475b-92a5-2da58a184a52",
price: 1980,
pic: "http://pc1.img.ymatou.com/G02/shangou/M09/D4/EC/CgvUA1e75-GAVy0TAAa5CXGm6mo536_n_w_l.JPG"
},
{
id: "cd3accbc-9c8e-44e8-bee2-0fd2062e54a2",
price: 2580,
pic: "http://pc1.img.ymatou.com/G02/shangou/M04/4B/61/CgvUBVem80yAFLBhAAEUV4Hs7vs476_n_w_l.jpg"
},
{
id: "7ace0a0f-2725-4a46-af60-036cb5ccbe83",
price: 1640,
pic: "http://pc1.img.ymatou.com/G02/shangou/M09/0E/3C/CgvUBFfFK_aALbCvAAD4yZZoPCM584_n_w_l.jpg"
},
{
id: "d8c8fae1-a169-4530-864c-6ba28222d3e7",
price: 1880,
pic: "http://pc1.img.ymatou.com/G02/shangou/M05/93/F0/CgvUBVeye--AdCSgAAIxaPtS2GM400_n_w_l.jpg"
},
{
id: "c475412f-ae29-4690-b46b-c4407db8916b",
price: 1700,
pic: "http://pc1.img.ymatou.com/G02/shangou/M0A/F4/E4/CgvUBFfAWu-AZgWZAAHlwvXa_Y0542_n_w_l.jpg"
},
{
id: "f5d34f68-d566-4cf2-aa8e-142ef058fd71",
price: 1499,
pic: "http://pc1.img.ymatou.com/G02/shangou/M06/BB/29/CgvUBFe3zPqAANCxAAHr5HcZC4E398_n_w_l.jpg"
},
{
id: "cf1a8142-91f2-4b2c-bb86-61ae0ede2b73",
price: 3200,
pic: "http://pc1.img.ymatou.com/G02/shangou/M02/85/8B/CgvUBVev8Y6ACkDoAAKBE5K1Wjg827_n_w_l.jpg"
}
],
follow: false,
topictype: 106
}
]
}
}
4.梯度提升二三事:怎么来自定义损失函数?
点击上方关注,All in AI中国
作者:Prince Grover 和 Sourav Dey
介绍
梯度提升技术在工业中得到了广泛的应用,并赢得了许多Kaggle比赛。(https://github.com/Microsoft/LightGBM/blob/master/examples/README.md#machine-learning-challenge-winning-solutions)互联网已经有很多关于梯度提升的很好的解释,但我们注意到关于自定义损失函数的信息缺乏:比如原因,时间和方式。这篇文章是我们尝试总结自定义损失函数在许多实际问题中的重要性,以及如何使用LightGBM梯度提升包实现它们。
常见的ML库中有许多常用的损失函数。如果你想进一步了解这方面的知识,请阅读这篇文章,这是Prince在攻读数据科学硕士时写的。(https://heartbeat.fritz.ai/5-regression-loss-functions-all-machine-learners-should-know-4fb140e9d4b0)在现实世界中,这些"现成的"损失函数通常无法很好地适应我们试图解决的业务问题。输入自定义损失函数。
自定义损失函数
使用自定义损失函数的一个例子是机场准时的风险不对称。问题是决定何时离开家,以便在合适的时间到达机场。我们不想太早离开,在机场等几个小时。与此同时,我们更不想错过我们的航班。任何一方的损失都是非常不同的:如果我们提前到达,情况真的不是那么糟糕;如果我们来得太晚而错过航班,那真的很糟糕。如果我们使用机器学习来决定何时离开房子,我们可能希望直接在我们的模型中处理这种风险不对称,通过使用自定义损失函数来"惩罚"晚期错误而不是早期错误。
另一个常见的例子是分类问题。例如,对于疾病检测,我们可能认为假阴性比假阳性要严重得多,因为给予健康人的药物通常比未治疗病人的危害小。在这种情况下,我们可能希望优化F-beta评分,其中β取决于我们想要给予误报的权重大小。这有时被称为Neyman-Pearson标准。
在Manifold,我们最近遇到了一个需要自定义损失函数的问题。我们的客户之一Cortex Building Intelligence提供的应用程序可帮助工程师更精确地操作建筑物供暖,通风和空调(HVAC)系统。大多数商业建筑物具有"租赁义务",以在工作日期间的工作时间内将建筑物室内温度调节在"舒适"温度范围内,例如在上午9点至下午6点期间在华氏70和74度之间。与此同时,HVAC是建筑物的最大运营成本。高效HVAC运行的关键是在不需要时关闭系统,如夜间,并在清晨再次开启以满足"租赁义务"。为此,Manifold帮助Cortex建立了一个预测模型,以建议在建筑物中打开HVAC系统的确切时间。
然而,错误预测的惩罚是不对称的。如果我们预测的启动时间早于实际所需的启动时间,那么建筑物将过早地达到舒适的温度并且会浪费一些能量。但是如果预测的时间晚于实际所需的开始时间,那么建筑物的温度就会升温较晚,租户也不会感到高兴——没有人想在冰冷的建筑物中工作,购物或学习。因此,晚开比早开更糟糕,因为我们不希望租户不开心。我们通过创建自定义非对称Huber损失函数将业务知识编码到我们的模型中,当残差为正与负时,该函数具有更高的误差。有关此问题的更多详细信息,请参阅此文章。(https://www.manifold.ai/blog/data-science-at-cortex)
结论:找到一个与你的业务目标紧密匹配的损失函数。通常,这些损失函数在流行的机器学习库中没有默认的实现。没关系:定义自己的损失函数并用它来解决你的问题并不难。
自定义训练损失和验证损失
在进一步讨论之前,让我们在定义中明确一点。ML文献中使用了许多术语来指代不同的东西。我们将选择一组我们认为最清晰的定义:
·训练损失。这是在训练数据上进行优化的函数。例如,在神经网络二进制分类器中,这通常是二进制交叉熵。对于随机森林分类器,这是基尼系数。训练损失通常也称为"目标函数"。
·验证损失。这是我们用来评估我们训练模型在看不见的数据上的性能的函数。这通常与训练损失不同。例如,在分类器的情况下,这通常是接收器工作特性(ROC)曲线下的区域——尽管这从未直接优化,因为它是不可微分。这通常称为"性能或评估指标"。
在许多情况下,自定义这些损失对于构建更好的模型非常有效。这对于梯度提升特别简单,如下所示。
训练损失
在训练期间优化训练损失。很难为某些算法自定义,比如随机森林(见这里:https://github.com/scikit-learn/scikit-learn/issues/3071),但对其他算法来说比较容易,比如梯度提升和神经网络。因为梯度下降的一些变体通常是优化方法,所以训练损失通常需要一个具有凸梯度(一阶导数)和海森(二阶导数)的函数。它最好是连续的,有限的和非零的。最后一个很重要,因为函数为零的部分可以冻结梯度下降。
在梯度提升的背景下,训练损失是使用梯度下降优化的函数,例如梯度提升模型的"梯度"部分。具体地,训练损失的梯度用于改变每个连续树的目标变量。(如果你对更多细节感兴趣,请参阅此文章。https://medium.com/mlreview/gradient-boosting-from-scratch-1e317ae4587d)请注意,即使训练损失定义了"梯度",每个树仍然使用与此自定义损失函数无关的贪婪分割算法生长。
定义自定义训练损失通常需要我们做一些微积分来找到梯度和海森。正如我们接下来将要看到的,首先更改验证损失更容易一些,因为它不需要那么多的开销。
验证损失
验证损失用于调整超参数。它通常更容易自定义,因为它没有像训练损失那样多的功能要求。验证损失可以是非凸的,不可微分的和不连续的。因此,从自定义开始通常是一个更容易的地方。
例如,在LightGBM中,一个重要的超参数是boosting的数量。验证损失可用于找到最佳数量的boosting次数。 LightGBM中的验证损失称为eval_metric。我们可以使用库中可用的验证损失之一,也可以定义我们自己的自定义函数。(https://github.com/Microsoft/LightGBM/blob/master/docs/Parameters.rst/#metric-parameters)由于它非常简单,如果它对你的业务问题很重要,那么你一定要自定义。
具体而言,我们通常使用early_stopping_rounds变量,而不是直接优化num boosting的轮数。当给定数量的早期停止轮次的验证损失开始增加时,它会停止提升。实际上,它通过监视样本外验证集的验证损失来防止过度拟合。如下图所示,设置更高的停止轮次会导致模型运行更多boosting 轮次。
蓝色:训练损失。橙色:验证损失。训练和验证都使用相同的自定义损失功能
k折交叉验证。每个测试折叠都有验证损失
请记住,验证策略也非常重要。上面列出的训练/验证是许多可能的验证策略之一。它可能不适合你的问题。其他包括k-fold交叉验证和嵌套交叉验证,我们在HVAC启动时建模问题中使用了这些验证。
如果适用于业务问题,我们希望使用自定义函数来进行训练和验证损失。在某些情况下,由于自定义损失的函数形式,可能无法将其用作训练损失。在这种情况下,仅更新验证损失并使用像MSE这样的默认训练损失可能是有意义的。你仍然可以获益,因为超参数将使用所需的自定义损失进行调整。
在LightGBM中实现自定义损失功能
让我们来看看它在实践中的样子,并对模拟数据进行一些实验。首先,让我们假设过高估计比低估更糟糕。另外,假设平方损失是我们在任一方向上的误差的良好模型。为了对其进行编码,我们定义了一个自定义MSE函数,它对正残差的惩罚比负残差多10倍。下图说明了我们的自定义损失函数与标准MSE损失函数的对比情况。
根据定义,非对称MSE很好,因为它具有易于计算的梯度和海森度,如下图所示。请注意,海森在两个不同的值上是常量,左边是2,右边是20,尽管在下面的图中很难看到。
LightGBM提供了一种直接的方式来实现自定义训练和验证损失。其他梯度提升包,包括XGBoost和Catboost,也提供此选项。这是一个Jupyter笔记本(https://github.com/manifoldai/mf-eng-public/blob/master/notebooks/custom_loss_lightgbm.ipynb),展示了如何实现自定义训练和验证损失功能。细节在笔记本中,但在较高的层次上,实现略有不同:
- 训练损失:在LightGBM中自定义训练损失需要定义一个函数,该函数包含两个数组,即目标及其预测。反过来,该函数应该返回每个观察的两个梯度和海森的数组。如上所述,我们需要使用微积分来导出梯度和海森,然后在Python中实现它。
- 验证损失:自定义LightGBM中的验证损失需要定义一个函数,该函数接受相同的两个数组,但返回三个值:一个字符串,其名称为metric的字符串,损失本身,以及关于更高是否更好的布尔值。
用于在LightGBM中实现自定义损失的代码
定义自定义验证和训练损失功能
在LightGBM中结合训练和验证损失(包括Python和scikit-learn API示例)
自定义损失函数的实验
Jupyter笔记本还对默认随机森林,默认LightGBM和MSE以及LightGBM与自定义训练和验损失函数进行了深入比较。(https://github.com/manifoldai/mf-eng-public/blob/master/notebooks/custom_loss_lightgbm.ipynb)我们使用Friedman 1合成数据集,进行了8,000次训练观察,2,000次验证观察和5,000次测试观察。验证集用于查找优化验证损失的最佳超参数集。下面报告的分数在测试观察结果上进行评估,以评估我们模型的普遍性。
我们已经完成了下表中总结的一系列实验。请注意,我们关心的最重要的分数是非对称MSE,因为它明确定义了我们的不对称惩罚问题。
我们的实验和结果
让我们详细看一些比较。
随机森林→LightGBM
使用默认设置,LightGBM在此数据集上的性能优于Random Forest。随着更多树和超参数的更好组合,随机森林也可能会给出好的结果,但这不是重点。
LightGBM→LightGBM,具有自定义的训练损失
这表明我们可以使我们的模型优化我们关心的内容。默认的LightGBM正在优化MSE,因此它可以降低MSE损失(0.24 vs 0.33)。具有自定义训练损失的LightGBM优化了非对称MSE,因此对于非对称MSE(1.31 vs. 0.81)表现更好。
LightGBM→LightGBM使用MSE调整早期停止轮次
两种LightGBM模型都在优化MSE。我们看到默认的MSE分数有了很大改善,只需稍微调整一下使用早期停止轮次(MSE:0.24 vs 0.14)。因此,我们应该让模型使用早期停止超参数来确定最佳提升次数,而不是将提升次数限制为默认值(即100)。超参数优化很重要!
LightGBM使用MSE→LightGBM调整早期停止轮次,并使用自定义MSE进行早期停止调整
这两个模型的得分非常接近,没有实质性差异。这是因为验证损失仅用于决定何时停止提升。梯度是在两种情况下优化默认MSE。每个后续树为两个模型生成相同的输出。唯一的区别是具有自定义验证损失的模型在742次增强迭代时停止,而其他的则运行多次。
LightGBM使用自定义MSE→LightGBM通过自定义损失进行调整,并使用MSE进行早期停止调整
仅在不改变验证损失的情况下自定义训练损失会损害模型性能。只有自定义训练损失的模型比其他情况增加了更多轮次(1848)。如果我们仔细观察,这个模型的训练损失非常低(0.013)并且在训练集上高度过度拟合。每个梯度提升迭代都是使用训练误差作为目标变量来创建新树,但仅当验证数据的损失开始增加时,提升才会停止。当模型开始过度拟合时,验证损失通常开始增加,这是停止构建更多树的信号。在这种情况下,由于验证和训练损失彼此不一致,因此模型似乎没有"得到消息"而导致过度拟合。这个配置只是为了完整而包含在内,并不是人们在实践中应该使用的。
LightGBM具有经过调整的早期停止轮次,MSE→LightGBM训练自定义训练损失,并通过自定义验证损失调整早期停止轮次最终模型使用自定义训练和验证损失。它通过相对较少的提升迭代次数给出最佳的非对称MSE分数。损失与我们关心的一致!
让我们仔细看看残差直方图以获得更多细节。
请注意,使用LightGBM(即使使用默认的超参数),与随机森林模型相比,预测性能也有所提高。具有自定义验证损失的最终模型似乎在直方图的右侧进行更多预测,即实际值大于预测值。 这是由于不对称的自定义损失函数的缘故。使用残差的核密度图可以更好地可视化残差的右侧偏移。
LightGBM模型的预测与对称和非对称评估的比较
结论
没有哪个模型是完美无缺的,但许多商业问题并没有不平等的对待低估和过高估。有时,我们有意地希望我们的模型将错误偏向某个方向,但这具体取决于哪些错误的成本更高。因此,我们不应该限制自己使用普通ML库中的"现成"对称损失函数。
LightGBM提供了一个简单的界面,可以合并自定义训练和验证损失函数。在适当的时候,我们应该利用这个功能来做出更好的预测。但是,你不应立即跳转到使用自定义损失函数。最好采用精益的、迭代的方法,首先从像随机森林这样的简单基线模型开始。在下一次迭代中,你可以移动更复杂的模型,如LightGBM,并进行超参数优化。只有在这些基线稳定后,才有必要进行自定义验证和训练损失函数。
更多推荐读物
如果你不清楚一般梯度提升的工作原理,我建议你阅读如何解释Terence Parr的梯度提升(http://explained.ai/gradient-boosting/index.html),以及Prince从头开始的梯度提升(https://medium.com/mlreview/gradient-boosting-from-scratch-1e317ae4587d)。
关于如何在不同的GBM框架中调整超参数,有很多文章。如果你想使用其中一个软件包,可以花些时间了解要搜索的超参数范围。 LightGBM GitHub问题可以大致了解要使用的值范围。(https://github.com/Microsoft/LightGBM/issues/695) Aarshay Jainhas写了一篇关于调整XGBoost和sklearn梯度提升的博客。(https://www.analyticsvidhya.com/blog/2016/03/complete-guide-parameter-tuning-xgboost-with-codes-python/)
要了解哪种梯度提升包适合你的情况,请阅读Alvira Swalin的CatBoost vs. Light GBM vs. XGBoost(https://towardsdatascience.com/catboost-vs-light-gbm-vs-xgboost-5f93620723db),以及Pranjan Khandelwal的哪种算法取得冠军:Light GBM vs XGBOOST?。(https://www.analyticsvidhya.com/blog/2017/06/which-algorithm-takes-the-crown-light-gbm-vs-xgboost/)
相关文章推荐阅读: