[AI開發]零數學公式告訴你什麼是(卷積)神經網絡

大部分介紹神經網絡的文章中概念性的東西太多,並且夾雜着不少數學公式,讀起來讓人頭疼,尤爲沒什麼基礎的人徹底get不到做者想要表達的思想。本篇文章嘗試零公式(但有少許數學知識)說清楚什麼是神經網絡,而且舉例來講明神經網絡能幹什麼。另一些文章喜歡舉「根據歷史交易數據預測房子價值」或者「根據歷史數據來預測將來幾天是否下雨」的例子來引入「機器學習/深度學習/神經網絡/監督學習」的主題,並介紹他們的做用,這種例子的樣本(輸入X輸出Y)都是數值,數字到數字的映射,簡單易懂,可是現實應用中還有不少場景並不是如此,好比本文後面舉的「圖像分類」例子,輸入是圖片並非簡單的數值輸入。html

卷積神經網絡的輸出網絡

 

分類和迴歸機器學習

咱們平時討論的機器學習/深度學習/神經網絡大部分時候說的是「監督學習」範疇,監督學習應用最爲普遍,也是神經網絡發揮巨大做用的領域,所以,本文全部內容都是基於監督學習。從帶有標籤的樣本數據中學習「經驗」,最後將經驗做用於樣本以外的數據,獲得預測結果,這就是監督學習。監督學習主要解決兩大類問題:函數

分類工具

分類很好理解,就是根據輸入特徵,預測與之對應的分類,輸出是離散數值,好比明天是否下雨(下雨/不下雨)、短信是不是垃圾短信(是/否)、圖片中包含的動物是貓、狗仍是猴子(貓/狗/猴子)等等。分類模型的輸出通常是N維向量(N爲分類數),每一個向量值表明屬於此分類的機率。學習

圖1  分類任務ui

如上圖,根據樣本數據(黃色圓形、藍色正方形、綠色棱形),監督學習能夠肯定兩條邊界線,對於任何樣本以外的數據(圖中灰色正方形),能夠預測它所屬分類爲B,對應的預測輸出能夠是[0.04, 0.90, 0.06],表明屬於A類的機率爲0.04,屬於B類的機率爲0.90,屬於C類的機率爲0.06,屬於B類的機率最大,所以咱們能夠認爲它的分類爲B。spa

請注意圖中用來劃分類型區域的兩條虛線,同類樣本並無徹底按照虛線分割開來,有黃色的圓形被劃分到B類中,也有藍色的正方形被劃分到A類中。這種狀況之因此出現,是由於監督學習獲得的經驗應該具有必定程度的泛化能力,因此容許學習過程當中出現必定的偏差,這樣的學習纔是有效的。3d

迴歸htm

與分類相反,迴歸主要解決一些輸出爲具體數值的問題,好比明天的氣溫(20、2一、30等)、明天股票開盤價(100、10二、200等)。迴歸模型的輸出通常是具體數值(包含向量,向量中包含每一個具體的數值)。

圖2  迴歸任務

如上圖,根據樣本數據(圖中藍色正方形,平面座標系點),監督學習能夠肯定一條直線y=1.5x+1,對於任何樣本以外的輸入(Xn),能夠預測對應的輸出Y爲1.5*Xn+1。

請注意經過監督學習獲得的直線y=1.5*x+1,事實上並非每一個樣本都恰好落在該條直線上,大部分分佈在直線周圍。緣由跟上面提到的同樣,監督學習過程容許出現必定的偏差,這樣纔是有效的學習。

學習的過程

無論是分類仍是迴歸問題,監督學習都是從樣本數據中學習經驗,而後將經驗應用到樣本以外的數據。那麼這個經驗具體指什麼?學習的本質是什麼呢?

以上面迴歸問題爲例,咱們獲得直線y=1.5*x+1的過程以下:

(1)肯定樣本數據呈直線分佈(近似直線分佈);

(2)設定一個目標函數:y=w*x+b;

(3)調整w和b的值,使樣本數據點儘量近地分佈在直線周圍(可使用最小二乘法);

(4)獲得最優的w和b的值。

以上是4步完成學習的過程,這個也是最簡單的監督學習過程。至於其中「如何肯定樣本呈直線分佈」、「如何判斷目標函數爲y=w*x+b」以及「如何去調整w和b的值,可使樣本數據點儘量近的分佈在直線周圍」這些問題,後面一一介紹。

