《Python深度學習》 Part 1

全部內容來源於《Python深度學習》,以練習爲主,理論知識較少,摻雜有一些個人的理解,雖然不算很準確,但是勝在簡單易懂,這本書是目前看到最適合沒有深度學習經驗的同學們入門的書籍了,不妨試試,該書作者:Francois Chollet,即Keras之父,該書譯者:張亮;

相關內容以及代碼已經在Kaggle的notebook上正常運行,歡迎大家star、fork;

深度學習第一個難點在於它所謂的黑盒,讓人望而生畏,這本書的思路是以最簡單的模型結構入手,針對最經典的全連接層、卷積層、循環層依次進行拆解,分析其原理、適用場景、爲什麼適用、例子(並且例子都非常有趣且實用)程序來驗證前面的觀點,在分析之中穿插有多種提升模型性能的手段,既能完成具體的項目看到效果,又能理解模型預測好與壞的原因以及如何定向的優化它;

本篇目錄:

  1. 電影評論分類、新聞分類、房價預測 - 全連接層
  2. 貓狗分類 - 卷積神經網絡
  3. 誰說深度學習都是黑盒 - 卷積神經網絡的可視化
  4. 文本序列分類、時間序列預測 - 循環神經網絡
  5. 從無到有創造文本 - 基於LSTM的語言模型
  6. 從無到有創造圖像 - 變分自編碼

深度學習標準工作流

  1. 讀取輸入數據、清洗、構建特徵、調整數據格式爲符合網絡輸入層要求;
  2. 搭建網絡拓撲結構;
  3. compile網絡設置optimizer、loss、metrics等參數;
  4. 訓練模型,通常需要指定validation data來實時驗證模型性能;
  5. 使用模型預測測試集數據;

全連接層

Dense層(全連接層、密集連接層)是神經網絡中最基礎也是最常用的層,它處理一維向量數據,對應的也就是shape=(samples,features)的二階張量,對於輸入數據的計算方式如下:

\[output = activation(dot(input,W)+B) \]

上式中,向量點積加法運算爲純線性計算激活函數activation提供非線性計算,這極大的增長了神經網絡模型的假設空間,通俗理解就是模型變得更加強大,能夠擬合更多的數據;

輸入數據準備:

  1. 不管是結構化數據、文本數據還是圖像數據,都需要進行向量化(數據轉爲N階張量)處理以符合網絡中輸入層的格式要求;
  2. 對於標籤列,如果是分類任務,則需要進行categorical處理,類似索引化處理;
  3. Dense、Conv2D、LSTM等需要的輸入數據的張量階數一般是不同的,通常需要reshape處理;

電影評論情感分類

該項目屬於文本二分類任務,也是NLP領域最基礎的任務之一,首先它的原始數據爲文本,因此需要想辦法對其進行向量化處理,其次它是分類任務,因此標籤列需要categorical處理;

下面一步一步來實現:

  1. 文本向量化:即索引化one-hot以及詞嵌入
    1. 索引化是將每個word(英文是單詞,中文是字或者詞,取決於你的顆粒度)映射到一個整數值,例如“我”->1,“愛”->2,“中國”->5,那麼“我愛中國”向量化後爲 1 2 5,由於文本的長度並不是固定的,因此通常會設置一個最長的限制,例如maxlen=10,超過maxlen的部分截斷,不足maxlen的需要以某個指定值填充,例如maxlen=5,不足使用0填充的“我愛中國”映射爲 0 0 1 2 5,這樣處理後就可以將每段文本轉換爲等長的向量;
    2. one-hot是類似獨熱編碼的處理,與索引化類似,依然使用上述“我愛中國”的例子,索引化的結果爲 0 0 1 2 5,而one-hot的結果爲 0 1 1 0 0 1 0 0 0 0,即將1、2、5對應位置改爲1,其餘保持0,同時長度固定爲10,主要區別在於:索引化中字的順序沒有變化,而one-hot中這種順序被丟棄了,其次通常索引化後的向量是密集的,而one-hot則是稀疏的;
    3. 詞嵌入是另一種文本向量化的方法,後面用循環神經網絡處理序列問題是會用到,我們後面再細說;
