🎯 2021.03.04 召回-负例的艺术(wip)
type
Post
status
Published
date
Mar 4, 2021
slug
2021.03.04 召回-负例的艺术
summary
2021.03.04 召回-负例的艺术
tags
推荐
召回
样本
category
算天算地系列
icon
password
召回是负例选择的艺术,如何根据场景选择合适的召回负例,是决定召回效果的关键。目前的实践来看负例一般有以下几个选项:随机负例,真实负例,in-batch负例,级联负例。

1. 随机负例

首先一个众所周知的实践结果是只用“真实负例+正例”的效果非常差,远不如“随机负例+正例”。
为什么呢?一般认为是训练空间和预测空间的不一致导致的:能展现在用户面前的“真实负例”毕竟是少数,而召回模型面临的是超大规模的候选集,如果大部分的广告或者内容这个模型都从未见过,那显然会有泛化性能的问题。
从另一个角度来看,通过粗排和精排层层筛选展现在用户面前的内容都已经是相对优秀的内容,这部分内容相对于召回的海量候选,算得上是困难样本,两者的分布差异巨大,只用困难样本训练必然导致召回模型过拟合于困难样本,就难以泛化到全量候选中的简单样本。
召回的作用是海选,需要有比较强大的泛化能力,需要让召回模型见到各种各样的样本,因此随机样本正是起到了这样的作用。正样本与随机样本的比例需要通过实验来确定,一般来说在 1:5 到 1:10 的水平比较合适。
“随机负例”也不是真的就全候选完全随机,而且也不是一定就好用,实践中,还需要考虑很多的问题,一般来说,使用“随机负例”有以下几类问题。

1.1 模型更新速度问题

由于正例与“随机负例”的比例是固定的,因此在建模比较稀疏的目标时,由于很少有正例,也就很少会去采负例,这样模型中这个目标的更新就会非常慢。比如假设有一个点击召回只用随机负例,如果一个用户对推荐给他的内容都不满意,一直在刷,从不点击,那点击召回模型就不会更新,也不可能学到用户的这个兴趣点。为解决这个问题,还是需要适当地补充一点其他的负例,比如真实负例。

1.2 高热打压问题

负例中高热内容占比比较大,随机负例采样会导致这部分内容被打压,影响效果,需要做一些降采样的操作,这个问题在 facebook 的论文中也有提及。
 
 
基于Popularity随机选择负例
越流行的item,如果没被用户点击看过,则更可能对于该用户来说是一个真实的负例。
 

2. 真实负例

即曝光未点击样本。
只用“真实负例”,确实会导致 sample selection bias 问题,即召回 serving 时的样本空间和 training 时的样本空间不一致,解法参考上文 1. 随机负例 部分。
FB 的文章里也提到,“真实负例”无论怎么用都没有什么作用,那是否真的就得一棒子打死呢?这个也得看场景,FB 文章的场景是搜索,搜索就存在很多 doc 确实曝光了,但可能位置偏后,用户根本没注意到的问题,这种情况还存在于双列的场景,曝光未点击的样本,用户是否不喜欢,是有比较大的噪声的。而对于单列沉浸式的场景,比如抖音,这种噪声就小不少,“真实负例”的价值也就更大一些。因此,不能盲目否定,需要根据优化的场景来判断。
“真实负例”相比“随机负例”,还是 hard 不少,在某些场景,可以帮模型学到更好的排序能力。比如“真实负例”可以一定程度上解决只用“随机负例”造成的稀疏目标模型更新速度问题,参考上文 1.1 模型更新速度问题

3. in-batch 负例

一定程度解决 sample selection bias 问题
 
 
 

4. hard 负例挖掘

4.1 级联负例

