2015-12-20

明镜止水

下午等考科目三的时候想到的一个问题.

给定一定的skill level k,结果的pass的score s与否应该是一个类似:
s = k*p
的关于p的一个概率关系.

也就是固有的技能熟练程度随一个分布的"随机"波动.

考虑把概率p展开为加权w的因素f的多项式看的话.
即类似:
p = w_1*f_1 + w_2*f_2 + ... = \sum w_i*f_i

则s=k*p
->
s = k*\sum w_i*f_i

这个形式好像没什么意义.

但如果换个思路写成
s = k + w_i*f_i + w_2*f_2 + ...
的话,即在给定技能水平的条件下,最终结果取决于跟其他因素的一个某种形式的和.

实际形式可能是
s = c_0(k) + c_1(w_i*f_i) + c_2(w_2*f_2) + ...
的形式.
其中c_n为某种到s的space的mapping functions.

通俗地说,就是给定技能水平的话,实际的结果收到一些f因素的影响.
也就是对分布p的波动性的某种形式的解释.

一个前提假设.
如果是绝对理性/理想的情况下,那么给定一定的k,则有一个相对于的固定的s.

现在引入c(w,f)作为对p的解释的话.
也就是说s的最终取值收到参考因素的影响/贡献.

实际的例子可能是f为紧张程度,或者环境因素.
对s的影响的形式就是比如过于紧张/环境关系造成的发挥失常/超常等的一种波动性的解释.

也就是当c(w,f)为positive的时候,对s的贡献就是正的.
换句话说,就是这个因素对技能水平的观测/评测有着积极的/超常的作用.

反之类似.

那么单从等式的角度来说,就存在一些解,使得最终的s尽可能地最大化.

即,如果能够分清因素对"发挥"这种行为是正面还是负面影响的话,就有可能使得最终的结果收益尽可能地大.

当然,这里c(w,f)可能隐含一种相互的约束.
因为s应该是一个bounded的,所以c(w,f)应该也是bounded的.
基于在这里认为c_0(k)是一个绝对中立/理性的值.

但是实际来说,在结果出来直接可能很难判定一个因素的影响是积极的还是消极的.
就像"紧张"这种因素.

它可能使得人注意力分散,也可能反过来刺激人的肾上腺素对结果造成正面的影响.

也就是说,这种描述更多地像是对一个one shot的东西做的一个事后的补充解释.
而不能在事前发现和重复利用.

类似于可以事后给出一个形如:
s = c_0(k) + c_1(w_i*f_i) + c_2(w_2*f_2) + ...
的表达式.
其中c_n都是"已知"的表示.

即可以有任意的满足
s = s' = r(k,w_1,f_1,w_2,f_2...)的函数.

即使在当时能够分辨地出能够影响结果的因素的f_n.
那么依然有着w_n的free variable.
并不能够确切地做一个确定的描述.

如果有确切的描述的话,那么就是已知w_n和k.
最大化s的问题就变成调整因素f_n的问题了.

也就是相对可控的"紧张"到什么程度能让结果较优/最优.

问题是,实际上并不能在事前得到这么一种表达方式.

换个思路.

既然假设了c_0(k)是一个常量的话.
也就是假设技能水平是固定不变的.

那么对于
s = c_0(k) + c_1(w_i*f_i) + c_2(w_2*f_2) + ...
就存在一个关于s的确定的解,

s_0 = c_0(k)

也就是说,如果不做一些诸如maximize的speculate的动作,而是遵循实际的技能水平的话.
那么是有一个确定可预知的结果的.

这个解的约束是\sum c_i(w_i,f_i) = 0.

同样的,如果从general的角度来看的话,因为无法在事前确定c(w,f)的具体形式和描述.
所以事前并不能根据实际的描述,来通过调整相应的f取得满足上面约束的解.

但同样的考虑一个特殊形式.
即所有的c(w,f) = 0的情况.

这是对于上面约束的一个特殊解.

即,如果把能够影响结果的因素的贡献都降低到0.
那么也就相当于实际上把这个影响因素移出等式/排除掉了.

