# Week1 ## Computer vision ![](https://i.imgur.com/wGhJqXM.png) 上面所提到的三個項目都可以算是Computer Vision所遇到要解決的問題。 ![](https://i.imgur.com/1ZlbgUC.png) 在計算機視覺的問題其中之一是輸入可能變得非常大。 例如,在之前的課程中,你已經使用了64×64的圖像。 所以64乘64乘3是輸入的顏色通道。 如果每張須有12288 (64 * 64 * 3)。所以X,輸入特徵的維數為12288。這不算太壞,但64乘64實際上是一個很 小圖像。 如果您使用較大的圖像,也許這是一個1000像素×1000像素的圖像,但是輸入特徵的維數將是1000 * 1000 * 3,因為你有三個RGB通道,那就是300萬,如果您使用標準的完全連接的網絡的話那將會是並且你的隱藏點有1000個,這將會是(1000,3M) 這是非常非常大的。 而且有了這麼多的參數,就很難獲得足夠的數據來防止神經網絡過度擬合,並且也不能滿足競爭的要求。 在具有30億參數的神經網絡中訓練的記憶要求,這有點不可行,但是對於計算機視覺應用程序,您不希望只使用微小的圖像卡住,而是希望能夠使用大圖像。 要做到這一點,你需要卷積運算的實現,它是卷積神經網絡的基本構件之一,下一節將會開始闡述如何處理這種問題。 :::info 為了解決大圖像導致的相關問題,使用Convolution就是一個好用的工具。 ::: --- ## Edge Detection ![](https://i.imgur.com/ofygiH1.png) 如何檢測邊緣? 如上圖有一些垂直,水平的線條,如何偵測出來,這時就要用到卷積。 ![](https://i.imgur.com/0hT55aU.png) :::warning 這個卷積矩陣(上圖中間),我們稱為filter,有些paper會稱為kernel,在這裡我們使用filter。 ::: :::info 此章節提到的作法,用一個濾波器重新計算一組新的矩陣出來,在Python稱作conv_forward,在Tensorflow -> tf.nn.conv2d,Keras -> Conv2D ::: 使用3x3濾波器進行卷積。關於符號的一個不幸的事情是,在數學中,星號是卷積的標準符號。但在Python中,這也被用來表示乘法或Python矩陣智慧乘法。但在這邊是當這個星號指的是卷積。而這個卷積運算符的輸出將是一個4x4的矩陣,你可以把它看作一個4x4的圖像。你計算這個4x4輸出的方式如下。要計算第一個元素(這個4x4矩陣的左上角元素),您要做的是將3x3濾波器貼到原始輸入圖像的3x3區域的頂部。所以這裡寫了1 1 1,0 0 0,-1 -1 -1 ![](https://i.imgur.com/kmOga76.png) 所以第一個是3x1,然後第二個是1x1,這裡是1x1,然後是2x1。然後加起來所有的九個數字。那麼中間的列就會給出0 x0 + 5x0 + 7x0。然後最右邊的列給出1x-1,8x-1 + 2x-1。加起來這九個數字會給你-5,其他以此類推 [](https://i.imgur.com/4zZnrju.png) 為什麼要像上面這樣做邊綠檢測? 我們可以看下面的例子: ![](https://i.imgur.com/eHwTunN.png) 上圖像中間有一個很強的垂直邊緣(計算方式如上)。提供一種可以垂直邊緣檢測的一種方法,因為正在使用一個3×3的濾波器。左側有明亮的像素。而且你並不在乎中間是什麼東西。在右邊的黑色像素。而6×6圖像中的圖像的中間部分實際上是左側可能有亮像素,而右側是暗像素。這就是為什麼它認為那裡有一個垂直的邊緣。卷積操作提供了一種方便的方法來指定如何在圖像中找到這些垂直邊緣。所以你現在已經看到了卷積運算符是如何工作的。 檢測到的邊緣似乎真的很厚, 這只是因為我們在這個例子中使用了非常小的圖像。 如果你正在使用,說一個1000×1000的圖像,而不是一個6×6的圖像 你會發現這樣做的確不錯, 確實檢測到圖像中的垂直邊緣。 ![](https://i.imgur.com/kEwCCz0.png) 不同的濾波器可以讓你找到垂直和水平的邊緣。事實證明,使用的3乘3垂直邊緣檢測濾波器只是一個可能的選擇。歷史上,在計算機視覺文獻中,關於什麼是最好的數字使用有爭議。所以這裡有一些你可以使用的東西,可能是1,2,1,0,0,0 -1,-2,-1,這叫做索貝爾濾波器。而且這樣做的好處是,它對中央行,中央像素有一點點的重要性,這使得它可能更健壯一些。但是計算機視覺研究人員也會使用其他數字集合。就像也許,而不是1,2,1,它應該是一個3,10,3,然後-3,-10,-3,這被稱為Scharr過濾器,這還有其他稍微不同的屬性。這就是所謂的垂直邊緣檢測,如果你把它翻轉90度,你會得到水平邊緣檢測。而隨著深度學習的興起,我們學到的一件事就是,當你真的想在一些複雜的圖像中檢測邊緣。也許不需要讓計算機視覺研究人員選擇這九個數字,也許可以學習它們。並把這個矩陣的九個數字作為參數,然後用反向傳播學習,目標是學習九個參數。所以,當你把6乘6的圖像,並透過3乘3過濾器運算,這給你一個很好的邊緣檢測器。 --- ## Padding & Strided Convolutions 上述方式有兩個缺點,第一缺點是當每次你應用一個卷積運算符時,圖像會縮小,以上章節為例,你從6x6降到4x4,那麼在圖像開始之前你只能做幾次否則會變得非常小。 :::info 縮小公式為 n-f+1,例如:6-3+1=4 ::: 或許它是一個接一個的東西,所以也許你不希望你的圖像每次觸碰邊緣或者安裝其他功能時都會縮小,所以這是一個缺點。而第二個缺點是,如果你看像素的角落或邊緣,這個小的像素被觸摸,它只用於其中一個輸出,因為這觸及了3x3的區域。如果你在中間取一個像素,那麼可能會有很多3x3的區域與這個像素重疊,但角落或邊緣上的像素使用的就可能少很多,所以在輸出中圖像的邊緣附近會丟掉了很多信息。 ![](https://i.imgur.com/rgTPA9v.png) 因此這時可以用填充方式如上圖,假設您在圖像周圍添加一個像素的邊框。所以,如果你這樣做,那麼6x6的圖像,你現在已經填補了8x8的形象。如果你用一個3x3的圖像來卷積一幅8x8的圖像,那麼現在你就可以看出,輸出的變成6x6(8-3+1)的圖像。所以你設法保留了6x6的原始輸入大小,所以這個綠色像素實際上會影響輸出的所有這些單元,這個效果可能不是很好,但可以解決圖像邊緣的信息因此可能會被丟掉的問題。 ![](https://i.imgur.com/oFfifD6.png) 上面分兩種填充方式,對於最終的輸出尺寸不同。Same方式最終輸出尺寸會與輸入相同。 :::info 最後講師公式推導之後可以得到,普遍來講濾波器將會是個奇數x奇數的矩陣,你會發現需要填充2個以保持輸出大小與輸入相同大小的濾波器則會是5x5( p = (f -1 / 2)),另外奇數個的濾波器還有一個好處是它會讓圖片是對稱的並且可以有個中心位置,這樣對於處理計算機視覺問題當中會比較好處理問題。 ::: 另一個方式是分段卷積,假設你想用這個3×3濾波器來卷積這個7×7的圖像,照通常的方式是一步一步地把藍色框內的值做運算,但這邊將會分兩步走,所以第一個值為91,然後要像這樣跳過兩步,所以下一步運算出來為100。而現在,我們將再次這樣做,使藍框跳過兩步。所以你最終在那裡,這給了你83,其他以此類推,所以在這個例子中,我們用一個3×3濾波器對7×7矩陣進行卷積,得到一個3×3的輸出,最後我們得到一組公式,若假如最後有些部分沒在藍色框內,你的3×3濾波器必須完全位於你的圖像或圖像加填充區域之前來生成相對應的輸出 :::info $$\frac{(n+2p-f)}{s} +1$$ ::: ![](https://i.imgur.com/qJqOwh4.png) --- ## Convoultions over volume 通常會圖片運算不會只有二維應該會包括(R,G,B)所以可能會的多維矩陣,從底下得知輸入過程中的圖片通道(Channels)的數量必須與您的濾波器中的通道數量相匹配(高度,寬度和通道數量),輸出則會為一個4x4矩陣,可以想成濾波器為一個立方體以投影片為例總共會有27個參數,每個參數與相對應的通道內的RGB進行相乘,最後將此立方體內的27個參數全部加起來變成最後得到4x4的矩陣輸出,最後甚至更可以製作多個附有特徵的濾波器,即如果我們不只是想檢測垂直邊緣,如果要檢測垂直邊緣和水平邊緣,以及可能的45度邊緣,也可能是70度邊緣也都是可以的 :::info 注意輸出是一個平面的4*4,而不是3D的,因為filter的計算結果會相加成一個值。 ::: ![](https://i.imgur.com/WI5R5uL.png) --- ## How to build one layer of convolutional neural network :::info 我們將可以設計多個濾波器並透過先前篇章的卷積神經網絡作法,最後你最終得到一個4x4x2的輸出,這是一層組成的神經網絡 ::: ![](https://i.imgur.com/nOOWNfm.png) :::info 卷積就像神經網路的權重w ::: ![](https://i.imgur.com/k9K6itz.png) ## Simple-convolutional-network-example :::info 當你深入到神經網絡時,通常你會從更大的圖像開始,39x39,然後高度和寬度將保持相同的一段時間,隨著您在網絡中的深入,逐漸趨於下降。所以從39到37到17到7逐步遞減,然而頻道數一般會逐步增加,從3到10到20到40。在很多其他的卷積神經網絡中也是一般的趨勢。 ::: ![](https://i.imgur.com/7KX0McU.png) 現在你已經看到了第一個卷積神經網絡的例子,簡稱ConvNet。 在一個典型的ConvNet中,通常有三種類型的層次。一個是卷積層,這就是我們在以前的網絡中使用的。另外還有其他兩種常見的圖層類型,但我們將在接下來的幾個視頻中討論。分別是池化層(pooling layer),另一個是完全連接的層,稱為FC。儘管可以使用卷積層來設計一個相當不錯的神經網絡。大多數神經網絡體系結構也將具有一些池化層和一些完全連接的層 ![](https://i.imgur.com/VtkcUwF.png) --- # Pooling Layers :::info 在使用Max pooling 的作法是將限定一個特定的矩陣維度例如影片內的2x2值,並從中挑出最大值當作輸出結果,另一個Average pooling,則是將裡面的值相加取平均 ::: ![](https://i.imgur.com/H2gRfSH.png) ![](https://i.imgur.com/AvQQPli.png) ![](https://i.imgur.com/JNjyvqf.png) --- # CNN Example :::info 雖然有時你會看到在線閱讀文章或者閱讀研究論文,你會聽到 Conv層和Pooling層,兩個單獨的層。但是這可能不是正確的術語用法。 所以在圖中把它們作為同一層。將在這裡使用CONV1和POOL1的名字,最後也指的是把這兩個視為神經網絡的第一層的一部分,第二層以此類推,最後你將會看到一種常見的神經網路模型CONV1-POOL1-CONV2-POOL2-FC3-FC4-SoftMax ::: ![](https://i.imgur.com/pQJs0ta.png) :::info 從下表格可以知道幾件事 * 在Pooling Layer 採用max pooling layers不會有任何的參數使用 * CONV層往往只有相對較少的參數 * 很多參數都傾向於在神經網絡的完全連接層中 * 然後隨著進入神經網絡的深度,激活大小可能會逐漸下降。如果下降得太快,通常對於性能也不是很好 * 最後你會發現最困難的部分是怎樣用最佳方式將這些方法建構成一個有效的神經網路,講師建議可以多看具體的例子提升自己的洞察力與直覺 ::: :::warning 下表內的#parameters個數感覺不太對應該為608才對(5*5*3 + 1) * 8 (在Quiz 2,3計算parameters是需要乘上channel個數) https://www.coursera.org/learn/convolutional-neural-networks/discussions/weeks/1/threads/-9zSTsKjEeeI9RKrra6UQA ::: ![](https://i.imgur.com/SDaVBRg.png) --- # Why Convolutions ![](https://i.imgur.com/PnIaykp.png) --- :::success 練習題: Quiz 9: CNN的parameter sharing的影響應該只會發生在使用的數據集中,而Transfer learning 可能會用到不同的數據集 ::: :::success 實作題: * Convolution model - Step by Step - v2 * zero_pad部份 * 注意不需要用2*pad來做為參數使用,題目所指的2*pad是指結果的shape。 * conv_single_step部份 * 注意這裡做的是已經slice的部份來相乘W,所以不用使用迴圈。 * conv_forward部份 * 最終有問題的地方應該會是在計算start, end的slice位置,注意這裡要以最終輸出Z的shape的每一個h, w上的點來回推slice的形狀位置來思考,即**從output的每個元素回推到input來想**。而不是從input A_prev->Z的想法來思考。 * 所以,for迴圈的h及w指的是Z的每一個元素,此時就可以想得到如果搭配上strid及pad,那麼在input的A_prev應該是在哪裡start及end,也就是h, w變成filter每移動一次的計數器了。 * 注意Z的初始化應該是四維度的,而不是只有寬x高而已。 * 注意第四個迴圈指的是W的filters數,而不是input的channel數。 * conv_backward部份 * 基本上給的提示照做已經足夠 * 主要問題會在第三個for迴圈,注意這些迴圈的目標是以最終的輸出來寫這些迴圈,所以最終我們要算的是dW, db,所以迴圈的條件寫法也要以dW,db的shape來寫 * 所以要注意c的這條迴圈,應該要用n_C做range,而不是n_C_prev,從最終輸出的dW, db將c變數用在第四個維度上,也可以得知應該是n_C * create_mask_from_window部份 * 注意只要mask = x==np.max(x)即可 * distribute_value部份 * 注意分母是dz,不是1 * pool_backward部份 * 這裡反而最容易混淆 * 要注意每個shape * dA_prev是用A_prev來做,所以initialize時,shape應該要跟A_prev相同。 * 在三個for迴圈時,要注意目的,for迴圈的目的是取出dA參數裡每個單一元素來進行之後的計算,所以不會是用n_H_prev的變數,即不會用dA_prev的shape來做迴圈,而會用dA的shape來做,由於channel部份都會相同,所以用n_C或n_C_prev就沒差了。 * 在取slice時 * 注意end是拿f來加,而不是pad * 在max部份: * 計算dA_prev時,記得如題目所說,mask要再乘上dA值才能加入dA_prev。 * 注意,這裡的dA值是一個純量,不是陣列了。如同for迴圈的目的,是要取出dA純量來計算,所以在取dA純量的index用法要注意,應該是直接i, h, w, c的方式來取出dA值,而不是再用start:end的方式。 * 在average部份: * 如同上面max所說,dA應該是一個純量的取法,不要用start:end方式。 * 記得使用distribute_value來做計算 * Convolution model - Application - v1 * forward_propagation 部份: * 注意在第二層Z2時,要注意輸入不再是X,而是之前計算出來的P1 * 使用到的s即strides的步長,直接改為題目要求的值即可。 * f則為window size,一樣改為題目要的即可。 * 最後的fully connected記得要依照題目說明加上activation_fn,並且注意輸入F應該是最後做完flatten的參數。 ::: --- # Week2 :::info 第二週一開始講師提了三個普遍看到的神經網路架構分別為LeNet-5, AlexNet, VGG-16,建議先從AlexNet論文開始,然後是VGG網絡論文,然後LeNet論文有點難以閱讀,但這是一個很好的經典範例。 ::: ![](https://i.imgur.com/nqK1Sb5.png) :::success [LeNet-5](http://vision.stanford.edu/cs598_spring07/papers/Lecun98.pdf)的目標是識別手寫數字,應用在灰階圖像上進行訓練,這就是為什麼它是32×32x1,這個神經網絡結構實際上和上個星期看到的最後一個例子非常相似。LeNet-5是在1998年發表這篇論文,而實際上在輸出層使用了一個不同的分類器,現在這個分類器是無用的。所以這個神經網絡按照現代標準來說很小,大約只有6萬個參數。而今天,經常會看到約1000萬到1億個參數的神經網絡,看到比這個網絡大千倍的網絡並不罕見。但是在這邊所看到的一件事是,當你在一個網絡中更深入的時候,當你從左到右走時,高度和寬度往往會下降,而頻道數量卻會一直在增加,另外它談到了一些被稱為圖形變壓器網絡的東西,這個目前還沒有被廣泛使用。所以,如果你嘗試閱讀這篇論文建議把注意力集中在第二節討論這個架構上,也許可以快速看看第三節有很多實驗和結果,應該會是這部份精華 ::: ![](https://i.imgur.com/fek6lrC.png) :::success [AlexNet](https://papers.nips.cc/paper/4824-imagenet-classification-with-deep-convolutional-neural-networks.pdf)有大約6000萬個參數。與LeNet相比,事實上,他們採取非常相似的基本構建塊,但有更多的隱藏單位和更多的數據培訓來訓練他們的數據集,使其有一個非凡的表現,而這個架構另一個方面比LeNet更好的原因在於它使用了值激活功能(value activation function) ::: :::info 另外如果對AlexNet與其他不同的Net比較的話,可以參考底下投影片(可以直接從page13開始看),會發現其實目前還有很多不同的模型可以玩 [張宴晟 [2017台灣人工智慧年會] Real Time Human Body Segmentation on Mobile Device with Deep Learning](https://docs.google.com/presentation/d/1qQEe54H8hxiSXfuXHvec_KNDVFrmU8tgVBh79iIwFZs/edit#slide=id.g290c29996a_0_93) ::: ![](https://i.imgur.com/WSanOdV.png) :::success [VGG-16](https://arxiv.org/pdf/1409.1556.pdf)中的16個指的是具有16個具有權重的層。而這是一個相當大的網絡,這個網絡總共有大約1.38億個參數。即使按照現代標準,這也是相當大的。但是VGG-16架構的簡單性使其非常吸引人,原因是他的模型的結構非常一致,寬高下降一半,頻道增加一倍(以64倍數增加),隨著層級越來越深,高度和寬度會隨之下降 ::: ![](https://i.imgur.com/AFKzvNw.png) ![](https://i.imgur.com/KpNVyVb.png) :::success 非常深的神經網絡很難訓練,因為漸變類型的問題正在消失和爆炸。在這個視頻中,您將了解到跳轉連接,可以讓您從一個圖層進行激活,然後突然將其饋送到另一個圖層,甚至更深入到神經網絡,使用[ResNet](http://image-net.org/challenges/talks/ilsvrc2015_deep_residual_learning_kaiminghe.pdf),使您能夠訓練非常非常深的網絡。有時甚至超過100層的網絡,ResNets是由一個被稱為殘餘塊(Residual Block)的東西構成的,此模型主要概念是希望能從中透過更深度的學習獲得更好的精準度但同時也要避免過於搓合的問題發生,其中裡面有個關鍵術語"快捷連接"的前向神經網絡來實現。快捷連接是那些跳過一層或更多層的連接,快捷連接簡單地執行恆等映射,並將其輸出添加到堆疊層的輸出,講師認為殘留網絡此方法可行的原因主要原因是這些額外的圖層很容易學習到身份識別功能,這樣可以保證它不會影響性能,甚至有助於表現 ![](https://i.imgur.com/MxeXetK.png) ::: ![](https://i.imgur.com/1Wy8ls4.png) ![](https://i.imgur.com/LRwZMNI.png) ![](https://i.imgur.com/0sBu7F9.png) :::info 這邊提到一個例子,將28x28x192的數據塊作為輸入,並且實現了5x5的相同卷積的32個濾波器,輸出28x28x32,如果你乘以所有這些數字,這就相當於1.2億(28x28x32x5x5x192)。雖然現代計算機可以完成1.2億次的增長,但這仍然是一個相當昂貴的操作,但如果中間運用了一對一卷積的思想,您將能夠將計算成本降低10倍。從大約1.2億個乘法運算到大約十分之一 ::: ![](https://i.imgur.com/TRsuAse.png) :::info 為了節省你的3x3卷積計算,你也可以在這裡做同樣的事情。然後三x三輸出為28x28x128,然後也許想考慮一個接一個的捲積。但其實沒有必要一個接一個地進行一個接一個的轉換。所以這裡只有一步。我們假設這個輸出由28x28x64最後是共享層。在這裡,我們要做一些有趣的事情。我們想要使用相同的填充最大池。所以輸出是28x28,我們可以將它與其他輸出連接起來做通道串聯,連接這(64+128+32+32),這給你一個28x28x256維輸出。最後Channel concat再連接了在前一個視頻中看到的塊。 ::: 這個特定的Inception network是由Google的作者開發的,他們把它稱為GoogLenet,而這個也是為了在前面的LeNet致敬。Inception網絡的名字來自哪裡?如果你看過電影"The Inception",作者們實際上把這個模型作為需要建立更深層的神經網絡的動機,這就是他們提出的Inception架構。自從最初的Inception模塊開發以來,作者和其他人已經開發,並提出了其他版本。因此,有關最新版本的Inception算法的研究論文,有時會看到人們在其工作中也會使用其中的一些版本,如Inception V2,Inception V3,Inception V4。還有一個初始版本,結合了跳過連接的常駐意見,有時甚至更好。但是所有這些變化都是基於你在這個和以前的視頻中學到的基本概念,然後把它們堆疊在一起。通過這些視頻,您應該能夠閱讀和理解Inception論文 --- # Practical advices for using ConvNets ![](https://i.imgur.com/Fu42ikV.png) :::success 假設你正在建造一個貓臉辨識探測器來識別你自己的寵物貓。根據互聯網,Tigger是一個常見的貓的名字,Misty是另一個常見的貓的名字。現在,你可能沒有很多Tigger或Misty的照片,所以你的訓練集會很小。你能做什麼?我建議你去網上下載一些神經網絡的開源實例,不僅下載代碼,而且下載模型權重。有許多可以下載的已經被訓練過的神經網路模型,例如,具有一千個不同子句的Init Net數據集,因此網絡可能有一個softmax單元,可以輸出一千個可能的子句中的一個。你可以做的是丟棄softmax層,創建自己的softmax單元,輸出Tigger或Misty或兩者都不是。就網絡而言,我鼓勵你把所有這些層都凍結固定,這樣你可以凍結網絡中所有層的參數,然後你只需要訓練與你的softmax層相關的參數即可。此外也可以只訓練與特定層相關的方式,最後,如果你有很多的數據,在極端的情況下,你也可以像初始化那樣使用下載的方式,然後可以做梯度下降,培訓更新所有的方式和網絡的所有層。 ::: :::info 目前在網路上已發布了大量的數據集在計算機視覺領域上,例如ImageNet,MS COCO或Pascal類型的數據集,因為互聯網上的開放數據集是如此之大,以至於別人花了數週時間進行培訓的方式已經從這麼多的數據中學到了,你會發現對於很多計算機視覺應用來說,你只要做得更好,並將其作為你的問題的初始化會是比較好的開始方式。除非你有一個特別龐大的數據集來從頭開始訓練其他所有東西,否則你幾乎應該這樣做。 ::: ![](https://i.imgur.com/A4Z9XHf.png) ![](https://i.imgur.com/IHQQlZH.png) ![](https://i.imgur.com/vs4jiDx.png) ![](https://i.imgur.com/Ee1bdtc.png) ![](https://i.imgur.com/Iv48o8D.png) :::success 平均而言,當你有大量的數據時,你會發現人們越來越喜歡使用更簡單的算法,而且手工設計也更少。所以,為這個問題精心設計功能就不那麼需要了,而是可以有一個巨大的神經網絡,甚至更簡單的架構,並有一個神經網絡。只要了解我們是否想要了解我們有很多數據。而相比之下,當你沒有那麼多的數據時,平均而言,你會看到人們從事更多的手工設計。如果你想變得不那麼可以說有更多的黑客。但是我認為當你沒有太多的數據時,手工設計實際上是獲得良好性能的最好方法。 幸運的是,當你的數據很少時,有一件事情可以幫助你轉移學習。例如上個影片提到的可以透過數據傳遞學習能夠有效幫助。 所以,要建立一個實用的系統,你最好從別人的神經網絡架構開始。如果可能的話,你可以使用開源專案實現,因為開源專案可能已經找出了所有的挑剔的細節,如學習率,案例調度和其他超參數。最後,別人可能花了數週時間來為6台GP使用和上百萬張圖像進行模型培訓。因此,通過使用別人的預訓練模型和對數據集進行微調,通常可以在應用程序上更快地完成工作 ::: :::info 測驗題: 如果有錯請跟大家討論,題目可能稍難。 實作題: 作業最後的手勢辨識模型結果需要修改一下程式碼 否則會遇到跑出來的結果都是0 <br> ```python= x = image.img_to_array(img)/255 x = np.expand_dims(x, axis=0) #x = preprocess_input(x) ``` 實作題Residual Networks - v2: * 注意在convolutional_block部份時: * 進行SHORTCUT PATH的處理時,要注意input是什麼,不應該再是X。 ::: --- # Week 3 ![](https://i.imgur.com/Y88E3FG.png) :::info 本週提的是物件偵測,這意味著你不僅要將這個標籤稱為一輛汽車,而且該算法還要負責放置一個邊界框,或者在圖像中圍繞汽車的位置繪製一個紅色矩形,這邊以自動駕駛的應用程序為例,那麼你可能需要檢測不只是其他汽車,但也許其他行人和摩托車,甚至可能還有其他物體,如果都沒有那可以是輸出背景。投影片把pc參數定義為是否有物體在裡面,若沒有偵測到的話為0,邊界框定義成bx,by,bh和bw,並將這四使用圖像左上角的符號約定,表示為坐標(0,0),右下角是(1,1),而c1, c2, c3分別為三個類別而這三種類別值加起來應為1,如果y1 = 1,那麼可以使用平方誤差來預測方差,以及所有八個分量的實際輸出。而如果y1 = 0,那麼第二到第八個分量我不在乎。所以你所關心的是你的神經網絡估計y1的準確程度,它等於pc。對於那些想要了解所有細節的人來說,我只是使用平方誤差來簡化這裡的描述,在實踐中,你可能可以使用類似於logistics regression loss的特徵損失,將c1,c2,c3用於softmax輸出。所以這就是你如何得到一個神經網絡不僅分類對象,而且可以用來做物件定位。有一個神經網絡輸出一串實數來告訴你事物在圖像中的想法是一個非常強大的想法。在接下來的視頻中,繼續和大家分享一些其他的地方。 ::: ![](https://i.imgur.com/qc6gmOu.png) :::info 在一般的情況下,您可以使用神經網絡輸出重要點和圖像X和Y座標,此時又稱為地標(Landmark),例如希望能從人臉辨識中的演算法告訴你人的眼角位置在哪裡,你可以在一個神經網絡的最後一層,只是輸出兩個更多的數字,將能表示人眼角的n個X與Y座標集合,影片內假設有l64X, l64Y來表述特徵,所以這個例子會有129個輸出單位,其中一個為是人臉或不是。此外如果您使用Snapchat裡面有一個功能為AR增強現實濾鏡(如Snapchat照片)它可以在臉上繪製皇冠並具有其他特殊效果。這之中有一個計算機圖形效果的關鍵構建塊,就是必須要能夠在臉上檢測這些標誌,並戴上皇冠或帽子。當然為了對待這樣的網絡,你需要一個標籤訓練集,在這裡人們將不得不經過將這些地標費力地註解,最後要注意一點,這些標籤必須在不同的圖像上要保持一致 ::: ![](https://i.imgur.com/QrvYrpy.png) :::info * 滑動窗口檢測(Sliding Windows Detection Algorithm): 影片中主要概念是透過在這侷限在紅色框內的資料做分類處理例如判斷是否汽車在裡面,但在滑動窗口檢測有一個巨大的缺點,就是計算成本很高。因為你在圖像中剪出了許多不同的方形區域,並通過一個適當的方式獨立運行每個區域。如果你使用一個非常粗的步幅,那麼這將減少你需要穿過網格的窗口數量,但可能會損害模型效能。而如果你使用非常精細的粒度或者非常小的步幅,那麼所有這些小區域的大量數據就意味著計算成本非常高。因此,在類神經網絡的興起之前,人們習慣於使用更簡單的分類器,比如簡單的線性分類器。而在那個時代,因為每個分類器的計算相對便宜,它只是一個線性函數,滑動窗口檢測運行沒問題。但若你希望在圖像中在這侷限在紅色框內這樣一步一步運行單一的分類任務是非常昂貴的,滑動窗口這種方式是可憐的慢。此外,除非您使用非常精細的粒度或者非常小的步幅,否則您最終無法對圖像做準確的判斷。幸運的是,這個計算成本問題有一個很好的解決方案。特別地在滑動窗口對象檢測器可以用卷積實現或者更有效地實現。在下一個影片中,我們可以來看看如何做到這一點 ::: ![](https://i.imgur.com/nNH1YJp.jpg) :::success Andrew引用這篇[論文](https://arxiv.org/pdf/1312.6229.pdf)的方法,其關鍵是將完全連接層導入濾波器的概念進來,在數學上,這與原本完全連接層層是一樣的,因為這400個值中的每一個都是這些5x5xx16的activations,所以最後可以給出一個1x1x4的結果出來,影片這邊四個參數是行人,汽車,摩托車,背景的一個機率值結果,因此,這展示如何利用這些完全連接層,並使用卷積層來實現它們,以便這些單元集合不是變成1×400,接下來讓我們來看看如何實現滑動窗口對象檢測的卷積實現,假設你測試的圖像是16×16×3。所以將黃色添加到這個圖像的邊界。在原來的滑動窗口算法中,您可能想要將藍色區域輸入到一個convnet中,然後運行一次以生成出這區塊的值出來,然後稍微下來,最少它使用兩個像素的步幅,然後您可以將其滑動到,右邊兩個像素將這個綠色矩形輸入到另一個convnet中,然後我們運行整個convnet並獲得另一個標籤。然後,您可以將此橙色區域輸入到convnet中,然後再運行一次以獲得另一個標籤,以此類推,最後則會得到2x2x4的輸出,而這個卷積實現並不是迫使你在輸入圖像的四個子集上獨立地運行四個傳播,而是把所有四個偵測到的區塊結合成一種計算形式,並且共享這些大量圖像區域計算,最後在舉一個更大一點圖像為例,按照先前作法最後你可以得到一組8x8x4的輸出,以前你做的是裁剪一個區塊。比方說,這是14x14,然後一步一步通過你所設定的範圍直到有認識到這輛車。但是現在,不是按順序執行,而是使用上圖中看到的捲積實現,可以實現整個圖像,全部可能是28x28,並且同時卷積地做出所有的預測,並希望能夠認識到汽車的所在位置。所以這就是如何實現滑動窗口卷積,它使整個事情更有效率,但這仍然還有一個問題,那就是邊界框的位置不會太準確。在下一個視頻中,讓我們看看如何解決這個問題。 ::: ![](https://i.imgur.com/MULWm1E.png) :::success 因你所要偵測的物件不一定都會剛好在你跑的紅色框內,完美的邊界框甚至不是相當正方形,它實際上可能有一個稍寬的矩形或略微水平的縱橫比,影片中提到[YOLO](https://pjreddie.com/media/files/papers/yolo.pdf)(You only look once)演算法可用來改善邊界框的預測,以上面圖為例裡面有兩個汽車物件,而YOLO算法所做的就是取出兩個物體的中點,然後將物體分配給包含中點的網格單元,然後你可以想像成這個九宮格會是個3x3x8的輸出,也就是說一個網格單元內有一組一個8維的Y向量,左上角的這個1x1×8的量對應於九個網格單元的左上角的目標輸出向量,其他以此類推,所以這個算法的優點是神經網絡輸出可以更精確的處理在邊界框的問題,當然在實踐中可以有更多的網格單元也許可以是19x19,它減少了多個對象分配給同一個網格單元格的可能性,提醒一下,當您查看對象的中點時,將對象分配給網格單元的方式,然後將該對象分配給任何一個網格單元格包含該對象的中點。因此,即使對象花費了多個網格單元,每個對像也只能分配給9個網格單元中的一個,或者3×3或19×19個網格單元中的一個。對19×19網格的算法來說,在相同網格單元中出現兩個物體中點對象的機會只是稍小一些。所以要注意兩點,首先,這很像我們在本週的第一個視頻中提到的圖像分類和定位算法。並且它明確地輸出邊界坐標。因此,這允許您的網絡輸出任何寬高比的邊界框,以及輸出更精確的坐標,而不僅僅是滑動窗口分類器的條紋大小。第二,這是一個卷積實現,你不是在3x3的網格上實現這個算法9次,或者如果你使用的是19x19的網格.19平方是361,所以,你不是運行相同的算法361次或19平方時間。相反,這是一個單一的捲積植入,在你所有的3×3或你所有的19×19的網格單元所需的所有計算之間使用大量的共享計算。所以,這是一個相當有效的算法,因為這是一個卷積實現,實際運行非常快,也很常拿來應用在即時物體偵測功能上面 ::: :::info YOLO做法可以想像是先找出中點,再給出長寬,再來畫紅框。早期做法則比較像先固定好紅框大小,再來位移紅框,確定紅框位置。 ::: ![](https://i.imgur.com/9ynmhMj.png) :::info 在YOLO算法中,相對於這個正方形,左上角的點是(0,0),右下點是(1,1).所以要指定中點的位置,那個橙點,bx可能是看起來是大約0.4。也許這是他們正確的方式0.4。然後你看by,可能是0.3。然後邊界框的高度被指定為該框的總寬度的一部分。所以,這個紅色框的寬度可能是那條藍色線的90%。所以bh是0.9,高度可能是網格單元整體高度的一半。那麼在這種情況下,bw就是0.5。所以bx和by,這必須在0和1之間,而橙點則是在該網格單元的邊界內分配的。如果它不在0和1之間,那麼它就在此網格之外,那麼將被分配到不同的網格單元。但是這些可能會比1更大。特別是如果你有一輛汽車的邊界框,那麼邊界框的高度和寬度,這可能會大於1的。所以,指定邊界框有多種方式,但是這是其中一個相當合理的約定 ::: ![](https://i.imgur.com/5xgv6FD.png) :::info IoU(Intersection over Union),常用來拿做對象檢測算法是否運行良好的一種技巧,如果您的算法以紫色輸出邊界框,紅色框的範圍為真正的範圍,那麼IoU做的就是計算這兩個邊界框的交集。也就是橙色的陰影區域除以綠色陰影區的數值,按照慣例,如果IoU大於0.5,則計算任務將判斷你的答案是正確的。如果預測的和實際的邊界框完全重疊,則IoU將是1 ::: ![](https://i.imgur.com/h0QuEuN.png) :::success Non-max suppression 又稱NMS或非級大抑制,其主要目的就是希望能消除多餘的邊界框,然後找到最佳的物體偵測位置,作法如影片中所說的,在很多計算的邊界框中都可能會含有偵測到汽車pc的機率,首先把pc小於0.6的全部捨棄,然後從剩下的邊界框中找出pc機率最大的,然後非最大抑制部分就是擺脫其他高IoU的部分,裡面提到可以把所有大於0.5的給捨棄掉,然後一直重復做直到你把每個都輸出,並將其輸出做為預測。 ::: ![](https://i.imgur.com/FDPwtHm.png) :::info Anchor Boxes(錨箱): 若希望同的網格單元要偵測多的物件可以採用此方式,其概念是將你希望偵測的物體的所有參數都放進Y矩陣中,第一組(黃色)為Anchor box1 用來偵測人形,第二組(綠色)則用來偵測汽車的參數,錨箱給你是讓你的學習算法更專業化。特別是,如果你的數據集有一些像行人那樣高大,瘦小的物體,還有一些像汽車這樣的白色物體,那麼這可以讓你的學習算法專門化,這樣一些輸出可以專門檢測像汽車這樣的物體的或是輸出單元可以專門檢測像行人那樣高大,瘦小的物體,所以最後,如何選擇錨箱?以前通常只是手工選擇它們,或者選擇五到十個錨箱形狀,這些錨箱形狀跨越了各種形狀,似乎涵蓋了您似乎檢測到的物體的類型。後來YOLO研究論文中更好的方法是使用K-means算法來分組一起你傾向於得到兩種類型的對象形狀。然後使用它來選擇一組錨定框,這些錨定框可能是您可能想要檢測的幾十個對象原因中最可能是多個的最典型的代表。但是這是自動選擇錨箱的更高級的方法,在下一個視頻中,讓我們把我們所看到的一切都整合到YOLO算法中 ::: --- ## YOLO Algorithms ![](https://i.imgur.com/LXD1DNL.png) ![](https://i.imgur.com/uQaf6tf.png) ![](https://i.imgur.com/N3IYvwb.png) :::info 內容主要是彙整前面的技巧從訓練集、預測到最後的透過NMS方法找出兩個想偵測的物件最佳邊框的過程,不過這邊小弟有個小疑惑就是錨箱的個數普遍而言是不是會與你所預期分類的c個數相同? (因為影片中錨箱設計為2個,覺得好像錨箱直覺上是用來能夠在同張圖像上偵測多個物件,感覺這跟預期想從圖像中找到的物體應該是一致的,然後自己去論壇找到的結果覺得可能是因為錨箱是用來偵測物件的邊框為主的關係,所以其實可以不一定要一致理論上只要小於分類c個數即可,若我觀念有錯的話再請後面補充,感謝) ::: --- ## Region Proposals ![](https://i.imgur.com/FyCLSqL.png) :::info 前面影片提到的你可以運行卷積算法來偵測每個網格單位是否有自己關注的物件,但是這個算法有一個缺點是它只是交叉了很多明顯沒有對象的區域,而Region Proposal(候選區域),就是一種先預先找出圖中目標可能出現的位置,然後利用圖像中的特徵資訊,讓在選取較少窗口(幾千個甚至幾百個)的情況下保持較高的IoU,論文中提出的一種叫做R-CNN的算法,它代表卷積網絡的區域或者帶有CNN的區域R-CNN算法還是很慢的,所以有一系列的工作來探索如何加快這個算法,例如fast R-CNN,它基本上是R-CNN算法,但是具有滑動窗口的捲積實現。這和你在本週的第四個視頻中看到的大致相似,這加快了R-CNN的速度。但事實證明,fast R-CNN算法的一個問題是在提出區域的聚步驟上仍然非常緩慢,因此提出了更快的R -CNN算法,它使用卷積神經網絡而不是傳統的分割算法在這些檢測區域上,並且比快速R-CNN算法的運行速度快得多 ::: :::success 實作題: * yolo_filter_boxes 部份: * argmax功能可以取出max所在的index,由於class的定義正好等於index位置關係,所以argmax這樣的功能取出的正好就代表了class。 * 使用max功能直接對box_scores處理就可以取出最大值分數,不需要使用argmax所得到的max class index去取該index所在的值。這兩種做法結果是相同的。所以用前法即可。 * step 4要注意最終要計算的三個值scores, boxes, classes應該要拿什麼對應的變數來進行mask。如果還是有錯就要再重新了解一下每個參數、變數的涵意。 * iou部份: * 注意四個xy值不是全部max,後面兩個是min * 如果不懂可以實際畫個圖,用下面的測試條件來畫,就知道iou的取法。 * yolo_non_max_suppression部份: * 由於tf已實作了non_max,所以剛才的iou實作實際上不需要。 * yolo_eval部份: * 這裡整合了你剛才實作的function, 仔細了解輸入參數的涵意,這裡面還不會牽扯到train model的過程,而是對model的輸出做yolo處理。 3.5、Run the graph on an image: 這裡面要注意一下sess要代進去的是什麼 <br> ```python= sess.run([yolo_eval輸出的結果], feed_dict={yolo_model.input: {image data} , K.learning_phase(): 0}) ``` * 這裡要注意一個sess的run方式。 * 為了要得到out_socres...第三個值,run就必須提供對應的三個最終輸出(即scores, boxes, classes), 並且要用[]包起來。在這三個最終輸出的建模過程中,需要用到input,即yolo_model.input,這個沒有在我們實作過程中出現,因為它已經是建好的model,所以我們直接使用,並把它規定的image_data做為輸入。這一段就要用feed_dict方式來指定代入。 ``` out_scores, out_boxes, out_classes = sess.run([scores, boxes, classes], feed_dict={yolo_model.input: image_data , K.learning_phase(): 0}) ``` ::: --- # Week 4 ![](https://i.imgur.com/ZJwIpl7.png) :::info 首先,讓我們開始回顧一下臉部識別中使用的一些術語。在人臉識別文獻中,人們經常談論臉部驗證(Face verification)和臉部辨識(Face recognition)。人臉驗證問題是如果您輸入圖像以及個人的姓名或身份證件,系統的工作是驗證輸入圖像是否是聲稱的人員圖像。所以,有時這也被稱為一對一的問題,你只是想知道這個人是否是他們自稱的人。而臉部辨識問題比驗證問題困難得多,假設您有一個99%準確的驗證系統。所以,百分之九十九可能不會太差,但現在假設在一個臉部辨識系統中K等於100。如果你將這個系統應用於數據庫中有100人的辨識任務,假設每個人犯錯誤的機會只有百分之一,那你現在會有100次犯錯的機會。所以,如果你有一個100人的數據庫,如果你想要一個可接受的辨識錯誤,你可能實際上需要一個可能達到99.9甚至更高的驗證系統,然後才能在一個有很高機會的100個人的數據庫上運行它但仍然有很高的機會得到不正確的。事實上,如果你有一個100人的數據庫,目前只是比99%高一點。所以在接下來的幾個影片中所做的重點是構建臉部驗證系統作為構建模塊,然後如果準確性足夠高,那麼您可能也將其用於臉部辨識系統,而在人臉驗證系統中。會遇到一個難題就是你需要解決一次性的學習問題(One shot learning),我們在下一個影片中將會看到這是什麼意思 ::: ![](https://i.imgur.com/yxJcrxc.png) :::info 在臉部辨識的挑戰之一就是你需要解決一次性學習問題。這意味著對於大多數臉部辨識應用程序,您只需要識別一個人且只能看到一個圖像,或者僅僅給出該人臉的一個例子,但如果只有一個訓練樣例,深度學習算法效果是不佳的,原因是訓練集不夠大到能訓練出強大的神經網絡,還有,如果一個新人加入你的團隊呢?所以現在你需要識別5個人變成應該有6個輸出。那這樣你每次都要重新培訓ConvNet嗎?這似乎不是一個好方法,要做到這一點,你要做的是學習一個兩兩相比較臉部是否相似的功能。這裡你可以用一個神經網絡來學習函數這裡用d表示,它輸入兩個圖像並輸出兩個圖像之間的差異程度。所以,如果這兩個圖像是同一個人,你可想像這個輸出是一個小數字。如果它們之間的差異程度小於某個閾值,這是一個超參數。那麼你會預測這兩張照片是同一個人。如果它大於,你會預測這些是不同的人,所以這就是你如何解決臉部驗證問題。要將其用於識別任務,您要做的是,給出這個新圖片,您將使用此函數d來比較這兩個圖像。也許我會輸出一個非常大的數字,例如10。然後,將其與數據庫中的第二個圖像進行比較。而且因為這兩個人是同一個人,所以你希望輸出的是一個很小的數字。您可以為數據庫中的其他圖像執行此操作,依此類推,相比之下,如果有人不在數據庫中,那麼使用函數d進行所有這些成對比較,希望d會輸出一個非常大的數字,然後說這不是數據庫中四個人中的任何一個。注意這邊是如何讓你解決一次性學習問題,就是只要你能學習這個函數d,讓它輸入一對圖像,並告訴你他們是同一個人或不同的人,然後如果你有新的人加入你的團隊,你也可以添加至第五人到你的數據庫,也就不需要 在重新訓練這函數d ::: :::success 即從原本是使用向量,依據人數的長度向量,轉變為一一比較的方式。 ::: ![](https://i.imgur.com/c8pGfEN.png) :::success 把x(1)的f當作輸入圖像x(1)的編碼。 所以把這個輸入圖像,在第一張的圖片上,重新表示為128個數字的向量,那麼你可以建立一個人臉辨識系統,如果你想比較影片中的這兩張圖片。你可以做的是將第二張圖片加入到具有相同參數的相同的神經網絡中,並得到一個不同的128位數的向量,它編碼了第二張圖。所以我打算把這個第二張照片叫做,所以我打算把這個第二張圖片的編碼稱為x(2),這裡我用x(1)和x(2)來表示兩個輸入圖像。他們不一定是你訓練集中的第一個和第二個例子。它可以是任何兩張照片,最後,如果你認為這些編碼是這兩個圖像的良好表示,那麼你可以做的是定義圖像,將x(1)和x(2)之間的距離d作為這兩個圖像的編碼之間的標準差,所以這個想法是在兩個不同的輸入上運行兩個完全相同的捲積神經網絡,然後進行比較,這神經網絡結構來自這篇[論文,而 Yaniv Taigman,Ming Yang,Marc'Aurelio Ranzato和Lior Wolf在他們開發的研究系統中稱為DeepFace](https://www.cs.toronto.edu/~ranzato/publications/taigman_cvpr14.pdf),所以你所要做的就是訓練這神經網絡,這樣它計算的編碼就會產生一個函數d,告訴你兩張圖片有多接近屬於同一個人。更正式地說,神經網絡的參數定義了x(i)的編碼f。因此,給定任何輸入圖像x(i),神經網絡輸出x(i)的這個128維編碼f。所以更正式地說,你要做的就是學習參數,如果兩張圖片xi和xj是同一個人,那麼你希望它們的編碼之間的距離很小。所以當你改變神經網絡所有這些層的參數時,你最終會得到不同的編碼。你可以做的是使用反向傳播,並改變所有這些參數,以確保滿足這些條件。所以你已經了解Siamese Network,並且了解你希望神經網絡為你輸出什麼樣的結果,從而形成一個好的編碼。但是,你如何確定一個目標函數來使神經網絡學會做我們剛剛討論過的?讓我們來看看如何使用三重丟失函數在下一個視頻中做到這一點 ::: ![](https://i.imgur.com/eEvndYo.png) :::info 課程裡採用的是[Triplet Loss](https://www.cv-foundation.org/openaccess/content_cvpr_2015/ext/1A_089_ext.pdf)方法,要應用Triplet Loss,您需要比較圖像方式。例如,左邊這對圖像,你希望他們的編碼是相似的,因為這些是相同的人。 而右邊這一對圖像,你希望他們的編碼是相當不同的,因為這是不同的人。在Triplet Loss的術語中,你要做的是總是看一個錨圖像A,然後你想在錨點和相同圖像之間進行兩張距離運算,反之,當你想要把這些錨點與它們為負面例子進行比較的時候,它們將會更加分離。所以,這就是Triplet Loss這個詞,在說你一直在看三幅圖像。 你會看到一個錨圖像,一個正面的圖像,以及一個負面的圖像,這裡分別將錨圖像,一個正面的圖像,以及一個負面的圖像分別表示為A、P、N,公式就如投影片那樣,其中如果每個圖像的編碼與每個其他圖像的編碼相同,在這種情況下,再次得到零減零。所以為了防止神經網絡這樣做,我們要做的就是修改這個目標也就是多加入一個α值,所以舉一個例子,如果在這個例子中,d(A,P)等於0.5,那麼如果d(A,N)略大一點,比如說0.51,那麼你就不會滿意。儘管0.51大於0.5,但你說這還不夠好,我們想要一個A與N比A與P還要大得多,可能會是希望它至少為0.7或更高。因此若要達到這差距這個至少要0.2的差距。所以這就是α參數在這裡的作用 ::: ![](https://i.imgur.com/Qnab4y7.png) :::info 在這裡取最大值的效果是,只要這個值小於零,那麼損失就是零,所以只要你達到了我以綠色強調的目標,只要你達到了使得小於或等於零的目標,那麼這個例子的損失就等於零。但另一方面,如果這大於零,那麼如果你拿最大值,最大值我們最終選擇,這件事我已經用綠色劃線了,所以你會有一個正損失。所以通過盡量減少這個,這樣做的效果是試圖把這個東西訓練到零,小於或等於零,只要零或小於或等於零,神經網絡並不關心它是多麼負面,所以,如果你有1000張不同的人的訓練集,需要做的就是拍攝你的10,000張照片,並用它來生成,選擇這樣的Triplet,然後使用梯度下降訓練你的學習算法這種類型的成本函數,這邊注意一下如果你有1,000張不同人的10,000張照片,那麼也許每1000個人中就有10張照片組成你的整個數據集。如果你只有一個人的照片,那麼你實際上是不能訓練這個系統。但是,當然,在訓練之後,但是當然在訓練了系統之後,你可以把它應用到你的一次性學習問題上面,像是在你的臉部辨識系統中,也許你只有一個人可能會試圖辨識。但是對於你的訓練集,你確實需要確保你的訓練集中至少有一些人有同一個人的多個圖像,這樣你才能有一對錨點和正面的圖像 ::: ![](https://i.imgur.com/gtZ6105.png) :::success Triplet Loss的最後一部分是提到,如果在訓練過程中如果A和N是隨機選擇的兩個不同的人,那麼這個數字就會比這個數字左邊的餘量α大得多。所以,神經網絡不會從中學到很多東西。所以要構建一個訓練集,你想要做的是選擇讓神經網絡難以訓練的三元組A,P和N,如果你選擇A,P和N的值,那麼d(A,P)實際上可能非常接近d(A,N),那麼這個三元組就是困難的。所以在這種情況下,學習算法必須加倍努力,把這個東西放在右邊,並試圖推動它,或者把它放在左邊,然後試著推下來,這樣至少有一個alpha之間的餘量左側和右側。讓這些Triple的效果提高了學習算法的計算效率 ::: ![](https://i.imgur.com/U1gSAzp.png) :::info 臉部辨識也可以作為一個直接的二元分類問題。訓練一個神經網絡的另一種方法是將這對神經網絡帶到這個Siamese Network,併計算這些維度,可能是128維,甚至更高,然後將它們輸入到邏輯回歸單元然後只是做一個預測。如果兩個人是同一人,那麼目標輸出將是1,如果這兩個人都是不同的人,則目標輸出為0。所以,這是一種將臉部辨識視為二元分類問題的方法。這是培訓這樣一個系統的Triplet Loss的替代方案。那麼這個最後的邏輯回歸單元究竟做了什麼呢?輸出是一個sigmoid函數,應用於一些功能集,而不僅僅是饋入,這些編碼,你可以做的是採取編碼之間的差異。所以,讓我告訴你我的意思。比方說,我寫了一個超過K的總和等於1到128的絕對值,在兩個不同的編碼之間採取element wise方式,然後我們將看到這意味著什麼。在這個符號中,xi的f是圖像xi的編碼,k意味著只選擇該向量方向。這是兩個編碼之間的元素Y的絕對值差異。而你可能要做的就是把這128個數字看做是你進入邏輯回歸的特徵。而且,你會發現可以有更多的參數w,i和b類似於正規邏輯回歸。而且你還要訓練適當這128個特徵,以預測這兩個圖像是同一個人還是不同的人。所以,這將是一個非常有用的方法來學習預測0或1個是否是同一個人或不同的人。關於如何計算我以綠色強調的公式,還有一些其他的變化。如綠色筆寫的公式。最後,要提一下,這計算技巧可以顯著幫助神經網絡部署,也就是說,如果這是一個新的圖像,那麼這是一個員工走在希望的門口將為他們打開的旋轉門,這是從你的數據庫映像。然後,不必進行計算,您可以在其中進行預先計算,因此,當新員工進入時,您可以使用此上層組件來計算該編碼並使用它,然後將它與預先計算的編碼進行比較,然後使用它進行預測。因為您不需要存儲原始圖像,而且因為如果您擁有一個非常龐大的員工數據庫,則不必每次都為每個員工數據庫計算這些編碼。這種免費計算的想法,其中一些編碼可以節省大量的計算。這種類型的預先計算適用於這種類型的連體中央架構,在這種架構中,將臉部辨識視為二元分類問題,當您學習編碼時,可能使用最後幾個影片中描述的Triplet Loss。所以,你剛剛看到的這個版本,把臉部辨識作為一個二元分類問題來處理,這樣做效果也不錯。希望你現在知道,是否需要訓練你自己的臉部驗證系統,或者你自己的臉部辨識系統 ::: ![](https://i.imgur.com/4gAf9hr.png) :::info 最近ConvNet最有趣和令人興奮的應用之一是Neural style transfer,將使用C來表示內容圖像,S表示樣式圖像,G表示您將要生成的圖像,例如你有一張圖片希望有梵谷畫風,輸出的結果就變成一幅有梵谷風格的圖片出來,在接下來的幾個視頻中你將學到的是如何自己生成這些圖像。為了實現神經風格轉換,您需要查看ConvNet在ConvNet的各個層次(淺層和深層)提取的特徵。在深入了解如何實現神經風格轉換之前,我想在下一個影片中試圖讓您更好地理解一個ConvNet的所有這些層真正計算過程的概念 ::: ![](https://i.imgur.com/HCjzy3K.png) :::info Deep network 是如何學習的呢?讓我們從第1層中的一個隱藏單元開始。假設您掃描了您的訓練集,通過你的神經網絡暫停你的訓練集,並找出最大化該特定單位激活的圖像是什麼。現在,請注意,第1層中的隱藏單元只會看到神經網絡中相對較小的一部分,會發現它正在尋找一個像這樣的邊或一條線,但隨者層數越往後面,你會看到特徵或模式正在檢測更複雜的東西,使用的所有例子都來自這篇[論文](https://cs.nyu.edu/~fergus/papers/zeilerECCV2014.pdf)有興趣的人可以點進去看一看,這邊主要讓你更直觀地了解神經網絡的淺層和深層,接下來,讓我們用這個直覺開始構建一個神經風格的傳輸算法 ::: ![](https://i.imgur.com/Kxvoqsg.png) :::info 要構建神經風格轉移系統,我們為生成的圖像定義一個成本函數。通過最小化這個函數,你可以生成你想要的圖像。記住問題的表述是什麼。你給了一個內容圖像C,給定一個樣式圖像S,你的目標是產生一個新的圖像G,我們將定義這個成本函數的兩個部分。第一部分被稱為內容成本(content cost)。這是內容圖像和生成的圖像的功能函數,它所測量的是測量生成圖像的內容與內容圖像C的內容之間相似程度。然後將其加上樣式成本(style cost)函數現在是J(S,G)的一個函數,它所表示的是測量圖像G的風格與圖像S的風格相似的程度。最後,我們將用兩個超參數alpha和beta來加權以指定相對內容成本和樣式成本之間的權重。使用兩個不同的超參數來指定權重的相對成本似乎是多餘的。一個超參數似乎是足夠的,但神經風格轉移算法的原始作者使用兩個不同的超參數,而在這邊僅是依照[論文](https://www.robots.ox.ac.uk/~vgg/rg/papers/1508.06576v2.pdf)裡面做的作法來解釋 ::: ![](https://i.imgur.com/BiuY0H0.png) :::info 算法運行的方式如上,必須找到G的成本函數J以便實際生成一個新的圖像,你所做的是以下內容。你會隨機初始化生成的圖像G,所以它可能是100×100×3或500×500×3或任何你想要的尺寸。然後,我們將定義上一張幻燈片中G的成本函數J。你可以做的是使用梯度下降最小化這個。這裡有一個例子,假設你從這個內容圖像和這個樣式圖像開始。這是另一個可能的畢加索樣式。然後當你隨機初始化G,你的初始隨機生成圖像就是這個雜訊圖像,因為每個像素值隨機選擇。在運行漸變下降時,通過像素值將G的成本函數J最小化,這樣就可以慢慢地獲得一個圖像,它越來越像您的內容圖像以您的風格樣式呈現。在本視頻中,您看到了神經風格轉換算法的整體輪廓,您可以在其中為生成的圖像G定義成本函數並將其最小化。接下來,我們需要了解如何定義內容成本函數以及樣式成本函數 ::: ![](https://i.imgur.com/PfzTyij.png) :::info 而現在你要測量給定的內容圖像和生成的圖像它們在內容上有多相似,因此,我們將在第l層隱藏單元激活之間的元素方面的差異,當你通過內容圖像時,與傳遞生成的圖像時相比,並採取平方。而且你可以在前面有一個標準化常數,但這並不重要,因為這可以通過先前提到的超參數α進行調整。所以這兩個激活之間的差異僅僅是元素方式的總和。但是它實際上只是層1中激活之間的差異的平方和,也就是C和G中的圖像之間的差異的平方和。所以,當稍後在J(C,G)上執行梯度下降以嘗試找到總體成本低的值,使這些隱藏層的激活類似於你得到的內容圖像,所以這就是你如何定義神經風格轉移的內容成本函數。接下來,讓我們繼續進行風格成本函數 ::: ![](https://i.imgur.com/raisYGI.png) :::info 所謂的style,就是你可以挑選CNN其中的某一層來做為style的定義。用它來measure。衡量style是否相似等。所以你可以拿這一層的activations來做style相似性的比對。 要定義style,例如我們可以拿這一層的前兩個channel,一個channel裡面的單位點跟另一個channel相同位置的單位點比較相關性。以下圖為例,紅色channle對應的視覺化圖片是中上那塊,黃色是左中那塊。 紅色channel傾向找出垂直條紋,黃色channle傾向找出橘色色調。如果,我們發現這兩個channel是高度相關的,那麼就表示如果有一些垂直線條,那麼就會伴隨著出現橘色色調。如果我們發現其實這兩個channel不相關,那麼就表示有垂直線條時,它可能不會有伴隨著橘色色調出現。 所以相關性可以告訴你這些特微紋理會不會在image裡某部份伴隨著一起出現,並且,這樣可以用來做為測量紋理常出現的頻率,或紋理之間常伴隨出現的頻率,或不會常伴隨出現的頻率。所以,我們就可以用這個相關性來做為這張圖片的風格定義。 如此,我們就可以用同樣的方式,來找出Generated Image裡面這兩個channel的紋理相關性,來比較style image跟generated image的風格相似性。 所以接下一節就將這個概念實作出來。 ::: ![](https://i.imgur.com/lT6F23c.png) ![](https://i.imgur.com/SHghusk.png) :::info 我們假設紅色神經元對應於試圖弄清楚是否在這個特定的小垂直紋理在第二個位置,讓我們說這個第二個通道,這個黃色的第二個通道對應這個神經元,它隱約地尋找橙色色塊。這兩個渠道高度相關是什麼意思?那麼,如果它們高度相關,那麼意味著圖像的任何部分都有這種細微的垂直紋理,那麼圖像的那一部分可能會具有這些橙色色調。這對他們來說意味著什麼?那麼,這意味著只要有垂直的紋理,它可能不會有橙色色調。因此,相關性告訴你哪些高級紋理成分傾向於在圖像的一部分中出現或不出現,這就是相關程度,它給出了一種測量這些不同的高級特徵(如垂直紋理或這種橙色色彩或其他事物,它們發生的頻率以及它們在一起發生的頻率,而不會一起發生在圖像的不同部分。因此,如果我們使用頻道之間的相關程度作為風格的衡量標準,那麼您可以做的是衡量您生成的圖像中第一個頻道與第二個頻道相關或不相關的程度,你在生成的圖像中這種類型的垂直紋理多久出現或不會出現在這個橙色的色調,這給你一個測量圖像樣式與輸入樣式圖像的樣式有多相似 ::: ![](https://i.imgur.com/nEYaRiP.png) :::info 所以style相似度,我們可以實作的方式是,可以給一個image一個叫Style matrix風格矩陣的東西。這個將衡量我們在上面所說的所有相關性的東西。 公式裡l表示某一個隱藏層,i,j,k分別對應上圖的H,W,C位置index,即高、寬、channel位置等。例如上張圖有5個channel,k將可以到5。 Style matrix 要做的就是去計算出一個G,G是一個nc*nc的矩陣,是一個方陣。記得我們有nc5個channel,channel跟channel之間要去算相關性,所以有5*5維矩陣來衡量它們之間如何相關聯的。用k來做為channel的index所以是1~5。 而如何計算$G_{k,k'}$的方式,是使用總和的做法,所以你會看到他將同h,w位置的兩個k, k'的activation做相乘。然後加總起來。最後這個G就是**風格矩陣** 加總的原因是,因為如果這兩個activation都常常伴隨,那麼加起來就會很大,反之如果他們都不相關,那麼則會較小。 (S),(G)則表示style 與 generated image,在數學裡,我們用的G矩陣也稱為**gram matrix** 而cost function J,就如上圖下方所示,對兩個G矩陣做差異處理。如下詳細。 ::: ![](https://i.imgur.com/tWxDDS6.png) :::info 有了單層的cost function,再將所有l加起來,然後再套上更上一層的cost function(如上面一開始講的),最後達成最終的cost function. ::: ![](https://i.imgur.com/fvAxa3H.png) ![](https://i.imgur.com/b4i0CYs.png) :::info 儘管大部分的討論都集中在圖像上,但是在二維數據上,因為圖像是非常普遍的。事實證明,你學到的許多想法也適用於2D圖像,也適用於一維數據以及三維數據,例如心電圖。基本上,如果你把一個電極放在你的胸部,這就可以測量胸部隨著你的心臟跳動而變化的微小的電壓。因為心臟跳動產生的小電波可以用一對電極測量。所以這是某人心跳的心電圖。所以每個峰值對應一個心跳。因此,如果您想使用EKG信號進行醫療診斷,那麼您將擁有一維數據,因為EKG數據是什麼時間序列顯示每個瞬間的電壓。所以,而不是一個14×14的尺寸輸入,也許你只是有一個14維的輸入。你發現一個14維度與這個5維的卷積,這會給你一個10維的輸出。而且,如果你有多個通道,那麼你可能只需要一個通道,在那裡10×16,這可能是你的ConvNet的一層。然後,對於ConvNet的下一層,如果輸入10x16維的輸入,則可以再次使用5維濾波器進行卷積。然後這些有16個頻道,所以有一個匹配。而我們有32個過濾器,那麼如果你有32個過濾器,那麼另一個層的輸出將是6×32,與2D數據類似,這與10x10x16的所有數據類似,並將其與5 x5x16的數據進行卷積,並且必須匹配,可以參考前面的Multiple filters 的概念,同理3D數據的情況也是一樣的 ::: :::warning 3D的做法,也可以套用而影片來做。 ::: :::success 實作題: * compute_content_cost 部份: * 注意相減使用 tf.subtract,且裡面兩個參數是逗號隔開,不要用到減號。 * reshape注意題意是要 a_C -- tensor of dimension (1, n_H, n_W, n_C),所以m似乎可以替換為1。因為呼叫此函式時是以for迴圈呼叫,所以在函數內不考慮m的情況。基本上這部份還不會有什麼問題。 * gram_matrix 部份: * 注意這裡做的是純粹的$A$ * $A^T$,也就是二維乘二維,所以不需考慮太多。 * compute_layer_style_cost 部份: * 注意reshape時的要求跟上面一樣,都不會用到m,也就是輸入是單一層的,所以就直接依題意使用n_H*n_W, n_C的形式reshpe,再將n_C轉形拉到前面即可。m的部份不考慮是因為外部呼叫時會用for迴圈處理。 triplet_loss: pass answer : 350.026 此答案是沒有加axis=-1的,但仔細回想應該是pos_dist和neg_dist要留下一樣的訓練集個數並與alpah相加,然後才把大於0的值全部數值相加得loss function值,所以應該是原本的結果輸出528.143才對 compute_layer_style_cost: 注意這邊要求的是n_C, n_H*n_W 而不是上題的n_H * n_W, n_C 如果覺得實作內的跑太慢,查看到有別人照論文所做快速版 neural style transfer,開GPU下去跑大概一輪五秒內完成 https://github.com/jcjohnson/fast-neural-style ::: :::info 實作題 model_nn 部份: > 我無法確認自己寫的code是否正確,這裡給出我寫的部份,大家可以檢查,如果有錯請再跟我說。_Jason ``` def model_nn(sess, input_image, num_iterations = 200): # Initialize global variables (you need to run the session on the initializer) ### START CODE HERE ### (1 line) sess.run(tf.global_variables_initializer()) ### END CODE HERE ### # Run the noisy input image (initial generated image) through the model. Use assign(). ### START CODE HERE ### (1 line) sess.run(model['input'].assign(input_image)) ### END CODE HERE ### for i in range(num_iterations): # Run the session on the train_step to minimize the total cost ### START CODE HERE ### (1 line) sess.run(train_step) ### END CODE HERE ### # Compute the generated image by running the session on the current model['input'] ### START CODE HERE ### (1 line) generated_image = sess.run(model['input']) ### END CODE HERE ### # Print every 20 iteration. if i%20 == 0: Jt, Jc, Js = sess.run([J, J_content, J_style]) print("Iteration " + str(i) + " :") print("total cost = " + str(Jt)) print("content cost = " + str(Jc)) print("style cost = " + str(Js)) # save current generated image in the "/output" directory save_image("output/" + str(i) + ".png", generated_image) # save last generated image save_image('output/generated_image.jpg', generated_image) return generated_image ``` ::: :::info 實作題2: * triplet_loss 部份: * 依題意實作不難,注意axis=-1是用在reduce_sum上。 * 第四步依題意也要進行reduce_sum。但注意不需axis參數。 * 這裡使用axis=-1的答案雖然test結果正確,但送出後會指示error,得不到分數。如果把axis=-1拿掉,就可以通過得分。但似乎使用axis=-1才是正確的,這應該是題目驗證上的bug。 * verify 部份: * 第一步如題目先前的例子去使用,model就用函式代進來的,不要直接用FRmodel。 * 第二步要算距離,由於第一步已先求到一個向量,所以第二步就把這個向量拿來算距離,而要計算的對像就是從database而來,索引即函式的參數有給的取出一個向量來,然後兩個就可以算距離。 * 注意由於這裡不是tensorflow,不要混淆,這裡應該用原始numpy算法來算距離,且注意不需要再進行一次平方,如題目所提示的。 * who_is_it 部份: * 大致上差不多,只是改成每一個database裡面的人都檢查,找出最小距離符合門檻的。 * 這裡注意min_dist從100開始。 * for迴圈要使用database.items()來取。不能直接用database這個參數。 :::