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