世俗上来说,就是如果能把"紧张"之类的情绪等因素排除掉干扰,那么就存在对结果的一种确定性的预期.

代价则是使得结果不存在变数,也就是不存在着某种程度的投机/优化.

所谓的明镜止水.



2015-12-13

同一类人

下午看 万万想不到 的时候在想一个问题.
好像很长一段时间以来的笑点都是在一些对所谓梗的理解上.

有时候只是意识到了用某些元素,但镜头还没达到就先笑了.

而有些时候,对于一些努力制造的笑点可能却没什么反应.
即使周围的人都笑了.

这里不是想说笑点高低的问题.
而是似乎很多行为的动机只是在寻找某些熟悉的东西.

包括一些社交网络上的一些动作.
很多时候也就是一些基础元素的延伸反复变化而已.

就像蛤一样.

有些内容其实并没有什么太大的意义.
但是通过某种联想和映射使之跟某些旧有的东西产生共鸣的话,仿佛就会产生一些奇怪的作用.

比如前段时间12306的验证码.

所谓的一个脑洞,就对各个小圈子/领域的人产生了某种群体创作和参与的潮流.

如果去考虑为什么有这种流向度的话.
一方面可能是某种讽刺形式扩散.

但可能更主要的是形式上的可重复性的某种reinforcement.

无论是哪个圈子的验证码组合,其内容也并没有带来什么新的东西.
反而可能是一些该圈子所共知的一个基本常识/事实而已.

一个更通常一些的形式可能就是某些特定的回复模式,或者说管有的吐槽方式.

就像某些账号黑穆斯林产生的关于羊的回复.

或者更常规的,从 跪了 到 这是我的膝盖 之类的同义固形的回复句式的应用.

再典型一点的就是某些所谓的表情所构成的聊天记录.

尤其是表情.

考虑聊天的内容构成是存在一定的上下文连续性的.
而纯表情能构建起来并继续下去,从另一方面看就是说明这些表情构成了一定的内容描述.

换个角度,如果把"表情"考虑为某种语言的基本"单词"呢.

或者更广泛地来说.

在对外部交互的时候,选择一些固有的模式作为回应的行为.
某种形式上就是以这些"旧"的东西作为基本的语言单位,重新"遣词造句"对外部做出反应的一种类语言行为

于是这种某种圈子内的reinforcement的行为,以及某些笑点上的行为实际上就可以考虑为是基于某种"语言"的共鸣交流/反应.

某种程度上来说,就是某种特定文化背景下面的语言交流方式.
即"共同语言".

所以,实际上,所谓的"共同语言"就是对某些事物的基本的共通性的认识.
或者说带有类似的上下文的演绎方式.

在既定的context下面,通过提供有限的几个元素/"基本词汇"的话,双方就存在着一种限定范围内的,对同一事物进行相同或者类似演绎的可能.
也就是通常所说的"一致的思路"或者"相似的想法",从而完成所谓的"交流".

那么考虑,把"梗"作为基本的"词"考虑.
把表述形式不同,但同义的"梗"考虑为同义词的话.

重新审视各个圈子/领域/亚文化.

比如,
"回老家结婚"

"已经没有什么好怕的了"

再比如
"PHP是最好的语言"

又比如
"谈笑风生"
"续一秒"
等.

看到的时候可能很快地会有类似的短句或者下一句/下几句的内容.

有时候,与其说这是一种交流,不如说是一种补完.
或者说同义反复.

它并不是在讨论什么具体的内容.
而是只对一个固有的模式/模型进行填充.

就好像人听一些动物比如猫的叫声一样.

可能它确实表达了某种信息.

但是表达的形式却不一定具有固定的形式.
而只是某种模式上的相似感/区别度.

人的语气变化也类似.

不同的语气或者同一语气的不同的句子可能都是某种情绪/内容的表达.
而决定其性质的可能并不是"句子"的词汇构成.

所以,某种程度上来说,"交流"只是一种把自己"所想"/"意愿"通过某种模式replicate出去的方式/方法而已.
或者说是context的传递.

