流形學習 manifold learning--自學小結(2)之 Isomap
http://isomap.stanford.edu/ 應有盡有
另外,中文blog:
http://www.cvchina.info/2010/05/31/manifold-learning/#more-1038
Isomap 論文裡的一個結果:
這裡的圖片來自同一張人臉(好吧,其實是人臉模型),每張圖片是 64×64 的灰度圖,如果把點陣圖按照列(或行)拼起來,就可以得到一個 4096 維的向量,這樣一來,每一張圖片就可以看成是 4096 維歐氏空間中的一個點。很顯然,並不是 4096 維空間中任意一個點都可以對應於一張人臉圖片的,這就類似於球面的情形,我們可以假定所有可以是人臉的 4096 維向量實際上分佈在一個 d 維 (d < 4096) 的子空間中。而特定到
實際上,上面的那張圖就是 Isomap 將這個資料集從 4096維對映到 3 維空間中,並顯示了其中 2 維的結果,圖中的小點就是每個人臉在這個二維空間中對應的座標位置,其中一些標紅圈的點被選出來,並在旁邊畫上了該點對應的原始圖片,可以很直觀地看出這兩個維度正好對應了 pose 的兩個自由度平滑變化的結果。
就我目前所知,把流形引入到機器學習領域來主要有兩種用途:一是將原來在歐氏空間中適用的演算法加以改造,使得它工作在流形上,直接或間接地對流形的結構和性質加以利用;二是直接分析流形的結構,並試圖將其對映到一個歐氏空間中,再在得到的結果上運用以前適用於歐氏空間的演算法來進行學習。
這裡 Isomap 正巧是一個非常典型的例子,因為它實際上是通過“改造一種原本適用於歐氏空間的演算法”,達到了“將流形對映到一個歐氏空間”的目的。
Isomap 所改造的這個方法叫做 Multidimensional Scaling (MDS) ,MDS 是一種降維方法,它的目的就是使得降維之後的點兩兩之間的距離儘量不變(也就是和在原是空間中對應的兩個點之間的距離要差不多)。只是 MDS 是針對歐氏空間設計的,對於距離的計算也是使用歐氏距離來完成的。如果資料分佈在一個流形上的話,歐氏距離就不適用了。
讓我們再回到地球——這個在三維空間中的二維流形,假設我們要在三維空間中計算北極點和南極點的距離,這很容易,就是兩點相連的線段的長度,可是,如果要在這個流形上算距離就不能這樣子算了,我們總不能從北極打個洞鑽到南極去吧?要沿著地球表面走才行,當然,如果我隨便沿著什麼路線走一遍,然後數出總共走了多少步作為距離,這是不成的,因為這樣一來如果我沿著不同的路線走,豈不是會得到不同的距離值?總而言之,我們現在需要一個新的定義在地球表面(流形)上的距離度量,理論上來說,任意滿足測度的 4 個條件的函式都可以被定義為距離,不過,為了和歐氏空間對應起來,這裡選擇一個直線距離的推廣定義。
還記得初中學的“兩點之間,線段最短”嗎?現在,我們反過來說,把線段的概念推廣一下,變成“兩點之間最短的曲線是線段”,於是流形上的距離定義也就等同於歐氏空間了:流形上兩個點之間的距離就是連線兩個點的“線段”的長度。雖然只是置換了一個概念,但是現在兩者統一起來了,不過,在流形上的線段大概就不一定是“直”的了(於是直線也變成不一定是“直”的了),通常又稱作是“測地線”。對於球面這個簡單的流形來說,任意一條線段必定是在一個“大圓”上的,於是球面上的直線其實都是一些大圓,也造成了球面這個流形上沒有平行線等一系列尷尬的局面(任意兩條直線均相交),如果你看過一些數學科普八卦類的書,應該會回憶起不少東西啦!
回到 Isomap ,它主要做了一件事情,就是把 MDS 中原始空間中距離的計算從歐氏距離換為了流形上的測地距離。當然,如果流形的結構事先不知道的話,這個距離是沒法算的,於是 Isomap 通過講資料點連線起來構成一個鄰接 Graph 來離散地近似原來的流形,而測地距離也相應地通過 Graph 上的最短路徑來近似了。如下圖所示:
這個東西叫做 Swiss Roll ,姑且把它看作一塊捲起來的布好了。圖中兩個標黑圈的點,如果通過外圍歐氏空間中的歐氏距離來計算的話,會是捱得很近的點,可是在流形上它們實際上是距離很遠的點:紅色的線是 Isomap 求出來的流形上的距離。可以想像,如果是原始的 MDS 的話,降維之後肯定會是很暴力地直接把它投影到二維空間中,完全無視流形結構,而 Isomap 則可以成功地將流形“展開”之後再做投影。
實驗:
ISOMAP人臉識別
兩種經典的非線性降維(Nonlinear Dimensionality Reduction)方法:lle和isomap。問題是別人做過的,演算法實現也基本都是現成的,我只是拿來"玩一玩"。實驗有很多環節,最有趣的一個環節,是給你698張人臉的影象(64×64灰度),通過isomap降維方法將每張臉當做一個點映到二維平面上,使得橫座標恰好反映人臉左右看的程度,縱座標反映人臉上下看的程度。
如果你也對這個實驗感興趣,就往下讀吧,很簡單的~
實驗環境:Matlab6.5
實驗步驟
步驟一:準備資料集和工具包
下載
並解壓縮
下載
的所有程式碼
步驟二:
準備圖片標記的人臉序號集:一共有698張人臉,都畫在平面上太擁擠了,所以選了30個人臉(存入posesSelect.mat的ks向量),選取的準則是:30個人臉的姿態儘量不同,也就是希望畫在平面上儘量分散。事實上,face_data.mat資料集中,poses是一個2行698列的矩陣,第j列就是第j張人臉的客觀姿態。
繪製客觀姿態分佈圖:
load face_data
load posesSelect
showFacesOnR2(images,poses,ks)
http://lh6.ggpht.com/_iMG9M3S-9Xo/SWXkfHPcWNI/AAAAAAAACBs/otRKwIQ6DMc/s800/image002.gif
步驟三:降維
用Isomap演算法將4096維的人臉資料images降維到2維,並繪製在平面上
load face_data
load posesSelect
D=L2_distance(images,images,1);
options.dims = [2];
[Y, R, E] = IsomapII(D, 'k', 7, options);
showFacesOnR2(images,Y.coords{1},ks);
http://lh4.ggpht.com/_iMG9M3S-9Xo/SWXkfu3IIOI/AAAAAAAACB0/nbFaLN3X1HM/s800/image004.gif
D是一個距離矩陣,i行j列值表示人臉i和人臉j的距離,這裡把一個人臉影象資料當做一個向量,使用2範數定義距離。
IsomapII是高效能演算法,先把D用k=7近鄰打成稀疏矩陣,然後用基於斐波那契堆的Dijkstra演算法計算最短路,Dijkstra演算法用C實現使用並且編譯成了.dll檔案為了提高效率。計算結果對我們有用的是Y.coords{1},它儲存了降維後的結果,是2行698列的矩陣。
觀察計算結果發現,以中間那個正的人臉為中心,他左邊的都在向左看,而且越是靠左的轉動越明顯。同理,他右面的都在向右看、上面的都在向下看、下面的在向上看。與客觀姿態分佈基本吻合。
實驗細節:
showFacesOnR2.m
%把頭像和姿態座標畫在平面上
function showFacesOnR2(images,poses,ks);
%normalize into 1:1
poses(1,:)=poses(1,:)/range(poses(1,:));
poses(2,:)=poses(2,:)/range(poses(2,:));
%draw all points
scatter(poses(1,:),poses(2,:),12,'o','filled');
xlabel('left-right pose');
ylabel('up-down pose');
hold on
%draw selected points
scatter(poses(1,ks),poses(2,ks),24,'ro');
hold on
%draw images on selected points
scale = 0.001;
x=zeros(64,64);
for p=1:size(ks,2)
k=ks(p);
for i=1:64
x(:,i)=images((i-1)*64+1:i*64,k);
end
xc=poses(1,k);
yc=poses(2,k);
imshow(xc:scale:xc+64*scale,yc:-scale:yc-64*scale,x);
hold on
end
return
轉自:http://hi.baidu.com/bess_tang/item/f3f0d216cde2520d8fbde438