从作为预测的模型到作为概率分布的模型 (Model: From Prediction to Distribution)

作为机器学习的实践者,自己对于模型的理解就是 Predict:从一组输入信号来计算目标变量,也就是:

(1)   \begin{equation*} y = F(x_1, x_2, x_3, ... x_n) \end{equation*}

但是在机器学习的理论学习中,我常常看到教材上提到模型也描述了概率分布,并从这个角度有很多理论上的推导,比如在分类模型中,Maximum Likelihood Estimation 和 Cross Entropy 是等价的,再比如如果假定观测误差符合正态分布的话,那么Maximum Likelihood Estimation 和 Mean Square Error 在回归模型中也是等价的,等等。在我看来,如果我们已经有了m个训练数据:

(2)   \begin{equation*} \begin{split} (x_{11}, x_{12}, ... x_{1n}, y_1), \\ (x_{21}, x_{22}, ... x_{2n}, y_2), \\ ..., \\ (x_{m1}, x_{m2}, ... x_{mn}, y_m) \end{split} \end{equation*}

那么训练数据的概率分布已经可以使用计数的方法(也就是 Empirical Distribution)直接计算了,为什么还需要一个模型呢?

直到最近,我才对于这个问题有了一些更深刻的认识:所谓模型描述了概率分布,指的是在给定输入条件 x_1, x_2, ..., x_n 的情况下,模型给出预测值 y,以及确认该值是 y 的概率。也就是下面的条件概率密度函数

(3)   \begin{equation*} p(y | x_1, x_2, x_3, ..., x_n) \end{equation*}

对于分类模型,上面的描述比较好理解:假定我们有 C 个 class,那么在最后一层网络中一般有 C 个输出,经过 Softmax 归一化处理以后,我们把 (p_1, p_2, ..., p_c) 就当做当前用例属于每一类的概率,这确实是一个概率分布。只不过在实践中我们需要取出概率最大的一个作为模型的输入而已。

对于回归模型,上面的描述的意义就不是那么明显了,下面一段分析引用自 Maximum Likelihood Estimation 和 Mean Square Error

假定我们根据实验观察,得到了大量的训练数据。因为总是有不可知因素能够影响 y的最终取值,但是却没有被我们包含在 x_1, x_2, ..., x_m当中,不难想象,在这种情况下,我们会发现某些训练数据的输入信号部分是完全一样的,但是 y却不一样。同时我们的模型只能够预测一个值,这个时候模型应该预测那一个值呢?如果我们把模型看做对于目标数据的概率密度函数,那么对于和模型预测值相同的那些值,它们的条件概率是1吗?和模型预测值不同的那些值,它们的条件概率是0吗?

对于模型应该预测的值,训练数据的平均值是一个明显正确的选择。但是后面两个问题,我们不应该采用非0即1的答案。统计学指出,在上面的情况下,我们应当假定在相同的输入信号下所有的目标变量y的概率分布符合正态分布(Normal Distribution),其分布的中心就是所有目标变量的平均值,这个值也是我们的模型的预测值(Predict)。但是对于和这个预测值相同的y值,其概率并不是1,和这个预测值不同的y值,其概率也不是0,而是符合正态分布。在这个前提下,我们就可以说模型描述了给定了条件 x_1, x_2, ..., x_m, y 的概率分布:

(3) 

<p class=     \begin{equation*} p(y | x_1, x_2, ..., x_m) = \mathcal{N} (y; \overline{y}(x_1, x_2, ..., x_m, \theta), \sigma ^2) \end{equation*}

” width=”370″ height=”22″ />

上式中 \theta 表示模型的具体参数,\overline{y} 表示模型预测的具体值,\sigma^2 可以暂时先使用一个任意指定的固定数值。这样我们的模型就表示了给定了条件 x_1, x_2, ..., x_m,某个 y 出现的概率。

综上所述,模型描述的概率分布是一个条件概率,它隐含了训练模型时使用的Cost Function。

通常意义上的概率分布指的是目标变量的概率分布,也就是:

(4)   \begin{equation*} p(y) \text{over all possible} (x_1, x_2, x_3, ... x_n) \end{equation*}

如果我们有一个模型,给定一个输入X就可以计算相应的目标变量y。在所有可能的输入信号上使用模型计算一遍,我们就可以计算出目标变量y概率分布,但是这受到输入信号 X 的概率分布的直接影响。如果所有可能的输入信号是概率相等的,那么使用模型在这些输入上执行一遍就可以计算目标变量y的概率分布。如果输入信号 X 的概率分布不是均匀分布但是是已知的,我们依然可以使用其概率作为权重来计算目标变量y的概率分布。如果输入信号 X 的概率分布是未知的,那么仅靠模型就无法有效的预测目标变量的概率分布了。但是我们需要明确:输入信号 X 的概率分布是另外一个问题,这个概率分布和能够从输入X预测目标变量y的模型是完全不同的,我们建立的目标变量y的模型本身并不包含X的概率分布,它本身倒是可以描述一个条件概率分布。