考虑眼神交流或者任何形式的交流.

把context以信息量计量量化的话,把交流时间考虑进来作为效率衡量维度.

"只要你一个眼神肯定"
这种描述的其实就是双方拥有类似context的情况下,传输过程可以以一种optimized的"压缩编码"方式进行.
从而缩短交流时间.

反过来说,沟通效率的高低就在于双方context的对等/交集情况如何.

所谓的同一类人的定义.


2015-12-08

由拉格朗日乘数想到

考虑lagrange multiplier的构造.
\mathcal{L}(X) = f(X) + \lambda*g(X)

这里一个比较有趣的地方是constraint function g作为一个余项引入.

根据g的定义,g(X) = 0.
也就是说实际上等价于
\mathcal{L}(X) = f(X)

考虑\mathcal{L}(X)的stationary points.
即满足\nabla \mathcal{L}(X) = 0的集合S.

如果s \in S且g(s) = 0的话,那么就是一个可能的solution.

这里的思路其实是通过构造一个零项保证function的mapping空间/关系不变.
但同时把问题简化为简单的stationary的解.

换个角度考虑的话,其实就是对一个现有space的某种形式的cut/prune/classify.
在保证某种特性不变的前提下,以g做出一定形式的划分.

考虑把f(X)看作是一种feature -> object的函数.
比如X是一组feature,object是一个用户标识.

也就是说假设存在一种描述,使得这个描述对某个用户唯一.
即通过feature vector可以unique地locate到某个用户.

然后考虑有一个对用户的label函数.
使得每个用户对应一个label.

重新如lagrange multiplier的形式的等式.
\mathcal{L}(X) = f(X) + \lambda_a*g_a(X) + \lambda_b*g_b(X) + ...

当X被归类为a的时候,其余的\lambda*g(X) = 0.
即此时的\mathcal{L}(X) - f(X) = \lambda_a*g_a(X) != 0.

如果令lambda都等于1的话,则形式为:
\mathcal{L}(X) = f(X) + g_a(X) + g_b(X) + ...
->
\mathcal{L}(X) = f(X) + col_sum(G*X).
G为一个dim(label)行feature列的matrix,col_sum为对列做的算数和.

那么就有可能解出一个matrix G,使得col_sum(G*X) = 0

对于一个给定的x,apply之后有col_sum(x;G) == 0 意味着什么呢?

意味如果x是在X中,且其对于label a的话,
\lambda_a*g_a(X) + \lambda_b*g_b(X) + ... == 0
->
\lambda_a*g_a(X) == 0即与label a的前提矛盾.

所以如果col_sum(x;G) == 0 的话,则表明x必定不在X中.

那么如果col_sum(x;G) != 0的话呢?

明显也不能说明x就在X中.
因为可能存在g_b(X) != 0等的情况.

如果G*X得到的vector形式V是[1,0,0,0,...]的某个维度值为1的unit vector呢?

也不能.

因为如果把G看作是X向feature space的project的话.
对于某个vector来说,project成unit vector也不足以说明就是在原来的X space.

所以,某种程度上来说,这个只是一个dim(X) -> dim(label)的某种形式的类bloom filter.

即G*X != unit vector的话,则必然不在原来的X中.











2015-12-06

授人以渔

早上看到条关于微博信息流展示算法调整的解释文章.

大致看了下,基本的思路是通过减少汇入的信息条数达到提高阅读率和互动率.
采用的手段里有个比较矛盾的是通过"时移",也就是把之前时段的内容,通过算法把评断为"用户可能在意而又错过"的"过时"微博重新编入信息流.

后面这个做法大概是为了后来人为操控某些信息,比如广告推广资源留的吧.
不过思路也不算完全自私.
毕竟,也算某种程度上的消息填谷去峰.

但是作为效果衡量的KPI选用阅读率和互动率可能就有失偏颇了.

考虑到阅读率/互动率其实是 交互数/信息流微博 数算出来的.
而调整的基本思路和策略则是减少汇入时间线的微博数.
也就是说,相当于直接调整/缩小基数.
于是,阅读率/互动率这几个KPI出现明显增长也算是自然甚至说理所当然的结果了.

