1. 程式人生 > >Linux 桌面玩家指南:15. 深度學習可以這樣玩

Linux 桌面玩家指南:15. 深度學習可以這樣玩

特別說明:要在我的隨筆後寫評論的小夥伴們請注意了,我的部落格開啟了 MathJax 數學公式支援,MathJax 使用$標記數學公式的開始和結束。如果某條評論中出現了兩個$,MathJax 會將兩個$之間的內容按照數學公式進行排版,從而導致評論區格式混亂。如果大家的評論中用到了$,但是又不是為了使用數學公式,就請使用\$轉義一下,謝謝。

想從頭閱讀該系列嗎?下面是傳送門:

前言

這一篇相當於是深度學習方面的一個 Hello World 吧。深度學習目前大火,吸引了無數人。但是很多時候,想了解深度學習的人總覺得雲山霧罩,怎麼也看不明白。如果要是有一個能執行的簡單的深度學習的例子該多好啊。我這裡就來玩一玩深度學習,來一個讓大家摸得著、看得見的例子,揭開深度學習的神祕面紗。語言方面,當然是選擇對科學計算極度友好的 Python 啦。我當然不會從頭擼程式碼,肯定會使用現成的庫的啦。目前最流行的深度學習框架是 Keras,在 Keras 中,它又使用了大名鼎鼎的 TensorFlow 作為後端。在 Python 中,安裝這幾個庫真的是太方便了。最後說一句,我用的是 Python3。

上一篇浮光掠影地講了一下科學計算,並探討了一下適合數值計算的語言需要什麼樣的特色。非常幸運,Python 正好具有這樣的特色,準確地說,應該是 Python 中的 numpy 庫正好具有這樣的特色。上一篇的內容略有過時,比如 IPython Notebook,目前就已經改成 Jupyter Notebook 了。但是在這一篇中,我就不用什麼 Notebook 了,我用 PyCharm。

JetBrains 大家都知道啦,JetBrains 全家桶是廣大程式設計師的福利啦。做科學計算,使用 PyCharm 的 Community 版就足夠了,沒必要下載 Professional 版啦,我更加是不鼓勵大家用破解版的啦。

環境安裝

到 JetBrains 的官網下載最新的 PyCharm 2018.3,正如前面所說,Community 版就夠了。解壓,執行之,用它建立一個 Python 專案,選擇使用虛擬環境,如下圖:

使用虛擬環境的好處,是可以為這個專案單獨安裝依賴的庫,不用擔心為了學一個什麼東西而把系統中的 Python 搞得亂七八糟。直接開啟 PyCharm 中的 Terminal,就可以進入這個專案的虛擬環境,在這個 Terminal 中執行的命令,預設就在這個專案的虛擬環境中執行。我們可以在這個 Terminal 中執行pip3 install命令安裝所有需要的庫。在 PyCharm 中使用pip3 install命令時,有一個令人頭痛的問題,那就是從國外的源下載的速度太慢,我們可以替換成國內的源。我太懶,都是使用臨時替換,只需要新增-i 源地址引數就可以了。例如,要安裝 numpy,並且選擇從阿里雲下載,就使用pip3 install numpy -i https://mirrors.aliyun.com/pypi/simple/命令。如下圖:

常用的國內源有:

  • 清華:https://pypi.tuna.tsinghua.edu.cn/simple
  • 阿里雲:https://mirrors.aliyun.com/pypi/simple/
  • 中國科技大學 https://pypi.mirrors.ustc.edu.cn/simple/
  • 華中理工大學:http://pypi.hustunique.com/
  • 山東理工大學:http://pypi.sdutlinux.org/
  • 豆瓣:http://pypi.douban.com/simple/

新版 Ubuntu 要求使用 https 源,要注意。

在這裡,我們需要安裝 numpy、keras、tensorflow、matplotlib 庫,numpy 用來操作向量和矩陣,matplotlib 用來畫圖。為了能夠讀取和預處理圖片,我還需要使用 PIL,可惜 PIL 不支援 Python 3,不過沒關係,使用 Pillow 就好了。安裝這幾個庫只需要如下幾個命令:

