跳到主要內容

[Development] Deep Learning over Python 深度學習基於 Python 2/3

  用 Python 練習實作深度學習,主要包含 Tensorflow 以及 SVM,著重於實作範例,未深入涉及各 DL 演算法模型原理及其數學。

大綱

[Development] Deep Learning over 深度學習基於 Python Python 1/3
  • Basic Tools: 基於 python- numpy, matplotlib, scipy, Pandas
[Development] Deep Learning over Python 深度學習基於 Python 2/3
  • Keras (基於 Tensorflow) ,使用
    1. Sequential 模型(範例實作 "MINST 手寫辨識")
    2. CNN (Convolutional Neural Networks) 卷積神經網路(範例實作 "MINST 手寫辨識")
    3. RNN (Recurrent Neural Networks) 遞歸(迴)神經網路(範例實作 "IMPb 評論辨識")
  • Tensorflow
    1. 基礎應用
    2. NN 基本作用原理
    3. CNN (Convolutional Neural Networks) 卷積神經網路(範例實作 "MINST 手寫辨識")
[Development] Deep Learning over Python 深度學習基於 Python 3/3
  • Support Vector Machine (SVM)
  • 強化學習 Reinforcement Learning (RL)

Reference: 本篇基於 Udemy 課程 "吳佳諺- Python 深度學習" 為架構出發衍生,其他引用資料個別在段落中標示

Keras

Keras 是一个用 Python 编写的高级神经网络 API,它能够以 TensorFlowCNTK, 或者 Theano 作为后端运行
Keras 的核心数据结构是 model,一种组织网络层的方式。最简单的模型是 Sequential 顺序模型,它由多个网络层线性堆叠。对于更复杂的结构,你应该使用 Keras 函数式 API,它允许构建任意的神经网络图

本篇即將進行的 Keras 範例即是以 TensorFlow 為後端支持
本篇所提供的範例 source code 為 Python Jupyter Notebook 文檔,須下載後載入 Jupyter 環境查看。

1. Sequential 順序模型

  Sequential 順序模型是最基本的模型,一個輸入層,數個隱藏層,最末一層為輸出層。
  輸入層即為 input 的 raw data。
  中間的隱藏層可以有數層,每一層都可以有數個神經元,每個神經元可以想做一個「特徵」。每層的神經元都是對下一層的神經元做投票 (weighting),也就是每一層的特徵對下一層的特徵做投票。因此整個從 in 到 out 的過程在概念上就是將 input 的 raw data 解析成各種特徵,各種特徵再進一步解析/合成成各種特徵。「 學習」或者說「訓練」的過程其實就是在嘗試找出,每一個特徵之間對於彼此的「影響」以及對於最終「判斷」結果的「幫助」程度。
  如此訓練出來的模型就可以實際拿來做使用的時候,對於即時的 input 先做特徵解析,然後依據各特徵符合與否,再加入考量各特徵的重要程度,去做投票,最終得出該 input 是否符合某 output 的信心程度。

  概念的部分先到這裡,先直接還看個實作例子,目的在揭示在 Keras 套件的幫助下,因為他已經封裝了底層的 API,所以可以非常方便迅速的完成這個循序模型的建立。

範例:MNIST 手寫數字辨識
  Source code: Jupyter file Minst_keras_sequential.ipynb
Keras 的官方文件有詳細的 API 使用說明 https://keras.io/zh/getting-started/sequential-model-guide/

