本文为笔记。

原论文:《Deep Landscape Forecasting for Real-time Bidding Advertising》
Authors: Kan Ren, Jiarui Qin, Lei Zheng, Zhengyu Yang, Weinan Zhang, Yong Yu
https://arxiv.org/abs/1905.03028
KDD2019

背景介绍

这篇文章讲的是广告竞价里,怎么预测整个价格空间。
现在的二次竞价制度,第一名的出价 = 第二名的出价+一个很小的bonus
也就是说,第二名的价格就是胜者面对的“市场价格”,超过这个市场价格,就能获胜。

举个不严谨的例子,假设第二名出价10元,第三第四第五名就更小了,不需要考虑。
你要考虑的只有竞争对手里面出价最高的那一个
那么,只要你出价高于10元,哪怕你出价是999999999999999999元,系统也会判定你胜出,然后你只需要支付10.01元。
这就是二次竞价制度。
以上为个人听完2019腾讯广告算法live的理解。

看完论文有一大堆疑问。
怀疑原文是不是笔误了,有多处符号跟我想的不太一样。
所以我按自己的理解再推一次。

一、理论部分

1.1 市场价格z

先定义market price (市场价格) 为变量z,显然z>0
于是z的概率密度函数可以定义为
p(z),z>0p(z) ,z>0p(z),z>0
为了简便起见,概率密度函数 Probability Density Function下文简称 P.D.F. (笑出声)。

于是可以推导出以出价b获胜与竞价失败的概率。

w(b)≐Pr(z<b)=∫0bp(z)dzw(b) \doteq Pr(z<b) = \int_{0}^{b} p(z)dz \qquadw(b)Pr(z<b)=0bp(z)dz
s(b)≐Pr(z≥b)=1−∫0bp(z)dzs(b) \doteq Pr(z \ge b) = 1-\int_{0}^{b} p(z)dz \qquads(b)Pr(zb)=10bp(z)dz
(公式4)

1.2 离散价格模型

整个市场价格空间中,分布着一系列的价格 b1,b2,b3,...,blb1,b2,b3,...,blb1,b2,b3,...,bl ,为了使模型更合理,我们显然可以在某一个角度,把这些价格全部看做整数,即 bl−bl−1=1b_{l}-b_{l-1} =1blbl1=1

个人补充

为什么可以看做整数?因为人类社会存在精度precision概念。
哪怕你的cpc广告出价是1块3毛每千次点击,这个1块3毛也可以转成1.03(元),转成103(分)。那么下一个出价就是104(分)。
在max精度的视角下,总可以得到一系列离散的整数。

我们人为地约定 b0=0b_{0} = 0b0=0

然后,定义离散价格区间(internal)
Vl=[bl,bl+1)V_{l} = \lbrack b_{l},b_{l+1})Vl=[bl,bl+1)

这里原文是左开右闭,我认为应该是左闭右开才符合逻辑。
因为z = b的时候,当前b就成了第二名的出价,显然b无法获胜。
你们也可以自己推一遍


那么现在我们就有了新的win和lose概率公式

给定出价bl:
w(bl)=Pr(z<bl)=∑j=0l−1(z∈Vj)w(b_{l}) = Pr(z<b_{l}) = \sum_{j=0}^{l-1} (z \in V_{j}) \qquadw(bl)=Pr(z<bl)=j=0l1(zVj)
s(bl)=Pr(z>=bl)=∑j=l∞(z∈Vj)s(b_{l}) = Pr(z>=b_{l}) = \sum_{j=l}^{\infty} (z \in V_{j}) \qquads(bl)=Pr(z>=bl)=j=l(zVj)

我们再定义,z恰好落在VlV_{l}Vl区间内的概率为
pl≐Pr(Z∈Vl)=W(bl+1)−W(bl)=[1−S(bl+1)]−[1−S(bl)]=S(bl)−S(bl+1)p_{l} \doteq Pr(Z \in V_{l}) = W(b_{l+1}) - W(b_{l}) \\ = [1-S(b_{l+1}) ] - [1-S(b_{l})] \\ =S(b_{l}) - S(b_{l+1}) plPr(ZVl)=W(bl+1)W(bl)=[1S(bl+1)][1S(bl)]=S(bl)S(bl+1)
(公式5)

于是我们的模型转化为了
给定一组数据 (x,b,z){(x,b,z)}(x,b,z) ,求概率密度函数p(z)p(z)p(z)
细一点说就是,对 ithsamlei \ th \ samleithsamle,求 P.D.F.ofzi,p(zi∣xi)P.D.F. of z^i,p(z^i | x^i)P.D.F.ofzip(zixi)

其中作为label的z对win case是可见的,对lose case是不可知的,被设为null。
因为广告竞价失败的广告主,只知道自己这个价格不行,不知道哪个价格可以。

可是我们知道,p(z)不好直接求,需要对其进行进一步的转化。

我们构造辅助变量hlh_{l}hl,约定其现实意义为,已知出价bl−1b_{l-1}bl1失败,那么出价blb_{l}bl 恰好获胜的概率。