pip3 install numpy -i https://mirrors.aliyun.com/pypi/simple/
pip3 install tensorflow -i https://mirrors.aliyun.com/pypi/simple/
pip3 install keras -i https://mirrors.aliyun.com/pypi/simple/
pip3 install matplotlib -i https://mirrors.aliyun.com/pypi/simple/
pip3 install Pillow -i https://mirrors.aliyun.com/pypi/simple/

這些庫都直接安裝到了我們的專案內,不會和系統中的 Python 起衝突。如下圖:

PyCharm 最大的優勢當然是它的自動程式碼提示了。不管是寫一個.py檔案,還是直接使用 PyCharm 中的 Python Console,就是有非常好的程式碼提示的。Python Console 還有一個非常棒的功能,就是可以觀察每一個變數的值,真的是太方便了。如下圖:

而在系統的終端中直接執行 Python3,我們是得不到這麼好的輔助功能的。如下圖:

最簡單的深度學習示例

首先,我們看一個最簡單的深度學習示例,就是訓練一個能夠識別手寫數字的密集連線神經網路。在這裡,我們需要一個用於訓練和測試的資料集,而這個資料集就是 MNIST 資料集,該資料集包含 60000 張用於訓練的 28×28 畫素的手寫數字圖片,以及 10000 張用於訓練的 28×28 畫素的手寫數字圖片。Keras 能夠自動下載該資料集。訓練這個神經網路的程式碼如下:

from keras.datasets import mnist
from keras import models
from keras import layers
from keras.utils import to_categorical

(train_images, train_labels),(test_images, test_labels) = mnist.load_data()

network = models.Sequential()
network.add(layers.Dense(512, activation='relu', input_shape=(28*28,)))
network.add(layers.Dense(10, activation='softmax'))

network.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])

train_images = train_images.reshape((60000, 28*28))
train_images = train_images.astype('float32') / 255

test_images = test_images.reshape(10000, 28*28)
test_images = test_images.astype('float32') / 255

train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)

network.fit(train_images, train_labels, epochs=5, batch_size=128)

把以上這幾行程式碼逐行輸入到 PyCharm 的 Python 控制檯,就可以看到效果了。當輸入到(train_images, train_labels),(test_images, test_labels) = mnist.load_data()這一行時,Keras 就會自動下載 MNIST 資料集,可惜的是,由於下載地址被牆的原因,經常會出現下載失敗的情況。不過出現下載失敗也不用著急,用搜索引擎找一下,很容易找到這個資料集的檔案:mnist.npz檔案,大小才 11.5M,下載很快的。把下載的這個檔案放到~/.keras/datasets目錄中即可。

以上所有的程式碼都輸入完成後,就開始了訓練,在這個例子中,訓練速度非常快,每個週期 4 秒多就完成了,總共 5 個週期。如下圖:

可以看到,這個神經網路達到了 98.9% 的精度。下面,我自己手寫一個數字測試一下。先開啟 Inkscape,自己隨便寫一個數字,如下圖:

儲存為~/test.png。然後,用下面的程式碼把該圖片讀入記憶體,並更改大小為 28×28 畫素,最後轉化為灰度影象。這些操作都使用 PIL 完成。PIL 操作影象那是相當的方便。

from PIL import Image
image = Image.open('/home/youxia/test.png').resize((28,28)).convert('L')

然後,將該影象轉化為 numpy 的陣列,並將其中的資料處理為 0 到 1 之間的浮點數。

import numpy as np
im = np.array(image)
im = 255 - im
im = im.astype('float32') / 255.0

可以使用 matplotlib 檢視一下該影象,程式碼如下:

import matplotlib.pyplot as plt
plt.imshow(im, cmap=plt.cm.binary)