级联负例是个比较大的话题,它的出现是通过缓解召回和排序不一致的问题 (这个问题还有其他解法,比如直接增加一路级联召回,扩大召回和进粗排的条数等),来提升召回的效果。
  • 为什么会有召回和排序不一致?
    • 目标导向不一致:因为召回往往是单目标建模 (最近也不断听到业内有公司开始尝试多目标召回),而排序往往是多目标建模后融合排序,因此在整个打分导向上是存在不一致的;
    • 侧重点不一致:召回模块只要能召回 top item 即可,而排序需要对 item 做准确的排序;
  • 不一致会带来什么问题?
    • 某路召回的内容不被排序模块认可,一直展示不出去,而这种信息却没有让召回模型学到,导致这一路持续在召回但一直无法得到展示;
    • 被排序认可的内容却一直得不到召回;
“级联负例”通过从粗排或者精排排序靠后的样本里进行采样作为召回的负例。什么叫靠后,怎么进行采样,采样多少样本,也都是有讲究的,具体的做法往往根据优化场景的不同而不同,且需要大量的实验进行测试。目前业界的一些做法:
  • 百度 Mobius 的做法:用上一版本的召回模型筛选出"没那么相似"的 <user,doc>对,作为额外负样本,训练下一版本召回模型。
  • FB 的做法:与百度 Mobius 的做法相似,FB 的做法是:采用上一版模型召回位置在101~500上的item 作为 hard negative (负样本还是以 easy negative 为主,文章中经验值是 easy:hard = 100:1),参考
    🎯
    2022.11.16 再读 fb embedding-based 召回的老文章
值的提一句的是,如果你是从粗排和精排靠后的样本进行采样得到“级联负例”,那么不同 rank 位置的样本,采样概率理论上需要不一样,因为 rank 位置越靠后,是真正负样本的概率就越大,所以rank 位置越靠后,采样为“级联负例”的概率应该越大,才能使得不同位置的采样的犯错概率期望一样。在具体实践中,可以对展示内容的 rank 值分段进行统计,得到不同 rank 值分段的正样本率,然后,按这个正样本率的倒数 (归一化) 对这个分段进行采样,使得每个 rank 分段采样的犯错期望是一样的。比如:
粗排“级联负例”:粗排排序 500 < rank < 1000,按 10% 概率采样(假设这个段的正例率为 90%),rank > 1000 按 90% 概率采样(假设这个段的正例率为 10%),每次请求采样 10 个作为负例;精排“级联负例”:精排排序 50 < rank < 100,按 20% 概率采样,rank > 100 按 80% 概率采样,每次请求采样 2 个作为负例。粗排“级联负例”和精排“级联负例”的比例大致和粗排/精排条数一致即可。另外,在为某一路召回增加“级联负例”时,只用增加这一路召回被采样到的“级联负例”即可,其他召回路的“级联负例”大概率不会有什么效果,毕竟那是人家的错误。
关于所谓级联召回
正样本可以选择精排的 top n,负样本可以从进入粗排的里面随机挑,并搭配一些全局随机负例等等。具体的细节和效果全看具体场景炼丹的结果。

4.2 业务 hard 负例

以 airbnb 为例
  • 增加与正样本同城的房间作为负样本,增强了正负样本在地域上的相似性,加大模型学习难度;
  • 增加“被房主拒绝”作为负样本,增强了正负样本在“匹配用户兴趣爱好”上的相似性,加大模型学习难度
 
百度的文章:Sample Optimization For Display Advertising
💰 2021.01.09 怎么算投资回报率
type
Post
status
Published
date
Jan 9, 2021
slug
2021.01.09 怎么算投资回报率
summary
2021.01.09 怎么算投资回报率
tags
算法
投资
金钱
category
算天算地系列
icon
password
 
 
一个例子:
 
一些收益率计算总结
 

 
举一个简单而极端的例子:
假设年初投入本金$1千,某一天投入资金$1百万,一天后涨了1%赚了$1万之后把这$1百万撤走了,到了年末的时候,投资的股票价格正好跌回和年初一样。这样的话,这一年中净资金流入CF为0,本金BV为$1千,而EV是$1.1万,最后计算回报率的时候如果按简单的直接把一段时间内的利润除以本金,即:
Return = (EV - BV - CF) / (BV + CF)
上面公式计算分母 (BV+CF) 是$1千,于是回报率 = 1000%。显然,这个结果没有任何意义。
由于投资期间不断有资金的流入流出,这些肯定是投资的重要一部分,因此上面这张简单计算投资回报率的方式基本上可以说是错误计算方式了。而正确的计算方式有两种:时间加权回报率 Time-Weighted Return (TWR) 和内部回报率 Internal Rate of Return (IRR),也称资金加权回报率 Money Weighted Rate of Return (MWR)。

