[Python深度學習](三)機器學習基礎

本文爲《Python深度學習》的學習筆記。

目錄

第4章 機器學習基礎

4.1 機器學習的四個分支

4.1.1 監督學習

4.1.3 自監督學習

4.1.4 強化學習

4.2 評估機器學習模型

4.2.1 訓練集、驗證集和測試機

4.2.2 評估模型的注意事項

4.3 數據預處理、特徵過程和特徵學習

4.3.1 神經網絡的數據預處理

4.3.2 特徵過程

4.4 過擬合和欠擬合

4.4.1 減小網絡大小

4.4.2 添加權重正則化

完整代碼

4.4.3 添加dropout正則化

完整代碼

總結常見防止過擬合的方法:

4.5 機器學習的通用工作流程

4.5.1 定義問題,收集數據集

4.5.2 選擇衡量成功的標準

4.5.3 確定評估方法

4.5.4 準備數據

4.5.5 開發比基準更好的模型

4.5.6 擴大模型規模:開發過擬合模型

4.5.7 模型正則化與調節超參數


第4章 機器學習基礎

本章着重於解決機器學習任務:模型評估、數據預處理、特徵工程、解決過擬合。

4.1 機器學習的四個分支

4.1.1 監督學習

監督學習(supervised learning):多分類、二分類和標量回歸問題

  • 序列生成(sequence generation):給一張圖片,預測描述圖像的文字。
  • 語法樹預測(syntax tree prediction):給定一個句子,預測其分解成語法樹。
  • 目標檢測(object detection):給定一個圖像,畫一個邊界框,對每個框進行分類或分類與迴歸聯合問題。
  • 圖像分割(image segmentation):給定一張圖像,在特定物體上畫一個像素級的掩模(mask)。

降維(dimensionality reduction)
聚類(cluster)

4.1.3 自監督學習

自編碼器(autoencoder),給定目標是未經修改的輸入。給定視頻過去的幀,然後預測下一幀,或者給定文本前面的詞預測下一個詞,也屬於時序監督學習(temporarilly sypervised learning)。
同時自監督學習可以被理解爲無監督或者監督學習。

4.1.4 強化學習

可以適用於自動駕駛汽車、機器人、資源管理、教育等。

 

4.2 評估機器學習模型

由錢一章可以看到在幾個訓練集上模型評估:僅僅幾輪過後,三個模型都開始過擬合。機器去學習的目的是得到可以泛化(generalize)的模型

4.2.1 訓練集、驗證集和測試機

信息泄露(information leak):每次基於模型在驗證集上的醒來來調節模型超參數,都會有一些關於驗證數據的信息泄露到模型,很快會導致模型過擬合。
三種經典的評估方法:簡單的留出驗證、K折驗證,以及有打亂數據的重複K折驗證。

1.簡單的留出驗證(hold-out validation)
留出一定比例的數據集作爲測試集。在剩餘數據上訓練模型。

# 4-1 留出驗證
import numpy as np
num_validation_samples = 10000

# 打亂數據
np.random.shuffle(data)

# 定義驗證集
validation_data = data[:num_validation_samples]
data = data[num_validation_samples:]

training_data = data[:]

model = get_model()
model.train(training_data)
validation_score = model.evaluate(validation_data)

# 重新調節模型、評估、然後再次調節
model = get_model()
model.train(np.concatenate([training_data, validation_data]))
test.score = model.evaluate(test_data)

缺點:如果可用的數據很少,那麼可能驗證集和測試集包含的樣本就太少。

2.K折驗證 K-fold validation將數據劃分爲大小相同的K個分區,對於每個分區K進行測試,在剩餘的分區上訓練模型。

# 4-2 K折交叉驗證
k = 4
num_validation_samples= len(data) // k
np.random.shuffle(data)

validation_scores = []
for fold in range(k):
    validation data = data[num_validation_samples * fold: 
                           num_validation_samples * (flod + 1):]
    training_data = data[:num_validation_samples * fold] + 
                    data[num_validation_samples * (fold + 1):]
    model = get_model()
    model.train(training_data)
    validation_score = model.evaluate(validation_data)
    validation_scores.append(validation_score)

validation_score = np.average(validation_scores)

model = get_model()
model.train(data)
test_score = mdoel.evaluate(test_data)