這是我們處理好之後的影象是下面這個效果,和 MNIST 自帶的影象基本基本一致:

下面使用我們前面訓練的神經網路來識別該圖片,使用 predict 函式即可。識別時,需要將影象資料的 shape 更改為 (1,784):

network.predict(im.reshape(1,784))

返回的值是一個包含是個數字的列表,代表該圖片可能為數字 0-9 的概率,可以看到,其中第 6 項,也就是為數字 5 的概率最大,接近於 1:

array([[2.19245143e-11, 7.56166017e-13, 2.06190620e-10, 3.12406366e-04,
        1.12510295e-13, 9.99686599e-01, 8.85503199e-11, 2.70172443e-11,
        2.85677032e-07, 7.55779013e-07]], dtype=float32)

如果不想自己用眼睛去判斷哪個概率值最大,可以使用 numpy 的 argmax 函式,如下:

np.argmax(network.predict(im.reshape(1,784)))

返回結果為幾,就說明識別出的數字為幾,如下:

5

從密集連線神經網路到卷積神經網路

前面的例子使用的是密集連線神經網路,每一幅影象都轉化為一個以為向量進行處理。在對影象進行深度學習時,最常用的方法是二維卷積神經網路。卷積神經網路的優點一是學到的模式具有平移不變性,在影象某一個區域學習到的模式,如果模式出現在新位置,它仍然能夠識別;二是卷積神經網路可以學到模式的空間層次結構。

在 Keras 中,對卷積神經網路也提供了非常強大的支援。上一節的程式碼,只需要進行簡單的修改,就可以構建一個二維卷積神經網路,程式碼如下:

from keras import layers
from keras import models
from keras.datasets import mnist
from keras.utils import to_categorical


model = models.Sequential()
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)))
model.add(layers.MaxPooling2D(2, 2))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D(2, 2))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.Flatten())
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(10, activation='softmax'))

model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])

(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
train_images = train_images.reshape((60000, 28, 28, 1))
train_images = train_images.astype('float32') / 255
test_images = test_images.reshape(10000, 28, 28, 1)
test_images = test_images.astype('float32') / 255

train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)

model.fit(train_images, train_labels, epochs=5, batch_size=64)

主要的改變體現在以下幾個方面:一是使用 Conv2D 層、MaxPooling 層和 Flatten 層修改了深度學習框架的結構,二是修改了輸入陣列的形狀。除此之外,該深度學習框架使用的啟用函式、損失函式都和前面是一樣的。訓練該網路,發現它比前面的網路訓練起來要慢一些,但是達到了 99.3%的準確度。

使用如下程式碼進行驗證:

import numpy as np
from PIL import Image

im = np.array(Image.open('/home/youxia/test.png').resize((28,28)).convert('L'))
im = 255 - im
im = im.astype('float32') / 255.0

print(np.argmax(model.predict(im.reshape(1, 28, 28, 1))))

關於深度學習的理論和實戰

深度學習的理論相對來說比較難,所以我這篇隨筆裡面就沒有怎麼介紹。如果想全面瞭解深度學習的理論,可以閱讀這本“聖經”:

但是,光有理論而無實踐,這麼枯燥的知識是學不下去的。在實戰方面,我覺得這本書不錯:

我這裡的內容,就是參考了這本書。最後,再次對 Python 點贊,用 Python 寫科學計算的程式碼,真的是太舒服了。

求打賞

我對這次寫的這個系列要求是非常高的:首先內容要有意義、夠充實,資訊量要足夠豐富;其次是每一個知識點要講透徹,不能模稜兩可含糊不清;最後是包含豐富的截圖,讓那些不想裝 Linux 系統的朋友們也可以領略到 Linux 桌面的風采。如果我的努力得到大家的認可,可以掃下面的二維碼打賞一下:

版權申明

該隨筆由京山遊俠在2018年12月16日釋出於部落格園,引用請註明出處,轉載或出版請聯絡博主。QQ郵箱:[email protected]