2019-12-28

Partial Order

考虑partial order.

一个set是partially order的,也就是任意地,a b不一定是comparable的.
imply的就是min/max是一个undefined的问题.

那么在此基础上做的minimize/maximize就是无意义的.

因为实际上可能并不存在这么一个可比性.
cost function可能引入了一个并不存在或者说错误的关系.

比如给定a 由于cost function一般是well defined的.
所以一定会引出a
但实际的ground truth可能是c
所以,某种程度上来说regression/statistics本质上算是一种偷换概念的行为.

因为原则上来说,这是两种不同的表达式.
或者说,实际上只是,而且只能是一个近似.

如果对这个partial order做个partition,使得其subset是well defined的.
那么它可能是完全描述的么?

也不一定.

因为subset不一定是bounded的.

所以这种近似并不能做到100%的等价.

那么它的意义在哪里呢?

给定足够多的数据和足够细的partition方式.
每一个well defined subset的近似度越高,整体的近似度也就越高.

理论上来说,是有可能完全表达训练集/样本数据的.
当存在一个partition方式,使得每个子集都是well defined的话.

如果把order关系看作一个directed graph的话.
那么就可能存在一个non-well defined的三角关系,使得不能存在一个拆分方式能够保留完全的关系表述.

一个例子就是上面提到的a
所以如果单纯是为了匹配准确度的话,拆分子集分别计算可能是最intuitive的方式.
而且考虑给定cost function去estimate效果的话,拆分本身也可以做随机化取最优方式.
或者按某种搜索方式剪裁拆分复杂度.

而如果是为了generalize的话呢?

其实可能也差不多.

因为所谓generalize只不过是对于样本之外的一种外延预期.

也就是对于ground truth的可能会是怎样,应该会是怎样的一种合理假设.
基于这个假设的分布特性,通过已有的样本空间去生成模拟空间.

然后对这个模拟空间做fitting.

从这个角度看meta learning的话,也不过是经典的search和feature engineering的组合而已.

所不同的可能是feature engineering更多是一种对概率分布的估计方法.


2019-12-21

Finite Automata

昨天看星战9,隔壁一个小哥在看到凯洛伦和雷伊最终接吻的时候表现有点兴奋.

感觉挺有意思的.

这并不算一个什么很出人意料的场景.
大抵兴奋的来源在于一种长期的预设立场被最终承认的一种价值实现带来的满足感.

那么从这个角度看饭圈/CP/偶像文化的话,大概也是类似的.

一种本质上同人创作的圈子文化.
限定在一定的共同背景设定上的自发演绎.

跟所谓的原作的契合度其实并没有实际上相关性.
就是作为一种基本的创作素材.

这样的话,一些现象也就不难解释了.

因为素材本身品质的好坏其实并不是这些二次创作者的关心点.
素材的价值在于提供了一个初始的设定/人设,帮助汇集了一些共同爱好/价值取向的人汇集在一起.

本质上是一种萤火效应.
一种类似随机光亮吸引昆虫的某种触发群体本能的一个动机.

用这个解释对偶像人设的一种苛刻性刻板要求的话.
就是一种偏离设定的不满情绪.

因为从这个角度来说,人本身反而是这种群体创作形象的一种现实的re-projection.
是一种反向作为虚拟设定向现实具像化的反向投射.

就好比针对图纸设计的实际工业产出的精度要求.

于是基于此衍生的消费品的着力点就并不在于消费品的意识形态本身.
而在于受众的接受程度或者说付费点.

所以本质上来说这是一个商业对于消费者的取悦行为.

那么它跟一般的商品买卖的区别在哪里呢?
或者说存在么.

基于供需理论的市场交易是建立在撮合机制上的.
也就是给定相互独立的供给和需求关系,在名为市场的机制下,产生一种联系对应关系.

它的一个前提是需求和供给的产生是相互独立的.

而商业在于,给定未匹配的需求提供对应的供给.

所以从这个角度来说,同人消费并没有什么特别的理论上的不同.

考虑另外一种情况.

在商业贩售本身并不可以提供某些内容的情况下,由消费者二次创作出来的内容/要素.