3.帶有打亂數據的重複K折驗證(iterated K-fold validation with shuffling)
一共需要訓練和評估PxK個模型,計算成本較大,在Kaggle競賽中十分有用。

4.2.2 評估模型的注意事項

  • 數據代表性(data representativeness):希望訓練集和測試集都能代表當前數據(通常需要隨機打亂數據)
  • 時間箭頭(the arrow of time):根據過去預測未來數據,不應該隨機打亂數據,不然會發生時間泄露。應保證測試集所有數據都晚於訓練集。
  • 數據冗餘(redundancy in your data):某些數據點出現了兩次,必須保證訓練集和驗證集之間沒有交集。

4.3 數據預處理、特徵過程和特徵學習

4.3.1 神經網絡的數據預處理

數據預處理的目的是使原始數據更適合用於神經網絡處理,包括向量化、標準化、處理缺失值和特徵提取。
1.向量化
神經網絡的所有輸入和目標都必須是浮點數張量。(data vectorization) 2.值標準化
取值小、同質性(homogenous)
3.處理缺失值

4.3.2 特徵過程

從更高層次理解問題

 

4.4 過擬合和欠擬合

降低過擬合的方法-正則化(regularization)

4.4.1 減小網絡大小

  • 這裏我們先減小網絡的大小,看看會發生什麼。
# 4-3 原始模型
from keras import models
from keras import layers

model = models.Sequential()
model.add(layers.Dense(16, activation = 'relu', input_shape=(10000,)))
model.add(layers.Dense(16, activation = 'relu'))
model.add(layers.Dense(1, activation = 'sigmoid'))

# 4-4 容量更小的模型
model = models.Sequential()
model.add(layers.Dense(4, activation = 'relu', input_shape=(10000,)))
model.add(layers.Dense(4, activation = 'relu'))
model.add(layers.Dense(1, activation = 'sigmoid'))

這裏我們再使用前面用到的imdb數據進行測試

# 用imdb數據測試
# 3-1 加載IMDB數據庫
from keras.datasets import imdb
(train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000)
print(train_data[0])
print(train_labels[0])

# 可以迅速把某條評論解碼爲英文單詞
word_index = imdb.get_word_index()
reverse_word_index = dict(
    [(value, key) for (key, value) in word_index.items()])
decoded_review = ' '.join(
    [reverse_word_index.get(i - 3, '?') for i in train_data[0]])

# 3-2 將整數序列編碼爲二進制矩陣
import numpy as np

def vectorize_sequences(sequences, dimension = 10000):
    results = np.zeros((len(sequences), dimension))
    for i, sequence in enumerate(sequences):
        results[i, sequence] = 1.
    return results

x_train = vectorize_sequences(train_data)
x_test = vectorize_sequences(test_data)

print(x_train[0])
y_train = np.asarray(train_labels).astype('float32')
y_test = np.asarray(test_labels).astype('float32')

# 3-7 留出驗證集
x_val = x_train[:10000]
partial_x_train = x_train[10000:]

y_val = y_train[:10000]
partial_y_train = y_train[10000:]
# 4-3 原始模型
from keras import models
from keras import layers

model1 = models.Sequential()
model1.add(layers.Dense(16, activation = 'relu', input_shape=(10000,)))
model1.add(layers.Dense(16, activation = 'relu'))
model1.add(layers.Dense(1, activation = 'sigmoid'))

# 4-4 容量更小的模型
model2 = models.Sequential()
model2.add(layers.Dense(4, activation = 'relu', input_shape=(10000,)))
model2.add(layers.Dense(4, activation = 'relu'))
model2.add(layers.Dense(1, activation = 'sigmoid'))

# 3-4 編譯模型
model1.compile(optimizer = 'rmsprop',
             loss = 'binary_crossentropy',
             metrics = ['accuracy'])
model2.compile(optimizer = 'rmsprop',
             loss = 'binary_crossentropy',
             metrics = ['accuracy'])

history1 = model1.fit(partial_x_train,
                   partial_y_train,
                   epochs = 20,
                   batch_size = 512,
                   validation_data = (x_val, y_val))
history2 = model2.fit(partial_x_train,
                   partial_y_train,
                   epochs = 20,
                   batch_size = 512,
                   validation_data = (x_val, y_val))

