【深度學習與TensorFlow 2.0】入門篇

:由於畢業論文須要用到相關知識,藉着 TF 2.0 發佈的時機,從新撿起深度學習。在此,也推薦一下優達學城與 TensorFlow 合做發佈的TF 2.0入門課程,下面的例子就來自該課程。html

原文發佈於博客園:http://www.javashuo.com/article/p-dqwntdax-by.htmlpython

本文中全部代碼都在文末第二個連接中,轉載請註明出處!git

 

機器學習與深度學習


深度學習是機器學習的一個分支,當下也是該領域發展最快、最受關注的一個分支。上週剛剛公佈的2018年圖靈獎就頒發給了對深度學習的發展作出了重要貢獻的三位科學家:Yoshua Bengio、Geoffrey Hinton 和 Yann LeCun。相對於傳統的機器學習算法,深度學習最大的區別在於:在訓練的過沖中,由神經網絡自主學習數據的表示,而不須要人工作特徵工程。github

以前寫了多篇與機器學習有關的博文,如下幾篇與深度學習有關,能夠幫助理解基礎知識:算法

  1. 【機器學習】一些基本概念及符號系統
  2. 【機器學習】代價函數(cost function)
  3. 【機器學習】邏輯迴歸(Logistic Regression)
  4. 【機器學習】神經網絡實現異或(XOR)

由於深度學習是機器學習的一個分支,與傳統的機器學習方法有很是多的類似之處。歸納以下:編程

  • 解決的主要問題:分類(二分類或多分類),迴歸,聚類;
  • 學習的基本過程:在有監督學習(分類和迴歸問題)中,都是輸入「數據 + 標籤(答案)」,得到「算法」(從數據到答案的某種映射關係);
  • 訓練過程都是對代價函數的優化過程;
  • 都面臨過擬合的挑戰,所以都須要正則化方面的技術;
  • 均可以使用梯度降低法來優化參數.

固然深度學習中,也有一些有別於傳統機器學習的主題:網絡

  • 網絡的結構:層數,每一層的神經單元數;
  • 激活函數:做用於隱藏層神經元,使得數據的變化過程從線性到非線性;
  • 反向傳播:用於多層神經網絡中偏差(或梯度)從網絡的輸出層向輸入層傳播;
  • 其餘特殊網絡結構:CNN 中的卷積、長短時間記憶網絡、編碼器和解碼器等.

 

多層感知機


多層感知機(multilayer percepton, MLP)也叫深度前饋網絡或前饋神經網絡,是典型的深度學習模型。其目的是近似某個函數$f^*$。當前饋神經網絡被拓展成包含反饋鏈接時,它們被稱爲循環神經網絡(recurrent neural network, RNN)。機器學習

關於多層感知機的基礎知識,能夠參考我以前的博客——【機器學習】神經網絡實現異或(XOR),或下面的兩篇博主"python27"的學習筆記:函數

 

一個簡單的例子


雖然接觸到深度學習的知識已經很長時間了,可是在平時遇到分類或是迴歸相關的問題,仍是會優先選擇傳統的機器學習算法。有時候是由於數據量比較小,可是還有一個比較重要的緣由是本身實踐太少,對於深度學習這個工具,用起來還不順手。以前學習的時候,在TensorFlow、Pytouch和Keras之間很難作出選擇。如今TF 2.0借鑑Keras中的API風格,既保持了性能的優點,也更加簡單易學。加上最近剛剛發佈的課程,所以就決定選擇TF 2.0做爲本身之後練習深度學習算法的工具。工具

 

將攝氏度轉換成華氏度

溫度的不一樣單位之間的轉換有明確的定義,知道其中一種單位的溫度值能夠經過下面的公式精確的計算出另外一種單位下的溫度值。

 $$ f = c \times 1.8 + 32 $$

 若是咱們已知該公式,將該公式寫成一個函數,輸入爲$c$,輸出爲$f$,那麼這就是一個入門級的編程練習題。

可是假如咱們如今知道幾個數值對,即輸入和答案,該公式並不知道。此時就能夠利用機器學習的方法,求出一個近似的從$c$到$f$的映射關係。

