DeepLearning.ai on Coursera 學習心得
去年九月很幸運在前同事的幫忙下,轉到公司內部的 Applied Data Science team ,開始接觸 Deep Learning 和 Natural Language Processing,同時也在隔週週二晚上遠端參加紐約台灣工程師 fast.ai 的讀書會。雖然在學校做過幾個小的 machine learning project,但其實我對 Deep Learning 可以說是完全沒經驗:聽同事解釋我們用來做 text classification 的 Very Deep Convolutional Networks(VDCNN)完全是鴨子聽雷;fast.ai 提倡的 top down learning 對我也不是很適用,也許是亞洲教育考試體系的訓練下我還是偏好 bottom up、有架構的學習(最好再搭配個考試,哥德斯爾摩症發作?)。
因此,我當時想找一個有系統的課程,把 Deep Learning 知識的基礎打好。從去年十月開始,我用下班時間上 Andrew Ng 開的 Deep Learning Specialization 。總共五堂課,每堂課分成三~四週,總共 16 週的課程內容包含上課影片、小考和程式作業,到今年三月才總算上完了(12 月基本上荒廢,平常下班也很常看上課影片看到睡著,或是把 Netflix打開就回不來了)。前兩堂課講的是基本的 Neural Networks ,影片裡沒有太強調數學公式背後的證明,但大學程度的微積分(derivitives, chain rule)、統計和線性代數(dot product, matrix manipulation)要應付綽綽有餘 。課程四和五教的是比較進階的 network,很多內容是來自學術論文,很常看完影片還是沒有概念,做作業的時候看到實際的 implementation 才比較有感覺。
第一堂課從最基本的 Logistic Regression 開始談起,從一個這麼基礎的 network,解釋 feedforward 和 back-propagation、Loss function (cross-entropy 的數學式證明跳過)怎麼計算也就一目瞭然了。
但這堂課也不純粹走學術風,在 production 的現實世界裡,運用 Vectorization(Python Numpy API),可以把 iterative 的計算轉化成平行運算,大幅縮短訓練時間。例如: z = np.dot(w, x) (w, x 皆是 dimension = n_x 的 vector)等同於取代 for i in range(n_x dimensions): z += w[i] * x[i] ,基本是就是盡可能避免用 for loop 來做運算。其他例子像 apply operation on every element of a vector: np.exp(v), np.log(v), np.abs(v), np.maximum(v, 0) 也是同理。
我們可以用 Vectorization 來計算 Logistic Regression 的 cost 和 gradient(這邊的數學式證明跳過):
# FORWARD PROPAGATION (FROM X TO COST) A = sigmoid(np.dot(w.T, X) + b) # compute activation cost = (- 1 / m) * np.sum(Y * np.log(A) + (1 - Y) * (np.log(1 - A))) # compute cost # BACKWARD PROPAGATION (TO FIND gradient) dw = (1 / m) * np.dot(X, (A - Y).T) db = (1 / m) * np.sum(A - Y)
同樣強大的 Broadcasting 是 Python 提供的另一個 API,讓你可以自由的運算 matrix,例如:A.sum(axis=0) 的 output 是加總每一排(sum vertically)後的 vector。
更多例子:
這堂課的程式作業是不用任何 framework,只用 Python/Numpy API 來建 Neural Network,先從兩層(1 hidden layer)開始再到多層(n-1 hidden layers)。每層 hidden layer 搭配一個 non-linear activation function(tanh, ReLU, 或 sigmoid),步驟和架構圖如下(source: Programming Assignment — Building your Deep Neural Network — Step by Step):
1. Define the neural network structure (# of input units, # of hidden units, etc). 2. Initialize the model's parameters 3. Loop # of iterations: - Implement forward propagation - Compute loss - Implement backward propagation to get the gradients - Update parameters with gradient descent (using parameters, and grads from backprop) 4. Use trained parameters to predict labels
這堂課講的是 Deep Learning 的核心,在之後的幾堂課裡,不管模型怎麼變化,基本上都是從這幾個步驟做延伸。而現在 deep learning 的 frameworks 中,你只需要 implement forward pass, framework 自動會幫你處理 backward pass 的部分。
這堂課在前一堂的基礎上,怎麼用 L2 Regularization, Dropout, normalization, BatchNorm(scale the hidden units in same layer) 來避免模型 overfit、怎麼用 gradient descent, RMSprop, Adam optimization 來加速 training。
這堂課教的概念實際應用在 framework 中,可能都只是一行或是一個模型參數,但實際 implement 一遍,對於了解、 debug 一個模型也會有幫助。
這堂課主要是經驗談,key take away 就是時間資源要花在刀口上,幾個原則可以記下來,像是列出 human-level performance、training error、test error,來判斷模型是 overfit(hight bias)或 underfit(high variance)。但這堂課也沒有程式作業,所以基本上就是速速掃過。
到目前為止,前三堂都是介紹 Fully connected layer,這堂課介紹了 convolution 和 pooling layer。CNN 主要應用在 image processing 上,但也可以用來處理 text。CNN 最基本的概念是,不像 Fully connect layer,CNN 把 input volume 跟 filter(或 kernel) 做內積( dot product),這個方法的好處除了減少參數量,更重要的是讓 network 學習過的 feature 可以 generalize 到 input volume 的其它地方。做內積有幾個參數可以調整,包含kernel size 代表 filter 長寬有幾格、stride 代表 filter skip 多少格、padding 代表 filter 周圍外層要加上幾圈 zero。每個 filter 代表一個 feature detection(detect patterns 例如:vertical edge、horizontal edge…),而每個 convolution layer 可以有多個 filter(= output volume depth)。
Pooling layer 相較之下簡單很多,通常用來縮小 input volume 的 height 和 width、減少計算量,常見的兩種 pooling layers 包含 max pooling 和 average pooling。
綜合這三種 layers,我們可以建 AlexNet 和 VGG-16。這兩個都是有幾十甚至幾百層的 network,這些大型的 network 好處是深層的 layers 可以學習更複雜的 feature,但缺點是深層網路容易導致 vanishing gradients,讓 gradient descent 變得很慢或誤差增大。為了避免這些,我們可以用 Residual Block 來建 identity function 捷徑(skip connection),用捷徑把 layer i 的 activation 加到 layer i + 1 activation 之後和下一個 ReLU 之前,所以 a[i] = a[i + 2]。這樣可以把深層的 loss 更完整的傳遞给淺層、避免 activation layer 退化過快,同時又能降低計算量。(paper: Deep Residual Learning for Image Recognition )
除了思考怎麼組合這三種 layer,你也可以讓 network 自己 train 需要多少 filter、filter 的參數多少,這個架構叫 Inception network。
但就算利用這些方法,有時候 network 還是太大、或是資料不夠,transfer learning 讓我們可以在別人 train 好的 pre-train model 上 freeze params 成 feature vector,再用你自己的 softmax output 取代最後一層 softmax output layer,讓 network classify 你想要的 class。
常見的 CNN 應用包含物體辨識(landmark detection, bounding box, anchor box) 、人臉辨識(one shot learning, Siamese network, triplet loss)和 neural style transfer。
最後一堂課是我最有興趣的,這堂課從 Recurrent Neural Network(RNN) 開始介紹起,不同於之前的 network,Sequence models 解決了無法預期 predict output 長短的問題。 RNN 有 time step 的概念,也就是前一個時刻的 activation value 會成為這一刻 input 的一部份,network 的預測於是就有了前後文的概念。
RNN 用 input/output architecture 來分有以下幾種類型:
- 多對多:如 name entity recognition(input size = output size)
- 多對多 with encoder and decoder (input size != output size):如 machine translation;
- 多對一如 language model and sequence generation
- 一對多 如 music generation
- (一對一,其實跟 generic neural network 無異)
實際應用的時候很少人會用純 RNN cell,因為容易遇到 vanishing gradients 的問題和不擅長取得 long range connections。使用 GRU 、 LSTM/Bi-LSTM(實際應用中最常見)cell 可以改善這兩個問題、幫助 network 選擇哪些 context 在此刻需要納入考慮(forget/update gate),以幫助模型做預測。
做圖像辨識的時候直觀上可以理解用 RGB 值當成 input,但做 text 的時候 input 應該是什麼呢?常見的做法是用 word embedding,也就是 train 每個字的 feature representation,feature 我們可以想像成是一個概念(number of features = size of embedding vector),可能的 feature 像是 gender, age, color ⋯, feature representation 相似的字更可能代表類似的概念,反之亦然。NLP task 像 name entity recognition、text summarization 常見的作法是用巨大資料量 pre-train 好的 word embedding,再做 transfer embedding 到特定領域的資料上(embedding matrix 的 dimension 為 number of features 乘上 size of vocabulary)。
要怎麼 learn word embedding 呢?最直觀、計算量也最複雜的做法是 neural language model,核心概念是透過統計訓練每個字在各種 context 之下出現的頻率来逼近在新的句子中出現的機率。實際的做法是給定 training set 中的一段文字,用每個字對應的 embedding vector 為 neural network 的 input,再用 softmax 預測下一個字最可能為何(paper: A Neural Probabilistic Language Model ),過程中 neural network 會 train 相似概念或用法的字 A 和字 B 擁有類似的 embedding vector,因為 training set 的類似的句子有時 predict 字 A 有時 predict 字 B 。
但這個做法計算量非常大,隨著下上文增加,可能的字組合會呈指數成長;training set 也不可能涵蓋所有可能的組合,而要存這些频率所需的空间也是指數成長。優化的方法包含 Word2Vec(Skip-gram:給定 input target word,用 softmax 預測出現 context word 的機率 P(target|context),cost function 是最小化所有 softmax 預測錯誤的 context words) 。但由於要 sum up 所有 softmax 的結果是 O(N=vocab size) time complexity,加上 unbalanced training set,不同的字的出現次數有很大的差異,我們可以用 hierarchical softmax(把原本的 output vector 轉化成 binary tree,每個節點代表一個字和其 softmax 的值,出現頻率高的字放在上層可以减少計算量,且加速 time complexity 成 O(logN)) 和 Negative sampling(隨機取幾個 non-target word 來做 training,這樣每個 training iteration 只會更新 target word 和那幾個 non-target word embedding vector,而不是整個 vocabulary set)來再優化。
最後是逐漸成為主流的 Attention mechanism,Attention 其實就是一個 weighting vector(通常是softmax output),dimension 等於 context 的長度;weighting 越大代表对應位置的context 越重要。
課堂裡沒有提到的是 Transformer 模型( paper: Attention is all you need),它把attention mechanism 從配角移到主角的位置,沒有 CNN 或 RNN,而是完全使用attention encoding。CNN 訓練的是局部的 feature,但是忽略了長距離的 dependency,所以 encoding 能力低於 RNN;但 RNN 平行運算能力差,而 Transformer 同時補足了這兩個缺點。Google 最新提出的 BERT 就是用 Transformer encoding。
雖然上完這系列的課讓我對 Deep learning 有粗淺的理解,但怎麼應用在工作中還是有待商榷(主要都還在做 backend 和 infra work 囧)。現在 Deep learning 已經發展到網路上有很多現成的 pre-trained model 可以用,讓一般軟體工程師在不用知道太多模型細節狀況下,就可以應用 Deep learning 在不同的 use case中,也許機器學習未來將會成為一般軟體工程師日常工作的一部份。
Originally published at http://pretteyandnerdy.wordpress.com on March 25, 2019.