这一点有些作品会作为一部分要素加入到原有的体系当中,当作一种甜点.
视程度的不同会对原有体系产生不同程度的倾斜和偏移.

另外一些作品则是本身因为各种各样的原因并不会或者并不便于/能够在官方体系当中加入这些要素.
但是并不排斥消费群体的二次创作.

再一些就是从根本上排斥二次创作的.

顺便地,针对二次创作的次级二次创作也可以视为稍微调整定义放到以上适用.

那么一部作品的消费成分就有两部分.
一个是原作品本身想要叙述提供的部分.
以及为二次创作部分提供素材的部分.

除了完全排斥二次创作的作品意外,其他的商业化路径无非就是两部分的比例侧重的不同.

考虑存在混合比例的情况.
在给定一个市场最大化效益函数的情况下,自然会针对两部分做不同的倾注投入.
以产生目的的投入产出.

所以从结果上来说,无非就是最广大人民根本利益的代表,或者说反应.

它的一个结果就是针对不同的效益函数作出的比例调整,以及基于此的长期自反馈带来的长久的比例成分变化.

以及基于此的连带的周边体系生态的随迁变化.

从这个角度来说,群体养成可能是某种更高阶一点的技术手段.

因为从商业角度看,依然是群体在引导商业作出变化.
而往上的,则是上层针对养成群体的参数控制和调整的一个结果.

某种程度上来说,也算一种设计精巧的finite automata.

2019-12-15

关于Profiler的一些想法

最近写个profiler,写完发觉大概有点不切实际.

开始是基于一个相对简单的想法.
因为一般debug java的一些线上问题无非就是看下哪些是hot method.
suspect之后一层一层顺着堆栈定位下去.

过程大体是相对繁琐的.

所以想着把这段稍微自动化点.
给定一个entry point,把整个execution过程的调用做个统计列出来.
免得再人工一个个去深入.

于是一个直接的想法就是做instrument.
在每个方法的调用前后加上time span,做耗时统计.

这里当时想了两种方式.
一种是在每个invoke*指令前后插入enter/leave的时间戳.
一种是在每个方法的entry/exit做这个时间戳统计.

第一种相对来说,最后生成的字节码会比较繁琐.
而且如果考虑到异常情况的化,这个time span可能还需要针对每个invoke做一个try-catch/异常处理block.

所以选择是在entry/exit插入.

从另一个角度来说的话,选择后者也实现上会相对的leap/优雅一些.

因为就是一个简单直观的rule.
而且具有相对的普适性.
即使再考虑异常情况的话,也又一个比较简洁的框架模式可以套.

比如对于一个
void target(){
// some code
}
形态的method来说.
插入之后大概就是
void target(){
Bridge.enter();
try{
// orignal
Bridge.leave();
}catch(Throwable e){
Bridge.leave();
throw e;
}
}

针对正常和异常都能相对结构简洁优雅地处理设计统计.

这里一个题外话就是Bridge的设计.

之所以叫Bridge主要是实现上用了一个小trick.

考虑到targe JVM一般是不太能够重启的,而attach的instrument agent有时候代码需要做改动.
尤其是开发时候.

所以实现上这里做了个classloader的处理.

agent在host vm里加载的时候会污染一部分host vm的classloader.
也即是agentmain部分的class会在host classloader里存在.

而如果全部agent code都是在这个classloader里的话,那么要达到代码的hot swap是不太可能的.
除非是transform自身.

于是,这里在agentmain的入口里做个简单的壳.
在agent load的时候切换切换class loader,使得每次attach的session使用自己独立的classloader.
以达到避免污染和hot reload的效果.

大致效果上类似于JSP的一些使用.

因为本质上来说,java的class实例是跟当前调用method的所属的class的classloader绑定的.
这样的话,只要创建一个目标classloader的shell class就能让后续的execution的常规class创建绑定在这个session bounded的loader里了.

在处理了这个热加在和基本的字节码处理框架之后,剩下的就是调用链条的crawl了.

直觉上来说,这也是个相对简单的过程.
因为jvm无非就几个invoke指令,scan一些method的bytecode做个筛选然后递归一下就是了.

只是实际麻烦的点就在于这几个invoke指令的语义.
尤其是invoke virtual和invoke interface.