下面是代碼:

 1 from __future__ import absolute_import, division, print_function
 2 import tensorflow as tf
 3 tf.logging.set_verbosity(tf.logging.ERROR)
 4 
 5 import numpy as np
 6 
 7 # 輸入的攝氏溫度以及其對應的華氏溫度,前面兩個故意寫錯了
 8 celsius_q    = np.array([-40, -10,  0,  8, 15, 22,  38],  dtype=float)
 9 fahrenheit_a = np.array([-40,  14, 32, 46, 59, 72, 100],  dtype=float)
10 
11 for i,c in enumerate(celsius_q):
12   print("{} degrees Celsius = {} degrees Fahrenheit".format(c, fahrenheit_a[i]))
13 
14 # 輸入後鏈接了只有一個神經單元的隱藏層
15 l0 = tf.keras.layers.Dense(units=1, input_shape=[1])
16 
17 # 將網絡層添加到序列模型中
18 model = tf.keras.Sequential([l0])
19 
20 # 編譯神經網絡模型
21 model.compile(loss='mean_squared_error',
22               optimizer=tf.keras.optimizers.Adam(0.1))
23 
24 # 訓練模型
25 history = model.fit(celsius_q, fahrenheit_a, epochs=500, verbose=False)
26 print("Finished training the model")

在這個例子中,包括如下要素:

  1. 訓練數據:一共有7個樣本(輸入 + 答案),有兩個樣本的值不許確(在實際項目中,有多是由於測量或記錄致使的偏差);
  2. 層(layers):神經網絡是以層爲基本組成單位的,每層有兩個最基本的參數units和activation,分別表示該層神經單元的個數和激活函數(這裏沒有設置第二個參數就表示不對該層的神經單元進行任何變換);
  3. 層的類型:層的不一樣類型,表明了層之間不一樣的鏈接方式,這裏使用的是全鏈接層(Dense),表示各層之間全部點都直接相連;
  4. 模型:組織不一樣「層」的方式,這裏使用的序列模型(Sequential)按照層的順序從輸入到輸出疊加各個層;
  5. 編譯(compile):訓練以前必須編譯,在編譯的時候須要指定兩個很是重要的參數——loss和optimizer,loss就是代價函數,optimizer是訓練模型的方法;
  6. 訓練模型(fit):必要參數爲輸入數據,對於的標籤(答案),迭代次數(epochs)等.

上面15行和18行一般會寫在一塊兒:

model = tf.keras.Sequential([
  tf.keras.layers.Dense(units=1, input_shape=[1])
])

 

模型訓練的過程當中,損失函數的值會隨着訓練次數發生變化。這些變化由fit函數返回,記錄在history中。畫出來以下:

import matplotlib.pyplot as plt
plt.xlabel('Epoch Number')
plt.ylabel("Loss Magnitude")
plt.plot(history.history['loss'])

圖1:loss隨着訓練次數的增長而減少

這個模型很是簡單,若是不算輸入層,整個模型只有1層:輸入層鏈接了只有一個神經單元的層l0,該層處理以後的數據直接做爲輸出值。

所以該模型的網絡結構以下:

圖2:上面例子中神經網絡的結構

上圖中的l0只有一個神經單元,另外還有一個偏置單元(輸入值x上方的藍色點,除了輸入層外,每層默認都會有一個做用於該層的偏置單元)。所以,從輸入到輸出能夠表示爲:

$$y = x*w + b$$

神經網絡的結構本質上是對最終模型的一種假設,這裏的假設剛好與真實模型徹底相同:線性模型,兩個參數。可是在徹底不知道真實模型的狀況下,大部分時候模型的容量可能都遠超過了真實模型,表如今參數多(模型的自由度大),結構複雜,添加了非線性變換的激活函數,所以容易致使過擬合。

訓練完成後,能夠查看模型各層的參數(偏置單元雖然畫在了輸入層上方,但仍是算做l0層的參數):

print("These are the layer variables: {}".format(l0.get_weights()))

下面是輸出:

These are the layer variables: [array([[1.8220955]], dtype=float32), array([29.117624], dtype=float32)]

第一個值(1.822,x的參數)與真實值1.8很是接近,第二個值(29.118,偏置單元的取值)與真實值32也比較接近。因而可知,雖然訓練數據中包含兩個偏差比較大的點,可是最終模型仍是比較準確的找到了這兩組數據之間的基本規律:$y = 1.82x + 29.12$

