深度神經網路是如何成為圖像大師的?
全文共3152字,預計學習時長6分鐘
深度學習為何如此有效仍是個謎。
在本文中,我們將嘗試用神經網路為我們繪製抽象的圖像,然後對這些圖像進行解釋,以便對神秘面紗下發生的事情有更好的理解。
看完這篇文章,你將學會生成一些圖像,如下所示。
(所有內容都少於100行PyTorch 代碼。隨附的Jupyter notebook:https://github.com/paraschopra/abstract-art-neural-network)
這幅圖像是如何生成的?
這張圖片是由一個簡單的架構—複合模式生成網路(CPPN)生成的。
(你可以通過http://blog.otoro.net/2015/06/19/neural-network-generative-art/這篇文章來了解。)
文章中,作者通過用JavaScript編寫的神經網路生成抽象圖像。而本文用PyTorch實現了它們。
通過神經網路生成圖像的一種方法是讓它們一次性輸出完整的圖像,比如說,下面的被稱為「生成器」的神經網路將隨機雜訊作為輸入,並在輸出層中生成整個圖像(以及寬度*高度)。
與輸出整個圖像不同,CPPN在給定位置(作為輸入)輸出像素的顏色。
忽略上面圖像中的z和r,注意網路正在獲取像素的x,y坐標,並輸出該像素應該是什麼顏色(用c表示)。這種網路的PyTorch模型如下所示:
class NN(nn.Module):
def __init__(self):
super(NN, self).__init__
self.layers = nn.Sequential(nn.Linear(2, 16, bias=True),
nn.Tanh,
nn.Linear(16, 16, bias=False),
nn.Tanh,
nn.Linear(16, 16, bias=False),
nn.Tanh,
nn.Linear(16, 16, bias=False),
nn.Tanh,
nn.Linear(16, 16, bias=False),
nn.Tanh,
nn.Linear(16, 16, bias=False),
nn.Tanh,
nn.Linear(16, 16, bias=False),
nn.Tanh,
nn.Linear(16, 16, bias=False),
nn.Tanh,
nn.Linear(16, 16, bias=False),
nn.Tanh,
nn.Linear(16, 3, bias=False),
nn.Sigmoid)
def forward(self, x):
return self.layers(x)
請注意,它接受2個輸入,並有3個輸出(像素的RGB值)。生成整個圖像的方法是輸入所需圖像(特定大小)的所有X、Y位置,並將這些X、Y位置的顏色設置為網路輸出的顏色。
神經網路實驗
也許,當你嘗試運行上面的神經網路時,你會生成下面的圖像:
也許你會充滿疑問:為什麼不管你提供的是什麼x,y位置,網路輸出的都是灰色?理想情況下,這不應該發生,因為這個網路如此的深。更改輸入值就應更改輸出值。
每次神經網路初始化時,由於參數(權重和偏差)的隨機初始化,它都有可能生成一個全新的圖像。但往往即使經過幾次嘗試,你從神經網路中得到的都是這種一片灰色。為什麼?
有人可能會說,是所用的特定激活函數-tanh 的問題。可能後續層中的多個tanh序列在輸出層(代表灰色)將所有輸入數字壓縮到接近0.5。然而,本文最開始推薦的那篇文章中也使用了tanh。我們所做的只是將博客中用JavaScript編寫的神經網路轉換成PyTorch而沒有做任何更改。
根源問題在哪裡?
當一個新的神經網路被初始化時,PyTorch是如何初始化權重的?根據用戶論壇,他們用從-1/sqrt(N)到 1/sqrt(N)隨機抽取的數字初始化權重。其中n是一個層中傳入連接的數量。因此,如果對於隱藏層N=16,權重將會被初始化為-1/4 到 1/4之間。所以,我們可以做如下猜測:假設產生一片灰色的原因是因為權重的範圍很小,而且變化不大。
如果網路中的所有權重都在-1/4到 1/4之間,當乘以任何輸入並加在一起時,可能會發生類似中心極限定理的效果。
中心極限定理(CLT)證明:在某些情況下,添加獨立隨機變數,即使原始變數本身不是正態分布,它們適當歸一化的和也趨向於正態分布(非正式地稱為「鐘形曲線」)。
回想如何計算後續層上的值。
在我們的例子中,第一個輸入層有2個值(x,y),第二個隱藏層有16個神經元。所以,第二層上的每個神經元得到2個值乘以權重,這些權重值在-1/4 到 1/4之間。這些值被求和,然後在它從激活函數tanh開始後,成為要傳遞到第三層的新值。
現在,從第二層開始,有16個輸入要傳遞到第三層的16個神經元中的每一個。假設這些值中的每一個都用z表示,那麼第三層中每個神經元的值是:
這是我們的另一個猜測。由於權重的方差較小(-1/4到 1/4),z的值(即輸入x,y乘以權重,然後通過tanh函數)也不會變化太多(因此會相似)。所以這個方程可以看作:
對於每個神經元,從-0.25到 0.25的16個權重之和的最可能值是零。即使在第一層,和不接近零,網路的八層給了上述方程足夠的機會使最終產生接近零的值。因此,不管輸入值(x,y)如何,進入激活函數的總值(權重乘以輸入的綜合)總是接近零值,tanh映射為零(因此,所有後續層中的值保持為零)。
x軸是tanh的輸入,y軸是輸出。請注意,0映射到0。
灰色的原因是什麼?這是因為s形函數(最後一層的激活功能)將這個輸入值取零,並映射到0.5(表示灰色,0表示黑色,1表示白色)。
注意s形函數如何將輸入值0映射到0.5。
如何修復一片灰色?
由於根源是權重的微小變化,我們下一步要做的就是增加它。更改默認的初始化函數,將權重從-100分配到 100(而不是-1/4到 1/4)。現在運行神經網路,我們可以得到:
哇!一片灰色現在是一些顏色的斑點。
現在有了一些進展。我們的假設是正確的。但是生成的圖像仍然沒有太多的結構。這太簡單了。
這個神經網路在表面下所做的就是將輸入與權重相乘,推動它們通過tanh,最後通過s形函數輸出顏色。既然我們固定了權重,那麼可以修改輸入以使輸出圖像更有趣嗎?當然。
請注意,上面的圖像是在輸入x,y作為原始像素坐標時生成的,這些坐標從0,0開始到128,128結束(這是圖像的大小)。這意味著我們的網路從來沒有一個負數作為輸入,而且由於這些數字很大(比如x,y可以是100,100),tanh函數要麼得到一個很大的數字(它被壓縮到 1),要麼得到一個很小的數字(它被壓扁到-1)。這就是我們看到原色的簡單組合的原因(例如,0,1,1的R,G,B輸出代表你在上圖中看到的青色)。
如何使圖像變得有趣?
就像在文章最開始提到的那篇文章中一樣,我們將x和y標準化。因此,我們不輸入x,而是輸入(x/image_size)-0.5。這意味著x和y的值範圍為-0.5到 0.5(不考慮圖像大小)。這樣就得到了以下圖像:
還是有一些進展的!
有趣的是,在前一幅圖像中,線條一直向右下角增長(因為x,y值在增加)。這裡,因為x,y值是標準化的並且現在包含負數,所以這些線向外均勻地增長。
然而,圖像仍然不夠漂亮。
如何使圖像更有趣一些?
如果你仔細觀察,你會發現在圖像的中間,似乎有比邊緣更多的結構。這是數學之神給我們的暗示,我們應該放大那裡去尋找美。
有三种放大圖像中心的方法:
· 生成一幅大圖像。由於像素坐標是標準化的,我們可以簡單地運行神經網路來生成更大的圖像。然後,我們可以通過圖像編輯工具放大中間部分,看看我們發現了什麼。
· 將x和y輸入乘以少量(縮放因子),這將有效地實現與前一種方法相同的結果(並避免我們在其他無趣區域進行浪費的計算)。
· 由於輸出是由輸入乘以權重決定的,因此我們也可以通過將權重值從-100、 100減少到 3、-3等其他值來進行縮放而不是減少輸入值(同時記住不要過度減少。還記得如果權重在-0.25到 0.25範圍內就會出現一片灰色嗎?)。
當我們採用第二種方法將x和y乘以0.01時,得到了:
當採用第三種方法並將權重初始化為介於-3和 3之間時,這是我們得到的圖像:
你的思維打開了嗎?
更多的實驗
將權重初始化更改為正態分布(平均值為0,標準差為1),並生成多個圖像(下圖是從隨機初始化開始的)。
當移除所有隱藏層(僅輸入到輸出映射)時:
0個隱藏層
當僅保留一個隱藏層(而不是默認的8個隱藏層)時:
1個隱藏層
當把隱藏層的數量加倍到16層時:
16個隱藏層,每層有16個神經元
正如你所能想像的,隨著增加隱藏層的數量,圖像變得越來越複雜。如果不是將層加倍,而是將層的數量保持不變(8),但是將每層神經元的數量加倍(從16到32),會發生什麼?我們得到的是:
8個隱藏層,每層32個神經元
請注意,儘管在上述兩種情況下,網路中的權重總數是相似的,但具有兩個層的網路比每層雙倍神經元的網路更像素化。像素表示,在這些區域中,函數變化劇烈,因此如果我們進一步縮放,會發現更多的結構。而對於層數不變但每層神經元數量加倍的網路,其功能相當平滑,因此「可縮放性」較小。
當然,所有這些都是深度使神經網路更具表現力的另一種說法。
計算函數的複雜度隨深度呈指數增長。
這正是我們所看到的。一般的逼近定理認為,理論上,一個足夠大的神經網路,即使有一個隱藏層,也可以表示任何函數。但在實踐中,網路越深,輸入到輸出映射就越複雜。
毫無意義但很有趣的實驗
如果我們把每層神經元的數量從8個增加到128個(數量級的增加)。
神經-波洛克!
如果我們從每一個隱藏層128個神經元開始,然後像下面這樣逐漸地在後續層將它們減半。
self.layers = nn.Sequential(nn.Linear(2, hidden_n, bias=True),
nn.Tanh,
nn.Linear(128, 64, bias=False),
nn.Tanh,
nn.Linear(64, 32, bias=False),
nn.Tanh,
nn.Linear(32, 16, bias=False),
nn.Tanh,
nn.Linear(16, 8, bias=False),
nn.Tanh,
nn.Linear(8, 4, bias=False),
nn.Tanh,
nn.Linear(4, 3, bias=False),
nn.Sigmoid)
我們得到的是:
這個看起來比其他的更「自然」。
有很多實驗可以做並且得到有趣的圖像,你可以嘗試更多的架構、激活和層次。
※威斯康星大學麥迪遜分校:情感分類中領域自適應詞嵌入方法的研究
※IT圈「最會掙錢」的女人這樣煉成,看你離成功還有多遠
TAG:讀芯術 |