根据jvm specification.
method resolution主要是基于class往上回溯的.
在interface和class method存在同名的情况下,class method的resolve规则相对靠前.
也就是相对的是favor的一方.

对于两者来说,给定一个invoke some_class some_method的指令.
形式上都是做一个virtual dispatch.

是运行时需要根据具体的instance类型做vtable/itable的lookup找到实际bind的method的.

也就是说,在scan到类似invoke some_class some_method的时候,并不能直接对some_class some_method做递归instrument.
因为除了some_class可能并不是concerted的情况意外,还有就是实际是一个sub class override的情形.

因此实际上要递归的对象/目标是从class/type hierarchy中upper bound为some_class的所有子类.

这样的话,就跟最初预期有了第一个意外.

当初预期做stack trace/调用链递归分析的出发点在于尽可能地只trace interested的部分.
也就是只在调用链条内的方法开销.

所以,在具体的tracing统计了,还做了个简单的per thread的stack matching.
保证被profile的方法的call stack里包含想要trace的entry method.
使得并不是所有特定方法的调用耗时都会包括进去,而是只有特定的调用栈的会被统计进来.

而如果作为upper bounded class的话,虽然形式上来说并没有打破这个约束/优化.
但是实际上的结果是会包含引入非常多的class被instrument.

一个测试方法的数据就是大概2000多个类会被触及到.

尽管理论上来说,这里是可以做一个静态分析的去除一部分的.
因为毕竟是实际上又所有被加载类的信息,加上制定了特定堆栈约束.
也就是相当于给定的一个execution state的initial parameter.

基于此做一个静态分析/执行引擎对涉及到的invoke做类型限定推导是有可能的.

只是一个是这个代价稍微有点大和复杂.

因为本质上相当于做个interpreter.

尽管如果写了之后可以进一步作为一个fuzzer的基础.

然而即使有了这个interpreter也并不难100%的限定类型.
因为存在一个动态类型是只有运行时才能确定的.

一个简单的例子就是反射.
以及一些涉及类似serviceloader加载机制的纯运行时特性.

于是,既然这种裁剪方式并没有一个相对完美的效果的话,那就不如不做筛选.
而是直接对所有class做instrument.

这样的话,实现上也更直接,不需要去做invoke scan的递归递归扫描操作.
而是直接无差别的transform,然后再在运行时再根据call stack决定需不需要做accounting.

唯一需要考虑的就是避免在做accepting的时候陷入递归.

因为做call stack check的代码也是被instrument的.
所有如果不对一些类做白名单处理的话,就直接递归了.

白名单的构建也尝试过用invoke scan的方式尽可能地构建一个小而完整的集合.
但问题依然是没办法100%保证确切的类型限定.
最终也是会指向type upper bounded的道路.

所以最终实现是用了限定java.lang和java.util将大多数jdk class排除在外.

在这个方案基础上出来的结果是第二个不预期的情况.

最初的构想是做了stack tracing之后,直接列出整个call stack的每一步的耗时.

而实际的结果是,尽管确实有了完整的call stack的每个step的耗时统计.
但问题在于涉及的method invoke太多.

一个方法trace有时候会展开成数十甚至上百的invoke method.

这个在事后其实也不难理解.

简单考虑一个method有个k个invoke,每个invoke针对m个class.
那么一级就是大概有k*m的调用统计.
再对每个k递归的话,就是理论上指数级的展开.
即使考虑其中可能会有重复的部分.

但理论上越是复杂的函数,最终的展开级数就越多.

所以这个在实际上是没有什么太大意义.

而且另外一个问题是因为是transform几乎所有class.
所以attch的time会明显地跟class数量线性相关.

更主要的是之前提到过的.
transform实际上会触发JIT的de-optimize.

针对所有class做instrument的话,基本上就是整个jvm打回warmup状态.

尽管理论上来说,会eventually JIT的.

但是从这个角度来说,基于instrument的profiler是会有一定程度的失真的.
尤其如果问题的实际不在bytecode层面,是VM本身的一些特性的话.

所以可能确实是基于perf couter和jvmti event的方案会更优雅准确一些.
至少,它们对VM的观察不会影响已有的JIT状态和实际的VM的代码层面允许逻辑.