咱們常常聽到的深度學習中模型訓練,其實指的就是學習的過程,最後輸出的模型中主要包含的就是w和b的值,換句話說,訓練的過程,主要是肯定w和b的值,能夠稱這些參數爲「經驗」。

監督學習的過程就是找出X->Y的映射關係,這裏的輸入X能夠稱之爲「特徵」,特徵能夠是多維的,實際上X大多數狀況都是多維向量,相似[1, 1.002, 0.2, ...],輸出Y稱爲「預測值」,預測值也能夠是多維的,相似[0.90, 0.08, 0.02],好比前面提到的分類問題中,輸出Y爲多維向量,每一個向量值表明預測對應分類的機率大小。

 

全鏈接神經網絡

全鏈接神經網絡由許許多多的「神經元」鏈接而成,每一個神經元能夠接收多個輸入,產生一個輸出,相似前面提到的X->Y的映射,若是輸入是多維的,格式就是[x1, x2, ..., xn]->Y(對於單個神經元來說,輸出都是一個數值)。多個神經元相互鏈接起來,就造成了神經網絡,神經元的輸入能夠是來自其餘多個神經元的輸出,該神經元的輸出又能夠做爲其餘神經元的輸入(的一部分)。下圖爲一個神經元的結構:

圖3 神經元結構

如上圖所示,一個神經元接收[x1, x2, ..., xn]做爲輸入,對於每一個輸入Xi,都會乘以一個權重Wi,將乘積結果相加再通過函數f做用後,產生輸出Y。多個神經元相互鏈接以後,獲得神經網絡:

圖4  全鏈接神經網絡

如上圖,多個神經元相互鏈接起來組成全鏈接神經網絡(圖中只包含w參數,省略了b),圖中神經網絡一共包含3層(Layer1,Layer2和Layer3),上一層每一個神經元的輸出所有做爲後一層每一個神經元的輸入,這種網絡叫「全鏈接神經網絡」(顧名思義,全鏈接的意思)。圖中黃色部分就是兩個完整的神經元結構,第一個神經元有三個輸入(x1,x2和x3),分別乘以對應的權重w31,w32和w33,第二個神經元有四個輸入(分別來自於Layer1層中的4個輸出)。該神經網絡能夠接受一個3維向量做爲輸入(格式爲[x1, x2, x3]),從左往右計算,最後輸出一個2維向量(格式爲[y1, y2])。對應它學習到的經驗,能夠用來處理符合以下映射關係的「分類」或者「迴歸」問題:

圖5 神經網絡的映射關係

全鏈接神經網絡是結構最簡單的神經網絡,相鄰兩層之間的神經元每一個之間都有鏈接,由於結構最簡單,所以一般以它做爲入口來介紹其餘結構更復雜的網絡。注意,大部分神經網絡並非每一個神經元都有鏈接關係,並且有些並非嚴格聽從「數據從左往右移動」這種順序。

神經網絡中的矩陣計算

對於單個神經元的計算過程而言,是很是簡單的,分三步:

(1)計算每一個輸入參數Xi和對應權重Wi的乘積;

(2)將乘積加起來,再加上一個偏移值b;

(3)最後將函數f做用在(2)中的結果上,獲得神經元的輸出。

可是對於神經網絡這種包含大量的神經元而言,如何能夠更加方便、代碼中更簡潔地去實現呢?答案是使用矩陣,線性代數搞忘記的同窗也沒關係,這裏僅僅是利用了「矩陣相乘」和「矩陣相加」的規則。

矩陣相加

矩陣相加要求兩個矩陣維度相同,矩陣中對應的數字直接相加便可,生成一個新的矩陣,維度跟以前同樣:

圖6 矩陣加法

矩陣相乘

矩陣相乘要求第一個矩陣包含的列數和第二個矩陣包含的行數相同,M*N的矩陣乘以N*T的矩陣,獲得M*T的一個新矩陣:

圖7 矩陣乘法

