Quantcast
Channel: Free Mind
Viewing all 62 articles
Browse latest View live

Constrained Optimization and Support Vector Machines

$
0
0

之前我们一直在讨论无约束的优化问题,定义域就是整个欧氏空间,不过在实际问题中我们经常需要解决带约束的优化问题。今天我们就来对带约束的优化问题做一个初步的介绍。在这里我们仍然假设所涉及的函数都是可导的,非光滑的优化问题将留到后面的篇幅来介绍。

带约束的优化问题的一般形式是

\[ \min_{x\in X} f(x) \]

其中\(X\)是我们允许的的取值范围。一般情况下我们会要求\(X\)是一个 Convex Set,这样的情况下优化通常会容易一点,但是需要注意的是在实际问题中碰到\(X\)是 non-Convex 的情况也是非常多的,并且有些 non-Convex 的情况也有很简单的解。其中一个比较典型的例子是我们在 Principal Component Analysis (PCA) 里碰到的一个优化问题:

\[ \min_{X_r} \|X - X_r\|_F^2, \quad s.t. \text{rank}(X_r) \leq r \]

也就是要求一个矩阵\(X\)的 low-rank 近似。其中\(\|X\|_F = \sqrt{\text{Tr}(X^TX)} = \sqrt{\sum_{i,j}X_{ij}^2}\)是矩阵的 Frobenius Norm。首先这个优化问题的约束集合\(\{X_r:\text{rank}(X_r)\leq r\}\)显然是 non-Convex 的,然而我们知道该问题的解可以通过 Singular Value Decomposition (SVD) 来求得。具体来说,令\(X=U\Sigma V^T\)\(X\)的 SVD 分解,其中\(\Sigma\)是对角矩阵,其对角线上的元素称为\(X\)的奇异值 (Singular Value),而\(U\)\(V\)分别是正交矩阵,令\(\Sigma_r\)是将\(\Sigma\)对角线上的最大的\(r\)个值(奇异值)以外的元素置为零得到的矩阵,则\(X_r^*=U\Sigma_r V^T\)是该问题的最优解。并且当第\(r\)个奇异值和第\(r+1\)个奇异值不相等时,该最优解是唯一的。

这里可以简单解释一下,注意到乘以一个正交矩阵只是进行基的旋转,并不改变矩阵的 Frobenius Norm,于是我们有

\[ \begin{aligned} \|X - X_r\|_F^2 &= \|U\Sigma V^T - X_r\|_F^2 \\ &= \|U^TU\Sigma V^TV - U^TX_rV\|_F^2 \\ &= \|\Sigma - U^TX_rV\|_F^2 \end{aligned} \]

注意到\(U^TX_rV\)仍然是一个\(r\)阶矩阵,现在问题变成用一个\(r\)阶矩阵去近似一个对角矩阵,而 Frobenius Norm 又是简单的所有元素的平方和,所以保留最大的\(r\)个对角元素是最优的解。对严格的证明感兴趣的同学可以参见(Stewart, 1998)的定理 4.32 (Schmidt-Mirsky)。

总而言之这里这个例子要说明的是,虽然我们会将精力主要集中在 convex set constrained 优化问题上,但是并不代表 non-convex set constrained 优化问题在实际中不会出现或者不重要,更不代表这样的问题就是没有全局最优解或者是不能很有效地求解的。

接下来让我们再回到优化问题上,一般情况下,\(x\in X\)这个约束条件本身也是由一些函数方程和不等式来描述的,此时优化问题一般写作如下形式:

\[ \begin{aligned} \min_x \;& f(x) \\ s.t. \;& g_i(x) \leq 0, \quad i = 1,\ldots,m \\ & h_i(x) = 0, \quad i=1,\ldots,l \end{aligned} \]

\(f\)\(g_i\)是 convex 且\(h_i\)是线性函数时这是一个 convex optimization 问题——也就是说目标函数和约束集都是 convex 的。注意当\(g_i\)是 convex 的时候,sub-levelset \(\{x:g_i(x)\leq 0\}\)是一个凸集,但是\(h_i\)是 convex 的时候并不能保证\(\{x:h_i(x)=0\}\)是凸集,所以需要更强的条件,要求\(h_i\)是线性的,此时\(\{x:h_i(x)=0\}\)是一个线性子空间,显然是凸的。

作为一个具体的机器学习中的例子,让我们来考虑支持向量机 Support Vector Machines (SVM)。我在之前写过一个比较详细的支持向量机系列的介绍文章,不过这里让我们不妨来简单回顾一下。

问题的背景是有一系列数据点\(x_1,\ldots,x_N\),每个点有一个二元类别\(y_i\in\{+1,-1\}\),我们想要寻找一个超平面\(w^Tx = b\)将这两类点分开。除此之外,我们还希望 margin 最大化,也就是说让所有数据点\(\{x_i\}_{i=1}^N\)到超平面的距离最大化。注意到当\(y_i=1\)时数据点\(x_i\)到超平面\(w^Tx-b=0\)的距离为

\[ \frac{w^Tx_i - b}{\|w\|} \]

\(y_i=-1\)时距离是上式的相反数。再注意到我们可以同时对\(w\)\(b\)乘以一个正常数并不会改变超平面的位置和方向,于是我们可以直接限制\(\|w\|=1\),于是优化问题可以完整地写为

\[ \begin{aligned} \max_{w,b,\delta} \;&\delta \\ s.t. \;& w^Tx_i - b \geq \delta, \quad y_i = +1 \\ & w^Tx_i - b \leq -\delta, \quad y_i = -1 \\ & \|w\| = 1 \end{aligned} \]

这已经是一个标准的带约束优化问题了(只要把 max 通过一个负号转换成 min 即可。)。不过我们注意到\(\|w\|=1\)这个约束并不是线性的,所以并不能一下子看出来这个问题的凸性。并且这个也和我们常见的 SVM 的目标函数差别有点大,于是我们做一下变量代换,令\(\omega = w/\delta\), \(\beta = b/\delta\),则上面的问题变成

\[ \begin{aligned} \max_{\omega,\beta,\delta} \;&\delta \\ s.t. \;& \omega^Tx_i - \beta \geq 1, \quad y_i = +1 \\ & \omega^Tx_i - \beta \leq -1, \quad y_i = -1 \\ & \|\omega\| = \frac{1}{\delta} \end{aligned} \]

再做简单变化消掉变量\(\delta\),即可得到

\[ \begin{aligned} \min_{\omega,\beta} \;&\|\omega\| \\ s.t. \;& \omega^Tx_i - \beta \geq 1, \quad y_i = +1 \\ & \omega^Tx_i - \beta \leq -1, \quad y_i = -1 \end{aligned} \]

到这里我们看到了熟悉的 SVM 的目标函数了(比较简单的没有带 slack variable 的版本),并且此时所有约束都是线性的,我们可以很明显地看出这是一个凸优化问题。通常情况下为了求导方便目标函数会写成\(\|\omega\|^2\)而不是\(\|\omega\|\),显然这两者的最优解是等价的。

现在让我们回到抽象的带约束优化问题上。回忆一下,在 unconstrained 优化问题中,我们证明了目标函数的 gradient 等于零是(局部)最优解的必要条件,并由此得出了 gradient descent 算法,通过不动点迭代来寻找 gradient 的零点。但是在 constrained 优化问题中,有可能出现的情况是目标函数 gradient 等于零的点是不能达到的,也就是说在约束集之外的,此时一般最优解会在约束集的边界上取到。总而言之 gradient 的零点不再是最优解的必要条件了,接下来我们将简要介绍一下在带约束的情况下如何来刻画最优解。

为了记号上方便,我们采用向量记法\(g(x) = (g_1(x),\ldots,g_m(x))\)\(h(x) = (h_1(x), \ldots,h_l(x))\)。此时带约束优化问题写作

\[ \begin{aligned} \min_x \;& f(x) \\ s.t. \;& g(x) \preceq 0 \\ & h(x) = 0 \end{aligned} \]

注意这里的讨论中我们并没有要求这是一个 convex 优化问题,但是为了简单起见,我们假设\(h(x)\)是线性约束,但是即使\(h(x)\)是非线性的,结论也会在给\(h(x)\)的 gradient 满足一定条件的时候成立,只是论证的过程需要使用隐函数定理之类的工具来进行局部讨论,有点繁琐。于是我们索性将问题写作

\[ \begin{aligned} \min_x \;& f(x) \\ s.t. \;& g(x) \preceq 0 \\ & Ax - b = 0 \end{aligned} \]

1
图 1

接下来我们考虑一个比较直观的几何条件。假设我们在一个 feasible point \(\bar{x}\),如果想要移动到一个更优的点,那么首先我们肯定希望向着 descent 方向移动;另一方面,我们希望移动的方向不会使得我们跑到 feasible region 外面去。

1

定理 1(Geometric First-order Necessary Conditions). 令\(F_0 = \{d\neq 0: \nabla f(\bar{x})^T d < 0\}\)为 descent 方向的集合,\(I\)表示当前所有 active 的不等式 constraints 的下标集合:\(I=\{i:g_i(\bar{x})=0\}\),而\(G_0=\{d\neq 0: \nabla g_i(\bar{x})^T d < 0, \forall i\in I\}\)是所有当前 active 的不等式 constraints 的 descent 方向的交集,\(H_0=\{d\neq 0: Ad = 0\}\)是保持 equality constraints 继续满足的方向集合。

\(\bar{x}\)是局部最优解的必要条件是\(F_0\cap G_0 \cap H_0 = \emptyset\)

该定理其实就是把我们刚才的 intuition 用数学语言陈述了一下。证明也非常简单,如果交集非空的话,我们任取交集中的一个方向\(d\),只要往该方向移动足够小的距离,可以保证同时减小目标函数的值并维持 feasible 状态,于是\(\bar{x}\)就不可能是局部最优解了。不过这个几何角度的定理虽然直观,但是却不怎么有用,接下来我们把这里的必要条件转化为可以具体运算的代数描述。

2
图 2

为此我们需要一些凸分析方面的工具,所以这里暂时“离题”介绍一些结论,因为可能以后也会用到这些结论,所以这里明确地给出来。

1

性质 1. 设\(S\subset\mathbb{R}^n\)是一个非空闭凸集,\(y\not\in S\),则

\[ \min_{x\in S} \|x-y\| \]

存在唯一解\(x^*\)。且\(x^*\)是最优解的充要条件是

\[ (y-x^*)^T(x-x^*) \leq 0, \quad\forall x\in S \]

从图(fig: 2)中来看这个结论所说的事情还是比较容易直观地记住的,证明并不复杂,我们就不在这里详细给出了。通过这个结论我们可以得出一系列的关于凸集的 separating hyperplane 的定理,根据凸集的开闭性、紧致性以及是凸集与点之间还是两个凸集之间会有各种不同的结论和变种。下面介绍一个我们马上会用到的版本。

2

定理 2(Strong Separation). 设\(S\subset \mathbb{R}^n\)是一个非空闭凸集,且\(y\not\in S\),则存在超平面\(w^Tx-b=0\)以及\(\epsilon > 0\),使得\(w^Ty-b \geq \epsilon\)且对任意\(x\in S\)\(w^Tx-b \leq -\epsilon\)。此时我们称超平面 strongly separate 凸集\(S\)和点\(y\)

利用前面的命题中得到的结论,令\(x^*\)\(y\)\(S\)的投影,则容易验证实际上\((y-x^*)^Tx - (y-x^*)^Tx^* - \epsilon = 0\)\(\epsilon \leq 0.5\|y-x^*\|^2\)时,就是满足条件的 separating hyper plane。

3

定理 3(Farkas’ Lemma). 设\(A\in\mathbb{R}^{m\times n}\)\(c\in \mathbb{R}^n\),则下面的两个线性系统中一定有且只有一个存在解:

  1. \(Ax\preceq 0\), \(c^Tx > 0\)
  2. \(A^Ty = c\), \(y\geq 0\)

这个定理初看有些莫名其妙,简单解释一下。考虑\(A\)的行所对应的向量\(A_1,\ldots,A_m\),第一条有解说的是存在一个向量\(x\),与所有的\(A_1,\ldots,A_m\)成钝角(非锐角),而和\(c\)成锐角。而该向量以法向量实际上定义了一个超平面将\(A\)的行向量与\(c\)分开。

第二条有解说的是存在一个非负权重,使得\(c\)\(A_1,\ldots,A_m\)的加权平均。换句话说,\(c\in \text{cone}(A_1,\ldots,A_m)\)

这样从几何的角度来解释之后 Farkas’ Lemma 其实还是挺直观的,实际上我们正是要用 Farkas’ Lemma 将代数和几何联系起来。我们这里省略证明,主要的麻烦的地方在于要证明一个构造出来的凸集是闭的,之后直接运用上面的 strong separation 结论就可以证明了。具体可以参见(Bertsekas, 1999)的附录 B.3 的内容。

4

定理 4(Fritz John Necessary Conditions). 设\(\bar{x}\)是局部最优解,则存在\(u_0\), \(u\)\(v\),使得

\[ \begin{aligned} &u_0\nabla f(\bar{x}) + \nabla g(\bar{x})^T u + A^Tv = 0 \\ &\quad u_0,u\geq 0, (u_0,u,v)\neq 0 \\ &\quad u_ig_i(\bar{x}) = 0, i=1,\ldots, m \end{aligned} \]

根据(thm: 1)\(F_0\cap G_0 \cap H_0=\emptyset\),也就是说,不存在\(d\)使得

\[ \begin{aligned} &\nabla f(\bar{x})^T d < 0 \\ &\nabla g_i(\bar{x})^T d < 0, \quad i\in I\\ &Ad = 0 \end{aligned} \]

\(\nabla g_I(\bar{x})=(\nabla g_i(\bar{x}))_{i\in I}\),以及

\[ B = \begin{bmatrix}\nabla f(\bar{x})^T \\ \nabla g_I(\bar{x})^T\end{bmatrix} \]

则如下 system 无解

\[ \begin{aligned} Bx + e\theta &\preceq 0, \quad \theta > 0 \\ Ax &\preceq 0\\ -Ax &\preceq 0 \end{aligned} \]

变换一下形式

\[ \begin{bmatrix} B & e \\ A & 0 \\ -A & 0\end{bmatrix}\begin{bmatrix}x \\ \theta \end{bmatrix} \preceq 0,\quad \begin{bmatrix} 0 \\ 1 \end{bmatrix}^T \begin{bmatrix}x \\ \theta \end{bmatrix} > 0 \]

于是根据刚才的 Farkas’ Lemma,我们知道存在\(y=(u_0,u_I,v^+, v^-)\succeq 0\)使得

\[ \begin{aligned} u_0\nabla f(\bar{x}) + \nabla g_I(\bar{x})^Tu_I + A(v^+-v^-) &= 0 \\ u_0 + e^Tu &= 1 \end{aligned} \]

\(v=v^+-v^-\),且定义\(u\)使得 active set \(I\)以外的元素为零,即证。

不过 Frtiz John 条件在\(\nabla f(\bar{x})\)前面有一个系数\(u_0\)比较讨厌,如果\(u_0>0\)的话,我们可以在等式两边同时除以\(u_0\),得到

\[ -\nabla f(\bar{x}) = \nabla g(\bar{x})^T u/u_0 + A^T v/u_0 \]

此时可以理解成目标函数的 gradient 向量的相反方向由 constraints 的 gradient 线性张成,并且考虑不等式 constraints 的话,由于\(u\geq 0\),所以还是在张成的 cone 中的。并且这种形式也是我们平常经常看到的 Lagrangian 的 gradient 等于零的形式。

为了做到这一点,注意到 Fritz John 条件里已经有了\(u_0\geq 0\),所以再只要排除\(u_0=0\)这种情况就可以了。当\(u_0=0\)时,我们可以得到:

\[ \nabla g(\bar{x})^T u + A^Tv = 0, \quad (u,v) \neq 0 \]

也就是说等式和不等式的 constraints 的 gradient 是线性相关的。因此如果我们能保证它们线性无关的话,就可以排除这种情况。于是有如下结论。

5

定理 5(Karush-Kuhn-Tucker (KKT) Necessary Conditions). 设\(\bar{x}\)是局部最优解,如果\(\nabla g_i(\bar{x}), i\in I\)\(A\)的行所对应的向量是线性无关的,则存在\(u,v\)使得

\[ \begin{aligned} \nabla f(\bar{x}) + \nabla g(\bar{x})^T u + A^Tv &= 0 \\ u &\succeq 0 \\ u_i g_i(\bar{x}) &= 0, \quad i = 1, \ldots, m \end{aligned} \]

这就是我们常见的 KKT 条件,成立的条件是\(\bar{x}\)是局部最优解并且“线性无关”,这里的“线性无关”也可以换成其他条件,通常称为 constraint qualification。除了刚才的定理之外,这里再列举两个比较常用的 constraint qualification。

6

定理 6(Slater Condition). 如果\(g_i(x)\)是 convex,且\(A\)的行线性无关,并且优化问题存在 Slater point,亦即存在一个 feasible 点\(x\)使得所有的不等式 constraints 严格满足:\(g_i(x)<0\)。那么 KKT 条件是局部最优解的必要条件。

7

定理 7(Linear Constraints). 如果所有 constraints 都是线性的,那么 KKT 条件是局部最优解的必要条件。

注意以上两个结论中都并没有要求目标函数\(f(x)\)是 convex 或者是 linear 的。但是如果\(f(x)\)\(g_i(x)\)全都是 convex 的话,KKT 同时也是充分条件。

8

定理 8(KKT Sufficient Conditions for Convex Problems). 设\(\bar{x}\)是一个 feasible point,如果存在\(u,v\)使得 KKT 条件满足,亦即\[ \begin{aligned} \nabla f(\bar{x}) + \nabla g(\bar{x})^T u + A^Tv &= 0 \\ u &\succeq 0 \\ u_i g_i(\bar{x}) &= 0, \quad i = 1, \ldots, m \end{aligned} \]如果\(f(x)\)\(g_i(x), i=1,\ldots,m\)是 convex 的,那么\(\bar{x}\)是该问题的全局最优解。

到这里为止几乎未加证明地介绍了许多结论了,让我们简单地带入 SVM 的问题中小结一下结束本篇文章。这里我们再对 SVM 问题做一些简单的变换,一个是用\(1/2\|\omega\|^2\)代替\(\|\omega\|\),再就是将所有不等式 constraints 写成统一形式:

\[ \begin{aligned} \min_{\omega, \beta} \;&\frac{1}{2}\|\omega\|^2 \\ s.t. \;& y_i(\omega^Tx_i - \beta) \geq 1, \quad i = 1,\ldots, N \end{aligned} \]

首先该问题显然是 convex 的,因此 KKT 条件是充分条件。然后 Slater point 的存在性其实就是看数据是否严格线性可分(注意到 SVM 的 constraints 全都是线性的,所以我们也可以利用 linear constraints 那个结论,不需要 Slater point 点存在性也可以得到 KKT 条件的必要性。),也就是说是否存在一个超平面\(\omega^Tx-\beta =0\)将两类数据严格分开:\(y_i(\omega^Tx_i-\beta) > 1\)。如果 Slater point 存在的话,那么 KKT 条件会是刻画该问题的全局最优解的充分必要条件:

\[ \begin{aligned} \omega - \sum_{i=1}^N u_i y_ix_i &= 0 \\ u_i &\geq 0, \quad i=1,\ldots, N \\ u_i \left( 1 - y_i(\omega^Tx_i-\beta) \right) &= 0, \quad i = 1,\ldots, N \end{aligned} \]

如果将\(u_i\)SVM 的 dual 推导里的 dual 变量联系起来的话,其中第一条实际上是给出了关于结果的 separating hyperplane 的法向量\(\omega\)的一个显式表达式,可以看到对于任意需要分类的点\(\tilde{x}\),有

\[ \omega^T\tilde{x} - \beta = \sum_{i=1}^N u_iy_i\langle x_i, \tilde{x}\rangle - \beta \]

只涉及到\(x_i\)\(\tilde{x}\)之间的内积运算,因此可以使用 kernel tricks。然后\(u_i\geq 0\)是每一个 training data point \(x_i\)的权重,注意第三个式子(称为 complememtary slackness),如果\(x_i\)不在 separating hyperplane 的 margin 上,也就是\(y_i(\omega^Tx_i-\beta) > 1\)的话,为了让 complememtary slackness 成立,对应的\(u_i\)必须为零。也就是说不在 margin 上的数据点,在最后进行分类的时候其对应的权重\(u_i=0\),也就是说只有 margin 上的数据点(称为 supporting vectors)才会起到作用,这也是 SVM 名字的由来。

最后小结一下,优化问题的最优解的充分条件和必要条件各自有什么用处。我们目前还没有涉及到任何实际的求解算法,但是必要条件一般可以用来寻找可能的最优解,因为最优解如果存在的话,一定会满足必要条件,因此一个比较暴力的办法就是直接枚举所有符合必要条件的解寻找最优的那一个。有些问题可以比较直接地解出满足必要条件的点,而令一些问题可能需要更多地步骤,例如在之前介绍的 unconstrained 优化问题中就是通过不动点迭代去寻找对应的必要条件(目标函数的 gradient 等于零)的点。而反过来,充分条件则有时候不是想象中的那么有用:如果你刚巧拿到了一个解并且这个解刚巧满足了充分条件的话,那么就皆大欢喜了:恭喜你找到了最优解。但是如果不满足充分条件的话,就说不清楚了,它既有可能是最优解也有可能不是。

References

  • Bertsekas, D. P. (1999). Nonlinear programming. Athena Scientific.
  • Stewart, G. W. (1998). Matrix Algorithms: Volume 1, Basic Decompositions. Society for Industrial and Applied Mathematics.

京都书店印象

$
0
0

中午吃饭的时候路过京大北门的吉冈旧书店无意中找到这样一张京都古书店的分布地图,很是喜欢。他们似乎很喜欢画各种手绘地图,去各种 guest house 下榻的话,好像也会有各自自家制作的手绘地图的复制版本发放。各个比较大的景区门口的全景地图通常也是漂亮的水墨风格的手绘。

想起来去杭州求学的时候,刚到那个城市就被夏天的热浪给震惊了,但是无意中看到一张报纸上说杭城的书店正在联合打折之类的,还把各大书店的大致方位在一个简易地图上标出来,我就拿着那个开始了我的首次杭城探索,把各大书店逛了一遍。当然后来也还时不时会去,开心的时候也好,失落的时候也好。

所以到京都来之后,也没有少去光顾各种书店,虽然大概不会按照这张地图上的标示把所有的二手书店也都一个一个逛下来了(笑)。

最初准备好好探索一番的时候碰到的问题就是不知道应该去哪里好。Google Map 上虽然可以搜索书店,但是只是列出一些位置而已,信息很少,因为我最先想去的是那种很大的书城,毕竟如果专程大老远跑过去结果发现是一间小屋,就有点太不划算的感觉。:P后来在京都车站附近找到几家规模挺大的书店,某些方面和国内的书店并无差别:比如会有挺多学生用的参考书。但是国内的书店大概绝对不会看到半数以上被漫画和文库本的小说占据的场景吧!当然,如果你觉得到了漫画的天堂,大概多少是要失望的:

因为几乎所有的书店里的漫画都是用塑料纸包装起来的,也就是不能翻开来看的。比较大型的书店一般会有照片中那样的挂起来的小册子,专门用来预览用,当然不是每一本漫画都会有预览版的。我找到过的最大的一个书店甚至在漫画区放了一个触摸屏,上面可以检索店内所有漫画然后预览。

总的来说还是有些不方便的,要看里面的话,除了看内容和画风之外,对于我这个日语半吊子来说,还有一件在意的事情就是对话里的汉字是否有注音。:p后来某次几个本地人聊天的时候他们说好像少年 Jump 的漫画经常会全文注音的。比较有意思的是他们说他们很多的汉字其实也都是小时候看漫画的时候学来的。

其次就是文库本的小说。所谓文库本就是指 A6 规格,大概是普通漫画那样大小的平装出版书籍,价格便宜便于携带。到日本来之前就听说日本的阅读风气很浓,在这边看到的虽然电车上年轻一代似乎玩手机的更多一些,但是在地铁、公交上看书的人还是随处可见的(而且我后来也加入到了他们的大军之中(笑),买了一本给小学生看的所有汉字都带注音的《怪人二十面相》在车上看。)。有一个说法是日本人这么喜爱阅读的一个原因就是文库本的发行方式。

文库本书籍里面有一大部分是轻小说。其实我到现在也不太分得清什么才算轻小说,我目前的分类方法是:如果有很漂亮的动漫风格的封面和插图,那大概就是轻小说吧。除此之外,也有很多正经的文学作品,诸如夏目漱石的经典作品之类的,还有国外名著的翻译版本等等。有个别书店连文库本小说都用塑料纸包起来,但是所幸大部分店铺都还是可以直接翻开看的。

除了漫画和文库本,剩下的就是比较正常的书,有很大一部分是旅行相关的,还有不少关于铁道、料理等方面的书。当然绘画方面的书也可以看到一些,但是却没有像国内书店那样大片大片的教你如何画漫画或者干脆如何画萌妹子的书。“不正常”的书自然也有了,比如比词典还要厚的整本整本的“日本全国铁路时刻表”之类的书,还有一些政治言论方面的书,比如有本书的标题说除了中国和韩国之外全世界都是亲日的,日本风正在吹遍全世界之类的,当然也有可能是我的 sample bias 导致只会注意到奇怪的书而忽略了那些“正常”的书。

当然奇怪的书中也有不少有趣的内容,如果不是考虑到回美国时候行李的问题,我大概会淘很多很多书吧,因为和美国那种“书的价格太贵了以至于出版社都不好意思印上价格”的情况比起来,日本的书价格还是很良心的。除了漫画书翻不开让人很恼之外,总体来说我还蛮喜欢日本的书店。我想漫画用塑料纸包装起来的目的应该是为了避免立ち読み,也就是站在那里不停地看的行为。就像下面这个样子:

这个是我在鸭川和三条通路交叉处的一个三层楼的二手漫画书店看到的场景,不论是漫画书还是站着看漫画的人都还是蛮壮观的。因为是二手书店,不仅书卖得非常便宜(大约 100 日元就可以买到一本,而且并没有明显损坏的痕迹),而且全部都是没有封装起来的,所以可以直接翻开看。不过猜想立ち読み的应该也是少数吧?因为即使是新的漫画,价格一般也就在四五百日元左右,还不到一碗拉面的钱。

我之前跑去京大的漫画研究社的活动(因为看到他们出的漫画月刊看起来很厉害的样子,以为平时的活动是在一起画画然后交流绘画技巧故事构思之类的,结果跑过去发现他们画漫画都是各自在家里进行的,而社团活动其实是大家在一起聊天看漫画打桌游……于是我就没有再去了。),跟他们聊天的时候提到 MIT 的图书馆有很多漫画,他们一开始觉得很神奇,但是接着又说在日本大概不需要,因为“大家都会买漫画嘛”。如果真的不想买,路边似乎也有一些漫画吧可以去。另外京都还有一个漫画博物馆,里面有一个叫做“漫画之壁”的东西。

话说回来,听到图书馆有漫画会觉得惊讶的原因是这边的图书馆和书店完全就是不同的画风。我去过学校的图书馆、市立图书馆和一些社区的公共图书馆,给人的感觉就是比较传统的样子吧。例如下面这个是醍醐图书馆(有没有一种醍醐灌顶的感觉?(笑)其实那一片地区叫都脚醍醐,似乎是来自于醍醐天皇。)

漫画肯定是没有的,书籍分类也比较齐全一点,然后还有报纸的缩印 archive,以及光碟影像资料等等。有一个小角落有一个比较有意思的阅览室中间有一个圆形的柱子四周摆了屏幕,大家围坐着柱子在那里看各自借出来的电影,好像比较老的诸如罗马假日之类的电影也都是有的。

然后还会有不少那种大开本的系列书籍,例如在京大附属图书馆就看到过一套《世界美术大全集》,非常非常赞。另外还有一整个书架上都摆着非常奇怪的书籍,比如这是一本词典:

后来才意识到原来是盲文,虽然有人能用手摸麻将,但是果然还是觉得靠手指的触觉神经的 resolution 来认字是件非常费力的事情啊。:(看不见的人真的是相当不容易!

到这里为止,我最大的困惑还是没有能解开:就是日本的大学生他们如果要买专业的教科书和参考书,到底要去哪里买呢?像国内的书店也都会有理科工科各类专门的书架,这边的大书店似乎看到一本正经一点的科普书就已经很难得了的样子。我在想大概是有专门的专业方面的书店我没有碰到?不过我倒是在去过的几个旧书店中的一个看到非常专业的藏书,数学物理化学全都是非常专业的书籍,还有不少外文原版的书包括GTM 系列的书也有。

其实这边的旧书店如果愿意认真探索的话,似乎还是有相当多的非常精致和有特色的小店的,通常都在狭窄的小屋里,密集的书架让人有一种“幸福地死在书堆里”的快感……XD,比如今天我看到的一家叫做“星与蝙蝠”的小店,就是要通过这样的下载旋转楼梯爬上三楼

楼上有一个小平台上有一个圆形小窗可以看到街道,回想那个楼梯有那么一瞬间我觉得自己好像是在一个潜水艇里。:D和正规的书店那种进门一堆人跟你道“欢迎光临”并鞠躬,出门还会有一堆人说“谢谢”的震慑感不一样,老板只是懒洋洋地自己在那边小心翼翼地清理一本旧书上的痕迹。这个店的内容和布置似乎是偏文艺或者说另类的风格。总之那个洗漱台改装的书架还有那里莫名其妙地冒出来的一只手真是让我哭笑不得……哈哈。

其实上来的途中还有一个小门,推开进去看到有一个人坐在桌子前忙碌着什么,因为只有稀稀落落几个书架,我怕是走错路了走到什么办公室之类的,就问他这里是不是书店。店主说:“书店倒是书店…………不过只有法语的书的……”,然后我就识趣地说了一声“打扰了”又退出去了。^_^bb

旧书店除了价格便宜,各有特色之外,还有一个好处是似乎时不时可以淘到所谓的“第一版”书,比如今天看到一本四叠半神话大系的第一版,还心动了一下。

最后,最近所有的旧书店门口都不约而同地挂起了这样的海报,关于 8 月份的旧书祭:

有点小遗憾的是按照我的原计划的话 8 月 11 日应该已经在东京了。下鸭神社的树林那里摆旧书摊,想想也是非常带感的呢!不过另一方面我觉得日本人非常有“煞有介事”的天赋,或者说日语本身就有这样的感觉?比如一听“古书祭り”就好像是很热闹很盛大的活动,但是如果翻译成英语“used book fair”的话,好像顿时就没有胃口了。:P

到了最后,再多嘴一句好了,下鸭神社位于两川交汇地,賀茂川和高野川在这里合流然后成为鴨川(“鴨川”和“賀茂川”的发音是一样的……)。这几个川的水都非常浅,据说古时候经常是洪水泛滥的,不知道什么时候变成了现在这个样子,按照现在的水深完全没觉得可以称为“川”啊。汇流处有石墩可以过河,其中有很多石墩是乌龟形状的。还有许多历史的故事,我也不是特别清楚,就不再多说了吧。:)

Projected Gradient Method and LASSO

$
0
0

上一次我们介绍了带约束的优化问题,以及局部最优解的充分条件和必要条件,这一次我们要介绍一个具体的算法,当 constraints 对应一个 convex set,并且计算到该集合的投影非常容易的时候,我们可以用一种叫做 Projected Gradient Method 的迭代算法来进行优化求解。具体来说,今天我们考虑这样的问题:

\[ \min_{x\in S}\; f(x) \]

其中\(S\)是非空闭凸集。上一次分析带约束优化问题的充分必要条件的时候我们将约束写成具体的等式和不等式的形式,这次我们只表示成抽象的\(x\in S\)的形式,因为我们并不关心其约束集的具体描述形式,只要假设有一个 blackbox 的投影算子\(P_S(x)\),能计算\(\arg\min_{y\in S}\|x-y\|\)即可。

Projected Gradient Method 其实非常简单,只是在普通的 Gradient Descent 算法中间多加了一步 projection 的步骤,保证解在 feasible region 里面。这个方法看起来似乎只是一个很 naive 的补丁,不过实际上是一个很正经的算法,可以用类似的方法证明其收敛性和收敛速度都和普通的 Gradient Descent 差不多。

首先我们要说明投影算法的可行性。具体来说,要计算投影,我们必须要有投影的存在性和唯一性。这个实际上在上一次的性质 1 中给出来了。方便起见我们在这里再重复一次,为了本文方便也把记号稍微变一下。

1

性质 1. 设\(S\subset\mathbb{R}^n\)是一个非空闭凸集,则对任意\(x\in \mathbb{R}^n\)

\[ \min_{y\in S} \|x-y\| \]

存在唯一解\(x_S\)。且\(x_S\)是最优解的充要条件是

\[ (x-x_S)^T(y-x_S) \leq 0, \quad\forall y\in S \]

由于这个结论对本文来说比较重要,我们在这里简单证明一下。首先存在性和唯一性是由\(S\)是非空闭凸集以及 norm 是严格凸函数得到的(可以任取\(S\)内的一点\(x'\),以\(x\)为中心\(\|x-x'\|\)为半径作一个球,与\(S\)相交得到一个紧的非空凸集,从而保证最优解的存在性。)。考虑当\(x\in S\)的时候,显然最优解就是\(x_S=x\)本身。此时性质中所对应的式子是 trivially 满足的。反过来如果该式子成立,由于\(x\in S\),带入式子中,可以得到

\[ \|x-x_S\|^2 \leq 0 \]

因此\(x=x_S\)。所以当\(x\in S\)的时候充要条件成立。接下来考虑\(x\not\in S\)的情况。首先证明必要性。用反证法,假设\(x_S\)是投影点,但是不等式不满足,亦即存在\(y\in S\)使得

\[ (x-x_S)^T(y-x_S) > 0 \]

此时考虑\(x_\theta = x_S + \theta (y - x_S)\),其中\(\theta \in [0,1]\),根据\(S\)的 convexity,有\(x_\theta \in S\)。接下来我们要证明\(x_\theta\)可以比\(x_S\)更优,以导出矛盾。

\[ \begin{aligned} \|x-x_\theta\|^2 &= \|x - x_S - \theta (y-x_S)\|^2 \\ &= \|x-x_S\|^2 - 2\theta (x-x_S)^T(y-x_S) + \theta^2 \|y-x_S\|^2 \end{aligned} \]

由于\(\theta^2\)\(\theta\)更加快速地趋向于 0,且\(\theta\)那一项的系数是严格负的,所以当\(\theta\)足够小时,我们可以得到

\[ - 2\theta (x-x_S)^T(y-x_S) + \theta^2 \|y-x_S\|^2 < 0 \]

也就是说\(\|x-x_\theta\|^2 < \|x-x_S\|^2\),矛盾。接下来考虑充分性,假设该不等式对任意\(y\in S\)成立,为了证明\(x_S\)是最优解,考虑任意的\(y \in S\),我们有

\[ \begin{aligned} \|x-y\|^2 &= \|x-x_S + x_S - y\|^2 \\ &= \|x-x_S\|^2 - 2(x-x_S)^T(y-x_S) + \|x_S-y\|^2 \\ &\geq \|x-x_S\|^2 + \|x_S-y\|^2 \end{aligned} \]

其中最后一步是根据条件中的不等式得到的。当\(y\neq x_S\)时,\(\|x_S-y\|^2>0\),此时我们可以得到

\[ \|x-y\|^2 > \|x-x_S\|^2 \]

根据\(y\)的任意性,即证明\(x_S\)是最优解。

当然,有了投影的存在性和唯一性并不代表该投影是很容易计算的。对于一些有特定结构的集合\(S\),可能会有专门的算法可以计算投影或者甚至有最优解。例如上一次作为例子介绍的 SVM 的目标函数中的 constraints 就是由每一个数据点对应的一个线性不等式所描述的 half space 相交得到的一个 polyhedron,计算该投影虽然有专门的算法,但是也称不上特别容易。所以本文我们暂时不用 SVM 的例子,而是考虑更简单的情况。其中最简单的例子就是所谓的 non-negative cone:\(S=\{x: x\succeq 0\}\),此时投影只要分别将每一维投影到非负半轴上就可以了,也就是令\(x_i\leftarrow \max\{x_i,0\}\)

不过,介绍具体的例子之前,让我们先回到 Projected Gradient Method 本身。假设我们现在有一个 blackbox 可以很容易地计算\(P_S(x)\),则算法由根据下迭代规则进行迭代直到收敛为止:

  • \(\bar{x}_k = P_S\left( x_k - s_k \nabla f(x_k) \right)\), \(s_k>0\)
  • \(x_{k+1} = x_k + \alpha_k (\bar{x}_k - x_k)\), \(\alpha_k\in (0,1]\)

其中\(s_k> 0\)是一个步长参数,例如取\(\alpha_k = 1\)的时候,上面的算法其实就变成了如下的迭代:

  • \(x_{k+1} = P_S\left( x_k - s_k \nabla f(x_k) \right)\)

也就是通过一次普通的 gradient descent 然后再利用 Projection Operator \(P_S(\cdot)\)投影到 feasible set 里来。加上\(\alpha_k\)参数之后实际上就是再多加了一步步长选择或者 line search 的过程,我们要求\(\alpha_k \in (0, 1]\)这样可以保证不会再移动到 feasible set 外面去。

另外有一点值得一提的是,投影之后的移动方向\(\bar{x}_k - x_k\)一定是一个下降方向:也就是说它和\(-\nabla f(x_k)\)成锐角。这是因为根据刚才证明的性质中投影算子的最优解的充要条件的不等式得到的,另外从图中可以比较直观地看出来。

除此之外,在类似的前提条件下,我们也可以和像 unconstrained optimization 中证明梯度下降算法的收敛性一样证明 Projected Gradient Method 的收敛性。回忆一下我们在第一篇证明简单的固定步长的梯度下降的收敛性的时候,是证明了每次迭代中

\[ \|x_{k+1}-x^*\| \leq M \|x_k - x^*\| \]

其中\(x^*\)是最优解,而\(M\)是一个严格小于 1 的正数。此时我们得到迭代法 Q-线性收敛到最优解。现在我们多了一步投影的步骤,在同样的前提假设下(此时上面的式子是成立的),我们有

1
图 1

\[ \begin{aligned} \|P_S(x_{k+1}) - x^*\| &= \|P_S(x_{k+1}) - P_S(x^*)\| \\ &\leq \|x_{k+1}-x^*\| \\ &\leq M \|x_k - x^*\| \end{aligned} \]

其中第一个等式是因为\(x^*\in S\),随后的不等式是因为投影算子是一个 Contraction,也就是说:

2

性质 2. 设\(S\subset\mathbb{R}^n\)是一个非空闭凸集,则投影算子

\[ P_S: x \mapsto \operatorname*{arg min}_{y\in S}\|x-y\| \]

是一个 Contraction,亦即

\[ \|P_S(x) - P_S(y)\| \leq \|x-y\|, \quad \forall x, y\in \mathbb{R}^n \]

这个性质有一个比较直观的几何证明,简单描述的话如图(fig: 1)所示,考虑\(x\)\(y\)以及它们到\(S\)的投影\(x_S\)\(y_S\),以\(x_S-y_S\)向量为法向量作两个分别通过\(x_S\)\(y_S\)的超平面\(H_x\)\(H_y\)。我们知道\(\|x_S-y_S\|\)是两个超平面之间的距离,也就是超平面上的两个点之间的最短距离,而\(x\)\(y\)两个点根据性质(prop: 1)分别在两个超平面上或者“外面”,因此它们两点的距离不会小于两个超平面之间的距离,也就是\(\|x_S-y_S\|\),即证。

现在回到我们的 Projected Gradient Method 上来。刚才的不等式中我们得到的结论是,由于投影算子是 Contraction,所以虽然多加了这一个步骤,但是并不会影响我们以前关于 gradient method 的收敛性的证明,所有步骤几乎可以原封不动地用到这个方法中来。

介绍完优化算法之后,同以往一样,我们将它用到一个机器学习的模型中去。从刚才的介绍和分析上可以看到,这个算法不论从计算步骤还是分析本身都只比普通的 gradient descent 多了一步而已,得到的收敛复杂度也是一样的,不过需要再次强调的是,这里的收敛复杂度是一迭代次数来计算的,我们一直都假设投影算子的计算是简单的,如果投影算子的计算本身就需要解一个复杂的优化问题的话,那么这样比较的意义就不大了。这里我们举一个投影算子非常容易计算的例子:LASSO

LASSO 是在 sparsity 相关的问题中应用非常广泛的一个模型,具体来说,LASSO 对应如下的一个优化问题:

\[ \min_w \; \sum_{i=1}^N (w^Tx_i - y_i)^2 + {\color{red}{\lambda\sum_{j=1}^n |w^j|}} \]

这里\(x_i\)是数据,\(y_i\)是对应的值,该优化问题是用线性回归去拟合给定的数据,而向量\(w\in\mathbb{R}^n\),也就是我们的优化变量是拟合的线性模型参数,而红色的项是 regularizer,其中\(w^j\)表示向量\(w\)的第\(j\)个 component,所有 component 的绝对值之和即\(w\)\(\ell_1\)-norm,通过添加\(\ell_1\) regularizer 可以带来稀疏性,当 regularizer 系数\(\lambda\)控制得当的时候最优解\(w\)的很多 component 将会是零。

LASSO 问题的解法有很多,例如用LARS可以一次性解出所有可能的\(\lambda\)取值所对应的解\(w\),这对于需要对\(\lambda\)进行 cross-validation 调参数的情况来说非常省时省力,不过今天我们我们的目的是为了给 Projected Gradient Method 进行示例,所以不会在这里介绍 LARS 对应的算法。

话虽如此,但 LASSO 问题其实是一个 unconstrained 优化问题,但是由于其 regularizer 中的\(\ell_1\)-norm 不可导,所以我们既不能套用之前讲过的简单的 Gradient Descent 算法(不可导的优化问题的解法相关的内容将会在以后陆续介绍。),也不能直接套用这里讲到的 Projected Gradient Method,所以需要对问题做一下小小的变形。

这里其实就涉及到了 optimization 中很重要的一个环节:problem reformulation。一般解决一个问题可以分为以下几个步骤

  1. 抽象问题,提出模型,建立目标函数
  2. 将目标函数转化为易于求解的形式
  3. 找到或者设计对应的优化算法
  4. 编程、调试、跑实验,看着 cpu 实时利用率图发呆等

其中第一步是属于特定的问题领域相关的知识和技术,而最后一部则属于 computer engineering 相关的内容。第三步显然是 optimization 的覆盖范围,但是几乎同等重要的第二步实际上也是属于优化范畴的,并且通常被轻视的一环。大概也因为这其实也是比较困难的、没有什么比较系统的方法或者规律可循的一环的缘故吧。

回到 LASSO 问题,注意到任意实数\(w^j\)都可以表示成其正部和负部之差\(w^j=w^j_+ - w^j_-\),其中\(w^j_+ = \max\{w^j,0\}\geq 0\), \(w^j_-=\max\{-w^j,0\}\geq 0\)。此时绝对值可以简单地表示成\(|w^j|=w^j_+ + w^j_-\)。根据这个性质,我们在 LASSO 问题中引入新的变量\(w^j_+, w^j_0\geq 0\)\(j=1,\ldots,n\),很容易可以证明,LASSO 问题等价于

\[ \begin{aligned} \min_{w_+,w_-} \quad& \sum_{i=1}^N \left( (w_+-w_-)^Tx_i - y_i \right)^2 + \lambda \sum_{j=1}^n (w^j_++w^j_-) \\ s.t. \quad& w_+\succeq 0, w_-\succeq 0 \end{aligned} \]

现在问题变成了 constrained 优化问题,并且目标函数是可导的(二次函数),约束集也是投影算子非常容易计算的 non-negative cone。简直就是为我们今天准备的模范例子!

为了码代码方便我们把上面的目标函数写成矩阵形式:

\[ \begin{aligned} \min_{w_+,w_-} \quad& \|Xw_+ - Xw_- - y\|^2 + \lambda w_+^T\mathbf{1} + \lambda w_-^T\mathbf{1} \\ s.t. \quad& w_+\succeq 0, w_-\succeq 0 \end{aligned} \]

其中\(X=(x_1,\ldots,x_N)^T\)是数据矩阵。我们进一步令\(\tilde{w}=(w_+^T,w_-^T)^T\)\(\tilde{X} = (X, -X)\),则问题的形式可以进一步简化为

\[ \begin{aligned} \min_{\tilde{w}} \quad& \|\tilde{X}\tilde{w} - y\|^2 + \lambda \tilde{w}^T\mathbf{1} \\ s.t. \quad& \tilde{w}\succeq 0 \end{aligned} \]

这样一来 gradient 的计算和投影的计算都变得非常明了了。接下来我们把学到的只是用的一个具体的例子里。今天我们选一个信号处理里的例子:利用 natural image 在 wavelets 下的稀疏性来去除白噪声。

为了和刚才的记号尽量保持一致,我们用\(y\)来表示一张图像,简单起见我们考虑灰度图像,也就是一个单通道的矩阵,不妨将\(y\)看成是把该矩阵的每一列接起来得到的一个长向量。而正交的 discrete wavelet transform (DWT) 通过一组正交基\(W\)可以将图像表示成系数\(w\)的形式:

\[ y = Xw \]

同时我们知道 natural image 和 wavelets 的性质:natural image 经过 DWT 之后得到的系数具有稀疏性——也就是说\(w\)是一个稀疏向量。这个稀疏性有很多通途,比如用于存储和传输,由于很多 component 是零,不需要进行存储,因此可以节省很多存储空间。在 JPEG 2000 标准中就用到了 DWT。更细节的东西可以参考DWT 的 wikipedia 页或者相关的书籍资料。

2
图 2

另一方面,图像白噪声,也就是随机的 Gaussian noise (图(fig: 2)是一个加成了白噪声的 lena 照片的示例)在 wavelet 变换下却并没有什么规律,或者说,其实还是白噪声,因为正交线性变换下高斯分布还是会得到高斯分布。图(fig: 3)是对比原始的 lena 图在 DWT 下的系数和白噪声加成之后的 DWT 系数的结果。可以看到白噪声严重破坏了稀疏性。

3
图 3
lena 在 DWT 下的系数。
lena + white noise 在 DWT 下的系数。

所幸的是白噪声所对应的系数绝对值都比较小,因此有一种非常简单的去白噪声的算法就是:将被白噪声污染的照片进行 DWT 得到变换后的系数,然后直接设定一个比较小的数作为阈值,将所有绝对值小于这个数的系数直接设为零,然后再进行逆向 DWT 得到去噪后的图片。

不过我们今天使用的是看起来略微“高端”一点的算法:我们通过\(\ell_1\)-norm regularization 而不是直接 hard thresholding 来获得稀疏性。具体来说,令\(X\)是 DWT 所对应的 wavelet 基,\(y\)是加上了白噪声的图片,我们通过求解下面的优化问题

\[ \min_w \|Xw - y\|^2 + \lambda \|w\|_1 \]

来得到一个稀疏的系数\(w\),最后再通过逆向小波变换将\(w\)变回图像域,得到去噪后的图片。图(fig: 4)是 lena 原图和通过我们刚才描述的算法,用 Projected Gradient Method 求解后得到的结果对比。

4
图 4

可以看到去噪效果还算过得去吧,不少噪音抹平了,但是图片本身的内容也有不小的损失。当然这是相当 naive 的去噪方法,只用到了 natural image 在小波基下的系数的稀疏性这样的基本性质。

最后值得一提的是,虽然这个示例的优化问题中的目标函数是写成矩阵相乘的形式,但是在具体的实现中计算 gradient 以及目标函数值的时候并不需要先展开整个 wavelet 基矩阵然后用矩阵向量相乘,而只需要有一个 blackbox 算法可以执行快速的 wavelet transform 以及其逆向 transform 就可以了,通常速度会快很多。本文示例的 julia 代码类似地可以在我的 MLOpt.jl 代码 repo 对应本文的 release下可以找到。详细参见example/pgd_lena.jl文件。

Mosh: the Mobile Shell

$
0
0

mosh估计超过半年了,因为基本上无缝替换 SSH,所以都没有太意识到它的存在,一直忘记了上来推荐一下。如其名字,mosh 差不多就是为移动设备设计的 SSH,现在的发展趋势:笔记本越来越轻便,网速越来越快,服务器越来越强大。结果几乎工作模式都变成了通过笔记本 SSH 到不知道肉身在世界的哪个角落的服务器上做计算。

这其中有一个小小的不便之处就是笔记本不管是从休眠中恢复也好,还是从一处拿到另一处也好,如果网络断开重新连接了,那么 SSH 之类的连接基本上也就挂掉了,当然如果在服务器上用了 GNU Screen 或者 tmux 之类的东西,那么其实只是要再重新连接一下 SSH 然后再 attach 到之前的 session 上就好了,其实也只是小麻烦,但终究还是麻烦的。mosh 就是为了解决这样的麻烦而设计的。

使用非常简单,只要连 SSH 的时候用mosh命令代替即可。这样即使你网络断开(截图中顶上的状态栏就是网络断开时 mosh 给的状态提示)或者休眠之后,当网络重新连上之时,mosh 会自动重新连接,而对于你在 mosh 里运行的程序来说,一切就好像你的 SSH 连接从来没有断开过一样。并且替换是无缝的,SSH 所有的公钥私钥验证全都支持——因为 mosh 在登陆验证这部分其实是直接用 SSH 的。

除此之外,由于使用了 UDP,mosh 号称延迟方面也比 SSH 人性化很多。我确实是在非常糟糕的网络环境下也用过 mosh,因为它并不像 SSH 那样等待服务端响应之后才把按键显示出来,所以不会因为卡顿而出现类似于“盲打”的情况,但是也只是感觉比较流畅一点而已,因为毕竟网速慢的话软件层面也没有太多办法。

在使用之前需要同时安装客户端和服务端。比较好玩的是我之前一直以为不需要安装服务端,因为我尝试的时候直接就 work 了,估计是因为在这边已经比较普及了所以我尝试的 server 上都已经安装好了吧,毕竟是自己学校这边搞出来的东西。不过即使要自己安装也非常方便,如果在服务端没有权限,只要安装在自己的 home 目录下面,然后把可执行文件的路径加到PATH里,让 SSH 登陆的时候能够找到mosh-server这个命令就好了。

另外,mosh 还有一个Chrome 插件,也许可以在网吧之类的只有 Chrome 浏览器的地方应急的时候用?或者大概主要还是给 ChromeBook 用的吧?

最后,目前 mosh 的最新版本是 1.2.4,这个版本有一个小问题就是不会汇报鼠标事件,如果你在远程的 VIM 或者 tmux 等支持鼠标事件的程序中喜欢用滚轮或者触摸屏滚动屏幕的话,可能会有点不习惯。如果不能忍,可以自己编译安装 git 里的最新版本的 mosh。如果是 OS X 下用Homebrew安装的话,只要用

brew install --HEAD mosh

即可安装 git 最新版本。废话就不多说了,请慢用!:P

Approximation Theory: From Taylor Polynomials to Wavelets

$
0
0

这是由 Ole Christensen 和 Khadija L. Christensen 两人合写的一本小册子,全书加上封面一共才 166 页,我想这应该是我能迅速把它看完的一大原因。:p当然书本身是非常有趣的,虽然我已经忘记了自己最初是在哪里碰到它的了。

全书从 Weierstrass Theorem 引出,该定理讲的是在有界闭区间上的任何一个连续函数可以由一个多项式函数进行 uniform approximation。记得很早以前跟数学系学长聊天的时候说我其实对数学很感兴趣,结果他冷不丁问我知不知道 Weierstrass’ Theorem。所以我想这应该是数学里的美妙结论的一个代表吧——当然话说回来数学里的美妙定理几乎是数也数不完的。这里的美妙之处就在于我们都知道多项式很“简单”,这样一来所有问题都可以近似地化归为多项式的问题来解决,简直就跟在说“所有的问题都已经解决了”一样。

当然如果是这样的话这本书就没得写了。实际上 Weierstrass 虽然美妙,但是实际用起来却还是有很多问题。比如定理只提到了存在性却并没有直接给出一个方便的近似构造方式,再比如我们虽然可以得到一列多项式函数一致地收敛到给定的函数,但是我们并不知道收敛速度是多少,更没有一个显式的误差估计,这些在实际问题中都是非常重要的。

当然天下没有免费的午餐,想要得到更多的结论,通常就需要对需要近似的函数加更多的限制和假设。书里紧接着给的例子就是在假设\(f(x)\)光滑(无限次可导)并且任意阶导数可以通过一个常数\(C\)控制住的情况下,使用泰勒级数给出了\(f(x)\)在一个区间\(I\)上的一个显式近似表达式以及误差估计项:对任意整数\(N\)和任意\(x\in I\)

\[ \left| f(x) - \sum_{n=0}^N \frac{f^{(n)}(x_0)}{n!}(x-x_0)^n \right| \leq \frac{C}{(N+1)!}|x-x_0|^{N+1} \]

其中\(x_0\)\(I\)中的一个点。这个结论其实可以很容易通过数学分析中学到的带余项的泰勒展开得到。以上的两个例子都是处理一致收敛或者说 uniform approximation 的情况,实际中我们经常还会碰到各种其他的收敛或者近似。比一致收敛弱一点的情况是 pointwise approximation,也就是说可以保证函数在每一点都收敛或者近似,但是却不能让它们达到步调一致,这比一致收敛要求要低很多,不过 pointwise 的结果当限制到一个紧集上的时候同样可以得到 uniform 的结果。再往下还有更弱的,比如积分收敛:函数列\(g_n(x)\)可能在任何一点\(x\)上都不收敛到\(f(x)\),但是当考虑两个函数之差\(|f(x)-g_n(x)|\)的时候,可以可以保证这个差值函数的积分趋向于零。直观来说就是尽管我不能保证每个点都很老实,但是只要集体行为(积分的尺度)从总体上来说可以控制就好了。这其实是非常常见的一种收敛形式,只要换一个形式就可以看到。考虑由如下内积定义的区间\(I\)上的函数的 Hilbert Space:

\[ \langle f, g\rangle = \int_I f(x)\overline{g(x)}\; dx \]

对应的 norm 就是

\[ \|f\|^2 = \int_I \left|f(x)\right|^2\; dx \]

此时考虑 Hilbert Space 中的一列向量\(\{g_n\}\)收敛到点\(f\),其实就是说

\[ 0 \leftarrow \lim_{n\rightarrow\infty} \|f-g_n\|^2 = \lim_{n\rightarrow\infty} \int_I \left| f-g_n \right|^2\; dx \]

也就是我们刚才所说的积分收敛,这个特殊情况也成为 least square 收敛。如果在\(L_p\)空间中考虑,就会对应不同形式的积分收敛。

在做一些无穷级数的准备知识介绍之后,书的内容就转向 Fourier 级数,也就是通过正弦余弦函数的组合来逼近一个周期函数,这里考虑\(2\pi\)为周期的情况。类似地这里我们会分别得到 least square 收敛和 pointwise 收敛等不同情况的结论。比如,考虑 least square 的情况,当\(f\)\([-\pi,\pi]\)上可积时,我们可以得到 least square 收敛,并且有如下 Parsevel 恒等式:

\[ \|f\|^2 = \sum_{n=-\infty}^{\infty}\left\|\hat{f}(n)\right\|^2 \]

其中\(\hat{f}(n)\)\(f\)的第\(n\)个 Fourier 系数,从这里我们可以看到,对\(f\)做 least square 近似可以通过只保留\(N\)个最大的 Fourier 系数的方式来实现。当然计算和比较所有的 Fourier 系数是不太现实的,但是如果我们进一步的有关于\(f\)的光滑性的前提的话,可以非常简单地直接保留前\(N\)个 Fourier 系数即可——因为\(f\)的光滑性实际上对应了其 Fourier 系数的衰减性质。例如,如果\(f\)是二阶连续可导的,那么其 Fourier 系数则以\(O(1/|n|^2)\)的速率衰减,因此当\(n\)很大时其系数可以忽略不计,所以根据上面的 Parsevel 恒等式直接 drop 掉所有\(n\)很大的对应项也不会有太大的损失。

不过 Fourier 级数有一个问题就是不能处理非周期函数。虽然 Fourier 变换作为 Fourier 级数的推广可以处理非周期函数了,但是级数求和变成了求积分之后,从 Approximation 的角度来看就不那么直观了。于是书的后面部分开始介绍 wavelet,还提到了 wavelet 的发展历史以及其中的一些趣事。

在接近末尾的 Best N-term approximation 一小节中,书里举了一个例子来说明 wavelet 带来的比 Fourier 级数更好的稀疏性的好处:如果保留前\(N\)项系数的话,那么通过 Fourier 级数和通过 wavelet 的方式来进行近似其 square error 的 decay rate 都是差不多的\(1/N\),但是如果考虑 wavelet 系数的稀疏性,同样保留\(N\)个系数,但并不一定限制是前\(N\)个的话,那么近似的 square error 可以达到\(2^{-N}\)的 decay rate。当然无论是 wavelet 也好还是 approximation 也好,都是非常大的 topic,这里只能是浮光掠影地提到一些,书里的很多结论虽然都给出了比较严格的叙述,但是几乎都没有给出证明——否则也不会这么轻易读完吧。:D

最后,我想说的是,这是一本相当有趣的书。实际上 Approximation 的问题在 machine learning 中也是无处不在。比如在优化的时候所谓 gradient descent 或者 Newton Method 之类的,其实就是在局部对函数做一阶或者二阶的近似。再考虑 Learning 问题本身,所谓的Empirical Risk Minimization (ERM)其实整个就是在对 (Unknown) True Risk 进行近似之后再最小化。而这个近似的 pointwise convergence 是由传统的大数定理或者具体的Chernoff Bound保证的,但是为了保证 ERM 结果的有效性,pointwise convergence 是不够的,还需要该近似在整个 Learning 用的函数空间\(\mathcal{H}\)上的 uniform convergence 性质才行,而VC 维之类的工具就是用来分析是否能从 pointwise convergence 得到 uniform convergence 的。

此外,Learning 本身为了保证可学习性,把搜索限制在一个函数空间\(\mathcal{H}\)内(比如如果是在做 classification 的话我们会要求\(H\)的 VC 维是有限的),但是当 true function \(f^\dagger\)不在\(\mathcal{H}\)内的时候,我们实际上会有一个 approximation error:

\[ \inf_{h\in\mathcal{H}}\|f^\dagger - h\| \]

在不改变\(\mathcal{H}\)的情况下,我们的 learning 算法再好也无法达到比这个更小的 error。所以这里存在一个 trade-off:一方面我们希望\(\mathcal{H}\)尽量“简单”以达到更好的 uniform convergence 保证,另一方面我们又希望\(\mathcal{H}\)尽量“复杂”以实现对\(f^\dagger\)的更好的近似降低 approximation error。就好像 coin 的两面,前者方面的研究主要是借助于 VC 维、Rademacher Complexity之类的工具,而后者方面的研究似乎知名度比较低一点,但是也是同样重要的内容。如果感兴趣的话 Ding-Xuan Zhou 有一本书叫做《Learning Theory: An Approximation Theory Viewpoint》似乎有讲这方面的内容。

后记:想读的书的 list 不管是专业书还是非专业书列表都在不停地增长,虽然经常都会做出努力去开始读一本书——并且是饶有兴致地,但是大部分情况都是在一两个星期之后由于其他的事情不知不觉间被打断了,很多时候往往经常是发现另一本届时觉得更加有趣或者更加急需阅读的书。结果就是不停地从图书馆借书,但是真正读完的却还是寥寥无几。所以为了督促我自己好好地读书,我想在读完一本书之后写一点书评或者简短的总结。专业类的书就贴到这个技术博客里好了。

DRM vs. DRM-free e-Books

$
0
0

电子书时代的逐渐到来一直是一件让我觉得兴奋不已的事情,当然目前离电子书取代传统书的时代还有很长的一段距离了。从目前的情况来说,电子书和纸质书的阅读可以说是各有优缺点,就好像传统的绘画和通过 Wacom 之类的设备直接在电脑上作画一样,虽然不排除随着技术的逐渐发展后者可能最终将会取代前者,但是就目前的状况来看,只能说是各有千秋了。

特别是电子书的市场本身也还正在发展中,总体来说也就是近几年新出的畅销大众化类的书比较多会有电子版,但是比较专业一点的书籍就没有那么好的支持。比如我虽然给我妈妈买了 Kindle PW,但是似乎用处也不是很大,她经常要读的那些比较正统的文学类书籍大都没有电子版出售,而且比较冷门的话就连网上的自制电子书也是没有的。

再比如数理类的专业书,Amazon 现在似乎花了很大的力气把很多新出版的这类书籍都配套上 Kindle 格式的电子书,却有种弄巧成拙的感觉——总之几乎就是非常简陋地直接把原来的排版转成劣质的 HTML 格式然后再打包成电子书,公式什么的就变成甚至都和周边文字无法对齐的模糊图片……这里就不做更多地吐槽了,总之 Amazon 这件事给人带来的印象是科技类书籍还是乖乖去看纸质版吧。当然踢开 Amazon 的话其实会发现真实情况并不是如此,许多出版社都提供非常精良的 PDF 格式的电子书供购买,有些甚至是 DRM-free 的。甚至连苹果的 iBook 里很多科技数学类书也可以看到非常精美的公式图表排版。我经常去学校图书馆的网站提交 purchase request,有时候发现某本很 popular 的书拍了很长的队伍要借的时候,就直接建议他们买一个电子版,然后可以从图书馆借阅,通过 Adobe Digital Editions 之类的阅读器可以在电脑上阅读,各种 tablet 上似乎也有可以阅读 DRM PDF 电子书的 app。当然就没有用自己喜欢的 PDF 阅读器那样得心应手了。

1
图 1
图书馆里可以访问到的 DRM-free 电子书,可以在任意 PDF 阅读器上阅读。

不过也有一些书籍是可以直接通过 DRM-free 的 PDF 格式访问到的,当然 policy 上是不允许随便传播的,并且下载该 PDF 的时候是需要通过学生 ID 登陆的,所以电子书里应该也会嵌入身份信息,如果传播到网上最后要追究源头的话应该会是比较严重的问题。

如果说专业类书籍的话还有一个问题就是阅读是非常“非线性”的,也就是说并不是一个简单地从前往后一页一页地看下去就行了,而是经常需要往前面翻一下查阅某个定理、定义呀,或者往后翻看一下某个参考文献啊等等,跳来跳去的这种操作目前来说拿着一个平板远没有拿着一本纸质书来得方便,更别说翻页翻得那么痛苦的各种 e-ink 阅读器了。

但是如果是看小说之类的可以顺序阅读的书籍的话,我觉得目前电子阅读的优势已经可以比较明显地让它成为我的首选阅读方式了。但是 DRM 就成为更严重的问题了。DRM,全称是Digital Rights Management,可以简单地认为是各个公司用来把限制用户使用那些虚拟的有可能被无限复制的内容的东西。比如我小时候第一次知道不同国家的 DVD 播放机不能解码其他国家的 DVD 碟片的时候就挺震惊的,震惊的是这件事情是故意设计成这样子的。当然后来我理解了有各种版权啊、授权啊、利益啊之类的因素在后面。只是逐渐认识到人类从古到今都在干着各种自己遏制人类社会的知识传播和发展的事情这件事情多少有些无奈。现在的电子书 DRM 的问题可以说是有过之而无不及。虽然除了 Amazon 之外,其他的电子书出版商大都基于开放的 epub 格式,但是各自加了各自的 DRM 之后,也就变得互不兼容了。

一方面从出版商或者是作者的角度来考虑的话,怎么处理电子书会被随意拷贝传播的问题确实是很重要的,但是另一方面就现在的情况来就的话,商家的目的似乎已经远远超过了限制拷贝,而是各种想尽办法把用户套死在自己的平台上。比如说你一直在买某一家的电子书,但是将来那家公司突然倒闭了,或者被另外某个神经病公司收购了,或者转战其他领域去了之类的,逐渐停止更新和支持阅读平台,那么你原来买的那些书基本上也就全部“dead”了(因为计算机领域有一个比较特殊的地方,一个软件或程序如果停止更新的话,因为周边的其他所有东西都在不断更新变化,很快它本身就会变得不兼容甚至无法运行了,这本身也是一件有趣的事情。原本一段程序代码是可以“恒久保存”的,但是实际的情况却是像有机物质一样会随着时间流逝慢慢“变质损坏”了。)。也许大部分的小说类书籍第一遍看完之后就不会再去看了,所以“死”不“死”都没太大关系。但是心里总是很不爽啊。也许是我的想法太过激了,我觉得利用 DRM 来将用户限制或者圈占到自己的生态系统上来是一件很下三滥的事情。就好像是你喜欢一个人想要跟他/她在一起,你不是去让自己变得更好让对方主动想要和你在一起,而是把他/她手脚都切了装到你家的花瓶里这样他/她就哪里都去不了只能和你在一起了。=.=b

其实就历史上的各种情况来看,统一标准通常都是最终的王道解决方案,其实电子书的 DRM 如果有一个强有力的标准出现的话就皆大欢喜了。只是不知道还要等多久。就目前来说,抛开各种“道理”上的东西的话,从实用主义的角度来说,DRM 虽然被限制死平台了,但是其实也可以很多平台一起用(有点略精神分裂就是了),而且如果平台本身可用性也还不错的话,其实也没有什么太多怨言了。但是反过来如果平台很不好用的话,就很难过了。

2
图 2
豆瓣的 iOS 阅读器,日文部分各种字体混杂。

例如豆瓣的 iOS 阅读器这里是作为一个反面例子出现的。之前我在 iPad 上打开就一直 crash,现在更新了终于不 crash 了,随机打开一个豆瓣在 2012 年最初推出阅读功能的时候提供的免费书 sample,在字体上就出了问题,而且 app 还不允许修改字体,不知道是不是遵从“极简”哲学。不过英文阅读平台才是更让人不爽的。

3
图 3
Google Play Books 的官方截图。英文的“左对齐”模式。
Kindle 官方广告。英文的“两端对齐”模式。

这里不妨看一下 Google 的 Google Play Book 和 Amazon 的 Kindle。由于英文不像中文那样是一个一个的方块字,所以在左边对齐的情况下右边如果想要避免在单词中间直接断开的话,就会出现每一行的长度不一样的“锯齿状”段落,就同图中的 Google Play Book 的显示效果差不多。右边不对齐很难看啊(请不要吐槽本博客里中英文混排的时候出现右边不能对齐的锯齿状段落……),不止是从小看对齐的方块字段落的我们才会这么觉得,西方人也是这么觉得的,所以他们发明了hyphen,对于一些长单词可以在其中断开用连字符接到下一行,这样一来长短不一的情况就可以得到大大改善,剩下的细微差别只要再稍微调整一下单词间距就可以做到完全对齐了——由于调整得非常小,所以也看不出违和感。

但是这样在排版的时候计算量比较大啊,一方面需要词典 + 规则来决定单词中间哪里可以断开哪里不能断开,一方面还要决定这个单词是放到下一行呢还是断开呢,从哪个部分断开呢,断开之后本行的单词间距如何分布调整呢之类的。比如 LaTeX 虽然能排出比较漂亮的对齐文档,但是编译一次也是要费点时间的。所以像 Word 那样需要实时渲染文档的字处理软件就不提供这种功能,但是右边不对齐总还是觉得很难看啊!怎么办呢?于是 Word 里有了一个叫做“两端对齐”的选项(不知道是不是他家首创的),简化了一下,就是不断开单词了,但是还是想要两端都对齐,于是就放荡不羁地调整单词的间距,大概就是图上的 Kindle 显示的段落的样子了……反正我是觉得这是最不能忍受的一种显示方式了。间距太大之后读起来都没有连贯感了,而且不同的行之间间距时大时小,就是一种乱七八糟的感觉。

现在的 CPU 计算速度已经和编译一个 LaTeX 文档需要好几分钟的时代有了巨大的进步,到底缺乏 hyphen 的支持是由于技术原因还是只是懒得加而已已经很难说了。就实时编辑而言 Adobe 的 InDesign 是支持实时 hyphen 的。而且现在浏览器里的段落渲染也有了专门的 CSS 标准用来支持 hyphen,虽然还没有完全得到各个浏览器的支持——主要也就是 Chrome 不支持了,其实也不是不支持,Chrome 其实实现了 hyphen 属性,但是是以不断词的方式来实现的……=.=b所以其实就是不支持了。另一方面各种移动设备上,比如 iOS 上的 iBook 和第三方的 Marvin 阅读器都支持 hyphen,也没有看出渲染的时候有什么特别明显的卡顿。不知道 Kindle e-ink 阅读器的 CPU 性能怎么样,但是估计 Amazon 也没有把这种小事当一回事吧,否则也不会那样子直接把这样的图拿来做官方广告了。

由于我强迫症比较严重,所以至今很少在这些平台上买电子书来看,一般都是去网上找 epub 然后在第三方阅读器上看(当然我原本就很少看小说就是了)。这样的问题就是网上的自制电子书时不时都有各种错误遗漏之类的,莫名其妙地空一行啊,排版混乱了啊,标点符号混乱啊之类的。不过我最近知道了一个好消息就是似乎几个比较常见的厂商的 DRM 都是可以比较容易地去除的。

当然这样做是违反电子书出版商的协议的,不过出版商的协议太霸道也让人不爽,只要保证是自己看而不拿到网上传播的话,至少从“道义”来说没有什么不对的了……=,=我想就出版商而言,与其让用户去下载参差不起的盗版电子书来看,让用户给自己合法购买的电子书去 DRM 之后放到其他的设备或者阅读器上看应该相对比较可以接受一点吧?

具体来说,在网上搜索 Apprentice Alf 可以找到一个 DRM Removal Tool,可以去除 Amazon 和 Adobe (Google Play Books 似乎是使用的 Adobe 的 DRM 方式。)的 DRM 限制。可以使用它提供的单独的工具或者 Calibre 插件。对于 Amazon 的电子书,最好使用 Calibre 插件,因为 Calibre 本身提供各种不同的电子书格式转换的功能,可以把 Amazon 的私有格式转换成标准的 epub 格式。Mac OSX 系统下大概步骤如下:

  1. 安装 Kindle for Mac,在 Mac App Store 里可以找到。
  2. 安装Calibre,以及上面提到的 DRM removal plugin。
  3. 打开 Kindle for Mac,登陆账号,注册该“设备”。
  4. 在 Amazon 购买电子书,然后推送到 Kindle for Mac 上。
  5. 找到下载的电子书,App Store 上下载的 Kindle App 的话,是放在~/Library/Containers/com.amazon.Kindle/Data/Library/Application Support/Kindle/My Kindle Content下面。在 Kindle 程序的选项那里其实可以查看和修改这个路径。里面的.azw后缀的文件就是电子书,只是文件名是某些标识符看不出哪一本是哪一本,可以全部导入到 Calibre 里面去,就会看到书的标题作者了。
  6. 如果之前的 DRM removal plugin 安装成功的话,在导入电子书的时候应该已经自动去掉 DRM 了。这个时候可以使用 Calibre 的转换格式功能,转换成 ePub 格式就可以拿到其他地方去阅读了。如果 DRM 没有去除的话,会得到无法转换的错误提示。
4
图 4

这里顺便需要提一下的是 Calibre 本身是一个非常强大的电子书管理和转换工具。并且它有一个 Content Server,可以把你的所有电子书索引起来然后在其他设备上通过浏览器进行访问。如果客户端支持Open Publication Distribution System (OPDS)的话,就更加方便了。比如 iOS 里的 Marvin 阅读器,就支持 OPDS,于是可以直接连接到 Calibre 的电子书库里浏览和下载自己书库里的书来阅读。还有几个公共的 OPDS server,包括 public domain 里的电子书,以及Project Gutenberg等有大量的经典书籍可以非常方便地直接浏览下载。

我自己因为有一台实验室的 Linux Desktop 是常年在线并且有固定公网 IP 和域名的,所以我决定把 Calibre 运行在那上面,并且把 Content Server 开起来,这样我在有网络的时候就可以随时通过手机或者平板连接上去下载电子书。此外,有不少可以跟踪文件系统变化的工具,例如 Ruby 的库listen或者 GUI 工具hazel,可以设置一个规则,就是发现 Kindle for Mac 的内容目录里有新的.azw文件的时候,就自动scp到 Linux Server 上的某一个特定的目录。然后 Calibre 也有跟踪目录自动导入的功能,让它观察服务器上的那个目录,自动导入电子书并自动转换为 epub,实现一条龙服务!

不过这里还有一个小问题就是 DRM Removal Plugin 在 Mac 下 work 是因为安装了 Kindle for Mac,并且你自己已经购买了该书籍,可以在 Kindle for Mac 里打开阅读。也就是说你拥有正当地解开 DRM 的 key,虽然我不知道那个 plugin 具体是怎么工作的,但是我想大概应该是通过那个 key 模拟了一下 Kindle for Mac 取得解密后的文档内容之后再导出吧。所以为了让 Linux Server 上的 Plugin 也能正常工作,需要把 Mac 下的 key 导入到 Linux 中。具体做法如下:

  1. 在 Calibre 的 Preference \(\rightarrow\) Plugins 的 File type plugins 里找到我们的DeDRM插件,选择 Customize plugin。
  2. 在弹出窗口里选 Kindle for Mac/PC ebooks,然后点左边的加号按钮,也就是 Create new Kindle for Mac and PC key。我猜这里是读取了 Kindle for Mac 里的信息生成的 key。
  3. 选中生成的 key,然后点击右边的导出按钮保存为.k4i文件,并将文件上传到 Linux Server 上,再在 Server 的 Calibre 里打开同样的界面,导入该文件即可。

至于中文书嘛,现在 Kindle for Mac 也支持中国的亚马逊商店了,理论上应该也用同样的方法可以解决,不过我没有尝试过,而且不同国家要不断地切换不同的账户,也挺讨厌的。至于其他的国内电子书平台,我现在不知道有没有通用的解决办法呢。不过好在中文的文字类书的话,稍微排版一下应该就不会太难看了,而且价格相当便宜啊。之前尝试在多看里买了一本书来看,虽然不能去除 DRM,但是它本身提供的阅读体验还是挺让人满意的。

总而言之,单就 DRM 的问题来说的话,我其实两者都支持,只是对于 DRM 的实现的方式来说,对于现在的各家分治互不兼容的状况很不满意而已了。

Softmax vs. Softmax-Loss: Numerical Stability

$
0
0

一切起源于我在caffe的网站上看到的关于SoftmaxLossLayer描述

The softmax loss layer computes the multinomial logistic loss of the softmax of its inputs. It’s conceptually identical to a softmax layer followed by a multinomial logistic loss layer, but provides a more numerically stable gradient.

caffe 是当下一个很常用的 C++/CUDA 的 Deep Convolutional Neural Networks (CNNs) 的库,由于清晰的代码结构和设计,并且速度也很快,所以不论是学术界还是工业界,要做一些扩展工作的时候经常会选用它。当然现在随着 Deep Learning 的流行,相关的计算库也繁荣起来,许多知名的库大都有各自的特色,具体要选用哪一个的话还得看自己的需求而定。

不过今天我们主要是要围绕上面引用的那一段话来闲聊一下。中心思想是:在数值计算(或者任何其他工程领域)里,知道一个东西的基本算法和写出一个能在实际中工作得很好的程序之间还是有一段不小的距离的。有很多可能看似无关紧要的小细节小 trick,可能会对结果带来很大的不同。当然这样的现象其实也很合理:因为理论上的工作之所以漂亮正是因为抓住了事物的主要矛盾,忽略“无关”的细节进行了简化和抽象,从而对比较“干净”的对象进行操作,在一系列的“assumption”下建立起理论体系。但是当要将理论应用到实践中的时候,又得将这些之前被忽略掉了的细节全部加回去,得到一团乱糟糟,在一系列的“assumption”都不再严格满足的条件下找出会出现哪些问题并通过一些所谓的“engineering trick”来让原来的理论能“大致地”继续有效,这些东西大概就主要是 Engineer 们所需要处理的事情了吧?这样说来 Engineer 其实也相当不容易。这样的话其实 Engineer 和 Scientist 的界线就又模糊了,就是工作在不同的抽象程度下的区别的样子。

接下来闲话就不多说了,今天的主角 Softmax 其实并不一定要和 Deep Learning 有什么关系,在 Logistic Regression 里就可以看到它(当然反过来说经典的 Deep Neural Networks 顶层其实本来也就是一个 Logistic Regression 分类器。)。具体来说,Softmax 函数\(\sigma(z)=(\sigma_1(z),\ldots,\sigma_m(z))\)定义如下:

\[ \sigma_i(z) = \frac{\exp(z_i)}{\sum_{j=1}^m \exp(z_j)},\quad i=1,\ldots,m \]

它在 Logistic Regression 里其到的作用是讲线性预测值转化为类别概率:假设\(z_i = w_i^Tx + b_i\)是第\(i\)个类别的线性预测结果,带入 Softmax 的结果其实就是先对每一个\(z_i\)取 exponential 变成非负,然后除以所有项之和进行归一化,现在每个\(o_i=\sigma_i(z)\)就可以解释成观察到的数据\(x\)属于类别\(i\)的概率,或者称作似然 (Likelihood)。

然后 Logistic Regression 的目标函数是根据最大似然原则来建立的,假设数据\(x\)所对应的类别为\(y\),则根据我们刚才的计算最大似然就是要最大化\(o_y\)的值(通常是使用 negative log-likelihood 而不是 likelihood,也就是说最小化\(-\log(o_y)\)的值,这两者结果在数学上是等价的。)。后面这个操作就是 caffe 文档里说的 Multinomial Logistic Loss,具体写出来是这个样子:

\[ \ell(y,o)=-\log(o_y) \]

而 Softmax-Loss 其实就是把两者结合到一起,只要把\(o_y\)的定义展开即可

\[ \tilde{\ell}(y,z) = -\log\left(\frac{e^{z_y}}{\sum_{j=1}^m e^{z_j}}\right) = \log\left(\sum_{j=1}^m e^{z_j}\right)-z_y \]

没有任何 fancy 的东西。比如如果我们要写一个 Logistic Regression 的 solver,那么因为要处理的就是这个东西,比较自然地就可以将整个东西合在一起来考虑,或者甚至将\(z_i=w_i^Tx+b_i\)的定义直接一起带进去然后对\(w\)\(b\)进行求导来得到 Gradient Descent 的 update rule,例如我们之前介绍 Gradient Descent 的时候举的两类 Logistic Regression 的例子就是这样做的。

反过来,如果是在设计 Deep Neural Networks 的库,则可能会倾向于将两者分开来看待:因为 Deep Learning 的模型都是一层一层叠起来的结构,一个计算库的主要工作是提供各种各样的 layer,然后让用户可以选择通过不同的方式来对各种 layer 组合得到一个网络层级结构就可以了。比如用户可能最终目的就是得到各个类别的概率似然值,这个时候就只需要一个 Softmax Layer,而不一定要进行 Multinomial Logistic Loss 操作;或者是用户有通过其他什么方式已经得到了某种概率似然值,然后要做最大似然估计,此时则只需要后面的 Multinomial Logistic Loss 而不需要前面的 Softmax 操作。因此提供两个不同的 Layer 结构比只提供一个合在一起的 Softmax-Loss Layer 要灵活许多。从代码的角度来说也显得更加模块化。但是这里自然地就出现了一个问题:numerical stability。

首先我们来看一下在神经网络中进行 gradient descent 的时候所谓的“Back Propagation”是什么意思。例如图中所示的一个 3 层神经网络,除了最开始的数据层\(L^0\)之外,每一层都有输入节点和输出节点,我们用\(I^1_2\)表示第一层的第二个输入节点,\(O^1_3\)表示第一层的第三个输出节点,每一层的输入和输出节点数量并不一定要一样多,但是通常情况下某一层的输入节点只是上一层的输出节点的“复制”,比如\(I^2_3=O^1_3\),因为所有的计算操作是发生在每一层结构内部的。对于普通的神经网络,通常每一层进行的计算都是一个线性映射再经过一个 sigmoid 的非线性操作\(\mathsf{S}\),例如:

\[ O^1_i = \mathsf{S}\left(\sum_{j=1}^3w^1_{ij}I^1_j + b^1_{i}\right) = \mathsf{S}\left( \langle w^1_i,I^1\rangle + b_i^1 \right) \]

后面是写成向量/矩阵的形式,一般会显得更简洁。现在如果要对参数\(w^1_{ij}\)进行求导以计算它的 gradient 来进行 gradient descent 一类的参数优化,利用微积分里的Chain Rule可以得到如下的式子:

\[ \frac{\partial f}{\partial w^1_{ij}} = \sum_{k=1}^3 {\color{red}{\frac{\partial O^1_k}{\partial w^1_{ij}}}}\cdot{\color{blue}{\frac{\partial f}{\partial O_k^1}}} \]

注意到红色的部分是和第一层网络的内部结构相关的,只需要知道该层的局部结构就可以进行计算,而蓝色的部分,由于我们刚才说了输出节点其实等于下一层的输入节点,所以其实是\(\partial f/\partial O^1_k = \partial f/\partial I^2_k\),这个是可以在“上面”的第二层进行计算的,而不需要知道任何关于第一层的信息。

因此整个网络的参数的 gradient 的计算方法是从顶层出发向后,在\(L^p\)层的时候,会拿到从\(L^{p+1}\)得到的\(\partial f/\partial I^{p+1}\)也就是\(\partial f/\partial O^p\),然后需要做两个计算:首先是自己层内的参数的 gradient,比如如果是一个普通的全连通内积层,则会有参数\(w^p\)和 bias 参数\(b^p\),根据刚才的 Chain Rule 式子直接计算就可以了,如果\(L^p\)层没有参数(例如 Softmax 或者 Softmax-Loss 层就是没有参数的。),这一步可以省略;其次就是“向后传递”的步骤,同样地,根据 Chain Rule 我们可以计算

\[ \frac{\partial f}{\partial I^p_i} = \sum_{k=1}^3\frac{\partial O^p_k}{\partial I^p_i}\cdot\frac{\partial f}{\partial O^p_k} \]

计算出来的\(\partial f/\partial I^p\)将会作为\(\partial f/\partial O^{p-1}\)传递到\(L^{p-1}\)层,整个过程就叫做Back Propagation,其实说白了就是 Chain Rule,只是涉及的符号有点多,容易搞混淆。

这里顺便可以跑题提一下在 Deep Learning 里经常会听到的Vanishing Gradient 问题,因为 back propagation 是用 chain rule 将导数乘到一起,粗略地讲,如果每一层的导数都“小于一”的话,在层数较多的情况下很容易到后面乘着乘着就接近零了。反过来如果每一层的导数都“大于一”的话,gradient 乘到最后又会出现 blow up 的问题。人们发明了很多技术来处理这些问题,不过那不是今天的话题。

搞清楚 Back Propagation 之后让我们回到 Softmax-Loss 层,由于该层没有参数,我们只需要计算向后传递的导数就可以了,此外由于该层是最顶层,所以不用使用 chain rule 就可以直接计算对于最终输出(loss)的导数。回忆一下我们刚才的 notation,Softmax-Loss 层合在一起的时候我们用\(\tilde{\ell}(y,z)\)来表示,它有两个输入,一个是 true label \(y\),直接来自于最底部的数据层,并且我们不需要对数据层做任何的 gradient descent 参数更新,所以我们不需要像那个输入进行 back propagation,但是另外一个输入\(z\)则来自于下面的计算层,对于 Logistic Regression 或者普通的 DNNs 下面会是一个全连通的线性内积层,不过具体是什么我们也不需要关心,只要把\(\partial \tilde{\ell}/\partial z\)计算出来丢给下面让他们自己去算后面的就好了。根据普通的微积分知识,我们很容易算出:

\[ \frac{\partial \tilde{\ell}(y,z)}{\partial z_k} = \frac{\exp(z_k)}{\sum_{j=1}^m\exp(z_j)} - 1 = \sigma_k(z) - \delta_{ky} \]

其中\(\sigma_k(z)\)是 Softmax-Loss 的中间步骤 Softmax 在 Forward Pass 的计算结果,而

\[ \delta_{ky}=\begin{cases}1 & k=y\\ 0 & k\neq y\end{cases} \]

非常简单对吧?接下来看如果是 Softmax 层和 Multinomial Logistic Loss 层分成两层会是什么样的情况呢?继续回忆刚才的记号:我们把 Softmax 层的输出,也就是 Loss 层的输入记为\(o_i=\sigma_i(z)\),因此我们首先要计算顶层的

\[ \frac{\partial \ell(y,o)}{\partial o_i} = -\frac{\delta_{iy}}{o_y} \]

然后我们把这个导数向下传递,现在到达 Softmax 层,在 apply chain rule 之前,首先计算层内的导数

\[ \begin{aligned} \frac{\partial o_i}{\partial z_k} &= \frac{\delta_{ik}e^{z_i}\left(\sum_{j=1}^me^{z_j}\right) - e^{z_i}e^{z_k}}{\left(\sum_{j=1}^me^{z_j}\right)^2}\\ &= \delta_{ik}o_k - o_io_k \end{aligned} \]

如果用 Chain Rule 带进去验算一下的话:

\[ \sum_{i=1}^m \frac{\partial o_i}{\partial z_k}\cdot\frac{\partial \ell(y,o)}{\partial o_i} = o_k - \delta_{yk}\cdot\frac{o_k}{o_y} = o_k - \delta_{yk} \]

和刚才的结果一样的,看来我们求导没有求错。虽然最终结果是一样的,但是我们可以看出,如果分成两层计算的话,要多算好多步骤,除了计算量增大了一点,我们更关心的是数值上的稳定性。由于浮点数是有精度限制的,每多一次运算就会多累积一定的误差,注意到分成两步计算的时候我们需要计算\(-\delta_{iy}/o_y\)这个量,如果碰巧这次预测非常不准,\(o_y\)的值,也就是正确的类别所得到的概率非常小(接近零)的话,这里会有 overflow 的危险。下面我们来实际试验一下,首先定义好两种不同的计算函数:

  1. function softmax(z)
  2. #z = z - maximum(z)
  3. o=exp(z)
  4. returno/sum(o)
  5. end
  6. function gradient_together(z,y)
  7. o=softmax(z)
  8. o[y]-=1.0
  9. returno
  10. end
  11. function gradient_separated(z,y)
  12. o=softmax(z)
  13. o_z=diagm(o)-o*o'
  14. f_o=zeros(size(o))
  15. f_o[y]=-1.0/o[y]
  16. returno_z*f_o
  17. end

然后由于 float (Float32) 比 double (Float64) 的精度要小很多,我们就以 double 的计算结果为近似的“正确值”,然后来比较两种情况下通过 float 来计算得到的结果和正确值之差。绘图代码如下:

  1. usingDataFrames
  2. usingGadfly
  3. M=100
  4. y=1
  5. zy=vec(10f0.^(-38:5:38))# float range ~ [1.2*10^-38, 3.4*10^38]
  6. zy=[-reverse(zy);zy]
  7. srand(12345)
  8. n_rep=50
  9. discrepancy_together=zeros(length(zy),n_rep)
  10. discrepancy_separated=zeros(length(zy),n_rep)
  11. fori=1:n_rep
  12. z=rand(Float32,M)# use float instead of double
  13. discrepancy_together[:,i]=[begin
  14. z[y]=x
  15. true_grad=gradient_together(convert(Array{Float64},z),y)
  16. got_grad=gradient_together(z,y)
  17. abs(true_grad[y]-got_grad[y])
  18. endforxinzy]
  19. discrepancy_separated[:,i]=[begin
  20. z[y]=x
  21. true_grad=gradient_together(convert(Array{Float64},z),y)
  22. got_grad=gradient_separated(z,y)
  23. abs(true_grad[y]-got_grad[y])
  24. endforxinzy]
  25. end
  26. df1=DataFrame(x=zy,y=vec(mean(discrepancy_together,2)),
  27. label="together")
  28. df2=DataFrame(x=zy,y=vec(mean(discrepancy_separated,2)),
  29. label="separated")
  30. df=vcat(df1,df2)
  31. format_func(x)=@sprintf("%s10<sup>%d</sup>",x<0?"-":"",int(log10(abs(x))))
  32. the_plot=plot(df,x="x",y="y",color="label",
  33. Geom.point,Geom.line,Geom.errorbar,
  34. Guide.xticks(ticks=int(linspace(1,length(zy),10))),
  35. Scale.x_discrete(labels=format_func),
  36. Guide.xlabel("z[y]"),Guide.ylabel("discrepancy"))

这里我们做的事情是保持\(z\)的其他坐标不变,而改变\(z_y\)也就是对应于真是 label 的那个坐标的数值大小,我们刚才的推测是当\(o_y\)很接近零的时候会有 overflow 的危险,而\(o_y=\sigma_y(z)\),忽略掉 normalization 的话,正比于\(\exp(z_y)\),所以我们需要把\(z_y\)那个坐标设成绝对值很大的负数。在得到的图中我们可以看到以整个数值范围内的情况对比。图中横坐标是\(z_y\)的大小,纵坐标是分别用两种方法计算出来的结果和“真实值”之间的差距大小。

首先可以看到的是单层直接计算确实比分成两层算要好一点,不过从纵坐标上也可以看到两者差距其实非常小。往左边看的话,会发现黄色的点没有了,那是因为结果得到了NaN了,比如\(o_y\)由于求一个绝对值非常大的负数的 exponential,导致下溢超出 float 可以表示的小数点精度范围,直接变成 0 了,此时\(1/o_y\)就是Inf,当要乘以\(o_y\)进行 cancel 的时候得到\(0\times \infty\),对于浮点数这个操作会直接得到NaN,也就是 Not a Number。反过来看蓝线的话,好像有点奇怪的是越往左边好像反而变得更加精确了,其实是因为我们的“真实值”也 underflow 了,因为 double 虽然比 float 精度高很多,但是也是有限制的。根据Wikipedia,float 的精度范围大致是\(10^{-38}\sim 10^{38}\),而 double 的精度范围大致是\(10^{-308}\sim 10^{308}\),大了很多,但是我们不妨来看一下图中的\(-10^2\)这个坐标点,注意到

\[ e^x=10^{x/\log 10} \]

所以\(\exp(-10^2)\approx 10^{-44}\),对于 float 来说已经下溢了,对于 double 来说还是可以表示的范围,但是和 0 的差别也已经如此小,在图上已经看不出区别来了。指数再移一格的话,\(\exp(-10^3)\approx 10^{434}\),会直接导致 double 也 underflow,结果我们的“真实值”也会是零,所以“误差”直接变成零了。

比较有趣的是往右边的正数半轴看,发现到了\(10^2\)之后蓝线和黄线都没有了,说明他们都得到了NaN,不过这里是另一个问题:对一个比较大的数求 exponential 非常容易发生 overflow。还是用刚才的式子可以看到\(\exp(10^2)\approx 10^{44}\),已经超过了 float 可以表达的最大上限,所以会变成Inf,然后在 normalize 的一步会出现Inf/Inf这样的情况,于是就得到NaN了。

这个问题其实也是有解决办法的,我们刚才贴的代码里的softmax函数第一行有一行被注释掉的代码,就是在求 exponential 之前将\(z\)的每一个元素减去\(z_i\)的最大值。这样求 exponential 的时候会碰到的最大的数就是 0 了,不会发生 overflow 的问题,但是如果其他数原本是正常范围,现在全部被减去了一个非常大的数,于是都变成了绝对值非常大的负数,所以全部都会发生 underflow,但是 underflow 的时候得到的是 0,这其实是非常 meaningful 的近似值,而且后续的计算也不会出现奇怪的NaN

当然,总不能在计算的时候平白无故地减去一个什么数,但是在这个情况里是可以这么做的,因为最后的结果要做 normalization,很容易可以证明,这里对\(z\)的所有元素同时减去一个任意数都是不会改变最终结果的——当然这只是形式上,或者说“数学上”,但是数值上我们已经看到了,会有很大的差别。

这就是本文的全部啦!如果想了解更多计算机浮点数值计算上会碰到的各种各样的问题,也许在这本书里会有更多的内容:《Numerical Computing with IEEE Floating Point Arithmetic: Including One Theorem, One Rule of Thumb, and One Hundred and One Exercises》。

最后,julia 允许 unicode 的变量名,于是可以写各种带数学符号的变量名了!而且vim 的 julia 插件有一个非常方便的功能就是能够将 LaTeX 的符号命令补全成对应的 unicode 符号,比如输入\nabla然后按 Tab,就会变成,非常方便。但是不得不念念碎一下的是很多地方还有待改进,比如现在加载一个像 Gadfly 绘图库这种规模的 package 简直就是要等到天荒地老,另外像这种没有事先编译的语言,哪里写错了不到运行到那里的时候都发现不了错误,可以想象我只是要写一个小的绘图 script 而已,写完运行,等个 N 秒终于把绘图库加载进来了然后碰到一个 typo,出错了,修掉 typo 再运行,又是一轮等待,然后又碰到一个 typo……当然我写代码比较粗心是我的问题,但是这种时候不得不就开始怀念编译型语言啊。不过听说现在正在开发的 0.4 版的一个重要内容就是静态预编译,这个功能实现之后各种库应该都能做到瞬间加载。

另外还想吐槽的是,julia 里轻量的 coroutine 和强大的宏虽然是两大卖点,但是却也还是要掂量着点用啊。最主要的问题就是错误报告,之前尝试过用 coroutine 来写一个东西,由于没有编译期错误检查,即使是很傻的代码错误也得等到运行期抛出异常来排查,结果用了 coroutine 之后,经常都在 stack trace 里找不到正确的出错行号。还有宏展开也是好像时不时会把错误汇报的行号搞乱掉。嘛,不过这些东西本来也就是双刃剑了,就像 C++ 的 template 用来做模板元编程如果出错的话也是会打印出几千页的编译错误的。

2014 明天的记忆

$
0
0

从 2009 年开始不知不觉养成以孙燕姿的一首歌作为年度总结贴的标题的习惯:

今年是“新”歌《明天的记忆》。

回忆的泥土让生命有厚度

2014 年,猛然一念间,好像发生了很多很多的事情,至少周围的人都发生了各种各样的改变,比如好多人结婚哈哈,确实是在这样一个时间点上吧。但是关于自己,好像有很多事情但是又不知道从何回忆起。拿了驾照(虽然 license 还没寄到);考了日语 N2(虽然过不过还要再等几个月才知道);跑了意大利日本新加坡(虽然还没有完全明白旅行的意义);放下了以前的心结谈了一场异国恋(虽然总共持续不到一年并且最后是 bad ending);一口气戒掉了人人微博朋友圈脸书 Twitter 之类各种社交网络(虽然因此变得喜欢刷Hacker News了并且似乎看动漫的数量明显增加);终于动手学了一点 CUDA 编程和搞了一点 Deep Learning 相关的东西(虽然学术方面进展似乎更加缓慢了)……一晃一眨眼间,不过既然平时从来不管我的 advisor 都突然问你有没有想好 PhD Thesis 的 topic 了没,我才突然意识到过去了的,是一瞬,同时也是一整年。

让明天把今天给记住不是因为孤独
因为我们追求的专注不管它起起伏伏
让今天把明天变特殊未必因为幸福
因为我们努力不服输从来不曾退出

想要从头回忆起来,但是却不知源头在哪里。上半年的时间我在做些什么呢?看自己的 blog,发现从一月到六月中间间隔了五个月没有任何音讯。努力回想的话,应该是在去年年末回到了国内办理签证,虽然经常被小伙伴说我办事“靠谱”,但是却发生忘记打印面谈预约确认页,以及带手机过安检被赶出来之类的事情……当然一如既往签证被 check。顺便和还在杭州的小伙伴们聚了一下。在家则是陪陪父母见见同学再看着家里的旧物件回忆回忆童年什么的。还有就是两人从时差六小时的两地再聚到一起变成时差零小时,看电影啊 K 歌啊吃东西啊逛街啊画画啊游西湖啊之类的总之就是情侣该干的事情了,似乎并不是现在的状况可以很淡定地回忆的事情……不过要写年度总结的话这些事情也避不开,而且这部分倒也不是什么痛苦的回忆了。

接下去的春季学期没有发生太多事情估计也情有可原,因为那学期修的课里面有一门非常够呛。起因是报名了学校的暑期去日本实习的项目,项目要求一个是日语课程,另外一个则是至少要修一门和日本文化相关的课程,无耐各种“文化课”都和其他的事情和课程之类的时间各种冲突,最后找到的两个选项。

1
图 1

一个是在 Harvard 上的一个日本媒体相关的课,我跑去听了第一堂课,是非常小的一个班,从老师的课程介绍和大家依次做自我介绍的流程下来,最大的感觉就是“我不应该出现在这里”,因为似乎是非常专业的文科系的研讨课一类的,他们口里蹦出来的那些专业相关的词汇云里雾里不说,他们那种谈吐之间不断地引用某本某本书某篇某篇文献里的观点和论述的方式,我也只能是知难而退了。另一个选项则是在本校的 Political Science 开的一门叫做东亚政治关系的课,似乎没有什么 pre-requisite。事实证明也不是轻松的课,从此以后见到文科社科的同学估计都要表示膜拜了。虽然内容还是比较有趣的,主要分析冷战那一段时间的东亚各国之间的关系,但是每周几百页的英文阅读资料实在是有点够呛,不读当然是不行的,马马虎虎扫过去也不成,因为定期会有小测验考察阅读文献里的内容……所以以我那种慢悠悠的英文阅读速度,结果就是无时无刻不在读文献,不知道会不会这一个学期的英文阅读量要超过之前所有阅读量了吧?希望自己至少在速读方面也许有所进步了!

回想起来回到波士顿的时候正是学校的 IAP 短学期中,在春学期正式开始之前还做了一些有趣的事情。其中一个就是参加了 IAP 的弓道课程,虽然只是为期两天的集中入门训练了。大概由于场地的限制,学校是没有弓道俱乐部的,不过波士顿似乎有私人的训练场地。总之这个就是日本的弓道了,所以规则和流程都相当复杂,毕竟日本的体育项目很多都强调“礼儀正しさ”嘛,但是这种大弓真的很酷啊,特别是拉弓的时候先将双手举上头顶再往下张开来这个动作很是喜欢,在《犬夜叉》里应该看到过很多次了。实际证明同时也是比较需要臂力的运动。因为不仅要将弓拉开,而且保持箭架住不掉下来也需要在旋转方向施加力量,我射一轮下来如果不休息直接射第二轮的话,就会很够呛了。

总而言之 IAP 毕竟是各种好玩的活动云集的时段,可以说是我大技校的文化祭也不为过啊。不过中途杀回来能参加的活动也就有限了。

2
图 2

开学之前还有另外一件事情则是关于情人节的。因为异地异国时差等原因嘛,交互方式非常有限啊,所以交换照片也变得相对平常(所以那段时间我也玩起自拍了……)。当时决定在情人节开了一个小玩笑就是做了一个简易的电子小说风格的 app 给对方,在对方打开 app 和 UI 里的人物做一些无厘头的交互对话的同时,后台却偷偷地扫描照片目录把包含对方人脸的照片全部搜集起来。处于人道主义考虑并没有直接将这些照片回传回来,因为玩笑要有一个度嘛。不过最终对方并没有把找到的图片发给我,所以我也不知道这个程序的 out-of-sample generalization 的 performance 到底怎么样了。因为需要做到“不被发觉”的情况下能独立运行的程序,估计不能用 OpenCV 那种巨形库,没记错的话,最后是用的libccv来做 detection,recognition 并没有用 deep learning 的东西,而是用 vlfeat 抽取 Fisher Vector 之类的传统特征,手工标定了之前搜集到的对方的照片做了数据集,再训练了一个线性的 SVM 分类器。因为实际上在这之前我对人脸识别这方面的 literature 也并不了解了,做调研之前或者是甚至到最后完成之前我都还不是特别确定自己是否能够搞定,怎么能够独立运行,依赖最少的运行库,保证精度但是又要控制计算量,不要让 CPU 瞬间飙起来导致风扇也响起来之类的,还有比如照片由于 EXIF 元信息使得电脑里打开预览虽然是正的,但是直接把图片数据读出来其实是旋转 90 度的结果,以及如何利用异步计算避免前台打掩护的 GUI 进程假死之类的,等等之类的情况大概就是做 engineering 的东西和做 research 的东西的时候许多不一样的地方吧。最后居然发现学校还有专门的 Mac 机房的,于是在没有安装任何 dev tool 的 clean OS X 环境下最后测试修复之后,发给对方了。据说效果还不错,而且同时我这边也收到了非常用心的礼物,说起来大概是印象里收到过的礼物中最用心的一个吧,还有后面一点收到的生日礼物也是。

嘛,其实之前一直以为 vision 里人脸这一块现在已经做到极致了,没想到其实效果也并不如想象的好,比如 detection 方面好像就还并不是很 robust,或者说可用的工具还不够成熟,Google、Facebook 之类的厂商他们自己的相册里人脸检测的结果看起来倒是非常准的。苦恼于 libccv 的 general face detector 的精度问题,我也尝试过一些其他解决方案,有一些专门提供人脸方面的算法的 API,使用起来其实相当不现实,包括非常有名声的国内创业团队做的 Face++,本来很想用他们的 SDK 的,但是怎么也没找到怎么用,并且后来随便测试他们自己的 online demo 的时候也会发现有一些看起来很正常的图片也是会检测不出来的,所以还是继续 ccv 了。另外说起 Face++,感觉这一年开始周围的关于技术创业方面的对话也逐渐变得频繁起来,啊,不过关于这方面还是稍后再说好了。

3
图 3

总而言之,春季学期就这样过去了,其他的,也主要还是关于两个人的事情吧。整个过程其实也挺多波折的,各种争吵与不理解中,双方才渐渐开始学会适应这种远程交流和相处方式吧,还有一些外在因素,包括一些比较戏剧化的事情,以及突然意识到自己其实被卷入到非常错综复杂的关系中之类的。不喜欢复杂的关系,但是既然走到了一起,也希望能一起把这些事情理清楚。但是自己对感情处理的成熟程度其实也比自己预想的要低吧。然后就是她在申请的学校中做最后决定的时候,东部和西部,我告诉她她选择哪一边我都会很开心的,因为两边都是很不错的项目,虽然确实是自己的真是想法,但是好像又有一些推卸责任的感觉。我不太清楚这种情况是否应该明确表达希望两人在比较近的地方这样的意愿,因为我对人生的理解一直是“很多时候没有哪个选择是正确或错误的,所以最后人生的抉择总是需要自己来做的”。当然从另一个角度来说也许这也是我对未来没有很具体的规划的体现吧,所以在分手的时候她向我提出这样的质疑的时候我也无言以对。最终她选择了东部离我很近的地方,所以我觉得会很顺利地慢慢找到两人共同的道路,其实即使她选择西部我也并没有会觉得会不一样吧,不管我想法太天真也好还是我根本就没有认真考虑过具体的未来也好,不想把这个年度总结搞成了情感总结,不过在后来我确实想了很多,就是关于自己的生存方式的问题。

自己关于抉择问题的观点毫无疑问是家庭教育的结果——初中以后就离开家在外读书,然后家里也就再没有干预过我自己对各种重大问题的决定。而关于未来的规划,大概从小到大一直在读书基本上就是顺其自然的道路走下来,也就养成了没有去仔细做规划的习惯吧,另一方面的原因是特别是在长大以后生活中经常会碰到一些完全没有意料到的事情,惊喜也好变故也好,让我渐渐开始觉得长远规划有点不太现实,于是自己更倾向于制定相对短期的目标,以及基于我异常广泛的兴趣爱好试图比较泛泛地打好自己的基础,然后在(某个我可能从未预料或者期待过的)机会到来的时候能够比较果断地下决定并有能力抓住它。到目前为止自己的人生轨迹基本上都是以这样的方式走过来的。然而在那样的情况下面对那样的质疑,也让我狠狠地重新思考了一下这些问题,自己的生存方式是不是太过偏执,可惜并没有得出什么具体的结论。

接近期末的时候去了一趟意大利,在佛罗伦萨的会议。顺便逛了一下,佛罗伦萨是一个小镇风情的感觉,步行就能逛完,但是却也确实非常耐看,建筑啊雕塑之类的,遍地都是文化的感觉,可惜不懂得意大利语,很多东西也不知道是什么意思。回来之前还去了一趟罗马,虽然从文化、建筑上依然非常令人震撼,但是从城市本身来说就和佛罗伦萨是完全不一样的感觉,怎么说呢,广告、骗子遍地的那种感觉吧。可能是因为在斗兽场那里被勒索了 20 欧在车站也碰到一堆小孩骗子要钱,所以印象不是特别好了吧?:p但是去梵蒂冈的时候似乎是碰到教皇出现,体验了一把“一个国家被人一个挨一个站满”的感觉。在罗马也是第一次住青年旅社,虽然订的时候是订了男生寝室,最后不知道怎么变成混合的了,但是好像也并没有什么违和感,总之就是大家各自睡觉就是了……累了一天也没有精力去关注周围的环境直接倒下就睡了。

从意大利回到学校之后一周就立刻跑去日本了。之后的 90 天的日本滞留,从各种各样的意义来说都将是非常难忘的一段经历,然而我现在已经开始淡忘了,比如我去“天下一品”的话都会点什么拉面,看来记忆力真的是不太行了呢。暑假同去日本的小伙伴说从没见过我那么开心的样子。然而另一方面却又是心理黑暗期,基本上到了得给自己灌心灵鸡汤来维持心跳的地步了。

4
图 4

去日本是通过学校的 MISTI 项目,可以到全世界各地去实习,如果 Host 不提供实习工资的话,学校方也会提供 funding 支持,简直再没比这更好的事情了,就只看你愿不愿意“浪费”掉一个暑假跑到外面去了。只要过了语言方面的基本要求,申请上基本没有什么悬念,联系了京大一位老师作为 Host,同时还说服了另一只关系挺好的小伙伴也去了京大,当然 MIT 这边今年通过 MISTI 去日本的一共应该有超过 20 人了,大部分都是本科生,许多都有一起上过日语课,到了那边也时常会聚一聚。

到学校之前先去了东京附近一个叫做湘南的地方,因为当时正好那里有一个 deep learning 相关的 workshop,老板是 co-organizer,反正刚好在日本,就问他能不能也让我去开开眼界。于是我收到了 invitation,然后一看邀请名单吓哭了,全是 Professor 什么的,就我一个 Mr.……^_^bbb不过到的人许多其实并不是正儿八经地在搞 deep learning 的,所以会议的主题其实有点散了。特别是有一些比较偏 neural 的听不太懂。会议在一个偏远的会议中心开,组织得挺不错,各种方式鼓励大家交互,像和Information Geometry的发明人拼乒乓球这种事情估计平时是不太会碰到的。总之我也是误打误撞了。当时也有理研的人在,谈及那件涉嫌学术造假的事件他们很回避。

湘南会议中心那里可以看到海对面的富士山,这大概是我这次在日本和富士山最“近距离”的一次接触了。湘南之后直接前往京都。从一开始到达就对日本印象特别好,食物、环境、公共设施等等各方面。虽然我的日语比我的英语生涩不知道多少倍,但是第一次到这个国家比初到美国的时候要放松很多。

不过我的烦恼也从到达湘南就开始了。因为 workshop 是非常 intense 的,我也不好意思在一堆大牛认真讨论的时候拿出手机来聊天,所以当时女朋友对我表达了一些不满。到京都之后我试图约她通电话两人仔细沟通一下,但是一直被回避,直到最终分手两人也没有通过话。总之暑假里对方的态度变化让我非常难以理解,当然我也能想出一些理由,比如忙毕业又忙项目之类的,所以对于各种被选择性地回避和无视好像也没有办法,更直接的沟通请求也一直是无视状态,但是又并不是完全不理不睬,所以我也总能找一些理由来说服自己,当然同时内心是异常痛苦的。在京都的时候时常漫无目的地在大街小巷闲逛,京都是个很耐逛的地方,我很喜欢在那里逛,偶尔还会和碰到的当地人聊几句。不过之所以会想出去走啊走啊一直不停地走下去,也是因为内心太压抑了。

有很多次想说这一句的,但是总觉得虽然时间短暂,但是都一起走到这一步了也不想随便放弃。于是就自己每天在矛盾中挣扎,直到给自己灌了很多心灵鸡汤之后决定采取相对积极一点的态度,在网上买各种礼物之类的。总之最后在某次组会上受到她的邮件说她想清楚了的时候,虽然算是晴天霹雳一般,但是那么一瞬间也有一种如释重负的感觉。尝试了各种方式挽回并没有结果,或者说只是变得更糟糕吧,本来想在后面的时间找机会去慢慢地挽回,但是对方显然将自己的意愿表达得非常坚决,甚至(在我个人看来)做法有点过分了,我也就放手了。那个时候大概是 7 月吧,非和平的分手。大概也是因为前半个暑假对自己的情绪压抑太过了的惯性,当天自己真是出奇的镇定,不过很开心地好朋友们都腾开手边的事情和我煲了一通电话,其实也就说些有的没的聊一些大家近来的生活,但是聊聊天真的舒缓很多,很感动呢。好朋友们都挺担心我,大概是因为我上一次碰到这种事情花了好几年才解开心结的缘故吧。不过这一次差别很大啊,大概自己也看得更开一些吧,如果两人不合适,那就各走各的呗,感谢一直以来的陪伴。就这样。

当然理性上看开了和感性上平复下来还并不是直接对等的,两人一起走过的时间,大概互相人格里都印上了一些对方的影子,我没法也不需要去否定过去的这一段时光,所以只是需要一点时间啦。划掉了之前比较常规路线的双人关东关西游览路线,制定了一条从九州南部的种子岛一路向北贯穿到北海道的奔袭路线,决定好好地散一散心。

总之由这件事情直接引起的两件事情,一个是后面非常难忘的贯穿日本之旅,二就是我终于如愿戒掉社交网络了。因为最后的一些争执言语中实在有点触到我自尊心底线,所以我也希望分开了就不要再有任何瓜葛了,但是总觉得跑去各种社交网络上把对方拉黑这件事有点幼稚(好像“觉得这件事情很幼稚”这件事情也蛮幼稚的哈。),但是看到对方的动态又会打乱慢慢恢复的心情的节奏,但是一下子要全部戒掉也不太容易啊,所以就转移了一下,避开她经常用的那些平台,跑到脸书之类的上面去水,结果到秋学期的时候渐渐就对社交网络整体淡化了,并不是经常会想去上而忍着不上,而是除非邮箱里有邮件说谁 at 我了之类的否则我都不太会想起来还有这些东西了的样子,我也不太清楚这样的转变是如何发生的,大概是因为我不再纠结“可能会错过好朋友的消息啊或者某些有用的资讯啊”之类的问题了吧——毕竟取舍总是要的。所以小伙伴们结婚什么的我经常都不知情没有送上祝福也是抱歉!不过戒掉社交网络也一直是我想做的事情,意外地完成了,并且没有很暴力地采用注销之类的方法,如果有人找我或者自己有什么事情的时候还是会登陆上去的。当然副作用也并不是没有的,虽然我也不知道是否有直接关联了,但是我下半年看动漫的次数明显变多了,同时追五六部新番动画片这样的事情在我人生中还是第一次出现……

5
图 5

再就是旅行的事情了。这个也是第一次,第一次自发地计划并实施旅行,从对要去哪里都毫无概念开始,去网上和书店查询各种旅行攻略,我还尝试问了一些日本人,发现他们很多人其实去过的地方也很少很局部。制定目的地和路线,订住的地方等等,其实还是相当花时间的。主要是我去的地方也不少了,大致路线是从东京出发(当时因为我京都的 Host 跑去法国了,于是我跑去东京的一个实验室做了三个星期的访问),新干线去名古屋,然后从名古屋那边的中部国际机场直接飞到南九州的鹿儿岛,名古屋那边的机场也挺有意思,候机厅可以直接到一个非常宽阔的室外平台去。鹿儿岛滞留期间去了附近的樱岛,是一座活火山,那里有产巨大的萝卜和很小的蜜桔。然后是种子岛:《秒速五厘米》中宇航员一段的场景所在,还有《机器人笔记》的舞台。还有 JAXA 种子岛航天中心。看到很漂亮又没有什么人的海滩,没有带专门的游泳裤但是还是直接冲到海里去了,第一次下海,海水果然好咸。

回去的路上被 Google Map Cache 和 GPS 误导跑到路上长满野草的深山里,好不容易回到大路上结果在路中间看到龟……还有野猫什么的,我打量了一下觉得应该是海龟吧?就把他带回港口丢到海滩上了,回去的途中还碰见另外一只,也是横在路中间,当地的居民好像也习以为常,开车过的时候也都让着它们。

之后又去了屋久岛:《幽灵公主》原型的苔藓森林就在那里。并且凑巧还碰到了鹿儿岛南部一个小镇举行的夏日祭,跑去凑了一番热闹。之后北上去熊本,因为听说熊本拉面很好吃,结果在体验到了非常壮观的浓烟滚滚的阿苏火山口。然后新干线去广岛看原爆纪念馆,正好碰上车站很多人穿着红色衣服,发现当晚有棒球比赛,也跑去凑热闹,一边看比赛一边学习规则。还在宫岛看到了传说中的海上神社,以及比奈良鹿子更有趣的宫岛鹿。路上碰到以为京大毕业的前辈,聊了很久,她对中国的事情也知道很多,说很想去看九寨沟,还说她知道她的姓“市場”的中文念法,是 market 的意思,我问她那日文里是什么意思,她说日本人的姓都没有具体的意思,只是名字才会有附加意义。

之后离开新干线的范畴坐 JR 特急八云号到出云,那里的出云大社很有名,日本的月份里有一个月叫做神无月,因为那个月里八百万神全都去出云开会去了,所以神无月在出云又叫做神在月,“神在”的音最后逐渐演变成日本一种常见的叫做ぜんざい的传统点心,在东京认识的一个在大学学佛教专业的小朋友有买给我吃过,吃起来感觉像很甜的豆粥。嘛,不过我主要是去拜访一下出云阿国的墓地的。

出云阿国据传是日本歌舞伎的创始人,据说她当时为了筹措出云大社的修缮费用,创立了歌舞伎这一种艺术形式,在京都表演,成为传奇。在京都的时候在河原四条那里有看到过她的雕像。总之我很敬佩这样的女子啊。

6
图 6

出云之后跑去鸟取,去那边主要是去看一个叫做北荣町的柯南小镇,是非常偏远的地方,车站没有自动门,我去的时候也没有人,只看到挂着牌子写着请把车费投到箱子里,甚至在去之前尝试找住宿的地方也难了我一把,没有任何网上可以预定的住处,好不容易找到一个旅馆电话,通过 Google Voice 打过去(我没有日本本地手机),对方只问了我国籍就把电话挂了,结果最后我到那边的时候那位老奶奶还真知道是我。但是非常有意思的一个小镇,从车站开始就到处都是柯南的雕塑和海报,小镇本身也靠海,宁静的沙滩没有人山人海,我躺在沙滩上看日落和天边的船只的信号灯,旁边的树林里有几家镇民在做露天烧烤。

鸟取还有一个巨大的沙丘海滩也比较有意思,大概到真正的沙漠里会更绝望吧:明明很短的距离,但是要费很大的劲才能走到,特别是往上爬的时候。在沙丘里爬了半天,后来回到地面上的时候,才突然意识到能双脚踩着踏实的地面这样“天经地义”的事情其实也是一种“福分”呢。去的时候旁边还在举行世界古代文明主题的大型沙雕展览,那几天是俄罗斯文明的展出,非常有意思。

从鸟取往南回到新干线的主干道上,到达神户,品尝了传说中的神户牛肉,第二天本来是要去看孙中山纪念馆,结果上错车了,是开去姫路的,于是索性去看了传说中的姫路城,由于天守阁正在修缮,所以有一片不能参观,但是看到了一个非常巨大的糖果做的姫路城的模型……非常好吃的样子。

之后回到京都暂时休整(主要是法国的 Host 临时回来了一趟,我要是不回去那个暑假就再没机会见他了)。由于我是直接从东京开始绕到南部岛屿,再辗转回到京都大本营的,所以有一个小问题就是其实我是拖着去东京生活三个星期用的行李去旅行的。好在我一向是行李极简主义者,所谓全部家当其实就是一个背包和一个斜挎包而已。

而且日本到处都有非常便利的 coin locker,我也不用扛着全部家当跑来跑去的。倒是行李里的一些奇怪物品(比如六孔插线板)中间起了挺多作用……实际上在京都修正之后的北海道之旅听起来更恐怖,因为那是我在日本的最后几天,最终我要从东京起飞,所以中途不会再回京都,于是我是真正拖着全部直接回美国的家当游北海道的——行李极简主义者的优越感顿时体现出来了。XD

JR Pass 的七天期限已经在南部用光了,而且新干线也只能通道青森而已,北海道要到 2015 才开通,所以决定飞过去。由于京都没有机场,从旁边的大阪起飞到新千岁机场。之后先去小樽,当晚去看了哆啦A梦 3D 版《Stand By Me》的首映。第二天正好正碰到小樽在举办风铃浴衣祭,小镇上的各种玻璃制品店和八音盒店都挂满了风铃,童话般的小镇吧,还看到浴衣时装大赛。小樽下一站是美瑛富良野,但是那边没有能找到合适的住宿,就住在旭川,和另一个小伙伴在那里汇合,悲剧地半夜聊到四点多,第二天一早坐火车去美瑛,因为他头一天已经去过美瑛和富良野了,所以路也比较熟悉,他说还想再逛一遍美瑛丘陵,于是我们在那里租了自行车。日本很流行那种带电动助力的自行车,上坡很省力。租一天大概要 3000 日元的样子,但是是还车的时候付钱,租的时候只要写下名字和国籍,什么证件押金之类的都不用就可以把车骑走了…………

美瑛非常漂亮,小伙伴是 Clannad 迷,看到一片向日葵田的时候停下来用手机开始播放插曲《小小的手心》。走完超广角之路之后他由于要往回赶就先离开了,我回到租车的店换了一张拼布之路的地图继续逛。一直到下午赶回车站坐车去富良野,小伙伴说他去那边看的时候薰衣草全都谢了没有什么好看的,但是我已经在那边订好了住宿,所以晚上还是得去那里,到那边的时候下起小雨,虽然是盛夏但是北海道的雨天也冷了起来,我在一个滑雪旅店留宿一晚之后第二天一早直接启程去函馆。富良野到函馆要坐 7 小时的火车,我虽然买了 JR 北海道 Pass 可以换指定席,但是那段时间好像是北海道旅行旺季,我跑去车站问票的时候都没有,只有去自由席找座位,结果发现很多人站着,当然和我在国内坐过的火车的拥挤程度还是没得比的。不过一路也很有趣,因为我从名古屋开始就在各种交通工具辗转的时候拿着笔画周围的人。铁路有很长一段一直是沿海的,中间还出现了海上彩虹,大家都很激动。

出现彩虹是因为有风雨,刚到函馆的时候那里正风起云涌,在车站问工作人员要怎么去函馆山的时候她们告诉我今天起风了缆车不开,我还想缆车原来这么不 robust 啊,吹点风就要停,结果一出车站差点整个人给卷到海里去了。不过纯属意外我之前定的行程也是在函馆留两晚,所以还是在第二天放晴之后到山顶看到了传说中的世界三大夜景之一。夜景的照片就不上了,确实很漂亮,但是我的手机拍不出什么效果来,于是拍了些人,很多很多的人,天还没黑就已经是这个样子了:

7
图 7

当然我在函馆呆两天并不是为了要看夜景,海鲜朝市、五稜郭、坂道等等,这里还有挺多有趣的地方,不过好像年度总结有点写成游记的嫌疑了我还是一笔带过吧。函馆之后去了洞爷湖,看了熊牧场,泡了温泉,吃到了非常美味的四川担担面。最后一站是札幌,不知为何在札幌的时候总是有种身在名古屋的错觉。在札幌的北海道厅旧址和一个工作人员老爷爷攀谈,他问我在哪里上学的,我说美国,然后他说,啊,厉害啊,该不会是 MIT 吧?……

除了我自己跑的以外,还有跟学校的小伙伴们一起去过奈良、箱根等地方。还有就是东京,很京都很不一样的城市,秋叶原并没有特别喜欢,虽然去了好几次但是都是为了给别人买礼物。倒是有一个叫做神保町的地方,聚集了 180 多家书店!!!我在那里买了一本日文译本的米兰·昆德拉的《相遇》,不知道要何年才看得懂。

从各种意义上来说是非常充实又非常累的一次旅行。住宿方面也是五花八门,基本上能找到什么就住什么,大约有一半是青旅,有那种整个就只有一间大屋,“你上去随便找个空着的床位”的男女混住的青旅,也有装修装饰都非常精美有趣榻榻米独立小隔间的青旅,还尝试过传说中的胶囊旅馆(略吓人),还有一些便宜的连锁酒店之类的。交通工具也是飞机火车汽车缆车电车高速船夜行巴士。

回到美国之后在纽约短暂滞留之后回到了 Boston。秋学期的计划是彻底调整好暑假的坏心情,考掉 JLPT N3,考掉驾照,完成 RQE Oral Defense。想考日语的主要原因是学校的日语课已经修到头了,但是又不想再这个挡头让好不容易入门的日语荒废掉,于是想报个等级考试督促一下自己学习。结果看到考试说明上写的只要做对 50% 就能过,果断弃掉 N3 直接报了 N2……在日本的三个月,其实并没有太多机会跟当地人长篇大论地用日语交流,但是平时的耳濡目染我感觉对语言水平提升还是蛮大的,主要是日常听力和口语方面。不过就督促自己学习这个目的来说的话基本上是完全失败了,虽然买了参考资料,但是最后基本就是裸考,更夸张的是,我在计划回国的时候完全忘记了这件事情,回国机票买了考试当天的机票,并且预约了回到国内第二天的签证面试,要不是这些东西都可以改时间,我这个名就白报了……

考驾照的计划是动员小伙伴们一起,但是大家都各自都很忙,一直拖着,有一天我终于决定要开始着手搞这件事情了,询问去年一起考 permit 的小伙伴,结果她说她看了一下 permit 上的日期,难道不就是去年的今天吗?我一阵黑线,最后还好发现 permit 的有效期是两年而不是一年……为了保险起见我学了很多次,最后约到回国之前几天的考试,大清早八点半,我到考点的时候还没有人,一群火鸡就在大路上晃悠……考试的过程很惊险,完全没有开过的车型,平行停车的时候我停在那里摸索了很久才搞清楚那个档位是怎么才能挂到倒档上的。其他还有各种情况,但是最后居然顺利通过了。也是非常幸运的事情!

RQE 虽然已经可以用之前做的东西来弄了,但是由于小伙伴们都决定下学期再搞,我也一下子没有动力了,想看看有没有更有趣的结果出来再说吧,于是就继续拖延了。结果这学期实验室一个只高我一届的学长一下子毕业了,庆祝会上老板扫视了一下大家,开玩笑道:“Who’s next?”大家一阵黑线……

8
图 8

不过当然压力挺大的。身边的不管是关系很好的小伙伴还是只是认识的人,也都发生着各种各样的事情,换导师、导师学术一年假、休学创业、还有要提前毕业去追寻自己的艺术理想的,等等等等……自己也很迷茫,老板过于 off hand 我也比较无奈,但是也并没有想要换导师的念头,最关键的是应不应该把学术上的进展缓慢和找不到方向归咎于导师的宽松政策,因为做研究似乎本来就是这样的,没有谁牵着你走,大部分时间是迷茫、失落、挫折。其实这次去日本原本的一个目的也是找一个比较年轻的 Host 体验一下比较紧密的师生合作关系的感觉是怎样的,不过 Host 有挺长一段时间不在(要不然我也没有机会满日本跑了……^_^bbb),而且其实整个暑假非常不在状态,从结果来看并没有做出什么有意思的东西来,但和 Host 坐在一起探讨整个东西的各种细节这样的经历还是让我觉得挺开心的。不过另一方面也认识到不论什么情况,其实最终最重要的还是要靠自己吧。否则再好的环境再好的机会也不一定能伸手就抓得住。

总而言之秋学期依旧是挺忙的,在日本的时候同一个本科小朋友订下来了回到学校之后要创立一个漫画俱乐部,找更多的人一起来画漫画。她画风很细腻,阴影很惊艳,在日本拿着本子到处画周围的人也是受她的影响了。不过结局两人都完全没有时间,只在学期初的时候碰了一个头。我甚至连上半年还在坚持的空手道部的活动也直接荒废了。

此外秋学期还去了一趟新加坡,也是开会。很幸运地拿到一篇 best student paper,不过虽然我是在二作但是其实对这篇论文的实质性贡献也非常有限。新加坡真是相当热的地方。吃的东西很赞。似乎法律相当严厉,以至于没有什么小偷之类的。入境卡片背面写着携带毒品入境直接击毙……机场里有一队一队持枪巡逻的人,每个人都要服兵役,并且还要定期回去服务个一个星期之类的,比如边防站岗或者前面说的持枪巡逻机场之类的,有一个当地人告诉我机场巡逻的活最难对付的是有些小姑凉要跑来和你自拍合影……^_^bbb新加坡是一个多民族国家,地铁上都是四种语言的标识,有一次在街头问路,我先试探地用英文问,结果说了一半对付表示听不懂我就换成中文,结果对方猛摇头,后来才发现原来是日本人。

9
图 9

期末的时候有小伙伴要去看五月花号,正好缺一个男生 share 酒店房间就拉我一起去了。就在麻州南部,一个小时的 bus 就到了。刚好是感恩节,去那里吃了一个很传统的 harvest dinner,那里的人装扮成十七世纪的模样,中途载歌载舞,还有一家子过来向同行的女生求婚(当然是表演节目而已),比较有意思,他就唱我家有多少头牛多少马车多少母鸡之类的,他家人就在后面附和。后面去参观两个村落遗址,一个是当地的美洲本地居民遗址,一个是随着五月花号过来建立的最初移民村落的遗址,都有人在那里生活并进行角色扮演。说实话这是我见过的最入戏的角色扮演,口音当然自不用说,对话后发现每个 NPC 都有自己的故事,并且他们还真在那里种菜、养鸡、做饭吃。

最后就是在学期快要结束的时候,开始弄一个东西,叫做Mocha.jl,简而言之就是 Julia 的一个 deep learning 库。取这个名字是因为最开始的设计很多都是参考 Caffe。起因原本是在实验中希望做一些和 deep learning 比较的东西,找了一下找到 caffe,因为一直想好好学一下 Julia,也想学一下 GPU 编程,所以临时决定做一个简单的 Julia 类似物,当时的想法就是花个三五天做一个最基本的东西玩玩,结果最后花的时间远远比自己想象的多,结果也比最开始的构思要完整得多,到最近也还在弄这个东西,反响还不错啦,在 github 统计的 Julia 语言的 package 的 monthly trends 里仅次于 Gadfly.jl。今天刚刚发布了 v0.0.6 版。总之回头有空会专门打一下广告的。

2014 年的画画方面,水彩画得很少,大概一两幅吧。有小伙伴毕业离开 Boston 的时候留给我了一箱画具,于是我回赠了闲置很久的 bamboo 绘图板。后面做的一些练习主要都集中在漫画风格方面,嘛,说是练习其实更多的时候都是散心用吧。

倒是有几个小伙伴今年好像在画画方面进步非常大,时不时会收到非常惊艳的作品 show off,很开心。:D

10
图 10

看书方面,读完了两本中译版的小说,一个是《白夜行》,似乎是在日本旅行的时候看完的,因为在日本的书店到处都看到东野圭吾的书在卖,就找了他的代表作来看,个人不是很喜欢。还有就是《十二国记》系列的《图南之翼》,很喜欢的系列里很喜欢的一本。《上帝掷骰子吗》,一本关于量子物理的历史回顾科普书。还有前几天看完的一个小册子《京都第五年》。

英文书看完了《Approximation Theory: From Taylor Polynomials to Wavelets》,很有意思的一本书,我在博客里介绍过。还有 Stein 的《Fourier Analysis》,这是作为秋学期旁听的一门课的课本,勉强算都看过了吧。《Anthropology of the Brain:Consciousness, Culture, and Free Will》是在图书馆无意中看到的一本书,到离校的时候只看了一半,还蛮有意思的,大致是讲 Consciousness 的形成并不只是在封闭的大脑之中,而是需要结合外部的符号、语言系统以及和其他人之间的交互,而这些外部的东西就像“假肢”一样。还有《Neuromancer》,非常经典的科幻小说,先看了一遍英文版,然后又看了一遍中文翻译版。

此外就是三本日文书。《怪人二十面相》是在日本的时候买的,是针对小学上级的全注音版本,所以看的时候不用频繁查词典了。其实如果忽略汉字的读音去猜意思的话,不需要注音也无所谓,但是那样以中文的方式来读就太没意思了,完全没有什么收获了。后面两本是冰果系列的第五部《ふたりの距離の概算》和第一部《氷菓》,这是正常的版本,因为是电子版,所以不知道读音的时候查词典也会相对方便一些,嘛,不过 iOS 和 OS X 的日文取词功能真的是非常难用,只能识别出原始的辞書型,词尾有任何变化都无法取词。前者基本上是在长途飞机上看完的,后者则是回到家之后感冒在床上休息的时候看完的。

当然有更多的只开了一个头,或者甚至从图书馆借来还没来得及翻开就得拿去还了(有些今年的新书还是我给图书馆提的 purchase suggestion)的……兴趣广泛碰到信息过载还真是不知道该怎么解决的好。当然另外一个原因也是自己专注程度还不够,说实话这一年浪费了很多时间来看动画片,当然也有几部很喜欢的片,我决定列一下,希望起到自我警醒的作用。

11
图 11
  • 《起风了》,宫崎骏,喜欢画风和片尾曲,剧情不评价。
  • 《野良神》,别人推荐的,喜欢片头曲的那种大色块画风。除了设定,主线剧情和结局已经不记得了。
  • 《颠倒的帕特玛》,很奇特的世界观设定,虽然剧情有点弱。
  • 《记录的地平线》第一、第二季,和《刀剑神域》完全不一样风格的网游相关的动画,很喜欢。演到第二季第 14 集的时候,女主角终于要隆重登场了。
  • 《龙珠Z:神与神》剧场版,我当时写的的评价是“炎发灼眼的孙悟空”,现在完全不记得任何东西了。
  • 《名侦探柯南:迷路的十字路口》剧场版,因为场景在京都,所以去贵船鞍马回来之后特地找来看了一下。
  • 《希德尼娅的骑士》星战科幻类,还蛮喜欢,记得有一次和小伙伴吃饭的时候讨论人进行光合作用的可行性,好像结论是能力不太够支撑人的活动。虽然是根据漫画改编的,但是觉得动画做得比漫画好。
  • 《献给某飞行员的恋歌》蒸汽朋克风,剧情毫无逻辑,大概只看了两三集。
  • 《哆啦A梦:伴我同行》在电影院看的,3D 剧场版。是大雄和静香之间故事的合辑,挺好看的。
  • 《圣斗士星矢》今年新出的 3D 剧场版,在日本的时候小伙伴拉我去电影院看的,不过我对圣斗士的故事没有什么了解,基本上是去看动画特效了。
  • 《十二国记》很多人成长的故事,今年很喜欢的一部作品,在日本的书店看到很有中国风的《十二国记》的文库本小说之后引起兴趣的。
  • 《我们仍未知道那天所看见的花的名字》原来那首很好听的歌是这个片尾曲。
  • 《苹果核战记:阿尔法》飞机上看的,由于没插耳机,也是看动画特效了。
  • 《心理测量者》第一季,第二季。很血腥,但是设定还比较有意思,系统可以计算你的“心理指数”,判断你犯罪的可能性,公安以此为依据逮捕或者直接击毙你……女主角各种冷静强大,不过在第二季就很过头了,基本上除了女主角其他人全都是渣渣的感觉。
  • 《ALDNOAH.ZERO》科幻机甲类,战斗主要靠找对方的弱点而不是虚无缥缈的“斗志”或者“主角光环”这一点倒是挺有意思的,但是在正规军全都是炮灰的情况下一个中学生开着练习用机甲以惊人的洞察力连败各种火星黑科技,也只能说是主角光环了。结局的时候男女主角双双挂掉然后打出广告来说敬请期待第二季……
  • 《恐怖残响》很喜欢的画风,故事虎头虫尾,简直就不是尾。好像现在很多动画片都是这样。照理说动画片应该是事先就计划好出多少集,而不是像漫画连载那样会临时决定要腰斩草草收尾的吧?
  • 《玉子爱情故事》,《玉子市场》的剧场版,感觉剧场版比 TV 版好看不知道多少倍了。
  • 《东京暗鸦》,虽然是喜欢的阴阳术题材,不过没看完……
  • 《京骚戏画》,风格独特的以京都为舞台的动画片。
  • 《盗梦侦探》,今敏的经典片子,音乐很赞,风格很独特,剧情比较难懂。
  • 《异邦人:无皇刃谭》,一个剧场版动画,继续赞打斗画面和音乐,细节也很写实的感觉,比如日本战国时期的混乱程度,还有中国武术用剑日本武道用刀的区别——其实我一直对这样的分歧的原因比较好奇,在日本的博物馆看到早期出土的文物中还是有双刃剑的,但是后期的武器就全是单刃的刀了。
  • 《月刊少女野崎君》,被推荐的,似乎是四格漫画改编的,轻松搞笑风。
  • 《龙与虎》,一直听说以经典,一直以为是少年热血类……很喜欢里面的櫛枝実乃梨。
  • 《乐园放逐》,一个虚拟世界、AI 等为元素的剧场版动画,2D 和 3D 结合的方式也有它独特的魅力呢,虽然故事情节比较没有什么存在感。
  • 《命运之夜无限剑制》第一季,重新拍的 Fate Stay Night,不得不感叹现在的动画片在战斗场景上都非常赞了。最后一集片尾曲出现以前的旧音乐的时候瞬间被治愈了。但是人物画得真的崩坏很厉害很厉害……
  • 《巴哈姆特之怒》听说经费很惊人,画风确实很精良,但是故事完全不知道是怎么回事。
  • 《七大罪》搞笑片?
  • 《境界触发者》似乎是主要面向中小学生的热血战斗类动漫,而且制作很节省成本,大量几乎静止的画面和重复利用的镜头,我居然也看得津津有味,内心果然还是有个热血少年吗?
  • 《魔弹之王与战姬》虽然颈部以上的画风都很喜欢,但是往下就是纯无节操卖肉片。片头曲非常热血非常喜欢,剧情上就觉得似乎是原本有一套很完整的设定和很宏大的剧情被动画制作方以一种非常拙劣的不连贯的方式呈现出来。
  • 《牙狼GARO 炎之刻印》大概特色是 2D 扁平画风的人物和 3D 全金属风格的铠甲之间的反差吧?剧情展开有点跌眼镜,好像还没完结,不知道后面会怎么演。
  • 《冰果》重看。
  • 《侧耳倾听》宫崎骏,重看。

嗯,总之好好忏悔吧……其他杂项。这一年来对噪音的忍耐程度上升了不少,于是不那么忌惮那个空调轰隆声呆在实验室的时间变多了。去听过音乐会,包括在佛罗伦萨的 fancy 包厢看台,还有学校自己办的音乐会,不过感觉我还是更喜欢听合唱的。订过一段时间的 the Economist,一开始还勉强都有些时间好好看,暑假从日本回来就堆成山了。食量似乎变小了,特别是中午很长时间每顿在 stata 吃一片 pizza 解决(并且居然开始觉得还挺好吃),但是总体来说今年大家一起去腐败吃大餐的次数显然也变多了。2014 年本来想好好把 optimization 方面的知识系统地学习整理一下,我自己也拟了一个很详细的计划要来写一整系列的 blog 文章,结果目前也还只写道 Projected Gradient Method 为止。

2015 年,有什么愿望呢?大家新年快乐!明けましておめでとう!

让明天把今天给记住不是因为孤独
因为我们追求的专注不管它起起伏伏
让今天把明天变特殊未必因为幸福
因为我们努力不服输尽管失误
让明天的记忆不模糊不是因为孤独
因为我们执着的态度不管它起起伏伏
让今天把明天变特殊未必因为满足
因为我们过得不含糊从来不曾退出


关于知识整理、积累与记忆

$
0
0

去年的年度总结中有提到过一个关于知识积累方面的困惑,最近被问起今年的年度总结中怎么没有再提及去年提出的那些问题,实际的原因是忘记了……这也正说明了对于像我这种忘性巨大的人来说知识积累真是一件迫在眉睫的事情,实际上在过去的一年中其实也做过各种尝试,虽然并没有算解决了这个问题,但是也不妨趁此机会分享一下我的一些尝试和想法吧。

首先说一下背景,我自己是一个记忆力比较不行的人,特别是短期记忆,比如见到陌生人问名字肯定在对方说完 0.5 秒之内就瞬间忘记了,或者是比如查询公交地铁路线之类的,往哪个方向在哪一站下,我都是查完瞬间忘记,每到一站又得重新打开手机确认一下。当然我觉得有可能是由于我“能不动脑子就不动脑子”的懒惰给惯成这个样子的……稍微中长期一点的记忆一般得经过一些强化才能记得住,比如大学的时候我从来不逃课,所以经常会宿舍之后会被问到今天某某课讲了什么,这个时候我是肯定想不起来的,但是借助外部媒介比如课本啊笔记之类的就能想起来了。当然我也并不是对于所有事情都无比健忘的类型,好像随机有一些事情还是会记得很牢固很多年不会忘记,所以说我觉得通过合适的方法加以强化和辅助的话应该还是有救的。

所谓强化记忆我觉得无非是两种方式,一种是不断地重复,另一种是加深理解。前者的典型大概可以算是歌词之类的记忆吧,其实有一些歌我虽然大致会唱但是完全都不知道歌词唱的是什么,基本上就是靠反复地听就慢慢记住了吧。当然这种方式对于正常的知识积累来说好像效率有点低下,而且也不是很确定是否管用,所以另一种“加深理解”的方式就更为可取一些。并且我觉得现在的另一个重要的挑战就是知识爆炸的问题,这是必须对知识进行解构、抽象和整理才能加以应对的。

当然知识要如何整理,记忆要如何强化,这些问题我想都是非常因人而异的,对于我来说,大概可以简单地罗列为以下几点吧:

  1. 主次和层次
  2. 积极跳出 comfortable zone
  3. 脑子动起来

主次和层次,其实主要是为了处理大量的爆炸性增长的知识所采取的措施。我在去年的年度总结中已经提到过,自己存在一个很大的问题就是自己记的笔记、日记之类的很少去阅读和回顾,导致直接被 archive 掉然后忘记掉。为了解决这个办法我有做过一段时间的尝试就是把笔记分为混乱的、临时的草稿性笔记和提炼、整理过的笔记。

首先一个是在日记方面(其实也算不上是什么正经的日记,主要是想看看自己都把时间用到什么地方去了。),我的做法是每天晚上花一点时间来回忆当天的事情,当天做了什么,有什么需要纠正的,有什么应该做的没有做的,有什么收获,什么糟糕的事情之类的,然后用一个简单的列表记录下来。这也算是一次简单的当日记忆强化。然后每周末再计划一点时间出来翻阅该周的记录,挑选重要的部分,做一个简短的一周 summary,也作为对一周中有价值的事情的再一次记忆强化。最后一级就是每月月末通过 weekly summary 做一月小结。

1
图 1

这种方法的好处是对于重要的事情进行了多次回顾,并且通过层次过滤之后,留下比较简练的 monthly summary 记录也更方便回顾和查阅,因为如果只是一堆 daily records 的话估计又会完全不想去慢慢翻看了。至于用处我也不敢完全说是有用或者没有用,我想有兴趣的人大可以去尝试一下,看看是否适合自己,因为实现起来其实很简单。我自己并没有坚持多久,大概四个月不到吧,但是我觉得主要原因是没有合适的记录工具。-.-bb因为我又想要记录的格式能够方便地支持数学公式、图片等附件,又要能自然地按照刚才提及的层次进行结构进行管理,还要想能够方便的检索、搜索和查阅……当然对软件太挑剔也是我的一个大毛病,只是那就暂时不是本文的话题了。

除去生活记录之外另外一个记录来源就是课堂笔记,我已经不记得在中学大学时期自己有没有记笔记的习惯以及是怎样记笔记了,但是现在我是很喜欢记笔记的(除非老师完全不板书而且上课的内容也完全在 slides 上,不过这种课我大概也不太会去上。),很大的一个原因是我发现这能有效地抑制打瞌睡的发生。但是通常我自己记的笔记是不太会去看的,特别是如果那个课本身还有专门的官方 lecture notes 的情况下,谁会丢下官方 lecture notes 去看字迹潦草排版混乱甚至还有各种笔误的课堂笔记呢?不过其实回顾课堂笔记能够帮助重现课堂场景,应该对于加深记忆和理解很有帮助才是。

对于这个问题,遵循刚才提到的原则,我一直在尝试把笔记分为收集和整理两个阶段。收集就尽量随意,到最后我都只带一个笔记本,所有的东西都记在同一个本子上,让它成为草稿的形式。其次就是整理阶段,让草稿形式的课堂笔记转变成简练便于查阅的笔记。

  • 标记重点疑点:抽时间(强迫自己)复习一遍课堂笔记,用不同颜色的笔标出有疑问的地方和困难、重要的地方,在必要的地方补充细节等等。总之做过 annotation 之后的笔记以后要看的时候也能一下子找到重点忽略掉一些不必要的细节。
  • 电子化:我现在的做法就是把笔记扫描之后放到云端,这样在手机里需要查询的时候也能随时看到,另外就是扫描分页之后之前全部混在一个笔记本里的记录也能分门别类地放好了。不得不说扫描笔记还是有点麻烦的,而且扫描的文件要想分辨率好一点也比较占空间。直接电子化的解决方案,比如Equil Spartpen、或者是 Wacom Inkling 这类的电子笔,或者像 Sony 的DPT-S1这样的神器,虽然 demo 看起来都让人很心动,但是也总是会有人抱怨特别是在高速书写的时候记录流畅程度、精确度都还存在许多问题,大概离代替纸笔还得再等一段时间吧。
  • 提炼:定期(比如半学期、或者整堂课结束以后)对笔记进行提炼,总结出最重要的内容。一个是强化记忆,我觉得分类、整理、以及建立各个部分之间的联系,等等这些都是对于加深理解来说非常必要的,而深刻的理解又是减轻记忆负担的重要手段。其实道理很简单,比如让你记忆一串数字 0, 1, 1, 2, 3, 5, ……可能会比较痛苦,但是如果进行提炼,找到其中的结构和规律\(F_n=F_{n-1}+F_{n-2}\)的话需要记忆的“内容”就变少了。其实看看各种压缩算法(比如 JPEG)很明显也是按照寻找结构进行提炼的套路来的。不过这部分目前还处于设想阶段,我还没有能成功实现过……:P

之前有问过实验室的 Y 师兄是如何看 paper 的,他说他只看公式,然后看看结果,碰到需要细看的论文再慢慢看。而我一直以来看论文的方式就完全不一样,基本上就是从头看下来的,从 introduction 开始,看 motivation,关于目前现状的介绍,到 related work,大家都做了什么样的尝试之类的,往往看得津津有味,而且非常喜欢 follow reference,看看引用了哪些文章,有意思的加到 to-read 列表里面去。也是由于这个原因,我的 to-read 永远是越来越多的,而且我看 paper 也就看得比较慢。当然其实我也意识到自己看论文的方式并不是非常有效的,这个可以说是刚才提到的主次的问题,但是也可以归为接下来要说的 comfortable zone 的问题。

Comfortable Zone 的问题:我喜欢看 introduction、related work 以及 follow references 因为这个完全落在了我的 comfortable zone 里面。我不知道心理学之类的究竟是如何定义 comfortable zone 的,我感觉大概就是人对于 level up 的追求和人对于懒惰安逸的追求之间的一个权衡。比如一直学习很痛苦,一直逛社交网络又太痛苦,因此权衡一下一直逛诸如知乎、Quora 这类的问答性质的社交网络就成了一部分人的 comfortable zone,一方面做到了安逸地上网,另一方面还能学到各种知识,在一定程度上缓解了罪恶感。类似的 balance 产生的 comfortable zone 在我身上也随处可见,最典型的大概就属于以“学日语”的名义刷动漫的这个 zone 了吧^_^bb

至于看论文的问题,balance 的两端,一边是看论文好费脑子不想动脑筋的惰性,另一边是想要看论文增长学术能力的上进心。权衡后在我身上得到的 comfortable zone 就是花很多精力去看这些部分:

  • Introduction:因为是白话文,所以看起来不用那么费脑子。而且作为论文开篇,往往都是作者尽量包装的精美华丽的部分,厉害的作者往往能写得让人看了之后热血沸腾心情澎湃,仿佛接下去的东西就是要 change the world 了一般。所以,自然而然地,得到的心理满足感也会很高。
  • Related work:同样是白话文,不费脑子。但是指点江山激昂文字啊,轻描淡写就把整个相关领域总结了一下,看那些估计得花一个星期或者甚至更久才能啃清楚的论文被一句话总结评价了,似乎确实是很提升成就感的样子。
  • References:这个理由就更简单了,首先加入 to-read 简直是一件简单得不能再简单的事情,都不用经过大脑回路,直接低级神经就能搞定。其次也是很有成就感的事情,就跟“资料收集成瘾综合症”是一个道理。

所以总结起来就是,一方面要不怎么费脑子,另一方面又有一些小的或者有点虚假的成就感 reward,就很容易形成 comfortable zone。我觉得人大概都是会追求上进的,但是比如虽然看完一本书可能会有很大的 reward,但是整个过程很漫长,中间可能并没有什么 progressive reward 之类的,相比之下看完一条微博虽然可能只有比较小的 reward,但是几乎是可以即时完成即时拿到的,大部分时候人们会趋向于在后者的情况下建立 comfortable zone 也就不是太奇怪了。但是问题在于这些 reward 并不是可以完全加成的,且抛开某些 reward 是类似于精神甜品一样的“不真实”的 reward,话同样的时间(可能中间过程有点痛苦地)完成一项完整的 project 所带来的价值通常是要比同样的时间精力下去做的各种各样的互不相关的带有细小 reward 和即时反馈的事情的价值总和要大的。

结论就是,尽量积极地跳出 comfortable zone 吧,当然并不就是说要自虐,因为 comfortable zone 本身就是人在生活中寻求 balance 的最优化得到的结果吧,时不时跳出去应该有助于避免陷入 local optimal 万劫不复。并且,跳出 comfortable zone 的结果应该是会扩大自己的 comfortable zone 的,所以,并不一定就是要过“苦行”的生活啦。

所以说,记笔记不看其实也是一个 comfortable zone 带来的问题,因为上课记笔记其实相对比较容易的,取决于老师讲课的方式,可能老师板书得非常详细你完全不用动什么脑子就能记下来很细致的笔记,也或者老师讲得如此之快你光写字就跟不上了完全没有时间动脑子。总之一方面满足了不用动脑子的条件,另一方面记下满满一本笔记,本身就是很有成就感的事情。因为光“下载很多论文和电子书”都会让人觉得收获了很多,把“论文抄写一遍”就更不用说啦。然而,要回头去看自己的论文并加以整理、复习,确实需要动脑筋的,就被排除在 comfortable zone 之外了。其实说来说去都是要不要动脑筋的问题,所以和第三条其实也并没有严格的区别了。

脑子动起来:跟 XH 一起上课的时候我发现她记笔记的方式跟我很不一样,我反正是原样 copy 老师的板书,但是她是有“互动”的,比如老师讲到我们把刚才讲到的公式或者定理套到这里来,就能得到什么什么,她就会自己通过心算写出结果来然后再和老师的板书对照。简而言之就是动脑子的记笔记方法和不动脑子的记笔记方法,从物质结果来看都是一份笔记没有区别,然而一种方式显然比另一种方式会得到更深刻的印象和理解。虽然我把自己一直没有实施这种方式的原因归为自己心算能力太弱,但是想来也许自己心算能力太弱这件事情大概也是长期不动脑筋的惰性养成的结果吧:有 Mathematica 的时候绝不动笔,有纸笔的时候绝不动脑子。

说到底人类的惰性不知道到底是来自于什么地方,懒得动手好像还可以理解,但是动动脑子好像也不是什么费“力”的事情,为何自己会有如此大的惰性,千方百计地都要避免动脑子呢?但是大脑其实不用的话也就浪费了……脑筋动起来,寻找脉络、结构、联系,这样知识积累起来应该就会有效很多。

总而言之,这些算是我自己的一些尝试加想法,是否合理还得看不同的人不同的情况。而且,这也只能算是必要不充分条件吧。比如写 blog 其实也是我自己的一个知识积累的方式,选择的主题通常都是近段时间学到的一些东西,觉得很有意思,就把自己了解到的东西加以整理和总结,再重新呈现出来。然而即便如此,其实在 blog 里写过的东西,很多我也还是会忘得很干净……=.=bb所以,嘛,总之,咱来引用一句千反田的话吧:頑張れば何とかなる保証はありませんが、頑張らなければ何ともならないことは保証できます。

Denoising Lena

$
0
0

在之前讲 Projected Gradient Method 的文章中,我们举了一个对加了白噪声的 Lena 的照片进行 denoising 的例子,文中提到了两种方法,一种是直接对 DWT 的系数进行 hard thresholding,将数值较小的值设为零,再用逆向离散小波变换得到 denoising 之后的图片。另一种方法是解一个\(\ell_1\)正则化的线性回归,我们选了后者因为刚好那个优化问题经过变化之后可以用 Projected Gradient Method 来解,这也是当时选这个问题作为那篇文章的原因。但是当时并没有解释为什么这些算法可以实现降噪,而这就是今天的话题。

当然,直观来讲,是不难理解的,因为 natural image 在小波基下呈现稀疏性,而白噪声,也就是 Gaussian Noise,则没有稀疏性,另外假设 noise 的 scale 和原始信号相对来说比较小的话,那么通过 hard thresholding,去掉那些较小的系数之后得到的稀疏系数会达到一定的降噪效果。我们在这里试图将问题 formally 定义出来。首先,我们假设 Lena 的图片是这样生成的

\[ y = Xw^* + \epsilon \]

其中\(X\in\mathbb{R}^{d\times d}\)是正交小波基,\(w^*\in\mathbb{R}^d\)是真实的 Lena 的照片在小波基下的系数,而\(\epsilon\sim \mathcal{N}(0, \sigma^2I_d)\)是零均值的高斯分布噪音。实际上我们并不需要高斯分布,在后面的分析中我们只需要\(\epsilon\)的分布的 tail decay 得足够快就可以。比如任何 bounded 随机变量,或者 sub-Gaussian 随机变量都是可以的。当然我们所能达到的降噪的效果会取决于噪音的 variance \(\sigma^2\)的大小。

因此,我们所观测到的\(y\),会是原始图像加上未知噪音\(\epsilon\)的结果,我们知道作为小波基的\(X\),但是却不知道原始的小波系数\(w^*\),而我们的目的正是要构造一个 estimator \(\hat{w}\),而我们这里将使用 mean square error (MSE) 来衡量一个 estimator 的好坏:

\[ \mathsf{MSE}(X\hat{w}) = |Xw^* - X\hat{w}|_2^2 \]

注意 MSE 是一个随机变量,随机性来自\(\hat{w}\),因为\(\hat{w}\)是根据\(y\)构造出来的,而\(y\)则依赖于随机变量\(\epsilon\)。这里看起来有点像 machine learning 的设定:\(X\)是数据,\(w^*\)是模型参数,而\(y\)是带噪声的 label,但是实际上设定并不太一样,首先这里的\(X\)是固定的 (fixed design),并不是像 machine learning 里是从一个数据分布中随机采样得到的 (random design),其次这里的目的是估计\(w^*\),并且衡量标准用重构出来的图片\(X\hat{w}\)和真实的图片\(Xw^*\)进行比较,而在 machine learning 中衡量标准则是要对于未知的,新的数据下的预测结果和真实结果进行比较。

在构造 estimator 之前,我们先对问题进行一些简单的变换,首先注意到小波基是一个 orthonormal basis,也就是说\(X^\top X=I\),因此,我们在模型(eq: 1)两边同时乘以\(X^\top\)就可以得到:

\[ X^\top y = w^* + X^\top \epsilon \]

\(X^\top y=Y\)\(X^\top \epsilon\)\(\xi\),我们可以得到如下的新模型

\[ Y = w^* + \xi \]

其中\(Y\)是观测到的量,\(\xi\)是(变换过的噪音),由于\(X^\top\)是 orthonormal 的,所以\(\xi \sim\mathcal{N}(0,\sigma^2 I_d)\),和原来的噪音是同分布的。类似地,MSE 可以变换为

\[ \begin{aligned} \mathsf{MSE}(X\hat{w}) &= (w^*-\hat{w})^\top X^\top X (w^*-\hat{w})\\ &= |w^*-\hat{w}|_2^2 \end{aligned} \]

现在问题变得简介了许多:我们观测到一个未知的向量\(w^*\)加成了高斯噪音的结果,现在想要估计\(w^*\)使得估计值和真实值的\(\ell_2\)距离平方最小。光这样似乎并不是特别明显我们可以做什么,如果有多个观测值的话我们似乎还可以求求平均之类的,现在只有\(Y\)这一个观测值。

接下来我们不妨来分析一下 Lena 和噪声各自的性质。首先 Lena 作为一张 natural image,在小波基下的系数\(w^*\)是应当呈现稀疏性的。另一方面注意到高斯噪声有一个很好的性质就是它的分布的 tail decay 得很快。例如,根据Wikipedia,一个高斯分布的随机变量取值在均值加减\(3\sigma\)的范围内的概率是 99.7%,这里\(\sigma^2\)是这个随机变量的方差。

1
图 1

根据这个,我们可以以很大的概率确定如下情况:\(|\xi_i|\)都是很小的;因此如果观测值\(|Y_i|\)是一个很大的值,那么说明在\(i\) index 下的真实值\(|w^*_i|\neq 0\),因此我们观测到的是真实值加噪音;另一方面,如果\(|Y_i|\)是一个很小的值,那么有两种情况,一是由于稀疏性,原始信号在这个位置的系数就是零,或者是原始信号虽然非零但是绝对值很小。这些分析下下面的所谓 hard threshold estimator 就变得 make sense 了:

\[ \hat{w}^{\text{HRD}}(Y)_i = \begin{cases} Y_i & |Y_i| > 2\tau \\ 0 & |Y_i| \leq 2\tau \end{cases} \]

这里的 threshold \(2\tau\)是什么我们接下来会讨论,简单来说就是,如果\(|Y_i|\)很大,那么观测到的是信号加噪音,由于我们不知道噪音具体是多少反正噪音相对于信号来说比较小,就索性留着;但是反过来\(|Y_i|\)很小的情况,如果信号原来在这里是稀疏的,那么正好我们设为零估计正确,但是即使原始信号在这里不稀疏,其绝对值也是很小的,因此我们设为零之后造成的估计误差也不会太大。

接下来就让我们把这个 idea 具体地用数学语言描述出来。首先,让我们来具体刻画一下高斯分布的 tail decay。具体来说,假设\(Z\)是均值为零,方差为\(\sigma^2\)的高斯分布,对于任意的\(t>0\),我们希望计算\(Z > t\)的概率:

\[ \begin{aligned} P(Z > t) &= \int_t^\infty p_Z(z)\,dz\\ &= \int_t^\infty \frac{1}{\sqrt{2\pi\sigma^2}}e^{-z^2/2\sigma^2}\,dz \end{aligned} \]

排除Q-function这种耍赖的存在的话,这个积分并没有一个表达式可以直接写出来,如果我们通过数值方法,可以算出类似刚才的\(e\sigma\)那样的数值来,不过我们这里希望有一个表达式,由于我们只是希望噪音 decay 的很快,也就是说在\(t\)变大的时候\(P(Z > t)\)变小得非常快,因此我们并不需要得到 exact 的等式,只要得到一个足够好的上界不等式就好了。这里有一个简单的方法,注意到当\(z \geq t\)时,\(z/t \geq 1\),因此

\[ \begin{aligned} \int_t^\infty \frac{1}{\sqrt{2\pi\sigma^2}}e^{-z^2/2\sigma^2}\,dz &\leq \int_t^\infty \frac{z}{t}\frac{1}{\sqrt{2\pi\sigma^2}}e^{-z^2/2\sigma^2}\,dz \\ &= \frac{\sigma}{\sqrt{2\pi}t}e^{-t^2/2\sigma^2} \end{aligned} \]

从这里可以看出,高斯分布的 tail 是以\(e^{t^2/2\sigma^2}\)来 decay 的,这将随着\(t\)的增大以非常快的速度趋向于 0,\(\sigma^2\)越小速度越快。这里我们暂时忽略前面的\(\sigma/\sqrt{2\pi}t\)的系数,注意到当\(t\)变得很小的时候这个系数变得非常大,此时这个上界就失去意义了,因为当\(t>0\)时我们显然有\(P(Z>t)<1/2\)。实际上,通过Chernoff Bound可以直接得到这样的方便处理的上界:

\[ P(Z > t) \leq e^{-t^2/2\sigma^2} \]

虽然推导并不复杂,但是篇幅有限,为了避免扯得太远,这里就直接使用这个结论了。现在我们回到\(\xi\),刚才的分析中已经知道它是一个\(d\)维,零均值,协方差矩阵为\(\sigma^2I_d\)的高斯分布变量,由于各个维度互相独立,通过简单的 union bound 和对称性,我们可以得到:

\[ P(|\xi_i| > t) \leq P(\xi_i > t) + P(\xi_i < -t) \leq 2e^{-t^2/2\sigma^2} \]

如果我们想要同时控制所有的\(\xi_i\)的话,同样利用 union bound 可以得到

\[ \begin{aligned} P\left( \max_{1\leq i \leq d} |\xi_i| > t\right) &= p\left( \bigcup_{i=1}^d \left\{ |\xi_i| > t \right\} \right) \\ &\leq \sum_{i=1}^d P(|\xi_i| > t)\\ & \leq 2de^{-t^2/2\sigma^2} \end{aligned} \]

令右边的式子等于\(\delta\),反解出\(t\),我们可以得到,对于任意\(\delta>0\),我们可以得到,以至少\(1-\delta\)的概率,如下式子成立:

\[ \max_{1\leq i \leq d}|\xi_i| \leq \sigma\sqrt{2\log(2d/\delta)} \]

也就是说,以很高的概率,我们可以将所有\(|\xi_i|\)控制在上面的 bound 以内,大约就是\(\sigma\)的 scale,当然会随着\(1/\delta\)\(d\)增大,但是都是根号下的 log-scale,增长比较缓慢,基本上可以接受。既然知道了噪音的大致 scale,那么我们不妨将 hard threshold estimator 里的\(\tau\)取成这里的噪音上界。具体来说,我们将得到如下结论。

1

定理 1. 假设模型满足(eq: 3),那么令\[ \tau = \sigma\sqrt{2\log(2d/\delta)} \]则对于任意\(\delta>0\),如(eq: 4)所定义的 Hard Threshold Estimator 可以以至少\(1-\delta\)的概率实现\[ |\hat{w}^{\text{HRD}}-w^*|_2^2 \lesssim k\sigma^2 \log(2d/\delta) \]其中\(k=|w^*|_0\)是真实系数的稀疏性。此外,如果最小的非零\(|w^*_i|\)数值都大于\(3\tau\)的话,以同样的概率可以实现\[ \text{supp}(\hat{w}^{\text{HRD}}) = \text{supp}(w^*) \]也就是说估计出来的系数有正确的稀疏性。

这里\(\lesssim\)是用于省略掉其中的一些常量的写法。在证明之前我们先来看一下结论。首先,MSE 随着\(\sigma^2\)的增大而增大,噪音越大,估计就越差,这是理所当然的事情。通常,我们都会要求噪音是足够小的,例如,如果\(\sigma\)是在\(1/d\)的 scale 上的话,上面的式子就会变得非常好看。另外前面的系数\(k\)相当于是必须要 pay 的 price,因为我们这里需要估计的参数有\(k\)个(\(w^*\)的稀疏性)。实际上,假设\(w^*\)不具有稀疏性,此时我们直接用 least square estimator,也就是

\[ \hat{w} = \operatorname*{\arg\min}_w |Y-w|_2^2 \]

很显然最优解就是\(\hat{w}=Y\),此时的 MSE 为\(|\hat{w}-w^*|_2^2=|\xi|_2^2\),根据我们刚才得到的高斯分布的 tail bound,再加上 union bound,可以得到

\[ \begin{aligned} P(|\xi|_2^2 > t) &\leq \sum_{i=1}^dP\left(|\xi_i|^2 > \frac{t}{d}\right)\\ &\leq \sum_{i=1}^dP\left(|\xi_i| > \sqrt{\frac{t}{d}}\right)\\ &\leq 2d\exp\left( -\frac{t}{2\sigma^2d} \right) \end{aligned} \]

令右边等于\(\delta\),我们可以得到,以至少\(1-\delta\)的概率,

\[ |\hat{w}-w^*|_2^2 \leq 2d\sigma^2 \log(2d/\delta) \]

可以看到我们得到的 bound 和\(\hat{w}^{\text{HRD}}\)是类似的,只是现在需要估计的参数是\(d\)个(由于没有稀疏性)。现在假设我们知道\(w^*\)的稀疏性是\(k\),并且知道\(w^*\)在哪\(k\)个位置上是非零的,此时我们可以只对这\(k\)个位置通过 least square 进行估计,将会得到和\(\hat{w}^{\text{HRD}}\)一样的 bound。也就是说,hard threshold estimator 在对\(k\)的值以及是哪\(k\)个位置上非零这些情报毫不知情的情况下,达到了和知道这些情报的情况下所能得到的差不多的估计误差,因此 hard threshold estimator 又被称为 sparsity adaptive thresholding estimator。接下来我们来证明该定理。

为方便起见,以下我们就记\(\hat{w}^{\text{HRD}}\)\(\hat{w}\),首先注意到

\[ \begin{aligned} |\hat{w}_i-w^*_i| &= |\hat{w}_i-w^*_i|\mathbf{1}_{Y_i>2\tau} + |\hat{w}_i-w^*_i|\mathbf{1}_{Y_i\leq 2\tau} \\ &= |\xi_i|\mathbf{1}_{Y_i>2\tau} + |w^*_i|\mathbf{1}_{Y_i\leq 2\tau} \\ &\leq \tau \mathbf{1}_{Y_i>2\tau} + |w^*_i|\mathbf{1}_{Y_i\leq 2\tau} \end{aligned} \]其中最后一个不等式根据刚才对高斯分布的 tail 的分析(eq: 7),是以至少\(1-\delta\)的概率成立,其中\(\tau\)就是取定理中所指定的值。此外,注意到,根据三角不等式

\[ \begin{aligned} |Y_i|>2\tau &\Rightarrow |w^*_i| = |Y_i - \xi_i| \geq |Y_i| - |\xi_i| > \tau \\ |Y_i|\leq 2\tau &\Rightarrow |w^*_i| = |Y_i-\xi_i| \leq |Y_i| + |\xi_i| \leq 3\tau \end{aligned} \]

因此,接着上面的不等式

\[ |\hat{w}_i-w^*_i| \leq \tau \mathbf{1}_{|w^*_i|>\tau} + |w^*_i|\mathbf{1}_{|w^*_i|\leq 3\tau} \]

我们将右边的式子分情况展开可以得到

\[ \begin{aligned} \tau \mathbf{1}_{|w^*_i|>\tau} + |w^*_i|\mathbf{1}_{|w^*_i|\leq 3\tau} &= \begin{cases} \tau + |w_i^*| & \tau<|w_i^*|\leq 3\tau \\ |w^*_i| & |w^*_i| \leq \tau \\ \tau & |w^*_i| > 3\tau \end{cases}\\ & \leq \begin{cases} 4\tau & \tau<|w_i^*|\leq 3\tau \\ |w^*_i| & |w^*_i| \leq \tau \\ \tau & |w^*_i| > 3\tau \end{cases}\\ & \leq \begin{cases} 4\tau & \tau<|w_i^*|\\ |w^*_i| & |w^*_i| \leq \tau \\ \end{cases}\\ & \leq \begin{cases} 4\tau & \tau<|w_i^*|\\ 4|w^*_i| & |w^*_i| \leq \tau \\ \end{cases} \end{aligned} \]

也就是说

\[ |\hat{w}_i-w^*_i| \leq 4\min(\tau, |w^*_i|) \]

从而,我们可以直接得到

\[ \begin{aligned} |\hat{w}-w^*|_2^2 &= \sum_{i=1}^d |\hat{w}_i-w^*_i|^2 \\ &\leq 16\sum_{i=1}^d \left(\min(\tau, |w^*_i|)\right)^2 \\ &\leq 16|w^*_i|_0\tau^2 \end{aligned} \]

带入定理中\(\tau\)的式子即证第一个结论。第二个结论很好证明,只要利用三角不等式即可。首先,如果\(w^*_i\neq 0\),此时根据假设我们有\(|w^*_i|>3\tau\),于是

\[ |Y_i| = |w^*_i + \xi_i| \geq |w^*_i| - |\xi_i| > 2\tau \]

于是\(\text{supp}(w^*)\subset\text{supp}(\hat{w})\)。反过来,如果\(|Y_i|>2\tau\),则

\[ |w^*_i| = |Y_i-\xi_i| \geq |Y_i| -|\xi_i| > \tau > 0 \]

于是\(\text{supp}(\hat{w})\subset\text{supp}(w^*)\)。定理即证。

结束之前,有几点注意事项。除了上面的 hard thresholding 之外,还可以定义 soft thresholding,也就是先对所有的系数的绝对值减去\(2\tau\),然后将不够减的这些系数设为零。通过类似的分析可以得到差不多的结论。此外这里的噪音并不限于高斯噪音,从上面的分析中看到我们只要求噪音的 tail decay 足够快即可,因此对于其他有类似于高斯噪音这样的 tail decay 速度的噪音是同样适用的。另外就是,当\(X\)并非正交的时候,我们也能得到一些相似的定理,但是此时必须对\(X\)加一些额外的条件,否则,比如一个极端的情况,如果\(w^*\)\(X\)的 null space 里,此时\(Xw^*=0\),那么测量到的将会完全是 noise,此时没有任何可能恢复原来系数的希望。这里需要对\(X\)所加的限制基本上是要求\(X\)“近似于”正交,具体地 formulate 出来将会得到 compressive sensing 里那些常用的诸如 incoherence、null space property 之类的性质。此外,当\(X\)并非正交之后,它的行数并不要求等于它的列数,compressive sensing 里的许多结论就是在说,当\(w^*\)本身满足一定的稀疏性之后,我实际上并不需要\(d\)行那么多的测量数,而是只要远远小于这个数目的行数(依赖于稀疏性\(k\))就能恢复原来的系数。这个时候我们得到的类似于定理中的 bound 里,上界里将会出现行数\(n\),并且 error bound 会随着\(n\)的增加而减小。

最后,理论分析里得到的\(\tau\)的取值通常并不适用于直接在实际中带入。因为在求上界的过程中经过了许多不等式的放松,而且即便是“tight bound”,通常都是指不考虑常数系数,以及在最坏情况下和下界达到一致之类的情况,因此主要还是 bound 里的各个参数的阶对于 bound 变化的影响是比较有用的。实际操作中通常会通过 cross validation 之类的另外的方法来选取 estimator 的参数。

由于本文没有什么图片,看起来比较枯燥,下面随便给了一段用来通过 hard thresholding 和 soft thresholding 对 Lena 的图片进行去噪的 julia 代码。

  1. # Requires the following packages:
  2. #
  3. # Pkg.add("Wavelets")
  4. # Pkg.add("Images")
  5. usingImages
  6. usingWavelets
  7. sigma=0.1
  8. dim=512*512
  9. delta=0.1
  10. img=reinterpret(Float64,float64(imread("lena512gray.bmp")))
  11. imwrite(img,"threshold-lena-orig.jpg")
  12. # add noise to the image
  13. img.data+=0.2*randn(size(img.data))
  14. imwrite(img,"threshold-lena-noisy.jpg")
  15. the_wavelet=wavelet(WT.sym4)
  16. img_coef=dwt(img.data,the_wavelet)
  17. forconfigin["bound","choose"]
  18. ifconfig=="bound"
  19. tau=sigma*sqrt(2*log(2*dim/delta))
  20. else
  21. tau=0.25
  22. end
  23. # hard thresholding
  24. img_coef_hrd=copy(img_coef)
  25. img_coef_hrd[abs(img_coef_hrd).<=2tau]=0
  26. rcv_img=idwt(img_coef_hrd,the_wavelet)
  27. imwrite(rcv_img',"threshold-lena-hrd-$config-rcv.jpg")
  28. # soft thresholding
  29. ifconfig=="choose"
  30. tau=0.1
  31. end
  32. img_coef_sft=copy(img_coef)
  33. coef=1-2tau./abs(img_coef_sft)
  34. coef=coef.*(coef.>0)
  35. img_coef_sft=img_coef_sft.*coef
  36. rcv_img=idwt(img_coef_sft,the_wavelet)
  37. imwrite(rcv_img',"threshold-lena-sft-$config-rcv.jpg")
  38. end

我们对比了 hard thresholding 和 soft thresholding 使用定理中给定的\(\tau\)和随便尝试了一下选取的\(\tau\)值(注意“随便尝试一下”并不是一个很科学的 parameter selection 的方法)。结果图所示。

2
图 2

可以看到,定理中给出的\(\tau\)值过大,通过那个值进行 thresholding 之后原本图像的细节都被去得所剩无几了。还有就是 hard thresholding 比较暴力,因此造成的图像上的 artifact 也比较严重一点,相对应的 soft thresholding 的结果就相对更加 smooth 一点。当然,总体来说,效果都只能算一般,真正要做降噪的应用的话,应该会利用更多的 prior knowledge 和更加复杂的模型的。

2015 就是这样

$
0
0

今年是老歌《就是这样》。

不穿鞋子体会真的感觉环游世界不在乎明天天气我的世纪梦与我没有距离说去就去发出讯息接收我的频率冒险前进顺从心里的好奇

Carlo 在 lounge 问我要不要喝一杯咖啡,于是我跑过去跟他们一起聊天,中途发现 Carlo 当天下午三点就要飞罗马了,并且这次是永久地离开,想起来上一次跟他聊天的时候他说过要去英国,没想到就是当天了。我匆忙跑到座位上翻出了一块画板——之前练习画的丙烯画——临时送他作为饯别。

查尔斯河的水面蓝了又白,不知不觉又过去了一年。由于下半年报了 Museum of Fine Arts 那边的 Acrylic 绘画班,每次上课步行过去,今年便多了不少时间来欣赏查尔斯河的景色,一路过去的 Back Bay Fens 有花园有湖有 Boston 传统的成排肥鹅有长椅还可以踩松软的落叶,其实是非常惬意的,特别是今年还是个暖冬。其实查尔斯河经常看到很惊艳甚至诡异的夕阳,让人想起 ZJG。

MFA 的每周一次的绘画课其实还蛮有意思,虽然感觉这样子学到的东西其实比较有限,但是好歹是算入了门。不得不说丙烯画相比水彩来说,不论是颜料还是画布各方面都是更加烧钱的。每当给整个画布上底色的时候,调好的颜料三笔以内就用完了,就会觉得电子绘画好,实际上年底打折也确实买了一个 Intuos Pro,但是论好玩程度来说(抛开调不出想要的颜色时的抓狂的话),果然还是真实的颜料好玩,而且很久没有用过绘画板了,相当生疏。

技能树方面今年做的另一件事情就是报了学校的一个游泳班学了自由泳——嘛,当然还是游得不是很像样,但是感觉接下去主要还是要练习了。实际上学校的游泳设施非常高端,不好好利用真实太浪费了。但是与其说是定期的锻炼用,我好像更多是玩,比如很喜欢带上脚蹼然后用海豚游法直接在水底一路扭到对岸去。:D

此外还克服拖延症,终于把 RQE 弄了,于是正式从 PhD Student 变成了 PhD Candidate,据说会涨一百块的工资?其他就没有什么了,日语在我正在犹豫要不要今年考个 N1 的时候,老师发邮件来说今年 JLPT 在我们学校办,欢迎大家下周来做志愿者啊,我才发现原来已经是下周就考试了……绘画方面暑假在法国受到浓浓的艺术熏陶,还买了一本文字都看不懂的人体肌肉骨骼方面的书回来练习,不过并没有能坚持太久,总的来说这其实是非常忙碌的一年。我有常识过用一些 app 来记录自己的生活。比如 Sleep Cycle 可以用来记录睡眠时间,睡眠质量之类的。

一直觉得自己是不睡满八小时第二天肯定会困得不行的人,结果看到自己这一年以来的平均睡眠时间根本就没有上过八小时,也是震惊了。但是一个不争的事实也是我现在几乎每天必须要喝至少一杯咖啡。另外一个记录用的 app 是叫做 iHour,可以用来记录学习、工作之类的时间,其实比较手动了,但是可以给出比较漂亮的统计图,而且还可以刷各种成就,所以也一直用。

最辛苦的时候是一周超过 100 小时的工作时间,想一想每天睡八小时,然后花 3 小时来吃饭,每周就可以轻松工作 90+ 小时,然而期望通常跟现实相距甚远,特别是用 app 记录之后就发现大部分时候是达不到这样的效率的,总是会有一些其他事情耽搁、开个小差、无法集中注意力干活之类的各种情况,然后要是中途去哪里休假几天之类的再回来,平均每周的工作时间其实也就五十多小时了。

当然即便从玩的角度来讲也是非常充实的一年。大致算一下这一年去过的一些地方:中国:南京苏州嘉兴(一周);美国:纽约、华盛顿、波特兰、Acadia 国家公园;法国(21 天):Paris、Lille、Marseille、Lyon;德国(两周):Frankfurt、Cologne、Berlin、Dresden;捷克布拉格(三天);加拿大 Montreal。因为我比较喜欢收集明信片,每次回到家除去寄出去了的卡片,都还剩下一大堆,于是就找机会将其中一部分贴到房间墙上当装饰用。后来我在布拉格的时候突然有一个想法,在网上搜索了一下发现真的有这样一个网站,叫做 postcrossing:就是给世界各地随机的人寄明信片,同时收到世界各地寄来的明信片。其实给陌生人写明信片和给朋友写明信片感觉是很不一样的体验,因为我好像并不擅长跟陌生人讲很多话,不过总的来说还是非常有趣的一件事情,这样回家的时候也时不时会对邮箱里是否有卡片充满期待啊。^_^

不过跑来跑去其实也是很有乐趣,虽然有时候在外面晃荡太久了也会有想回去。年初在国内江南几处跑其实是由于签证被 check,只好在附近转一转,虽然在杭州很多年,但是周围都没有去过也是觉得人生很不完整。南京这个地方我还蛮喜欢,有种杭州的感觉,虽然并没有哪一处让我觉得好惊艳,但是就感觉即使长期生活在这里大概也不会很腻的样子,钟山景区那一带,感觉就很适合周末约几个朋友亦或者是独自去爬山。大概对南京的最初印象就是来自一张背景是中山陵台阶的照片,不过爬到顶上并没有一个什么博物馆啊资料馆之类的东西,多少有点小遗憾。

苏州也很漂亮,苏州博物馆的建筑很有特点,大概是在我还没有开始收集明信片的习惯之前收到过的第一张明信片好像就是苏博的建筑。平江路的各种小店也很有意思。不过大冬天的几乎都是室外景点,最后只能瑟瑟发抖,然而即使这样其实也是有相当多的游客。比较有意思的是在许多景点会有警察在用广播播放请大家不要随便轻信兜售打折票,团体票之类的小贩,然后旁边全是兜售打折票团体票的小贩。本来还想去同里或者西塘、乌镇之类的地方,最后因为太冷就回杭州了。在湖边和 prada 家寄住了好久。

美国的地方,纽约差不多每次基本上都是路过,所以其实并没有非常仔细低玩过。去华盛顿是看樱花,几个朋友一起开车过去。赏樱的人非常多,没有在日本看过樱花,所以不知道是不是会是同样的感觉,总之我虽然觉得樱花很漂亮,但是并没有觉得比其他的普通的花有更漂亮的地方,相比之下我更喜欢红叶。不过华盛顿似乎很好玩,各种博物馆都不要钱简直就是 bug 啊。

去波特兰的时候本来不知道要怎么玩,结果因为 QQ 先去了一趟,正好发现 HZ 在那边,于是我过去的时候便找到了接应的人,结果两人周末开车在 Oregon 州到处乱逛,属于毫无准备的自驾乱逛游,非常好玩,最好玩的是第一处去的 Oneonta Gorge,HZ 一开始跟我讲要做好全身湿透的准备,我听了半天没有听明白是什么意思,以为是要穿越森林,湿气很重之类的,结果到了那里发现是穿越峡谷溪涧到深处去看瀑布。一开始是攀爬大石和倒下的木头,但是到一些地方没有地方可以爬的时候只能淌水……一开始觉得穿着鞋淌水很不自在,而且完全没有带干衣服过来,然而后面大半身都湿透了之后就是无忌惮地玩水了,不过水其实很冷的。尽头是一个小瀑布。由于没有带手机,就在网上找了一张照片放在这里。

淌完水回来反正要开回城里也好很久,索性就破罐子破摔继续往前走,一路看了大大小小的瀑布,最后跑去看 painted hills,临时跑来一个估计只有几十人的小村庄住了一晚,第二天又跑去 Smith Rock 去 hiking 看 Monkey Face 那里攀岩的地方。一路上看到好大一片的风车和农田,非常非常的漂亮。Monkey Face 顾名思义就是一块(从特定的角度看)像猴子脸一样的石头,其实是非常非常大的一块石头,即使从对面的山看别人在那边攀岩也会觉得有些心惊胆战啊。

回去的路上车差点就撞到了一只飞奔过来的鹿,不管是我们还是鹿都是九死一生的感觉。以后在森林里的公路上开车果然还是要慢慢开才行。

秋季的尾巴跟学校的朋友们一起去北边的 Acadia 国家公园看红叶,那也是一个非常赞的地方,有山有海,当然也有红叶。hiking 一天下来,过去原本是很正常的量,那天居然觉得膝盖关节异常疼痛,难道真是越来越老了,还是平时实在是太缺乏锻炼了。暑假在学校的时候其实跟 ZD 一起还去开辟了 Boston 附近的 hiking 场所,有一个叫做 Middlesex Fells Reservation 的地方,坐地铁就可以到入口处,其实湖和树林也都非常漂亮的。

感觉再这样说下去就要变成纯游记了。说一点其他的吧,其实旅行途中的话,我基本上就不想干学习工作方面的事情了。做的比较多的是涂鸦或者看书。特别是年初在江南等签证的时候看了不少书,导致今年的阅读量似乎突然增加很多:统计一下有 42 本中文书,2 本英文书,1 本日文书。

  • 《黑客与画家》:很有名的书,我觉得还蛮有意思,但是并不是所有的内容都喜欢或者同意。
  • 《游戏玩家》:科幻类,似乎是一个叫做《文明》的系列的一本,里面的嗡嗡机还蛮有意思,感觉是还算有意思但是又不至于吸引你想要让你一通宵不看完不罢休的那种。以至于我现在都不太记得具体故事了。
  • 《ABC谋杀案》:在嘉兴的书店买到的,因为《冰菓》里的一个故事而一直想看这个。阿加莎·克里斯蒂的超有名的一个故事。个人很喜欢。
  • 《火星公主》:号称是全球销售2.8亿册的经典科幻巨著,感觉就是一部 YY 小说,超级没有意思,强烈不推荐。
  • 《不能承受的生命之轻》:在苏州的书店买的,米兰·昆德拉的这本书,因为比较有名,很早就一直都想找来看一看的,感觉全文读起来都相当阴郁,还不错吧,虽然也并没有特别喜欢。
  • 《练习一个人》:好像很早以前下载的,是个散文集,看了并不喜欢。
  • 《雪国》:因为很喜欢川端康成的《伊豆的舞女》,所以买了在跨洋飞机上看。《雪国》里也是像伊豆的舞女里那样说话语无伦次的姑娘。有时候经常觉得,小说里的人物,一生都过得好单纯,然而现实中的我们却又是如此纷繁复杂。买的这个版本同时还收录了《湖》,顺便也看了一下,感觉这种描写心理变态的小说看着有点吓人。
  • 《Through the Looking Glass》:XZ 推荐的书,其实我也很早就知道,因为好像之前看过一本书特别喜欢引用这里面的句子作为章节抬头句。强烈推荐看英文原版,因为很多脑洞是语言特有的,估计会比较难翻译。总之就是脑洞大开欢乐轻松的书。
  • 《罗生门》:在多看限免下载的,其实是一个包含了《罗生门》这个故事的短篇故事集。其中有不少故事还蛮有中国风的,有点像那种古代短小说集一类的。不置可否。
  • 《动物农庄》:实际上之前看了《1984》之后就应该来看这个的,不过一直拖了好多年。从情节上来看比《1984》更加轻松愉快一点,当然讽刺的味道一点都没有减,是一本好书!
  • 《风起陇西》:马伯庸早期的一本以三国为背景的间谍小说。还不错吧。
  • 《银河帝国》:“基地”系列 7 部曲,设定宏大的科幻小说。我觉得还蛮好看的(否则也没法坚持把 7 部看完),不过前面和中间部分比较好看,到后面的时候虽然很多东西和之前相呼应起来,但是还是感觉有点略烂尾了。
  • 《听到涛声》:吉卜力比较早期 (1993) 的一部动画片《听到涛声(海がきこえる)》的小说原型。首先动画片是蛮喜欢看的,数年后听人谈起有原著小说就去找来看了,比动画片里的故事更多,还包括了主角们中学毕业上大学之后的故事。总之就是青春爱情故事啦。蛮喜欢的。:)
  • 《我们为什么会分手》:因为有一段时间某位朋友在感情上碰到一些苦恼的问题,大家在尝试帮忙的时候谈起这本书,就去找来看了一下。是一个访谈集,对其中一部分故事和观点还蛮有感触的。
  • 《The Sorrows of Young Werther》:就是《少年维特之烦恼》,差不多是跟上面一样的原因而提到的,我初中的时候看过中文版,不过由于已经不太记得了,便又找出来看。我发现很多经典名著由于版权过期了,都可以在 Gutenburg 上找到非盗版的电子书。像维特那种鲜明的对于自己所认定东西持非常 strong 态度的个性让我觉得很像大学时的一个同学。感觉自己大概是比较不太会出现那种强烈的态度吧,更多的是在模棱两可之中。
  • 《每况愈下》:约翰·韦恩的这本书描写上世纪战后英国青年一代的生活,似乎那些人有一个标签叫做“愤怒的青年”,大概是比较有写实和记录意义的一本小说。
  • 《小王子》:本科毕业的时候看过一次,印象深刻的是驯化狐狸的故事,现在想起来还是很感触,麦田的金色,大概就是对于感情或者羁绊的最简洁的诠释吧。重看这本书是因为去了一趟作者的故乡 Lyon。或者说去 Lyon 其实是因为这本书吧。:)
  • 《Impressionism》:在多看上随便买的一本 Nathalia Brodskaya 的电子书,因为在法国看博物馆被震撼到了,决定至少要了解一下这些印象派先驱们的故事。
  • 《Van Goph》:perfect square 系列的一本。
  • 《我们为什么旅行》:不喜欢,迅速扫完之后现在已经没有印象了。曾经有一段时间特别执着于寻找旅行的意义,到现在其实并没有找到,然而也觉得似乎已经没有必要去追究这个问题了。有机会的时候,总会再一次踏上旅途,大概这就是旅行的意义吧。
  • 《三体》:刘慈欣的三体三部曲,非常好看的科幻小说,有很多人都给我推荐过很多遍了。最喜欢第二部。在德国旅行的途中看完的,白天出门暴走,晚上回来熬夜看小说,真是相当累人。:P
  • 《极简欧洲史》:以前看过一次,内容忘记了,在德国和捷克看一些历史博物馆,了解宗教发展和改革的一些东西的时候,不禁又对这些内容感兴趣,于是又找出来看了一下。感觉大概还是内容太多了以一点点的篇幅想要非常 coherent 地把所有内容串起来想到困难,感觉看到后面就有点乱了,如果不是事先就对欧洲历史全貌有比较好的了解的话,后面还是会看得比较晕的感觉。
  • 《全频带阻塞干扰》:刘慈欣的短篇小说,还可以吧。
  • 《证据游戏》:讲律师的小说,人物描写很细致入微。顺便了解了一下西方的审判系统,最后是否有罪居然是让大街上随便强制抓来的陪审团来决定,也是蛮神奇的。
  • 《六花的勇者》:同名动画片的原著轻小说,情节构思非常有意思,引人入胜,所以在等不及动画片更新之后就去看小说了。一贯的干巴巴的像看 manual 一样的轻小说文笔,但是设定和故事都很有意思,最喜欢第五卷。第六卷由于没有翻译版,就在日本 Amazon 买了原版来看,写得非常虐的一卷,不是特别喜欢。
  • 《仿生人会梦见电子羊吗?》:实验室 labmate 推荐给我的科幻小说。似乎是一本经典名著。不过我也觉得确实写得很好,我自己其实也是非常喜欢这类探讨人类和 AI 之间模糊界限的小说。
  • 《Liars and Outliers》:看的是中文翻译版叫做《我们的信任》。探讨人类如何从个人利益最大化(比如博弈中的纳什均衡之类的)的死结中走出来建立信任约束关系从而建立社会分工和文明的。比如说我们去餐馆吃饭为什么不用担心老板会下毒害我们之类的。我觉得探讨的问题还蛮有意思,但是最终觉得自己还是不是很喜欢看这种类型的偏社会学的书,长篇大论的纯文字性质(而不是建立数学模型通过逻辑来进行论证)的摆事实讲道理的讨论,就很容易让我觉得好像无论怎样讲都能讲出道理来的。
  • 《解忧杂货店》:满满温情,还有有趣的时间交错叙事方式。拥有烦恼并愿意与人商量的人,多半是想要去积极解决的人,大概本人其实心中早已有了抉择了吧——这样说也许过于绝对,但是反过来想其实有时候做出怎样的选择并不是最重要的,因为很多时候并无严格的黑白对错之分,重要的只是在选择之后的努力吧。不得不说和《白夜行》的风格形成鲜明的对比。
  • 《大秦帝国(第一部):黑色裂变》:第一部是上下两册,主要讲商鞅变法全过程。总的来说还不错,感觉小说的成分相对较大,不知道历史的成分有多少,当然两千多年前的事情,就是何真何假原本就很难讲清楚了。感觉春秋战国百家争鸣真是一个学术开放的年代,经营一个国家就跟现在开个公司似的,有才能的人也不会被诸如民族主义之类的东西束缚,能够自由地云游四方传播知识,还能今天在这里当两天丞相,明天再去另一国当丞相。
  • 《大秦帝国(第二部):国命纵横》这是第二部,也是上下两册,主要讲苏秦张仪合纵连横的故事。渐渐发现之所以看着觉得有点假的是每个男主角必定安排一个(或多个)完美无缺(聪明漂亮冷静善良武功又高等等)的女主,虽然说是英雄配美人,但是也太过模式化了。然后继续感叹诸子百家时候的学术开放,居然还有挂六国相印这样的事情,有点像现在的一个教授在好多学校挂名,还出任公司顾问啊之类的,哈哈。不过要论国家而言,现在世界上似乎主要还是以民族和宗教作为分化,并且互相之间似乎有诸多难以化解的仇恨的样子…… sigh。
  • 《天之痕》:其实是游戏了,干脆也列在这里吧,因为听到《幽城幻剑录》的 BGM 感觉非常怀念,就在网上找有没有重置版或者 iOS 版之类的,没有找到,但是看到《天之痕》的 iOS 版,虽然不是国产游戏中最喜欢的《幽城》,但是还是下载下来又玩了一遍。

总的来说好像看书的类型比较杂乱,原因是有时候打开多看 app 看到限时免费的书如果觉得还比较靠谱的话有可能会下载下来,所以其中有一部分书的类型比较随机。实际上这一年电影也看了不少,基本上都是被朋友抓去电影院之类的,其中最喜欢的一部是 Pixar 的 Inside Out,非常推荐。想起来我好像从来没有一个人去电影院看过电影。至于动画片,我记得去年有反省过看太多了,今年要少看,我自己感觉似乎确实看得相对少一点(而且现在很多动画片拍得相当烂俗):

  • 《噬神者》:好像是根据游戏改编的,剧情不知道在讲什么,单纯是喜欢那种浓重的大色块画风。
  • 《机动警察》:比较早期的动画片,很独特是视角,机战的设定,然而面对的却是现实中的柴米油盐,可以说是非常独特的一个动画系列。我看了剧场版和一些 OVA,TV 版陆陆续续看了一部分还没看完。
  • 《秦时明月》:国产动漫,追了许多年了,最慢的时候几个月才出一集,我估计很多人继续追的动力主要是想看看蓉姐姐到底什么时候能从昏迷中醒过来。不过客观来讲还是国产动漫中的佳品,特别是打斗动作,非常精彩。
  • 《记录的地平线第二季》:剧情比第一季更加拖沓了,不过喜欢画风和设定也就继续忍了。到第二季第 14 集女主角终于第一次登场了……
  • 《七大罪》热血类的动画片,有点像七龙珠的感觉,原本还以为自己早已过了热血的年纪呢,哈哈。瀧川ありさ唱的 ED 的 Season 超级好听。
  • 《境界的彼方剧场版》分过去篇和未来篇,过去篇就是 TV 版的重新剪辑,未来篇虽然是原创故事,但是剧情完全不能忍……不愉快です。另外还有一个 TV 未放松的隐藏话,讲主角们是如何认识的故事。
  • 《命运石之门》:非常中二但是非常好看,最后去把各种剧场版也都找来看了。TV 版一开始比较拖沓和无厘头,大概到 12 集才开始正式剧情,然而后面基本上就是一发不可收拾,并且最后把前面所有的铺垫全都联系起来了。豆瓣评分 9.2。
  • 《来自新世界》:看完以后很想说“什么鬼”,然而还是觉得是非常值得一看的。算是常识探讨“人类”这个东西的一部作品吧。豆瓣评分 8.8。
  • 《傀儡公主》:不错的动画短片。
  • 《希德尼娅的骑士第二季》:没有第一季好看啊。我一直期待对于最开始星白说人类和奇居子没有能好好互相交流的这个伏笔能有所展开,却一直没有。
  • 《红白黑黄 (RWBY)》:美国制作的系列动画短片,虽然有一些剧情但是感觉几乎可以忽略不计,重点是打斗非常精彩。目前出到第三季,然而作者之一似乎今年去逝了。顺便请不要觉得我看动画会关注战斗场景是因为我有暴力倾向……😂,其实是因为我小时候喜欢画武侠风格的漫画,自己觉得要表现精彩的战斗是很困难的技巧,所以就会格外关注了。
  • 《Angel Beats!》:忘记为什么会找来看了,因为这个动画片 10 年作为新番的时候我看过一集并没有跟下去。SSS 的 leader 有点像凉宫春日的感觉,片头的钢琴很好听。
  • 《玻璃之唇》:好像是因为想起在小樽看到的玻璃工坊才翻出来看的,剧情和人物刻画就不评价了,但是明亮的画风和精致的场景刻画,色彩、高光、静动,很多地方都觉得制作得很赞。歌《夏の日と君の声》也很好听。
  • 《六花的勇者》:前面说过小说了,设定很新颖的推理魔幻类动漫。
  • 《画江湖之不良人》:另一个国产动漫,战斗动作相对于《秦时明月》来说比较弱,不过人物 3D 模型方面似乎相对又要更细致一点。剧情还不错吧,武侠类型的,只要不是有太严重的逻辑漏洞我都还蛮喜欢的。
  • 《夏洛特 / Charlotte》:个人不是很喜欢,剧情后期毫无逻辑。
  • 《传颂之物虚伪的假面》:尾巴设定超级萌,画风很喜欢,还有 OP《不安定な神様》超级好听。只是剧情实在不知道要讲什么,而且到后期女主角实在是太多了分不清楚,只好放弃了……
  • 《一拳超人》:非常有意思的设定,男主角无敌,一般的怪肯定一拳秒杀,他的必杀技叫マジ殴り(认真殴打),用来对付最强的 boss。相比龙珠类一直打怪升级的故事,可以说是非常新颖的设定,然而在这样的设定下究竟还能写出什么样的故事呢?就请自己去看吧,我觉得故事也蛮有意思的。另外一拳超人原始漫画画风非常非常烂,后来有另一个漫画家是这个故事的粉丝,于是按照原始故事进行重新绘画。动画里的画风和在市面上看到的正常画风(非常精致)的一拳超人都是重画版的。

数了一下数目上大致是去年的一半多一点的样子。不过我的目标并不是不看动画片,毕竟有些动漫还是很经典很值得一看的,而且必要的休息也是需要的。

画画方面,一个就是最开始提到的丙烯绘画班,总的来说画得不多,有一些画具甚至都还没打开过,大致画了五六幅丙烯画(也是第一次在 canvas 而不是纸上画),两三幅水彩画,两三幅粉彩棒的画,还有几幅原本是 sketch,后来兴起了就用水溶彩铅开始上色最后搞得皱巴巴反而看起来很有感觉的小画,剩下就主要是中性笔涂鸦了(这个其实画了不少,至少有一个笔记本被我画完了)。主题基本上还是风景、人像和漫画三种类型,有临摹原画、照片或者实物,并没有尝试自己凭空创作过。趁着圣诞打折买了一只 Wacom Intuos Pro,也没有尝试过几次(借口是刚剁了手一时半会长不回来),而且好久没有用数位板了特别生疏,画得也非常生硬就不贴上来了。

当然去年开始玩的旅行中的速写(就是在火车、地铁、公交等地方画陌生人)也并没有完全中断,至少是在法国的时候还一直在玩,只是就能明显感觉到民风和之前在日本很不一样——原来之前在日本大家都知道我在画他们只是不好意思说破而已,在法国就不同了。有一次我在画对面坐的一个人,过一会儿一抬头发现人不见了,结果发现她跑到我身后来偷拍我画的画。当然还有更直接的,临下车之前走过来说给我看看,嗯,还不赖嘛,之类的。还有一次正在画前排的一对绅士着装的夫妇,旁边坐的一个黑人小妹妹就开始跟我说话,发现我听不懂法语之后她纠结了很久最后在手机上找了一个翻译页面开始跟我讲画得很好看能不能也给我画一张。于是我就画了撕下来送给她。画直接坐在邻座的人还有一次就是在日本的一次火车途中,当时那个女生坐着一动不动,不知道是不是吓坏了,估计是被当做是变态了😂。不过后来去德国就没怎么动笔,因为当时坐车途中主要在看书,《三体》之类的那几本。空闲时间只有那么少,也是没有办法,不过旅行本身还是很好玩的。

法国之行极大地刺激了我的艺术细胞,我当时就在想,如果我时小时候来过巴黎,说不定这辈子就决定去搞艺术了哈哈哈。当然现在的话就只能空热血一下咯,反正绘画作为一个爱好,也还是不错的。其实(至少对我来说)画画跟科研也有些像,展示出来的基本上都是画得还不错的作品,但是其实还有更多的废品,也有很多时候其实是挣扎在无法画出自己想要的或者满意的样子的时候的痛苦之中,科研不也是这样子吗哈哈?

在巴黎呆了近十天,给我的感觉就是住在那里永远不会无聊,逛不完的博物馆当然是一大亮点(在奥赛博物馆不吃不喝逛了一整天最后闭馆被赶出来的时候简直就想抱着柱子赖着不走),但是街头也有很多好玩的,虽然很多人给我忠告过天黑以后不要在外面到处跑,但是由于去的时候是夏天,晚上十点天才开始黑……所以我就经常跑去 Palais de Chaillot 的露台那里,就着埃菲尔铁塔为背景看街头艺人表演,亦或者跑去蓬皮杜艺术中心前面的广场看催眠术表演,催眠一大群人看起来真的很神奇,可惜听不懂法语不是很清楚催眠师具体在说些什么。说起法语,不得不说个人感觉英语在法国的普及程度似乎并不比在日本要更好,完全一句英文都不会讲的人碰到过不少,即使会讲英文,每当问路的时候,因为地名街道名之类的总是会以法语发音念出来,所以也是只能叫哭了。所以刚到第一天什么状况都没搞清楚就坐火车跑去旁边的小镇 Giverny 看莫奈花园害的我差点买错票去了几百公里远之外的地方。但是莫奈花园真的很赞啊,且不说花的数量,就种类而言都已经超过我之前见过的花的总和了,莫奈一定藏着一颗少女心,然后我再也不相信什么“画家都很穷吃不起饭”之类的话了。最后,差点忘记说,巴黎当街接吻的人好多,包括各种性别组合的。

从巴黎去马赛的火车刚好被我订在法国国庆节那一天(完全犯二了),早上去凯旋门看阅兵式,结果各种人山人海,最后打算回来的时候发现各种道路封锁,绕了无比大的圈子才回来赶上火车,正好马赛也有庆祝活动,就是在老港口放焰火,印象比较深刻的是无论有多挤,端着酒盘子的服务员总能如入无人之境。选择去 Marseille 而不是 Nice 和蔚蓝海岸的原因是小时候特别迷的《基督山伯爵》——说不定我在听说马赛的时候还不知道有巴黎这个地方。

所以我当然去了那个伊夫岛看了那个监狱,差不多算是到此一游啦,不过马赛本身其实也蛮不错的,Google Photos 根据我拍的照片和视频什么的自动生成了这样一个小视频:

总之城里最好玩的就是老港附近,早上会有鱼市,新鲜捕捞上来的各种千奇百怪的鱼放在那里卖,并不是我想象中的像《冰与火之歌》里那种中世纪各种喧哗叫卖的巨大的港口鱼市,但是也比较有意思。整个旧港一片也会有各种街头表演啊之类的(马赛鱼汤很赞)。另外马赛附近的峡湾也是强烈推荐,我去的好像是叫做 calanque de sugiton,坐 21 路车就可以到 hiking 起点,大约 hiking 半小时可以到观景台,海和峭壁的组合之前没有觉得会看起来这么让人心动的,就很向往海鸥可以沿着峭壁俯冲下去然后再迎风而上,随着高度上升如同镜头拉远一样渐渐将峡湾全景收入眼中,我简直都可以想象届时的背景音乐是怎样的,真是忍不住想一跃而下的😄。从观景台往下再 30 分钟就可以到海边。

海边并没有大片的沙滩,而是一些分离的小海滩,大部分是巨大的岩石,有很多人在岩石上玩跳水,我就把鞋子挂在书包上到水里去走了,绕着峭壁走了一大圈后来发现有一片地方大家什·么·都·没·有·穿…………后来回来的时候在岩石上看到 nudisme de tradition 的字样,大致就能猜出来了,原来这边是一片裸体海滩,完全不知道还有这么一回事。然而不知道是不是太突然了没有做好心理准备,好像也并没有觉得非常奇怪。感觉旅行的一个作用就是让你见识大千世界,有些东西在亲自经历之前光凭想象大概是会有很大的偏见或者 bias 的,等到真正见得多了就会见怪不怪了吧。除了裸体海滩之外另一个大概在我以前的三观中很难以理解的事情就是青旅中会有男女混住的房型——记得最开始来美国的时候听说美国的宿舍男女生是同一栋楼的时候就已经震惊得不行,到现在可以很自然地接受 Mixed Room(根据我的统计碰到鼾声如雷的室友的概率小了很多)的过程,其实客观的事情并没有什么改变,改变的知识文化和认知上的差异吧。有一句话说得好,很多事情只是不同,并无是非。

离开之前没忍住还是跳到海里去了,浪比较大不过很好玩,不小心喝了一口海水咸到要死,不过更糟糕的是,我下水的地方选得不是特别好,水里大石头比较多,海水又比较冷感觉不到,等我上岸的时候发现自己鲜血淋淋……O_o,擦破的撞破的,有些伤口还不小,虽然不是血如泉涌,但是也不是一下子就止住的那种。由于场面过于血腥就不放相关照片了,总之我赶紧打道回府,回到市区找了一个超市买了一大盒创可贴,心想着要去哪里洗伤口,看到 Google Map 上旁边有一个 Basilique Notre-Dame de la Garde,觉得教堂肯定有泉水之类的,就去那里,结果它居然是在山上(以后看 Google Map 一定要注意垂直高度)……总而言之最后是没有事情,但是由于脚底有伤,直接导致后来一段时间暴走能力下降很多。^ ^bb

最后在马赛的青旅前台居然碰到一个哈佛的小朋友在那里做志愿者,她说她们青旅是完全志愿者运营的,她自己是学法国文学的,就借这个暑假来这里做志愿者就可以免费吃住顺便了解当地文化风俗。

马赛旁边还去了 Aix-en-Provence,去这里纯属意外😂,因为本来是要去普罗旺斯看薰衣草的,后来我没搞清楚具体位置,而且好像开车比较方便,然后就来这个小镇逛了一圈,没想到 Cézanne 的故居和画室原来在那里,此外小镇本身也还比较有意思,老城区有一片地方随便走个三五步就会看到一个不同的喷泉。唯一比较诡异的经历就是有个中国大叔不停地叫我帮他摆拍照片,然后又不停地批评我拍得不好不够认真,说他照片要用来作为他们公司的形象代言什么的,我觉得他似乎有在酝酿跟我讲人生哲理等等一系列话题的企图于是赶紧找个借口跑掉了。

在法国去的另一个城市就是 Lyon,主要是为了《小王子》,在广场上有一个石桩上又小王子和他的作者的雕像。比较有意思的是虽然《小王子》名扬四海,但是其实在 Lyon 并没有看到比如满大街都是圣-埃克苏佩里周边产品这样的疯狂地“沾光”和商业化的景象。Lyon 本身是一个很不错的小城,美食好像也很有名,然后城市自东向西从古罗马时期到近现代几乎保留了各个时代的典型建筑,而我去那里的另一大目的就是看壁画啦——散落在城里一些地方的建筑上有巨幅的快要能以假乱真的壁画,因此里昂又有”壁画之都“的称号。

除了七月在法国之外,八月份又跑了一趟欧洲,主要是在德国,顺便去了一趟捷克。因为时间有限,纠结了很久最终决定放弃南部的慕尼黑一带(虽然我很想去看新天鹅堡),只在北边活动,以后有机会再去吧。第一站是科隆,不得不说从车站一出来就震惊到了,因为科隆大教堂就在火车站门口。

因为科隆大教堂本身就很宏伟,再和周围的建筑一对比,就变成非常鲜明的一副景象,可以登顶俯瞰全城,似乎是有五百多级台阶,旋转而上。另外还有一件比较有意思的是里面有一面彩绘玻璃非常特别,是像素风格的,后来 HZ 跟我讲那时一个叫做Gerhard Richter的艺术家专门设计的。教堂旁边就是霍亨索伦桥,科隆最古老的桥,横跨莱茵河,大概因为它本身就比较长,反正是我见过的同心锁挂得最多的一座桥了。Wallraf-Richartz-Museum 还有 Museum Ludwig 之类的各式博物馆也比较集中,步行游览非常方便。中间又一次在一个教堂门口碰到了一个旅行团一样的,然后有一个女生就一直跟我聊天,似乎是本地人,刚刚毕业,暑假逗留一段时间然后马上要去英国读法律硕士之类的,还说她老爸是搞建筑的,目前在中国西藏考察当地的民俗风格的建筑之类的,总之最后我终于搞清楚了原来她是导游的小帮手,然后当她知道我其实不是旅行团的一员时露出非常复杂难以形容的表情……^_^bbb抽空还去了附近一个叫做布吕尔的小镇,据说整个区被列为世界文化遗产,不过不知道我是迷路了还是怎么,除了看 Augustusburg and Falkenlust Palaces 之外,在小镇上并没发现什么特别的地方。

科隆之后是法兰克福,一般来说法兰克福是欧洲重要的交通枢纽,很多飞机都会在这里转机,但是作为游玩地似乎不是那么出彩,不过这次我在法兰克福逗留两天是因为正好赶上一年一度的博物馆河岸节(Museumsuferfest),我原本口水的是 7 欧元通票逛遍美茵河边所有博物馆,结果发现节日庆典本身也非常好玩,岸边绵延几公里全是小摊小铺,来自世界各地的音乐、舞蹈、美食、皮革、书籍、木雕、陶瓷、绘画、各种手工艺品、民俗特色,还有演唱会、露天舞蹈、大力士、射箭、赛龙舟、烟花等等,当然还有很多很多很多的人。一句话总结就是——由于围观各种东西在一直在太阳底下晒,导致后来直接被晒蜕了一层皮……-.-bb

当时订住的地方订好了之后收到邮件说,我们是在红灯区,不过你放心,这里很安全……然后我凌晨看完烟火大会回去的时候街边果然就气氛诡异,不过让我没想到的是那些拉客的人有的时候真的是字面上地来拉住你啊……吓了我一大跳,撒腿就跑。。。。哈哈哈。啊,对了,歌德故居也在法兰克福。

由于后来下雨,我在柏林的三天主要干了两件事情:逛博物馆和排队,正好有三天博物馆通票,就是排队的人太多了。最令人发指的是 Old National Gallery 那里在开一个 Impressionism and Expressionism 的特展,大清早提前一个小时到那里就已经有人打着伞在雨中排队了……当然博物馆岛那一片的馆都不错,除了艺术馆之外,历史文物也比较多,包括古埃及还有一些其他早期的文明,Pergamon Museum 里把别人整个城堡城墙都放在里面展览……附近还有历史博物馆,差不多能把德国那一块地方从最早期开始一直到二战结束之后的整个历史过一遍,德国人对于二战也好大屠杀也好还是比较能不偏不倚地客观地去看待的,跟我之前在日本看到的某些博物馆里的东西简直形成鲜明对比。此外还有一个专门的犹太人历史博物馆。柏林的小吃 Currywurst 我很喜欢,买了好多吃。柏林大教堂比较奇怪,进去参观居然要收费,后来我晚上路过的时候看到很多人在排队,发现是音乐会,结果在卖票的地方正好碰到有人不知道为什么想要出手自己买到的票,于是她一欧元卖给了我一张票,虽然位置一般,不过也堂而皇之地去听了一场音乐会,也就没有再打什么 Berlin Philharmonic 之类的主意,反正我对交响乐的兴趣也就一般啦。

最后是千塔之城布拉格。虽然主要是冲着穆夏去的,但是安排了三天的行程实在是太明智了。感觉这是一个很适合发呆的城市,每到下午我就跑去查理大桥发呆听街头音乐,一直到天黑人散尽为止。因为别的地方的街头艺人一般都是一把吉他,所以在这里看到街头各种提琴、电钢琴以及一些稀奇古怪的吟游诗人带来的民俗乐器之类的就觉得很奇特。更神奇的是还在这里碰到了 YZ,成立了 MSTC 驻捷克临时分部……

最开始是在巴黎的圣心堂附近买了一张非常精致的明信片,看那个设计原本以为是现代装饰艺术的卡片,结果发现作者是十九世纪的人,就是慕夏,Mucha 也有翻译做”慕哈“(就音译来说是更准确的),然而我真是非常喜欢慕夏这个名字,当然画也非常喜欢。在城里有一个 Mucha 纪念馆,可以看到他的许多作品,虽然并不是原件(当然由于他那些装饰画主要是用于商业印刷,不知道到底有没有原件保留以及什么算是原件)。另外我后来在离市中心稍远的地方闲逛的时候发现一个叫做 Trade Fair Palace 的地方,里面放着 Mucha 晚年的巨幅画作系列斯拉夫史诗 (The Slav Epic),并不是之前的装饰画风格,而是写实油画风格的大约 20 来幅是 6x8 米这种规格的巨幅画作。能发现这里也纯属意外,完全没想到 Trade Fair Palace 这种地方为什么会是博物馆,不过好像所谓的 National Gallery in Prague 本身就是由集散在布拉格各处的一些分馆合起来的总称,而这里也是其中一个,所以说感觉很容易错过的样子。另外旁边还有一个交通工具的馆,火车汽车飞机摩托车自行车各个年代都有,感觉非常有趣,虽然好像主要是小朋友在参观。

呃,我果然把总结写成游记了。旅行的事情先就此打住吧。2015 年,自身的经历和变化,认识到的一件事情就是:和自己做斗争,真实惨无人道的至死方休的战斗。换句话说在养成新的习惯学会新的东西的同时也有可能会养成坏的习惯和忘掉旧的东西。这一年感觉自己的拖延症尤其严重:小事比如经常晚上要十二点前睡觉也会拖到一两点,大事比如 Qual 结束,TA 的要求也完成了,之后本来应该要想 Thesis Topic 的却一直没有仔细弄,连 blog 也几乎全年处于荒芜状态,还有原本在想明年要不要找实习也是拖到十二月了才马马虎虎弄了一下,发现好像很多坑都早就满了又有种懒得弄了大不了留学校的感觉……

拖延症加重的原因除了完美主义强迫症之外,另一个一个重要原因大概是由于客观上来说本身要做的事情就太多了又都很不 trivial,真的做不过来……比如秋季学期就是既在做 TA 又在修课,身上压着两个 funding 相关的 project,以及其他的 meeting,绘画课和游泳课,还要做开源相关的东西。当然我自己也脱不开干系,总结起来就是我太拖泥带水,很多事情都放不下,这也想做那也想做,最后就会所有事情都卡住做不了。或者说即使想要 follow 本心舍小区大什么的,也由于自己生活完全无战略目标和计划可言(好像看《大秦帝国》看得有点走火入魔),自然就乱了章法。新的一年如果在这个方面有所突破的话当是万幸。

说到 open source,其实也比较好玩,去年提到有做一个东西叫做Mocha.jl,顺便我后来才发现发音很有歧义,其实我最开始想的是“摩卡”,而不是“抹茶”哈哈……^_^bb。总之这个主要是去年做的,到后来在 Julia 社区似乎变得比较有名了,在 Github 上是 Julia 的 package 里是 star 数仅次于 IJulia 和 Gadfly.jl 的项目,导致有时候会有人建议我去一些场合讲这个,比如 OSCon、JuliaCon 之类的,多少有些无心插柳,其实我虽然会在实验和解具体的问题中有时候用到 deep learning 模型,以及对背后的优化和理论方面的东西都比较感兴趣,还有也会抽空 follow 一些最新进展,但是我自身的研究课题并不能明确地算是做 deep learning,不过这年头反正全民皆 deep,也没有那么多界限分明了。

总之托这个福,也让我认识了不少新的朋友和同事,接触到一些新的机会。记得之前在哪里听过一个 talk 里收到过一个建议就是,无论任何时候去做 presentation 都要做好万全的准备,因为你永远不知道听众里会出现什么样的人(并不是说会有人问问题把你问到死,而是说可能会碰到手握你将来生杀大权的大佬啊,或者是未来的志同道合的朋友啊之类的)。到现在我很难讲自己做到了每一次做 presentation 都做好万全的准备,不过对于这个道理的认同感也确实是越来越深了。此外大概九月末的时候在 winsty 的引荐之下认识了 tianqi 他们那一帮dmlc的人,他们正在搞一个叫做MXNet的比较新的项目,问我有没有兴趣帮他们搞一下Julia 的 binding,因为看起来也比较有趣,就顺势加入了这个组织。后来还在加拿大的时候跟团队其他人见了一面。不得不说他们真是太勤奋了,东西海岸不过三个小时的时差,就导致我每天早上醒来的时候得 archive 几十封 github 的 pull-request、issue 相关的邮件才起得了床。总之是非常有活力的一群人,让我想起了埼玉一开始的台词,「趣味でヒーローをやっている者だ」(“兴趣使然的英雄”)。:)

反正我觉得这其实是温情满满的一年,其中有一件事情让我感触特别深。有一次路过 Stata Center 一楼大厅的时候看到一个女生拿着粉笔在大黑板面前发呆,黑板上写了一个大大的 H 字,下午再次路过的时候看到上面写着“Happy Tuesday”,瞬间就觉得被各种劳累和压力烟消云散,一下子就被治愈了。真是没有想到原来很多时候人们只是需要如此简单的鼓励,我想肯定有很多路过的学生跟我有同样的感受。

那之后的很长一段时间,几乎每周都会有不同风格的“Happy Tuesday”出现(有时候是其他 Weekday),一直持续到大家期末考试结束。每次看到这个就会拍下来,一开始觉得很神秘,后来渐渐觉得这不是一个人能完成的,说不定是某个神秘的社团呢。到后来某一天起得特别早,跑去 stata 楼下买咖啡的时候看到一个小朋友正在黑板上涂鸦中,就上去道了谢,顺便询问了一下,原来她们一共只有两个人在换班!

不知道有多少人被这些黑板涂鸦鼓舞了士气,平时也时常见到旁边有小字写的 thank you 之类的,客观来讲很难说写个 happy tuesday 的实际作用是什么,但是人类果然是社会生物啊,就好像之前看的《Liars and Outliers》一本书里讲的,人类社会的建立,本身就是一个奇迹,因为你的整个生活乃至生存的根本都得基于对数不清的跟你非亲非故的各行各业的人的信任之上。就好比博弈,如果人类一直都按照Nash equilibrium那样的方式来行事的话,大概整个社会系统最初就没法建立起来。然而如果考虑到人是需要群居,并不断地互相打交道的话,诸如“信任”、“信誉”之类的概念就渐渐地出现了,其实现在机器学习里 online learning 里的研究课题差不多就是这样的repeated game,只要从长远来看做到 No Regret 就好了。比如今年 NIPS 的 best paper award 之一的 Fast Convergence of Regularized Learning in Games,就是讲这方面的东西:过去关于 online learning 的研究,即使考虑了 repeated game,也还是在对方是完全 adversarial 的情况下考虑的,更“真实”的情况是各个玩家都采用一种 no regret learning 的策略(比以前更加贴近于人类社会的模型),这篇论文证明了在这样的情况下能得到比 adversarial 快很多的 convergence rate。

感觉我好像有点扯远了,说起 conference,今年非常幸运地包括自己去开会以及由于各种各样的原因而得以蹭会等等,围观了包括 CVPR、COLT、ICML、INTERSPEECH、NIPS 等各个领域的会,也算是增长了不少见识。此外还有一件比较有趣的事情就是今年 TA 的一门课里由于有几百个学生,试验了一种 peer review 改作业的办法,完全使用真实的 paper review system,TA 扮演 program chair 和 area chair,学生匿名提交作业,并且充当 reviewer,最后的评分会根据 reviewer 打分综合得到,当然如果 reviewer 乱搞(比如某篇作业的评分 variance 很大的话就很容易发现)会被额外扣分,所以最后大家都很认真对待 review 的事情。虽然中间有各种各样的小问题,但是总的来说还是蛮成功的,反正既然是 graduate level 的课,让大家早日接触到这样的流程也是一件好事,特别是现在 AI 相关的领域科研热,NIPS 明年居然都说要开始试验强制要求所有 submit 了 paper 的人就要充当 reviewer……不过我想说的是,当了一回山寨的 PC 之后,真的是非常想给那些有好几千 submission 的会议的 PC 致敬!😂

真的越说越远了,还有什么事情要说的?哦,今年重新配了一副眼镜,因为之前的眼镜在 Oregon 玩的时候被大风吹跑了………………虽然平时不戴眼镜,但是上课的时候会用,其实可以明显感觉自己的视力是在下降中的。

恩,还有朋友之中不少人结婚了,直接或者间接地见证了大家组成新的家庭,很是开心,甚至还有幸当了一次伴郎,大概是自从小学时期六一儿童节上台表演以来第一次穿正装啊。当然有聚就有散,似乎是亘古不变的真理,作为旁观者,这一年之中其实也目睹了不少分手的故事,甚至还有一些在感情方面比较颠覆三观的事情。想起来有人跟我开玩笑说看你每年的总结就是跳过所有的内容只看 8g 的部分,想一想莫非是我过去几年的总结都写得很“为情所困”的样子😂?不过今年就没有我什么事情了,直接导致我在选今年的歌的时候发现好难选。只好开始用几首压箱底的轻松愉快类歌了。

走路快一点脚步大一点心事少一点情绪好一点明天或后天不管不管不管向前看近一点就是这样摇滚吧全世界就是这样超越虚拟的界限就是这样颠覆时间就是这样天地是那么炫就是这样换个美丽画面今天不就是永远

好像全球好多地方今年都是暖冬,波士顿亦是如此,一直到年底几乎最后一天才下了一个上午的雪,当然这一个上午的雪直接导致我机票延误以及往后一连串的悲剧事件发生,😂可以说是“晚节不保”了。新的一年,希望改善拖延症,多写 blog!😀附上往年总结的链接:

The Volume of High-dimensional Unit Ball

$
0
0

高维度数据是现代机器学习的一个重要特点,而人脑无法直观地对超过三维的东西进行 visualize (至少我自己做不到)一直是我觉得作为一个人类最痛苦的事情之一,如果什么时候有机会做一回超人或者宇宙人什么的,能够选择技能树的话,我大概会优先选择这一项吧。正因为如此在高维空间中的许多现象看起来非常“反直觉”。比如今天我们要讲的结论是:高维空间的单位球(半径为 1 的球)的体积随着维度的增大趋向于 0。我跟一个朋友提起这件事情的时候她说这是她在听说了“奇数和整数一样多”这件事以来让她最为震惊的事情。

首先,本文的主要内容来自于 Avrim Blum、John Hopcroft 和 Ravindran Kannan 的一本叫做《Foundations of Data Science》的书里的第二章。这本书还没有出版,在作者主页上可以下载到 draft。

我们都知道一维的单位球(是一个线段)的“体积”(也就是长度)为 2,二维情况下的“体积”也就是(面积)为\(\pi\approx 3.14\),三维的体积是\(3\pi/4\approx 2.36\)。似乎并没有什么明显的规律。但是只看三个 case 要总结出规律其实比较勉强,这也是为什么只能 visualize 到三维为止是一个局限性非常大的技能,因为基本上总结不出在高维里应该“长什么样”的直观规律来。

不过要讲 intuition 的话,其实还是有的。虽然几何课上没有学过高维球体的“体积”的公式,但是我们知道立方体的体积永远都是所有的边相乘。所以\(n\)维的 unit cube 的体积永远都是 1,然后我们可以将 unit ball 和 unit cube 相比较,就能得到一些信息。

这里我直接盗取了书中的插图 2.3:如上图最左边所示,我们可以将一个单位正方形和一个单位圆同时置于原点。从原点到圆上所有点的距离都是 1,而从圆到正方形的最短距离是到边的中点的距离,为\(1/2\),而最远的距离为到两边交点的距离,为\(\sqrt{2}/2\)。中间一个图是 4 维的情况,虽然在网上见过各种各样的 4 维立方体的 visualization,但是我还是对它长什么样并没有一个什么具体的概念。好在这里我们的目的只是比较两个东西的体积大小,而有几样东西我们是知道的:

  • 原点到球面上任意一点的距离仍然是 1,和维度无关。
  • 原点到 cube 的“面”的距离仍然是\(1/2\),因为 cube 的边长被固定为 1,而这是边长的一半。
  • 原点到 cube 的“顶点”的距离可以根据勾股定理算出来,比如 4 维的情况就是\(\sqrt{4(1/2)^2}=1\)

可以看到虽然 2 维的时候 unit cube 还完全包含在 unit ball 内部(因此 unit ball 的体积大于 1),但是到 4 维的时候 unit cube 的顶点已经接触到 unit ball 的外壳。推广到\(d\)维的时候,顶点到原点的距离变成\(\sqrt{d(1/2)^2}=\sqrt{d}/2\),当\(d\)变大的时候这个长度可以变得很大,最终效果就如上面图中最右边所示。此外,虽然图中只画了 4 个顶点,但是实际上\(d\)维 cube 的顶点数目是\(2^d\)个,最终结果就是 unit cube 的大部分 volume 集中在顶点的地方,而内部的部分的比例越来越小。相比较起来单位球的体积也就越来越小。如果你觉得这个 intuition 还不够直观,可以通过积分来具体地计算\(d\)维球体的体积。在极坐标下单位球的体积可以写成

\[ V(d) = \int_{S^d}\int_{r=0}^1 r^{d-1}\,dr\,d\Omega = \int_{s^d}d\Omega \int_{r=0}^1 r^{d-1}\,dr = \frac{1}{d}\int_{s^d}d\Omega = \frac{A(d)}{d} \]

其中\(A(d)\)\(d\)维单位球面的表面积,而\(A(d)\)的计算可以通过一个迂回的办法来实现。考虑如下的积分

\[ I(d) = \int_{-\infty}^\infty \int_{-\infty}^\infty \cdots \int_{-\infty}^\infty \exp\left(-(x_1^2 + x_2^2 + \cdots + x_d^2)\right)\,dx_d\cdots\,dx_2\,dx_1 \]

这个积分很好计算,将\(\exp\)中的变量分开,我们可以分别对每个\(x_1, \ldots, x_d\)求积分,其中每个独立的积分可以直接通过一元正态分布的概率密度公式得到:

\[ I(d) = \left( \int_{\infty}^\infty \exp(-x^2)\, dx \right)^d = (\sqrt{\pi})^d = \pi^{d/2} \]

而另一方面,我们也可以通过极坐标来计算\(I(d)\),如下:

\[ I(d) = \int_{S^d}\, d\Omega\int_0^\infty \exp(-r^2)r^{d-1}\, dr = A(d) \int_0^\infty \exp(-r^2)r^{d-1}\, dr \]

而剩下部分的积分通过一步变量代换,可以发现和Gamma 函数的定义匹配起来:

\[ \int_0^\infty \exp(-r^2)r^{d-1}\, dr = \frac{1}{2}\int_0^\infty e^{-t}t^{d/2-1}\, dt = \frac{1}{2}\Gamma\left(d/2\right) \]

结合两种不同的计算\(I(d)\)的方法,可以得到\(d\)维单位球的表面积公式,以及体积公式为:

\[ A(d) = \frac{2\pi^{d/2}}{ \Gamma(d/2)}, \quad V(d) = \frac{2}{d} \frac{\pi^{d/2}}{\Gamma(d/2)} \]

现在我们可以很清楚地看到,球体的体积公式中,分子是指数级增长,而分母的\(\Gamma\)函数是更加可怕的阶层级别的增长,随着\(d\rightarrow \infty\)\(V(d)\rightarrow 0\)

到了这里,即便是超级 counter intuitive,也还是只能接受了。然而“问题”到底出在哪里呢?仔细想一想,好像“体积”的概念最初在提出来的时候并没有考虑到非常高维度的情况,也没有考虑会将不同维度下的“体积”用来相互比较。一个 cube 的体积是所有边长相乘,似乎总是会出现指数增长或者指数 decay 这样的不太好的情况,如果我们 normalize 一下会怎样呢?比如我们定义一个新的体积,在\(d\)维的情况下计算原来体积的基础上再开\(d\)次方根:

\[ \tilde{V}(d) = \left(V(d)\right)^{1/d} = \left(\frac{2}{d}\right)^{1/d} \frac{\sqrt{\pi}}{(\Gamma(d/2))^{1/d}} \]

例如一个 Gamma 函数的 lower bound:\(\Gamma(d/2)\geq (d/(2e))^{d/2}\),我们得到:

\[ \tilde{V}(d) \leq \left(\frac{2}{d}\right)^{1/d} \sqrt{\frac{2e\pi}{d}} \]

其中随着\(d\)趋向于无穷大,第一项趋向于 1,然而第二项还是会趋向于零。所以看来我们的 normalization 的补救并不能阻止高维 unit ball 的体积趋向于零。

Optimization and Assumptions

$
0
0

因为想要熬夜看Alpha Go 和 Lee Sedol 的围棋比赛,自己的围棋知识又没有达到能全盘 follow 看懂的地步,所以决定一边看一边写点东西。跟 AI 没有什么关系,当然非要扯上一点关系的话,可以这样来 motivate 一个话题。我们都知道人和电脑各自有一些各自擅长的东西,比如电脑擅长计算,而人脑擅长……呃,这里先留白,等我想到了再补上。总之我在最初接触 optimization 这个问题的时候其实也是这样的概念:计算机算法在这里似乎相当笨拙,比如我们经常看到类似图中的例子被用来说明当计算机面临 non-convex 问题的时候会如何陷入 local minimum 出不来。

相反对于这个例子,人“一眼”就能找到 global minimum 的位置。但是其实仔细想一想大概只是自我感觉良好而已。

首先人类到底怎样“一眼”找到这个 global minimum 的,其实我并没有什么概念,比如我自己大概一下子定位到 minimum 在中间一块,然后因为在 0 的左边和右边两个 minimum 相对比较接近一点,所以再多看了“一眼”,最终确定在 0 左边这里是 global minimum。感觉上似乎是一个非常复杂的甚至还有一些 hierarchical 的大脑计算过程,然而其实从另一个角度来看,比如从 information 的角度来看——如果我们遮住了 0 左边一半的曲线,那么我们就没法找到这个全局最优点,而遮住右边一半,虽然我们能找到全局最优,但这纯粹是运气好,我们也并不能确信自己是否找到了。所以不管大脑采用了什么样的算法,有一点我们可以确定的是它把屏幕上的所有 sample \(x\)和它对应的函数值\(f(x)\)全部用上了。

所谓的 sample 其实就是屏幕上显示的这一条曲线上的点。我在画上面这个图的时候实际上是在 -3 和 +3 之间平均取了 1000 个点\(x_1,\ldots,x_{1000}\),然后把对应的函数值画出来。虽然看起来是光滑的曲线,但是它并不是数学意义上的光滑曲线。而我们人脑不论使用什么算法,实际上 input 也只是这 1000 个离散点处的函数值而已。仅凭 1000 个点判断出 global optimum,人类似乎很厉害。但是其实这样的事情电脑也可以轻松做到:只要线性地过一遍\(f(x_1), \ldots, f(x_{1000})\)这个数组,电脑可以在比我快得多的时间内找到最优值,甚至不用“多看一眼”。

到这里可以看到,其实人类所谓的“看一眼”找到最优值,计算机如果想做的话也可以不费吹灰之力地做到。可是为什么计算机不这样做,而是去用一些看起来笨笨的像 gradient descent 这样的,在一个小小的局部最优坑里就出不来了的,鼠目寸光的,……,的算法呢?原因有非常非常多。我们下面列举一些,并和“人肉优化”进行比较一下,我们会看到其实计算机算法会碰到的困难人都是会碰到的。

连续性: 一个优化问题一般 formulate 成寻找\(f(x)\)的最小值,同时会对\(f\)做一些假设。从最弱(没有任何假设)到最强(比如明确知道\(f(x)=x^2+\sin(8x)\))中间会有很多过渡状态,比如\(f\)是连续、光滑、strongly convex 之类的等等。在最弱(没有假设)的情况下,问题是无解的。

如果我们对\(f(\cdot)\)一无所知,此时\(f(\cdot)\)成为一个黑盒子,通常叫做 0-th order oracle,我们可以给定一个\(x\),这个 oracle 会返回对应的函数值\(f(x)\),如果同时还返回该点的 (sub)gradient \(f'(x)\)的话,一般就是我们所熟知的 first order oracle。刚才我们所说的人“看一眼”和计算机扫描数组,都算是 zero order method。在不加任何假设的情况下不能保证找到最优解的一个最明显的难点就是函数的连续性。

不论我们采样了多少 sample,总归是有限多个点,如果对在没有被采样到的点处的 behavior 没有任何限制的话,我们将永远不知道是否真正找到了全局或者甚至是局部最优点。比如上面的图,如果采样率放大一万倍,你怎么知道在之前的\(x_{20}\)\(x_{21}\)之间没有非常 crazy 的情况出现呢?举一个极端的例子,考虑函数

\[ f(x) = x^2 + \sin(8x){\color{red}{ - 100\mathbb{1}_{x=\sqrt{2}}}} \]

其中红色的项只在一个无理数上取非零值,不论是采用浮点数存储计算的计算机程序,还是通过把图像画在电脑屏幕上来“看一眼”的人类,都不可能采样到那一点,所以最终谁都无法找到真正的最优解。而上面的例子中我们“看”到的最优解,也不过是一种假象。

连续性假设的引入差不多就是为了避免这种情况。回忆一下,我们说一个函数\(f\)\(L\)-Lipschitz 连续的,是指对其定义域内任意两点\(x_1,x_2\),满足

\[ |f(x_1)-f(x_2)| \leq L |x_1-x_2| \]

这里的绝对值\(|\cdot|\)可以可以换成任意度量空间上的度量。这样一来,我们就能对\(f\)在没被采样到的点处的行为进行刻画了。最简单考虑一个一维情况的例子:比如我们采样了相邻的两点\(x_1=0.1\)\(x_2=0.2\),带入连续性假设,我们可以得到,对于任意\(x\in[x_1,x_2]\),我们有

\[ \max\begin{Bmatrix} f(x_1)-L(x-x_1)\\ f(x_2)-L(x_2-x)\end{Bmatrix} \leq f(x) \leq \min\begin{Bmatrix} f(x_1) + L(x-x_1)\\ f(x_2) + L(x_2-x) \end{Bmatrix} \]

在一维的情况下,可以形象地画出来,在\(x_1\)\(x_2\)两点之间,\(f(x)\)的取值范围被限制在了一个菱形方框以内。这样一来,只要\(L\)足够小,采样点的密度足够大,我就能保证至少我找到的最优解即使不是真实的最优解,也“八九不离十”。而实际上我们也可以看到,很多优化算法一上来就假设\(f\)\(L\)-Lipschitz 连续的,差不多也是没办法。

有界性:很显然,即使有了连续性,如果我们需要优化的函数定义域是无界的,那上面的采样算法还是不会 work。比如说,万一最开始那个图,我把镜头往右移动到 10000 左右的地方,发现\(f(x)\)下降到 -100 的范围了呢?我们觉得 gradient descent 之类的鼠目寸光,只能看到局部的东西,但是我们自己又何尝不是井底之蛙呢?如果定义域本身是无限的,那么不管你眼睛睁多大,都只是一个“局部”。

所以,在实际优化问题中,经常用到的一个假设还有定义域的有界性。比如一般会假设只考虑包含在半径为\(B\)的球以内的\(x\)。当然,也有可能会有其他的方式来做假设,比如如果通过某种性质知道\(f(x)\)在“远处”的时候值趋向于无穷大,进而超过某个范围之后就可以不管了,这之类的。

实际上,在假设了连续性和有界性的情况下,“看一眼”或者说平均采样求值然后取最小的办法似乎不失一种有效的算法。比如假设我们需要在\([-R,R]\)这个区间上寻找函数\(f(x)\)的最小值,可以平均地采样\(m\)个点,然后令\(\hat{x}\)是这\(m\)个点中函数值最小的一个点。现在假设\(x^\star\)是真实的最小值点,令\(\tilde{x}^\star\)是这\(m\)个采样点中离\(x^\star\)最近的一个点,根据连续性,我们有

\[ f(x^\star) \geq f(\tilde{x}^\star) - L|\tilde{x}^\star-x^\star| \geq f(\tilde{x}^\star) - \frac{2RL}{m-1} \]

同时根据定义,\(f(\hat{x})\leq f(\tilde{x}^\star)\),由此得到

\[ f(\hat{x}) \leq f(x^\star) + \frac{2RL}{m-1} \]

是不是很棒?对比一下,对于普通的 Lipschitz 连续并且 convex 的情况下做 subgradient descent,得到的 gurantee 也只是\(\mathcal{O}(RL/\sqrt{m})\),比如参见(Bubeck, 2015)的定理 3.2。简直不敢相信自己的眼镜,暴力等距采样法甚至在不要求函数是 convex,也不需要任何求导操作的情况下,比 convex 情况下用 subgradient descent 的 convergence 速度还要快(假设我们按照顺序,每个 iteration 做一个新的点的 query,所以采样的个数就等于迭代次数)。问题出在哪里?

维度灾难:这个词相信大家都已经相当不陌生了。高维度带来的问题不仅是问题本身变得非常复杂,我觉得更大的问题是我们很多在低维度里 develop 出来的 intuition 都变得不再成立,偏偏人类又没有办法很有效地 visualize 三维以上的东西——这个硬件限制一直让我觉得非常恼火。而我们这里提到的很多“错觉”,到了高维度的时候也就不攻自破。

比如人能“一眼”看到最优点,那在高维的情况下又如何呢?比如一个定义域是\(\mathbb{R}^2\)的函数,我们可以用一个三维的 surface 画出来(当然又会投影到电脑的屏幕平面上),是否还能“一下子”找到全局最优点呢?好像也不是太困难,但是如果把图中的等高线去掉,surface 上表示函数值大小的颜色全部标成同样的颜色又会怎样?

更高维的情况呢?如果定义域本身是三维的,我就已经没法 visualize 了,而我们似乎也没有办法从“外面”来进行观察,此时如果要“看”的话,估计得前后左右上下都找一遍才能找到最优点。至于更高维的空间,实在是难以想象如果我能观察到更高维的空间,会是怎样的一种视觉冲击哈哈。

另外,对于计算机,也会碰到同样的问题。到了高维的情况下,采样法迅速变得非常的差。在数轴上我们很容易算出要使得采样密到任意一个定义域内的点到离他最近的采样点的距离不大于\(\epsilon\),只要采样\(\mathcal{O}(1/\epsilon)\)那么多个点就够了。在高维情况下,会变得稍微复杂一点,我们可以用covering number来刻画,一个集合\(K\)的 covering number \(N_\epsilon(K)\)是指最小的数\(N\),使得存在一个大小为\(N\)的点集\(C\),如果我们在每个\(x\in C\)上放上一个半径为\(\epsilon\)的 ball,则这些 ball 的并集包含\(K\)。换句话说,对任意\(x'\in K\)

\[ \min_{x\in C} \|x' - x\| \leq \epsilon \]

\(d\)-维空间里半径为\(R\)(球心在原点)的 ball 为\(R\mathcal{B}^d\)的话,\(N_\epsilon(R\mathcal{B}^d)\)就是我们需要达到精度\(\epsilon\)而采样的点的个数。我们可以简单估算一下一个\(d\)-维实心球的 covering number。假设\(C\)\(R\mathcal{B}^d\)的一个\(\epsilon\)-covering,显然

\[ R\mathcal{B}^d\subset\bigcup_{x\in C} \left\{ x + \epsilon\mathcal{B}^d\right\} \]

两边同时求体积,可以得到

\[ R^d \leq \sum_{x\in C} \epsilon^d = |C|\epsilon^d \]

因此\(C\)的元素个数,也就是\(R\mathcal{B}^d\)的 covering number 是大于等于\((R/\epsilon)^d\)的。可以看到此时采样法的收敛速度将会随着维度的升高而变得奇慢无比。而对比起来,之前提到的 subgradient descent 的收敛速度是并不依赖于维度的——这个好像也有点 too good to be true 是吧?在更具体的实际问题中,通常像 Lipschitz constant \(L\)之类的会随着维度增加而变大,所以也不能说完全是不依赖于 dimension 的,总之还要看具体问题而定了。

局部-全局:最后,在高维度下面采样法的失败导致我们从 sample complexity 的角度来说就无法得到函数的一个“全局观”,于是只能退而求其次,寻求“局部算法”,通过对问题添加更多的假设,使得我们可以得到诸如 gradient 或者 subgradient 之类的信息,只用局部的信息来进行 navigate。感觉就好像,来到了一个一百万维的世界,由于阳光同时从一百万个维度上照射过来,亮得整个世界只剩一片纯白,从此我开始闭着眼睛摸着石头走路。

虽然实属无奈之举,那摸着石头走路能不能保证我们能很接近全局最优点呢?很遗憾的是,不能——除非我们再加额外的条件,一些能够建立局部和全局之间的关系的条件。比如非常常见的一个条件就是函数\(f\)的 convexity。回顾一下 convexity 要求在每一点上存在一个 hyperplane,使得函数图像在这个 hyperplane 的“上面”。在 convex 的情况下,比如我在某一点\(x_0\)上发现函数\(f\)的 gradient 等于零(假设\(f\)可导的话),注意 gradient 是一个只依赖于\(f\)\(x_0\)附近的一个任意小的领域内的性质所定义的量,我们可以把\(f\)在稍远处的函数值随便怎么折腾,都不会影响原来那个局部点的 gradient。而有了 convexity 的条件之后,这个非常局部的性质一下子就能刻画函数的一个全局性质——也就是全局最优解的位置。因为 gradient 为零表示我们能够找到一个水平的 hyperplane 来 lower bound 住函数的图像,换句话说,任意\(x\neq x_0\)的点的函数图像都不会低于\(f(x_0)\),也就是说,\(x_0\)是全局最小值点。

当然 convexity 并不是唯一的能联系局部和全局的特性。对于某些具体的问题,可能有一些非常特殊的 structure,也能帮助我们在局部 navigate 的情况下最终找到全局最优点。比如对某些带有随机性的函数,我们可以通过某些方法大致估计出其 global optimum 的位置范围(作为算法的 initialization),并且\(f\)限制到某一个范围之内是 locally convex 或者只有 unique minimizer 之类的。再比如之前一篇尝试解释 deep neural network 优化的文章(Choromanska, Henaff, Mathieu, Ben Arous, & LeCun, 2015),其思路就是试图证明 DNN 中的目标函数\(f\)的绝大部分 local minimum 点\(x\)处的目标函数值\(f(x)\)都跟全局最优的\(f(x^\star)\)差不了太多。虽然这篇文章里面做了过多的简化和不合实际的假设导致最终的结论和实际的 DNN Training 过程中的目标函数的性质之间的联系变得非常不 clear。

实际上,近些年来 non-convex 的优化算法也变得越来越受到关注,一方面是 empirically 很多 non-convex 的算法效果非常好(比如 DNN training、EM algorithm、dictionary learning 里面的 alternative minimization 之类的),另一方面有些算法(比如Semi-definite Programming)虽然是 convex 的,但是速度比较慢,通过 re-formulate 成 non-convex 的问题有时反而会得到非常好的算法。

最后,一些 take-home message:暴力搜索并不一定就是很烂的;低维情况跟高维情况往往差别是很大的;要解优化问题是需要各种 assumption 的;assumption 通常都是有 intuition 可循的;convex 问题不一定就是可以(efficiently)解的;non-convex 问题不一定就是没有 convergence guarantee 的;一边看围棋比赛一边写 blog 是不行的,最后还是得重写过。

顺便说一句,我们在这里逐渐加上的各种 assumption 相当于是对问题添加各种 structure,在 Information Theory 里,我们有用于衡量概率模型的有序程度的 entropy 的概念,而这里虽然并没有 randomness 出现,但是实际上同样有这样的结构性程度的 notion 在里面,比如实际上有一个叫做Kolmogorov complexity的东西,用来衡量一个“object”的复杂度,具体就不在这里展开讲了。从哲学意义上来说, entropy 或者 complexity 的大小刻画了一个 fundamental 的“难度”,通过对问题添加一些 structure 的 assumption,将“难度”降低之后,才逐渐变得 approachable。

References

  • Bubeck, S. (2015). Convex Optimization: Algorithms and Complexity. Foundations and Trends® in Machine Learning, 8(3-4), 231–357. doi:10.1561/2200000050
  • Choromanska, A., Henaff, M., Mathieu, M., Ben Arous, G., & LeCun, Y. (2015). The Loss Surfaces of Multilayer Networks. In AISTATS 2015 (pp. 192–204).

Disable OS X System Integrity Protection

$
0
0

大学时代曾经一度在 Linux 和 Windows 之间挣扎徘徊,直到后来开始用 Mac,几乎是瞬间就觉得各种满意。好用的命令行加上好用的 UI,基本上不能奢求更多了。不过近年来感觉 Mac OS X 好像在某些奇怪的路上越走越远,特别是在命令行的兼容性方面经常出各种各样的事情。比如之前某次由于一个奇怪的原因需要手工恢复一部分 dotfile 配置文件,于是直接用cp命令从 Time Machine 的备份里把一堆文件复制过来,结果系统各种 run 不起来,后来发现好像是奇怪的权限问题,总而言之似乎是 OS X 在 shell 的基础权限之外又做了其他的权限,而cp不知道这些东西,所以拷贝过来的东西也用不了。由于我也不是 sys admin,对这些东西也不感兴趣,最后就用 Finder 比较麻烦地重新拷贝了一遍才好了。

不过今天要 fix 的是这个叫做System Integrity Protection (SIP)的东西,又叫 rootless,总之就是保护系统了。听上去感觉很有用的样子,似乎确实也很有用,不过刚出来的时候好像导致homebrew出了很多问题,然后最近由于DYLD_LIBRARY_PATH的问题终于忍无可忍决定要把它 disable 掉。

对 Linux 编程熟悉的同学应该都知道LD_LIBRARY_PATH,就是可以设置一些搜寻动态链接库的路径,通常安装一些第三方的库,如果不是直接安装到系统的/usr/lib之类的路径下面去(比如没有 root 权限,或者不想污染系统)的话,就可以把任意的路径加到LD_LIBRARY_PATH里去,让其他的程序还是可以找得到这个第三方库的 shared library。而DYLD_LIBRARY_PATH就是 OS X 的LD_LIBRARY_PATH对应物(好像直接用LD_LIBRARY_PATH也可以)。

然后现在 SIP 为了“安全起见”,把LD_LIBRARY_PATH和所有DYLD_开头的环境变量全部禁用了。症状就是一个程序在启动一个子进程的时候,是会继承父进程的环境变量的,但是环境变量里的这几个项会被系统给屏蔽掉。我也不知道为什么这个会破坏系统安全,但是确实这样之后带来各种各样的麻烦,比如在 iPython 里要是用到 CUDA 的库之类的,就会找不到 shared library。如果想用lldb去调试一个依赖于一些第三方动态库的程序,或者用Makefile来启动一些 tests,也会发现找不到这些动态链接库。之前找到一个临时的解决办法是先用otool -L来列出你编译出来的程序依赖于哪些未 resolve 的动态链接库,比如这样的:

your-program-file
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1226.10.1)
    @rpath/libcudart.7.5.dylib (compatibility version 0.0.0, current version 7.5.20)
    @rpath/libcublas.7.5.dylib (compatibility version 0.0.0, current version 7.5.20)
    @rpath/libcurand.7.5.dylib (compatibility version 0.0.0, current version 7.5.20)

这些@rpath就是未 resolve 的,然后用install_name_tool把这些@rpath换成你知道的绝对路径,比如:

install_name_tool -change @rpath/libcudart.7.5.dylib \
    /usr/local/cuda/lib/libcudart.7.5.dylib your-program-file

当然每次重新编译过之后都又得 fix 一遍。非常麻烦,后来我发现可以直接把 SIP disable 掉,方法如下:

  1. 重启系统,按住Command+R,在出现的界面里选Utilities> Terminal
  2. 在出现的终端里输入csrutil disable
  3. 正常重启系统。

然后就一了百了了!不过没有了 SIP,也许系统不够安全了呢?不过要是系统真的不够安全还有办法就是换系统!特别是现在 Windows 都开始直接支持运行 Linux 的 binary 了,说不定几年之内“码农友好”的操作系统的局面会逐渐开阔起来呢!拭目以待咯。

Could a neuroscientist understand a microprocessor?

$
0
0

最近看到一篇有趣的文章叫做Could a neuroscientist understand a microprocessor? (DOI: 10.1101/055624)。讲的是用神经科学的分析方法来把计算机微处理器当做一个黑盒子来研究。这让我想起之前听过的一个 talk,里面有提到这篇叫做A search for life on Earth from the Galileo spacecraft的文章。

就是说人们开发了许多技术和手段来探测外星生命的存在,然后终于有人想起来拿这些方法来对地球做了一下探测,看是否真的能探测到生命的存在,或者说,从另一方面来看,看这些技术和手段是不是真的有用。看似非常自然的基本测试,好像却还是比较容易被忽略的样子。

而这篇 neuroscience 的文章,其实也是类似的东西。首先 neuroscience 是一个比较新的学科,我自己的不完全理解它很大一部分内容是研究大脑的工作原理。所谓 science,差不多就是一个设计实验、观察结果、总结规律、建立理论、行为预测、结果检验的迭代过程。比如牛顿看到苹果从树上掉下来,于是建立了万有引力理论,用于刻画苹果的受力,同时还建立了牛顿运动定律之类的,用于刻画在受到给定的力的情况下苹果的运动。我们之所以接受这套理论是因为它能够进行“行为预测”,比如它能够描述梨从树上掉下来,桃子从树上掉下来,或者我们可以设计 controlled experiment,让铁球从树上掉下来,观察运动轨迹,验证理论的正确性。当然相比于“预测”,一套理论更重要的作用也许在于能帮助我们“理解”,就是了解事情的来龙去脉,因果关系。

但是与此同时,Science 之于 Math 的一大特点就是基本上“只能证伪不能证实”。就是说如果我观察到和理论不符合的实验结果,就可以证明理论是不正确的,但是不论我做出多少符合预期的观测结果,都不能严格地证明理论是“正确的”。比如后来爱因斯坦建立相对论,因为出现了一些牛顿理论无法很好地解释的现象。而爱因斯坦的理论是否又是“正确”的呢?或者说后来的其他理论。大概这是一个永无止境的过程。

而神经科学也面临着同样的问题,比如我们通过对脑部的 activity 进行测量,发现当我们看到人脸的时候,有一部分的神经元会有比较强烈的活动,于是我们可以建立一个关于脑部对于人脸专用的处理单元的模型或者理论,或者甚至关于Grandmother cell的理论。在比如通过对某些脑部由于意外受到部分损伤的病人的研究,发现某些部位损伤之后病人不能说话了,另一些部位损伤之后病人不能造句了,于是我们可以建立一个脑部各部分功能映射的模型等等。这里说得有点夸张和简化,但是大致差不多就是这样子。

从“预测”和“理解”的角度来看的话,神经科学的目的大概可以看成是 (1) 构建一个计算模型(或者实体计算机)能够实现大脑的功能;(2) 一套完整的理论用来描述大脑计算的来龙去脉。我自己的感觉是第一个目标大概是要容易很多的,也许不远的将来人们就能够通过海量的数据和计算训练出一个神经网络或者什么其他模型来,可以达到简单动物大脑类似的功能,然而这并不等价于同时实现了 (2),因为这个训练出来的模型也许就是一个很复杂的难以“分析”的东西,到头来我们并不知道它到底是怎么回事。一个极端一点的玩笑就是,其实要实现 (1) 很“容易”,只要 follow 一些固定程序,十月怀胎生一个小孩,你就算是 build 了一个 powerful 的大脑了,但是你还是不知道这个大脑是怎么 work 的。

但是所谓“理解”究竟是什么意思呢?感觉好像一个大脑是一件非常复杂的艺术品,似乎并不能像许多物理上的现象那样能用比较 clean 的几个公式就能完整刻画。并且如果只能证伪不能证实的话,似乎也很难讲什么是真正的“理解”。

所以这里计算机微处理器就登场了。虽然还达不到人脑的复杂度,但是一个现代的 CPU,或者说一台完整的电脑,显然已经是非常复杂了。并且幸运的是它是我们人类自己建造的,我的意思是说,所有的模块、功能、层次抽象从头到尾都是人类设计出来的,而不是在一个全连接的电路板上通过“gradient descent”之类的方法“train”出来的。在这个情况里,我们知道了计算机这样一个复杂系统,虽然极其复杂,但是并不是无法“描述”或者“理解”的,虽然也许要用上很多本大部头在加上 EECS 专业的学生数年时间的学习才能得到一个相对不那么粗略的系统概貌。第二点就是我们有一个 ground truth 在,所以我们知道当我们得到一些结论或者理论的时候,到底是正确的还是错误的。当然还有很多其他优点,比如在模拟器上能够做非常精确又不影响原始功能的测量(反过来要在不破坏大脑功能的情况下做很精确的测量其实是比较难的),还有基本上可以免费生成无限量的实验数据等等。

所以说,回到文中最开始提到的这篇论文。作者的做了一些有趣的实验,就是用神经科学里常用的一些实验设计和数据分析方法来分析一个游戏机板子。比如通过观测某些 transistor 会对某些像素有强烈的反应之类的来对 transistor 的功能进行刻画。再或者通过“杀死”一部分的 transistor 看是否会影响某些功能,来判断某些 transistor 或者“区域”的功能,比如作者发现禁用掉某一些 transistor 之后“大金刚”游戏就启动不起来了,那是否这些 transistor 就是大金刚专用 transistor 呢?当然我们知道微处理器本身是 general purpose 的结构,而逻辑存在于软件之中,可能就会觉得这样的结论不一定是正确的:比如也许它们其实是某些关键运算(比如加法)的 transistor,导致程序不能正确运行了,或者把磁盘之类的也考虑进去的话,也许刚好是存储大金刚程序的那部分“neuron”,所以程序不能正确运行了。等等。

We find that many measures are surprisingly similar between the brain and the processor and also, that our results do not lead to a meaningful understanding of the processor.

且不说文章里用的神经科学的实验设计和分析方法是否足够完整和严格,也不说它所得出的结论是否合理,就这个问题或者说设定本身来说其实是非常有意思的。虽然人脑和电脑的工作原理也许会有 fundamental 的不同,但是如果我们能有办法以黑盒子的方式从外部 reconstruct 出一整套关于电脑的工作原理的完整描述出来的话,那我们也就能很好地理解人脑了吧!


2016 无限大

$
0
0

那一年留在膝盖粉红的伤疤还刻着
那些在学会奔跑疼痛的过程都过了
好几年终于碰到肩膀的长发刺刺的
我要的爱情在距离永恒最靠近那次毁灭了
像一篇还没懂得分辨谎言的笨心得

朋友们开始问起我今年准备用哪一首歌的时候,我发现 2016 年又到了尾巴上。现在发在博客上的文章数量越来越少,以至于都快要只剩下年度总结了,不过至少年度总结是要认真写的。我想以一张今年的照片开头,但是好像虽然一年只在一转眼,要用单单一张照片来总结也还是不容易,于是就随便找一次喜欢的经历吧:深秋踩着冰凉的浪在沙滩上疯跑,裤子湿透了,爬满沙子。

接下来是正题,我想这次分主题来回顾一下:正经事(科研、学习、开源),不正经事(游玩、画画、音乐、读书、动漫、博客、电影、锻炼、游戏、感情)。既然已经是假期了,就先说不正经的事吧。

除了例行回国以外,今年欧洲主要跑了西班牙(巴塞罗那、马德里),剩下就是在美国,远一点的去了加州、Minnesota、芝加哥。近处主要就是一些短程的像 Cape Code、女巫镇世界尽头之类的。

西班牙是第一次去,在巴塞罗那刚下飞机,出租车司机就说,你是巴萨球迷吧,我一看你的围巾就知道了。我才意识到自己戴的格兰芬多红黄相间的围巾似乎也是巴萨客场球衣的颜色。不过可惜我并不是球迷,否则也许这次西班牙之旅还会有更多乐趣,不过即便如此也已经很好玩了。

巴塞罗那是海滨城市、旅游城市、气候温暖,市区有些地方走走就能到沙滩上。我去的时候已经是冬天了,水还是很冷的,不过可以看到很多穿着全身保暖服装冲浪的人。网上视频里看到的冲浪都是很酷的乘风破浪,现场倒是能看到更多现实:几秒钟的滑翔之后得费很大劲从岸边游回睡深处,再等待合适的浪头,如此不断重复。简直就是人生的剪影,所以看他们不断地重复倒挺励志的。

在海边的另一个好处就是海鲜。我一个人旅行的时候通常不会太花时间考虑吃什么,不过这次我有幸尝试了一个比较 hardcore 的模式:跟 JJ 一起逛景点(意味着凡是比较有名的景点肯定都不会被错过)然后跟 WZ 一起吃饭(意味着凡是有稀奇古怪的当地食物肯定都会尝试)。

除了足球和美食,巴塞罗那的建筑也很有名,比如圣家堂,已经持续修建了一百多年的大教堂,古典和现代的结合,非常值得一看,官方说是希望在 2026 年高迪诞辰 100 年的时候把它建完,不知道是否能实现。除此之外还有各种高迪的其他建筑,比如米拉之家巴特略之家桂尔宫等等,而且正巧那个时候我正好在读一本关于建筑师的书 The Fountainhead(后面会讲)。走到老城区,会看见各种广场、小巷、游客、街头艺人……总之是闲逛就很舒适的地方。虽然在去之前几乎所有人都警告我注意小偷,但是最后我并没有被偷什么东西,也没有觉得哪里有不太安全的感觉,也许是运气比较好?😛

我比较喜欢的博物馆有毕加索博物馆和加泰罗尼亚艺术博物馆 (Museu Nacional d’Art de Catalunya)。毕加索年轻的时候在这里待过,博物馆里有一系列按照时间顺序索引的他的作品,可以看到他幼年时期绘画水平就已经非常厉害,到后来逐渐成熟,最终走火入魔开始探索一些独特的东西,形成到后来常见的毕加索作品的典型风格。我去的时候还看到一个关于 Las Meninas 的展品集(不记得是不是临时展了)。Las Meninas是西班牙伟大艺术家Diego Velázquez的一幅名画,毕加索非常喜欢,晚年的时候画了 58 幅同人恶搞图解构分析的画作:毕加索版 Las Meninas。在网上可以找到一些图,比如这里这里。不过我也是不太看得懂毕加索后期的画,后来我去马德里在普拉多博物馆看到了 Velázquez 的原画,觉得很有意思。

其他大部分巴塞罗那的博物馆感觉还是以现代艺术为主。跟着 JJ 逛了好几个现代艺术馆,看到不少稀奇古怪的东西,大部分都不太能理解。我比较喜欢的有两个展品,一个是用一整面墙作为投影幕布循环播放猫咪喝牛奶的视频……另外一个是一间屋子里按顺序挂了约一百张从出生不久到 100 岁的人的照片。

期间似乎还有巴萨和皇马的一场球赛,不过显然我没有注意到这个,而是去加泰罗尼亚音乐宫听了柴可夫斯基D 大调小提琴协奏曲(Alexandra Soumm 演奏、Tomàs Grau 指挥)。不得不感叹欧洲听古典乐好便宜啊。对比起来后面看的Flemanco表演就性价比有点低。作为吉他的发源地,我倒挺想在西班牙听一场古典吉他的表演的,在网上听过Recuerdos de la Alhambra之后就挺着迷这种吉他轮指多声部的演奏。

过去收到过许多欧洲寄过来的明信片。从一个地方回来之后会翻出来看看上面的文字,自己走过看过之后再和单凭读别人的描述对比起来总是会有很多不一样的理解。我觉得旅行是一件很麻烦的事情,而且一点也不放松,每次一想到要计划出行之类的就会觉得很麻烦,但是当我在飞机上看到连绵的雪山、静止的海洋时,就会觉得跑出来真好!看过越多的地方就越觉得世界好大,特别遗憾的是许许多多的地方大概一辈子最多只有机会去一次。

巴塞罗那之后去了马德里,由于西班牙只给了我 15 天签证,所以就挑了近一点的地方玩。马德里是首都,不过经济上好像不如巴塞罗那好,英语普及率也相应更低一些。感觉法国人是假装不会英文,西班牙人是真心不会英文,包括许多看上去很年轻的人。我对马德里的第一印象是人好多!特别是几个广场以及连接的街道,简直是人挤人,有种到了中国的感觉。不知道是不是碰上了什么节假日还是平时就这样。

实验室有一位在巴塞罗那长大的学姐,我跟她讲我要去马德里的时候她一脸震惊,感觉也许对当地人来说马德里和巴塞罗那的旅游价值可能差别很大,不过马德里的特色是博物馆资源很好。而且奇怪的是街上那么多人却没有在任何一个博物馆碰到有排很长的队。并且许多博物馆都有每周或者甚至每天的免费时间段。所以我买的博物馆通票完全没有什么用处。

如果说巴塞罗那是高迪的天下的话,感觉马德里就是戈雅的地盘。Francisco José de Goya y Lucientes(1746年3月30日-1828年4月15日)一生风格奇异多变,从巴洛克风格到类似表现主义,不断地在探索和自我超越,并且对后期的现实主义、浪漫主义、印象派等都产生了重要影响。

在马德里普拉多博物馆里展出的最有名的两幅戈雅的画就是下面的“裸体的马哈”和“穿衣的马哈”两幅。当然下图右边的描述 1808 年的半岛战争中西班牙反抗人民北法国军队枪杀的The Third of May 1808也很重要,对后世的许多名画都产生了影响,比如印象派画家 Manet 的The Execution of Emperor Maximilian系列画作,以及毕加索描写西班牙内战的格尔尼卡(也在马德里,藏于索菲娅王后国家艺术中心博物馆)。在普拉多博物馆还能看到戈雅晚年风格迥异的“Black Paintings”。

除了普拉多之外,在马德里大大小小的各种私人或者公共馆藏里基本上都可以找到戈雅的大作。当然西班牙还有许多其他很厉害的画家。比如Diego VelázquezJoaquín Sorolla等等。

我个人觉得马德里除了几个广场、皇宫(有历史上最伟大的弦乐器制造师之一的安东尼奥·斯特拉迪瓦里的一只中提琴、一只大提琴和两个小提琴)、大教堂之类的逛一逛之外,剩下的就是泡博物馆啦。其中主打普拉多博物馆 (Museo Nacional del Prado),是西班牙最大的美术馆,据说 19 世纪末是世界四大美术馆之一。我从 10 点开门一直逛到晚上 7 点,后来临走前又趁免费的时间段又去了一次。实在是很喜欢,不过不能拍照,所以走的时候只好扛了一本跟我其他行李一样重的The Prado Masterpieces回来。不过我还是偷偷拍了一些照片啦,感觉就像在玩红白机游戏:观察NPC工作人员走来走去的规律,然后找一个周围的工作人员的共同死角区域和时段,迅速果断拍一张。😝

虽然我一般对文艺复兴及以前的画不太感冒,不过似乎普拉多有不少拉斐尔的画。另外有一幅 1490~1510 年间由荷兰画家耶罗尼米斯·博斯所画的人间乐园 (Tuin der lusten)实在是非常超前和震撼的。

普拉多旁边还有一个Thyssen-Bornemisza Museum也是非常不错,我去的时候还刚好碰到Renoir的主题特展。另外刚才提到的索菲娅王后国家艺术中心博物馆)也在附近,不过主打现代艺术,比较难懂。

除此之外我超喜欢的一个小馆就是El Museo Sorolla,其实应该就是画家 Sorolla 他家,离主流景点稍微远一点。最开始在普拉多看到他那幅Boys on the Beach的时候就很喜欢,但是因为之前并不了解西班牙的艺术所以没有注意到画家是谁。等到我走进他家的时候几乎是眼睛一亮。感觉他对光和影的描绘超级赞,他早期的作品感觉是 Social Realism 风格,主要描绘社会中大众人们的生活,比如那幅藏于普拉多的And They Still Say Fish are Expensive!就非常典型。后来他画了很多海滨的场景,特别喜欢他对于湿漉漉的皮肤和水的描绘,总之不知道怎么形容了,反正就是瞬间变粉丝就是啦。

其他的一些我比较喜欢的小馆还有 Real Academia de Bellas Artes de San Fernando 和 Museo Lázaro Galdiano。后者的布景很有意思,在一堆古典艺术品中时常会冷不丁出现一个现代艺术的展品,某个厅的顶画上还有“穿衣的马哈”和一大堆其他人物包括戈雅自己的自画像的混杂,没找到解说不知道是谁画的哈哈。最后偶然在某个小广告上看到Fundación MAPFRE有一个野兽派发展历程的特展,也是非常赞。非艺术类的航海博物馆也比较有意思,但是还有其他一些私人展比如 Museo Nacional del Romanticismo、Museo Cerralbo 我就觉得一般般,主要就是看别人当时有多有钱了。

至于美国,湾区去了两次,一次是去开会,时间比较短,印象比较深的是蹭到了神雕侠侣的神雕 winsty 和 wistone 的飞机,于是第一次见到金门大桥居然是俯瞰。第二次是暑假过去实习,呆得比较久。其实来美国这么久今年才第一次去湾区,去之前所听到的关于那边的言论完全是两极分化:有的人说那里是人间天堂,有的人说那里简直没法呆。我自己的感觉是并没有喜欢那里,天气虽然好,但是天天都是晴天也会很单调啊,偶尔也想看看雨发发疯啊。西海岸的自然风光资源似乎比东海岸要丰富很多,但是暑假也比较懒基本上没怎么探索过,所以也没有太大的感觉。其他好像没有什么了,感觉湾区最不缺的就是工作机会,然后其他就什么都没有了。中餐也很多,但是每家店都要开半小时车再排半小时队也是很崩溃的。

总而言之湾区给我的感觉就是超级大农村。以前我觉得界定农村和城市的主要因素是人口,到了美国才知道有“大农村”这种概念。感觉美国社会很多地方也蛮奇怪的,在科研各方面无疑都是世界领先的,但是日常生活中的许多东西都是很陈旧的技术和系统,比如无力吐槽的铁路系统,再比如近两年才开始用的芯片信用卡,刷卡每次都要等几十秒,前几日还被刚来波士顿的朋友吐槽说你们这里的地铁居然要等红灯的。当然很多都可以归结为历史原因,但是最源头的原因是什么呢?是不是这边早期汽车太发达加上太强调 DIY 了,凡是都自家搞定,于是就没有形成很好的社会分工和基础设施之类的。感觉湾区就是这样的典型,大家只是房子一家一家地挨在一起,放眼望去,全是住宅,特别是坐在神雕飞机上往下看的时候。但是除了住宅什么都没有,大家并没有构成一个相互分工合作的有机社会体,出现武器店、杂货店、药品店、客栈、游击士协会、钓公师团广场、公园、博物馆、电影院、音乐会馆之类的,如果哪一天大地震,把所有的房子自己互相隔开十公里,大概并不会对这个群体产生什么影响吧。

Minnesota 也是因为有事情过去的,并没有专门玩,印象就是并不是想象中的冰天雪地(毕竟去的时候是初夏)。之后去了一趟芝加哥,很不错,有点像波士顿的风格,不过密歇根湖和摩天大楼结合在一起的风光感觉是要比波士顿的查尔斯河要更胜一筹的,湖边骑车感觉很舒服。还有Art Institute of Chicago也很赞,有很多很厉害的藏画,印象中好像还在里面看到高更、梵高和梵高的耳朵之间的纠葛😃。芝加哥交响乐团也是世界上水准最高的交响乐团之一,不过那个时候我还没有很入交响乐的坑,所以没有去听。

剩下的就是波士顿周边游了。似乎东海岸这边能游览的自然景观确实不多。一次是去Cape Cod,一次是去女巫镇世界尽头。都是一日往返,比较赶,但是却玩得很开心。在 Cape Cod 的海滩上直接疯掉了,踩着浪跑呀跑,裤子全湿透了。后来又发现一块超级重的木头,不知道从哪里来的,那密度感觉像里面藏了黄金,大家费了九牛二虎之力把它立起来,然后怕会砸伤路人,就又把它推倒了。总之就是做一些很没有意义的事情但是好开心……在女巫镇更北边的 Halibut Point State Park 的时候天黑了(冬天天黑得好早),黑漆漆的树林里树枝们全都摆出很戏剧性的造型,一队人在里面抹黑走,很有魔幻童话的感觉。女巫镇数年前去过一次,记得那个时候还在墓地了读了好久的墓碑。

好吧游记先到此打住。现在本科生们已经结束了期末考,进入学生假期,学校周边就一下子冷清起来,临近年末,甚至各种店铺也都陆续关门了。我晃悠到 Food Court 去觅食,结果连 Food Court 也不开了,于是顺势进了旁边的 Coop 书店,看到一本白色封皮很漂亮的书叫做Absolutely on Music,讲一个作家和一个音乐家关于音乐的对话。在排队等待付款的时候上网查了一下亚马逊上的价格,果然网上买要便宜十块,不过节假日快递寄过来不知道都要多少天以后了,在物流这方面美国跟国内发达地区比差距还是相当大的,不过我想说的是在亚马逊页面上看到推荐了许多其他很眼熟的书,才发现原来作者是村上春树。我之前很少看他的书,不过这本我一口气在年末结束之内看完了,结果成了今年唯一看完的一本实体书。

数了一下,2016 年我读了共计 29 本中文书,10 本英文书,3 本日文书,几乎全都是以电子书的形式阅读的(对比起来去年是 42 本中文书,2 本英文书,1 本日文书,其中有不少是实体书)。今年我按照自己的喜好来大致排列一下,并尽量给一个豆瓣链接,以方便感兴趣的朋友。当然很多书(特别是翻译版)都是有很多不同版本的,我并没有特别深究。部分简介可能会有轻微剧透,我尽量不透露会影响阅读乐趣的关键剧情。实际上我感觉除了某些剧情有重要伏笔剧透以后就没法看的书之外,有很多写得好的书读起来的趣味性并不会因为剧透而受影响,特别是有些值得读好几遍的书🙂:

非专业类

  • 月亮与六便士》:英国作家毛姆笔下的名作。很多人即使没有看过小说,应该也听过这个 quote:If you look on the ground in search of a sixpence, you don’t look up, and so miss the moon。据说这是小说标题的解读,因为小说的内容跟月亮或者便士都没有什么具体的关系。小说的主角是一个画家,其原型是著名的后印象派画家高更。⑴我个人很喜欢这本小说,不论行文还是人物的塑造,都非常厉害,当然我也喜欢文中的主角,简单来讲就是一个纯粹的、义无反顾的、没心没肺的人。当然“喜欢”并不代表我赞成或者不赞成主角的处事方式,我觉得自己是不可能做得到那样的义无反顾的,所以就不用费力去考虑赞成与否了。实际上我觉得自己的性格也许恰恰相反,太拖泥带水,一直将自己 trap 在许许多多难以舍弃的东西里吧。⑵客观来讲,处在社会中,人们往往不得不做出各种各样的妥协,要做一个纯粹的人,不仅自己会付出很大的代价,身边在意你的人也会做出很大的牺牲,最终往往会造成各种争议吧。一方面这是一个很大很难的话题,另一方面其实也是与我们息息相关,人要如何对待自己和身边的人?人与社会是什么样的关系?所谓朋友是什么?⑶不知道现实中的高更是什么样一个人,他的画非常容易被辨认出来,在波士顿的 MFA 有他的名作《Where Do We Come From? What Are We? Where Are We Going?》。之前在布拉格的慕夏画室也看到过高更在那里弹琴的照片;在芝加哥艺术博物馆还看到一段关于高更与梵高的轶事:大概 1888 年梵高在法国南部租了一个小屋,邀请高更过去一起共创美好艺术新天地,在热切地期待高更到来的过程中,梵高灵感大发,为了装饰 studio,创作了许多后世名作,后来高更加入,他们还互赠自画像之类的,然而两个月之后两人关系破裂,高更离开,梵高精神失常,割掉了自己的左耳,而高更则好像什么事都没发生一样,还把梵高送他的自画像拿去卖了…这样的故事好像确实很像是《月亮与六便士》里有可能会发生的情景哈哈。
  • Absolutely on Music:村上春树对于小澤征爾(著名指挥家,在波士顿交响乐团担任了近 30 年音乐总监)的关于古典音乐的访谈,或者更像是朋友之间的讨论。村上春树并不是音乐家,但是他从小就听很多古典和爵士,通过小澤征爾的女儿(作家)相识,后来两人决定做这样一个访谈项目。全书主要以对话的形式呈现(没有任何乐谱出现),主要话题围绕协奏曲、交响乐、歌剧和室内乐展开,除了小澤征爾对音乐的看法和态度,还涉及到其他一些音乐人,例如古尔德伯恩斯坦马勒卡拉扬等等。有一些趣闻轶事(比如伯恩斯坦在一次和古尔德合作勃拉姆斯第一钢琴协奏曲的时候对观众说,接下来你们将要听到的是古尔德对于勃拉姆斯的解读,虽然我并不持相同的观点。)以及一些小知识(比如协奏曲中独奏演奏家和指挥谁做主导、指挥和乐团之间如何沟通以及都沟通些什么,指挥在一个交响乐团中到底起到什么样的作用,像古典音乐这样几乎所有东西都写在乐谱里了那指挥还如何做不同的“解读”),感觉更多的是两个人(一个音乐家和一个外行音乐爱好者)对于音乐的一些理解。

    我觉得特别是像古典音乐这种要真正理解还有一定门槛的东西,能有机会听到真正的音乐人自己对它的理解和看法还是挺难得的,感觉通常他们都不会太 care 或者没有时间与大众来交流这些东西,而本书写作的契机也正是小澤征爾因为动手术之后需要进行身体恢复不能继续指挥,突然有了一大段空闲的时间,才让村上春树抓住了这个机会两人聊了很多。我觉得这比那些“二手”的来自音乐评论家们的解读或者甚至是知乎上的评论更加珍贵一些。

  • 光明王》:蒸汽朋克与科幻魔幻的结合,非常有意思的设定,简单来讲所谓的“神”就是在基因或者科学技术上占有绝对优势的一部分人相对于普通人的存在。类似的设定在其他一些作品中也出现过,比如阿莫西夫的《基地》系列中有讲到在宇宙荒漠建立新的文明的过程中,先进的科技以宗教的形式存在和传播;而卡德的《天贼》虽然没有很强调,但是也基于这样的大背景下讲述了新文明的建立。如果你处在这样的“神”的位置,而“神性”是可以通过教育和知识传播的方式授予“凡人”的,那你是会严格限制神性的传播,建立阶级统治,还是会广播神性,让世界平等?如果你要传播神性,又需要怎样具体去实施呢?《天贼》里有一段给处于蒙昧状态的人类社会灌输“民主”思想的尝试,而这里的光明王则用了完全不同的方式。
  • 天贼》:《安德的游戏》的作者卡德的科幻处女作。前半和后半故事风格迥异,让人不禁觉得是不是两部完全不相干的作品,然而事实上只是两种不同的人类社会的形态。书中有许多有趣的内容,比如这本写于 1979 年的科幻小说成功预测了未来社会里大红大紫的“直播”文化,而关于新文明的成长和建立的探讨在关于《光明王》的讨论中已经提到了。看完的时候正好碰到《文明 VI》的发布,当时就很有兴致想看一看这个游戏关于一个文明的建立和发展是如何解读的,不过一直都没有时间去玩。

  • The Fountainhead》:Ayn Rand在 1943 年写的一本关于建筑师的小说,似乎 Ayn 本身所持的观点和这本书都是非常有争议的存在,而且这书的影响也一直持续存在,根据 Wikipedia 的资料,到目前为止在全世界卖出了 650 万册。主要争议的地方在于书中所持的对于“个人主义”和“集体主义”或者说“利他主义”之间的观点。当然并不是讲政治,而是讲人自己的本性。对“自我中心”的刻画以及高度理想化人物的描绘,导致它和上面的《月亮与六便士》很相似。事实上正是在我看完《月亮》之后 HY 给我推荐了 Ayn。当然实际上是很不一样的书,最明显的就是一个很短,一个很长很长……而且我觉得两者所要表达的观点也并不一样,《月亮》讲自我价值的实现,而《源泉》虽然是讲自我主义,要表达的却是人类社会整体价值的实现。

    我觉得 Ayn 的观点是,最大的“个人主义”就是完全无视别人,只在乎自己的价值实现,比如书中主角设计建造廉价出租房的目的是最大限度地实践自己的极简主义建筑风格,同浮华的古典建筑形成对比,每一块砖的存在都是有其功能上的作用和意义;相反他完全不在乎贫穷的人是否租得起房子之类的事情。而最大的“利他主义”则是凡事都以别人的 concern 为基础。

    个人主义是社会进步的基石,而利他主义是导致社会消亡的毒药。咋一看好像搞反了,但是其实也挺有道理。在自己所喜欢和追求的东西上面,人们才会拼尽全力,才会创新和突破。另一方面,极端的“利他主义”则完全不知道自己真正想要的是什么,一切都取决于“他人”的看法,他们并不会去真正认真做一件事情,而是只是让自己在别人眼中看起来好像在认真做一件事情。引用一些句子:“A truly selfish man cannot be affected by the approval of others. He doesn’t need it.”,“I think the only cardinal evil on earth is that of placing your prime concern within other men…. If one doesn’t respect oneself one can have neither love nor respect for others.”,而相反的一面,“They have no concern for facts, ideas, work. They’re concerned only with people. They don’t ask: ‘Is this true?’ They ask: ‘Is this what others think is true?’”,“Not to do, but to give the impression of doing. Not creation, but show.”,“What would happen to the world without those who do, think, work, produce?”,“He’s not really struggling even for material wealth, but for the second-hander’s delusion—prestige.”,“What was his aim in life? Greatness—in other people’s eyes. Fame, admiration, envy—all that which comes from others. Others dictated his convictions, which he did not hold, but he was satisfied that others believed he held them. Others were his motive power and his prime concern. He didn’t want to be great, but to be thought great. He didn’t want to build, but to be admired as a builder. He borrowed from others in order to make an impression on others. There’s your actual selflessness. It’s his ego that he’s betrayed and given up. But everybody calls him selfish.”。

    语言上来讲还是很有趣的一本书,大概书中的人物性格太强硬怪异了,所以有些地方经常看到忍不住笑出来。不过真的有点太长了,实体书好像是有 1000 页左右。并且虽然知道是故意要描写单纯的典型人物,但是有些地方还是觉得有点怪怪的啦。至于书中的哲学,我比较同意个人主义会是社会前进的动力或者甚至是主要动力,更确切的说,我觉得社会既不可能是完全建立在所有人都为他人考虑的基础上,也不可能建立在所有人都是 adversarial,即便不利己也要损人,最后达到的一种平衡之上;而是到达一种个人利益和集体利益有重叠的状态所达到的平衡点,因为若非如此,大概人类最初就不会群居并形成社会吧。最后,关于书中所说的 second-handed life,固然是不太好,但是凡事都以自己独立的想法为前提好像也并非就是好事,毕竟并不是每个人都能总是能像小说中的人物那样总是能迅速洞察到事情的本质。

    最后感叹一下建筑真是比其他艺术更难的一个职业啊。像画画啥的,如果能有办法糊口不饿死,再搞点钱买画材的话,基本上还是可以自由自在地作画的。而建筑除了等 commission 之外,完全没有办法,空有一身本事,没人找你修楼的话连自娱自乐都办不到。

  • 无人生还》:阿加莎·克里斯蒂的经典侦探小说之一,主打逻辑和人性。15 年底英国拍摄的三集同名电视剧也挺不错的,可以一起享用。
  • 东方快车谋杀案》:阿加莎·克里斯蒂的另一本经典。侦探之外,同时也在讨论一些诸如公正之类的大概永远也没有正确答案的问题。总之好像稍微多说一些就有可能会剧透了。
  • Harry potter and the cursed child》:JK 罗琳的新作,一个舞台剧的剧本,故事主要发生在哈利波特他们下一代的身上,当然哈利他们也有挺多戏份。实际上很大一部分笔墨描写的是哈利父子之间的爱与矛盾、误解、冲突与无助。有一个很有名的老爹,也许对一些人来说是一件幸运的事,而对另一些人却不是。总而言之感觉是很细致的描写。不过像这种“外传”或者“前传”、“后传”之类的作品里最让我喜欢的还是视角的改变:还是同样的 Harry, Ron 和 Hermione,但是当视角转换,他们变成别人的故事里的辅助角色的时候,我们看到很不一样的画面,并不是说作者改变了她笔下的角色,而是展现了事物的多面性,还有我们自己的 cognitive bias。实际上类似的事情在现实生活中也时常发生,有一些事件,时隔很久之后再以一种更加客观的旁观者的身份回忆起来,就会发现和当时其中时所看到的东西和现在很不一样。
  • 安德的游戏》:主线似乎是讲主角 Ender 如何在残酷的环境下生存并战胜困难,他所处的战斗学校是地球联军为了对抗虫族而建立的针对神童们说进行的心理和战术训练基地。而忽隐忽现的暗线则是讲述两个无法互相理解的文明之间相遇之后的种种。这似乎也是一个经常被讨论的话题,比如《三体》系列里有著名的“黑暗森林法则”,再比如《Stories of your life and others》里两个文明在文字和语言上的沟通和尝试。总之感觉很好看,故事发展也很紧凑。不过虽然已经习惯了日本动漫里中学生拯救世界的设定,但是在科幻小说里看到神童们作为主角却还是有点不习惯。
  • Stories of your life and others》:这是一个短篇科幻故事集,同名的短篇在 16 年底被拍成了电影,叫做“Arrival”,电影我就不多评价了,感觉在一些基本剧情上做了改动,变得更像伦理片而不是科幻片了。但是电影的生动形象无疑对于理解文中要表达的意思是很有帮助的。除了同名短篇以外,还有另一个叫做《liking what you see: a documentary》的短篇我比较喜欢,讲的是“看脸的社会”发展到最后的样子,以及人们采取的措施和所带来的一些其他问题,另外行文以 documentary 的形式给出,也比较有意思。其他的几个短篇也并不难看了,我想也许对短篇的要求会更高一些,除非是非常拍案叫绝的作品,否则好像对我来说留给读者大量的想象空间似乎并没有看作者精妙地展开故事发展和人物个性来得享受一些。毕竟如果不是写得非常好,要勾起读者足够的想象力也是蛮难的。
  • 秘密》:东野圭吾的小说,这本书相对于推理,更偏伦理和感情;相对于黑暗系,应该也更偏治愈系一点。感觉对于父女和夫妻之间的感情描写得很细致入微。不过缺点就是主线逻辑有点模糊不清,经常看着看着有点搞不清楚到底要讲什么。据说关于最终的“秘密”可以有三种不同的解读方式,在读完之后如果没有理解的话可以去网上搜一下解读。

  • いちご同盟》:基本上是为了《四月是你的谎言》而去看的这本书,顺便发现了在亚马逊上买电子书这一方便的日文书渠道。在《四月》中有一处宮園薰问有馬公生要不要跟她一起殉情。公生困扰了很久之后后来对薰说,君は王女さまじゃないよ。カヌレが好きなケーキ屋さんの子で小説のヒロインじゃない。僕はラヴェルなんて絶対弾かない。(你并不是公主殿下,也不是什么小说的女主角,只是一个喜欢吃カヌレ的蛋糕店家的女儿。我是绝对不会弹拉威尔的。)这些全都是来自《一五同盟》里的剧情。动漫里有一段渡亮太给住院的宮園薰从学校借了很多书来,其中有一本就是《一五同盟》,她在书里的借阅记录里看到了公生的名字,知道他看过了这里的故事,才跟他说那句“あたしと心中しない”(和我一起殉情吗)。看书的话,会发现《四月》跟《一五同盟》在剧情上有很多相似和关联的地方,同时也都是基于钢琴展开。总之作为《四月》与钢琴的粉丝,我还是挺喜欢这本书的。
  • 《旅人-柏舟》《旅人-怀人》:看过好多遍了,《旅人》一直是九州奇幻里我非常喜欢的一个系列。不过现在回想起来,好像前几次翻出来看都是一样在自己比较脆弱的时候。也许是作为类似心灵避难所一样的存在吧。
  • 遗落的南境》三部曲:击败《三体》拿走“星云奖”的小说,感觉是有点另类的科幻,有许多诡异和悬疑的地方比较吸引人,第一部比较好看。第二部似乎是想讲述权利斗争,但是讲得不好。第三部就不知道要讲什么了,仿佛是要把前面的一些线索联系起来,但是仍旧讲得不明不白,感觉要制造一个开放式结局,但是我感觉有些虚幻缥缈。比如像《The Fountainhead》那样的故事,讲到最后它想要表达的东西已经全部说出来了,真正故事的结局已经不太重要了,倒是比较适合开放式结局的,但是这个就完全云里雾里。我觉得大概在第一册的时候完结是比较好的。
  • 巨人的陨落》三部曲:看到评分超高特地买来读的,不知道什么原因一直以为是魔幻巨著,第一册看完一半的时候才反应过来,原来是讲第一次世界大战的(可见我历史也是很差的)。情节和人物的编制都挺不错的,有种看武侠小说的感觉,特别是武侠里特有的一点就是:但凡剧情需要,角色们无论走到哪个国家,都是随时可能碰到的。书中描写的一战的触发和扩大都是由一些似乎不至于发展到世界大战这种规模的事件,但是历史上应该是有一些更加本质的冲突和利益吧,资本啊资源之类的。
  • 大秦帝国(第二部):国命纵横》:上下两册,主要讲苏秦张仪合纵连横的故事。那个时候的国家制度还蛮有意思的,在一个国家任职,还能在另一个国家兼职,像“挂六国相印”这样的事情,恐怕在现在的各个公司之间,也是很难做到。但是那个时代的国家之间的竞争似乎确实更像当代的公司之间的竞争,更多的是实力、技术、策略之类的良性竞争,而不是像历史上后来的许多战争那样是不同的民族或者宗教之间的的冲突,目的不是要让自己变得更好,而主要是要把别人(外族、异端)都弄死。
  • 大秦帝国(第三部):金戈铁马》:主要讲范雎的远交近攻和白起的故事。看到了好多之前听说过的故事,远交近攻、胡服骑射、负荆请罪、纸上谈兵……还有“锅盔”的来历。就内容和故事来讲感觉是前三部中最好看的一部。不过大秦帝国的坑真是好大,后面还有很多部,暂时不想看了。
  • 走れメロス》:奔跑吧,梅乐斯是太宰治的短篇小说。讲梅乐斯必须要一路奔跑在一定时限内赶到一个地方才能救他友人的性命,这中间的赶路的过程。很短,但是感觉对人心的描写还是蛮细致入微的。等待与被等待,究竟哪一方是更让人难耐的呢?
  • 时间简史(第一推动丛书)》:同那本很流行的画册相比这个有更多的文字和细节。不过这种科普看多了就觉得好像并没有什么颠覆三观的东西,大概翻来覆去都还是那些内容吧。其实看到最后还是蛮伤感的,像物理之类的自然科学到头来都不能证明什么,只能等着被证伪。不过可证伪性大概也是自然科学最重要的一个特征了——比如跟宗教的东西比起来。其实刚来美国头几年也还会对诸如“证明上帝存在”之类的讨论活动之类的有些兴趣,但是后来发现很多时候宗教的东西根本就是不能证伪的,如果你不避讳地问及一些敏感问题,大概最终会得到“不要去揣摩神的想法”之类的模板回复,所以后来我就对宗教完全失去兴趣了。
  • 玛格丽特小镇》:故事以一种很有意思的行文方式来描写女性的内心世界,从童年到青年,到叛逆期、成年再到老去。当然,书的主题是关于爱情。什么是爱情,答案隐藏在故事之中,当然这大概原本就是难以确切地回答的问题,所以只能这样了。
  • 音乐的历史》:号称是翻译自房龙的书,但是我找了一下并没有找到英文的版本或者在房龙的作品列表里找到类似的书。总之是讲音乐的发展和一些重要人物的经历介绍。感觉有一些故事和《古典音乐一本通》里有些出入,果然历史上的东西还是大家各自众说纷纭吧。
  • 古典音乐三巨头的账本》:比较有意思的一本小册子,分析了过去知名古典音乐家的职业状态。简单地来说就是如果你是名人的话还是非常有钱的。
  • 古典音乐一本通》:古典音乐家的简介和八卦合集,看完的感觉是伟大的作曲家基本上是:终身未娶,或者娶了一个很彪悍的老婆苦不堪言;英年早逝,或者晚年精神病,或者耳聋眼瞎手残之类的……书的话还行吧,名家介绍感觉主要还是集中在八卦轶事上,后面的作品赏析由于没有给标准的作品编号,对于外行来说查找起来也比较麻烦。
  • 《北京折叠》:今年雨果奖入围的中国短篇科幻。还不错,就是篇幅实在太短了,感觉故事完全没有展开。越来越觉得“越短越难写”这句话好像真是挺有道理的了。
  • 顾城作品精选》:大概是我看的第一本诗集,当时好像是在别处看到一段他的诗,“草在结它的种子,风在摇它的叶子。我们站着,不说话,就十分美好。”才去找来看的。不过事实证明我还是不太能看得懂诗的。
  • 心が叫びたがってるんだ》:同名动画片“心灵想要大声呼喊”的动画脚本改编的小说,之前本来以为是原著小说,看完之后发现几乎跟动画片一模一样,只稍微补全了一点点细节……才意识到是先有动画片。总的来说这种音乐占很重要部分内容的故事,无声的小说的表现力就不如动画片了,而且动画片的叙事线条也更喜欢一些。【言いたいことを聞いてくれる人がいる。ちゃんと答えてくれる人がいる。】确实是一件幸福的事情。
  • 夏与冬的奏鸣曲》:据说是备受争议的推理小说。我完全没看懂,不论情节还是人物都不是很喜欢,也没搞清楚要表达的东西。
  • 光与暗的生灵》:《光明王》作者的另一部经典,不过我完全不喜欢看这本,草草翻完了。
  • 英伦魔法师》第一册:评价很高,而且有尼尔盖曼作序,似乎是很厉害的样子,但是看起来情节非常拖沓,很多看起来无关紧要的事情和人物,猜测后期也许会再次联系在一起,但是由于没有什么扣人心弦的进展,所以看了第一册也没有想要看后面的了。“英伦”也许是很贴切,描写的人物和故事浓郁的迂腐英国风。

专业类

  • Effective Modern C++》:原《Effective C++》的作者写的书,讲了 C++11 和 14 中的一些新的东西的用法和注意事项,有些地方讲得过于细节了,不过整体来讲是很不错的书。算是目前了解 C++ 新标准的一个很好的渠道。
  • A Tour of C++》:不错的小册子,用来复习 C++ 以及了解一下近几年新标准加入的一些新功能。
  • 《Practical C++ Metaprogramming》:O’Reilly 出的 50 页的小册子,主要讲 C++ 11 和 14 新标准改进之后的模板元编程。虽然新标准改进了地方,避免了各种奇怪的使用方式,但是模版元编程果然还是像一个晦涩的函数编程语言 dsl 小子集,尖括号代替圆括号,struct 代替 function,类型代替值。还是一套完整的 macro 系统更让人舒坦啊,不知道 C++ 还要统治系统编程多少年。
  • 《Why Rust》:O’Reilly 出的 60 页小册子,介绍了 Rust 管理内存的三大原则,ownership 的基本概念以及优点:避免内存错误,简化(?)多线程程序。Rust 的 ownership 系统作为现代编程语言中的独一无二的存在,固然是很有意思并且也很有野心,但是肯定也有它的 trade-off,如果书再多花一点篇幅讲一下 ownership system 带来的“坏处”,比如什么样的程序会变得难以编写或者非常麻烦之类的,就更诚恳啦。
  • 《C++ Today》:O’Reilly 出的 70 页的小册子,简要介绍了 C++ 标准化发展的历程和一些最近几年加入标准的新东西,还有对 C++ 17 的一点展望。
  • The Complete Idiot’s Guide to Music Theory》:书的内容覆盖比想象中全面,不过组织得一般吧,感觉更像是罗列表格和知识点的 reference book。

记得好像有句什么名言讲的是身体和灵魂总要有一个在路上,好像对于我来说经常是要么都在路上,要么都在家😅。因为主要的阅读时间都是在 travel 或者 commute 的过程中,其他就是吃饭的时候(我以前是比较反感吃饭的时候拿着手机看的,但是现在也渐渐养成了这样的习惯)或者是晚上失眠的时候(有时候是反过来,因为不小心看书看太晚了于是失眠了)之类的。当然偶尔也会特地抽出一段时间找个地方坐下来看书,不过一般是被情节吸引住了不得不往下看的时候。总而言之虽然我还是觉得看书的体验是实体书大于 Kindle 大于手机,但是琐碎和比较随机的阅读时机导致我虽然买了一些实体书,但是看的机会很少。比如我在三番很有名的城市之光书店买的一本《美国众神》,原本是很好看的,但是书很大一本,我不可能随身带着,基本上只有碰到回家吃晚饭的时候才有机会看,所以至今只看完了大概一半左右。

至于 Kindle,虽然比手机更不坏眼睛,但是由于现在电子书各大平台锁定用户,DRM 互不兼容,导致也基本上没法用。我看的书基本都是在多看平台上,从排版的质量上来讲,多看无疑是最好的,豆瓣正在改进但是差距也还很明显,而亚马逊的很多电子书基本上感觉就是用脚本转一下,连目录跳转都没有,还有一些直接有乱码,数量很多,质量却很差,经常准备买书的时候看到有更便宜的 Kindle 版都会点开预览看一下,然后吓得赶紧关掉。相比之下苹果的 iBook 最近好像很侧重在排版上,之前出了一款哈利波特的电子书,书里的插图就跟电影里的报纸一样是可以动的,非常有趣。多看的手机阅读器也很好用,并且对英文书的支持也很好(包括 hyphenation 和非常方便的词典支持,比 Kindle App 好用多了)。但是多看的 Kindle 系统对于现在比较新一点的 Kindle 设备都刷不了了,而且他家的书也没法去掉 DRM,所以目前我也只能在手机里看。希望电子书早日出现一个统一开放的版权解决方案,好让各个平台都能通用。

实际上关于为什么要看书,我跟朋友之间有过一些讨论。议题是“看书并不能起到放松和休息的作用”,特别是在看外文书的时候,cognitive load 有时会会相当高,更不用说有时候看上瘾了到深夜才睡觉导致接下来几天精神状态很差之类的。想来想去发现我没法反驳这一点,但是后来我发现自己看书(以及其他大部分兴趣相关的事情)的目的并不是“放松或者休息”,而是满足自己的某种“欲望”、好奇心之类的东西。

同样的理由也适用于旅行,特别是一个人背包旅行,简直就是一个不小的课题,要查阅景点、制定行程、订机票车票旅店、到了现场还会各种暴走到精疲力尽、在青旅因为室友鼾声如雷而睡不着、因为语言不通而迷路等等,总而言之是从熟悉的环境到未知的环境,有可能会碰到各种各样大的或者小的突发事件需要处理,如果是为了放松,简直找不到任何走出家门口的理由。

相关的另一个话题是关于“遗忘”,虽然没有专门跟别人讨论过,但是我有时会想这个问题,随着年龄的增长(也有可能是随着大脑内存的占用量增加),忘记东西的概率似乎越来越大,看过的书也好走过的地方也好,有时候会发现对一些细节变得完全没有印象。如果都会很快遗忘,那么是否还有必要去追寻呢?关于这个问题我并没有什么很好的答案,不过这也并没有让我很烦恼,因为这好像是在问,如果最终要死亡,是否还有必要努力地去生活一样吧?

某张照片追究也太傻
某个情节又何需惊讶
某些白发真实的表达
某个以后都是无限大
某个路人又哭着回家
某个电台用情歌惩罚
某次晚餐只听见刀叉
某个转角真的无限大

既然成功地生硬地插入了一段歌词,那么就来讲讲音乐吧。其实我一早想讲的,因为这基本上是这一年自己的一个重要改变。以往音乐在我生活中分量并不重,我本来是挺喜欢听歌的,比如学日语的最主要的原因就是为了日文歌。不过几年前开始长期耳鸣之后就听得比较少了。而 2016 年的重大改变就是我入了古典音乐这个坑,并且开始学习钢琴。

有时候我觉得我可以说在 2016 年谈了两场恋爱,一次非常非常长,一次非常非常短。长的这次就是跟古典音乐或者说是钢琴。为什么说是恋爱呢?因为我想来想去觉得只有这个形容最恰当啊,或者至少是可以称作是“单恋”的。一切都来得很突然,几乎是毫无征兆,在这之前所谓“古典音乐”在我的概念里跟“轻音乐”是混为一谈的,对音乐本身的认识也几乎为零,五线谱自不用说,给我简谱我也是唱不出来的,什么和弦、十二平均律之类的也都完全没概念,甚至连贝多芬和萧邦谁是谁都分不清,听得最多的古典乐大概就是卡农变奏曲的George Winston 编排版本(虽然我之前并不知道这是古典乐以及“卡农”是什么意思)和月光曲(根据小学语文课本,我一直以为自己听的是贝多芬的月光奏鸣曲,直到今年我才意识到那其实是德彪西的月光 Clair de Lune)。

导火线无疑是一部叫做《四月是你的谎言》的动画片。我不知道是不是所有人在碰到有好感或者有种相见恨晚的感觉的人的时候都会去试图搜刮所有的蛛丝马迹想要去努力地了解和认识这个人。我感觉自己那个时候就是这种状态:我去找各种关于钢琴、古典音乐相关的书(见上面提到的那些,一开始的时候看不太懂乐理相关的东西,于是就看历史八卦类的)、电影、纪录片和动画片(心灵想要大声呼喊、交响情人梦第一季第二季第三季坂道上的阿波罗The Highest Level: Lang Lang with the Berliner Philharmoniker莫扎特传不能说的秘密钢琴家Le concert海上钢琴师等等),还会去下载各种相关的 app、去听学校的钢琴 recital 和乐团的表演、去 Youtube 上看乐器演奏的视频、甚至还去 Coursera 上看相关的课程(强烈推荐这位耶鲁的老爷爷开的Introduction to Classical Music,穿插各种多媒体教学工具和实际演示,一点也不枯燥,他之前的一个叫做Listening to Music with Craig Wright也在 Youtube 上可以看到,更侧重音乐本身的角度而不是历史线条,此外比 Coursera 上的版本讲得稍微更深一些)。总之就是病入膏肓的即视感。而且有时候在从学校琴房回家的路上会走着走着就兴奋地跑起来跳起来,或者走路走着走着停下来了,因为试图用三拍同步双脚步子的二拍把自己搞晕卡死了(我节奏感不好),还有晚上会一直想着它翻来覆去睡不着,这难道不就是热恋中的迷失了心智的人吗?😝

几乎同时下的决定就是学习钢琴。对于一个毫无任何音乐和乐理知识,也不会任何乐器的人来说,确实有些突然。不过我当时想啊,电脑键盘上那么多键我都按熟了,钢琴不是差不多的吗?又不是像弦乐乐器那么复杂,只要按对键了就好了。当然事实证明自己当时的想法是多么 naive,不过幸好自己那个时候很 naive 啊。我先是借了 XH 的电子琴尝试了一下,当时碰巧碰到一个叫做Yousician的 app,可以通过识别你弹的音和节奏来帮助你学习和入门,我试了一下感觉非常好,就顺势买了一年的会员(当然后来我发现这个 app 主要是辅助作用,只靠它还是没法学习钢琴的),又花了两天了解了一下电子琴、midi 键盘和电钢琴的区别之后毅然(以给自己的生日礼物为借口)买了一个Casio Privia PX-160 电钢琴(当然后来我其实主要是在学校琴房的 acoustic piano 上练习)……总而言之似乎是一连串的冲动而不太明智的决定,但是好处在于这样我就骑虎难下了。其实这样说也不太恰当,因为我中途并没有犹豫过,唯一的障碍大概就是耳鸣会加重(好听的音乐听久了也会加重,所以并不是因为我弹得太难听了,虽然我也确实弹得不好听哈哈哈)。在咨询过 XZ 之后找了老师 3 月 8 日第一次开始上课,也找到了学校的琴房。

除去暑假不在的几个月,到现在为止加在一起大概学了有六个月左右了吧。跟我之前(什么都不会)相比当然是进步很大,不过还有很长的路要走啦。关于这件事情其实在开始之前我就想的很清楚:到入门或者说能比较容易弹自己想弹的曲子为止可能需要数年或者更久的时间(毕竟我画了这么多年的画也还没有做到能随心所欲地画自己想表达的东西),但是我觉得“时间”正是大人相对于小孩的一个优势——仿佛上一次写年终总结还没多久,现在马上又过了一年,在大人的世界里时间似乎总是过得飞快,所以几年或者十几年对于小朋友来说很漫长,但是对于我们来说基本上就是眨眨眼吧——虽然不是什么值得自满的事情。😂

但凡是在学校期间,我的 schedule 大致是每周上一次课,45 分钟,然后每天花大约一小时左右练琴,主要是完成老师布置的作业。前期主要是用的“小汤普森”和 Piano Adventures 这两本教材,最近刚刚开始小汤第四册和车尔尼 599。其实上课的时候相对于老师讲解和示范,更多的时间是我在弹上一周的作业,然后老师给反馈,但是我觉得上课比自己学要有用很多。一方面是进度控制(看我暑假时候的状态就知道了),更重要的是提供各种反馈,特别是初期可能会养成一些不良习惯之类的到后面可能很难改过来,而且很多东西自己基本上都不太会考虑到的。即使是像小汤普森里这种没有什么技术含量的两行小乐谱,老师弹出来也比我弹出来好听百倍,如果只是让我自己不断地去听两个版本对比来自己领悟究竟要怎样弹才能弹得好听的话,估计要花上十倍的时间吧。

我的老师是 XZ 介绍的,是河对岸 BU 的 Doctor of Musical Arts (Piano Performance) 在读,估计年纪实际上跟我差不多,但是不知道为什么我好像不太擅长跟她以朋友的方式相处,虽然她其实是个相当 nice 的人,大概是我心里有种老师的敬畏感吧,亦或者每次见面的时间都是要收钱的,不太适合闲聊太多啊哈哈哈。总之我觉得她是相当厉害的,之前去听过她的期末 Concerto Recital。不过我总感觉到这个行业对新人大概还是相当不友好的吧。之前在波士顿交响乐团听一个莫扎特的钢琴协奏曲,是由一位93 岁的老爷爷来演奏的。古典音乐界对于钢琴家的需求量估计并不是很大,而且已经成名的音乐家应该会长期占着坑使得整个行业长期处于饱和状态使得新人们得到的机会非常少。这样想想好像咱们读 PhD 的要搞科研但是好的学校的 Professor 的坑又不多的情况好像也并没有差太多哦?

不过不论是艺术还是科研,为之献身的人们我都是很敬佩的。暑假在 Google 实习期间我无意中发现有两个组,一个是Google Culture Institute,它们在做一个叫做 Arts and Culture 的 app,基本上就是我心中一直在想的一个东西,差不多就是把世界各地的博物馆电子化。刚看到这个的时候心里一阵激动,每次在世界各地的博物馆徘徊的时候我都会冒出这样的想法——当然电子化的目的并不是代替博物馆本身,因为在博物馆看原画和拍下来的照片的体验差别还是相当大的,但是我们需要一个方便的索引,帮助我回忆起在某个博物馆看到了哪些画、或者找到哪幅画在哪里馆里能看得到,或者一些扩展功能比如相同、相似类型的画,不同的流派、风格、发展等等。另一个项目组是Project Magenta,基本上就是机器学习跟音乐组合。我感兴趣的技术和艺术之间结合的项目,从某种意义上来说也许是非常适合我的地方,但是兴奋之余似乎自己心里也清楚,自己大概会一直避免把艺术变成自己的主业吧。其实我不太清楚自己在追寻什么,有时候觉得需要好好了解一下自己,但是从来也没有真正认真思考过的感觉。

回到音乐的话题上,我发现在多少了解了一点乐理知识之后,自己也渐渐开始对交响乐之类的大型曲目开始感兴趣了(之前是肯定听睡着的),不过开始去BSO听音乐会也是冬天的事情,想想在波士顿能有这么好的资源,并且学生票只要 7 块钱就能听一年这种福利不好好利用真是太浪费了。难以想象我在刚来的第一年就买过一张 BSO 的学生年票,然而因为要去拿票跑两趟最终一次都没有去听过就过期了。不过开始关注之后就发现其实周围挺多人会弹钢琴或者甚至弹得很好的,也有许多人对古典音乐很热衷的。

钢琴的故事才刚刚开始,前面的路还有很长,希望自己能一直 enjoy 这个新的爱好,同时画画的事情也不能落下。2016 年的绘画旅程大概可以总结为“买买买”“尝试了很多不同的画法”吧。比如以下依次是:中性笔肖像(在家的时间段通过豆瓣的一个上传照片画肖像的活动画了很多人脸);丙烯画星空(画到后面直接用手了,全是颜料);Wacom 板子用黑色画布和白色画笔学习透光效果(个人很喜欢这张);纯色块无线条风格;粉彩棒买来一直不太会用,画的人脸;天鹅堡(Wacom 加仿真画笔);宫园薰(马克笔,买了很久了第一次认真用,后来脸被我涂破了于是用笔挡了一下)。

另外我还稍微尝试了一下逐帧动画,为了简化工作量,我想做成前阵子网上很流行的那种动态照片,就是大部分内容是静止的而有一些细节如台灯啊窗帘啊之类的在动。结果并不是特别成功,我发现光画一个数秒钟的窗帘飘动的动画工作量都相当大的样子,以后有机会应该会再尝试的。后半年某天一冲动就买了个超大号的 iPad Pro,特别喜欢,看论文、做笔记、画画都很好用。更冲动的是后面我还订阅了 Adobe Creative Cloud 全套件,人生第一次用上了正版的 PhotoShop。下面几乎都是用 Apple Pencil 画的,最后一张则是学校的Student Art Association在 Student Center 的画室。去年在MFA学习丙烯画我觉得挺不错的,后来知道学校也有绘画课之后就觉得 MFA 跑过去好远啊,所以 XJJ 跟我提起 SAA 的课的时候我立马就报名了,虽然这边只有油画课得重新买颜料之类的,不过尝试一下油画也挺好的啊。我觉得我画画挺心血来潮的,有时候想画的东西,拖一阵子就一点兴趣都没有了,所以基本上如果不一次画完的话后面就不会跟下去了,而是会去画别的东西(比如下面那幅线稿,其实是上了一半色没上完,就干脆留成线稿了)。然而油画这个东西干得特别慢,除非就是故意要混成一团,否则黏黏的一层颜料的时候基本上很难在上面画东西,我想如果没有每周例行课程这种东西的话,我大概是没有办法完成任何一幅油画的了吧。

不过学校这边的油画课感觉跟我之前上的丙烯课很不一样,老师基本上不教任何技术,唯一一次示范就是教大家怎样把颜料挤到调色板上……感觉主要还是激发兴趣,鼓励大家自己尝试为主。然后就依次跟大家聊天,不论你画什么老师都会觉得很好……我觉得我问她最多的一个问题就是“黑色要怎么混来着?”😂。从这方面来讲学费的性价比不太高,所以有点小犹豫下学期还要不要选这个课。不过每次一想到快要毕业了,以后说不定就没有什么机会上这样的课了也不太找得到小伙伴一起画了。不禁想起暑假在 G 实习的时候,找到一个叫做 Sketch Friday 的活动,每周五午饭的一小时时间,5 分钟一幅画做快速 sketching,主要是练习速写、动作之类的,有一些网站有很大的模特图库,并且有定时功能,比如SketchDaily。活动内容虽然很有意思,但是我第一次去的时候加上我只有两个人去了约定的地点,其他人都通过远程视频会议连过来,第二次就只有我一个人了。原本就没有几个人参与,还全部都通过视频会议参加,画画过程中也没有什么交流,总之感觉怪怪的,跟自己一个人画好像没太大区别。

反正我现在从各方面都有点抗拒毕业啊,到了这个时间段,同年级的小伙伴们大家都多多少少到了不得不对未来做抉择的时候,不论是像我这样急着不想毕业的,还是像 SW 那样急着想要毕业的,好像大家的心态也都比前几年更加 unsettle 了。一个很明显的特征就是今年特别是下半年的集体活动频率大幅增加,基本上每周都会有聚餐或者桌游、电影之类的活动。直接导致我今年去电影院的频率大幅增加。2016 年比较喜欢的电影(包括在家补的以前的电影)和电视主要有:疯狂动物城神奇动物在哪里权利的游戏第六季莫扎特传The Highest Level: Lang Lang with the Berliner Philharmoniker蝙蝠侠:黑暗骑士机械姬奇异博士指环王1:魔戒再现无人生还星球大战外传:侠盗一号让子弹飞湄公河行动东方快车谋杀案

相比之下我今年看的动画片数量似乎跟去年相比又进一步缩水了,特别是新番基本上很少有我喜欢看的,感觉现在日本动漫似乎商业化越来越严重了,各种后宫各种套路,各种卖肉各种卖腐,不知道是现在市场太好了大家都冲着最大化赚钱的路子走还是说现在市场太不好了,不走套路认认真真做独立的动漫很难存活。反正结果是我把许多收藏了很多年的箱底片都翻出来看了。

  • 四月是你的谎言:这个是两年前的片,当时就听到好评如潮,但是不知道为什么我一直没有看,也忘记了是什么契机让我突然把它翻出来看的。然而不可否认的是这个动画片现在成为我人生中的一个重要转折点,即使抛开这一点,客观来讲,画风、配乐、人物刻画、感情描写各方面都是很棒的。我也就看了大概四遍吧。年底的时候日本上映了一个真人版电影,虽然据说差评如潮,但是还是很想看,可惜一直都没有资源。
  • 交响情人梦第一季第二季第三季,也是若干年前的老片子,蛮好看的,属于轻松愉快搞笑型,三季按顺序可以看出制作到后面变得越细致了:特别是演奏、指挥的画面从静止幻灯片变成了真正的动画。突然感觉音乐类的动画片画起来还蛮难的,比如弹个钢琴、拉个小提琴啥的,动作也不能乱画,还得和音乐配合得上,导致也不能重复利用(像交响情人梦第一季里翻来覆去用同一个小提琴的动画镜头,看着就特别糟糕),制作成本就上去了。像《四月》这样的精良制作里一些不太重要的配角在演奏的时候也是会用幻灯片风格的。
  • 红猪:宫崎骏的经典,并且好多宫崎骏爱好者都跟我表示过这一部是最爱,确实是非常好看。
  • 千年女优:“追逐着你,即便已经不再记得你的样子。因为我喜欢那样的自己。”也是一部经典好片,来自今敏,叙事风格很有意思,现实和回忆重叠。
  • 灰与幻想的格林姆迦尔:今年的新番,画面唯美,水彩风格,没有什么剧情,当然其实是有剧情的,大概就是类似于刀剑神域那种人被 trap 到了一个游戏世界里,但是剧情实在太过拖沓了,所以结局了之后我是直到下一个星期发现这一集是不是已经看过了,才意识到哦原来结局了啊。😓
  • 心灵想要大声呼喊:本来是看到宣传海报很喜欢画风跑去看的,结果被音乐惊艳到了。讲一个说话的能力被封印起来的女孩通过唱歌来表达内心的故事,全剧的高潮是音乐剧的演出,绿袖子改编的那一段歌『わたしの声』超好听,特别是在动画片里这一段登场的方式非常触动人。末尾的悲怆奏鸣曲Over the Rainbow的双声部合唱同时展开音乐剧的两种不同的结局,也让人耳目一新。
  • 亚人第一季第二季:分别是今年的一月和十月新番。故事背景是人类中偶尔会出现一些被称为“亚人”的人,其主要的特殊能力就是死了之后能复活,由于在社会上不太被接纳,而且政府也有一些秘密机构用亚人来做活体药物、武器实验之类的。故事则主要以两个意见相左的亚人为中心展开。感觉是很好的设定,不过似乎并没有能很好地探讨政治、社会方面的问题,不过许多战斗还是挺吸引人的,虽然介于 2D 和 3D 之间的神秘生硬动作的画风让人有点受不了。
  • 你的名字:新海诚的新作,在网上找的低画质版本,看低画质的新海诚有点暴殄天物。剧情还不错,觉得比他以前的好看,感觉偏搞笑一点,感觉男主丧心病狂。我个人觉得不太好的地方一个是女主说服她爸的过程直接被省略了,会让人有点觉得是编剧没有能力把这一段重要的细节描绘出来而耍了个小 trick;另一个是最后结局要是留成开放式,在两人即将回头的时候掐掉就好了。
  • 大鱼海棠:剧情无力吐槽但是画面很美,然而我看的是针孔摄像头偷拍版……
  • 其他还有只有我不存在的城市(新番,评分很高,但是我一直不太抓得住主题,看到后面忘记了,完结的时候补了一下结局)、传颂之物虚伪的假面(新番,画风比较喜欢,剧情比较拖沓,看了一阵子就忘记了)、恋爱随意链接(12 年的动画,中文标题翻译比较自作主张,感觉设定和故事 idea 很好,development 却很烂,铺出了很多很难的关于人心和人性的探讨,但是每次都莫名其妙就结束了)。还有就是由于对武侠的爱好一直断断续续地看的两部国产动画秦时明月(N 个月随机出一集)和画江湖(每周出但是每集大概只有 5 分钟的剧情,剩下都是广告以及片头片尾)。

漫画看得比较少,基本上就看了一点《亚人》、补了一次《热血江湖》的最新进展、还有愛瑪儂系列的后续,以及在图书馆看到终于购入了新世纪福音战士漫画的最后一册顺便补了一下。至于游戏,大概真正认真玩过的主要就是Transistor了,很不错的游戏,就是剧情有点短。Don’t Starve尝试玩了一阵子,还蛮好玩的,就是太难了又不能存档,基本上就是各种花样死法,捅马蜂窝被蛰死,生吃蘑菇被毒死或者被饿死、冻死……文明 6 出来的时候一直想玩,但是后来还是忍住了,感觉自己会一下子玩几天几夜直到猝死为止……Pokemon Go 出来的时候本来也没有在玩,但是到后来几乎成了你不玩都跟大家没有任何共同话题的时候还是玩了一阵,那个时候我的座位上坐着就能够得到两个补给点,于是抓了很多小鸟一个星期就到了 20 级,不过后来还是觉得比较无聊就没玩了。暑假心情抑郁的时候在公司的游戏机房随便玩了一些 random 的游戏,也不是很有兴趣。我发现现在的大型游戏都好复杂,而且欧美游戏那种画风过于写实化的游戏像古墓丽影这种我玩起来内心是有点受不了的……

锻炼差不多就只是不定期去游泳,偶尔实验室一个意大利人会叫我打乒乓球,总结起来就是比较缺乏锻炼。原本我觉得今年的睡眠质量下降了许多,不过看了下 Sleep Cycle 记录的数据,似乎跟去年差不多,而且似乎一年的睡眠质量有个很一致的 pattern 啊:差不多就是暑假睡得很舒服,9 月一开学就完蛋了,当然 Sleep Cycle 的数据也不知道到底有多准了。我自己觉得今年是有经常失眠的(很多时候只是由于弹钢琴弹得太兴奋了),不过也许这说明其实去年也经常失眠吧,哈哈哈。

博客显然处于荒废状态,我想我以后的目标是不要首页全是年终总结……不过其实偶尔会起个小头,但是后来又弃掉,也许自己要求越来越高,同时花在上面的时间也越来越少两方面的原因都有吧。也许明年可以尝试一下多写一点更加随意的东西。

最后是感情生活。如我前面提到,除了跟钢琴的这段“恋爱”之外,今年暑假期间其实有一段真实的感情经历,虽然开始和结束都异常地迅速,但是对我打击还是挺大的,所以我暑假过得比较抑郁,那阵子特别想家,也许对湾区的印象较差也有一部分原因来自于此。大概自己对于许多事情还是太过于天真和草率了。感情这种事情好像越是经历越觉得难以捉摸,我在想也许我就是个不太适合谈恋爱的人,作茧自缚也束缚了他人。除非一定要跟谁过不去,否则如果是能做朋友的人的话,还是应该好好珍惜认认真真做朋友比较好吧。比较有趣的是那阵子太难过了于是渐渐开始用微信朋友圈了,而之所以“开始用”正是因为两年前在感情受挫的时候关闭了朋友圈模块,所以说,真是神奇……😅幸运的是假期结束开学之后一大波聚餐电影桌游火锅 KTV 以及游山玩水活动来袭,很快就恢复了正常的心态,显然这是恢复最迅速的一次,当然有些东西大概是没法轻易遗忘的吧,所以 FF 提起陈奕迅的“一丝不挂”歌词里前后两段微妙的变化的时候才会觉得深有感触。我想成长对于记忆中伤口的作用并不是更快地遗忘,而是让它们慢慢变成你可以去正常面对和接受的东西。毕竟没有什么结是解不开的,等到大家都牙齿掉光了,所有的过去都不过是一时的年少轻狂吧。昨天收到信用卡公司寄来的新卡,原来自己这几年一直在用的两张卡都马上就过期了,打开信封发现各自同时还寄来了一张副卡,才想起当时申请的时候看到可以免费加副卡就顺便办了。现在看着卡上这个曾经很熟悉的名字,不能说心里没有任何触动,但是并不是什么很复杂的情感。

其实这两年单身期间时不时亲朋好友之类的会给我介绍女生认识,即便是在诸如地域、圈子等客观条件绝对不现实的情况我都有很认真地去对待,原本的想法是即使不会有过多的发展认识新的朋友也是挺好的。但是后来我发现好像这样交朋友的方式就是不太现实,原本就是极端微妙的 context,有时候好像怎样去 behave 都有点不太合适,即便抛开这些问题,没有合适的契机好像也是很难发展出持久的友情的。其实我有时候会想为什么大家都会觉得越长大越难以交到新朋友,也许根本原因并不是人越长大人心越复杂从而导致没法交朋友,正好相反,复杂的内心在引起共鸣的时候才会产生更加坚固的羁绊吧。我想建立深厚的友谊的先决条件一方面你们要有共同的地方,能够互相吸引,另一方面是你们要有一个交流、磨合和相互了解的过程,说得玄乎一点大概是要触及各自灵魂深处的共鸣点。基于这样的假设,年轻的时候容易交朋友的一大原因在于学校这个环境强迫一群原本不相关的人凑到一起,并且共同去完成许多事情,这给大家提供了很多共同经历和互相了解的机会,从中小学早操上课晚自习全都在一起,到大学自由选课,再到 graduate school 你的研究课题的细节可能在世界上没有第二个人可以讨论,这样的“强制社交”的环境是越来越弱的。那工作以后呢?按理说同一个项目组的人每天都在一起做同一件事情,为什么还会有人说工作以后交不到朋友呢?我想也许一个原因是工作上的同事构成比较单一,都是通过该工作为 criterion 过滤之后留下的人,所以不像学生时代那样只是由于地域之类的原因聚在一起的一堆人那么多样化?总之只是我的一些无聊时的胡思乱想。

好像扯得太远了,其实关于恋爱观,我也有考虑过一点。也许将来的想法会改变,不过现在我的态度是恋爱婚姻这些东西并不是人生目标甚至不是人生必须要经历的的一个 milestone,所以我大概不太会刻意去追求,当然也并不持反对态度。对我来说一个人和两个人大概就是不同的生活方式吧,一个选择问题,孰优孰劣无法定论。客观来讲我一个人就能开开心心地过,事实上我的生活看起来好像是非常充实的,甚至有时候非常亲密的朋友也会觉得我好像就不可能有空虚无聊的时候,然而事实并非如此,我想这大概就好比你再有钱也会有买不起东西的时候吧?——不同的人会有不同的烦恼。同理,两个人的生活也是有取有舍吧,我一点也不否认爱情的强大魔力显然也是这宇宙中独一无二的一种存在。

闲话说太多了,讲点正经事好了。今年是 PhD 第 4 学年到第 5 学年的过渡,课程方面早就已经没有任何需要处理的了,不过我一直觉得我很喜欢学校的一个原因就是可以不停地学各种东西,简而言之就是一种满足大脑的求知欲的精神毒品吧(大概跟人们会享受刷知乎了解各种五花八门的知识类似吧)。不过今年似乎悄无声息地发生了一点点转变,春学期的时候我只上了一门课,到秋学期我居然史无前例地一门课都没有修,甚至连旁听都没有。也许我终于转型到 graduate student 的状态,认识到应该把重心花在科研而不是课程上?或者说也许我突然到了该毕业的时间了?——虽然我心里挺抗拒毕业的,也许是我的学生生活过得太舒服了,但也许也只是我害怕这个转变吧:学生时代的结束,拖延了这么久还是无法回避的一件事。我在想也许我并不是害怕这件具体的事情,而只是对于“这是一个不可逆的过程”这个属性感到抵触,可想而知再过一些年月当我意识到我快死的时候肯定也会很不好受,毕竟那是个更加不可逆的过程。

科研方面差不多还是老样子,没有什么成果的时候就会觉得自己究竟在做什么,莫非整天在 lab 无所事事?偶尔有一些成果的话就会很欣喜,但是过一阵子又会觉得好像什么都没有做,渐渐就习惯了,好像科研的常态就是如此。暑假在 Google Brain 实习,虽然因为个人原因过得不开心并且导致有点回避各种社交活动,但是工作上还是比较顺利的,感觉自己这次能跟到很好的 host 也是非常幸运的一件事情,做的东西个人也觉得比较有意思。此外偶尔会抽空做一点开源的东西(上图是 github 一年 commit 频率概要),主要是MXNet吧,基本上是一阵一阵的。MXNet 最近发展得挺好的,感觉身在这样一个团队里是一件挺幸运的事情。

其他一些杂七杂八的事情:2016 年第一次开始用机械键盘。开始几乎每天喝咖啡。第一次坐小飞机(感谢飞行员 winsty)和帆船(感谢船长 XJJ)。第一次一个人租车开车(快要把自己吓哭了,我真不太适合开车)。继续玩了一阵子postcrossing,寄了不少明信片(包括一些自己手绘的)也收到了一些 lovely 的明信片,打开信箱的时候偶尔发现有东西还是非常惊喜的,不过后来由于 travel 中断了之后就没有继续玩了,好像有时候跟陌生人写明信片的时候有点不知道要说些什么。第一次收到陪审团传唤,虽然我并不是美国公民(感觉像是政府在骗钱,因为如果你在多少天内不回复说你不是公民不能参加陪审团的话就要罚款几千块)。第一次做证婚人。第一次去警察局报案(虽然不是我丢东西),还有第一次收到警察的邮件、电话、甚至上门访问的留言纸条等等(一个素未谋面的人不知道什么原因被警察逮捕了需要保释,然后他托警察通过 Google 搜索找到了我的联系方式……让我第一次认识到也许要开始注意互联网上的隐私了)。第一次 Career Fair 没有拿任何 free T-shirt,也许等剩下的这几件穿完我就会彻底告别 free t-shirt 了。买了降噪耳机,觉得很好用,开起来之后除了自己的耳鸣什么都听不见了,对于冰箱、空调之类的噪音很有效果,猜想飞机上应该也会很好用,不知道有生之年神经科学和脑机接口能否发展到可以对耳鸣进行降噪呢?第一次分清了村上春树 vs 春上村树以及郎朗 vs 朗朗。第一次简单做了一下个人十年总结,觉得自己变化好大,十年之后自己又是什么样子,完全想象不出来。

哪时候开始学会微笑不回答都忍着
谁说的那些疯狂年纪不同了非忘了
规则都只是神话
气象总是会偏差
冷一点暖一点也不过这样

2017,新年快乐!

Plotting 3D Surfaces in Python

$
0
0

最近需要 visualize 一些三维的曲面数据,于是简单调查了一下 Python 绘制三维曲面的一些常用的办法,贴在这里以免自己将来再需要用到的时候又想不起来了。比如我们想要画这个样子的 3D 曲面图。

方便起见,我们假造一个 user case,假设\(x\)\(y\)是两个 hyper parameter,现在你使用 grid search 的方式尝试了每个参数组合下的模型效果。

  1. importnumpyasnp
  2. defeval_params(x,y):
  3. # ...
  4. # Make data.
  5. X=np.arange(-5,5,0.25)
  6. Y=np.arange(-5,5,0.25)
  7. Z=np.zeros((len(X),len(Y)))
  8. foriinrange(len(X)):
  9. forjinrange(len(Y)):
  10. Z[i,j]=eval_params(X[i],Y[j])

现在我们希望把这个参数搜索的曲面画出来,看看最大值最小值、曲面的连续性之类的性质,所以我们需要画一个 3D surface 图。比较新版本的 Matplotlib 其实已经有挺好的 3D 绘图支持。上面的示例图其实就是在 Matplotlib 里画的。

  1. importmatplotlib
  2. frommpl_toolkits.mplot3dimportAxes3D
  3. importmatplotlib.pyplotasplt
  4. frommatplotlibimportcm
  5. fig=plt.figure()
  6. ax=fig.gca(projection='3d')
  7. XX,YY=np.meshgrid(X,Y)
  8. # Plot the surface.
  9. surf=ax.plot_surface(XX,YY,Z,cmap=cm.coolwarm,
  10. linewidth=0,antialiased=True)
  11. # Add a color bar which maps values to colors.
  12. fig.colorbar(surf,shrink=0.5,aspect=5)
  13. plt.savefig('surface.pdf')

其中import Axes3D那句虽然没有直接用到,但是如果删掉的话在创建 3D projection 的 axes 的时候就会出错。plot_surface这个函数负责绘制 3D surface,参数相当 straightforward。因为Z作为我们 evaluate 参数的结果是一个二维的矩阵,所以plot_surface需要的前两个参数也是二维矩阵,并且需要是和Z大小相同。

简单来说,对于一组 index (i, j)XX[i, j], YY[i, j]Z[i, j]一起给出了一个位于曲面上的点的三维坐标。而meshgrid这个函数就是用于方便地根据原来的XY来创建这样的二维矩阵的。

到这里我们的目标其实已经达到了。如果把上面的savefig换成plt.show()的话,会弹出一个对话框来显示 3D 曲面图,好处在于可以对曲面进行旋转、缩放等交互操作,有时候对于看到曲面被挡住的部分来说非常有用。不过 Matplotlib 的 3D 操作交互反应速度相当缓慢,可能是没有用任何硬件加速之类的简单实现吧。如果你不能忍受那个缓慢的交互速度,或者需要将生成出来的图片发给别人看,而对方又不一定是能运行 Python 代码的,那还有一个选择就是生成内嵌 3D 对象的 PDF 文件。PDF 文件可以通过PRC格式内嵌 3D 图像模型,不过目前只有 Adobe 家的阅读器(比如 Adobe Reader 或者 Adobe Acrobat)可以查看这种格式的对象。在 Acrobat 里打开大概长下面这个样子,可以对 3D 曲面进行各种操作和检查。

不过 Matplotlib 本身似乎并不支持直接输出这种内嵌 3D 对象的 PDF 文件。这里我们可以借助另外一个叫做Asymptote的绘图工具。它其实是一种绘图语言,和 LaTeX 结合得比较紧密,但是和PGF/TikZ或者是PSTricks不一样的是,它并不是实现为 TeX 的宏包,所以它的语法并不是一些看起来像英语一样的很飘逸但是一不小心就会语法错误的DSL,而是有点类似于 C 语言语法。很多年前用它画过一些 3D 的 vector field 之类的图,感觉比较适合画一些复杂的 scientific 的 illustration,可以看一下它的示例

当然我一般不会用它来 plot 数据图,不过这里可以借用一下的是它能输出内嵌 3D 对象的 PDF 文件的功能。Asymptote 画图的简单流程是创建一个foo.asy文件,把命令写在里面,然后执行

asy -f pdf -o foo.pdf foo.asy

就可以了。Asymptote 里构建一个 3D surface 可以通过一个叫做surface的命令来实现,它的第一个参数是一个描述 surface 的函数:输入是\(i,j\)两个 index,输出是一个三维坐标\((x(i,j), y(i,j), z(i,j))\)。这个比较适合画一些 parametric function,不过这里我们是直接 plot 数据,其实只要做一个简单的矩阵查表函数就可以了。Asymptote 里最简单的读取数据的方法是读入空白分隔的文本文件,打开文件之后只要对一个数组或者矩阵进行赋值就可以读入一行或者一块数据:

  1. importgraph3;
  2. importpalette;
  3. size3(150,IgnoreAspect);
  4. // Open the data file
  5. filein=input("data.txt").line();
  6. // read file by assignment
  7. // this read a line of numbers as an array
  8. real[]x=in;// first line
  9. real[]y=in;// second line
  10. // read the rest of the file as a matrix
  11. // 0, 0 means do not restrict the number of
  12. // elements to read in either dimension
  13. real[][]z=in.dimension(0,0);
  14. triplef(pairt){
  15. inti=round(t.x);
  16. intj=round(t.y);
  17. return(x[i],y[j],z[i][j]);
  18. }

数据文件格式非常简单,头两行分别是两个参数\(x\)\(y\)的值列表,然后剩下的行是整个数据矩阵\(z\)的一个表格。通过 Numpy 的savetxt函数很容易导出。在 Asymptote 里读入数据之后我们就可以构造查表函数\(f\)了,从上面可以看到\(f\)只是直接通过下标取得相应的坐标而已。接下来就可以直接构造 surface 并进行绘制了:

  1. surfaces=surface(f,(0,0),(x.length-1,y.length-1),x.length-1,y.length-1);
  2. s.colors(palette(s.map(zpart),Rainbow()));
  3. draw(s,meshpen=blue);
  4. triplem=currentpicture.userMin();
  5. tripleM=currentpicture.userMax();
  6. tripletarget=0.5*(m+M);
  7. currentprojection=perspective(camera=target+realmult(dir(60,210),M-m),
  8. target=target);
  9. xaxis3(Label("$\lambda_1$",position=MidPoint,align=-Y-Z),
  10. Bounds(),blue,OutTicks(Step=0.25,step=0.05));
  11. //Bounds(),blue,OutTicks(Label(align=-Y-X)));
  12. yaxis3(Label("$\lambda_2$",position=MidPoint,align=-5X),
  13. Bounds(),red,OutTicks(Step=0.25,step=0.05));
  14. zaxis3("Error",Bounds(),black,OutTicks(Step=0.25,step=0.05));

代码非常直接,唯一需要简单注意一下的是我们在调用surface函数的时候,传递了参数(0,0)(x.length-1, y.length-1),这里对应\(f\)在查表时的输入序列。

这样就大功告成了,当然缺点就是 Adobe 家族以外的 PDF 阅读器都看不了。第三个对于 viewer 来说比较 user friendly 的选项就是通过 web 页面。现在在 webGL 之类的技术支持下,其实 web 页面里渲染 3D 对象的效果其实已经非常好了。

比如之前在网上看到这个 3D 的卡通画,简直太惊艳了,我觉得现在的各种 3D 游戏之类的都处于严重的Uncanny Valley之中,让我非常难以接受,相反若是做成这种风格,应该会(让我觉得)赏心悦目很多。然而虽然看起来只是简单的 line drawing 的结果,但是实际的制作过程还是要进行正儿八经的三维建模、渲染之类的,作者在这里给了制作过程介绍,看起来似乎还是相当费力的。另外还有这里也有一些非常漂亮的 3D 线条漫画,看起来都非常酷,而且都是直接在浏览器了渲染出来的,不需要额外安装什么很复杂的 viewer 。

就我所知范围,目前的绘图工具中似乎plotly算是对 webgl 支持比较好并且也简单易用的。它们的 3D 图大概长下面这个样子,这里有一个在线的例子可以直接进行交互,渲染和交互效果都挺好的。

例如直接用我们刚才的 Python 里的数据的话,用下面的代码可以直接生成 plotly 的图,结果保持成一个 HTML 文件。文件里内嵌的 viewer,应该用任意一个现代一点的浏览器都能打开预览和交互。

  1. importplotly
  2. importplotly.graph_objsasgo
  3. data=[go.Surface(z=Z,x=XX,y=YY)]
  4. layout=go.Layout(title='Test Plot',autosize=True)
  5. fig=go.Figure(data=data,layout=layout)
  6. # save offline standalone HTML files
  7. plotly.offline.plot(fig,filename='test-plot')

唯一的缺点可能就是由于内嵌的 viewer,所以 HTML 文件还是比较大的,一个简单的 surface plot 大概也需要 2M 左右。另外 plotly 还能内嵌在 Jupyter Notebook 里预览交互图,它还提供收费的云服务可以在服务器上 host 你的 figure。

感觉以后的科技论文格式应该允许更多的交互内容,嵌入视频、音频、交互图表之类的,还有更全的 meta data,图表、公式、引用的预览、跳转等等。然而现实是目前很多地方还会要求 plot 必须是在黑白打印的情况下也能分辨的。

Distributed Learning in Julia

$
0
0

我之前在这里介绍过Julia这个语言,提到了它的许多好的(和不好的)特性,不过有一点没有提到的是它方便的并行和分布式计算的能力,结合优质的数值计算能力,其实让它非常方便用于做分布式数据处理——比如 distributed optimization、learning 之类的任务。虽然 Julia 这些年一直在稳步发展并且每个版本都会 break 一些东西,让人需要不断地维护和修改代码有点心累,同时 community 里的第三方库也还不够强大,不过最近在做一点点 distributed optimization 相关的东西中体会到它在这方面的好处,在这里简单分享一下。一方面因为 Julia 的文档虽然比较全,但是似乎还是比较难找到一个完整的例子。本文相关的完整代码会放在这里

在 Julia 里分布式编程主要是通过 Remote Procedure Call (RPC) 的方式来完成。但是 RPC 并不需要用户显式地启动一个 server 来监听调用,然后做 message passing 之类的传输结果,而是有更加 high level 的 API 可以直接实现“在某个节点上执行某段代码”这类的语义。这里提到的 API 如果在将来改变或者改名之类的,主要可以参考 Julia 文档的Parallel Computing一章查看最新的接口。

要进行分布式编程,首先要做的是启动计算节点。在 Julia 里非常简单地可以通过julia -p 2来启动两个 worker 进程,利用nprocs()函数可以看到当前有 3 个进程,myid()会返回每个进程的 id (和系统里的 pid 并不一样,而是从 1 开始的数字),其中主进程的 id 总是 1,然后其余的是 worker。在这个例子中,nworkers()会返回 2,表示一个主进程两个 worker 进程。默认情况下(不加-p参数启动 Julia 的时候)只有一个进程,nprocs()nworkers()都返回 1,这时主进程自己同时也是 worker。除了在启动的时候用-p参数之外,还可以在启动之后通过调用addprocs(...)函数来添加 worker 进程。

当然-p只是启动单机多进程,要实现真正的分布式,可以通过给定一个 hostname 列表的方式,Julia 会尝试通过 SSH 启动远程节点进程,或者如果你的集群已经有一个集群或者调度管理器的话,可以通过实现 Julia 里的ClusterManager接口来进行对接,在专用集群里启动任务。方便的是单机多进程和真正的分布式对于在 Julia 的 high level API 来说大部分情况下并没有区别。除非实现具体的计算中需要专门考虑多机通讯比本地更慢这些方面的问题,否则可以直接在本机写代码和小范围调试,再 deploy 到集群上去。

启动 worker 进程之后,就可以进行 RPC 来调度任务了。Julia 里 RPC 的接口非常简单,最基本的一个函数是remotecall(func, wid, args...),其中func是要调用的函数,wid是对应的 worker 的 ID,而args...则是需要传给函数的参数,参数会被自动传输到对应的 worker 那里。remotecall函数是立即范围的,它返回的结果是一个Future,这相当于对于 RPC 执行结果的一个 handle,对于这个 handle 调用fetch会拿到对应的结果,如果对应的 RPC 计算还没有完成,则 block 等待完成,同时fetch还会自动把结果传输到当前调用fetch的这个节点上来,当然如果结果已经在同一个节点上了,fetch则不需要额外的数据传输开销。下面是一个例子:

data_ref=remotecall(rand,2,(20,30))ret=remotecall_fetch(x->norm(fetch(x)),2,data)

在 worker 2 上调用了rand生成一个随机矩阵,注意这里参数传输的代价只是(20, 30)这个 tuple,并且data_ref只是作为一个 handle 返回到当前进程,这个 handle 直接被传回 worker 2 上计算其norm,而在 worker 2 上调用fetch的时候会发现生成出来的矩阵已经在该节点上了,所以最终结果并没有太大的数据传输代价。这里的remotecall_fetch有点类似于嵌套调用fetch(remotecall(...)),但是由于它自己本身是一个 primitive,所以更加高效,也不会出现隐藏的 race condition 问题。除了这些 primitive 之外,还有一些更 high level 的 API 和宏,比如@spawn@spawnat可以很方便地在 worker 上执行任意代码,例如:

julia>ref=@spawnat2beginx=rand(2,2)norm(x)endFuture(2,1,12,Nullable{Any}())julia>fetch(ref)1.2147872352524431

Julia 还提供一些更加 high level 的函数,诸如pmap之类的可以很自动地把计算分配到当前可用的 worker 上执行,并收集结果之类的。但是如果我们需要实现非常具体和细致的算法 scheduling——哪个 worker 执行那一段代码等等,则需要直接使用比较 low level 一点的 API。

假设我们现在要实现一个 ASGD,也就是 Asynchronized Stochastic Gradient Descent,算法的基本思想是每一个 worker 有自己的一份数据,算法执行的时候每个 worker 并行地从 parameter server 里拿到当前最新的参数,然后在本地数据的一个 mini-batch 上计算 gradient,再把 gradient 传回 parameter server,后者再根据传回的 gradient 更新参数。之所以是 asynchronized 是因为每个 worker 是并行并且独立地工作的,因此会有许多可能的不一致的情况,比如当一个 worker 拿到参数,计算了 gradient 并传回去的时候,parameter 上最新的参数已经由其他 worker 传回的结果更新过了,因此参数和梯度的对应关系出现了不一致。在一些给定的条件下,一定程度的不一致是可以允许的,并且能够证明最终收敛性,因为 SGD 本身就是 noisy 的,并且优化算法只要保证前进的方向和 descent 当方向有足够的 correlation,而不一定非常完全 align 起来。不过这些并不是本文要讨论的主要问题。

总而言之,要保证分布式和单进程计算的 SGD 结果一样,我们需要在每个 mini-batch 的计算中等待所有 worker 算完,把结果 gradient 求一个平均值,再更新参数,然后进行下一个 mini-batch 的计算。但是这样会导致很大的等待延迟,特别是如果其中有一个 worker 计算速度或者网速很慢的话,就会直接拖慢其他所有节点。ASGD 则选择直接无视同步从而获得更好的 scalability,并且在实际中通常收敛得也很好(有时候可能需要使用更小的 step size)。假设我么想要实现 ASGD,大致可以写成这个样子:

  1. function asgd_step(w::Vector{Float64})
  2. grad=compute_grad(w)
  3. returngrad
  4. end
  5. forwidinworker_ids
  6. grad_ref=remotecall(asgd_step,wid,w)
  7. # should we do this here?
  8. w-=step_size*fetch(grad_ref)
  9. end

看起来没有什么问题,但是实际上并不能实现我们想要的效果:问题在于第 9 行的fetch会 block 等待结果算完并传回当前进程(也就是主进程),所以这个for循环会在第一个迭代就 block 住,直到第一个 worker 算完之后才会继续第二个迭代,并且再次 block,最终结果就是每个 worker 依次执行,并没有任何并行可言。

为了解决这个问题,我们不能够调用fetch来 block 住主进程的执行,但是我们逻辑上我们又必须要等到每个 worker 算完之后拿到结果,然后再用那个结果来更新参数。如何将异步程序逻辑串起来这几乎是所有异步编程中都会碰到的问题。有两种比较常见的解决方案,一种是使用回调函数,在 Javascript 里这是非常常见的做法,并且有很方便的then函数可以把一个一个的回调函数串起来,例如下面这个没有什么意义的例子:

  1. varp=newPromise(function(resolve,reject){
  2. // a promise that will be fulfilled after
  3. // sleeping for 1 second
  4. setTimeout(()=>{resolve(1);},1000);
  5. });
  6. // chain callbacks that will be executed
  7. // upon the fulfillment of the promise above
  8. p.then(function(value){
  9. // heavy computation of gradient
  10. grad=value+1;
  11. returngrad;
  12. }).then(function(grad){
  13. // update parameter
  14. console.log('grad = ',grad);
  15. });

这里的做法就是把整个程序的逻辑分成一个一个的 block,分别包装在一些函数里,然后通过把一堆回调函数按顺序串起来的方式来实现异步操作。另一种解决办法是用不同的调度线程,这样我们在调用fetch进行 block 等待的时候只是 block 了那个 worker 对应的调度线程,而主线程则可以继续运行,大致可以用下面的伪代码来表示:

  1. # pseudo code for thread-based scheduling
  2. threads=[]
  3. forwidinworker_ids
  4. thread=new_thread()do
  5. # now we are blocking the worker-scheduler
  6. # thread, instead of the main thread
  7. grad=remotecall_fetch(asgd_step,wid,w)
  8. w-=step_size*grad
  9. end
  10. push!(threads,thread)
  11. end
  12. # now all the jobs are scheduled, block
  13. # the main thread to wait until all scheduler
  14. # threads finish
  15. wait_all(threads)

由于每个 worker 有自己的 scheduler thread,所以我们可以直接调用remotecall_fetch来 block 掉它的 thread,但是由于主线程还在继续执行,所以这里并不会导致其他 worker 也被 block 住。使用一个独立的线程对应一个远端的 worker ——其本身可能是一个独立的进程或者甚至是网络上另一台机器——的好处是在每个线程里可以自由地 block 等待,代码风格基本上就变成了简单的同步执行逻辑,而不需要切成一块一块地用回调函数串联起来。

当然,多线程也有它自己的问题,就是线程之间现在有了同步和 racing 等各种问题,比如上面的伪代码中第 7 行更新w的那一步,通常就需要通过加锁来保证不会有多个线程同时写入w导致严重的数据不一致情况等等。并且 Julia 自己的多线程支持其实还在比较早期的开发阶段。

幸运的是在 Julia 里有更简单有效的解决方案,比较类似于多线程,但是这里的执行单元是一个一个的coroutine,或者在早期有时会被称为“纤程 (Fiber)”——以区别于“线程 (Thread)”。coroutine 非常像线程,但是不同的是 coroutine 的 context switch 比较轻量级,并且最重要的是所有 coroutine 全部都在当前的一个线程中执行,每一个时刻只会有一个 coroutine 在运行,因此不会像使用线程那样出现 racing 或者需要加锁的情况。由于本质上只有一个执行单元在执行,因此 coroutine 并不像线程那样能起到加速的作用,其主要功能在于提供方便的调度功能,特别是在需要等待外部资源,比如 IO,或者远程的计算节点的时候能够方便地切换调度。

在 Julia 里有很多方式可以创建 coroutine,我们这里使用@async宏来方便地在一个 coroutine 里直接一个代码 block。和之前的远程 RPC 一样的,该代码 block 立即返回,其内部的代码实际在什么时候被执行是未知的,当我们通过@async把所有的工作 coroutine 都调度好了之后,可以通过一个@sync调用来 block 住当前进程,直到所有 coroutine 都执行完毕为止。下面是一个简单的例子:

@syncbeginfori=1:3@asyncbeginsleep(rand(1:5))println(i)endendend

在 Julia 中执行这段代码,会按照随机顺序打印出 1, 2, 3 这三个数字。这里我们创建了 3 个 coroutine,每个 coroutine 在执行的时候碰到sleep函数就会放弃自己的执行权,导致另一个 coroutine 被调度。在 coroutine 内部可以有很多这样的 blocking point,比如是 IO 读写的等待,或者是调用fetch来等待Future的结果甚至是显式地调用yield来交还执行权等等,效果上这有点类似于自动地在这些 blocking point 把代码逻辑切割成了一个一个的小回调函数来执行。

弄清了这个基本概念之后,我们可以写一个如下的基本的工具函数,来将一个任务分配到所有 worker 上执行,并等待所有 worker 执行完毕,拿到最终结果(其实和系统自带的pmap很像),只额外再加了一点点异常处理的代码。这段代码可以在我们提供的样例 project中的src/worker.jl找到。

  1. """
  2. invoke_on_workers(f, workers, args...)
  3. Invoke `f` on each workers in parallel, with `f(worker_ref, args...)`.
  4. This function blocks until all workers finishes, and return a list
  5. of results from each worker.
  6. """
  7. function invoke_on_workers(f::Function,workers,args...)
  8. rets=Array{Any}(length(workers))
  9. @syncbegin
  10. for(i,(pid,worker_ref))inenumerate(workers)
  11. @asyncbegin
  12. rets[i]=remotecall_fetch(f,pid,worker_ref,args...)
  13. end
  14. end
  15. end
  16. # propagate remote exceptions
  17. forobjinrets
  18. ifobjisaRemoteException
  19. throw(obj)
  20. end
  21. end
  22. returnrets
  23. end

有了这个 building block,我们就可以把分布式算法的基本框架写出来(这里我们用了 Julia 的“do block”来方便地构建匿名函数传入invoke_on_workers的第一个参数):

  1. # create workers
  2. workers=spawn_workers(...)
  3. # load data
  4. invoke_on_workers(workers)dow_ref
  5. # the code here are executed on remote
  6. # worker node
  7. worker=fetch(w_ref)
  8. worker.dataset=load_data(worker.data_partition)
  9. returntrue
  10. end
  11. # accumulate data statistics
  12. stats_all=invoke_on_workers(workers)dow_ref
  13. worker=fetch(w_ref)
  14. stats=Dict(:n_tr=>num_samples(worker.dataset),
  15. ...)
  16. returnstats
  17. end
  18. n_tr_total=sum(stats[:n_tr]forstatsinstats_all)
  19. # prepare for running
  20. hp=HyperParameter(step_size=args["step-size"],...)
  21. invoke_on_workers(workers,hp)dow_ref,hp
  22. worker=fetch(w_ref)
  23. worker.hp=hp
  24. worker.tr_idx=random_tr_smp_order()
  25. ...
  26. returntrue
  27. end
  28. # start training
  29. forepoch=1:args["n-epoch"]
  30. # schedule algorithm on workers
  31. ...
  32. end

这里的worker对象是我们自己定义的一个 struct,它并不是一个进程或者工作节点,而是我们定义的用于方便存储所有工作节点本地需要维护的状态和临时变量的一个容器。在实际的代码中它长这个样子:

  1. """
  2. A `Worker` object holds the necessary local states for a learner worker:
  3. - dset_tr: the local partition of the training dataset
  4. - dset_tt: the local partition of the test dataset
  5. - hp: hyper parameters specific to each algorithm (e.g. batch size)
  6. - lp: local parameters specific to each algorithm (e.g. algorithms in the
  7. dual might store dual variables locally)
  8. """
  9. mutablestructWorker{HPType,LPType}
  10. dset_tr::Dataset# training set
  11. dset_tt::Dataset# test / validation set
  12. hp::HPType# hyper parameters
  13. lp::LPType# worker local parameters
  14. Worker{HPType,LPType}()where{HPType,LPType}=new()
  15. end

可以看到为了要让实际的算法跑起来,除了调度计算之外,还有许多准备工作需要做,比如让每个 worker 把自己的数据加载进来,计算一些统计量,方便做一些全局的 normalization 等等,并且中央 scheduler 还需要把一些 hyper parameter,比如 batch size 之类的告诉每个 worker。准备工作做完之后就可以开始计算了。

理论上我们也可以用invoke_on_workers这个辅助函数来调度 ASGD 的计算逻辑。但是 ASGD 这个算法在每个 worker 上其实有一个内层循环(关于 mini-batch 的迭代),其中内层循环的每一次迭代都要同中央进程交换信息——获取最新的 w,并返回计算的 gradient。如果你尝试去写这个算法,你会发现似乎 worker 并不能很方便地主动和中央进程通信。到目前为止的通信模式都是中央进程通过 RPC 调用的方式将信息以函数参数发送到 worker 上,然后 worker 通过函数返回值把应答返回给中央进程。但是 worker 并不能在计算的过程中主动请求中央进程传一下目前最新的 w。

有这样的限制的原因是分布式编程逻辑处理起来比较复杂,如果 worker 和 scheduler 都是独立自主的节点,同时有自己的主线逻辑,以及在监听外部节点发过来的请求的话,整个逻辑线就会变得复杂起来。通常我们会把主要逻辑放在某一方,而让另一方以纯监听事件触发任务的被动方式执行。我们这里选择的是将主线逻辑放在 scheduler 这一方,另一种比较常见的做法是将主线逻辑放在 worker 上,而中央进程此时退化成一个 parameter server,它只实现简单的 pull 和 push 事件(或者说 RPC 接口),当 worker 请求 pull 最新参数的时候它发送 w,当 worker 调用 push 回传 gradient 的时候它通过传回的 gradient 来更新 w,其他时间则处于等待状态。然后每个 worker 自己处理自己的逻辑,类似于这样子:

  1. # on worker
  2. data=load_data(my_data_partition)
  3. forepochinn_epochs
  4. forbatchinn_batches
  5. w=pull(param_server)
  6. grad=compute_grad(w)
  7. push(param_server,grad)
  8. end
  9. end

看起来似乎很简单。这种 parameter server 的模式在每个 worker 能够比较独立自主地工作的时候就会比较方便,反过来如果中央 server 需要做一些调度,就会比较麻烦。比如我们希望每个 worker 把数据加载完之后算一下均值和方差,然后把所有 worker 上的统计量合并一下,最后再统一 normalize 一下数据。这个时候每个 worker 就没法很独立地执行,因为必须等所有其他的 worker 都把数据加载完毕,计算完统计量之后才能进入下一步,而这个 sync point 需要 somehow 通过与 parameter server 的通信来实现,就变得稍微有点麻烦。

总之对于调度逻辑比较多的情况下,似乎把主线逻辑放在中央节点会让程序写起来更自然一点。回到刚才的 ASGD 的问题,虽然 worker 节点只能被动地与中央节点通信,但是这并不是非常大的一个问题。一个比较 naive 的解决办法就是把 ASGD 的内层循环写开来,大概像这个样子:

  1. forepoch=1:n_epoch
  2. forbatch=1:n_batch
  3. grad_all=invoke_on_workers(worker,w)dow_ref,w
  4. worker=fetch(w_ref)
  5. grad=compute_gradient(w)
  6. returngrad
  7. end
  8. # now on central node
  9. w+=-step_size*mean(grad_all)
  10. end
  11. end

当然这个其实并不是 ASGD,而是 Synchronized SGD,因为我们等待所有 worker 把 gradient 算出来之后求了 average,然后统一加到 w 上。这是由于我们之前写的invoke_on_workers这个辅助函数的逻辑导致的,正确的做法可以通过写开来:

  1. function asgd_step(w_ref::Future,w::Vector{Float64})
  2. worker=fetch(w_ref)
  3. ...
  4. returncompute_gradient(w)
  5. end
  6. forepoch=1:n_epoch
  7. forbatch=1:n_batch
  8. @syncbegin
  9. for(wid,w_ref)inworkers
  10. @asyncbegin
  11. grad=remotecall_fetch(asgd_step,wid,w_ref,w)
  12. w+=-step_size*grad
  13. end
  14. end
  15. end
  16. end
  17. end

这个看上去似乎是正确的,因为现在我们让每个 worker 的 coroutine 单独去更新w了。不过实际上还是没有达到我们想要的效果,因为我们的@sync block 被放在了 mini-batch 循环的内部,所以每个 mini-batch 结束 worker 都会停下来等其他所有 worker 执行完,还是没有达到 async 的效果。幸运的是 Julia 的 coroutine 和 RPC 的接口非常 flexible,要实现这里想要的逻辑,我们只要把 mini-batch 和@sync block 交换一下顺序即可。下面是我们示例代码里 ASGD.jl 中的实际 code:

  1. function run_epoch(workers,params::Parameters)
  2. @syncbegin
  3. for(pid,worker_ref)inworkers
  4. @asyncbegin
  5. whiletrue
  6. Δw=remotecall_fetch(compute_delta,pid,worker_ref,params.w)
  7. ifΔw===nothing
  8. # this worker finishes its epoch
  9. break
  10. end
  11. params.w.+=Δw
  12. end
  13. end
  14. end
  15. end
  16. end
  17. """
  18. compute_delta(worker_ref, w)
  19. To be run on remote workers. Compute the updates for the weights. We have
  20. applied step sizes locally on each worker.
  21. """
  22. function compute_delta(worker_ref::Future,w::Vector{Float64})
  23. worker=try_fetch(worker_ref)
  24. idx1=(worker.lp.i_batch-1)*worker.hp.batch_size+1
  25. ifidx1>length(worker.lp.tr_idx)
  26. returnnothing# end of epoch
  27. end
  28. idx2=min(worker.lp.i_batch*worker.hp.batch_size,
  29. length(worker.lp.tr_idx))
  30. data_idx=worker.lp.tr_idx[idx1:idx2]
  31. X=worker.dset_tr.data[:,data_idx]
  32. y=worker.dset_tr.labels[data_idx]
  33. pred=X'*w
  34. w=(X*hinge_gradient(pred,y))/size(X,2)
  35. w+=worker.hp.λ*w# gradient from the regularizer
  36. Δw=-worker.lp.ηₜ*w
  37. worker.lp.i_batch+=1
  38. returnΔw
  39. end

这里的@sync@async的组合可能一开始有一点 confusing,概念明白之后就会非常清晰。由于 coroutine 的缘故,第 11 行的参数更新不需要任何加锁之类的操作。每个 coroutine 通过一个while循环来连续地调度 worker 进行计算,最外层的@sync block 保证在一个 epoch 结束之后等待所有 worker 停下来。在 ASGD 中这个同步操作其实也可以去掉,不过如果是更加复杂的优化算法,比如如果有 variance reduction 相关的操作之类的,需要在这个时刻停下来做一些 maintenance 操作等等。

总结一下:我们主要使用 Julia 的 RPC 功能来实现多机并行计算,同时利用 coroutine 的功能来实现算法的具体调度。中央调度节点同时作为 scheduler 和 parameter server 的角色存在。我把完整的示例代码放在DistLearn.jl里,除了这里提到的 ASGD 算法之外,还提供了一个 COCOA 的实现,这是一个 dual 算法,在每个节点本地需要维护和 training samples 数目同样多的 dual variable。当然这个代码库并不是试图提供一个完整的 Julia 的分布式学习的算法实现,而主要是作为一个如何在 Julia 里实现自己的分布式系统的示例。

Denoising Lena

$
0
0

在之前讲 Projected Gradient Method 的文章中,我们举了一个对加了白噪声的 Lena 的照片进行 denoising 的例子,文中提到了两种方法,一种是直接对 DWT 的系数进行 hard thresholding,将数值较小的值设为零,再用逆向离散小波变换得到 denoising 之后的图片。另一种方法是解一个\(\ell_1\)正则化的线性回归,我们选了后者因为刚好那个优化问题经过变化之后可以用 Projected Gradient Method 来解,这也是当时选这个问题作为那篇文章的原因。但是当时并没有解释为什么这些算法可以实现降噪,而这就是今天的话题。

当然,直观来讲,是不难理解的,因为 natural image 在小波基下呈现稀疏性,而白噪声,也就是 Gaussian Noise,则没有稀疏性,另外假设 noise 的 scale 和原始信号相对来说比较小的话,那么通过 hard thresholding,去掉那些较小的系数之后得到的稀疏系数会达到一定的降噪效果。我们在这里试图将问题 formally 定义出来。首先,我们假设 Lena 的图片是这样生成的

\[ y = Xw^* + \epsilon \]

其中\(X\in\mathbb{R}^{d\times d}\)是正交小波基,\(w^*\in\mathbb{R}^d\)是真实的 Lena 的照片在小波基下的系数,而\(\epsilon\sim \mathcal{N}(0, \sigma^2I_d)\)是零均值的高斯分布噪音。实际上我们并不需要高斯分布,在后面的分析中我们只需要\(\epsilon\)的分布的 tail decay 得足够快就可以。比如任何 bounded 随机变量,或者 sub-Gaussian 随机变量都是可以的。当然我们所能达到的降噪的效果会取决于噪音的 variance \(\sigma^2\)的大小。

因此,我们所观测到的\(y\),会是原始图像加上未知噪音\(\epsilon\)的结果,我们知道作为小波基的\(X\),但是却不知道原始的小波系数\(w^*\),而我们的目的正是要构造一个 estimator \(\hat{w}\),而我们这里将使用 mean square error (MSE) 来衡量一个 estimator 的好坏:

\[ \mathsf{MSE}(X\hat{w}) = |Xw^* - X\hat{w}|_2^2 \]

注意 MSE 是一个随机变量,随机性来自\(\hat{w}\),因为\(\hat{w}\)是根据\(y\)构造出来的,而\(y\)则依赖于随机变量\(\epsilon\)。这里看起来有点像 machine learning 的设定:\(X\)是数据,\(w^*\)是模型参数,而\(y\)是带噪声的 label,但是实际上设定并不太一样,首先这里的\(X\)是固定的 (fixed design),并不是像 machine learning 里是从一个数据分布中随机采样得到的 (random design),其次这里的目的是估计\(w^*\),并且衡量标准用重构出来的图片\(X\hat{w}\)和真实的图片\(Xw^*\)进行比较,而在 machine learning 中衡量标准则是要对于未知的,新的数据下的预测结果和真实结果进行比较。

在构造 estimator 之前,我们先对问题进行一些简单的变换,首先注意到小波基是一个 orthonormal basis,也就是说\(X^\top X=I\),因此,我们在模型(eq: 1)两边同时乘以\(X^\top\)就可以得到:

\[ X^\top y = w^* + X^\top \epsilon \]

\(X^\top y=Y\)\(X^\top \epsilon\)\(\xi\),我们可以得到如下的新模型

\[ Y = w^* + \xi \]

其中\(Y\)是观测到的量,\(\xi\)是(变换过的噪音),由于\(X^\top\)是 orthonormal 的,所以\(\xi \sim\mathcal{N}(0,\sigma^2 I_d)\),和原来的噪音是同分布的。类似地,MSE 可以变换为

\[ \begin{aligned} \mathsf{MSE}(X\hat{w}) &= (w^*-\hat{w})^\top X^\top X (w^*-\hat{w})\\ &= |w^*-\hat{w}|_2^2 \end{aligned} \]

现在问题变得简介了许多:我们观测到一个未知的向量\(w^*\)加成了高斯噪音的结果,现在想要估计\(w^*\)使得估计值和真实值的\(\ell_2\)距离平方最小。光这样似乎并不是特别明显我们可以做什么,如果有多个观测值的话我们似乎还可以求求平均之类的,现在只有\(Y\)这一个观测值。

接下来我们不妨来分析一下 Lena 和噪声各自的性质。首先 Lena 作为一张 natural image,在小波基下的系数\(w^*\)是应当呈现稀疏性的。另一方面注意到高斯噪声有一个很好的性质就是它的分布的 tail decay 得很快。例如,根据Wikipedia,一个高斯分布的随机变量取值在均值加减\(3\sigma\)的范围内的概率是 99.7%,这里\(\sigma^2\)是这个随机变量的方差。

1
图 1

根据这个,我们可以以很大的概率确定如下情况:\(|\xi_i|\)都是很小的;因此如果观测值\(|Y_i|\)是一个很大的值,那么说明在\(i\) index 下的真实值\(|w^*_i|\neq 0\),因此我们观测到的是真实值加噪音;另一方面,如果\(|Y_i|\)是一个很小的值,那么有两种情况,一是由于稀疏性,原始信号在这个位置的系数就是零,或者是原始信号虽然非零但是绝对值很小。这些分析下下面的所谓 hard threshold estimator 就变得 make sense 了:

\[ \hat{w}^{\text{HRD}}(Y)_i = \begin{cases} Y_i & |Y_i| > 2\tau \\ 0 & |Y_i| \leq 2\tau \end{cases} \]

这里的 threshold \(2\tau\)是什么我们接下来会讨论,简单来说就是,如果\(|Y_i|\)很大,那么观测到的是信号加噪音,由于我们不知道噪音具体是多少反正噪音相对于信号来说比较小,就索性留着;但是反过来\(|Y_i|\)很小的情况,如果信号原来在这里是稀疏的,那么正好我们设为零估计正确,但是即使原始信号在这里不稀疏,其绝对值也是很小的,因此我们设为零之后造成的估计误差也不会太大。

接下来就让我们把这个 idea 具体地用数学语言描述出来。首先,让我们来具体刻画一下高斯分布的 tail decay。具体来说,假设\(Z\)是均值为零,方差为\(\sigma^2\)的高斯分布,对于任意的\(t>0\),我们希望计算\(Z > t\)的概率:

\[ \begin{aligned} P(Z > t) &= \int_t^\infty p_Z(z)\,dz\\ &= \int_t^\infty \frac{1}{\sqrt{2\pi\sigma^2}}e^{-z^2/2\sigma^2}\,dz \end{aligned} \]

排除Q-function这种耍赖的存在的话,这个积分并没有一个表达式可以直接写出来,如果我们通过数值方法,可以算出类似刚才的\(e\sigma\)那样的数值来,不过我们这里希望有一个表达式,由于我们只是希望噪音 decay 的很快,也就是说在\(t\)变大的时候\(P(Z > t)\)变小得非常快,因此我们并不需要得到 exact 的等式,只要得到一个足够好的上界不等式就好了。这里有一个简单的方法,注意到当\(z \geq t\)时,\(z/t \geq 1\),因此

\[ \begin{aligned} \int_t^\infty \frac{1}{\sqrt{2\pi\sigma^2}}e^{-z^2/2\sigma^2}\,dz &\leq \int_t^\infty \frac{z}{t}\frac{1}{\sqrt{2\pi\sigma^2}}e^{-z^2/2\sigma^2}\,dz \\ &= \frac{\sigma}{\sqrt{2\pi}t}e^{-t^2/2\sigma^2} \end{aligned} \]

从这里可以看出,高斯分布的 tail 是以\(e^{t^2/2\sigma^2}\)来 decay 的,这将随着\(t\)的增大以非常快的速度趋向于 0,\(\sigma^2\)越小速度越快。这里我们暂时忽略前面的\(\sigma/\sqrt{2\pi}t\)的系数,注意到当\(t\)变得很小的时候这个系数变得非常大,此时这个上界就失去意义了,因为当\(t>0\)时我们显然有\(P(Z>t)<1/2\)。实际上,通过Chernoff Bound可以直接得到这样的方便处理的上界:

\[ P(Z > t) \leq e^{-t^2/2\sigma^2} \]

虽然推导并不复杂,但是篇幅有限,为了避免扯得太远,这里就直接使用这个结论了。现在我们回到\(\xi\),刚才的分析中已经知道它是一个\(d\)维,零均值,协方差矩阵为\(\sigma^2I_d\)的高斯分布变量,由于各个维度互相独立,通过简单的 union bound 和对称性,我们可以得到:

\[ P(|\xi_i| > t) \leq P(\xi_i > t) + P(\xi_i < -t) \leq 2e^{-t^2/2\sigma^2} \]

如果我们想要同时控制所有的\(\xi_i\)的话,同样利用 union bound 可以得到

\[ \begin{aligned} P\left( \max_{1\leq i \leq d} |\xi_i| > t\right) &= p\left( \bigcup_{i=1}^d \left\{ |\xi_i| > t \right\} \right) \\ &\leq \sum_{i=1}^d P(|\xi_i| > t)\\ & \leq 2de^{-t^2/2\sigma^2} \end{aligned} \]

令右边的式子等于\(\delta\),反解出\(t\),我们可以得到,对于任意\(\delta>0\),我们可以得到,以至少\(1-\delta\)的概率,如下式子成立:

\[ \max_{1\leq i \leq d}|\xi_i| \leq \sigma\sqrt{2\log(2d/\delta)} \]

也就是说,以很高的概率,我们可以将所有\(|\xi_i|\)控制在上面的 bound 以内,大约就是\(\sigma\)的 scale,当然会随着\(1/\delta\)\(d\)增大,但是都是根号下的 log-scale,增长比较缓慢,基本上可以接受。既然知道了噪音的大致 scale,那么我们不妨将 hard threshold estimator 里的\(\tau\)取成这里的噪音上界。具体来说,我们将得到如下结论。

1

定理 1. 假设模型满足(eq: 3),那么令\[ \tau = \sigma\sqrt{2\log(2d/\delta)} \]则对于任意\(\delta>0\),如(eq: 4)所定义的 Hard Threshold Estimator 可以以至少\(1-\delta\)的概率实现\[ |\hat{w}^{\text{HRD}}-w^*|_2^2 \lesssim k\sigma^2 \log(2d/\delta) \]其中\(k=|w^*|_0\)是真实系数的稀疏性。此外,如果最小的非零\(|w^*_i|\)数值都大于\(3\tau\)的话,以同样的概率可以实现\[ \text{supp}(\hat{w}^{\text{HRD}}) = \text{supp}(w^*) \]也就是说估计出来的系数有正确的稀疏性。

这里\(\lesssim\)是用于省略掉其中的一些常量的写法。在证明之前我们先来看一下结论。首先,MSE 随着\(\sigma^2\)的增大而增大,噪音越大,估计就越差,这是理所当然的事情。通常,我们都会要求噪音是足够小的,例如,如果\(\sigma\)是在\(1/d\)的 scale 上的话,上面的式子就会变得非常好看。另外前面的系数\(k\)相当于是必须要 pay 的 price,因为我们这里需要估计的参数有\(k\)个(\(w^*\)的稀疏性)。实际上,假设\(w^*\)不具有稀疏性,此时我们直接用 least square estimator,也就是

\[ \hat{w} = \operatorname*{\arg\min}_w |Y-w|_2^2 \]

很显然最优解就是\(\hat{w}=Y\),此时的 MSE 为\(|\hat{w}-w^*|_2^2=|\xi|_2^2\),根据我们刚才得到的高斯分布的 tail bound,再加上 union bound,可以得到

\[ \begin{aligned} P(|\xi|_2^2 > t) &\leq \sum_{i=1}^dP\left(|\xi_i|^2 > \frac{t}{d}\right)\\ &\leq \sum_{i=1}^dP\left(|\xi_i| > \sqrt{\frac{t}{d}}\right)\\ &\leq 2d\exp\left( -\frac{t}{2\sigma^2d} \right) \end{aligned} \]

令右边等于\(\delta\),我们可以得到,以至少\(1-\delta\)的概率,

\[ |\hat{w}-w^*|_2^2 \leq 2d\sigma^2 \log(2d/\delta) \]

可以看到我们得到的 bound 和\(\hat{w}^{\text{HRD}}\)是类似的,只是现在需要估计的参数是\(d\)个(由于没有稀疏性)。现在假设我们知道\(w^*\)的稀疏性是\(k\),并且知道\(w^*\)在哪\(k\)个位置上是非零的,此时我们可以只对这\(k\)个位置通过 least square 进行估计,将会得到和\(\hat{w}^{\text{HRD}}\)一样的 bound。也就是说,hard threshold estimator 在对\(k\)的值以及是哪\(k\)个位置上非零这些情报毫不知情的情况下,达到了和知道这些情报的情况下所能得到的差不多的估计误差,因此 hard threshold estimator 又被称为 sparsity adaptive thresholding estimator。接下来我们来证明该定理。

为方便起见,以下我们就记\(\hat{w}^{\text{HRD}}\)\(\hat{w}\),首先注意到

\[ \begin{aligned} |\hat{w}_i-w^*_i| &= |\hat{w}_i-w^*_i|\mathbf{1}_{Y_i>2\tau} + |\hat{w}_i-w^*_i|\mathbf{1}_{Y_i\leq 2\tau} \\ &= |\xi_i|\mathbf{1}_{Y_i>2\tau} + |w^*_i|\mathbf{1}_{Y_i\leq 2\tau} \\ &\leq \tau \mathbf{1}_{Y_i>2\tau} + |w^*_i|\mathbf{1}_{Y_i\leq 2\tau} \end{aligned} \]其中最后一个不等式根据刚才对高斯分布的 tail 的分析(eq: 7),是以至少\(1-\delta\)的概率成立,其中\(\tau\)就是取定理中所指定的值。此外,注意到,根据三角不等式

\[ \begin{aligned} |Y_i|>2\tau &\Rightarrow |w^*_i| = |Y_i - \xi_i| \geq |Y_i| - |\xi_i| > \tau \\ |Y_i|\leq 2\tau &\Rightarrow |w^*_i| = |Y_i-\xi_i| \leq |Y_i| + |\xi_i| \leq 3\tau \end{aligned} \]

因此,接着上面的不等式

\[ |\hat{w}_i-w^*_i| \leq \tau \mathbf{1}_{|w^*_i|>\tau} + |w^*_i|\mathbf{1}_{|w^*_i|\leq 3\tau} \]

我们将右边的式子分情况展开可以得到

\[ \begin{aligned} \tau \mathbf{1}_{|w^*_i|>\tau} + |w^*_i|\mathbf{1}_{|w^*_i|\leq 3\tau} &= \begin{cases} \tau + |w_i^*| & \tau<|w_i^*|\leq 3\tau \\ |w^*_i| & |w^*_i| \leq \tau \\ \tau & |w^*_i| > 3\tau \end{cases}\\ & \leq \begin{cases} 4\tau & \tau<|w_i^*|\leq 3\tau \\ |w^*_i| & |w^*_i| \leq \tau \\ \tau & |w^*_i| > 3\tau \end{cases}\\ & \leq \begin{cases} 4\tau & \tau<|w_i^*|\\ |w^*_i| & |w^*_i| \leq \tau \\ \end{cases}\\ & \leq \begin{cases} 4\tau & \tau<|w_i^*|\\ 4|w^*_i| & |w^*_i| \leq \tau \\ \end{cases} \end{aligned} \]

也就是说

\[ |\hat{w}_i-w^*_i| \leq 4\min(\tau, |w^*_i|) \]

从而,我们可以直接得到

\[ \begin{aligned} |\hat{w}-w^*|_2^2 &= \sum_{i=1}^d |\hat{w}_i-w^*_i|^2 \\ &\leq 16\sum_{i=1}^d \left(\min(\tau, |w^*_i|)\right)^2 \\ &\leq 16|w^*_i|_0\tau^2 \end{aligned} \]

带入定理中\(\tau\)的式子即证第一个结论。第二个结论很好证明,只要利用三角不等式即可。首先,如果\(w^*_i\neq 0\),此时根据假设我们有\(|w^*_i|>3\tau\),于是

\[ |Y_i| = |w^*_i + \xi_i| \geq |w^*_i| - |\xi_i| > 2\tau \]

于是\(\text{supp}(w^*)\subset\text{supp}(\hat{w})\)。反过来,如果\(|Y_i|>2\tau\),则

\[ |w^*_i| = |Y_i-\xi_i| \geq |Y_i| -|\xi_i| > \tau > 0 \]

于是\(\text{supp}(\hat{w})\subset\text{supp}(w^*)\)。定理即证。

结束之前,有几点注意事项。除了上面的 hard thresholding 之外,还可以定义 soft thresholding,也就是先对所有的系数的绝对值减去\(2\tau\),然后将不够减的这些系数设为零。通过类似的分析可以得到差不多的结论。此外这里的噪音并不限于高斯噪音,从上面的分析中看到我们只要求噪音的 tail decay 足够快即可,因此对于其他有类似于高斯噪音这样的 tail decay 速度的噪音是同样适用的。另外就是,当\(X\)并非正交的时候,我们也能得到一些相似的定理,但是此时必须对\(X\)加一些额外的条件,否则,比如一个极端的情况,如果\(w^*\)\(X\)的 null space 里,此时\(Xw^*=0\),那么测量到的将会完全是 noise,此时没有任何可能恢复原来系数的希望。这里需要对\(X\)所加的限制基本上是要求\(X\)“近似于”正交,具体地 formulate 出来将会得到 compressive sensing 里那些常用的诸如 incoherence、null space property 之类的性质。此外,当\(X\)并非正交之后,它的行数并不要求等于它的列数,compressive sensing 里的许多结论就是在说,当\(w^*\)本身满足一定的稀疏性之后,我实际上并不需要\(d\)行那么多的测量数,而是只要远远小于这个数目的行数(依赖于稀疏性\(k\))就能恢复原来的系数。这个时候我们得到的类似于定理中的 bound 里,上界里将会出现行数\(n\),并且 error bound 会随着\(n\)的增加而减小。

最后,理论分析里得到的\(\tau\)的取值通常并不适用于直接在实际中带入。因为在求上界的过程中经过了许多不等式的放松,而且即便是“tight bound”,通常都是指不考虑常数系数,以及在最坏情况下和下界达到一致之类的情况,因此主要还是 bound 里的各个参数的阶对于 bound 变化的影响是比较有用的。实际操作中通常会通过 cross validation 之类的另外的方法来选取 estimator 的参数。

由于本文没有什么图片,看起来比较枯燥,下面随便给了一段用来通过 hard thresholding 和 soft thresholding 对 Lena 的图片进行去噪的 julia 代码。

  1. # Requires the following packages:
  2. #
  3. # Pkg.add("Wavelets")
  4. # Pkg.add("Images")
  5. usingImages
  6. usingWavelets
  7. sigma=0.1
  8. dim=512*512
  9. delta=0.1
  10. img=reinterpret(Float64,float64(imread("lena512gray.bmp")))
  11. imwrite(img,"threshold-lena-orig.jpg")
  12. # add noise to the image
  13. img.data+=0.2*randn(size(img.data))
  14. imwrite(img,"threshold-lena-noisy.jpg")
  15. the_wavelet=wavelet(WT.sym4)
  16. img_coef=dwt(img.data,the_wavelet)
  17. forconfigin["bound","choose"]
  18. ifconfig=="bound"
  19. tau=sigma*sqrt(2*log(2*dim/delta))
  20. else
  21. tau=0.25
  22. end
  23. # hard thresholding
  24. img_coef_hrd=copy(img_coef)
  25. img_coef_hrd[abs(img_coef_hrd).<=2tau]=0
  26. rcv_img=idwt(img_coef_hrd,the_wavelet)
  27. imwrite(rcv_img',"threshold-lena-hrd-$config-rcv.jpg")
  28. # soft thresholding
  29. ifconfig=="choose"
  30. tau=0.1
  31. end
  32. img_coef_sft=copy(img_coef)
  33. coef=1-2tau./abs(img_coef_sft)
  34. coef=coef.*(coef.>0)
  35. img_coef_sft=img_coef_sft.*coef
  36. rcv_img=idwt(img_coef_sft,the_wavelet)
  37. imwrite(rcv_img',"threshold-lena-sft-$config-rcv.jpg")
  38. end

我们对比了 hard thresholding 和 soft thresholding 使用定理中给定的\(\tau\)和随便尝试了一下选取的\(\tau\)值(注意“随便尝试一下”并不是一个很科学的 parameter selection 的方法)。结果图所示。

2
图 2

可以看到,定理中给出的\(\tau\)值过大,通过那个值进行 thresholding 之后原本图像的细节都被去得所剩无几了。还有就是 hard thresholding 比较暴力,因此造成的图像上的 artifact 也比较严重一点,相对应的 soft thresholding 的结果就相对更加 smooth 一点。当然,总体来说,效果都只能算一般,真正要做降噪的应用的话,应该会利用更多的 prior knowledge 和更加复杂的模型的。

2015 就是这样

$
0
0

今年是老歌《就是这样》。

不穿鞋子体会真的感觉环游世界不在乎明天天气我的世纪梦与我没有距离说去就去发出讯息接收我的频率冒险前进顺从心里的好奇

Carlo 在 lounge 问我要不要喝一杯咖啡,于是我跑过去跟他们一起聊天,中途发现 Carlo 当天下午三点就要飞罗马了,并且这次是永久地离开,想起来上一次跟他聊天的时候他说过要去英国,没想到就是当天了。我匆忙跑到座位上翻出了一块画板——之前练习画的丙烯画——临时送他作为饯别。

查尔斯河的水面蓝了又白,不知不觉又过去了一年。由于下半年报了 Museum of Fine Arts 那边的 Acrylic 绘画班,每次上课步行过去,今年便多了不少时间来欣赏查尔斯河的景色,一路过去的 Back Bay Fens 有花园有湖有 Boston 传统的成排肥鹅有长椅还可以踩松软的落叶,其实是非常惬意的,特别是今年还是个暖冬。其实查尔斯河经常看到很惊艳甚至诡异的夕阳,让人想起 ZJG。

MFA 的每周一次的绘画课其实还蛮有意思,虽然感觉这样子学到的东西其实比较有限,但是好歹是算入了门。不得不说丙烯画相比水彩来说,不论是颜料还是画布各方面都是更加烧钱的。每当给整个画布上底色的时候,调好的颜料三笔以内就用完了,就会觉得电子绘画好,实际上年底打折也确实买了一个 Intuos Pro,但是论好玩程度来说(抛开调不出想要的颜色时的抓狂的话),果然还是真实的颜料好玩,而且很久没有用过绘画板了,相当生疏。

技能树方面今年做的另一件事情就是报了学校的一个游泳班学了自由泳——嘛,当然还是游得不是很像样,但是感觉接下去主要还是要练习了。实际上学校的游泳设施非常高端,不好好利用真实太浪费了。但是与其说是定期的锻炼用,我好像更多是玩,比如很喜欢带上脚蹼然后用海豚游法直接在水底一路扭到对岸去。:D

此外还克服拖延症,终于把 RQE 弄了,于是正式从 PhD Student 变成了 PhD Candidate,据说会涨一百块的工资?其他就没有什么了,日语在我正在犹豫要不要今年考个 N1 的时候,老师发邮件来说今年 JLPT 在我们学校办,欢迎大家下周来做志愿者啊,我才发现原来已经是下周就考试了……绘画方面暑假在法国受到浓浓的艺术熏陶,还买了一本文字都看不懂的人体肌肉骨骼方面的书回来练习,不过并没有能坚持太久,总的来说这其实是非常忙碌的一年。我有常识过用一些 app 来记录自己的生活。比如 Sleep Cycle 可以用来记录睡眠时间,睡眠质量之类的。

一直觉得自己是不睡满八小时第二天肯定会困得不行的人,结果看到自己这一年以来的平均睡眠时间根本就没有上过八小时,也是震惊了。但是一个不争的事实也是我现在几乎每天必须要喝至少一杯咖啡。另外一个记录用的 app 是叫做 iHour,可以用来记录学习、工作之类的时间,其实比较手动了,但是可以给出比较漂亮的统计图,而且还可以刷各种成就,所以也一直用。

最辛苦的时候是一周超过 100 小时的工作时间,想一想每天睡八小时,然后花 3 小时来吃饭,每周就可以轻松工作 90+ 小时,然而期望通常跟现实相距甚远,特别是用 app 记录之后就发现大部分时候是达不到这样的效率的,总是会有一些其他事情耽搁、开个小差、无法集中注意力干活之类的各种情况,然后要是中途去哪里休假几天之类的再回来,平均每周的工作时间其实也就五十多小时了。

当然即便从玩的角度来讲也是非常充实的一年。大致算一下这一年去过的一些地方:中国:南京苏州嘉兴(一周);美国:纽约、华盛顿、波特兰、Acadia 国家公园;法国(21 天):Paris、Lille、Marseille、Lyon;德国(两周):Frankfurt、Cologne、Berlin、Dresden;捷克布拉格(三天);加拿大 Montreal。因为我比较喜欢收集明信片,每次回到家除去寄出去了的卡片,都还剩下一大堆,于是就找机会将其中一部分贴到房间墙上当装饰用。后来我在布拉格的时候突然有一个想法,在网上搜索了一下发现真的有这样一个网站,叫做 postcrossing:就是给世界各地随机的人寄明信片,同时收到世界各地寄来的明信片。其实给陌生人写明信片和给朋友写明信片感觉是很不一样的体验,因为我好像并不擅长跟陌生人讲很多话,不过总的来说还是非常有趣的一件事情,这样回家的时候也时不时会对邮箱里是否有卡片充满期待啊。^_^

不过跑来跑去其实也是很有乐趣,虽然有时候在外面晃荡太久了也会有想回去。年初在国内江南几处跑其实是由于签证被 check,只好在附近转一转,虽然在杭州很多年,但是周围都没有去过也是觉得人生很不完整。南京这个地方我还蛮喜欢,有种杭州的感觉,虽然并没有哪一处让我觉得好惊艳,但是就感觉即使长期生活在这里大概也不会很腻的样子,钟山景区那一带,感觉就很适合周末约几个朋友亦或者是独自去爬山。大概对南京的最初印象就是来自一张背景是中山陵台阶的照片,不过爬到顶上并没有一个什么博物馆啊资料馆之类的东西,多少有点小遗憾。

苏州也很漂亮,苏州博物馆的建筑很有特点,大概是在我还没有开始收集明信片的习惯之前收到过的第一张明信片好像就是苏博的建筑。平江路的各种小店也很有意思。不过大冬天的几乎都是室外景点,最后只能瑟瑟发抖,然而即使这样其实也是有相当多的游客。比较有意思的是在许多景点会有警察在用广播播放请大家不要随便轻信兜售打折票,团体票之类的小贩,然后旁边全是兜售打折票团体票的小贩。本来还想去同里或者西塘、乌镇之类的地方,最后因为太冷就回杭州了。在湖边和 prada 家寄住了好久。

美国的地方,纽约差不多每次基本上都是路过,所以其实并没有非常仔细低玩过。去华盛顿是看樱花,几个朋友一起开车过去。赏樱的人非常多,没有在日本看过樱花,所以不知道是不是会是同样的感觉,总之我虽然觉得樱花很漂亮,但是并没有觉得比其他的普通的花有更漂亮的地方,相比之下我更喜欢红叶。不过华盛顿似乎很好玩,各种博物馆都不要钱简直就是 bug 啊。

去波特兰的时候本来不知道要怎么玩,结果因为 QQ 先去了一趟,正好发现 HZ 在那边,于是我过去的时候便找到了接应的人,结果两人周末开车在 Oregon 州到处乱逛,属于毫无准备的自驾乱逛游,非常好玩,最好玩的是第一处去的 Oneonta Gorge,HZ 一开始跟我讲要做好全身湿透的准备,我听了半天没有听明白是什么意思,以为是要穿越森林,湿气很重之类的,结果到了那里发现是穿越峡谷溪涧到深处去看瀑布。一开始是攀爬大石和倒下的木头,但是到一些地方没有地方可以爬的时候只能淌水……一开始觉得穿着鞋淌水很不自在,而且完全没有带干衣服过来,然而后面大半身都湿透了之后就是无忌惮地玩水了,不过水其实很冷的。尽头是一个小瀑布。由于没有带手机,就在网上找了一张照片放在这里。

淌完水回来反正要开回城里也好很久,索性就破罐子破摔继续往前走,一路看了大大小小的瀑布,最后跑去看 painted hills,临时跑来一个估计只有几十人的小村庄住了一晚,第二天又跑去 Smith Rock 去 hiking 看 Monkey Face 那里攀岩的地方。一路上看到好大一片的风车和农田,非常非常的漂亮。Monkey Face 顾名思义就是一块(从特定的角度看)像猴子脸一样的石头,其实是非常非常大的一块石头,即使从对面的山看别人在那边攀岩也会觉得有些心惊胆战啊。

回去的路上车差点就撞到了一只飞奔过来的鹿,不管是我们还是鹿都是九死一生的感觉。以后在森林里的公路上开车果然还是要慢慢开才行。

秋季的尾巴跟学校的朋友们一起去北边的 Acadia 国家公园看红叶,那也是一个非常赞的地方,有山有海,当然也有红叶。hiking 一天下来,过去原本是很正常的量,那天居然觉得膝盖关节异常疼痛,难道真是越来越老了,还是平时实在是太缺乏锻炼了。暑假在学校的时候其实跟 ZD 一起还去开辟了 Boston 附近的 hiking 场所,有一个叫做 Middlesex Fells Reservation 的地方,坐地铁就可以到入口处,其实湖和树林也都非常漂亮的。

感觉再这样说下去就要变成纯游记了。说一点其他的吧,其实旅行途中的话,我基本上就不想干学习工作方面的事情了。做的比较多的是涂鸦或者看书。特别是年初在江南等签证的时候看了不少书,导致今年的阅读量似乎突然增加很多:统计一下有 42 本中文书,2 本英文书,1 本日文书。

  • 《黑客与画家》:很有名的书,我觉得还蛮有意思,但是并不是所有的内容都喜欢或者同意。
  • 《游戏玩家》:科幻类,似乎是一个叫做《文明》的系列的一本,里面的嗡嗡机还蛮有意思,感觉是还算有意思但是又不至于吸引你想要让你一通宵不看完不罢休的那种。以至于我现在都不太记得具体故事了。
  • 《ABC谋杀案》:在嘉兴的书店买到的,因为《冰菓》里的一个故事而一直想看这个。阿加莎·克里斯蒂的超有名的一个故事。个人很喜欢。
  • 《火星公主》:号称是全球销售2.8亿册的经典科幻巨著,感觉就是一部 YY 小说,超级没有意思,强烈不推荐。
  • 《不能承受的生命之轻》:在苏州的书店买的,米兰·昆德拉的这本书,因为比较有名,很早就一直都想找来看一看的,感觉全文读起来都相当阴郁,还不错吧,虽然也并没有特别喜欢。
  • 《练习一个人》:好像很早以前下载的,是个散文集,看了并不喜欢。
  • 《雪国》:因为很喜欢川端康成的《伊豆的舞女》,所以买了在跨洋飞机上看。《雪国》里也是像伊豆的舞女里那样说话语无伦次的姑娘。有时候经常觉得,小说里的人物,一生都过得好单纯,然而现实中的我们却又是如此纷繁复杂。买的这个版本同时还收录了《湖》,顺便也看了一下,感觉这种描写心理变态的小说看着有点吓人。
  • 《Through the Looking Glass》:XZ 推荐的书,其实我也很早就知道,因为好像之前看过一本书特别喜欢引用这里面的句子作为章节抬头句。强烈推荐看英文原版,因为很多脑洞是语言特有的,估计会比较难翻译。总之就是脑洞大开欢乐轻松的书。
  • 《罗生门》:在多看限免下载的,其实是一个包含了《罗生门》这个故事的短篇故事集。其中有不少故事还蛮有中国风的,有点像那种古代短小说集一类的。不置可否。
  • 《动物农庄》:实际上之前看了《1984》之后就应该来看这个的,不过一直拖了好多年。从情节上来看比《1984》更加轻松愉快一点,当然讽刺的味道一点都没有减,是一本好书!
  • 《风起陇西》:马伯庸早期的一本以三国为背景的间谍小说。还不错吧。
  • 《银河帝国》:“基地”系列 7 部曲,设定宏大的科幻小说。我觉得还蛮好看的(否则也没法坚持把 7 部看完),不过前面和中间部分比较好看,到后面的时候虽然很多东西和之前相呼应起来,但是还是感觉有点略烂尾了。
  • 《听到涛声》:吉卜力比较早期 (1993) 的一部动画片《听到涛声(海がきこえる)》的小说原型。首先动画片是蛮喜欢看的,数年后听人谈起有原著小说就去找来看了,比动画片里的故事更多,还包括了主角们中学毕业上大学之后的故事。总之就是青春爱情故事啦。蛮喜欢的。:)
  • 《我们为什么会分手》:因为有一段时间某位朋友在感情上碰到一些苦恼的问题,大家在尝试帮忙的时候谈起这本书,就去找来看了一下。是一个访谈集,对其中一部分故事和观点还蛮有感触的。
  • 《The Sorrows of Young Werther》:就是《少年维特之烦恼》,差不多是跟上面一样的原因而提到的,我初中的时候看过中文版,不过由于已经不太记得了,便又找出来看。我发现很多经典名著由于版权过期了,都可以在 Gutenburg 上找到非盗版的电子书。像维特那种鲜明的对于自己所认定东西持非常 strong 态度的个性让我觉得很像大学时的一个同学。感觉自己大概是比较不太会出现那种强烈的态度吧,更多的是在模棱两可之中。
  • 《每况愈下》:约翰·韦恩的这本书描写上世纪战后英国青年一代的生活,似乎那些人有一个标签叫做“愤怒的青年”,大概是比较有写实和记录意义的一本小说。
  • 《小王子》:本科毕业的时候看过一次,印象深刻的是驯化狐狸的故事,现在想起来还是很感触,麦田的金色,大概就是对于感情或者羁绊的最简洁的诠释吧。重看这本书是因为去了一趟作者的故乡 Lyon。或者说去 Lyon 其实是因为这本书吧。:)
  • 《Impressionism》:在多看上随便买的一本 Nathalia Brodskaya 的电子书,因为在法国看博物馆被震撼到了,决定至少要了解一下这些印象派先驱们的故事。
  • 《Van Goph》:perfect square 系列的一本。
  • 《我们为什么旅行》:不喜欢,迅速扫完之后现在已经没有印象了。曾经有一段时间特别执着于寻找旅行的意义,到现在其实并没有找到,然而也觉得似乎已经没有必要去追究这个问题了。有机会的时候,总会再一次踏上旅途,大概这就是旅行的意义吧。
  • 《三体》:刘慈欣的三体三部曲,非常好看的科幻小说,有很多人都给我推荐过很多遍了。最喜欢第二部。在德国旅行的途中看完的,白天出门暴走,晚上回来熬夜看小说,真是相当累人。:P
  • 《极简欧洲史》:以前看过一次,内容忘记了,在德国和捷克看一些历史博物馆,了解宗教发展和改革的一些东西的时候,不禁又对这些内容感兴趣,于是又找出来看了一下。感觉大概还是内容太多了以一点点的篇幅想要非常 coherent 地把所有内容串起来想到困难,感觉看到后面就有点乱了,如果不是事先就对欧洲历史全貌有比较好的了解的话,后面还是会看得比较晕的感觉。
  • 《全频带阻塞干扰》:刘慈欣的短篇小说,还可以吧。
  • 《证据游戏》:讲律师的小说,人物描写很细致入微。顺便了解了一下西方的审判系统,最后是否有罪居然是让大街上随便强制抓来的陪审团来决定,也是蛮神奇的。
  • 《六花的勇者》:同名动画片的原著轻小说,情节构思非常有意思,引人入胜,所以在等不及动画片更新之后就去看小说了。一贯的干巴巴的像看 manual 一样的轻小说文笔,但是设定和故事都很有意思,最喜欢第五卷。第六卷由于没有翻译版,就在日本 Amazon 买了原版来看,写得非常虐的一卷,不是特别喜欢。
  • 《仿生人会梦见电子羊吗?》:实验室 labmate 推荐给我的科幻小说。似乎是一本经典名著。不过我也觉得确实写得很好,我自己其实也是非常喜欢这类探讨人类和 AI 之间模糊界限的小说。
  • 《Liars and Outliers》:看的是中文翻译版叫做《我们的信任》。探讨人类如何从个人利益最大化(比如博弈中的纳什均衡之类的)的死结中走出来建立信任约束关系从而建立社会分工和文明的。比如说我们去餐馆吃饭为什么不用担心老板会下毒害我们之类的。我觉得探讨的问题还蛮有意思,但是最终觉得自己还是不是很喜欢看这种类型的偏社会学的书,长篇大论的纯文字性质(而不是建立数学模型通过逻辑来进行论证)的摆事实讲道理的讨论,就很容易让我觉得好像无论怎样讲都能讲出道理来的。
  • 《解忧杂货店》:满满温情,还有有趣的时间交错叙事方式。拥有烦恼并愿意与人商量的人,多半是想要去积极解决的人,大概本人其实心中早已有了抉择了吧——这样说也许过于绝对,但是反过来想其实有时候做出怎样的选择并不是最重要的,因为很多时候并无严格的黑白对错之分,重要的只是在选择之后的努力吧。不得不说和《白夜行》的风格形成鲜明的对比。
  • 《大秦帝国(第一部):黑色裂变》:第一部是上下两册,主要讲商鞅变法全过程。总的来说还不错,感觉小说的成分相对较大,不知道历史的成分有多少,当然两千多年前的事情,就是何真何假原本就很难讲清楚了。感觉春秋战国百家争鸣真是一个学术开放的年代,经营一个国家就跟现在开个公司似的,有才能的人也不会被诸如民族主义之类的东西束缚,能够自由地云游四方传播知识,还能今天在这里当两天丞相,明天再去另一国当丞相。
  • 《大秦帝国(第二部):国命纵横》这是第二部,也是上下两册,主要讲苏秦张仪合纵连横的故事。渐渐发现之所以看着觉得有点假的是每个男主角必定安排一个(或多个)完美无缺(聪明漂亮冷静善良武功又高等等)的女主,虽然说是英雄配美人,但是也太过模式化了。然后继续感叹诸子百家时候的学术开放,居然还有挂六国相印这样的事情,有点像现在的一个教授在好多学校挂名,还出任公司顾问啊之类的,哈哈。不过要论国家而言,现在世界上似乎主要还是以民族和宗教作为分化,并且互相之间似乎有诸多难以化解的仇恨的样子…… sigh。
  • 《天之痕》:其实是游戏了,干脆也列在这里吧,因为听到《幽城幻剑录》的 BGM 感觉非常怀念,就在网上找有没有重置版或者 iOS 版之类的,没有找到,但是看到《天之痕》的 iOS 版,虽然不是国产游戏中最喜欢的《幽城》,但是还是下载下来又玩了一遍。

总的来说好像看书的类型比较杂乱,原因是有时候打开多看 app 看到限时免费的书如果觉得还比较靠谱的话有可能会下载下来,所以其中有一部分书的类型比较随机。实际上这一年电影也看了不少,基本上都是被朋友抓去电影院之类的,其中最喜欢的一部是 Pixar 的 Inside Out,非常推荐。想起来我好像从来没有一个人去电影院看过电影。至于动画片,我记得去年有反省过看太多了,今年要少看,我自己感觉似乎确实看得相对少一点(而且现在很多动画片拍得相当烂俗):

  • 《噬神者》:好像是根据游戏改编的,剧情不知道在讲什么,单纯是喜欢那种浓重的大色块画风。
  • 《机动警察》:比较早期的动画片,很独特是视角,机战的设定,然而面对的却是现实中的柴米油盐,可以说是非常独特的一个动画系列。我看了剧场版和一些 OVA,TV 版陆陆续续看了一部分还没看完。
  • 《秦时明月》:国产动漫,追了许多年了,最慢的时候几个月才出一集,我估计很多人继续追的动力主要是想看看蓉姐姐到底什么时候能从昏迷中醒过来。不过客观来讲还是国产动漫中的佳品,特别是打斗动作,非常精彩。
  • 《记录的地平线第二季》:剧情比第一季更加拖沓了,不过喜欢画风和设定也就继续忍了。到第二季第 14 集女主角终于第一次登场了……
  • 《七大罪》热血类的动画片,有点像七龙珠的感觉,原本还以为自己早已过了热血的年纪呢,哈哈。瀧川ありさ唱的 ED 的 Season 超级好听。
  • 《境界的彼方剧场版》分过去篇和未来篇,过去篇就是 TV 版的重新剪辑,未来篇虽然是原创故事,但是剧情完全不能忍……不愉快です。另外还有一个 TV 未放松的隐藏话,讲主角们是如何认识的故事。
  • 《命运石之门》:非常中二但是非常好看,最后去把各种剧场版也都找来看了。TV 版一开始比较拖沓和无厘头,大概到 12 集才开始正式剧情,然而后面基本上就是一发不可收拾,并且最后把前面所有的铺垫全都联系起来了。豆瓣评分 9.2。
  • 《来自新世界》:看完以后很想说“什么鬼”,然而还是觉得是非常值得一看的。算是常识探讨“人类”这个东西的一部作品吧。豆瓣评分 8.8。
  • 《傀儡公主》:不错的动画短片。
  • 《希德尼娅的骑士第二季》:没有第一季好看啊。我一直期待对于最开始星白说人类和奇居子没有能好好互相交流的这个伏笔能有所展开,却一直没有。
  • 《红白黑黄 (RWBY)》:美国制作的系列动画短片,虽然有一些剧情但是感觉几乎可以忽略不计,重点是打斗非常精彩。目前出到第三季,然而作者之一似乎今年去逝了。顺便请不要觉得我看动画会关注战斗场景是因为我有暴力倾向……😂,其实是因为我小时候喜欢画武侠风格的漫画,自己觉得要表现精彩的战斗是很困难的技巧,所以就会格外关注了。
  • 《Angel Beats!》:忘记为什么会找来看了,因为这个动画片 10 年作为新番的时候我看过一集并没有跟下去。SSS 的 leader 有点像凉宫春日的感觉,片头的钢琴很好听。
  • 《玻璃之唇》:好像是因为想起在小樽看到的玻璃工坊才翻出来看的,剧情和人物刻画就不评价了,但是明亮的画风和精致的场景刻画,色彩、高光、静动,很多地方都觉得制作得很赞。歌《夏の日と君の声》也很好听。
  • 《六花的勇者》:前面说过小说了,设定很新颖的推理魔幻类动漫。
  • 《画江湖之不良人》:另一个国产动漫,战斗动作相对于《秦时明月》来说比较弱,不过人物 3D 模型方面似乎相对又要更细致一点。剧情还不错吧,武侠类型的,只要不是有太严重的逻辑漏洞我都还蛮喜欢的。
  • 《夏洛特 / Charlotte》:个人不是很喜欢,剧情后期毫无逻辑。
  • 《传颂之物虚伪的假面》:尾巴设定超级萌,画风很喜欢,还有 OP《不安定な神様》超级好听。只是剧情实在不知道要讲什么,而且到后期女主角实在是太多了分不清楚,只好放弃了……
  • 《一拳超人》:非常有意思的设定,男主角无敌,一般的怪肯定一拳秒杀,他的必杀技叫マジ殴り(认真殴打),用来对付最强的 boss。相比龙珠类一直打怪升级的故事,可以说是非常新颖的设定,然而在这样的设定下究竟还能写出什么样的故事呢?就请自己去看吧,我觉得故事也蛮有意思的。另外一拳超人原始漫画画风非常非常烂,后来有另一个漫画家是这个故事的粉丝,于是按照原始故事进行重新绘画。动画里的画风和在市面上看到的正常画风(非常精致)的一拳超人都是重画版的。

数了一下数目上大致是去年的一半多一点的样子。不过我的目标并不是不看动画片,毕竟有些动漫还是很经典很值得一看的,而且必要的休息也是需要的。

画画方面,一个就是最开始提到的丙烯绘画班,总的来说画得不多,有一些画具甚至都还没打开过,大致画了五六幅丙烯画(也是第一次在 canvas 而不是纸上画),两三幅水彩画,两三幅粉彩棒的画,还有几幅原本是 sketch,后来兴起了就用水溶彩铅开始上色最后搞得皱巴巴反而看起来很有感觉的小画,剩下就主要是中性笔涂鸦了(这个其实画了不少,至少有一个笔记本被我画完了)。主题基本上还是风景、人像和漫画三种类型,有临摹原画、照片或者实物,并没有尝试自己凭空创作过。趁着圣诞打折买了一只 Wacom Intuos Pro,也没有尝试过几次(借口是刚剁了手一时半会长不回来),而且好久没有用数位板了特别生疏,画得也非常生硬就不贴上来了。

当然去年开始玩的旅行中的速写(就是在火车、地铁、公交等地方画陌生人)也并没有完全中断,至少是在法国的时候还一直在玩,只是就能明显感觉到民风和之前在日本很不一样——原来之前在日本大家都知道我在画他们只是不好意思说破而已,在法国就不同了。有一次我在画对面坐的一个人,过一会儿一抬头发现人不见了,结果发现她跑到我身后来偷拍我画的画。当然还有更直接的,临下车之前走过来说给我看看,嗯,还不赖嘛,之类的。还有一次正在画前排的一对绅士着装的夫妇,旁边坐的一个黑人小妹妹就开始跟我说话,发现我听不懂法语之后她纠结了很久最后在手机上找了一个翻译页面开始跟我讲画得很好看能不能也给我画一张。于是我就画了撕下来送给她。画直接坐在邻座的人还有一次就是在日本的一次火车途中,当时那个女生坐着一动不动,不知道是不是吓坏了,估计是被当做是变态了😂。不过后来去德国就没怎么动笔,因为当时坐车途中主要在看书,《三体》之类的那几本。空闲时间只有那么少,也是没有办法,不过旅行本身还是很好玩的。

法国之行极大地刺激了我的艺术细胞,我当时就在想,如果我时小时候来过巴黎,说不定这辈子就决定去搞艺术了哈哈哈。当然现在的话就只能空热血一下咯,反正绘画作为一个爱好,也还是不错的。其实(至少对我来说)画画跟科研也有些像,展示出来的基本上都是画得还不错的作品,但是其实还有更多的废品,也有很多时候其实是挣扎在无法画出自己想要的或者满意的样子的时候的痛苦之中,科研不也是这样子吗哈哈?

在巴黎呆了近十天,给我的感觉就是住在那里永远不会无聊,逛不完的博物馆当然是一大亮点(在奥赛博物馆不吃不喝逛了一整天最后闭馆被赶出来的时候简直就想抱着柱子赖着不走),但是街头也有很多好玩的,虽然很多人给我忠告过天黑以后不要在外面到处跑,但是由于去的时候是夏天,晚上十点天才开始黑……所以我就经常跑去 Palais de Chaillot 的露台那里,就着埃菲尔铁塔为背景看街头艺人表演,亦或者跑去蓬皮杜艺术中心前面的广场看催眠术表演,催眠一大群人看起来真的很神奇,可惜听不懂法语不是很清楚催眠师具体在说些什么。说起法语,不得不说个人感觉英语在法国的普及程度似乎并不比在日本要更好,完全一句英文都不会讲的人碰到过不少,即使会讲英文,每当问路的时候,因为地名街道名之类的总是会以法语发音念出来,所以也是只能叫哭了。所以刚到第一天什么状况都没搞清楚就坐火车跑去旁边的小镇 Giverny 看莫奈花园害的我差点买错票去了几百公里远之外的地方。但是莫奈花园真的很赞啊,且不说花的数量,就种类而言都已经超过我之前见过的花的总和了,莫奈一定藏着一颗少女心,然后我再也不相信什么“画家都很穷吃不起饭”之类的话了。最后,差点忘记说,巴黎当街接吻的人好多,包括各种性别组合的。

从巴黎去马赛的火车刚好被我订在法国国庆节那一天(完全犯二了),早上去凯旋门看阅兵式,结果各种人山人海,最后打算回来的时候发现各种道路封锁,绕了无比大的圈子才回来赶上火车,正好马赛也有庆祝活动,就是在老港口放焰火,印象比较深刻的是无论有多挤,端着酒盘子的服务员总能如入无人之境。选择去 Marseille 而不是 Nice 和蔚蓝海岸的原因是小时候特别迷的《基督山伯爵》——说不定我在听说马赛的时候还不知道有巴黎这个地方。

所以我当然去了那个伊夫岛看了那个监狱,差不多算是到此一游啦,不过马赛本身其实也蛮不错的,Google Photos 根据我拍的照片和视频什么的自动生成了这样一个小视频:

总之城里最好玩的就是老港附近,早上会有鱼市,新鲜捕捞上来的各种千奇百怪的鱼放在那里卖,并不是我想象中的像《冰与火之歌》里那种中世纪各种喧哗叫卖的巨大的港口鱼市,但是也比较有意思。整个旧港一片也会有各种街头表演啊之类的(马赛鱼汤很赞)。另外马赛附近的峡湾也是强烈推荐,我去的好像是叫做 calanque de sugiton,坐 21 路车就可以到 hiking 起点,大约 hiking 半小时可以到观景台,海和峭壁的组合之前没有觉得会看起来这么让人心动的,就很向往海鸥可以沿着峭壁俯冲下去然后再迎风而上,随着高度上升如同镜头拉远一样渐渐将峡湾全景收入眼中,我简直都可以想象届时的背景音乐是怎样的,真是忍不住想一跃而下的😄。从观景台往下再 30 分钟就可以到海边。

海边并没有大片的沙滩,而是一些分离的小海滩,大部分是巨大的岩石,有很多人在岩石上玩跳水,我就把鞋子挂在书包上到水里去走了,绕着峭壁走了一大圈后来发现有一片地方大家什·么·都·没·有·穿…………后来回来的时候在岩石上看到 nudisme de tradition 的字样,大致就能猜出来了,原来这边是一片裸体海滩,完全不知道还有这么一回事。然而不知道是不是太突然了没有做好心理准备,好像也并没有觉得非常奇怪。感觉旅行的一个作用就是让你见识大千世界,有些东西在亲自经历之前光凭想象大概是会有很大的偏见或者 bias 的,等到真正见得多了就会见怪不怪了吧。除了裸体海滩之外另一个大概在我以前的三观中很难以理解的事情就是青旅中会有男女混住的房型——记得最开始来美国的时候听说美国的宿舍男女生是同一栋楼的时候就已经震惊得不行,到现在可以很自然地接受 Mixed Room(根据我的统计碰到鼾声如雷的室友的概率小了很多)的过程,其实客观的事情并没有什么改变,改变的知识文化和认知上的差异吧。有一句话说得好,很多事情只是不同,并无是非。

离开之前没忍住还是跳到海里去了,浪比较大不过很好玩,不小心喝了一口海水咸到要死,不过更糟糕的是,我下水的地方选得不是特别好,水里大石头比较多,海水又比较冷感觉不到,等我上岸的时候发现自己鲜血淋淋……O_o,擦破的撞破的,有些伤口还不小,虽然不是血如泉涌,但是也不是一下子就止住的那种。由于场面过于血腥就不放相关照片了,总之我赶紧打道回府,回到市区找了一个超市买了一大盒创可贴,心想着要去哪里洗伤口,看到 Google Map 上旁边有一个 Basilique Notre-Dame de la Garde,觉得教堂肯定有泉水之类的,就去那里,结果它居然是在山上(以后看 Google Map 一定要注意垂直高度)……总而言之最后是没有事情,但是由于脚底有伤,直接导致后来一段时间暴走能力下降很多。^ ^bb

最后在马赛的青旅前台居然碰到一个哈佛的小朋友在那里做志愿者,她说她们青旅是完全志愿者运营的,她自己是学法国文学的,就借这个暑假来这里做志愿者就可以免费吃住顺便了解当地文化风俗。

马赛旁边还去了 Aix-en-Provence,去这里纯属意外😂,因为本来是要去普罗旺斯看薰衣草的,后来我没搞清楚具体位置,而且好像开车比较方便,然后就来这个小镇逛了一圈,没想到 Cézanne 的故居和画室原来在那里,此外小镇本身也还比较有意思,老城区有一片地方随便走个三五步就会看到一个不同的喷泉。唯一比较诡异的经历就是有个中国大叔不停地叫我帮他摆拍照片,然后又不停地批评我拍得不好不够认真,说他照片要用来作为他们公司的形象代言什么的,我觉得他似乎有在酝酿跟我讲人生哲理等等一系列话题的企图于是赶紧找个借口跑掉了。

在法国去的另一个城市就是 Lyon,主要是为了《小王子》,在广场上有一个石桩上又小王子和他的作者的雕像。比较有意思的是虽然《小王子》名扬四海,但是其实在 Lyon 并没有看到比如满大街都是圣-埃克苏佩里周边产品这样的疯狂地“沾光”和商业化的景象。Lyon 本身是一个很不错的小城,美食好像也很有名,然后城市自东向西从古罗马时期到近现代几乎保留了各个时代的典型建筑,而我去那里的另一大目的就是看壁画啦——散落在城里一些地方的建筑上有巨幅的快要能以假乱真的壁画,因此里昂又有”壁画之都“的称号。

除了七月在法国之外,八月份又跑了一趟欧洲,主要是在德国,顺便去了一趟捷克。因为时间有限,纠结了很久最终决定放弃南部的慕尼黑一带(虽然我很想去看新天鹅堡),只在北边活动,以后有机会再去吧。第一站是科隆,不得不说从车站一出来就震惊到了,因为科隆大教堂就在火车站门口。

因为科隆大教堂本身就很宏伟,再和周围的建筑一对比,就变成非常鲜明的一副景象,可以登顶俯瞰全城,似乎是有五百多级台阶,旋转而上。另外还有一件比较有意思的是里面有一面彩绘玻璃非常特别,是像素风格的,后来 HZ 跟我讲那时一个叫做Gerhard Richter的艺术家专门设计的。教堂旁边就是霍亨索伦桥,科隆最古老的桥,横跨莱茵河,大概因为它本身就比较长,反正是我见过的同心锁挂得最多的一座桥了。Wallraf-Richartz-Museum 还有 Museum Ludwig 之类的各式博物馆也比较集中,步行游览非常方便。中间又一次在一个教堂门口碰到了一个旅行团一样的,然后有一个女生就一直跟我聊天,似乎是本地人,刚刚毕业,暑假逗留一段时间然后马上要去英国读法律硕士之类的,还说她老爸是搞建筑的,目前在中国西藏考察当地的民俗风格的建筑之类的,总之最后我终于搞清楚了原来她是导游的小帮手,然后当她知道我其实不是旅行团的一员时露出非常复杂难以形容的表情……^_^bbb抽空还去了附近一个叫做布吕尔的小镇,据说整个区被列为世界文化遗产,不过不知道我是迷路了还是怎么,除了看 Augustusburg and Falkenlust Palaces 之外,在小镇上并没发现什么特别的地方。

科隆之后是法兰克福,一般来说法兰克福是欧洲重要的交通枢纽,很多飞机都会在这里转机,但是作为游玩地似乎不是那么出彩,不过这次我在法兰克福逗留两天是因为正好赶上一年一度的博物馆河岸节(Museumsuferfest),我原本口水的是 7 欧元通票逛遍美茵河边所有博物馆,结果发现节日庆典本身也非常好玩,岸边绵延几公里全是小摊小铺,来自世界各地的音乐、舞蹈、美食、皮革、书籍、木雕、陶瓷、绘画、各种手工艺品、民俗特色,还有演唱会、露天舞蹈、大力士、射箭、赛龙舟、烟花等等,当然还有很多很多很多的人。一句话总结就是——由于围观各种东西在一直在太阳底下晒,导致后来直接被晒蜕了一层皮……-.-bb

当时订住的地方订好了之后收到邮件说,我们是在红灯区,不过你放心,这里很安全……然后我凌晨看完烟火大会回去的时候街边果然就气氛诡异,不过让我没想到的是那些拉客的人有的时候真的是字面上地来拉住你啊……吓了我一大跳,撒腿就跑。。。。哈哈哈。啊,对了,歌德故居也在法兰克福。

由于后来下雨,我在柏林的三天主要干了两件事情:逛博物馆和排队,正好有三天博物馆通票,就是排队的人太多了。最令人发指的是 Old National Gallery 那里在开一个 Impressionism and Expressionism 的特展,大清早提前一个小时到那里就已经有人打着伞在雨中排队了……当然博物馆岛那一片的馆都不错,除了艺术馆之外,历史文物也比较多,包括古埃及还有一些其他早期的文明,Pergamon Museum 里把别人整个城堡城墙都放在里面展览……附近还有历史博物馆,差不多能把德国那一块地方从最早期开始一直到二战结束之后的整个历史过一遍,德国人对于二战也好大屠杀也好还是比较能不偏不倚地客观地去看待的,跟我之前在日本看到的某些博物馆里的东西简直形成鲜明对比。此外还有一个专门的犹太人历史博物馆。柏林的小吃 Currywurst 我很喜欢,买了好多吃。柏林大教堂比较奇怪,进去参观居然要收费,后来我晚上路过的时候看到很多人在排队,发现是音乐会,结果在卖票的地方正好碰到有人不知道为什么想要出手自己买到的票,于是她一欧元卖给了我一张票,虽然位置一般,不过也堂而皇之地去听了一场音乐会,也就没有再打什么 Berlin Philharmonic 之类的主意,反正我对交响乐的兴趣也就一般啦。

最后是千塔之城布拉格。虽然主要是冲着穆夏去的,但是安排了三天的行程实在是太明智了。感觉这是一个很适合发呆的城市,每到下午我就跑去查理大桥发呆听街头音乐,一直到天黑人散尽为止。因为别的地方的街头艺人一般都是一把吉他,所以在这里看到街头各种提琴、电钢琴以及一些稀奇古怪的吟游诗人带来的民俗乐器之类的就觉得很奇特。更神奇的是还在这里碰到了 YZ,成立了 MSTC 驻捷克临时分部……

最开始是在巴黎的圣心堂附近买了一张非常精致的明信片,看那个设计原本以为是现代装饰艺术的卡片,结果发现作者是十九世纪的人,就是慕夏,Mucha 也有翻译做”慕哈“(就音译来说是更准确的),然而我真是非常喜欢慕夏这个名字,当然画也非常喜欢。在城里有一个 Mucha 纪念馆,可以看到他的许多作品,虽然并不是原件(当然由于他那些装饰画主要是用于商业印刷,不知道到底有没有原件保留以及什么算是原件)。另外我后来在离市中心稍远的地方闲逛的时候发现一个叫做 Trade Fair Palace 的地方,里面放着 Mucha 晚年的巨幅画作系列斯拉夫史诗 (The Slav Epic),并不是之前的装饰画风格,而是写实油画风格的大约 20 来幅是 6x8 米这种规格的巨幅画作。能发现这里也纯属意外,完全没想到 Trade Fair Palace 这种地方为什么会是博物馆,不过好像所谓的 National Gallery in Prague 本身就是由集散在布拉格各处的一些分馆合起来的总称,而这里也是其中一个,所以说感觉很容易错过的样子。另外旁边还有一个交通工具的馆,火车汽车飞机摩托车自行车各个年代都有,感觉非常有趣,虽然好像主要是小朋友在参观。

呃,我果然把总结写成游记了。旅行的事情先就此打住吧。2015 年,自身的经历和变化,认识到的一件事情就是:和自己做斗争,真实惨无人道的至死方休的战斗。换句话说在养成新的习惯学会新的东西的同时也有可能会养成坏的习惯和忘掉旧的东西。这一年感觉自己的拖延症尤其严重:小事比如经常晚上要十二点前睡觉也会拖到一两点,大事比如 Qual 结束,TA 的要求也完成了,之后本来应该要想 Thesis Topic 的却一直没有仔细弄,连 blog 也几乎全年处于荒芜状态,还有原本在想明年要不要找实习也是拖到十二月了才马马虎虎弄了一下,发现好像很多坑都早就满了又有种懒得弄了大不了留学校的感觉……

拖延症加重的原因除了完美主义强迫症之外,另一个一个重要原因大概是由于客观上来说本身要做的事情就太多了又都很不 trivial,真的做不过来……比如秋季学期就是既在做 TA 又在修课,身上压着两个 funding 相关的 project,以及其他的 meeting,绘画课和游泳课,还要做开源相关的东西。当然我自己也脱不开干系,总结起来就是我太拖泥带水,很多事情都放不下,这也想做那也想做,最后就会所有事情都卡住做不了。或者说即使想要 follow 本心舍小区大什么的,也由于自己生活完全无战略目标和计划可言(好像看《大秦帝国》看得有点走火入魔),自然就乱了章法。新的一年如果在这个方面有所突破的话当是万幸。

说到 open source,其实也比较好玩,去年提到有做一个东西叫做Mocha.jl,顺便我后来才发现发音很有歧义,其实我最开始想的是“摩卡”,而不是“抹茶”哈哈……^_^bb。总之这个主要是去年做的,到后来在 Julia 社区似乎变得比较有名了,在 Github 上是 Julia 的 package 里是 star 数仅次于 IJulia 和 Gadfly.jl 的项目,导致有时候会有人建议我去一些场合讲这个,比如 OSCon、JuliaCon 之类的,多少有些无心插柳,其实我虽然会在实验和解具体的问题中有时候用到 deep learning 模型,以及对背后的优化和理论方面的东西都比较感兴趣,还有也会抽空 follow 一些最新进展,但是我自身的研究课题并不能明确地算是做 deep learning,不过这年头反正全民皆 deep,也没有那么多界限分明了。

总之托这个福,也让我认识了不少新的朋友和同事,接触到一些新的机会。记得之前在哪里听过一个 talk 里收到过一个建议就是,无论任何时候去做 presentation 都要做好万全的准备,因为你永远不知道听众里会出现什么样的人(并不是说会有人问问题把你问到死,而是说可能会碰到手握你将来生杀大权的大佬啊,或者是未来的志同道合的朋友啊之类的)。到现在我很难讲自己做到了每一次做 presentation 都做好万全的准备,不过对于这个道理的认同感也确实是越来越深了。此外大概九月末的时候在 winsty 的引荐之下认识了 tianqi 他们那一帮dmlc的人,他们正在搞一个叫做MXNet的比较新的项目,问我有没有兴趣帮他们搞一下Julia 的 binding,因为看起来也比较有趣,就顺势加入了这个组织。后来还在加拿大的时候跟团队其他人见了一面。不得不说他们真是太勤奋了,东西海岸不过三个小时的时差,就导致我每天早上醒来的时候得 archive 几十封 github 的 pull-request、issue 相关的邮件才起得了床。总之是非常有活力的一群人,让我想起了埼玉一开始的台词,「趣味でヒーローをやっている者だ」(“兴趣使然的英雄”)。:)

反正我觉得这其实是温情满满的一年,其中有一件事情让我感触特别深。有一次路过 Stata Center 一楼大厅的时候看到一个女生拿着粉笔在大黑板面前发呆,黑板上写了一个大大的 H 字,下午再次路过的时候看到上面写着“Happy Tuesday”,瞬间就觉得被各种劳累和压力烟消云散,一下子就被治愈了。真是没有想到原来很多时候人们只是需要如此简单的鼓励,我想肯定有很多路过的学生跟我有同样的感受。

那之后的很长一段时间,几乎每周都会有不同风格的“Happy Tuesday”出现(有时候是其他 Weekday),一直持续到大家期末考试结束。每次看到这个就会拍下来,一开始觉得很神秘,后来渐渐觉得这不是一个人能完成的,说不定是某个神秘的社团呢。到后来某一天起得特别早,跑去 stata 楼下买咖啡的时候看到一个小朋友正在黑板上涂鸦中,就上去道了谢,顺便询问了一下,原来她们一共只有两个人在换班!

不知道有多少人被这些黑板涂鸦鼓舞了士气,平时也时常见到旁边有小字写的 thank you 之类的,客观来讲很难说写个 happy tuesday 的实际作用是什么,但是人类果然是社会生物啊,就好像之前看的《Liars and Outliers》一本书里讲的,人类社会的建立,本身就是一个奇迹,因为你的整个生活乃至生存的根本都得基于对数不清的跟你非亲非故的各行各业的人的信任之上。就好比博弈,如果人类一直都按照Nash equilibrium那样的方式来行事的话,大概整个社会系统最初就没法建立起来。然而如果考虑到人是需要群居,并不断地互相打交道的话,诸如“信任”、“信誉”之类的概念就渐渐地出现了,其实现在机器学习里 online learning 里的研究课题差不多就是这样的repeated game,只要从长远来看做到 No Regret 就好了。比如今年 NIPS 的 best paper award 之一的 Fast Convergence of Regularized Learning in Games,就是讲这方面的东西:过去关于 online learning 的研究,即使考虑了 repeated game,也还是在对方是完全 adversarial 的情况下考虑的,更“真实”的情况是各个玩家都采用一种 no regret learning 的策略(比以前更加贴近于人类社会的模型),这篇论文证明了在这样的情况下能得到比 adversarial 快很多的 convergence rate。

感觉我好像有点扯远了,说起 conference,今年非常幸运地包括自己去开会以及由于各种各样的原因而得以蹭会等等,围观了包括 CVPR、COLT、ICML、INTERSPEECH、NIPS 等各个领域的会,也算是增长了不少见识。此外还有一件比较有趣的事情就是今年 TA 的一门课里由于有几百个学生,试验了一种 peer review 改作业的办法,完全使用真实的 paper review system,TA 扮演 program chair 和 area chair,学生匿名提交作业,并且充当 reviewer,最后的评分会根据 reviewer 打分综合得到,当然如果 reviewer 乱搞(比如某篇作业的评分 variance 很大的话就很容易发现)会被额外扣分,所以最后大家都很认真对待 review 的事情。虽然中间有各种各样的小问题,但是总的来说还是蛮成功的,反正既然是 graduate level 的课,让大家早日接触到这样的流程也是一件好事,特别是现在 AI 相关的领域科研热,NIPS 明年居然都说要开始试验强制要求所有 submit 了 paper 的人就要充当 reviewer……不过我想说的是,当了一回山寨的 PC 之后,真的是非常想给那些有好几千 submission 的会议的 PC 致敬!😂

真的越说越远了,还有什么事情要说的?哦,今年重新配了一副眼镜,因为之前的眼镜在 Oregon 玩的时候被大风吹跑了………………虽然平时不戴眼镜,但是上课的时候会用,其实可以明显感觉自己的视力是在下降中的。

恩,还有朋友之中不少人结婚了,直接或者间接地见证了大家组成新的家庭,很是开心,甚至还有幸当了一次伴郎,大概是自从小学时期六一儿童节上台表演以来第一次穿正装啊。当然有聚就有散,似乎是亘古不变的真理,作为旁观者,这一年之中其实也目睹了不少分手的故事,甚至还有一些在感情方面比较颠覆三观的事情。想起来有人跟我开玩笑说看你每年的总结就是跳过所有的内容只看 8g 的部分,想一想莫非是我过去几年的总结都写得很“为情所困”的样子😂?不过今年就没有我什么事情了,直接导致我在选今年的歌的时候发现好难选。只好开始用几首压箱底的轻松愉快类歌了。

走路快一点脚步大一点心事少一点情绪好一点明天或后天不管不管不管向前看近一点就是这样摇滚吧全世界就是这样超越虚拟的界限就是这样颠覆时间就是这样天地是那么炫就是这样换个美丽画面今天不就是永远

好像全球好多地方今年都是暖冬,波士顿亦是如此,一直到年底几乎最后一天才下了一个上午的雪,当然这一个上午的雪直接导致我机票延误以及往后一连串的悲剧事件发生,😂可以说是“晚节不保”了。新的一年,希望改善拖延症,多写 blog!😀附上往年总结的链接:

Viewing all 62 articles
Browse latest View live