hl=Pr(z∈Vl−1∣z≥bl−1)=Pr(z∈Vl−1)Pr(z≥bl−1)=pl−1Sbl−1h_{l} = Pr(z \in V_{l-1} | z \ge b_{l-1}) \\ = \frac {Pr(z \in V_{l-1})}{Pr(z \ge b_{l-1})} = \frac {p_{l-1}}{S_{b_{l-1}}}hl=Pr(zVl1zbl1)=Pr(zbl1)Pr(zVl1)=Sbl1pl1
(公式6)


备注

原文定义的 hl=plsbl−1h_{l} = \frac {p_{l}}{ s_{b_{l-1}}}hl=sbl1pl
可是若按照VlV_{l}Vl的空间划分和hlh_{l}hl的现实意义来看,分子的下标应该是l−1l-1l1而非lll
是我理解错了还是怎么回事?
而且从后面的代码来看,这个hlh_{l}hl不像是winning probability,倒像是lose probability?

1.3 价格空间预测

完成了上面的准备公式,下面可以正式将问题的数学建模,转换成神经网络可以操作的形式

作者引入RNN模型,因为一堆参考文献123456789都表现的挺好,而且我们的公式中可以看出来,离散价格区间有明显的序列特征。用n-1去推n正是RNN擅长的事情。

将RNN网络看成一个大的函数 fθf_{\theta}fθ,则可以将公式(6)进一步写成。

hli=Pr(z∈Vl−1∣z≥bl−1,xi;θ)=fθ(xi,bl∣rl−1)h_{l}^i = Pr( z \in V_{l-1} | z \ge b_{l-1},x^i;\theta) \\ =f_{\theta} (x^i,b_{l} | r_{l-1})hli=Pr(zVl1zbl1,xi;θ)=fθ(xi,blrl1)
公式(7)

第二步的下标为什么加一了?

解释:我们的hlh_{l}hl的现实意义是,已知出价bl−1b_{l-1}bl1失败,那么出价blb_{l}bl 恰好获胜的概率。
对应到 fθf_{\theta}fθ中,rl−1r_{l-1}rl1就是上一个RNN Cell传过来的 "bl−1b_{l-1}bl1失败了"的信息, fθf_{\theta}fθ要去计算出价blb_{l}bl 恰好获胜的概率。
所以写成了fθ(xi,bl∣rl−1)f_{\theta} (x^i,b_{l} | r_{l-1})fθ(xi,blrl1)

本文选用的RNN Cell是标准的LSTM Unit。

重点
由公式(4),(6),(7)可以推出以出价blb_{l}bl失败的概率
S(bl∣xi;θ)=Pr(z≥bl∣xi;θ)=Pr(z∉V1,z∉V2,...,z∉Vl−1∣xi;θ)=Pr(z∉V1∣xi;θ)∗Pr(z∉V2,...,z∉Vl−1∣z∉V1,xi;θ)=Pr(z∉V1∣xi;θ)∗Pr(z∉V2∣z∉V1,xi;θ)∗Pr(z∉V3,...,z∉Vl−1∣z∉V1,z∉V2,xi;θ)=Pr(z∉V1∣xi;θ)∗Pr(z∉V2∣z∉V1,xi;θ)∗Pr(z∉V3∣z∉V1,z∉V2,xi;θ)∗...∗Pr(z∉Vl−1∣z∉V1,z∉V2,...,z∉Vl−2,xi;θ)=Pr(z∉V1∣xi;θ)∗Pr(z∉V2∣z≥b2,xi;θ)∗Pr(z∉V3∣z≥b3,xi;θ)∗...∗Pr(z∉Vl−1∣z≥bl−1,xi;θ)=∏k=1l−1Pr(z∉Vk∣z≥bk,xi;θ)=∏k=1l−1[1−Pr(z∈Vk∣z≥bk,xi;θ)]=公式(6),(7)∏k=1l−1[1−hk+1i]=∏0<k<l[1−hk+1i]S(b_{l} | x^i;\theta) = Pr( z \ge b_{l} | x^i;\theta) \\ = Pr( z \notin V_{1}, z \notin V_{2},...,z \notin V_{l-1} | x^i ;\theta) \\ = Pr(z \notin V_{1} |x^i ;\theta)*Pr(z \notin V_{2},...,z \notin V_{l-1} | z \notin V_{1},x^i ;\theta ) \\ =Pr(z \notin V_{1} | x^i ;\theta)*Pr(z \notin V_{2} | z \notin V_{1},x^i;\theta)*Pr(z \notin V_{3},...,z \notin V_{l-1} | z \notin V_{1},z \notin V_{2},x^i ;\theta ) \\ = Pr(z \notin V_{1} | x^i ;\theta)*Pr(z \notin V_{2} | z \notin V_{1},x^i;\theta)*Pr(z \notin V_{3} | z \notin V_{1},z \notin V_{2}, x^i ;\theta)*...\\ *Pr(z \notin V_{l-1} | z \notin V_{1},z \notin V_{2}, ...,z \notin V_{l-2},x^i ;\theta) \\ =Pr(z \notin V_{1} | x^i ;\theta) *Pr(z \notin V_{2} | z \ge b_{2},x^i ;\theta)*Pr(z \notin V_{3} | z \ge b_{3},x^i;\theta)*...*Pr(z \notin V_{l-1} | z \ge b_{l-1},x^i;\theta)\\ =\prod_{k=1}^{l-1} Pr(z \notin V_{k} | z \ge b_{k},x^i;\theta) \\ =\prod_{k=1}^{l-1} [ 1 - Pr (z \in V_{k} | z \ge b_{k},x^i;\theta) ]\\ \xlongequal{公式(6),(7)} \prod_{k=1}^{l-1} [1-h_{k+1}^i] \\ \xlongequal{} \prod_{0<k<l}^{} [1-h_{k+1}^i]S(blxi;θ)=Pr(zblxi;θ)=Pr(z/V1,z/V2,...,z/Vl1xi;θ)=Pr(z/V1xi;θ)Pr(z/V2,...,z/Vl1z/V1,xi;θ)=Pr(z/V1xi;θ)Pr(z/V2z/V1,xi;θ)Pr(z/V3,...,z/Vl1z/V1,z/V2,xi;θ)=Pr(z/V1xi;θ)Pr(z/V2z/V1,xi;θ)Pr(z/V3z/V1,z/V2,xi;θ)...Pr(z/Vl1z/V1,z/V2,...,z/Vl2,xi;θ)=Pr(z/V1xi;θ)Pr(z/V2zb2,xi;θ)Pr(z/V3zb3,xi;θ)...Pr(z/Vl1zbl1,xi;θ)=k=1l1Pr(z/Vkzbk,xi;θ)=k=1l1[1Pr(zVkzbk,xi;θ)](6),(7)