第一個矩陣A的第一行每一個元素與第二個矩陣B的第一列各個元素相乘而後加起來,做爲結果矩陣C中的第一行第一列,第一個矩陣A的第一行每一個元素與第二個矩陣B的第二列各個元素相乘而後加起來,做爲結果矩陣C中的第一行第二列,以此類推。上圖中3*3的矩陣乘以3*2的矩陣,獲得一個3*2的新矩陣。若是將上圖7中A矩陣換成神經網絡中的參數W(W11,W12,W22...),將B矩陣換成輸入X特徵(X1, X2, X3...),那麼全鏈接神經網絡中每一層(能夠包含多個神經元)的計算過程能夠用矩陣表示成:

圖8 矩陣在神經網絡中的用法

如上圖,使用矩陣咱們能夠批量操做。對於圖4中第一層(Layer1)全部神經元的計算過程,能夠經過圖8一次性計算完成。圖中W矩陣先和X矩陣相乘,再加上偏移值B矩陣,獲得一箇中間結果(也是一個矩陣),而後再將中間結果傳給函數f,輸出另一個新矩陣Y,那麼這個Y就是神經網絡第一層Layer1的輸出,它會做爲下一層Layer2的輸入,後面以此類推。注意,函數f接受一個矩陣爲參數,並做用於矩陣中每一個元素,返回一個維度同樣的新矩陣,後面會提到。能夠看到,以前須要計算4次f(w*x+b),如今只須要一次就能夠了。

經過前面的介紹,能夠得知,神經網絡的訓練過程就是找到最合適的W矩陣(多個)和最合適的b矩陣(多個)使得神經網絡的輸出與真實值(標籤)最接近,這個過程也叫作模型訓練或者調參(固然模型訓練遠不止這樣,還有其餘諸如超參數的肯定)。

非線性變換

即便輸入是高維向量,通過簡單的W*X+b這樣處理以後,輸出和輸入仍然呈線性關係。可是現實場景中大部分待解決的問題都不是線性模型,所以咱們須要在輸入和輸出之間增長一個非線性變換,也就是前面屢次提到的f函數(又稱爲激活函數)。因爲各類緣由(這裏涉及到神經網絡具體的訓練過程,反向傳播計算權重值,暫不過多解釋),常見可用的激活函數並很少,這裏舉兩個函數爲例:

Sigmoid函數

Sigmoid函數能將任意實數映射到(0, 1)之間,具體函數圖像以下:

圖9 Sigmoid函數圖像

上圖中Sigmoid函數將任意輸入映射到(0, 1)之間的值,所以Sigmoid函數又常常被稱爲邏輯函數,經常使用於二分類預測問題,假設有兩個分類A和B,對於任何輸入特徵X,Sigmoid返回值越趨近於1,那麼預測分類爲A,反之則爲B。

ReLu函數

ReLu函數很簡單,返回值爲max(x, 0),具體函數圖像爲:

圖10 ReLu函數圖像

上圖中ReLu函數將任意輸入的負數轉換爲0,其餘輸入原樣輸出。ReLu函數是目前深度學習中應用最多的激活函數,具體緣由這裏不作解釋。這裏須要說一下,深度學習/神經網絡中有些東西並無很是充足的理論依據,徹底靠前人經驗總結而來,好比這裏的ReLu函數看似簡單爲何在大部分場合下效果最好,或者神經網絡訓練中神經元到底如何組織準確性最高等等問題。

神經網絡解決分類問題

通過前面的介紹不可貴出,神經網絡能夠解決複雜映射關係的「分類」問題。將特徵輸入到神經網絡,通過一系列計算獲得輸出。下圖舉一個形象的例子來講明神經網絡如何解決分類問題:

 

圖11  預測白酒品牌

上圖顯示一個和全鏈接神經網絡一樣結構的管道網狀結構,從上到下有多個閥門能夠調節控制液體走向(圖中①),通過事先屢次樣本液體訓練(使用不一樣品牌、不一樣酒精度、不一樣子型號的白酒),咱們將閥門調節到最佳狀態。隨後將一杯白酒從最頂部倒入網狀結構,最後通過管道全部液體會分別流進三個玻璃杯中(圖中③)。若是咱們將一杯五糧液倒入管道,理論狀況全部的液體應該徹底流進第一個玻璃杯中(圖中左側),可是實際上因爲神經網絡具有泛化能力,對於任何輸入(包括訓練樣本),大部分時候不會跟正確結果100%一致,最終只會保證第一個玻璃杯中的液體最多(好比佔85%),其他兩個玻璃杯一樣存在少許液體(圖中右側)。