所以,某种程度上来说,以这两个指标来衡量主时间线/信息流质量的话,难免缺乏些说服力.
而且,从比较量化的角度来说,要把这两者作为衡量指标的话,也还得除去基数变化带来的对结果的影响.
即,要以这个指数来证明调整确实有好的作用的话,也得把由基数变化带来的变化的影响部分去掉.

因此,至少从数据上来说,这个调整就算有效果,那么效果也不是里面提到的数字.
而是应该更低些.

那么,应该如何才能比较合适地评定一个信息流的好坏呢?

广义的高互动的内容并不一定就是用户所喜欢或者希望接受的内容.

一个例子就是最近那个猎鸟的事件.
自己的时间线上相关的内容其实不少,但考虑到对国内媒体的节操和舆论作风来说,其实没有什么悬念和值得关注的点了.
但是如果单纯时间线上其他人的互动角度来说,机械的算法可能就会认为这个可能感兴趣的内容.

出现这种bad case的原因在于,对用户的"好的内容"的定义过于局限,或者说维度过于片面.
个人的决策过程中还包含一些认知上的倾向性context.
尤其是对于,"好"/"坏"这种主观意愿性很强的东西.

即使是人本身也很难对喜好做一个准确的划分和定义.
毕竟,这是一个很动态的东西.

客观上来说,所能观测到的只是一个人对某条或者某些微博是否有交互的行为.
而这个交互行为本身是积极的还是消极的信息接受过程是未定的.

就像个转发/评论一条微博并不一定是赞同,也可能是批驳.

即使是 赞 这种设计上是积极倾向的动作,有时候也不一定就是赞同的意思.
比如赞的内容是一条转发微博,而里面可能是夹杂了两个对立观点的.

所以,有时候能做的,更多的只是一种交互意愿性的描述.

而要描述交互意愿,可用的维度就多很多了.

比如点开一个微博的转发/评论列表.
点开某条微博的昵称/头像.
点击了某条链接.
阅读长微博时滚动条的变化速率等.

基本上,所有的交互动作都是有倾向性并且可记录的.

那么,对于个人来说,有强交互意愿的内容,对于其他人来说,就也一定存在强交互意愿么?
或者进一步说,交互的概率就比其他普通信息更高么?

这个可能比较难量化.

毕竟,前面说了,这是个很主观的东西.

对于信息的接受方来说,推送过来的可能各个层面和维度的其他人的强交互意愿内容.
但可能只会对其中的某一些部分有较高的交互概率.
而如何界定这一部分的特征,就涉及到当时的立场/认知甚至于心情了.

所以,原则上来说,干涉调整个人的信息流的内容,可能是一个有作用但未必有效的方式.

实际上,早前Google+的circle/分组/list就有一个调整该circle/分组/list内的人的信息在主信息流出现频率的功能.
但基本上最后就只是看和不看的区别.
而不是看多少的区别.

毕竟分组的存在本身就已经是个人调整的结果了.

有特别想关注的自然会做一些分组方便浏览.

如果一个人的内容多数时候不感兴趣或者反感,就直接取消关注就是了.

某种程度上来说,主时间线信息流只是一个相对来说辅助性的东西.
虽然从使用角度上来说,这个是主要场景.

但如果作为一个信息消费品来说,主信息留只是一个广场集市入口.
它要保证的只是内容和来源的多样性.

立场和观点多了,自然能从转发链中吸收到新的关注点/人.


2015-12-04

反编译的一点想法

最近两天在看某券商的Android App.

当然,说看其实不太确切.
只是dex2jar然后再jd回来的混淆代码.

大概是连猜带蒙的看吧.

看的时候发现一些disassemble失败的部分,直接给的是bytecode.
还有一些是比较奇怪的代码分支层次.

前者倒是没想出什么原因.
而且也大致不算影响阅读,毕竟java bytecode其实还是比较简单可读的.

后者的原因想了想,大概是vm结构的区别了.
毕竟,dalvik是基于register,而jvm是stack base的.