k=1l1[1hk+1i]

0<k<l[1hk+1i]
W(bl∣xi;θ)=1−S(bl∣xi;θ)=1−∏0<k<l[1−hk+1i]W(b_{l} | x^i;\theta) = 1 - S(b_{l} | x^i;\theta) \\ = 1- \prod_{0<k<l}^{} [1-h_{k+1}^i] W(blxi;θ)=1S(blxi;θ)=10<k<l[1hk+1i]公式(8)

对公式(8)的备注

在现实生活中,市场价格不可能为0,所以我们知道z≥b1z\ge b_{1}zb1是必然事件,
Pr(z≥b1)=1Pr(z\ge b_{1})=1Pr(zb1)=1
所以公式中的推导中的第一项可以写成
Pr(z∉V1∣xi;θ)=Pr(z∉V1∣z≥b1,xi;θ)Pr(z \notin V_{1} | x^i ;\theta) = Pr(z \notin V_{1} | z\ge b_{1}, x^i ;\theta)Pr(z/V1xi;θ)=Pr(z/V1zb1,xi;θ)
所以可以合并为k=1时,连乘号里的项。

再放一次图防止忘记。

现在有了公式(8),它的价值在于,现在我们可以用RNN 网络的输出值 hlh_{l}hl 来计算测试集的某条记录的win和lose概率了。相当于是一个连接器bridge。

我们再由公式(5),(6)可知,对第i个样本而言,ziz^izi刚好落在区间Vl−1V_{l-1}Vl1的概率:
pl−1i=Pr(zi∈Vl−1∣xi;θ)=hli⋅Sbl−1i=hli∏0<k<l−1[1−hk+1i]=hli∏1<k<l[1−hki]p_{l-1}^i = Pr(z^i \in V_{l-1} | x^i;\theta) = h_{l}^i \cdot S_{b_{l-1}}^i \\ =h_{l}^i \prod_{0<k<l-1}^{} [1-h_{k+1}^i] \\ =h_{l}^i \prod_{1<k<l}^{} [1-h_{k}^i] pl1i=Pr(ziVl1xi;θ)=hliSbl1i=hli0<k<l1[1hk+1i]=hli1<k<l[1hki]
公式(9)

备注

然而看完代码你会发现这条公式并没有被用到。
能用公式(5)算plp_{l}pl,为什么要用公式(9)。
可是既然如此,你为什么要推一次公式(9)呢…
凑字数?

1.4 损失函数与目标方程

完成了RNN网络的准备部分,现在我们可以引入loss function了。

原文分为2个视角进行定义。

吐槽,C.D.F.的概念第一次出现在第5页,却在第9页才写备注,还得猜半天这什么意思

1.4.1 先从P.D.F. 概率密度函数的角度看。

我们使用negative log-likehood (负对数似然)作为loss。
显然给定一个win样本,我们就知道了市场价格为z∈Vlz \in V_{l}zVl
我们就希望网络预测的 Pr(z∈Vl∣xi;θ)→1Pr(z \in V_{l} | x^i;\theta) \to 1Pr(zVlxi;θ)1