# 3-9 繪製訓練損失和驗證損失
import matplotlib.pyplot as plt

history1_dict = history1.history
history2_dict = history2.history
loss_values = history1_dict['loss']

val_loss_values1 = history1_dict['val_loss']
val_loss_values2 = history2_dict['val_loss']

epochs = range(1, len(loss_values) + 1)

plt.plot(epochs, val_loss_values1, '+', label = 'Original model')
plt.plot(epochs, val_loss_values2, 'bo', label = 'Smaller model')
plt.title('Training and Validation loss')
plt.xlabel('Epochs')
plt.ylabel('Validation Loss')
plt.legend()
plt.show()

明顯更小的網絡過擬合時間晚於參考網絡。

  • 同樣的,我們來看看更大的網絡。
# 4-5 容量更大的模型
model3 = models.Sequential()
model3.add(layers.Dense(512, activation = 'relu', input_shape=(10000,)))
model3.add(layers.Dense(512, activation = 'relu'))
model3.add(layers.Dense(1, activation = 'sigmoid'))

model3.compile(optimizer = 'rmsprop',
              loss = 'binary_crossentropy',
              metrics = ['accuracy'])

history3 = model3.fit(partial_x_train,
                   partial_y_train,
                   epochs = 20,
                   batch_size = 512,
                   validation_data = (x_val, y_val))
import matplotlib.pyplot as plt

history1_dict = history1.history
history3_dict = history3.history
loss_values = history1_dict['loss']

val_loss_values1 = history1_dict['val_loss']
val_loss_values3 = history3_dict['val_loss']

epochs = range(1, len(loss_values) + 1)

plt.plot(epochs, val_loss_values1, '+', label = 'Original model')
plt.plot(epochs, val_loss_values3, 'bo', label = 'Bigger model')
plt.title('Bigger model')
plt.xlabel('Epochs')
plt.ylabel('Validation Loss')
plt.legend()
plt.show()
import matplotlib.pyplot as plt

history1_dict = history1.history
history3_dict = history3.history
loss_values = history1_dict['loss']

val_loss_values1 = history1_dict['val_loss']
val_loss_values3 = history3_dict['val_loss']

epochs = range(1, len(loss_values) + 1)

plt.plot(epochs, val_loss_values1, '+', label = 'Original model')
plt.plot(epochs, val_loss_values3, 'bo', label = 'Bigger model')
plt.title('Bigger model')
plt.xlabel('Epochs')
plt.ylabel('Validation Loss')
plt.legend()
plt.show()

明顯可見,更大的網絡早一輪開始過擬合,同時過擬合情況也更嚴重。

 

import matplotlib.pyplot as plt

history1_dict = history1.history
history2_dict = history2.history
history3_dict = history3.history
loss_values = history1_dict['loss']

val_loss_values1 = history1_dict['val_loss']
val_loss_values2 = history2_dict['val_loss']
val_loss_values3 = history3_dict['val_loss']

epochs = range(1, len(loss_values) + 1)

plt.plot(epochs, val_loss_values1, '+', label = 'Original model')
plt.plot(epochs, val_loss_values2, 'd', label = 'Smaller model')
plt.plot(epochs, val_loss_values3, 'bo', label = 'Bigger model')
plt.title('Bigger model')
plt.xlabel('Epochs')
plt.ylabel('Validation Loss')
plt.legend()
plt.show()

4.4.2 添加權重正則化

L1正則化
L2正則化

# 4-6 向模型添加L2權重正則化
from keras import models
from keras import layers
from keras import regularizers

model4 = models.Sequential()
# 每個係數都會使總網絡損失增加0.001 * weight_coefficient_value
model4.add(layers.Dense(16, kernel_regularizer = regularizers.l2(0.001), activation = 'relu', input_shape=(10000,)))
model4.add(layers.Dense(16, kernel_regularizer = regularizers.l2(0.001), activation = 'relu'))
model4.add(layers.Dense(1, activation = 'sigmoid'))

model4.compile(optimizer = 'rmsprop',
              loss = 'binary_crossentropy',
              metrics = ['accuracy'])

完整代碼

# 4-6 向模型添加L2權重正則化
from keras import models
from keras import layers
from keras import regularizers
import matplotlib.pyplot as plt