大屏幕下的《帝国时代 I》

《帝国时代 I》是自己上学时候特别着迷的一款游戏,很多个周末都和朋友在机房联网打这个游戏度过。这个游戏背景题材基于历史,着眼宏大,画面逼真,兵种设计丰富全面,打起来很好玩。电脑AI 喜欢作弊但是整体战略很傻,这一点甚至得到了我们的喜爱,几个人团结起来打电脑,利用电脑的漏洞才能取胜。美中不足的是这个游戏当时最大只有 800 * 600 的分辨率,指挥大部队作战的时候,常常前队已经开出很远和敌人遭遇了,后队还在家里排队,地图移来移去真是麻烦。

因为一个偶然的原因,我发现这个游戏在2018年发行了大屏幕版本,就在 Steam 上下载了一份,发现有很多惊喜:

  • 最大支持 4k 屏幕,前面所说的问题完全不存在了。
  • 现在农民可以自动开始重新种地了,实在是太好了。
  • 最大人口提高到 250 人,战斗场面更加宏大。
  • 新版本的元素图形和老版本完全一致,特别适合我这种怀旧的老鸟。

自己又尝试了一把先造围墙迷惑敌人并从容发展,然后箭塔配合僧侣在狭窄处伏击敌人主力,最后大批投石车和战车弓箭手平推敌人基地的经典战术,大屏幕下真是爽啊。

过滤低质量的训练数据

过滤低质量的训练数据是提高训练精度的一个好办法。理论上来讲,训练用例分为正例和反例,但是在实践中这并不是非黑即白。自己现在做的 Dual Encoder,虽然图片周围的实体都可以被当作正例,但是实践中实体的标注实际上就有一个 Confidence Score,这个 Confidence Score 如果太小,那就不把它当作正例即可,这就起到了过滤部分低质量训练数据的效果。

以前的工程师用了一个模型来给训练数据打分,自己一直觉得不需要这么复杂,直接使用Confidence Score就应该很好了。这次大胆地把模型去掉,没有想到训练的效果差了很多,自己很是吃了一惊。仔细研究之下,结果发现就是因为直接使用实体的Confidence Score时,因为分数分布的缘故,比起原来用一个模型,过滤掉的低质量训练数据一下子少了很多,因此训练效果就变差了。提高Confidence Score Threshold以后问题就解决了。真好。

苹果电脑近年来的一些奇葩决定

自己在2014年左右上了苹果的贼船,刚开始觉得很好,用了这么多年下来,才发现苹果用心险恶,总是在谋求对于用户的全面控制,为了长期的稳定,尽量还是要远离苹果的产品。下面列出我自己收集的近年苹果的一些奇葩决定:

  • 两下空格变成一个句号。这是从手机搬到电脑上的一个特性,完全无用,却又默认打开,啊。
  • 出现一个 Siri,要你对它讲话。这么用电脑也实在太奇怪了。
  • Touch-bar,用了几年下来,除了调整一下音量或者屏幕亮度,就没有发现有用的时候。每次看着各种提示候选在Touch-bar上显示,真是无法理解,白白浪费电池。
  • 为了打通云端系统开始收钱,强迫登录 Apple ID,然后向云端同步一大堆无用的图片、视频。一旦默认空间快要用完,就开始积极的向你弹窗提示,快快缴费!
  • 为了能够卖出iPad,笔记本从来不带触摸屏。
  • 为了能够卖出更多的iPad,从来不支持多用户。
  • 不停的提示你需要更新系统,好向你推送更多可以收费的机会。

Setup SiteSync For WordPress

