0
確保網(wǎng)絡正常運行的關鍵因素之一是網(wǎng)絡的配置。正如機器學習大師 Jason Brownle 所說,「深度學習神經(jīng)網(wǎng)絡已經(jīng)變得易于定義和擬合,但仍然難以配置。」
本文分為以下幾個部分:
訓練一個神經(jīng)網(wǎng)絡,在開始訓練過程之前需要討論什么是最重要的,以便更好地控制我們的模型。
逐漸增加模型復雜性(如果需要的話),我們將知道為什么從一個簡單的模型架構開始,然后根據(jù)需要增加復雜性很重要。
調整函數(shù)的權重,這將導致超參數(shù)的調整,以提高神經(jīng)網(wǎng)絡的性能。
除此之外,還將討論模型集成和模型壓縮等技術。
在這一過程中,我將分享個人評論、來自資深學習實踐者的故事和代碼片段。享受你的學習之旅吧!
訓練神經(jīng)網(wǎng)絡
讓我們先來看一下可能會失敗的神經(jīng)網(wǎng)絡有哪些共同點。正如 OpenAI 的 Josh Tobin 所指出的那樣,深度學習模型中最常見的五個錯誤如下:
實施 bug:
如果在加載圖像數(shù)據(jù)時,意外地混淆了圖像和標簽的順序,并且所有圖像都以錯誤的方式進行了標記,會怎么樣?出現(xiàn)這種情況時,你可能無法立即發(fā)現(xiàn)它,因為少數(shù)(圖像、標簽)對可能是偶然正確的。請考慮以下代碼段:
X_train = shuffle(X_train)
Y_train = shuffle(y_train)
而實際上它應該是:
X_train, y_train = shuffle(X_train, y_train)
如果標準縮放表格數(shù)據(jù)集的分類特征,會怎樣?將分類特征表示為一個熱編碼向量,并將其視為另一個數(shù)字特征是截然不同的??紤]以下小數(shù)據(jù)集:
樣本數(shù)據(jù)集
這里有三個分類特征:Sex, Has_Masters 和 Has_Bachelors。你可以用 one-hot 編碼來更好地表示關系,或者你可以保持它們的原樣。數(shù)據(jù)集中有兩個連續(xù)的特征:Age 和 Bounties。它們在計量單位上有很大的不同,所以你需要將它們的比例標準化。由于所有變量都是數(shù)值型的,你可以考慮使用以下方法來標準化連續(xù)特征:
scaler = StandardScaler()
scaled_train = StandardScaler().fit_transform(data.values)
但它應該是:
scaled_train = StandardScaler().fit_transform(data[non_cat_feats].values)
如果將所有權重初始化為零,然后使用 ReLU 會如何?
有幾種方法可以初始化神經(jīng)網(wǎng)絡中的權重。你可以從將所有的權重設置成零開始(這是不可取的),你可以隨機初始化它們,或者你可以選擇一種技術,如 Xavier 初始化或 HE 初始化。如果你使用 Xavier 或 HE 方案,則需要相應地考慮激活函數(shù)。例如,推薦 TANH 激活使用 Xavier 方案,而 RELU 激活使用 HE 方案。使用 keras 聲明網(wǎng)絡時,請考慮以下示例:
# Define a Sequential model
model = Sequential()
model.add(Dense(64, kernel_initializer='zeros', activation='relu'))
...
在上面的例子中,模型的權重初始化為零,這意味著在將輸入值乘以初始化為零的權重后,結果只有零。如果要使用 ReLU 激活函數(shù),更好的方法是:
# Define a Sequential model
model = Sequential()
model.add(Dense(64, kernel_initializer='he_normal', activation='relu'))
...
你在用 PyTorch 嗎?你忘了把梯度歸零了嗎?這是 PyTorch 用戶特有的,因為這些梯度是在反向傳播過程中累積的,不會更新。你不希望將權重以小批量混合;你希望以正確的方式更新參數(shù)。
請在 PyTorch 中考慮以下訓練循環(huán):
for e in range(epochs):
running_loss = 0
# Loop over the images and labels in the current batch
for images, labels in trainloader:
# Load the data to the available device and reshape the images
images = images.to(device)
labels = labels.to(device)
images = images.view(images.shape[0], -1)
# Get predictions from the model and determine the loss
log_ps = model(images)
loss = criterion(log_ps, labels)
# Calculate the gradients and update the parameters
loss.backward()
optimizer.step()
running_loss += loss.item()
注意,在更新參數(shù)之前,代碼不會將梯度歸零。在使用模型進行預測之前,請嘗試下面的代碼行:optimizer.zero_grad()。
模型對超參數(shù)選擇的敏感性:
在訓練過程的開始使用非常高的學習速率。你不想在訓練過程的一開始就分道揚鑣,也不想學習速率太低,以至于模型需要永遠接受訓練。
非常高的學習速率會導致非常大的權重更新,產(chǎn)生 NaN 值。由于這種數(shù)值具有不穩(wěn)定性,當 NaN 值開始慢慢變多時,網(wǎng)絡變得完全無用。
學習速率是一個完整的領域,需要深入研究。如果您感興趣,可以研究下這篇文章:https://blog.floydhub.com/ten-techniques-from-fast-ai/ 。
設置的時間段太少,無法在大型數(shù)據(jù)集上正確訓練模型。你可能有一個相當大的數(shù)據(jù)集,例如 ImageNe,并且你不允許模型(不是預先訓練的模型)通過數(shù)據(jù)進行足夠數(shù)量的迭代。
為相對較小的數(shù)據(jù)集設置過大的 batch 大小。你正在為一個只有 100 個圖像的模型擬合,并將 batch 大小設置為 64。在這種情況下,有一個相對較小的 batch 更好。
數(shù)據(jù)集構造和其他:
你沒有以正確的方式構造驗證集。訓練數(shù)據(jù)集中的類分布在很大程度上不同于驗證集。驗證本身也可能有問題。假設你正在構建一個圖像分割模型,并且數(shù)據(jù)集由從視頻中捕捉的幾個幀組成。創(chuàng)建帶有隨機拆分的部分驗證集可能不是一個好主意,因為你可能最終在驗證集中擁有一個與訓練集中某個圖像非常相似的圖像。在這種情況下,模型很容易從驗證集中對圖像進行分割。一個好的驗證集包含的圖像本質上與訓練集中的圖像不連續(xù)。(該示例的靈感來自 Fastai 提供的《Practical Deep Learning for Coders v3》課程。)
訓練組中的數(shù)據(jù)分布與測試組有很大不同。例如,你已經(jīng)在貓和狗的低分辨率圖像上訓練了模型,并且正在高分辨率圖像上測試模型。請考慮以下示例,以便更清楚地理解這一點:
假設一個虛擬網(wǎng)絡正在由左側圖像組成的數(shù)據(jù)集上訓練?,F(xiàn)在,如果在右邊的圖片上進行測試,這個訓練過的網(wǎng)絡很可能會失敗,因為網(wǎng)絡從來沒有遇到過貓的圖片。
數(shù)據(jù)集中有標簽噪聲。這是一個非常嚴重的問題,很難發(fā)現(xiàn)。當數(shù)據(jù)點的標記不正確時,就會出現(xiàn)此問題。假設您正在處理狗貓數(shù)據(jù)集,有一些狗的圖像被錯誤地標記為貓,有些貓的圖像被錯誤地標記為狗。如果在錯誤未糾正的情況下訓練模型,你會發(fā)現(xiàn)它沒有按預期執(zhí)行。
假設你正在微調一個預先訓練的模型,以便對不同品種的金魚進行分類。如果在構造數(shù)據(jù)集時,沒有使用預訓練模型的原始數(shù)據(jù)集的平均值和標準偏差來規(guī)范化數(shù)據(jù)集。這樣,你的網(wǎng)絡將無法捕獲正在接受訓練的數(shù)據(jù)集的真實分布。
數(shù)據(jù)集中有一個主要的類不平衡,但是你得到了一個很好的精度分數(shù),你就陷入了精度悖論。部署模型時,它無法檢測次要類。
以上問題是深度學習實踐者在日常工作中遇到的最普遍的問題。我們非常需要完全擁有我們的深度學習模型,這樣我們就可以根據(jù)需要調試它們,而不會失去理智。
使整個深度學習模型調試過程非常困難的因素是,一個深度學習模型可能會悄無聲息地失敗。考慮以下情況:
在數(shù)據(jù)增強過程中,你選擇的超參數(shù)會增強圖像,使其標簽更改。
數(shù)據(jù)增強的影響有時可能是殘酷的!在這種情況下,數(shù)字 6 可能會在其標簽仍為 6 時旋轉為 9
在應用遷移學習時,你沒有使用原始數(shù)據(jù)集的平均值,在原始數(shù)據(jù)集上訓練模型(將要使用的模型)來對你的自定義數(shù)據(jù)集執(zhí)行平均減法。假設您正在使用 VGG16 網(wǎng)絡構建一個狗的圖像分類器。與貓數(shù)據(jù)集相比,網(wǎng)絡是在 ImageNet 數(shù)據(jù)集上訓練的?,F(xiàn)在假設你正在編寫數(shù)據(jù)加載器,如下所示:
# initialize the data generator object
datagen = ImageDataGenerator()
# specify the mean to the data generator object
# so that it can perform mean subtraction on the fly
datagen.mean = dogs_cats_mean
但在這種情況下,正確的方法是:
# initialize the data generator object
datagen = ImageDataGenerator()
# specify the mean to the data generator object
# so that it can perform mean subtraction on the fly
mean = np.array([123.68, 116.779, 103.939], dtype="float32") # ImageNet mean
datagen.mean = mean
上面的代碼片段使用 Keras ImageDataGenerator 類將數(shù)據(jù)流傳輸?shù)侥P汀?/p>
不幸的是,這些對單元測試來說也不是小事。你將需要對模型、其配置、超參數(shù)選擇等有完整的命令,以了解其失敗的原因和性能良好的原因。正如 Andrej Karpathy 所解釋的那樣:
因此,(這一點很難被過分強調)訓練神經(jīng)網(wǎng)絡的「快速而激烈」的方法不起作用,只會導致痛苦。現(xiàn)在,痛苦是讓神經(jīng)網(wǎng)絡正常工作的一個非常自然的部分,但它可以通過徹底、偏執(zhí)和沉迷于基本上所有可能事情的可視化來減輕。
顯然,我們需要在這方面有相當水平的專業(yè)知識,使我們能夠在適當?shù)臅r候發(fā)現(xiàn)上述各種問題。這需要經(jīng)驗、知識和深思熟慮的實踐。
在我們練習的時候,我們需要知道一些最常見的策略,以避免讓我們自己遭受遇到怪異模型的痛苦。訓練神經(jīng)網(wǎng)絡需要大量的原型。在下一節(jié)中,我們將重點介紹模型原型制作過程中的一些要點和一些應用策略。
維護一個健康的原型過程
深度學習實驗包括快速原型,即為給定的任務嘗試新的模型架構,使用相同的模型架構嘗試不同的配置,等等。Matt Gardner 等人在他們廣受歡迎的 Writing Code for NLP Research 中,仔細地列出了原型設計的三個主要目標,下面我將對它們進行總結。
快速編寫代碼:通過重用現(xiàn)有的代碼/框架建立一個基線(又稱:不要重新發(fā)明輪子!)。嘗試找到一個現(xiàn)有的項目來解決你正在處理的相同問題(或與問題非常相似的問題)。這里的想法是快速脫離標準位,在原型制作過程中更多地關注新的位。
小心使用別人的組件也是明智的。你應該能夠閱讀代碼,能夠在需要時繞過抽象等等。
運行實驗并跟蹤你所做的嘗試:有時,如果你和你的團隊沒有相應地維護一個注冊表,則幾乎不可能跟蹤原型制作過程中發(fā)生的所有事情。因此,你可能會錯過原型制作過程中發(fā)生的一些不可思議的事情??偨Y原型制作過程中的實驗,以及 floydhub 之類的平臺或 git 提交的電子表格中的適當指標及其結果。下圖完美地表達了這一想法:
靈感來源
分析模型行為。它做的是你想要的嗎?你的指標提高了嗎?如果沒有,那就找出原因。一個好的起點是分析網(wǎng)絡內部發(fā)生的偏差-方差分解。TensorBoard 可能會很有幫助,因為它使你能夠非常有效地可視化你的網(wǎng)絡的訓練行為與許多定制選項。
現(xiàn)在,我們將討論一個非常關鍵全面的檢查機制,它可以幫助識別模型中的許多隱藏錯誤,有時還可以幫助識別數(shù)據(jù)預處理步驟中的許多隱藏錯誤。
過擬合單批數(shù)據(jù)
-在進行其他操作之前,請確認你的模型能夠記住單個 batch 的標簽,并快速將損失降到零
-這個跑起來很快,如果模型做不到,那你就知道它壞了
-Tom B Brown,2019 年 7 月 30 日
這種理智的檢查常常被忽視!
這種技術假設我們已經(jīng)有了一個模型,并在給定的數(shù)據(jù)上運行?,F(xiàn)在,我們希望能夠在單個 batch 數(shù)據(jù)上得到任意接近于零的損失。這帶來了許多問題:
損失可能上升而不是下降
損失可能會持續(xù)下降一段時間,然后突然上升
損失可能在一個區(qū)域內振蕩
損失可以降到一個標量(例如,0.01),但不會比這個更好
以下是導致上述問題的最常見原因:
根據(jù)我的經(jīng)驗,我發(fā)現(xiàn)我最常見的錯誤要么是沒有按照正確的順序加載數(shù)據(jù)和標簽,要么是沒有在登錄時應用 softmax。
接下來,我們將討論為什么從一個簡單的實驗模型體系結構開始,然后逐漸增加復雜性常常會有幫助。它不僅有助于更好的研究,而且對于模型調試也非常有效。
作為順序函數(shù)的模型復雜性
簡單的開始比我們想象的更重要。將一個淺層的完全連接的網(wǎng)絡與我們的數(shù)據(jù)集相匹配必然會給我們帶來糟糕的性能。我們應該確定這一部分,它不應該偏離太多。如果偏離的話,肯定是出問題了。在簡單的模型中檢測出錯誤比在 resnet101 模型中更容易。
在重用預先訓練的模型之前,確定該模型是否真的適合當前的任務。以下是在選擇網(wǎng)絡體系結構時應考慮的一些指標:
網(wǎng)絡訓練時間
最終網(wǎng)絡的大小
推理速度
準確性(或特定于任務的其他適當度量)
PS:我們在上一篇文章中使用了 FashionMNIST 數(shù)據(jù)集,我們在這里也將使用這個數(shù)據(jù)集。
FashionMNIST 數(shù)據(jù)集帶有預定義的訓練集和測試集。我們將首先創(chuàng)建更小的數(shù)據(jù)子集,包括訓練集中的 1000 個(每個類 100 個圖像)圖像和隨機順序的測試集中的 300 個(每個類 30 個圖像)。我們還將確保這兩個集合中類的分布沒有任何偏差。
我們首先可以使用下面的 helper 函數(shù)生成一組關于標簽和集合的隨機索引:
def generate_random_subset(label, ds_type):
if ds_type == 'train':
# Extract the label indexes
index, = np.where(y_train==label)
index_list = np.array(index)
# Randomly shuffle the indexes
np.random.shuffle(index_list)
# Return 100 indexes
return index_list[:100]
elif ds_type == 'test':
# Extract the label indexes
index, = np.where(y_test==label)
index_list = np.array(index)
# Randomly shuffle the indexes
np.random.shuffle(index_list)
# Return 30 indexes
return index_list[:30]
然后我們可以以迭代的方式創(chuàng)建訓練和測試,如下所示:
# Generate the training subsetindexes = []for label in np.unique(y_train):
index = generate_random_subset(label, 'train')
indexes.append(index)all_indexes = [ii for i in indexes for ii in i]x_train_s, y_train_s = x_train[all_indexes[:1000]],\
y_train[all_indexes[:1000]]
現(xiàn)在訓練子集已經(jīng)被創(chuàng)建好啦??梢杂妙愃频姆绞絼?chuàng)建測試子集。創(chuàng)建測試子集時,請確保將測試傳遞給 generate_random_subset()函數(shù)。
這兩個子集現(xiàn)在準備好了。我們現(xiàn)在可以建立一個非常簡單、完全連接的網(wǎng)絡。讓我們從以下體系結構開始:
Flatten 層將圖像轉換為 Flatten 向量,然后是密集層,最后是另一個密集層生成輸出。讓我們看看其他細節(jié)的代碼:
# Baseline modelmodel = tf.keras.models.Sequential([
tf.keras.layers.Flatten(input_shape=(28, 28)),
tf.keras.layers.Dense(128, activation='relu',kernel_initializer='he_normal'),
tf.keras.layers.Dense(10, activation='softmax')])model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
一種直接的模型配置,由于存在 ReLU 激活,可以初始化 dense 的權重。如果你想了解更多關于神經(jīng)網(wǎng)絡中權重初始化的知識,請看這節(jié)課。現(xiàn)在是時候繼續(xù)訓練這個模型的 5 個階段,batch 大小為 32,同時驗證它:
# Train the network and validatemodel.fit(x_train_s, y_train_s,
validation_data=(x_test_s, y_test_s),
epochs=5,
batch_size=32)
正如所料,它沒有在社交媒體上獲得一個值得一提的分數(shù):
模型過擬合——看看損失和值損失指標。讓我們從深度學習中最常見的錯誤列表里面交叉檢查下面幾點:
對損失函數(shù)的輸入不正確:這在我們的模型中不存在,因為我們使用 CrossEntropy 作為損失函數(shù),它隱式地處理這種情況。如果我們用的是 NegativeLogLoss,我們可以再檢查一遍。
數(shù)值不穩(wěn)定性- inf/NaN:這可以通過觀察每一層的數(shù)學運算來驗證。除法、求冪、對數(shù)等運算都可能導致 inf/NaN。在我們的情況中,只有最后一層不是這樣的。
這里需要考慮的幾點:
創(chuàng)建隨機子集幾次,并查找評估度量中的任何特殊變化。如果觀察到變化,我們肯定應該進一步調查。
預測幾個單獨的測試樣本并手動驗證它們。如果模型對圖像的分類不正確,請進行人工評估——你是否可以對該圖像進行正確分類?
可視化模型的中間性能。這有助于學習模型是如何處理圖像的。正如 Andrej Karpathy 在他的文章中所說的那樣:
明確正確的數(shù)據(jù)可視化位置就在 y_hat=model(x)(或 tf 中的 sess.run)之前。也就是說,你想把進入你的網(wǎng)絡的東西形象化,把數(shù)據(jù)和標簽的原始張力解碼成具體形象。這是唯一的「真理之源」。我數(shù)不清這多少次拯救了我,也暴露了數(shù)據(jù)預處理和擴充方面的問題。
我們來談談第二點,并做一些預測。我已經(jīng)創(chuàng)建了一個 helper 函數(shù),它將以一個索引作為輸入,并將返回模型對與索引對應的圖像的預測以及它的真實標簽。以下是 helper 函數(shù):
def show_single_preds(index):
pred = model.predict_classes(np.expand_dims(x_test_s[index], axis=0))
print('Model\'s prediction: ',str(class_names[np.asscalar(pred)]))
print('\nReality:', str(class_names[y_test_s[index]]))
plt.imshow(x_test_s[index], cmap=plt.cm.binary)
plt.show()
下面是一些關于函數(shù)的預測:
show_single_preds(12)
show_single_preds(32)
模型也做出了一些錯誤的預測:
show_single_preds(101)
show_single_preds(45)
請注意,進行這些實驗時,圖像可能會有所不同,因為子集是隨機構造的。
從這兩個錯誤的預測中,你可以注意到模型混淆了褲裝和連衣裙。上圖第一眼看上去很像一條褲子,但如果仔細看,那是一條裙子。這個簡單的模型無法找到這個細粒度的細節(jié)。繪制混淆矩陣應該能說明這一點:
這個模特把上衣和套頭衫混為一談。如果有人感興趣,下面的代碼生成一個類似于上面的混淆矩陣圖:
# Plotting model's confusion matrix
import scikitplot as skplt
preds = model.predict_classes(x_test_s)
skplt.metrics.plot_confusion_matrix(y_test_s, preds, figsize=(7,7))
plt.show()
scikitplot 庫使生成混淆矩陣圖變得非常容易。
我們現(xiàn)在對基線模型很有信心,我們知道它的配置,我們知道它的失敗在哪里?;€模型以展平矢量為輸入。當涉及到圖像時,像素的空間排列會因為它們變平而丟失。這鞏固了一個基礎,即在將數(shù)據(jù)傳送到網(wǎng)絡之前,數(shù)據(jù)表示部分很重要,而且這種表示因體系結構而異。盡管我們在圖像示例中看到了它,但對于其他類型的數(shù)據(jù),其一般概念也保持不變。
你可能希望保存正在工作的訓練和測試集的當前子集,以便在合并更復雜的模型時看到任何進一步的改進。由于子集只不過是 numpy 數(shù)組,你可以通過以下方式輕松保存它們:
# Saving the subsets for reproducibility
np.save('tmp/x_train_s.npy', x_train_s)
np.save('tmp/y_train_s.npy', y_train_s)
np.save('tmp/x_test_s.npy', x_test_s)
np.save('tmp/y_test_s.npy', y_test_s)
save()以 .npy 格式序列化 numpy 數(shù)組。要加載并驗證序列化是否正確完成,我們可以編寫如下內容:
# Load and verifya = np.load('tmp/x_train_s.npy')plt.imshow(a[0], cmap=plt.cm.binary)plt.show()
你應該得到類似這樣的輸出:
此時,你可以安全地使用數(shù)據(jù)集構建更復雜的模型。Josh Tobin 在他的《Troubleshooting Deep Neural Networks》中列出了常見的架構:
一旦我們啟動并運行了復雜的模型,并且驗證了它產(chǎn)生的結果,接下來的步驟就是優(yōu)化超參數(shù)。
調整旋鈕:追蹤超參數(shù)
超參數(shù)對模型的性能有很大影響。與權重和偏差不同,這些是由開發(fā)人員明確指定的內容,通常不需要學習。在神經(jīng)網(wǎng)絡中,超參數(shù)的例子包括學習速率、階段數(shù)、batch 大小、優(yōu)化器(以及它的配置)等。如果你想加深對超參數(shù)和一些優(yōu)化過程的理解,我強烈推薦 floydhub 的 alesio 寫的這篇文章。
我們將獲取最重要的超參數(shù)集(根據(jù)網(wǎng)絡類型的不同而有所不同),并討論以有效方式對其進行優(yōu)化的策略。
Declarative Configuration 簡介
機器學習的代碼庫通常很容易出錯,而神經(jīng)網(wǎng)絡可能會失敗得悄無聲息。深度學習實驗包含大量基于試驗和錯誤的帶有超參數(shù)的手動檢查。隨著我們對模型的不斷試驗,超參數(shù)的選擇變得越來越成熟。我們可能希望嘗試我們最喜歡大小的 batch 或一組不同的學習速率,或兩者相結合。在我們的實驗中,我們經(jīng)常希望能夠調整超參數(shù)的任意組合。
因此,在這些情況下,最好將超參數(shù)的規(guī)范部分與訓練循環(huán)分開。有許多框架遵循聲明性配置,如 tensorflow 對象檢測 api(tfod)、allennlp、caffe 等。下圖顯示了 TensorFlow 對象檢測 API 中遵循的這種配置的一部分:
請注意,tensorflow 對象檢測 api 是如何允許我們指定超參數(shù),如批處理大小、優(yōu)化器的。最好設計代碼庫,以便使用聲明性配置來處理超參數(shù)的規(guī)范。我強烈建議您查看本文以了解有關 tensorflow 對象檢測 api 的更多信息。
組織超參數(shù)調整過程
如前所述,有了經(jīng)驗和對不同組件的算法的良好理解,你可以很好地選擇正確的超參數(shù)值集。但達到那個水平需要一段時間。在你此之前,你需要依賴于超參數(shù)優(yōu)化方法,比如網(wǎng)格搜索、隨機搜索、粗到精搜索和貝葉斯超參數(shù)優(yōu)化。
Josh 列出了最常見的超參數(shù)及其對模型性能的影響:
注意,對于基于序列的模型來說,這些超參數(shù)可能會改變。
在本文的最后一部分,我們將討論兩種在提高模型精度方面非常有效的策略:模型集成、知識提煉等等。
模型集成、知識蒸餾
在本節(jié)中,我將向你介紹模型集成,并解釋它為什么工作(以及它為什么不工作),然后告訴你有關知識蒸餾的知識。但首先,讓我再次引用 Andrej Karpathy 的話:
模型集成是一種幾乎可以保證在任何事情上獲得 2% 精度的方法。如果你在測試時負擔不起計算開銷,可以考慮使用暗知識將你的集成提取到一個網(wǎng)絡中。
模型集成
模型集成的概念比聽起來簡單;它指的是組合來自多個模型的預測。但為什么要這么做呢?好吧,神經(jīng)網(wǎng)絡在本質上是隨機的,這意味著如果你用相同的數(shù)據(jù)集進行相同的實驗,你可能不會一直得到相同的結果。在生產(chǎn)環(huán)境中,甚至在黑客大會和個人項目中,這都會令人沮喪。
這個問題的一個非常簡單的解決方案如下:
在同一數(shù)據(jù)集上訓練多個模型
使用所有這些模型在測試集上進行預測
把那些預測平均化
這種方法不僅允許不同模型的集成來捕獲數(shù)據(jù)集的方差,它也比任何一個模型都能得到更好的分數(shù)。Goodfellow 等人在他們廣受歡迎的深度學習書籍中簡單地解釋了為什么這樣做:
模型平均有效的原因是不同的模型通常不會在測試集上產(chǎn)生相同的錯誤。
要詳細了解不同的加密方法,可以查看這篇 MLWave 團隊的文章。
模型集成并不是最終的全部解決方案;當涉及到構建深度學習系統(tǒng)時,它有一個明顯的缺點:
提高幾乎所有機器學習算法性能的一個非常簡單的方法是在相同的數(shù)據(jù)上訓練許多不同的模型,然后對它們的預測進行平均。不幸的是,使用一整套模型進行預測是很麻煩的,而且計算成本可能太高,不允許部署到大量用戶,特別是如果單個模型是大型神經(jīng)網(wǎng)絡時——Hinton 等人在《Distilling the Knowledge in a Neural Network》中提到。
這些沉重的模型很難部署在硬件資源有限的邊緣設備上。你可能會問:「如果這個龐大的模型可以作為 rest api 在云上公開,然后根據(jù)需要在以后使用呢?」但有一個制約因素:缺乏可靠的互聯(lián)網(wǎng)連接。還有一個因素需要考慮,那就是不太復雜的模型通常無法捕獲數(shù)據(jù)的底層表示。在擴展這些模型時,還需要考慮環(huán)境成本,如果模型提供實時推理,還需要考慮對服務水平協(xié)議的依賴性。即使你有一個巨大的連接,也不太可能在云中部署模型。以特斯拉自動駕駛儀為例,當汽車在行駛時,它不能總是查詢云服務以獲得所需的預測。這些預測任務可以包括目標定位、車道檢測、行人檢測等。
記住,網(wǎng)絡越大,占用的設備內存越多,占用的設備內存越多,部署起來就越困難。
我們希望能夠將復雜(重量級)模型的知識提取為更簡單的模型,我們希望那些更簡單的模型能夠很好地逼近復雜模型所學習的關系。因此,現(xiàn)在是討論知識蒸餾的時候了。
知識蒸餾
Hinton 等人早在 2015 年就在他們的開創(chuàng)性論文《Distilling the Knowledge in a Neural Network》中首次提出了知識蒸餾的概念。這個想法涉及兩個網(wǎng)絡:教師網(wǎng)絡和學生網(wǎng)絡。
利用教師網(wǎng)絡從原始數(shù)據(jù)中提取模式,以期生成軟目標。軟目標有助于我們消除在數(shù)據(jù)集的不同數(shù)據(jù)點中可能存在相似性的歧義。例如,它幫助我們了解 mnist 數(shù)據(jù)集中有多少 2 和 3 類似。這些軟目標以類概率的形式出現(xiàn),它們捕獲的原始數(shù)據(jù)集信息比硬目標多得多。軟目標也表示一種不確定性,通常被稱為暗知識。
然后將這些軟目標反饋給學生網(wǎng)絡,以模擬教師網(wǎng)絡的輸出(硬目標)。通過匹配輸出分布,訓練學生網(wǎng)絡以與教師相同的方式進行泛化。但這里有一個小問題:交叉熵損失被軟目標(如教師網(wǎng)絡所產(chǎn)生的)而不是硬目標所取代,然后轉移到學生網(wǎng)絡。
我絕對建議檢查一下這個由「Hugging Face」團隊完成的工作,這個團隊能夠將知識蒸餾的思想融入到他們的一個架構 distilbert 中,distilbert 是強大的語言模型 bert 的提煉版本。
彩票假說
神經(jīng)網(wǎng)絡的大小取決于它包含的參數(shù)數(shù)目。例如, VGG16 網(wǎng)絡包含 1.38 億個參數(shù),其大小約為 528MB(keras)。現(xiàn)代語言模型架構,如 BERT 及其變體,甚至更重??纯聪旅娴膱D表,它顯示了語言模型中參數(shù)數(shù)量的逐漸增加。
在部署模型以運行推理時,這種沉重性是模型的主要限制。這就是網(wǎng)絡剪枝技術發(fā)揮作用的地方,它們可以將模型中的參數(shù)數(shù)量減少 90%,而不會對性能造成太大影響。彩票的概念是一個探索了這一現(xiàn)象的令人難以置信的研究。
Jonathan 等人在 2018 年的論文《The Lottery Ticket Hypothesis: Finding Sparse, Trainable Neural Networks》中首次探索了深度學習彩票的思想。作者認為,刪除網(wǎng)絡中的小權重并對其進行再訓練可以產(chǎn)生令人震驚的結果。他們提出的想法非常簡單:訓練一個網(wǎng)絡,將小于某個閾值的權重設置為零,即刪減權重,然后用未運行的權重重新訓練網(wǎng)絡,使其達到初始配置。這不僅比無權值剪枝的網(wǎng)絡有更好的性能,它還表明了:
與更大的、未運行的網(wǎng)絡相比,積極剪枝的網(wǎng)絡(85% 到 95% 的權重修剪)性能沒有下降
只有適度剪枝的網(wǎng)絡(50% 到 90% 的權重修剪)通常比未剪枝的網(wǎng)絡表現(xiàn)更好。
在剪除較大網(wǎng)絡中的權重之后,我們得到了一個幸運的子網(wǎng)絡,作者稱之為中獎彩票。
要了解更多關于彩票的評論以及如何確定剪枝權重的標準,一定要查看 Uber AI 的這篇文章。
量化
如前所述,最終的網(wǎng)絡模型通常不太可能通過云作為 api。在大多數(shù)情況下,我們希望能夠在設備上服務,比如通過手機。另一種減小模型大小并使其更易于服務的方法是量化。
模型量化直接關系到數(shù)值精度,如 float64、float32、float16、int8、int16 等。深度學習模型通常在所有計算中使用 float32 精度,這代表著網(wǎng)絡參數(shù)是最重要的參數(shù)。深度學習模型的大小取決于其權重記錄的精度。精度越高,模型就越重。所以,問題是:我們能否利用較低的數(shù)值精度來表示(重)網(wǎng)絡的權重?當然可以,但這需要更低的精度,盡管它仍然可以與較重模型的精度相媲美。這是通過量化實現(xiàn)的。下圖顯示了當更高精度的網(wǎng)絡權重量化為更低精度時會發(fā)生什么。
如果您想了解有關模型量化的更多信息,請從本文開始。
結論
你看到了最后:恭喜你!
整理這篇文章的主要目的是歸納不同研究者的有價值的發(fā)現(xiàn),以便給社區(qū)提供一份關于神經(jīng)網(wǎng)絡及其訓練的所有相關內容的詳盡文檔。我們已經(jīng)介紹了如何訓練一個神經(jīng)網(wǎng)絡,你可能會發(fā)現(xiàn)什么樣的錯誤,以及如何處理它們,還有非常棒的彩票假說。當然,我的文章不可能包含關于訓練和調試神經(jīng)網(wǎng)絡這一主題的所有內容,因此請查看下面的鏈接,以便進一步閱讀,并查看這些資源以進行進一步研究,所有這些都是我對該主題的理解的基礎:
Josh Tobin 的 Troubleshooting Deep Neural Networks。如果你想真正有效地調試神經(jīng)網(wǎng)絡,這可能是最好的指南。
Andrej Karpathy 的 A Recipe for Training Neural Networks , Andrej Karpathy 在這里分享了他訓練神經(jīng)網(wǎng)絡的個人心得。
deeplearning.ai 的 Improving Deep Neural Networks: Hyperparameter tuning, Regularization and Optimization 。這門課程講授了提高神經(jīng)網(wǎng)絡性能的許多方面,涵蓋了正則化、超參數(shù)調整等許多基本方面。
Joel Grus、Matt Gardner 和 Mark Neumann 在 EMNLP 2018 上的演講 Writing Code for NLP Research。它討論了一系列的技巧和建議,在編寫基于 NLP 的應用程序的代碼時應該牢記這些技巧和建議,并且它可以很容易地擴展到一般的深度學習項目。
Joel Grus 的 Reproducibility in ML,它討論了機器學習中的可再現(xiàn)性的許多關鍵問題,并揭示了克服這些問題的一些解決方案。它最初是 ICML 2019 在機器學習研討會上再現(xiàn)性的一部分。
FastAI 的 Deep Learning from the Foundations 。這門課程采用了一種非常重代碼的方法來教授從構建塊進行深度學習。
Google Developers 的 Testing and Debugging in Machine Learning。這門課程討論了幾個重要的方面,從調試模型到監(jiān)視生產(chǎn)中的管道。
Jason Brownlee 的 Better Deep Learning,這本書致力于提高深度學習神經(jīng)網(wǎng)絡模型的性能。
Sanjeev Arora 的 Toward theoretical understanding of deep learning,介紹了深度學習的一些關鍵理論方面,并對其進行了詳細討論。
via:https://blog.floydhub.com/training-neural-nets-a-hackers-perspective/
雷鋒網(wǎng)雷鋒網(wǎng)雷鋒網(wǎng)
雷峰網(wǎng)版權文章,未經(jīng)授權禁止轉載。詳情見轉載須知。