訓練好模型以後,可使用下面的方法預測新值:

print(model.predict([100.0]))

輸出爲"[[211.32718]]",該值與真實值212很是接近。

以上就是假設在不知道溫度兩種單位之間的轉換公式的狀況下,經過很是簡單的神經網絡學習到兩組數據之間關係的過程。

學習到與真實的轉換公式如此接近的結果,強烈依賴於最開始設定的網絡結構(一種先驗,對最終模型的假設)。在不知道真實模型的狀況下,一般會假設一個比較複雜的網絡結構。此時模型參數多,自由度大,模型的容量和搜索空間也是遠超過了真實模型,此時真實模型必定被包含其中,但不必定能找到,或者找到很是接近全局最優解的局部最優解。

下面是另外一種網絡結構的假設:

 1 l0 = tf.keras.layers.Dense(units=4, input_shape=[1])  
 2 l1 = tf.keras.layers.Dense(units=4)  
 3 l2 = tf.keras.layers.Dense(units=1)  
 4 model = tf.keras.Sequential([l0, l1, l2])
 5 model.compile(loss='mean_squared_error', optimizer=tf.keras.optimizers.Adam(0.1))
 6 model.fit(celsius_q, fahrenheit_a, epochs=500, verbose=False)
 7 print("Finished training the model")
 8 print(model.predict([100.0]))
 9 print("Model predicts that 100 degrees Celsius is: {} degrees Fahrenheit".format(model.predict([100.0])))
10 print("These are the l0 variables: {}".format(l0.get_weights()))
11 print("These are the l1 variables: {}".format(l1.get_weights()))
12 print("These are the l2 variables: {}".format(l2.get_weights()))

輸出以下:

Finished training the model
[[211.74747]]
Model predicts that 100 degrees Celsius is: [[211.74747]] degrees Fahrenheit
These are the l0 variables: [array([[ 0.45070484, -0.611826  ,  0.1898421 ,  0.0913914 ]],
      dtype=float32), array([ 3.4355907, -3.5666099, -2.7151687,  3.45835  ], dtype=float32)]
These are the l1 variables: [array([[ 0.22470416,  1.2858697 ,  0.81416523,  0.359274  ],
       [ 0.38035178, -0.86285967,  0.34824482, -0.30044237],
       [-0.16603428, -0.5080208 , -0.27835467, -0.6047108 ],
       [-0.5545173 ,  0.9019376 ,  0.19518667, -0.2925983 ]],
      dtype=float32), array([-3.1969943,  3.4892511,  1.7240645,  3.4472196], dtype=float32)]
These are the l2 variables: [array([[-0.30633917],
       [ 1.4714689 ],
       [ 0.31956905],
       [ 0.41886073]], dtype=float32), array([3.3831294], dtype=float32)]

能夠看到新模型預測100攝氏度的結果也很是接近其真實的華氏溫度。此時模型的結構以下:

圖3:第二個模型的網絡結構

不算輸入層,這個模型一共有3層。其中兩個隱藏層各自含有4個神經單元(藍色點表示每層的偏置單元)。除了輸入層外,其餘每一個神經單元的取值都由直接與之相連的點(及對應的參數)決定:例如l1層從上往下數第2個橙色點的取值由上一層4個點(及對應的參數)的取值和偏置單元的取值決定。能夠歸納的表示以下:

$$y' = x·w + b$$

其中$x$表示上一層的全部神經單元構成的向量,$w$是鏈接$y'$與上一層全部單元的參數,$b$是偏置單元。由於這裏仍是沒有設置激活函數,所以每一層中的各個單元都是上一層全部單元取值的線性組合。

雖然第二個模型也能很好的完成預測任務,可是與真實的轉換公式之間差別巨大,並且可解釋性也變差了。

 

 

Reference


https://cn.udacity.com/course/intro-to-tensorflow-for-deep-learning--ud187

https://github.com/OnlyBelter/examples/blob/master/courses/udacity_intro_to_tensorflow_for_deep_learning/l02c01_celsius_to_fahrenheit.ipynb

相關文章
相關標籤/搜索