那麼如今有個問題,神經網絡最後輸出的是數值(或多維向量,向量包含具體數值),結果是如何體現「分類」的概念呢?本文最開始講到過,分類問題最後都是經過幾率來體現,某個分類的機率最高,那麼就屬於該分類,下圖顯示如何將數值轉換成機率:

圖12 數值到機率轉換

如上圖所示,對於2分類問題,咱們一般使用前面提到的Sigmoid函數將其轉換成(0,1)之間的機率值,而後再根據機率值劃分類別。對於N分類(N也能夠爲2),咱們要使用另一個函數Softmax,該函數接受一個向量做爲參數,返回一個新向量,維度跟輸入一致,新向量的每一個值均分佈在在(0, 1)以前,而且全部機率之和爲1。注意該函數做用在整個向量上,向量中的每一個值之間相互有影響,感興趣的同窗上網查一下公式。

 

圖像分類任務

圖像分類又稱爲圖像識別,給定一張圖,要求輸出圖中包含的目標類型,好比咱們常見的「微軟識花」、「識別貓仍是狗」等等,這是計算機視覺中最典型的「分類」問題。圖像分類是其餘諸如「目標檢測」、「目標分割」的基礎。

圖像的定義

數字圖像本質上是一個多維矩陣,常見的RGB圖像能夠看做是3個二維矩陣,矩陣中每一個值表示對應顏色通道上的值(0~255),還有其餘好比灰度圖,能夠看做是是1個二維矩陣,矩陣中每一個值表示顏色的像素值(0~255)。

圖13 彩色數字圖像矩陣

如上圖所示,一張RGB全綵數字圖片大小爲180*200,對應3個矩陣,大小都是180*200,矩陣中的數值範圍都在0~255。對於單通道灰度圖而言,對應1個矩陣,大小也是180*200:

 圖14 灰度圖矩陣

使用全鏈接神經網絡進行圖像分類

前面已經講到如何使用全鏈接神經網絡解決「分類」的問題,圖像分類一樣屬於分類問題,所以也可使用神經網絡的方式解決,惟一的區別是前面提到的都是數值特徵輸入[x1, x2, x3, ...],那麼對於圖像而言,該將什麼輸入給神經網絡呢?答案是圖像矩陣,圖像矩陣中包含數值,將一個M*N的二維矩陣展開後,獲得一個M*N維向量,將該向量輸入神經網絡,通過神經網絡計算,輸出各個分類機率。下面以「手寫數字圖像識別」爲例,介紹全鏈接神經網絡如何作圖像分類。手寫數字圖像識別是深度學習中的一個HelloWorld級的任務,大部分教程均以此爲例子講解圖像識別,下圖爲手寫數字圖片:

圖15 手寫數字圖像

上圖顯示4張手寫數字圖片,分別爲「5」、「0」、「4」、「1」,每張圖片大小爲28*28,即長寬都爲28像素,圖片都是灰度圖像,也就是說每張圖片對應1個28*28維矩陣,將該矩陣展開獲得一個28*28維向量,直接輸入到全鏈接神經網絡中。從0到9一共10個分類,所以神經網絡的輸出是一個10維向量。

圖16 手寫數字圖片識別全過程

如上圖所示,原始輸入圖片大小爲28*28,將其展開成[784*1]的特徵X傳入神經網絡。神經網絡一共包含兩層,第一層W矩陣大小爲[1000*784],W*X以後獲得大小爲[1000*1]的輸出,該輸出做爲第二層的輸入X,第二層W矩陣大小爲[10*1000],W*X以後獲得大小爲[10*1]的輸出,該輸出(通過Softmax做用後)即爲數字0~9的機率。

注意上面定義的神經網絡結構中,只包含兩層(圖中藍色和綠色,黃色部分不算),第一層的W矩陣尺寸爲[1000*784],這裏的1000是隨意設定的,能夠是500甚至2000,它和神經元數量保持一致。第二層的W矩陣尺寸爲[10*1000],這裏的1000跟前面同樣,這裏的10是分類數,由於一共10個分類,因此爲10,若是100分類,這裏是100。神經網絡的層數和每層包含的神經元個數均可以調整,這個過程就是咱們常說的「修改網絡結構」。