2019-12-07

负利率

负利率也就是说央行在做积极的cash in.

反过来说就银行自身的头寸在减少.

如果要维持增长规模的 话.
那么,要么提高利率,要么加快周转速度.

提高贷款利率的话,需要借入方存在相应等级的ROI.
不然是非rational的.

考虑如果实际负债/债务水平在合理的条件下.
反过来也就是说,确实贷款利率水平存在弹性空间的前提下,进一步提高利率是合理的.

而如果负债水平已经在一个水平之上了, 高利率显然是没有什么空间的.

这是在债务人的ROI在利率水平之上的情况下.
利率水平存在一个upper bound.

那么如果ROI是irrational的呢?
也就说,实际的收益率低于贷款利率水平的情况下.
是什么动机驱动借款的产生的呢?

这里其实是一个递归过程.

把出借方置换成央行,借入方置换为银行.
那么借入方的动机就在于维持规模增长.

则在这种情况下就是一个同态的链式结构.
整个链条的稳定性取决于末端节点的rational的ROI水平.

而实际情况可能更复杂一下,不是一个简单的无环结构.
可能是一个复杂的网络图形态.

但不管怎么复杂,都存在一个单一的链状结构,使得整个链条的稳定性和风险聚焦于末端的状态.

如果末端出现一些不稳定因素的话.
比如default的话,那么网上回推就是 一系列的坏账.

加上环状结构的放大的话,可能就是一个系统性风险.

所以一个很自然的,在复杂系统下的简单防御策略就是控制债务规模.
降低违约风险.
至少是要在一个可控范围内,防止反推压力,以及阻断扩散.

这是在利率空间上维持增长的情况.

考虑提升周转率的途径.

在给定总量缩减的情况下,提高周转率也就因为着在单位时间内是可以达到 缩减前的规模的.
而理论上来说,提高周转率也总是一个逻辑上 较优的一个解.

同样地,如果周转率存在进一步上升空间的话,是没什么问题的.
因为可reduce成不同利率上限的情况.

如果周转率 不能进一步上升呢?

这里如果再细分一下.
即分为不同品质的周转率的 无法进一步提升.

那么显然地,高周转率的产品会具有优先偏好性.

也就是说,在这种情况下,短期贷款会优先于长期贷款.

intuitive的也是.
周期长意味着复合风险高.

所以在这种情况下,短期借贷会较长期更为繁荣.

而如果不是的话,要么说明短期符合利率upper bounded的情况.

或者在现有的规模下无法有效地触发短期借贷.
比如长期借款已经沉默/沉淀下来了,在短期内无法convert成较高流动性的成分.

在这种情况下就会有动机将长期负债转化为短期负债.

非单一债权人存在的情况下,一个合理且直接的做法就是想办法令自己的长期借款结算.
然后产生一个新的短期形态的债款.

这个短期借款可以是自己也可以是新的债权人.
而后者,整个系统来看的话,不过是风险所属方的转移而已.

那么对于针对自身的长期转短期的可行性呢?

长期的风险在于一是抵押品的流动性,二是偿还周期本身.

后者在债务人支付能力既定的情况下,只能是某种频繁短期债务置换方式.
即将一个长期债务等价分割为一个连续可展的短期性质的债务.
降低违约风险和反应时间.

前者的流动性问题的话也类似.
改变抵押物流动性的方式要么是变成可分割的.
要么是转变抵押物的构成方式,化整为零.

相对于分割方式需求的法律等其他因素变量更多之外.
抵押物置换拆分的方式可能更合理且现行可操作.

而对于短期借贷本身来说,因为形式上求解的过程使得周期本身是一个常量.
所以风险的分散可能在于额度.

这么一想的话,能串起来的就多了.




聊聊卡布里尼

最近看了部片叫卡布里尼,算是可能这段时间来比较有意思的一部电影. 故事也不算复杂,就是一个意大利修女去美国传教,建立慈善性质医院的故事. 某种程度上来说,也很一般的西方普世价值主旋律. 但是如果换一套叙事手法,比如共产国际的社会主义革命建立无产阶级广厦千万间的角度来看的话,也不是...