2. CNN (Convolutional Neural Networks) 卷積神經網路

  卷積神經網路在圖像和語音辨識方面能夠給出更好的結果,是目前深度神經網路 (deep neural network) 領域的發展主力。
  相比於最基本的順序模型,CNN 是在「特徵」解析的部分提出一道方法。也就是我們一定會有的疑惑,讓「特徵」根據個別重要性去做「投票」這概念大概可以理解,但怎麼讓機器能夠把資料的「特徵」一一抓出來呢?
  CNN 所提出的方法即是對於圖像辨識和語音辨識特別有效,也就是說對於圖像辨識和語音辨識這兩種應用,CNN 提出一種有效的特徵提取方法。

  descriptions below are collected from ref: https://brohrer.mcknote.com/zh-Hant/how_machine_learning_works/how_convolutional_neural_networks_work.html
  you may go to the link to see the complete article with pics accordingly.
  • 在比對圖片時,如果有任何一個格子的值不相等,電腦就會認為兩張圖不一樣。理想上,我們希望不管在平移、縮小、旋轉或變形等情況下,電腦都能正確判斷符號。這時 CNN 就派上用場了
  • 卷積層(convolution)
    • CNNs 會比較兩張圖片裡的各個局部,這些局部被稱為特徵(feature)。比起比較整張圖片,藉由在相似的位置上比對大略特徵,CNNs 能更好地分辨兩張圖片是否相同 
    • 比如一個 X 符號,可以進一步切割成幾個特徵小圖,i.e. 左斜線、右斜線、中間的小 x。
      考量平移、縮小、旋轉或變形的情境,CNNs 需要把這些小特徵去和整張圖的各個局部做比對,以辨認出比如左斜線這個特徵在某張圖是不是被位移到了靠中間的位置 
    • 其中的評估計分方式就是「卷積」:要計算特徵和圖片局部的相符程度,只要將兩者各個像素上的值相乘、再將總和除以像素的數量。
      如果兩個像素都是白色(值為 1),乘積就是 1 * 1 = 1;如果都是黑色(值為 -1),乘積就是 (-1) * (-1) = 1。也就是說像素相符的乘積為 1,像素相異的乘積為 -1。如果兩張圖的每個相素都相符,將這些乘積加總、再除以像素數量就會得到 1;反之,如果兩者的像素完全相異,就會得到 -1 
    • 根據每次卷積的值和位置,製作一個新的二維矩陣。值越接近 1 的局部和該特徵越相符,值越接近 -1 則相差越大,至於值接近 0 的局部,則幾乎沒有任何相似度可言
    • 也就是最終 比如一個 X 符號,可以進一步切割成 3 個特徵小圖 左斜線、右斜線、中間的小 x,那就會得到 3 個新的二維矩陣,這 3 個新的二維矩陣分別代表了這三個特徵在此張圖每一個局部的符合程度,矩陣中的元素值越接近 1,代表該局部和該特徵越相符,值越接近 -1 則相差越大,值接近 0 的局部則幾乎沒有相似度
  • 池化層(pooling)
    • 池化是一個壓縮圖片並保留重要資訊的方法
    • 池化會在圖片上選取不同窗口(window),並在這個窗口範圍中選擇一個最大值。實務上,邊長為二或三的正方形範圍,搭配兩像素的間隔(stride)是滿理想的設定
    • 最終我們會得到一樣數量、但包含更少像素的圖片。這也有助於改善耗費運算問題
    • 池化後的資訊更專注於圖片中是否存在相符的特徵,而非圖片中哪裡存在這些特徵。這能幫助 CNN 判斷圖片中是否包含某項特徵,而不必分心於特徵的位置
    • 也就是最終 比如一個 X 符號可以進一步切割成 3 個特徵小圖 左斜線、右斜線、中間的小 x,我們可以只關心左斜線是否有出現在整張圖的右上角,而不用細緻到他是出現在右上角的最最角落還是有一點偏
  • 線性整流單元(Rectified Linear Unit,ReLU)
    • 將圖片上的所有負數轉為 0。這個技巧可以避免 CNNs 的運算結果趨近 0 或無限大
  • 全連結層(fully connected layers)
    •  本層就是在做循序模型做的事情,讓各特徵依其 weighting 做投票

      反向傳播(back propagation)
    • 特徵從何而來?以及在全連結層中,我們該如何決定權重?
    • 為了使用反向傳播,需要先準備一些已經有答案的圖片。接著準備一個未經訓練的 CNN,其中任何像素、特徵、權重和全連結層的值都是隨機決定的。然後就可以用一張張標好的圖片訓練這個 CNN
    • 經過 CNN 的處理,每張圖片最終都會有一輪決定類別的選舉。和之前標好的正解相比,這場選舉中的誤判,也就是辨識誤差,可以告訴我們怎樣才是好的特徵跟權重。我們可以透過調整特徵和權重,讓選舉所產生的誤差降低。在每次調整後,這些特徵和權重會被微調高一點或低一點,誤差也會被重新計算,成功降低誤差的調整將被保留。所以當我們調整過卷積層裡的每個像素、和全連結層裡的每個權重以後,我們可以得到一組稍微更擅於判斷當前圖片的權重。接著我們可以重複以上步驟,辨認更多已標記的圖片。訓練過程中,個別圖片裡的誤判會過去,但這些圖片中共通的特徵和權重會留下。如果有夠多的已標記圖片,這些特徵和權重的值最後會趨近一個擅於辨識大多數圖片的穩定狀態
  所以可以發現,如果行和列的位置並不重要,也就是說在不影響資訊的情況下,它們可以被任意排列,資料不會受改變行列順序所影響,這種資料就不適合使用 CNN 處理。不過如果可以將問題轉成類似圖片辨識的形式,那 CNN 很可能是最理想的工具。

  上面我們大概了解了 CNN 的基本原理和模型架構,這裡就一樣用 MNIST 手寫辨識這個應用作為例子,因為他就是一個典型的圖像辨識的應用,應用 Keras 提供的 CNN API 來實作