把m个样本的Pr(z∈Vl∣xi;θ)Pr(z \in V_{l} | x^i;\theta)Pr(zVlxi;θ)全部乘起来,得到
L1=−log∏xi,zi∈DwinPr(zi∈Vl∣xi;θ)=−log∏xi,zi∈Dwinpli=公式(9)−log∏xi,zi∈Dwin{hl+1i∏1<k<l+1(1−hki)}=−∑xi,zi∈Dwin{loghl+1i+log∏1<k<l+1(1−hki)}=−∑xi,zi∈Dwin{loghl+1i+∑0<k<llog(1−hki)}L1 = -log \prod_{ x^i,z^i \in \Bbb{D}_{win}} Pr(z^i \in V_{l} | x^i;\theta) \\ = -log \prod_{ x^i,z^i \in \Bbb{D}_{win}} p_{l}^i \\ \xlongequal{公式(9)} -log \prod_{ x^i,z^i \in \Bbb{D}_{win}} \{ h_{l+1}^i \prod_{1<k<l+1}^{} (1-h_{k}^i) \} \\ = - \sum_{x^i,z^i \in \Bbb{D}_{win}} \{ log h_{l+1}^i + log \prod_{1<k<l+1} (1-h_{k}^i) \} \\ = - \sum_{x^i,z^i \in \Bbb{D}_{win}} \{ log h_{l+1}^i + \sum_{0<k<l} log(1-h_{k}^i) \} L1=logxi,ziDwinPr(ziVlxi;θ)=logxi,ziDwinpli(9)

logxi,ziDwin{hl+1i1<k<l+1(1hki)}=xi,ziDwin{loghl+1i+log1<k<l+1(1hki)}=xi,ziDwin{loghl+1i+0<k<llog(1hki)}
公式(10)

于是我们可以用RNN的输出hkih_{k}^ihki来计算L1损失,其中k表示第k个价格区间。

备注

醉了,我在看代码的时候还纳闷,怎么没出现L1啊?
原来这个作者在后面还介绍了一种metric方法,叫average negative log probability (ANLP) 。
再定睛一看,这个ANLP不就是测试集上的L1损失吗!!!
代码里也清清楚楚的写了总损失 comcost=alpha∗L2+beta∗anlpcomcost = alpha*L2+ beta *anlpcomcost=alphaL2+betaanlp
在代码里面L1也直接被作者命名为anlp了,更加证明是两者同一个东西。
那你为什么要给同一个东西标志2个名字,还煞有介事的专门开一节介绍ANLP,凑字数吗?直接说 this equals to L1 introduced above不可以吗?
不搞多重命名,就是对我们最大的善意了!

1.4.2 视角2 从C.D.F的角度看

先解释C.D.F. (corresponding winning probability),简而言之就是获胜概率。
整篇文章的公式只有2类。
第1类就是P.D.F.的,以z为主体,问 z∈Vlz \in V_{l}zVl的概率。
第2类就是C.D.F的,以bid为主体,问以出价blb_{l}bl获胜、失败的概率。
举例就去看1.3部分,里面的公式(8)属于C.D.F获胜概率,公式(9)属于P.D.F.落在某个价格区间的概率。

显然,对win case而言,我们希望
Pr(zi<bli∣xi;θ)→1Pr(z^i <b^i_{l} | x^i;\theta) \to 1 Pr(zi<blixi;θ)1
对lose case而言,我们希望
Pr(zi≥bli∣xi;θ)→1Pr(z^i \ge b_{l}^i | x^i;\theta) \to 1Pr(ziblixi;θ)1

于是可以定义:
Lwin=−log∏xi,bi∈DwinPr(zi<bli∣xi;θ)=−log∏xi,bi∈DwinW(bl∣xi;θ)=−∑xi,bi∈Dwinlog[1−∏0<k<l(1−hk+1i)]L_{win} = -log \prod_{x^i,b^i \in \Bbb{D}_{win}} Pr(z^i < b_{l}^i | x^i;\theta) \\ = - log \prod_{x^i,b^i \in \Bbb{D}_{win}} W(b_{l} | x^i;\theta) \\ = - \sum _{x^i,b^i \in \Bbb{D}_{win}} log[ 1- \prod_{0<k<l}^{} (1-h_{k+1}^i)]Lwin=logxi,biDwinPr(zi<blixi;θ)=logxi,biDwinW(blxi;θ)=xi,biDwinlog[10<k<l(1hk+1i)]

再定义:
Llos=−log∏xi,bi∈DlosePr(zi≥bli∣xi;θ)=−log∏xi,bi∈DwinS(bl∣xi;θ)=−∑xi,bi∈Dwinlog[∏0<k<l(1−hk+1i)]=−∑xi,bi∈Dwin∑0<k<llog(1−hk+1i)L_{los} = -log \prod_{x^i,b^i \in \Bbb{D}_{lose}} Pr(z^i \ge b_{l}^i | x^i;\theta) \\ = - log \prod_{x^i,b^i \in \Bbb{D}_{win}} S(b_{l} | x^i;\theta) \\ = - \sum _{x^i,b^i \in \Bbb{D}_{win}} log[ \prod_{0<k<l}^{} (1-h_{k+1}^i)] \\ = - \sum_{x^i,b^i \in \Bbb{D}_{win}} \sum_{0<k<l} log(1-h_{k+1}^i) Llos=logxi,biDlosePr(ziblixi;θ)=logxi,biDwinS(blxi;θ)=xi,biDwinlog[0<k<l(1hk+1i)]=xi,biDwin0<k<llog(1hk+1i)
公式(11)

备注

原文这里不知道是不是写错了,我觉得不应该有等号。

为了把LwinL_{win}LwinLloseL_{lose}Llose结合起来,我们引入一个记号数www,它的作用相当于二分类的指示器 (indicator )。