时间加权回报率

TWR (Time-Weighted Rate of Return),把整个时间段分成一个个小的时间段,在每个小时间段内资金流入流出为0,然后再把各个简单的回报率相乘得到总的投资回报率。它的计算公式如下:
notion image
TWR 这种计算投资回报率的方式去掉了资金量大小对投资回报率的影响,便于和 benchmark(例如SP500基金)进行比较。看基金经理的业绩就比较适合看 TWR,因为基金经理旗下的资金量大小不是自己能决定的,而是投资者决定的,拿基金经理的 TWR 和 SP500 的进行比较就很有意义。

资金加权回报率

TWR 固然方便和 benchmark 进行比较,但是忽略掉资金流入流出的影响也让它有很重的缺陷。假设一年11个月收益都是正的,只有1个月的收益是负的,结果投资人很不幸就是在那回报为负的一个月加了重仓,就有可能导致这样的结果:TWR 收益是正的,但是其实这位投资者这一年却赔了不少钱。这时就要引入另一种计算方式:MWRR (Money-weighted rate of return) = IRR (Inner rate of return),这个计算方式的本质是给重仓的时间更大的权重,轻仓的时间更低的权重。
notion image
IRR 在 excel 中有对应的函数 XIRR,IRR 这种计算方式的好处是能体现出投资者择时的影响,能反应出真实的总个人得失,但是拿 IRR 和 SP500 直接比较就比较不合理了。参考:https://www.physixfan.com/twr-vs-irr/
https://www.investopedia.com/terms/m/mirr.asp

栗子们

例子 1

期数
日期
组合初值
新投入资金
组合终值
1+HPi
1
2010/1/1
0.00
1,000,000.00
1,000,000.00
2
2010/8/15
1,162,484.00
100,000.00
1,262,484.00
1.1625
期末
2011/1/1
1,192,328.00
0.00
1,192,328.00
0.9444
TWRR
1,100,000.00
ROR
8.39%
  • TWRR
    • 第一期:Return = ($1,162,484 - $1,000,000) / $1,000,000 = 16.25%
    • 第二期:Return = ($1,192,328 - ($1,162,484 + $100,000)) / ($1,162,484 + $100,000) = -5.56%
    • 所以,TWR = (1 + 16.25%) x (1 + (-5.56%)) - 1 = 9.79%
  • ROR
    • ROR = ($1,192,328 - $1,100,000) / ($1,100,000) = 8.39%

例子 2

期数
日期
组合初值
新投入资金
组合终值
1+HPi
1
2010/1/1
0.00
1,000,000.00
1,000,000.00
2
2010/8/15
1,162,484.00
-100,000.00
1,062,484.00
1.1625
期末
2011/1/1
1,003,440.00
0.00
1,003,440.00
0.9444
TWRR
900,000.00
9.79%
ROR
11.49%
  • TWRR
    • 第一期:Return = ($1,162,484 - $1,000,000) / $1,000,000 = 16.25%
    • 第二期:Return = ($1,003,440 - ($1,162,484 - $100,000)) / ($1,162,484 - $100,000) = -5.56%
    • 所以,TWR = (1 + 16.25%) x (1 + (-5.56%)) - 1 = 9.79%
  • ROR
    • ROR = ($1,003,440 - $900,000) / ($900,000) = 11.49%
上面两个例子里,两个投资者一个增加投资,一个减少投资,但他们的 TWR 都是 9.79%,这就是一个典型的例子,说明 TWR 消除了资金流入流出的影响。

基金的算法

 

另一件事

国内好像没有类似的网站,系统性的介绍了金融理财投资的基本概念和方法,感觉可以搞一个,以及做一些理财小工具之类(变现方式可以是接各种券商开户广告、普通互联网广告和卖课的广告、卖数据)
notion image