經過上面的方式作手寫數字圖片識別的準確性可能不高(我沒有試驗過),即便已經很高了它也不是一種很是好的方式,這種方式也許對於手寫數字圖片識別的任務頗有效,可是對於其餘圖片好比貓、狗識別仍然頗有效嗎?答案是否認的,緣由很簡單:直接將整張圖片的數據徹底輸入到神經網絡中,包含的特徵太複雜,或者噪音太多,這種現象可能在手寫數字這種簡單的圖片中有效,一旦換成複雜的圖片後可能就不行了。那麼針對通常圖像分類的任務,在將數據傳到神經網絡進行分類以前,咱們還須要作什麼呢?

圖像特徵

圖像特徵在計算機視覺中是一個很是很是重要的概念,它在必定程度上能夠看成圖片的特定標識,每張圖片都包含一些人眼看不到的特徵。關於圖像特徵的介紹,你們能夠參考我以前的一篇博客:http://www.javashuo.com/article/p-bwhwelmq-ba.html

在使用神經網絡對圖片進行分類以前,咱們須要先提取圖像特徵,而後再將提取到的特徵輸入到全鏈接神經網絡中進行分類,所以解決圖像分類問題的正確神經網絡結構應該是這樣的:

 圖17 包含特徵提取的神經網絡

如上圖所示,在全鏈接神經網絡以前增長了一個模塊,該模塊也是神經網絡的一部分,一樣由許許多多的神經元組成,可是可能再也不是全鏈接這種結構了,它能夠自動提取圖片特徵,而後將特徵輸入到後面的全鏈接網絡進行分類,咱們一般把這裏的全鏈接網絡稱爲「分類器」(是否是似曾相識?)。這樣一來,全鏈接網絡的輸入特徵大小再也不是[784*1]了(圖中黃色部分),而應該根據前面的輸出來定。

圖17中這種由全鏈接神經網絡(分類器)和特徵提取部分組合起來的神經網絡有一個專有名詞,叫「卷積神經網絡」,之因此叫「卷積」,由於在提取特徵的時候使用了卷積操做,具體後面介紹。

 

卷積神經網絡

卷積神經網絡中包含一個特徵提取的結構,該結構主要負責對原始輸入數據(好比圖像,注意還能夠是其餘東西)進行特徵提取、抽象化、降維等操做,它主要包括如下幾個內容:

卷積層

卷積層主要負責特徵提取,它使用一個卷積核(一個小型矩陣)以從左到右、從上到下的順序依次做用於原始輸入矩陣,而後生成一個(或多個)新矩陣,這些新矩陣咱們稱之爲feature maps。具體操做過程以下圖:

圖18 卷積操做過程

如上圖所示,圖中綠色部分爲原始輸入矩陣,黃色矩陣爲卷積核(一個3*3的矩陣),通過卷積操做後生成一個新的矩陣(粉色),該矩陣稱爲feature map。卷積核能夠有多個,每一個卷積核不一樣,同一個輸入矩陣通過不一樣的卷積核處理以後會獲得不一樣的feature map。所以在卷積層中,存在多個卷積核處理以後就會生成多個feature maps,這些feature map各不相同,每一個都表明必定的特徵。

若是原始輸入矩陣是一張圖片,通過卷積核處理以後,生成的多個feature maps雖然仍然是矩陣的形式,可是不能再把它們看成圖片來對待。下圖顯示一張圖片通過兩個不一樣的卷積核處理以後生成的兩個feature maps,咱們用工具將這兩個feature maps以圖片的形式顯示出來:

圖19  feature map的可視化

如上圖所示,一張原始圖片通過一次卷積處理以後,生成的feature map以圖片的方式顯示出來以後彷佛仍是能夠人眼識別出來。可是,若是通過屢次卷積處理以後,那麼最終的feature map就沒法人眼識別了。上圖還能夠看出,不一樣的卷積核處理同一張輸入圖片後,生成的feature map之間有差異。

這裏再次強調,雖然通過卷積操做獲得的feature maps仍然能夠以圖片的形式顯示出來,可是它不在是咱們一般理解中的「圖片」了。雖然人眼看再也不有任何意義,可是對於計算機來說,意義很是重大。卷積層能夠存在多個,一個卷積層後面能夠緊跟另一個卷積層,前一層的輸出是下一層的輸入。卷積層中的一些參數,好比卷積核矩陣中的具體數值,都須要經過訓練獲得,這個道理跟前面提到的W和b參數同樣,也是須要經過訓練去擬合。