範例:MNIST 手寫數字辨識
  Source code: Jupyter file Minst_keras_cnn.ipynb

3. RNN (Recurrent Neural Networks) 遞歸(迴)神經網路

  序列到序列翻譯(sequence to sequence translation),包括將語音轉為文字或翻譯不同語言,多利用遞歸神經網路,尤其是長短期記憶模型(long short-term memory,LSTM)

  RNN 的基礎概念在此篇文章有很簡單明瞭的解釋 https://brohrer.mcknote.com/zh-Hant/how_machine_learning_works/how_rnns_lstm_work.html,因為要搭配圖片比較好了結,這裡就沒有再做節錄了。

  「投票」的概念不變,因為這就是最基礎的機器深度學習架構。所以 RNN 一樣是著墨在「特徵」提取上。RNN 的善於處理的命題可以說是與「時間前後」有關的命題,比如「語言」就是,我們學英文的時候總是會先學最英文有種最基本的語式是主詞 + 動詞 + 受詞,所以可以說要辨識語句含義,每一個詞彙之間出現的先後關係是一個重要的特徵。
  我們可能已經有一些既有特徵,這些特徵可能是一些個別的客觀事實,所以每一個個別特徵都是一個神經元,這些神經元對於我們要預測的結果有不同的重要程度,以上是循序模型。而 RNN 多導入的一條線就是前一個時間點的預測結果也會成為用來預測後續時間點的結果的 input,也就是後續的時間點所參考的神經元,不只是只有該時間點的客觀事實的那些特徵,還有一個 RNN 帶來的「以前」的資訊去一起做 weighting 投票。

  Google 的 LSTM 基於 RNN,LSTM 模型如何藉著回顧兩個、三個甚至更多循環前的結果,以作出更合理的預測。基礎 RNN 也能回顧幾個循環前的結果,只是沒有 LSTM 這麼多。LSTM 可以成功回顧更多循環前的結果。

  這裡用的範例是 IMDb 的影評辨識,資料庫提供了觀眾對於電影的觀後評價,我們透過機器學習去建立模型來讓機器判斷某則評價是屬於正面評價還是負面評價。
範例:IMDb 影評資料滿意度分析
  Source Code: Jupyter file Imdb_keras_rnn.ipynb


  上述的 CNN 和 RNN 範例都是使用 Keras 函式庫,Keras 是基於 Google Tensorflow 為 NN 演算法的 backend,也就是 Keras 進一步封裝 Google Tensorflow 的 API 以提供更方便快速的使用,但犧牲的就是細節的優化空間,所以以下就會介紹直接使用 Google Tensorflow APIs

Tensorflow

1. 基礎應用

  Variable type, session, place holder, math operation, tensorboard:
  Jupiter file- tensorflow_basic.ipynb

2. NN 基本作用原理

  先講有了模型後是如何達成對數入圖做判斷的,再講模型是如何訓練產生的

預測/判斷

  在數字辨識這個圖像辨識的範例中,下 圖 B-1 為經機器學習訓練後產生的模型的具象化,藍色為正的權重,紅色為負的權重;

圖 B-1

  也就是藍色部分若出現筆畫,則貢獻 positive 投票,紅色部分若出現筆畫,則貢獻 negative 投票。
  可以想像現在有一張新的數字圖,機器要去判斷此圖究竟是哪一個數字,他就會去和這 10 張圖做「相乘」,就會產生 10 個分數。這裡所謂的「相乘」實際上的效果就是,這張新的圖在藍色區域若有筆畫出現,就會有加分的效果;如果在紅色區域有筆畫出現,就會有扣分效果。如此,最後出來的 10 個分數,最高分的那個就會是機器判斷最有可能符合的數字。
  上述為概念的解釋,接下來就看所謂「相乘」的數學部分該怎麼做。因為程式運算當然是要數學,程式沒辦法抽象了解「概念」,需要數學工具去將我們的概念給程式化好讓電腦依此運算。

圖 B-2-1