model4 = models.Sequential()
# 每個係數都會使總網絡損失增加0.001 * weight_coefficient_value
model4.add(layers.Dense(16, kernel_regularizer = regularizers.l2(0.001), activation = 'relu', input_shape=(10000,)))
model4.add(layers.Dense(16, kernel_regularizer = regularizers.l2(0.001), activation = 'relu'))
model4.add(layers.Dense(1, activation = 'sigmoid'))

model4.compile(optimizer = 'rmsprop',
              loss = 'binary_crossentropy',
              metrics = ['accuracy'])

history4 = model4.fit(partial_x_train,
                   partial_y_train,
                   epochs = 20,
                   batch_size = 512,
                   validation_data = (x_val, y_val))

history1_dict = history1.history
history4_dict = history4.history
loss_values = history1_dict['loss']

val_loss_values1 = history1_dict['val_loss']
val_loss_values4 = history4_dict['val_loss']

epochs = range(1, len(loss_values) + 1)

plt.plot(epochs, val_loss_values1, '+', label = 'Original model')
plt.plot(epochs, val_loss_values4, 'bo', label = 'L2 regularization')
plt.title('L2 regularization')
plt.xlabel('Epochs')
plt.ylabel('Validation Loss')
plt.legend()
plt.show()

4.4.3 添加dropout正則化

Geoffrey Hinton
訓練時隨機將矩陣一部分值設爲0
model.add(layers.Dropout(0.5))

# 4-8 向IMDB網絡中添加dropout
model = models.Sequential()
model.add(layers.Dense(16,activation = 'relu', input_shape=(10000,)))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(16, activation = 'relu'))
model.add(layers.Dropout(0.5))
model.add(layers.Dense(1, activation = 'sigmoid'))

完整代碼

# 4-8 向IMDB網絡中添加dropout
model5 = models.Sequential()
model5.add(layers.Dense(16,activation = 'relu', input_shape=(10000,)))
model5.add(layers.Dropout(0.5))
model5.add(layers.Dense(16, activation = 'relu'))
model5.add(layers.Dropout(0.5))
model5.add(layers.Dense(1, activation = 'sigmoid'))

model5.compile(optimizer = 'rmsprop',
              loss = 'binary_crossentropy',
              metrics = ['accuracy'])

history5 = model5.fit(partial_x_train,
                   partial_y_train,
                   epochs = 20,
                   batch_size = 512,
                   validation_data = (x_val, y_val))

history1_dict = history1.history
history5_dict = history5.history
loss_values = history1_dict['loss']

val_loss_values1 = history1_dict['val_loss']
val_loss_values5 = history5_dict['val_loss']

epochs = range(1, len(loss_values) + 1)

plt.plot(epochs, val_loss_values1, '+', label = 'Original model')
plt.plot(epochs, val_loss_values5, 'bo', label = 'Dropout')
plt.title('Dropout')
plt.xlabel('Epochs')
plt.ylabel('Validation Loss')
plt.legend()
plt.show()

總結常見防止過擬合的方法:

  • 獲取更多的訓練數據
  • 減小網絡容量
  • 添加權重正則化
  • 添加dropout

 

4.5 機器學習的通用工作流程

4.5.1 定義問題,收集數據集

4.5.2 選擇衡量成功的標準

  • 準確率(precision)
  • 召回率(recall)
  • ROC/AUC

4.5.3 確定評估方法

  • 留出驗證集
  • K折交叉檢驗
  • 重複的K折驗證

4.5.4 準備數據

4.5.5 開發比基準更好的模型

  • 最後一層的激活
  • 損失函數
  • 優化配置

4.5.6 擴大模型規模:開發過擬合模型

  • 添加更多的層
  • 讓每一層更大
  • 訓練更多的輪次

4.5.7 模型正則化與調節超參數

  • 添加dropout
  • 嘗試不同的架構;增加或減少層數
  • 添加L1正則或者L2正則
  • 嘗試不同的超參數,如每一層的單元格數或者優化器的學習率
  • 反覆做特徵工程

work:測試L1正則化以及同時L1和L2正則化
regularizers.l1(0.001)
regularizers.l1_l2(l1=0.001, l2=0.001

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