非線性變換(激活函數)

和前面講全鏈接神經網絡同樣,通過卷積層處理以後生成的feature maps仍然須要進行非線性轉換,這裏的方式跟前面同樣,使用常見的激活函數,好比ReLu函數做用在feature map上的效果以下圖:

圖20 對feature map作非線性變換

如上圖,feature map通過激活函數處理以後,獲得另一個矩陣,咱們稱之爲 Rectified feature map。根據前面介紹ReLu的內容,咱們能夠得知,該激活函數(max(0, x))將原feature map矩陣中的全部負數所有變成了0。

池化層

只有卷積操做和激活處理仍是不夠,由於到目前爲止,(Rectified) feature maps包含的特徵數據仍是太大,爲了讓模型具有必定的泛化能力,咱們須要對feature maps進行降維,這個過程稱之爲池化:

圖21 最大池化操做

如上圖,池化層在原始feature maps上進行操做,仍是按照「從左往右從上到下」的順序,選擇一個子矩陣(圖中圓圈部分2*2,相似前面的卷積核),選取該子矩陣範圍內最大的值做爲新矩陣中的值,依次處理後最後組成一個全新矩陣,這個全新矩陣尺寸比原來的小。除了取最大值外,還有取平均值和求和的作法,可是通過前人實踐證實,取最大值(最大池化)效果最好。

通過池化層處理以後的feature maps仍然能夠以圖片的方式顯示出來,仍是和前面同樣,人眼已經分不清是啥了,可是對於計算機來說意義重大。

圖22 池化操做

如上圖所示,一張feature map通過兩種方式池化,取最大值求和,分別獲得不一樣的新矩陣,而後將新矩陣以圖片的方式顯示出來,能夠看到差異仍是很是大(雖然人眼已經分不清內容)。

一般狀況下,卷積層後面不須要都緊跟一個池化層,能夠通過多個卷積層以後再加一個池化層,也就是說,卷積和池化能夠不按照1:1的比例進行組合。卷積神經網絡中特徵提取部分就是使用卷積層、激活處理、池化層等組合而成,能夠根據須要修改相應網絡層的數量(一般所說的「調整網絡結構」)。最後一個池化層輸出的結果就是咱們提取獲得的圖像特徵,好比最後一個池化層輸出T個矩陣(feature maps),每一個大小爲M*N,那麼將其展開後獲得一個T*M*N維向量,那麼這個向量就是圖像特徵。到這裏應該就很清楚了,咱們若是將這個特徵向量傳到一個「分類器」中,經過分類器就能夠獲得最終的分類結果,分類器可使用前面講到的全鏈接神經網絡。

全鏈接層(分類器)

其實看到這裏的同窗,若是前面的內容都看懂了,這塊就不難了。圖像特徵已經獲得了,直接將它輸入到全鏈接神經網絡中去,就能夠獲得最終分類結果。下圖顯示將一個手寫數字圖片傳入卷積神經網絡中的過程,先分別通過兩個卷積層和兩個池化層(交叉相連而成,圖中忽略了激活處理等其餘操做),而後將最後一個池化層的輸出先展開再做爲全鏈接網絡的輸入,通過兩個全鏈接層,最終獲得一個10*1的輸出結果。

圖23 卷積神經網絡的計算過程

關於卷積神經網絡的配圖均來自:https://ujjwalkarn.me/2016/08/11/intuitive-explanation-convnets/

注意:

(1)本篇文章沒有涉及到具體模型訓練的原理,也就是求W和b矩陣的具體過程,由於該過程比較複雜並且涉及到不少數學公式,讀者只須要知道:模型訓練的本質就是使用大量帶有標籤的樣本數據找到相對比較合適的W和b矩陣,以後這些矩陣參數能夠做用於樣本以外的數據。

(2)深度學習不少作法缺少實際理論依據,大部分仍是靠經驗,好比到底多少層合適,到底用什麼激活函數效果更好,不少時候針對不一樣的數據集(或者問題)可能有不一樣的答案。

(3)除了名字相同外,深度學習中的神經網絡跟人腦神經網絡工做原理沒有關係,以前覺得有關係,因此取了一個相似的名字,後來科學家發現好像沒什麼關係,由於人腦太複雜。

相關文章
相關標籤/搜索