register base的话,因为数量限制,加上一些优化策略,涉及到register的复用.
所以在跟源代码对译的时候,难免会出现不一致的地方.

尤其对于Java这种强类型语言来说.
ClassA和ClassB因为"生命周期"的不同可能导致复用同一个register,导致还原的时候,代码效果不是很理想.

而stack base的原则上来说就没有这个问题.
有多少个源代码级别的local variable就有多少个对应的bytecode里的variable.
所以对译起来相对简单得多.

想了下,自己实现JVM bytecode disassembler的话,好像不难.
变量,分支,签名,异常,类型都有.
大概是时间和精力/兴趣问题了.

然后想了下dalvik的情况.

如果搞定变量对应/区分的话,其他应该跟JVM的难度差不多.

考虑,在从source code到bytecode的translate过程中,对register的allocation策略.

一个naive的方式自然是算下source code级别的变量的作用域/生命周期了.
如果到某个点不再被使用,那么其所占用的register自然可以被复用.

某种程度上来说,这是个data dependency的问题.
那么大致的算法过程应该是以数据为中心展开的.

也就是基本的读写操作的序列化和拆分.

换个角度来说,就是以数据/变量为基本symbol的state machine/DAG了.

如果把某个变量v考虑为一个基本basic symbol或者symbol class.
一个赋值或者自增等操作之类的读写之后衍生一个同一symbol class的derivative symbol.
两个symbol之间做个link或者transfer标记.

那么数据之间如果有依赖的话,就是不同的symbol class之间存在link.

于是,一趟parse下来就得到一个大致的forest like的graph了.

这个graph的用处理论上来说可以做一定程度的并行编译.
如果不考虑实际的物理计算代价的话.

毕竟,每个不同symbol class的link intersect point就是实际的synchronize point.
在此之前的都算是独立数据流,可以分配到不同的CPU上执行.

当然,实际代价是另一回事.
而且真考虑的话,优化过程加上一下代价预估,也是顺手的事情.

另一个用途自然是register的allocation了.

如果不考虑dead code elimination的话,那么所有数据流应该都是会汇集到同一个点的.
不管这个点是真实的数据点(return value),还是一个pseudo/dummy.

那么,从这个角度看的话,其实这个graph就退化成tree了.

于是,重新考虑register allocation的策略.

对于基本的单层或者说双层(包含root)的tree来说,所需要的register数量就是root的children的数量.
递归推广下,对于多层的结构来说,就是整个tree structure里面,需要的register的数量就是至少是某个node的直接children的最大值local_max_children.

但实际所需的最大register数并不一定就是这个local_max_children.
因为当把这个subtree eliminate之后,实际上可用的register数为local_max_children-1,即reduce之后的结果要占一个register.

那么怎么算具体需要多少个register呢?

对于一个给定的tree,eliminate的策略应该是首先找leaf node上一层里children数最多的做prune.
因为这时候只能prune这一层的node,且这时所需的register数必然是最大children数.

于是,递归一下,reduce回root的话,实际上就算出了实际需要的register数量了.
而且,如果不关心具体数量的话,那么递归的过程实际上也就是allocation/reuse的过程了.

这个是source code到bytecode的translate过程.

但问题是如何逆向回来.

考虑到正向的过程其实类似某种变种形式的后续遍历形式.

如果正向过程中,对register的选择有固定的顺序或者选择策略的话,那么直觉上这个过程应该是可逆的.

因为每消耗一个register代表的其实是一层max children的leaf tree的elimination.
而每一个被小号的register的读就意味着一次subtree的merge/面向root的propagate.

所以理论上应该是可行的.




爽文

去看了好东西. 坦白说,多少是带着点挑刺的味道去的. 毕竟打着爱情神话和女性题材的气质,多多少少是热度为先了. 看完之后倒是有些新的想法. 某种程度上来说,现在的年轻人或者说声音就像小叶. 只要说点贴心的话就能哄好. 也是那种可以不用很努力了. 留在自己的舒适区避难所小圈子抱团就...