对第i个样本:
wi={1,if bi>zi0,otherwise bi≤ziw^i = \begin{cases} 1, &\text{if } b^i>z^i \\ 0, &\text{otherwise } b^i \le z^i \end{cases} wi={1,0,ifbi>ziotherwisebizi
于是可以推出
L2=Lwin+Llose=−log∏xi,bi∈DwinPr(zi<bli∣xi;θ)−log∏xi,bi∈DlosePr(zi≥bli∣xi;θ)=−log∏xi,bi∈DPr(zi<bli∣xi;θ)wi⋅Pr(zi≥bli∣xi;θ)1−wi=−∑xi,bi∈D{wi⋅logW(bi∣xi;θ)+(1−wi)⋅log[1−W(bi∣xi;θ)]}L_{2} = L_{win}+L_{lose} \\ = -log\prod _{x^i,b^i \in \Bbb{D}_{win}} Pr(z^i < b_{l}^i | x^i;\theta) -log \prod_{x^i,b^i \in \Bbb{D}_{lose}} Pr(z^i \ge b_{l}^i | x^i;\theta) \\ =-log\prod _{x^i,b^i \in \Bbb{D}} Pr(z^i < b_{l}^i | x^i;\theta)^{w^i} \cdot Pr(z^i \ge b_{l}^i | x^i;\theta)^{1-w^i} \\ =- \sum_{x^i,b^i \in \Bbb{D}} \{ w^i \cdot log W(b^i|x^i;\theta) + (1-w^i)\cdot log[1-W(b^i|x^i;\theta)] \}L2=Lwin+Llose=logxi,biDwinPr(zi<blixi;θ)logxi,biDlosePr(ziblixi;θ)=logxi,biDPr(zi<blixi;θ)wiPr(ziblixi;θ)1wi=xi,biD{wilogW(bixi;θ)+(1wi)log[1W(bixi;θ)]}
公式(14)

于是总的目标方程:
arg⁡min⁡θαL1+(1−α)L2\arg \min_{\theta} \alpha L_{1} + (1- \alpha ) L_{2} argθminαL1+(1α)L2

备注

然而在作者的github代码里,代价函数是这样写的
总损失 comcost=alpha∗(L2loss+0.001∗L2norm)+beta∗anlp=1.2∗(L2loss+0.001∗L2norm)+0.2∗anlpcomcost = alpha* (L2loss+ 0.001*L2norm) + beta*anlp \\ = 1.2 *(L2loss+ 0.001*L2norm) + 0.2*anlpcomcost=alpha(L2loss+0.001L2norm)+betaanlp=1.2(L2loss+0.001L2norm)+0.2anlp
跟论文里的有一定差别。
在前面L1损失那节说过了,这个anlp在作者眼里相当于前面的L1损失项(实际上并不完全一致)。
而这个L2损失项我也标明了,不仅仅是L2损失,还加了一个L2正则项。

理论部分,完毕。
事实证明,理论可以漂亮,实践还得tricky。

补充
L2就是某种意义上的交叉熵。

L1其实是一个商业领域的要求了。
回到广告业务上,我们不仅仅希望知道当前的bid,能否赢得这次auction。
我们还希望以最小的价格获胜。
那么我们希望预测出的关于z的概率密度,能在z∈Vl−1z \in V_{l-1}zVl1这个价格区间内,无限接近于1,这样才能使损失项L1接近于0。
Pr(z∈Vl−1)→1Pr(z \in V_{l-1}) \to1Pr(zVl1)1可以让我恰好用价格blb_{l}bl来获胜,这是最完美的答卷。

若在Pr(z∈Vl−1)Pr(z \in V_{l-1})Pr(zVl1)概率离1越远,我们就越有可能多付钱才能获胜,这便是L1损失的实际含义。

二.代码部分

原作者开源地址:
https://github.com/rk2900/DLF

原文这里为什么要加个点?

从/python/BASE_MODEL.py开始

batchsize=64
n_features =16
MAX_SEQ_LEN = 330
embd_dim = 32 #embedding
state_size = 128 #rnn cell
mid_feature_size = 30 #中间dense层#先把所有特征全部embd一下,然后hstack在一起,组成(64,16*32)
#input = (batchsize,n_features*embd_dim)#dense层,把(16*32)降维到(30),relu作为激活
middle_layer = tf.layers.dense(input, self.MIDDLE_FEATURE_SIZE, tf.nn.relu)  # hidden layer#现在我们得到一个dense_x =(batchsize,mid_feature_size)
#对其中第i个sample,x=(mid_feature_size)
#对应我们公式里的xi
#由于是RNN,对l个区间,需要重复l次输入,于是需要复制l次xi。
#为了平衡不同的样本的b,对应的l值不同,统一复制max_seq_len次。
x = tf.reshape(tf.tile(x, [self.MAX_SEQ_LEN]), [self.MAX_SEQ_LEN, self.MIDDLE_FEATURE_SIZE])
#再合并成input_x = (batchsize,max_seq_len,mid_feature_size)#定义LSTM网络
rnn_cell = tf.contrib.rnn.BasicLSTMCell(num_units=self.STATE_SIZE)outputs, (h_c, h_n) = tf.nn.dynamic_rnn(rnn_cell,                   # cell you have choseninput_x,                    # inputinitial_state=None,         # the initial hidden statedtype=tf.float32,           # must given if set initial_state = Nonetime_major=False,           # False: (batch, time step, input); True: (time step, batch, input)sequence_length=self.tf_rnn_len)#lstm的输出output = (batchsize,max_seq_len,state_size)
#需要变形处理,用一个全连接层降到1维,然后转成概率hl
#
new_output = tf.reshape(outputs, [self.MAX_SEQ_LEN * BATCH_SIZE, self.STATE_SIZE])
logits = tf.matmul(new_output, W) + b
#logits = (batchsize*max_seq_len,1)
preds = tf.transpose(tf.nn.sigmoid(logits, name="preds"), name="preds")[0]
#preds = (1,batchsize*max_seq_len)[0] = (batchsize*max_seq_len)#survival_rate 同 (batchsize*max_seq_len)
survival_rate = preds#batch_rnn_survival_rate = (batchsize,max_seq_len)
#对应max_seq_len个hl,l in range(max_seq_len)
batch_rnn_survival_rate = tf.reshape(survival_rate, [BATCH_SIZE, self.MAX_SEQ_LEN])#再经过2次tf.concat()
map_parameter = tf.concat()
#map_parameter
# =batchsize*cat[(batchsize,MAX_SEQ_LEN ,bid_len,market_price]
# =(batchsize,MAX_SEQ_LEN+1+1) ,这就是论文里的(x,b,z)#对前面输处进行连乘 h0*h1*......*hl, l = bid_len
#h0*h1*......*hl, l = market_len
def reduce_mul(x):bid_len = tf.cast(x[self.MAX_SEQ_LEN], dtype=tf.int32)market_len = tf.cast(x[self.MAX_SEQ_LEN + 1], dtype=tf.int32)survival_rate_last_one = tf.reduce_prod(x[0:bid_len])anlp_rate_last_one = tf.reduce_prod(x[0:market_len + 1])anlp_rate_last_two = tf.reduce_prod(x[0:market_len])ret = tf.stack([survival_rate_last_one, anlp_rate_last_one, anlp_rate_last_two])return ret#经过这步rate_result = (batchsize,3)
rate_result = tf.map_fn(reduce_mul, elems=map_parameter ,name="rate_result")#log(anlp_rate_last_two - anlp_rate_last_one+1e-20)
#猜测加上1e-20是防止两个的生存概率都降到0,log报错。
#这步要结合公式(5)来看
#得到(1,batchsize),表示每个sample的pz(z|x)
log_minus = tf.log(tf.add(tf.transpose(rate_result)[2] - tf.transpose(rate_result)[1], 1e-20))#todo debug#取平均值,再乘(-1),计算anlp (average negative log probability)
#结合公式(10)来看
anlp_node = -tf.reduce_sum(log_minus) / self.BATCH_SIZE #todo load name
anlp_node = tf.add(sanlp_node, 0, name="anlp_node")#在bid所属价格区间的生存概率,(1,batchsize)
final_survival_rate = tf.transpose(rate_result)[0]#1-s=w,就是死亡概率,(1,batchsize)
final_dead_rate = tf.subtract(tf.constant(1.0, dtype=tf.float32), self.final_survival_rate)#predict = (batchsize,2)
predict = tf.transpose(tf.stack([final_survival_rate, final_dead_rate]), name="predict")#tf_y = (batchsize,2) 标识0,1,计算交叉熵
cross_entropy = -tf.reduce_sum(self.tf_y*tf.log(tf.clip_by_value(self.predict,1e-10,1.0)))#计算所有训练变量的L2损失
tvars = tf.trainable_variables()
lossL2 = tf.add_n([ tf.nn.l2_loss(v) for v in tvars ]) * 0.001#加在一起
cost = tf.add(cross_entropy, lossL2, name = "cost")  / self.BATCH_SIZEoptimizer = tf.train.AdamOptimizer(learning_rate=self.LR, beta2=0.99)#.minimize(cost)
optimizer_anlp = tf.train.AdamOptimizer(learning_rate=self.ANLP_LR, beta2=0.99)#.minimize(cost)#梯度修剪
grads, _ = tf.clip_by_global_norm(tf.gradients(self.cost, tvars),self.GRAD_CLIP, #self.GRAD_CLIP=5.0)
self.train_op = optimizer.apply_gradients(zip(grads, tvars), name="train_op")#anlp梯度修剪
anlp_grads, _ = tf.clip_by_global_norm(tf.gradients(self.anlp_node, tvars),self.GRAD_CLIP,)
self.anlp_train_op = optimizer_anlp.apply_gradients(zip(anlp_grads, tvars), name="anlp_train_op")#这才是我们的总Loss = 0.25*cost(L2) + 0.75*anlp_cost(L1)
self.com_cost = tf.add(alpha * self.cost, beta * self.anlp_node)#同样做修剪
com_grads, _ = tf.clip_by_global_norm(tf.gradients(self.com_cost, tvars),self.GRAD_CLIP,)
self.com_train_op = optimizer.apply_gradients(zip(com_grads, tvars), name="train_op")tf.add_to_collection('train_op', self.train_op)
tf.add_to_collection('anlp_train_op', self.anlp_train_op)
tf.add_to_collection('com_train_op', self.com_train_op)#这里的逻辑是tf_y提供win和lose case的,显然我们人为在对应索引位置上的生存/死亡概率应该大于另一方。
#举例第i行,是lose case,那么tf_y[i,0]=1,tf_y[i,1]=0
#predict[i,0]应该趋向于1,大于predict[i,1]
correct_pred = tf.equal(tf.argmax(predict, 1), tf.argmax(tf_y, 1))
self.accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32), name="accuracy")#后面train部分
#要记住,对win case 可以同时计算L1+L2,所以用self.com_cost对应的self.com_train_op
#对lose case,只能算L2,没有L1,所以用sel.cost对应的self.train_op

简单自学了一下生存分析。
原论文里面说,他们也是采用了不预先估计参数分布的KM分析法。

可是不同之处在于,KM是传入一组样本,估计同一个时间序列。
而价格空间预测,是把【时间序列】替换成了【价格序列】。
把【结束事件】即【死亡】替换成了【竞价成功】。
把【生存概率函数S(t)】替换成了【失败概率函数S(b)】。
而且,对ithsamplei_{th} sampleithsample而言,组内样本数为1,而不是KM或者传统医学分析里面的传入m个样本。

但是这样,就又要求RNN的输出是conditional suvival_rate,即出价blb_{l}bl的【条件失败概率】。
可原文的前面又把hlh_{l}hl定义为 ‘just’ winning probability。
为什么是winning…? 应该是losing啊!

我认为,前面的定义都可以改一下。
实际上RNN输出的不是前面定义的hlh_{l}hl,而是 1−hl1-h_{l}1hl。(划重点啊!!!

本模型中,在blb_{l}bl失败概率S(b) 就是所谓的 生存概率
根据S(bl)S(b_{l})S(bl)的计算式,公式(8),我们知道在blb_{l}bl的生存概率,或者说失败概率S(b),可以用RNN网络的前lll个输出值 (1−h1)∗(1−h2)∗...∗(1−hl)(1-h_{1})*(1-h_{2})*...*(1-h_{l})(1h1)(1h2)...(1hl)计算得到。

有了S(bl)S(b_{l})S(bl),1减一下,就得到在blb_{l}bl的获胜概率,或者说死亡概率W(bl)W(b_{l})W(bl)。、
然后就能算交叉熵L2了。

至于L1,或者说作者眼中的anlp。
先说anlp,
简单而言就是,对某个win case来说,模型预测的ziz^izi落在区间VlV_{l}Vl上的概率的负对数值,−logPr(zi∈Vl∣xi)-logPr(z^i \in V_{l} | x ^i)logPr(ziVlxi)
其中VlV_{l}Vl是这个win case标注好的市场价格z的所属区间。
然后对群体样本求个均值即可。

乍一看anlp的定义,和我们推导的L1很像。
但L1公式里面,根本没有均值这个概念!

L1=−log∏xi,zi∈DwinPr(zi∈Vl∣xi;θ)=−∑xi,zi∈DwinlogPr(zi∈Vl∣xi;θ)L1 = -log \prod_{ x^i,z^i \in \Bbb{D}_{win}} Pr(z^i \in V_{l} | x^i;\theta) \\ = - \sum_{ x^i,z^i \in \Bbb{D}_{win}} log Pr(z^i \in V_{l} | x^i;\theta)L1=logxi,ziDwinPr(ziVlxi;θ)=xi,ziDwinlogPr(ziVlxi;θ)

这很可能又是一个笔误。

更新0524

完成了在pytorch上的复现。
果然我理解的没错,RNN的输出并非论文里的hlh_{l}hl,而是生存分析里的条件生存概率,在本论文中即指1−hl1-h_{l}1hl条件竞价失败概率

数据集采用的是作者附赠在开源代码里的的toy dataset ‘2259’。

toy dataset 是原话!

真的很toy啊,总共才8k多数据。

超参数全部抄作者的。
Adagrad, lr=0.002。
大概30个epoch开始,lose case的corss_entropy损失就0.01~0.0之间徘徊了。
对应的概率值为
exp(−0.03)=0.9704exp(-0.03) = 0.9704exp(0.03)=0.9704
exp(−0.01)=0.9900exp(-0.01) = 0.9900exp(0.01)=0.9900
结果上来说挺不错了。

不过数据集就这么小了,调参调出花来也不能上天。
等我把完整的iPinYou下载过来试一哈。

另外,我实施的时候有点问题,没有采用作者那样一次给出的batch全部是win case或者全部是lose case的方案。
所以每个batch里面都含有lose case。
这就导致仅对win case 有效的anlp指标没法用上。
还需要修改一下。

论文复现《Deep Landscape Forecasting for Real-time Bidding Advertising》相关推荐

  1. java 万年历绪论,基于FPGA的万年历设计

    基于FPGA的万年历设计(论文15000字) 摘要:万年历在人们的生活中一直扮演着重要的角色,可随着时代的发展,传统的纸质万年历已经越来越无法满足人们对于时间精确度以及便捷性的要求.随着电子科学的不断 ...

  2. 基于FPGA的FFT设计

    基于FPGA的FFT设计 1.verilog源代码还有实验报告 2.FFT的主要算法 FFT算法并不是一种新的理论算法,它只是用来计算DFT的快速算法,所以它是以DFT为基础的.本课题采用的是基-2 ...

  3. 基于 FPGA Vivado 信号发生器设计(附源工程)

    今天给大侠带来基于 FPGA Vivado 信号发生器设计,开发板实现使用的是Digilent basys 3,如有想要入手 basys 3 开发板的,可以联系牛总:18511371833.话不多说, ...

  4. 频谱仪设计基于FPGA的频谱仪设计,可以测试分析多种频率的频谱,分辨率100HZ

    频谱仪设计基于FPGA的频谱仪设计,可以测试分析多种频率的频谱,分辨率100HZ,配套资料多达100M,东西复杂 ID:982500594354361311卡哇伊2号小宝贝

  5. 基于 FPGA Vivado 示波器设计(附源工程)

    今天给大侠带来基于 FPGA Vivado 示波器设计,开发板实现使用的是Digilent basys 3,如有想要入手 basys 3 开发板的,可以联系牛总:18511371833.话不多说,上货 ...

  6. FPGA项目(12)——基于FPGA的万年历设计

    首先称述一下所实现的功能:可以显示年.月.日.时.分.秒,有闹钟设置功能,闹钟时间到时,蜂鸣器响,报警.用6位数码管进行显示,分三个显示页面,第一个页面显示年月日,第二个界面显示时分秒,第三个页面显示 ...

  7. 基于fpga的数码管动态扫描电路设计_【至简设计案例系列】基于FPGA的密码锁设计(altera版)...

    秦红凯 明德扬FPGA科教 一.项目背景概述 随着生活质量的不断提高,加强家庭防盗安全变得非常重要,但传统机械锁的构造过于简单,很容易被打开,从而降低了安全性.数字密码锁因为它的保密性很高,安全系数也 ...

  8. 【示波器】基于FPGA的数字示波器设计实现

    1.软件版本 quartusii 2.本算法理论知识 框图结构: 1.缓存里包含有触发控制和触发存储器: 2.由设计指标需要1GsPs的采样率,最后的数据流要降到到250MbPs: 3.从指标来看从波 ...

  9. 【至简设计案例系列】基于FPGA的密码锁设计(altera版)

    本文为明德扬原创及录用文章,转载请注明出处! 作者:秦红锴 一.项目背景概述 随着生活质量的不断提高,加强家庭防盗安全变得非常重要,但传统机械锁的构造过于简单,很容易被打开,从而降低了安全性.数字密码 ...

  10. android五子棋论文,基于Android五子棋的设计与实现论文.doc

    . PAGE . 总 目 录 毕业设计(论文) 指导老师评语表 评阅人评阅表 答辩记录表 答辩委员会评语表 承 诺 书 我谨此郑重承诺: 本毕业设计(论文)是本人在指导老师指导下独立撰写完成的.凡涉及 ...

最新文章

  1. 水平和垂直翻转可视对象
  2. linux系统中tar命令的使用,linux 系统的tar命令使用方法详解
  3. Zookeeper 的学习与运用
  4. 【ntp】虚拟机时间莫名异常
  5. spring项目搭建-约束引入
  6. 从零到破万节点!支撑618大促背后的蚂蚁金服Kubernetes集群
  7. 计算机更新服务,使用 Microsoft Update 更新计算机
  8. Linux -Ubuntu安装 Tomcat
  9. 关闭加速渲染_“瀑布屏”旗舰 摩托罗拉Edge+渲染图曝光,Moto G8正式发布
  10. C++结构体中有构造函数和析构函数
  11. princomp 与pca的区别与联系
  12. 误码率matlab怎么计算,Matlab 仿真(7,4)汉明码 传输误码率
  13. 零基础学python书籍-非IT行业,零基础自学Python,选什么书?
  14. 实现SharePoint的无限潜力
  15. 麻瓜编程python爬虫微专业_麻瓜编程·python实战·1-3作业:爬取租房信息
  16. BZOJ2794: [Poi2012]Cloakroom
  17. ffmpeg保存rtsp视频流为mp4文件
  18. 深度解密Mysql数据库索引
  19. Linux(Centos7)yum安装Nginx
  20. nginx1.18.0 安装vts

热门文章

  1. 你企业的物联网投资投对方向了吗?
  2. Linux那些事儿之我是SCSI硬盘(6)三座大山(三)
  3. Android 不归路之百度地图API学习(导航篇)
  4. 20号(组装台式机教程) 篇1. 概述
  5. 王喆<深度学习推荐系统实战>之推荐模型篇学习笔记
  6. 【操作系统】《2023 南京大学 “操作系统:设计与实现” (蒋炎岩)》- 知识点目录
  7. 今日安利:2款支持OFD阅读的神仙软件
  8. 高德地图行业领头,企业网盘为其发展保驾护航
  9. C++11 之auto
  10. 雷达篇(五)雷达的应用情况