# 此處使用的是**one-hot**向量化處理,由於Dense層單獨處理每個輸入張量,因此無法捕獲序列中的前後依賴信息,因此更適合處理**one-hot**向量化後的數據
# 通過keras內置的imdb數據集加載數據,num_words表示只加載出現最多的前10000個單詞
(train_data,train_labels),(test_data,test_labels) = imdb.load_data(num_words=10000)

# 文本序列向量化處理
def vectorize_sequences(sequences, dimension=10000):
    # 構建全0向量
    results = np.zeros((len(sequences),dimension))
    # 根據文本中單詞的索引值來指定對應位置的元素爲1,其餘爲0,結果爲 0 0 1 1 0 1 0 0 1 ....長度爲10000的由0和1組成的向量
    for i,sequence in enumerate(sequences):
        results[i, sequence] = 1
    return results

x_train = vectorize_sequences(train_data)
x_test = vectorize_sequences(test_data)
  1. 搭建網絡拓撲結構:
# 對於文本二分類等簡單任務,拓撲結構不宜太複雜,此處選擇一個Dense作爲輸入層,一個Dense作爲隱含層,一個Dense作爲輸出層的線性堆疊結構
network = models.Sequential()
# 激活函數使用relu,一般情況下都適用
network.add(layers.Dense(16,activation="relu",input_shape=(10000,))) # relu整流激活函數實現表示空間非線性
network.add(layers.Dense(16,activation="relu"))
# 由於是二分類問題,因此選擇sigmoid作爲輸出層激活函數,sigmoid將輸出壓縮到0~1之間作爲二分類的類別概率值
network.add(layers.Dense(1,activation="sigmoid"))
  1. 編譯模型:
# 以下使用的都是二分類問題的基本參數,很多時候默認的就是最優的
network.compile(loss="binary_crossentropy", # 適用於輸出概率值的二分類模型
               optimizer="rmsprop", # SGD的變種
               metrics=["accuracy"])
  1. 訓練模型並觀察最優迭代數:
# 訓練過程需要實時測試性能,因此需要將數據劃分爲訓練集和驗證機
x_val = x_train[:10000]
x_train_partial = x_train[10000:]
y_val = train_labels[:10000]
y_train_partial = train_labels[10000:]

# epochs表示模型迭代次數,batch_size表示每次迭代的每一輪模型權重參數更新使用的數據量
history = network.fit(x_train_partial,y_train_partial,epochs=20,batch_size=512,validation_data=(x_val,y_val))

# 通過history參數來查看訓練過程每一輪記錄的loss和accuracy
history_df = pd.DataFrame(history.history)
history_df[["loss","val_loss"]].plot()
history_df[["accuracy","val_accuracy"]].plot()
  1. 在測試集上驗證模型:
# 上述圖中可以看到最優epochs約爲4
network = models.Sequential()
network.add(layers.Dense(16,activation="relu",input_shape=(10000,)))
network.add(layers.Dense(16,activation="relu"))
network.add(layers.Dense(1,activation="sigmoid"))
network.compile(loss="binary_crossentropy",optimizer="rmsprop",metrics=["accuracy"])
network.fit(x_train,train_labels,epochs=4,batch_size=512)
result = network.evaluate(x_test,test_labels)
# 結果爲:[0.3078942894935608, 0.8791999816894531]

以上就是一個完整的深度學習建模並測試的流程,雖然不管是數據處理還是模型調優等都儘可能的簡化了,但是麻雀雖小五臟俱全,再複雜的模型也是在這個基礎上產生的,對於這個情感分類問題,如果採用機器學習算法,比如隨機森林、邏輯迴歸、XGBoost等也是可以做到一樣甚至更好的準確率的,但是過程會複雜很多,主要體現在特徵工程部分,需要針對不同情感分類對應的關鍵字等進行特徵構建,因此我們依然可以看到深度學習的魅力,即便是在如此簡單的一個問題上;

新聞多分類

這個項目與上述電影評論分類唯一的區別在於它是個多分類問題,因此下述主要展示這一點區別對流程上的影響;

