![]() |
|
Spaces home 笑对人生,傲立寰宇PhotosProfileFriendsMore ![]() | ![]() |
笑对人生,傲立寰宇无边的大海上,一只白帆,勇敢地航行着,就为了前面的点点星光
May 07 让MATLAB更快MATLAB是一门在数值运算方面非常高效的语言,对于提高MATLAB的效率,有一些大家熟知的方法,比如避免使用for循环,向量化,使用C-mex写核心,等等。这些原则大体是没错的,但是教条地运用有时反而会降低效率。 根据问题的规模,适当选择向量化的策略 向量化的基本思想是以空间换时间,通过把要处理的对象转化成一个矩阵,集中处理。这比起非向量化的处理方式往往需要消耗更多的内存。在内存紧张的时候,内存分配的开销可能是很大的。 比如,给定一个列向量v1,和一个行向量v2, 计算矩阵M,使得M(i, j) = v1(i) + v2(j)。一种常用的向量化实现: m = length(v1); n = length(v2); M = repmat(v1, [1, n]) + repmat(v2, [m, 1]); 这个过程中,除了M以外,还要创建两个大小为m x n的临时矩阵。repmat创建临时矩阵有一定的overhead,主要花费在元素索引上。由于元素加法的向量化收益本身并不显著,扣除repmat的额外开销后,得益就更小了。另外,当这些矩阵很大,接近物理内存容纳能力的时候,必然导致和虚拟内存进行频繁的交换,耗费大量的IO时间,向量化可能得不偿失。这种情况下,下面这种向量化程度略低的方式可能是更好的选择: M = zeros(m, n);
if m < n
for i = 1 : m
M(i, :) = v1(i) + v2;
end
else
for i = 1 : n
M(:, i) = v1 + v2(i);
end
end
这个例子是要说明在设计向量化的时候,要对其它潜在的影响因素也进行考虑,权衡得失。对于这个例子本身,在2007版以后的matlab,有一个通用的简洁的写法。 M = bsxfun(@plus, v1, v2); MATLAB内部对于bsxfun有很专业的优化,这个写法在时间和空间上都比较节省。 对一组d x d矩阵求逆,假设这些矩阵放在大小为d x d x n的数组里。在一般条件下,多个矩阵求逆没有特别的向量化方法,通常就是逐个求 n = size(A, 3);
B = zeros(size(A));
for i = 1 : n
B(:, :, i) = inv(A(:, :, i));
end
不过,当d很小而n很大的时候,比如对大量2x2矩阵求逆(这在设计几何的问题中很常见),那么直接利用2x2矩阵的求逆共识,进行向量化了: a = reshape(A(1, 1, :), [1, n]); b = reshape(A(1, 2, :), [1, n]); c = reshape(A(2, 1, :), [1, n]); d = reshape(A(2, 2, :), [1, n]); g = 1 ./ (a .* d - b .* c); r11 = d .* g; r12 = -b .* g; r21 = -c .* g; r22 = a .* g; B = reshape([r11; r21; r12; r22], [2, 2, n]); 在正式的代码中,还需要处理可能为奇异(a*d-b*c=0)的情况。 某些非数值计算问题的向量化 有些问题,表面上不像是数值计算,但是通过适当的转化,也可以通过向量化解决。 非等量复制: 比如有一组数[10, 20, 30], 各自要复制成[3, 2, 5]份,最终产生出 [10 10 10 20 20 30 30 30 30 30]。这个问题,虽然简单,但是因为不是那么“整齐”,因此向量化不是特别直接。下面给出一种思路: 首先产生出起始位置标志向量[1 0 0 1 0 1 0 0 0 0],然后通过cumsum,产生出[1 1 1 2 2 3 3 3 3 3],最后以此为索引,可以得到结果。 % vs: the values to be copied % ns: the numbers of copies vs = vs(ns > 0); ns = ns(ns > 0); sp = [1, cumsum(ns(1:end-1)) + 1]; result = vs(cumsum(sp)); 对于图像处理或者二维信号问题,善用filter。 比如,要对每个像素,基于其局部邻域进行一些计算。即使整个计算本身不是线性的,但是只要能分解成线性局部运算的组合,就可以利用filter。 比如,对于图像I, 产生V,使得V(i, j)是像素I(i, j)周围w x w邻域的像素的方差。 I = im2double(I); h = ones(w, w) / (w * w); M = imfilter(I, h, 'symmetric'); M2 = imfilter(I.^2, h, 'symmetric'); V = M2 - M.^2; April 19 图˙谱˙马尔可夫过程˙聚类结构题目中所说到的四个词语,都是Machine Learning以及相关领域中热门的研究课题。表面看属于不同的topic,实际上则是看待同一个问题的不同角度。不少文章论述了它们之间的一些联系,让大家看到了这个世界的奇妙。 从图说起 这里面,最简单的一个概念就是“图”(Graph),它用于表示事物之间的相互联系。每个图有一批节点(Node),每个节点表示一个对象,通过一些边(Edge)把这些点连在一起,表示它们之间的关系。就这么一个简单的概念,它对学术发展的意义可以说是无可估量的。几乎所有领域研究的东西,都是存在相互联系的,通过图,这些联系都具有了一个统一,灵活,而又强大的数学抽象。因此,很多领域的学者都对图有着深入探讨,而且某个领域关于图的研究成果,可以被其它领域借鉴。 矩阵表示:让代数进入图的世界 在数学上,一种被普遍使用的表达就是邻接矩阵(Adjacency Matrix)。一个有N个节点的图,可以用一个N x N的矩阵G表示,G(i, j)用一个值表示第i个节点和第j个节点的联系,通常来说这个值越大它们关系越密切,这个值为0表示它们不存在直接联系。这个表达,很直接,但是非常重要,因为它把数学上两个非常根本的概念联系在一起:“图”(Graph)和“矩阵”(Matrix)。矩阵是代数学中最重要的概念,给了图一个矩阵表达,就建立了用代数方法研究图的途径。数学家们几十年前开始就看到了这一点,并且开创了数学上一个重要的分支——代数图论(Algebraic Graph Theory)。 代数图论通过图的矩阵表达来研究图。熟悉线性代数的朋友知道,代数中一个很重要的概念叫做“谱”(Spectrum)。一个矩阵的很多特性和它的谱结构——就是它的特征值和特征向量是密切相关的。因此,当我们获得一个图的矩阵表达之后,就可以通过研究这个矩阵的谱结构来研究图的特性。通常,我们会分析一个图的邻接矩阵(Adjacency Matrix)或者拉普拉斯矩阵(Laplace Matrix)的谱——这里多说一句,这两种矩阵的谱结构刚好是对称的。 谱:“分而治之”的代数 谱,这个词汇似乎在不少地方出现过,比如我们可能更多听说的频谱,光谱,等等。究竟什么叫“谱”呢?它的概念其实并不神秘,简单地说,谱这个概念来自“分而治之”的策略。一个复杂的东西不好直接研究,就把它分解成简单的分量。如果我们把一个东西看成是一些分量叠加而成,那么这些分量以及它们各自所占的比例,就叫这个东西的谱。所谓频谱,就是把一个信号分解成多个频率单一的分量。 矩阵的谱,就是它的特征值和特征向量,普通的线性代数课本会告诉你定义:如果A v = c v,那么c 就是A的特征值,v就叫特征向量。这仅仅是数学家发明的一种数学游戏么?——也许有些人刚学这个的时候,并一定能深入理解这么个公式代表什么。其实,这里的谱,还是代表了一种分量结构,它为使用“分而治之”策略来研究矩阵的作用打开了一个重要途径。这里我们可以把矩阵理解为一个操作(operator),它的作用就是把一个向量变成另外一个向量:y = A x。对于某些向量,矩阵对它的作用很简单,A v = cv,相当于就把这个向量v 拉长了c倍。我们把这种和矩阵A能如此密切配合的向量v1, v2, ... 叫做特征向量,这个倍数c1, c2, ...叫特征值。那么来了一个新的向量x 的时候,我们就可以把x 分解为这些向量的组合,x = a1 v1 + a2 v2 + ...,那么A对x的作用就可以分解了:A x = A (a1 v1 + a2 v2 + ...) = a1 c1 v1 + a2 c2 v2 ... 所以,矩阵的谱就是用于分解一个矩阵的作用的。 这里再稍微延伸一点。一个向量可以看成一个关于整数的函数,就是输入i,它返回v( i )。它可以延伸为一个连续函数(一个长度无限不可数的向量,呵呵),相应的矩阵 A 变成一个二元连续函数(面积无限大的矩阵)。这时候矩阵乘法中的求和变成了积分。同样的,A的作用可以理解为把一个连续函数映射为另外一个连续函数,这时候A不叫矩阵,通常被称为算子。对于算子,上面的谱分析方法同样适用(从有限到无限,在数学上还需要处理一下,不多说了)——这个就是泛函分析中的一个重要部分——谱论(Spectral Theory)。 马尔可夫过程——从时间的角度理解图 回到“图”这个题目,那么图的谱是干什么的呢?按照上面的理解,似乎是拿来分解一个图的。这里谱的作用还是分治,但是,不是直观的理解为把图的大卸八块,而是把要把在图上运行的过程分解成简单的过程的叠加。如果一个图上每个节点都有一个值,那么在图上运行的过程就是对这些值进行更新的过程。一个简单,大家经常使用的过程,就是马尔可夫过程(Markov Process)。 学过随机过程的朋友都了解马尔可夫过程。概念很简单——“将来只由现在决定,和过去无关”。考虑一个图,图上每个点有一个值,会被不断更新。每个点通过一些边连接到其它一些点上,对于每个点,这些边的值都是正的,和为1。在图上每次更新一个点的值,就是对和它相连接的点的值加权平均。如果图是联通并且非周期(数学上叫各态历经性, ergodicity),那么这个过程最后会收敛到一个唯一稳定的状态(平衡状态)。 图上的马尔可夫更新过程,对于很多学科有着非常重要的意义。这种数学抽象,可以用在什么地方呢?(1) Google对搜索结果的评估(PageRank)原理上依赖于这个核心过程,(2) 统计中一种广泛运用的采样过程MCMC,其核心就是上述的转移过程,(3) 物理上广泛存在的扩散过程(比如热扩散,流体扩散)和上面的过程有很重要的类比,(4) 网络中的信息的某些归纳与交换过程和上述过程相同 (比如Random Gossiping),还有很多。非常多的实际过程通过某种程度的简化和近似,都可以归结为上述过程。因此,对上面这个核心过程的研究,对于很多现象的理解有重要的意义。各个领域的科学家从本领域的角度出发研究这个过程,得出了很多实质上一致的结论,并且很多都落在了图的谱结构的这个关键点上。 图和谱在此联姻 根据上面的定义,我们看到邻接矩阵A其实就是这个马尔可夫过程的转移概率矩阵。我们把各个节点的值放在一起可以得到一个向量v,那么我们就可以获得对这个过程的代数表示, v(t+1) = A v(t)。稳定的时候,v = A v。我们可以看到稳定状态就是A的一个特征向量,特征值就是1。这里谱的概念进来了。我们把A的特征向量都列出来v1, v2, ...,它们有 A vi = ci vi。vi其实就是一种很特殊,但是很简单的状态,对它每进行一轮更新,所有节点的值就变成原来的ci倍。如果0 < ci < 1,那么,相当于所有节点的值呈现指数衰减,直到大家都趋近于0。 一般情况下,我们开始于一个任意一个状态u,它的更新过程就没那么简单了。我们用谱的方法来分析,把u分解成 u = v1 + c2 v2 + c3 v3 + ... (在数学上可以严格证明,对于上述的转移概率矩阵,最大的特征值就是1,这里对应于平衡状态v1,其它的特征状态v2, v3, ..., 对应于特征值1 > c2 > c3 > ... > -1)。那么,我们可以看到,当更新进行了t 步之后,状态变成 u(t) = v1 + c2^t v2 + c3^t v3 + ...,我们看到,除了代表平衡状态的分量保持不变外,其它分量随着t 增长而指数衰减,最后,其它整个趋近于平衡状态。 从上面的分析看到,这个过程的收敛速度,其实是和衰减得最慢的那个非平衡分量是密切相关的,它的衰减速度取决于第二大特征值c2,c2的大小越接近于1,收敛越慢,越接近于0,收敛越快。这里,我们看到了谱的意义。第一,它帮助把一个图上运行的马尔可夫过程分解为多个简单的字过程的叠加,这里面包含一个平衡过程和多个指数衰减的非平衡过程。第二,它指出平衡状态是对应于最大特征值1的分量,而收敛速度主要取决于第二大特征值。 我们这里知道了第二大特征值c2对于描述这个过程是个至关重要的量,究竟是越大越好,还是越小越好呢?这要看具体解决的问题。如果你要设计一个采样过程或者更新过程,那么就要追求一个小的c2,它一方面提高过程的效率,另外一方面,使得图的结构改变的时候,能及时收敛,从而保证过程的稳定。而对于网络而言,小的c2有利于信息的迅速扩散和传播。 聚类结构——从空间的角度理解图 c2的大小往往取决于图上的聚类结构。如果图上的点分成几组,各自聚成一团,缺乏组与组之间的联系,那么这种结构是很不利于扩散的。在某些情况下,甚至需要O(exp(N))的时间才能收敛。这也符合我们的直观想象,好比两个大水缸,它们中间的只有一根很细的水管相连,那么就需要好长时间才能达到平衡。有兴趣的朋友可以就这个水缸问题推导一下,这个水缸系统的第二大特征值和水管流量与水缸的容积的比例直接相关,随比例增大而下降。 对于这个现象进行推广,数学上有一个重要的模型叫导率模型(Conductance)。具体的公式不说了,大体思想是,节点集之间的导通量和节点集大小的平均比例和第二大特征值之间存在一个单调的上下界关系。导率描述的是图上的节点连接的空间结合,这个模型把第二特征值c2和图的空间聚集结构联系在一起了。 图上的聚类结构越明显, c2越大;反过来说,c2越大,聚类的结构越明显,(c2 = 1)时,整个图就断裂成非连通的两块或者多块了。从这个意义上说,c2越大,越容易对这个图上的点进行聚类。机器学习中一个重要课题叫做聚类,近十年来,基于代数图论发展出来的一种新的聚类方法,就是利用了第二大特征值对应的谱结构,这种聚类方法叫做谱聚类(Spectral Clustering)。它在Computer Vision里面对应于一种著名的图像分割方法,叫做Normalized Cut。很多工作在使用这种方法。其实这种方法的成功,取决于c2的大小,也就是说取决于我们如何构造出一个利于聚类的图,另外c2的值本身也可以作为衡量聚类质量,或者可聚类性的标志。遗憾的是,在paper里面,使用此方法者众,深入探讨此方法的内在特点者少。 归纳起来
马尔可夫过程代表了一种时间结构,聚类结构代表了一种空间结构,“谱”把它们联系在一起了,在数学刻画了这种时与空的深刻关系。
April 10 How to get a solution?我们所做的topic,一般有几个阶段:
最近的工作都集中在Solving这部分,就说说这个吧。 求解的方法 求解问题有很多不同的方法,就我知道的来说,大概有这么几个大家族。
和这里很多留学生一样,我一向潜心于自己的学习和研究。可是最近,我们的世界并不宁静,我认识的不只一个在美国的朋友受到了不太友好的挑衅——在不知不觉中,我们可能已经身处反分裂和支持奥运的前线。我看到包括MIT CSSA在内的很多学生团体开始组织起来支持自己的祖国。我没有具体帮上什么,但是,我对所有在用自己的行动捍卫国家荣誉的同胞怀有最深的敬意。我也希望,我的努力,能让外国的朋友明白中国人是值得尊敬的。 April 02 深入问题本身很多做research的朋友喜欢top-down approach,包括我自己。就是说,在开始一个topic的时候,在第一时间就设定了大体的formulation,model又或者methodology。至于选择哪种设定,往往取决于研究者本身的偏好,知识背景,或者对问题的第一反应。 接下来的事情就顺理成章了,推导数学模型和相关公式以及算法步骤,然后设计程序进行实验。当然少不了再拉上几个相关工作,比较一番。如果自己的设计很幸运地有明显的improvement,于是非常满意,开始写paper(在不少情况下,paper的理论部分甚至提前写好了)。可是,如果不work呢? 通常大家会采取下面一些方法中的一种或者几种:
无论如何,你总算把实验搞定了。但是,为什么work呢?除了几条曲线,你总得找一些“让人信服”的理由。在我所在的领域,有一些理由几乎是万能的,因而普遍出现在paper里面:
还有很多,不一而足。总体来说,就是增加了某方面的复杂性,推广了模型,或者把某些部分变得更加时髦,数学更深。正因为多了东西可以调节,只要花上足够时间去设定参数,还是有很大机会能找到一组能得到improvement的参数的。可是,这种improvement是不是真正有意义呢?是不是足够significant,以至于所增加的复杂性是值得的呢? 我们的世界总是无限复杂的,和无数的因素相关,这些因素又总是有某种联系。我们的前辈们留给我们的最好的方法,就是从问题中分离出最关键的要素,和最重要的关系,而非不断地增加价值不大的因素,建立意义不大的联系。 我并不是一个完全拒绝复杂,但是我个人觉得对复杂性的增长应该慎重。每增加一个要素,都应该是基于对问题的深入分析,而不是先入为主的设想和冠冕堂皇的理由。这不完全是知识能力的问题,更多的是一种治学态度——是不是愿意安心下来对问题本身进行深入细致的解剖,找出问题本身的关键所在,而不是脱离问题预先构想某种“漂亮”模型或者“巧妙”方法,并且通过上面所述的种种方法推销出去。 研究是一种创新的过程,广拓思路是必须的。但是真正有价值的novelty应该是建立在对问题本身的深入理解,确实发现了别人忽略的关键因素,或者主流算法的真正不足,并且创造性地提出解决方法。这需要持之以恒的努力。真正经得起考验的学术价值,源于解决还没有被解决的问题,而不是使用了某种所谓别人没用过的“新颖”方法来解决本来已经解决的问题,又或者给模型加入某个要素来取得非实质性的性能改进。 上面所说的这些问题,几乎都发生在我的身上。而汤老师的很多建议,其实正是指出了这些问题,却没有被我认真思考,反而总是以为只要理论做得高深,模型设计得精巧,就是好的工作。来了MIT之后,更多地阅读一些有历史价值的文章(现在看CVPR反而比较少了),接触一些更加solid的工作。许多有重要贡献的工作,往往未必有很炫的方法和模型,但是,其对于问题本身的深入发掘和洞察却令我惭愧。 要做真正的学问,首先要戒除浮躁。 March 30 MATLAB的思维风格最近做course project的时候,我发现所写的程序中有几个地方特别能反映MATLAB与别的高级语言很不一样的风格。 例1:一批user去访问文件,比如u1访问了f11, f12, ..., u2访问了f21, f22, ...,每个用户访问的文件数目可能不等,要求输出一个表M, M(i, j)是用户 i 和 j 都访问过的文件的个数。 先用高级语言给出一个比较直接的解决吧,下面是python的代码。(其实C++/C#/Java的也类似,不过python的代码比较简洁) 首先,建立一个访问字典(或者叫map),记录每个文件都被哪些人访问过。 # input is a map named ufiles,
# ufiles[u] is a set of files accessed by u
acc_dict = {}
for u in users:
for f in ufiles[u]:
if f in acc_dict:
acc_dict[f].add(u) # add u to an existing set
else:
acc_dict[f] = set([u]) # initialize the set
然后,基于这个字典进行计数。对每一个文件,给每一对访问过它的用户的相应计数加1 # initialize the table
M = {}
for u1 in users:
for u2 in users:
M[(u1, u2)] = 0
# do counting
for f in acc_dict:
uset = acc_dict[f]
for u1 in uset:
for u2 in uset:
M[(u1, u2)] += 1
这样就基本完成计数了。 MATLAB没有像python那样丰富的数据结构,比如set(集合)和dict(映射表,字典)。但是,在这个表面上需要依靠经典数据结构完成的问题,我们可以用MATLAB给出一个更加高效简洁的解决方法 给出代码之前,先做点数学分析。令F是一个矩阵,F(u, f) = 1代表u访问过这个文件,否则F(u, f) = 0。那么M其实就可以写成: M(u1, u2) = sum_f F(u1, f) F(u2, f) --- 很容易看出,这就是u1, u2都访问过的文件的数目。写成矩阵形式: M = F * F' 下面的代码就很顺理成章了 % Input: ufiles is a cell array of indices of files accessed by each user
% ufiles(i) is a row vector of the indices accessed by user i
% construct F
n = length(ufiles)
% to produce usrs like {[1 1 1 1 ...], [2 2 2 ...], ...}
usrs = arrayfun(@(i) i * ones(1, length(ufiles{i})), 1:n, ...
'UniformOutput', false)
I = [usrs{:}] % concatenate the indices into one long vector
J = [ufiles{:}]
F = sparse(I, J, 1);
% compute M
M = F * F'
注意这里用sparse matrix, 那么运算复杂度会显著降低,并且只依赖于实际访问的数量。实际性能上,通过MATLAB的稀疏矩阵乘法比自己用高级语言实现更快。 熟悉kernel的朋友可能已经看出来,MATLAB的做法其实是用file access indicator vector作为每个user的feature,构造出来的M则是相应的Gram matrix。不过,如果没有这方面的思维习惯的话,未必能很快就把一个统计文件访问量的问题联想到矩阵乘法或者内积计算。 例2:给出一组数字,算出每个不同数字出现的次数。 python的实现 counts = {}
for v in values:
if v in counts:
counts[v] += 1
else:
counts[v] = 1
用高级语言实现,一般需要一个映射表来快速定位某个数字的计数器。
Matlab的实现 svalues = sort(values); dp = find(diff(svalues)); sp = [1, dp+1]; ep = [dp, length(svalues)]; U = svalues(sp); % U is the set of distinct values C = ep - sp + 1; % C is the corresponding counts of these values 一般情况下,两种实现的时间复杂度都是O(n log(n))。不过,它们体现了不太一样的思维方式。高级语言倾向于通过数据结构加速每个元素的处理,而MATLAB没有复杂的数据结构,它注重于以整体方式进行操作。 March 19 MATLAB 2008这几个星期一直忙着作业和考试,这里有些天没有更新了。刚过了mid-term,回到这里和朋友们说说话。 今年3月,Mathworks推出了MATLAB一个重要的新版本,MATLAB 2008a,也叫做MATLAB 7.6。在这个版本里,MATLAB解决了几个长期以来固有的弊端,而且加入了一些重要的能力。这次的更新是非常aggressive的,可能代表了MATLAB的一种历史性的转型。
从这些特点看来,MATLAB这个版本的重要改变,就是全面吸收其它高级语言的特性,从一个数值运算语言开始迈向一个以数值计算为强项的通用语言,以应对复杂或者更大规模应用的需要。 一直以来,由于matlab缺乏处理高级数据结构和建立复杂应用的能力,它有一个有力的竞争者numpy,这是python里面进行矩阵和数值运算的包,它建基于python这种著名的通用语言,并且提供matlab矩阵的部分能力。这次MATLAB的全面升级,对于numpy无疑提出了严峻的挑战。 除了程序设计结构方面的变化,MATLAB 2008在多个方面也有重要进步。
MATLAB 2008刚刚发行,现在学校内部还没开始支持。不过,这个版本确实非常值得期待。 March 07 课业这两周经历了这个学期第一个忙碌的高峰。 这里的课业本来就很繁重,而且,很多时候并不均衡。最近,两门课程“不约而同”地把整个学期30%以上的作业量集中到了两个星期——我不记得这两周除了完成各种接续不断的assignment,还做过什么。 学计算机的人都知道循环语句,可是,如果这些人做TA,并且在布置作业的时候使用for循环,那是什么一种情况呢?最近一次作业的一道大题,竟然使用三重循环来布置,实在令人佩服。题目大概是长成这个样子: 1. (a). (a.1) xxxx, (a.2), xxxx, .... (a.n) xxxx, (a.(n+1)) change some condition, please repeat from (a.1) to (a.n) ...... (b) ..... (c) ..... (d) ........ (e) with a new setting, please repeat (a) to (d) ..... 2 ..... 3 ..... 4 ...... 5 in a new method, please repeat 1 to 4. 除了两门课的作业和实验,还需要完成Network的research proposal。这里的课程project都有一个特点,全部都是不命题的。学生需要自己完成,从survey, proposal, formulation, experiment, 到最后的report的全过程。Network这门课的老师特别强调,project必须探索这个领域的研究前沿,最后的report必须写成可以发表的paper的形式,中间有一次中期检查,最后还有一次答辩。他不只一次的告诉我们,每年都有相当数量的project paper成功发表到top conference上——这应该是他对我们的一种期待——这对于这门课的学生,尤其是不在这个领域的,确实是极具挑战性的。 CS的决策人确实是用心良苦——要求每个学生修的课必须覆盖3大领域(system, theory, AI),而在大部分的课程中,教授都要求学生完成一个从选题到最后报告的完整的课题研究过程。虽然非常辛苦,但是,学生确实可以获得在计算机科学的各大领域开展研究的经验。另外一方面,几年前CS把所属的全部实验室合并成CSAIL——常年有800人工作的超大型实验室,鼓励各个研究小组相互交流。强制性的跨领域修课政策加上大实验室制,使得CSAIL内部的交叉研究特别活跃。很多研究课题都是“杂交”的。每个老师管着不同领域的课题,每个学生参与不同小组的meeting,已经司空见惯。在某些具体的领域,CSAIL的研究未必是最好的,但是,这里确实是世界上交叉学科发展最为蓬勃的地方。 February 21 Homework? Review paper for Science今天作业的一部分,是以Science的reviewer的身份去review一篇文章,并攥写review报告。 这篇文章是已经在1996年发表于Science上,标题非常有趣: Statistical Learning by 8-Month-Old Infants 大家可以非常容易在google上找到这篇文章的全文。 文章指出一个一个很值得思考的心理学实验结果:一个很小的婴儿,只需要听上两分钟的连续语音,就能形成对以后听到的连续语音进行有效分词的能力。 这篇文章阐述的是在语言学习方面的结果,而事实上,在所有智能领域,我们都可以看到类似的观察。比如在Vision,人们都没有经过系统的可控的物体识别训练,但是却非常容易获得在复杂的世界上对对象进行迅速的分割,识别,以及获取其它方面信息的能力,而目前computer vision的能力在最简单的可控实验中依旧举步维艰。 人类只需要很少的训练的情况下能够迅速获得非常灵活有效的“模型”去应对充满变化和干扰的实际输入,而计算机学习算法通过在大量样本训练,也很难接近哪怕是婴儿的水平呢? 人类的学习机制和目前人工智能研究所采用的方式究竟有什么不同? 现在统计学习领域百花齐放,但是,大部分的方法,无论formulation有多大的数学上的差别,基本上都是让一个具有某种结构的model按照某种准则去"fit"训练数据,通常还加上某种复杂性的约束。不过,很难想像人类是使用类似的方法从现实中学习的。我们每天感受到的是一个不断变化,各种要素充分融合的世界,没有分离的“训练数据”去学。我们的大脑能够理解非常复杂的东西,但是我们所接触的“训练集”按照经典统计学系理论的观点是无法支持这种复杂性的。虽然,我们经常会犯被观察所误导的错误,但是,相比于机器学习算法,我们overfitting的机会和程度远小得多。 我相信,我们的学习过程远比目前所有的机器学习算法聪明得多,绝不仅仅是observed->fitting这样的统计形式。AI的主要领域的研究现在过分依赖于统计建模,可是统计有它固有的瓶颈。早在Vapnik他们建立统计学习基础的时代,已经明确告诉了大家,统计学习受到复杂性的根本制约。因此,统计学习本身并没有足够能力到达人工智能的目标。相对于人类真正的智能来说,统计所能产生的智能只能认为是一种非常初级的形式。 从rule-based的专家系统到神经网络,再到统计学习,AI几十年内经历了几次大规模方法论更新的浪潮,但是是不是离真正的智能越来越近了呢?我们究竟是不是走在一个正确的方向上? February 18 有价值的paperCVPR 2008的审稿期刚刚结束了。今年,我对于所审的paper,采取了更加宽容的态度。 Vision依旧很热闹,但是,我感觉这个领域在喧嚣的背后似乎有点疲态了。年复一年,每年成百上千的paper仍旧是在那几个旧的舞台上唱着老调子。比如object recognition,无数打着"novel framework"旗号的车子,仍旧挤在local feature extractor + classifier (SVM/AdaBoost ...)的独木桥上,难道,这是唯一的方法么? 在没有看到有人开辟新的道路的时候,我更欣赏那些专注解决于一个具体的小问题,并且提出了有见地的方法的文章。对于那种表面华美的,而内里却仅仅是把A feature换成B feature,C model换成D model的,我一般评价很低。 这里的一位教授在谈到写paper的时候,提到了一种很多人都会犯的毛病。还是用object recognition的工作为例子,为了完成实验,你必须做大量的工作,把整个framework搭建起来,从data到feature到classifier,要写很多很多的code,花很多很多的时间去debug。为了对得起这些付出,很多人想把这些努力都写到paper上去,因此形成了很多并不新颖的工作每年都在投。而事实上,这些工作并不完全是没有新的东西,但是,那一点新的东西,在整个framework式的表述中被喧宾夺主了。 要写一篇有吸引力的文章,必须有取舍的决断。有些为了完成实验必须做的工作,你即使在上面付出了半年时间,但是如果缺乏真正的学术价值,在paper中应该尽量简省,把大部分的篇幅着力于那些真正的有意义的地方(哪怕那个地方其实你只花了3个小时想出来)。评paper不是评劳模(当然有些reviewer可能有这种倾向),不能把工作量的因素拿来布局paper的篇幅,不能把对某些工作“舍不得”的情绪带到paper的presentation当中。 CVPR审稿落幕了,我们的reading group又开始了。这个学期,John决定让大家自己轮流选paper,lead每个星期的reading。他说,除非有充分的理由,不要选近五年的文章。他上学期其实就是这样的风格,选的很多都是五六十年代的文章——信息论和统计学习的奠基者们那种seminal的经典著述。这些paper让我感慨前辈们的工作是多么有生命力,今天无数的主流算法仍旧发源于40年前的某篇文章,而且事实上没有走远多少。科技日新月异,其核心学理的进化则缓慢得多,艰难得多。 在paper里面通过比较几个近期工作来claim自己的东西是新的很容易,但是,要让一个工作放在这个学科的整个发展历史中去考量却依然有价值,则是非常艰难。这个学期,我开始要参加Alan的meeting, 他是MIT另外一个大实验室LIDS的director。有一次和Alan meeting的时候,大家提到一些最新发表的算法,他说,这些东西has been done 40 years ago。他人很nice,但是一项工作要得到他的认同很难。那次,我在他面前present了40分钟我的新工作,很多的东西都被他认为是在数学领域已经解决的(虽然vision里面没有出现这样的publication),不过庆幸的是,还是有一个point,被他指出I have never seen people working on this。后来两个星期,我在这个point上投入了很多时间去思考,发现这确实是一个很有价值的问题。 我在这里所接触的教授都很nice,平常对学生的工作也不干涉太多,但是对于一项工作的评价非常挑剔。John告诉我,要解决最困难的问题,容易解决的问题让别人做去。这半年来,脱离了CVPR的指挥棒,在沿着自己的道路一点一点的缓慢前进着,但是走的很踏实。刚来的时候,对MIT的氛围有点不太习惯,好像CVPR也好,NIPS也好,都没什么要紧的。现在才慢慢觉得,只有从conference的指挥棒中走出来,才能脱离浮躁,实实在在的进行有意义的探索。 两个星期后,将轮到我挑选reading group上讨论的paper。这么长时间大家都讨论的是信息论和统计方面的文章,我说,我要变一下,找vision的paper,John答应了,不过条件是paper必须是经得住考验的真正的好paper。我现在不知道哪篇能达到这个要求。 February 12 统计模型 or not开学第一周,下岗了很长时间的闹钟又开始工作了。在上课和作业中,生活又恢复了忙碌。 这个学期选的一门Natural Language Processing,上课的风格还是让我觉得颇有创意。这门课每隔两周都要学生完成一篇类似GRE Issue这样的作文,就某个看上去有点深度的问题进行辩论。 在第一堂课,就布置了这样的讨论题:
其实原题给出的是两个虚拟的Google员工的辩论,要求对其发表评论,上面这句话只是一个简要的归纳。题目中有一个很有意思的类比:
事实上,离开自然语言这样一个context,更广义上说,这里做的是让经验模型PK核心定律。 这里继续引申,可以到达一个听起来有点离经叛道的思考,前辈们在过去几百年间通过艰辛的努力和积累,建立起了以物理定律为基础的科学,
我不是“统计万能”的支持者,但是,我相信,对这些问题的思考,有助于于理解统计方法的本质能力——它究竟能做什么,不能做什么。在过去的十几年里,统计学习在AI的众多领域里占据了主导地位。AI在继专家系统和神经网络之后,迎来了“统计时代”。但是,统计是不是就是建立真正意义的人工智能的钥匙呢?在享受统计方法给我们带来的一切好处的同时,也许,我们也许还需要一种批判的眼光去审视当今科学研究中的统计潮流。 February 10 再访纽约上一次去纽约,已经是一年半前的事情了——参加2006年的CVPR。 昨天,我再次来到了纽约——因为要给Dylan当搬运工,同时也看看远道而来的小呆了,呵呵。 纽约是在很多人心中国际大都会的象征。但是,无论从哪个角度说,它都不属于那种人见人爱的城市。不同于东方的几个明星城市像香港和新加坡,纽约给我的第一印象就是既破又脏。 作为游客,我在纽约的主要交通工具是地铁——这里的地铁是世界上最古老的地铁之一,不过,也是我见过的最破烂的地铁。黑森森的地铁站里面站着,目无表情的人,从楼梯,站台,乃至铁轨上面到处都是垃圾和烟头——散发着令人不太愉悦的味道。很多地铁站内没有线路牌,地铁里面很多时候也是不报站的。不过,只要留心观察,要是有足够的素材让你判断火车到了哪个站了——虽然不是特别清晰显眼。 曼哈顿的主要区域都可以用“坐标”定位,主要的街和大道排成规则的纵横网格,都是用数字编号,使得在这个大城市里面找地方变得非常方便。曼哈顿岛上有大片的鳞次栉比的高楼群(从总数上超过香港的中环很多)。在美国的很多城市(包括Boston, San Diego乃至Houston)晚上都是颇为安静的,街上的商店很早就关门了。而纽约和这个国家的其它城市不同,到了晚上12点,主要的街道上依旧车水马龙,热闹非凡——就像香港的弥敦道。 三教九流的人共融在这个城市里。在这里,你经常可以看到豪华的加长林肯招摇过市,也可以看到在街边的衣衫褴褛的乞丐。在高耸入云的摩天大厦的下面就是遍地烟头的街道和破败不堪的地铁站。 纽约,不是一个花园城市,但却是一个充满魅力的城市——它的魅力源于它海纳百川的胸襟——藏龙卧虎和又藏污纳垢——鲜明的反差渗透在这个城市的每一个角落,构成了纽约最独特的性格。 February 06 开学了新学期开始啦——寒假后,又要开始面对繁忙的课程了。 开学第一天,就和mentor meeting了——他非常满意,算是给这个学期开了个好头。这个学期的任务还是很重的,选了两门课 Computer Networks:选这门课,是因为系里要求学生在qualify前选择的课程必须横跨三个领域,在System领域,我们大家合计选这门了——因为考试的比重比较少。不过,这门课是research-oriented的,课程project要求很高。
看来有得忙活了。如果上三个月课作出来的project就能发到mobicom/sigcomm,我估计得考虑转行做网络了,哈哈。历史上是有这号牛人的,敬仰一把。 还有一门Natural Language and Computer Representation of Knowledges。这门本不是我要选的,只因为Computer Vision课被Freeman取消了,起码今年没有。不得不在AI领域另选一门。不过看了一些syllabus,内容还是很interesting的。 开拓视野,博纳众长,说不定对自己的research还有所启发。 最后,祝愿大家新春快乐! February 03 Is computer vision as good as thought?随手翻开这期TechTalk, 在头版的大标题computer vision的字样赫然入目。第一次在TechTalk看到自己领域的文章,自然很感兴趣。 先介绍一下,TechTalk是MIT内部一份免费派发的报纸,每周一期,主要报道学校的各种科学研究的进展。一直以来,占据这份报纸头版的主要是生命科学,能源科学,或者新材料。 这篇文章的标题是 Computer vision may not be as good as thought 文章的作者来自 McGovern Institute of Brain Research @ MIT。 文章主要是针对近期在Object recognition所取得的“进展”而发的。它开篇就旗帜鲜明地提出:
在MIT McGovern Institute和Harvard Rowland Institute的一项联合研究中,他们认为,被广泛用于评价object recognition性能的Caltech 101 database并不能有效反映出算法在真实条件下的能力。文章指出,object recognition的核心困难源于一个物体在形成图像过程中,由于方向,位置,光照,外界环境等等的要素影响而发生的各种变化。而以Caltech 101为代表的主流测试库,在获取过程中实际上是隐含了有利于计算机辨别的因素,而不能真实反映客观世界的复杂变化,并且掩盖了实际问题的复杂性。
在他们的实验中,他们做了一个非常naive的算法作为baseline,该算法仅仅用到了一些非常初级的信息,而且没有进行特别处理和分析。他们原以为这个算法会fail,但是他们惊奇地发现,这个naive算法在Caltech 101上表现出色(surprisingly well),其性能甚至超过了5个最新提出的state-of-the-art的算法。 从这样的实验结果中,他们对主流的算法评价体系提出了质疑
为了验证他们的想法,他们设计了这样的实验,只使用飞机和车两类物体,但是,尽可能引入各种真实变化的条件。他们发现,那些在Caltech 101上面分多类分得很好的算法,在这里分两类都分得一蹋糊涂。这个团对得到这样的结论:
他们提出,computer vision的研究人员应该抛弃现有的不科学的评价体系。 作为脑科学系的研究人员,他们研究object recognition的方法,主要是探索our brain's own solution,并且尽可能地去模仿它。他们认为,这是一个正确的方向。 January 27 关于平均值小时候,老师就告诉我们,读书讲究先由薄而厚,再由厚而薄。前者是吸收和积累,后者是融会和消化。 这些年,读了不少关于统计学习的东西,很多东西都记不清楚了。从我自己的角度看来(可能是很肤浅的),学概率和统计,关键是记住三个概念:测度(measure),期望(expectation),和独立性(independence)。 测度是现代概率理论的基石。在经典的概率论里面——比如我们在本科学的那些——大多是通过举例子和文字说明的方式告诉你概率是什么,这容易明白,不过缺乏严密的公理化根基。现代概率论整个建立在测度理论的基础上,概率的定义非常简单,不过也很抽象——所谓“概率”,就是归一化的测度。没有测度,就没有整个概率论的大厦,所以它很重要——不过,它在实用中直接用上的机会不大,所以不是这篇文章的主体。关于独立性,以及它的一个孪生的名词:Markov,也扮演着非常重要的角色,它是Graphical models的基础。有兴趣的可以去读M. I. Jordan的书。 而在统计学习的实际应用中,就是你平时写code,用得最多的就是期望,或者一个通俗点的版本——平均值。其实这两者不太一样,期望是从model出发演绎的,平均值通常是指从data出发归纳的。不过它们的关系确实非常密切。 统计学习在很多情况下,就是求平均值 我们平常说去Learn一个model——其实,在很多情况下,这就是干一件听上去很简单的事情,求平均值。我们知道,我们所接触的大部分重要的概率分布,都属于exponential family,比如Gauss, Binomial, Multinomial, Dirichlet, Poisson, Exponential, Gamma等等分布都属于这个家族。它的一个重要特点就是——得期望者得天下。就是说,知道了某些统计量的期望,就知道了整个model,至于model的参数,或者就是期望本身(比如Gauss),或者不难从期望中得到。可以证明,对于这些model,对它们的最大似然估计(Maximum Likelihood estimation),就是从data中算出某些统计量的平均值作为model的期望。 在Bayes学习中,我们还考虑先验分布(prior)。在这里,model的估计还是求平均值。所谓prior是怎么来的?就是以前曾经观察过的data那里总结得到的,然后以prior的形式影响当前的model估计。一般而言,使用exponential family,我们通常会使用conjugate prior,这种prior,基本就是沿着刚才说的,假想我们已经看过一些data的思路得到的,它的形式和data mean几乎如出一辙。而带了prior的估计,还是在求平均值,不过这里的平均值就是(假想)以前观察过的数据和当前的数据合在一起求平均。 对于更加复杂的Graphical model,每个节点的estimate和update,很多时候,其实是做了这样的事情——把其它节点传来的平均值和这个节点接触的数据的平均值混合进行新的平均。从最简单的Gauss, 到更加复杂的Gaussian Mixture Model, Latent Dirichlet Allocation, Markov Random Field, Generalized Kalman Filtering概莫能外——大家可以仔细看看它们的每一个update公式,看看哪个不是在求平均值。 怎样求平均值 平均值是很重要的。不过怎么求呢?这似乎是小学初中就解决了的问题。不过,求平均值的世界其实是如此博大精深。如果说它是少林武学,我现在这点水平,也就够在嵩山下扫扫地罢了。很多在世界上赫赫有名的数学家,穷毕生心血,方能一窥堂奥。 虽然,只有扫地的水平,不过起码也看过大师们练武。这门学问主要有两个方面:得到data求平均值,得到model求期望。 先说说求data的平均值。这太简单了,有什么好说的。不就是加法和乘法么,小学学过算术的人都会算,即使没学过,拿个计算器也照样算。在通常的实数空间内,确实很简单;不过对于一般的求平均值的情况,就非常非常困难了。一般来说,求平均值有两个流派,一种是基于线性代数(linear algebra),另外一种是基于度量空间(metric space)。前面一种大家很熟悉:
这是我们读了这么多年书最常见的平均值。不过,这样定义太局限了,它要求这些东西能做加法和数乘——我不得不说,这个要求实在太高,只有线性空间(这种空间是数学里面的贵族,它们什么好处都全了)能够满足——对于数学领域更广大的人民群众(各种更一般的数学结构,比如群,拓扑流形),加法和数乘简直是一种奢侈得不切实际的活动。 其实平均值是一个非常广泛的概念,不仅仅存在于线性空间中,还为广大人民群众服务。对于某个度量空间,它的一般性定义是这么给出的
也就是说,求平均值是一个优化问题。关于这个问题,在不同的空间中有不同的答案:在最高级的希尔伯特空间中(定义了内积的完备线性空间),m就是上面给出的基于线性代数的形式。所以说,基于线性代数的定义仅仅是基于度量空间的定义的一个特例。不过由于这个特例被广泛使用,所以大家一说平均值就想起它,而不是一般形式。在推广一些的巴拿赫空间中(定义了范数的完备线性空间),上述的问题是一个凸优化问题,因为范数必然是凸函数。它具有唯一的最优解。 最困难的是在非线性空间中。一个典型的例子是黎曼流形(注意,这里我们只讨论黎曼流形,对于更为一般的拓扑流形或者微分流形,因为不具有度量结构,所以不能定义均值。)在黎曼流形上,两点间的距离是通过测地距离给出的。在黎曼流形上,通过测地距离定义的平均值,叫做黎曼中心。一部分朋友对于这几个术语可能不太熟悉,还是举个形象点的例子。比如,在地球上给出几个地点,你要在地面上找一个“平均地点”,使得它到那几个地点的“地面距离”的平方和最小。如果,用传统的算术方法拿这些地点的三维坐标来算,你估计得在那钻个油井了。对于“球面平均”问题(专门一点的说法叫做特殊正交群SO(3)的黎曼中心,恩,这个名词我也有点晕),到了在本世纪,在数学里依旧可以发paper,目前还没有一般情况下的解析解。 别的领域我不懂,不过“球面平均”在vision里面价值是很大的,它是对三维旋转变换建立统计模型的基础——我们再一次看到了求平均值对于统计的重要意义。球面平均求的是“平均”的旋转,如果对于一般的仿射变换(Affiine transform),“平均”的变换又怎么求呢?这是个open problem,留待大家思考。 怎样求期望 说完从data求平均值,再说说从model得到期望(expectation)——这们学问就更博大了。虽然,期望的定义很简单——求和或者积分就行了。不过,它的实际计算,对于很多实际模型是intractable的。 概率论最早源于掷色子,我们的前辈数学家们为了破解求复杂模型求期望的问题,提出的方法就是掷色子。在学术上,美其名曰“蒙特卡罗方法”(Monte Carlo)。原理很简单,不断地掷色子来大量采样,然后从采来的样本求平均值来逼近模型的期望。 掷色子是世界上最有学问的之一,正因为如此,我们对于“赌神”,“赌王”之类的人物崇拜犹如滔滔江水,因为它们掷色子掷得好。无数的统计学家把毕生经历奉献给掷色子(采样)事业,并且做出伟大成就。关于采样的专著和文献,汗牛充栋。 掷色子就这么难么?是的。据估算,即使对于一个复杂度不高的model,要得到一个可以接受的估计,所需的样本量往往大得惊人,而且指数增长。如果不掌握要领,你即使掷到宇宙末日,估计离一个靠谱的估计还远着呢。采样技术名目繁多,最流行的莫过于重要性采样(importance sampling)和马尔科夫链蒙特卡罗过程(MCMC)。具体就不多说了。 | |||||||||||||||||||||||