圖 B-2-2

  上圖 B-2-1, B-2-2
  • x 為各像素
    • 如果今天每張圖是 28*28,也就是總共有 784 像素,就會有 x1 ~ x784
  • W 為權重,可視為圖 B-1 的數學表示型態,也就是矩陣
    • 模型經過訓練後,每個 candidate 都會有一個 W 矩陣,具象化後就是圖 B-1 的 10 個紅藍圖;
      手寫辨識例子總共有 0 ~ 9 共 10 個 candidates,所以也就有對應的 10 個 W 矩陣,具象化後就是圖 B-1 當中的 10 個圖,各 W 矩陣當中各的元素值若為正數即以藍色表示,若為負數則以紅色表示。
      圖 B-1 的具象化圖示可以看出這個訓練結果一看之下有跡可循可以理解
    • 每一個像素 x,在 10 個 candidates 的 W 矩陣中都會有對應的 w 權重值,比如 x2 在 W1 對應的位置的權重值就是以 W1,2 表示
    • 一張 784 像素的圖,去分別乘上 W1 ~ W10,就會得到 10 個矩陣,i.e. W'1 ~ W'10。此 10 個矩陣即可以理解為對於此張 784 像素的圖,10 個 candidates 各別的信心指數。
      因為 W 當中的各元素是以正數代表正面信心,負數代表負面信心,所以若將 W' 中所有元素的值相加,即可代表投票結果,代表對於多有信心此張 784 像素的圖屬於符合自己要求的程度多有信心,i.e.
      W'1 中 784 個元素的值的和即代表對於此輸入圖,符合數字 0 的特徵的信心指數,可視為 y1;
      W'2 中 784 個元素的值的和即代表對於此輸入圖,符合數字 1 的特徵的信心指數,可視為 y2
  •  y1 ~ y10 即為對此輸入圖符合數字 0 ~ 9 的特徵的信心指數,softmax 函數可理解為,為了數學上矩陣運算,可以將 y1 ~ y10 當中值最大者凸顯出來的作用
  更進一步歸納,圖 B-2-2 其實是由下圖 B-3 的矩陣運算而來
圖 B-3
  而圖 B-3 的矩陣運算即可輕鬆藉由 Tensorflow 提供的函式庫 matmul() 和 softmax() 達成,稍後的範例就可以看到。
  上述是電腦已經有了模型之後,怎麼對即時的影像做判斷。接下來要講那模型是怎麼產生的。

模型訓練

  首先要先理解交叉熵的概念,以下說明 Collected from https://ithelp.ithome.com.tw/articles/10187002
  • Cross Entropy 交叉熵
    • 為了訓練模型,必須先定義一下怎樣的模型才是好的模型.在機器學習中,把這個定義稱作成本 (cost) 或是損失 (loss).它代表我們的模型和預期的結果間的差距
    • 我們會嘗試要最小化這些成本,當這些成本或損失越低的時候,就代表著我們的模型越好
    • 最簡單的 loss 函數就是均方平方差 (Mean Squared Error),預測值與真實值直接相減,為了避免得到負數取絕對值或者平方,再做平均就是均方平方差
    • 平方差可以表達預測值與真實值的差異,但在分類問題的效果並不如 Cross Entropy 好。Cross Entropy 是非常常見而且很棒的成本函數,也是 loss 函數的一種
    • y 是預測的機率分佈,而 y' 是真實的機率分佈 (one-hot 數字向量),所以上式 H 就可以理解為是,我們目前的這個模型在這一次做出的判斷錯得有多離譜
  Tensorflow 訓練模型 API 所提供的功能和效果其實就是,可以自動的去計算反向傳遞(backpropagation algorithm)並且調整參數來讓成本(lost)最小化,這裡的成本帶入的就是上面的 cross entropy 去計算,也就是讓 H 最小。並且 Tensorflow 可以讓我們自己選擇要使用哪一個調整參數的最佳化演算法。比如 Tensorflow 提供的其中一個最佳化演算法是,梯度下降法 gradient descent algorithm,用來最小化 cross entropy,它的學習速率 (learning rate) 是 0.5。

  反向傳遞上面已經有解釋過,這裡再更淺白的說一下
  • 反向傳遞(back propagation algorithm)
    • 正向傳遞就是有一函數 y=f(x),把 input x 帶入照著算就可以得到 y
    • 反向傳遞就是透過 y 反求 x
    • 機器學習中的權重 W 就是訓練模型時要訓練的主要對象,怎麼將 W 最佳化就是一個不斷計算反向傳遞的過程。比如先隨便對 W 賦一個初值,得到結果 y,將 y 和預期的正解做誤差計算,然後反向調整 W,要做到這一點則需要知道 W 中的每條線對於此造成誤差的影響力。
    • 此篇文章實際以帶入值走一次反向傳遞過程可以清楚了解其概念 https://www.cnblogs.com/charlotte77/p/5629865.html