network = models.Sequential()
# 你會注意到輸入層與隱含層的神經元個數較新聞評論二分類相比多了,由16->64,這裏沒有一定的規則,但是通常認爲多分類任務較二分類要複雜,神經元個數代表了神經層的表示能力,因此需要增加,但是具體增加到多少是需要調試的
network.add(layers.Dense(64,activation="relu",input_shape=(10000,))) # 隱藏單元數設置爲64,用於構建更復雜的表示空間去識別複雜的46個類別的表示
network.add(layers.Dense(64,activation="relu"))
# 多分類問題需要使用softmax做多類別的概率輸出,46爲類別數
network.add(layers.Dense(46,activation="softmax")) # softmax用於多分類的激活函數,輸出46個類別對應的概率,概率和爲1

# 與二分類使用binary_crossentropy不同,多分類使用categorical_crossentropy
network.compile(optimizer="rmsprop",
               loss="categorical_crossentropy",
               metrics=["accuracy"])

x_val = x_train[:1000]
x_train_part = x_train[1000:]
y_val = y_train[:1000]
y_train_part = y_train[1000:]

history = network.fit(x_train_part,y_train_part,epochs=20,batch_size=512,validation_data=(x_val,y_val))
history_df = pd.DataFrame(history.history)
history_df[["loss","val_loss"]].plot()
history_df[["accuracy","val_accuracy"]].plot()

波士頓房價預測

之前的兩個項目都是分類任務,本項目爲迴歸任務,實際從構建網絡上來看,迴歸任務更簡單一些,同樣的下述從差異介紹;

  1. 由於輸入數據是結構化因此不需要向量化處理,但是由於各個特徵量綱不同,一般需要統一量綱:
# 各個特徵統一到均值爲0,標準差爲1下
mean_ = train_data.mean(axis=0)
std_ = train_data.std(axis=0)
train_data -= mean_
train_data /= std_
test_data -= mean_
test_data /= std_
  1. 輸出層參數、損失函數以及監控指標的區別:
model = models.Sequential()
model.add(layers.Dense(64,activation="relu",input_shape=(train_data.shape[1],)))
model.add(layers.Dense(64,activation="relu"))
# 由於Dense層本身輸出的就是連續值,因此不需要激活函數
model.add(layers.Dense(1))
# 損失函數選擇mse、性能指標選擇mae,都是迴歸問題常用的指標
model.compile(optimizer="rmsprop",loss="mse",metrics=["mae"])

卷積神經網絡

深度學習在圖像識別領域是遠遠領先於其他機器學習算法的,主要原因在於對於機器學習算法,圖像數據難以人工構建有效特徵,而特徵工程的好壞直接影響了最終模型的性能,而深度學習模型更擅長此類問題,比如用於處理圖像識別的卷積神經網絡,我們知道視覺空間有兩大特點:

  1. 平移不變性:假如模型在某個局部範圍內學習到了”耳朵“這個模式,那麼它在其他位置依然可以識別該模式;
  2. 空間層次結構:隨着網絡層的加深,不同的卷積層會學習到不同維度的模式,一般最上層是一些純色邊緣等基礎的、通用的模式,而越往後模式就越抽象,比如貓狗分類中會出現貓耳朵狗尾巴等模式被識別出來(PS:這種模式是可以通過可視化的方式直觀看到的,這個在後面的卷積神經網絡可視化部分會展示給大家看,非常有趣);

對於平移不變性,卷積神經網絡的做法是通過固定大小的滑窗逐步的對部分像素數據進行計算,識別其模式,而對於空間層次結構,通過堆疊卷積層,使得靠後的卷積層在之前卷積層的輸出上進一步識別模式,以此實現對高維模式的捕獲;

卷積層對輸入數據的計算如下:

\[activation(\sum_0^n \sum_0^m dot(W,input)+b) \]

假設輸入圖像數據5*5,卷積核爲3*3,步幅爲1,那麼計算過程如下:

可以看到,在此情況下輸出爲3*3,雖然與Dense一樣都可以看做是信息蒸餾的過程,但是與Dense同時計算全部數據不同,卷積層是依次對不同區域的像素數據進行計算,因此可以識別更基礎的模式,且最終結果依然保持了圖像信息的相對位置,這一點很重要;

最後

下一部分將進入各個實戰章節,包含MNIST、貓狗識別、時序問題、生成式深度學習、深度學習可視化等等,將會更加有趣,一起期待一下把;

最後附上notebook鏈接,大家最好copy過去修改、運行、看效果哈,動手學習效果最佳;

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章