自从搞了一个不上网的笔记本,我就一直琢磨着怎么才能 Offline 写博客。期间尝试了无数的办法,包括:

  • 切换到 Jekyll:这个软件就是为Offline写博客准备的,按说应该是完美的选择,但是在实践中这是一个大坑,最后有几点让我放弃了。
    • Jekyll 的插件不够丰富,特别的,没有围棋的支持。
    • Jekyll 不支持私有的文章。
    • 最后,把所有的文章从 WordPress 迁移到 Jekyll 是个浩大的工程,我还专门试了试Jekyll自带的导入工具,结果跑出来的格式都需要手动调整,最少需要几天时间。
  • Offline Blog Write Tool:按说这个不难,但是不知道为什么,在Linux上就是没有能够用的工具。在 https://wordpress.org/support/article/weblog-client/ 上列出的工具,不是不能运行,就是长久以来没有人维护了。
  • Offline 写在Google Docs中,然后再把 Google Docs 嵌入到帖子中:这个问题就是太难看了,实在不愿意。
  • WordPress Desktop:本来我对这个报了极高的希望,折腾了很长时间,甚至还安装 JetPack 插件,最后这个软件只是通过桌面来远程操作Wordpress站点,但是还是需要上网,大失所望!
  • 还有一个比较搞笑的地方就是我的笔记本是一个Chromebook上面安装的Linux。这个Linux的奇怪地方是所有的程序中文输入法的支持都有问题:Terminal Vim 输入中文屏幕显示一塌糊涂,X-window Based Vim 干脆没有办法切换到中文输入,只有在Chrome 浏览器里输入中文还算正常,这也给了我试图建立Offline 编辑的想法当头一棒,唉。

在尝试了多种办法均失败以后,最后我看到了一个叫做 WPSiteSync 的插件,号称可以在两个站点之间同步文章。我想了想,如果按照这个办法,第一不用学习新的博客软件,第二Offline编辑的环境也和原来一样,看上去还可以,我就一咬牙,在我的笔记本上架起了完整的Wordpress (幸好上次迁移的时候写了一个攻略,正好用上),然后再安装和设置好同步插件,结果真的工作了!

这样我就可以 Offline Edit 我的博客文章了,几天以来的辛苦工作终于有了回报,很开心。

儿子教我弹会了《致爱丽丝》

《致爱丽丝》是一首经典的古典曲目,自己觉得很好听,可是从来没有想过自己试一试。在我的潜意识里,我也就弹弹流行通俗歌曲,对于古典曲目那是肯定拿不下来的,就不用浪费时间了。

儿子自己不知深浅,倒是常常对着 Youtube 上的视频练习。有一天儿子突然对我说他已经学会了这首曲子,然后要教我弹。我抱着陪他游戏一下的心情,就让他开始教我。没有想到前奏部分不是很难,我很快就学的像模像样了,儿子开始是自己背了一些指法,后来我们两个人又从网上找来曲谱打印出来认真学习,结果我花了一周时间,就把前奏学完了。以前只是想想,现在可以自己弹了,真好!

感谢本!

不用f前缀但是像fstring一样Print (fstring print without f-prefix)

Python 早期的Print语句受到 C 的直接影响,在把变量嵌入到输出的字符串时采用了占位符语法。使用这种打印语句,程序员需要在脑子里把所有的变量处理两次,一次是它们在字符串中的位置,一次是它们的具体名称。这样处理实际上比较繁琐而且容易出错的:

name = 'Bob'
age = '60'
print('%s is % years old.' % (name, age))

新的f-string 语法可以直接把变量嵌入到字符串中,算是朝正确的方向前进了一大步:

print(f'{name} is {age} years old.')

现在的问题是,我们总是要加上 f 这个恼人的前缀,特别是如果输出的消息是多行的话,每一行都要写上这个前缀,更是麻烦。我琢磨了很久,终于搞明白怎样在正常的字符串中嵌入变量名处理了,真是不错:

def Print(message):
  import inspect
  frame = inspect.stack()[1][0]
  print(message.format_map({**frame.f_globals, **frame.f_locals}))

name = 'Bob'
age = '60'
Print('{name} is {age} years old. - Print magic')

长久以来的一个心病终于解决了。

Del Valle Regional Park

感恩节期间,朋友邀请我们一家去 Del Valle Regional Park 游玩。本来以为就是一个普通的公园,没有想到深秋的湖水美极了。特别是后来两家人都在湖边扔石子玩,而我一个人沿着湖边向尽头的大坝走的时候,湖边很安静,阳光映在湖面波光粼粼却又静谧,天空高远,而山的线条也很柔和,很久没有这么心旷神怡的时候了。

大自然真是美好。

Jiggler 是个很棒的程序 (Jiggler is a Pretty Useful Application For Mac OS).

公司的电脑为了安全起见,自动锁定的时间设计的特别短。写程序的时候常常一思考,结果笔记本先自己锁定了,然后SSH连接也自动超时断开了,每次想好了主意要开始操作,结果先要手忙脚乱的解锁和重新连接,浪费不少时间。

最近静下来一个人琢磨,突然意识到,我其实可以找个程序自动的移动鼠标,防止屏保启动。一旦有了主意,上网一搜就看到了 Mac Jiggler 这个程序,还是个开源项目。装上一用,顿时觉得设计的特别贴心,思考的时候,它帮助你保持机器处于非锁定状态,如果你要主动让机器休眠,它也不会干涉你。几乎就是装上以后再也不用管了,真的节省了时间啊。