實作範例

  我們就一樣以 MNIST 手寫辨識為例,但不使用 Keras 的 API,而是直接使用更底層的 Tensorflow APIs,這裡只有用到基礎的投票概念,也就是說實作的是基本的順序模型
  以 MNIST 為例:Jupiter file- Mnist_tf_sequential.ipynb

3. Tensorflow CNN

  CNN 步驟分析可以往上看 Keras 的部分,這裡只是範例不使用 Keras 的 API,而是直接使用更底層的 Tensorflow APIs 來建 CNN
  以 MNIST 為例:Jupiter file- Minst_tf_cnn.ipynb


繼續閱讀 [Development] Deep Learning over Python 3/3


留言

這個網誌中的熱門文章

[Development] git

本篇介紹幾個 git 會用到的基本 command line 指令 安裝 on Mac OS [tested on macOS Catalina 10.15.1] (可以用 Brew 安裝,若尚未安裝 Brew:  https://brew.sh/index_zh-tw ) $ brew install git $ git --version git version 2.21.0 (Apple Git-122.2)   github 官網就有提供 GUI 的應用 ,想用 GUI 的直接去下載安裝就行了,也有簡單明瞭的教學,非常容易。另外也有好幾個第三方的好用 GUI 介面,Google 一下比較一下選自己喜歡的也行。   但以下還是用 command line 的方法來操作,因為這還是最 general 到哪都可以用的基本方法。因為實務上,比如 code 都放在公司的 server,你可能也是都要 ssh 到 sever 上去改 code,改完之後要上傳到 github。而公司的 server 就是一台 Linux 環境,很可能是沒有提供 GUI 讓你使用的,所以你就只能用 command line 的方式完成 git 的上傳。 Create Repo   去本地一個你想要放置 git 專案的地方,比如我想把我之後的 git code 都放在我 Mac local 的 /Users/chungchris/git $ cd /Users/chungchris/git $ git init   就會看到在此 git 目錄下產生一個隱藏的 .git 資料夾,這樣就完成了: (base) Chris-MBP:git chungchris$ ls -al total 0 drwxr-xr-x   3 chungchris   staff     96 11 21 11:01 . drwxr-xr-x+ 53 chungchris   staff   1696 11 21 10:45 .. drwxr-xr-x   9 chungchris   staff  ...

[Coding] Compiler

Something about compiling. #compiler #link #gcc Reference PTT LinuxDev, 作者: cole945 (躂躂..) 看板: LinuxDev, 標題: [心得] 用gcc 自製Library, 時間: Sun Nov 5 04:15:45 2006 Static Link Compile 時將 library 加入程式碼,執行快但佔空間,code size 和 mem 使用都比較多 Compile source codes to generate object files $ gcc -c file1.c file2.c file3.c -c 編出 object 檔 Create a static library named libmylib.a $ ar rcs lib mylib .a file1.o file2.o file3.o 把一堆 object 檔用 ar(archiver) 包裝集合起來,檔名以`.a’ 結尾 Using a Static Library to generate a executable files $ gcc -o main main.c -L. -l mylib -L: the directory of the library. 可以指定多次 -LDIR -l: the name of the library (注意 藍色 部分是 match 的) Dynamic Link Compile 時不將 library 加入程式碼,執行程式的時後再將 library 載入程式碼,若有多個程式共用同一個 library,只需載一個 library 進 memory Compile source code $ gcc -c -fPIC file1.c file2.c file3.c -fPIC 表示要編成 position-independent code,這樣不同 process 載入 shared library 時,library 的程式和資料才能放到記憶體不同位置。-fPIC 較通用於不同平台,但產生的 code 較大,而且編譯速度較慢 Create a shared library...

Let's Move On

今天決定要建個部落格 身為資工系的學生, 又那麼愛做筆記 XD 卻到今天才想做這件事似乎有點落漆 還沒明確知道想用來記錄些什麼, 有可能只是與程式相關的東西, 也有可能會很雜 但也很有可能過了一年什麼屁都沒有, 到時候也可以拿出來嘲笑自己一下自我檢討一番 Decide creating the blog today. It seems abnormal for a computer science student to do this so late. After all, I like taking note a lots... Still not sure about what am gonna write here. Maybe all about programming. Maybe it will be really mixed. Nevertheless... very likely that it will still be empty after a year... Then I can open it and piss myself. 迅速 Google 了一下該用哪個平台, 只想找個簡單好用的 外貌先決下 wordpress 和 blogger 脫穎而出, 進一步看了一下覺得並沒有複雜架站的需求所以最後選了 blogger