具體來(lái)說(shuō),

這兩個(gè)分布日志都是通過(guò) wandb 的內(nèi)置監(jiān)視實(shí)用程序處理的。

wandb.watch(model, log="all", log_freq=10)

通過(guò)迭代當(dāng)前模塊參數(shù),可以輕松完成矩陣范數(shù)。兩者為你提供了對(duì)同一數(shù)據(jù)的略有不同的視圖。

數(shù)據(jù)點(diǎn):數(shù)據(jù)集示例隨著時(shí)間的推移具有黃金價(jià)值。如果損失計(jì)算中存在錯(cuò)誤,損失指標(biāo)可能會(huì)成功下降,即使網(wǎng)絡(luò)沒(méi)有學(xué)到任何有價(jià)值的東西。錯(cuò)誤更難隱藏在人類(lèi)可理解的數(shù)據(jù)點(diǎn)中。

最終層 logits:在單標(biāo)簽、多類(lèi)別問(wèn)題中,你可能會(huì)使用 softmax 作為損失函數(shù)的一部分。由于 softmax 不是硬最大化算法,因此你可以鼓勵(lì)模型在正確的類(lèi)別上創(chuàng)建權(quán)重分布。如果你在圖表上記錄最終層 logits,你應(yīng)該注意到大多數(shù)概率質(zhì)量會(huì)隨著時(shí)間的推移收斂到正確的值(尤其是在過(guò)度擬合運(yùn)行期間)。在過(guò)度擬合過(guò)程中,你走得越遠(yuǎn),這個(gè)最大值點(diǎn)應(yīng)該越明顯。但權(quán)重應(yīng)該有一個(gè)明顯的轉(zhuǎn)變,從均勻分散到接近正確值。

這為過(guò)度擬合的進(jìn)展提供了額外的健全性檢查。它確保模型以你期望的方式在統(tǒng)計(jì)上發(fā)展,并且軟最大化值平穩(wěn)增加。通常,查看隨時(shí)間的變化是分析訓(xùn)練的一種有用方法。

如有疑問(wèn),請(qǐng)始終記錄。

2、從簡(jiǎn)單的架構(gòu)替代開(kāi)始

大多數(shù)核心 ML 活動(dòng)都有通用的抽象層。Transformers 可以用 RNN 代替,Resnet 可以代替 CNN。這些更簡(jiǎn)單的方法無(wú)法達(dá)到你想要的精度,但可能能夠證明整體線(xiàn)束的梯度流是否存在問(wèn)題。它們的訓(xùn)練速度也更快,如果你嘗試對(duì)新的過(guò)度擬合管道進(jìn)行快速健全性檢查,這將非常有用。

我還注意到,較新的筆記本電腦在矩陣乘法方面變得出奇地快。當(dāng)然還不足以訓(xùn)練整個(gè)網(wǎng)絡(luò),但我現(xiàn)在經(jīng)常發(fā)現(xiàn)自己在本地進(jìn)行初始原型設(shè)計(jì)。這項(xiàng)工作的重點(diǎn)是簡(jiǎn)單架構(gòu)上的過(guò)度擬合、數(shù)據(jù)的健全性檢查以及確保矢量化在邏輯上正確。

3、使隨機(jī)性可重現(xiàn)

現(xiàn)代模型中內(nèi)置了大量隨機(jī)性。

正如預(yù)期的那樣,這些技術(shù)有助于通過(guò)使網(wǎng)絡(luò)難以過(guò)度擬合來(lái)推廣模型。但在過(guò)度擬合期間,你確實(shí)希望它們過(guò)度擬合,理想情況下是積極地記住輸入以測(cè)試模型容量和訓(xùn)練工具。如果輸入、輸出或損失具有隨機(jī)性,則很難確定過(guò)度擬合期間是否存在問(wèn)題。

我過(guò)去常常在過(guò)度擬合時(shí)手動(dòng)禁用模型的所有隨機(jī)元素:將 dropout 設(shè)置為零,禁用數(shù)據(jù)增強(qiáng)等。這種方法的缺點(diǎn)是有很多 if elif 語(yǔ)句,而且不一定能捕獲導(dǎo)入的模塊是否在其實(shí)現(xiàn)中嵌入了一些隨機(jī)性。我沒(méi)有采用這種方法,而是在每個(gè)訓(xùn)練和驗(yàn)證步驟中開(kāi)始用固定種子為模型播種。在 Pytorch-Lightning 中,這看起來(lái)像:

CONSTANT_SEED = 60

class MySmartModule:
def training_step(self, batch):
if self.trainer.overfit_batches:
print("Will reset seed for reproducable overfitting")
pl.seed_everything(CONSTANT_SEED)

def validation_step(self, batch):
if self.trainer.overfit_batches:
print("Will reset seed for reproducable overfitting")
pl.seed_everything(CONSTANT_SEED)

這不會(huì)直接消除隨機(jī)性,但它應(yīng)該使隨機(jī)值在每個(gè)訓(xùn)練和驗(yàn)證步驟中保持一致,這實(shí)際上是同一件事。這應(yīng)該允許模型過(guò)度擬合以及零隨機(jī)性實(shí)現(xiàn)。通過(guò)日志進(jìn)行雙重檢查以確認(rèn)輸入值確實(shí)相等。

4、過(guò)度擬合1,然后 2,然后 5

任何足夠大的網(wǎng)絡(luò)都應(yīng)該能夠在少數(shù)數(shù)據(jù)點(diǎn)上達(dá)到 0 損失。我通常從一個(gè)示例(1 個(gè)批次,批次大小 1)開(kāi)始。這應(yīng)該是可以輕易學(xué)習(xí)的,因?yàn)樯踔敛恍枰獎(jiǎng)?chuàng)建判別輸出空間。如果成功,則擴(kuò)展到 2 個(gè)不同的示例,然后擴(kuò)展到 5 個(gè)不同的示例。

5、將每個(gè)自定義矢量化編寫(xiě)兩次

這聽(tīng)起來(lái)有點(diǎn)矯枉過(guò)正,但它省去了很多麻煩。每當(dāng)我做前饋傳遞值以外的任何事情時(shí),我都會(huì)將張量轉(zhuǎn)換重構(gòu)為單獨(dú)的函數(shù)。然后,我使用標(biāo)準(zhǔn) for 循環(huán)和基于單個(gè)索引的張量重寫(xiě)此邏輯。然后運(yùn)行幾個(gè)示例并確保它們的值匹配。這是驗(yàn)證矢量廣播和其他并行操作是否按預(yù)期工作的最簡(jiǎn)單方法。

具體來(lái)說(shuō),我將兩個(gè)實(shí)現(xiàn)都包裝在描述轉(zhuǎn)換的類(lèi)中。假設(shè)我們要編寫(xiě)一個(gè)掩蓋特定值顏色的函數(shù)。我從 for 循環(huán)實(shí)現(xiàn)開(kāi)始,逐個(gè)索引地進(jìn)行。調(diào)用矢量化管道的嘗試失敗了。原始類(lèi)結(jié)構(gòu)如下所示:

class ColorMasking:
def __init__(self, vectorize):
self.vectorize = vectorize

def __call__(self, *args, **kwargs):
if self.vectorize:
return self.vectorized(*args, **kwargs)
else:
logging.warning("Using greedy implementation of ColorMasking")
return self.greedy(*args, **kwargs)

def greedy(self, img):
for y in range(img.shape[0]):
for x in range(img.shape[1]):
...

def vectorized(self, img):
raise NotImplementedError()

這個(gè)類(lèi)可讓你輕松地在顯式(速度慢但更可能正確)和矢量化(速度快但更可能引入錯(cuò)誤)之間切換。它還內(nèi)置了一個(gè)可單元測(cè)試的代碼塊,可以更輕松地檢查一段時(shí)間內(nèi)的實(shí)現(xiàn)問(wèn)題。然后,你可以在神經(jīng)網(wǎng)絡(luò)模塊內(nèi)選擇是否要全面切換到矢量化,或者使用手動(dòng)矢量化對(duì)幾個(gè)時(shí)期進(jìn)行健全性檢查。

class MySmartModule(torch.nn.Module):
def __init__(self):
self.vectorize = False

def forward(img):
mask = ColorMasking(vectorize=self.vectorize)(img)

這也對(duì)實(shí)現(xiàn)過(guò)程進(jìn)行了補(bǔ)充,到目前為止您可能只有一個(gè)明確的實(shí)現(xiàn):

class MySmartModule(torch.nn.Module):
def __init__(self):
self.vectorize = False

def forward(img):
mask = ShapeMask(vectorize=self.vectorize)
mask = ColorMasking(vectorize=False)(img)

有時(shí)我會(huì)直接用這個(gè)非向量化函數(shù)運(yùn)行過(guò)度擬合作業(yè),以檢查它是否按照我的意愿運(yùn)行。有時(shí)由于速度限制,我會(huì)直接編寫(xiě)向量化邏輯。

6、單元測(cè)試輔助函數(shù)

為向量化、數(shù)據(jù)加載器和訓(xùn)練管道添加重型單元測(cè)試組。

向量化:作為上一節(jié)的延續(xù),驗(yàn)證向量化代碼是否正常工作。通過(guò)幾個(gè)手寫(xiě)示例定義預(yù)期的轉(zhuǎn)換。嘗試使用不同的張量大小并記錄預(yù)期權(quán)重或一些預(yù)期的轉(zhuǎn)換。

數(shù)據(jù)加載器:這也適用于數(shù)據(jù)加載器。如果可能,通過(guò)反向轉(zhuǎn)換來(lái)保證轉(zhuǎn)換符合預(yù)期。獲取文本 logits 的 argmax 并檢索文本,將圖像像素轉(zhuǎn)換為可以與靜態(tài)工件進(jìn)行比較的實(shí)際 PIL,等等。

訓(xùn)練管道:額外的集成測(cè)試可以驗(yàn)證訓(xùn)練管道的某些行為。最大的問(wèn)題之一通常是梯度流 – 無(wú)法正確傳播到網(wǎng)絡(luò)中較早的張量的損失。在最好的情況下,你錯(cuò)過(guò)了可驗(yàn)證的學(xué)習(xí) – 在最壞的情況下,較早的層將保持隨機(jī)初始化,而網(wǎng)絡(luò)的其余部分將猜測(cè)隨機(jī)輸入噪聲。一種解決方法是進(jìn)行測(cè)試,該測(cè)試傳遞一些合成數(shù)據(jù)并跨過(guò)梯度權(quán)重并斷言每個(gè)范數(shù)都非零。網(wǎng)絡(luò)的每一層都應(yīng)該有一些學(xué)習(xí)。

我的訓(xùn)練管道傾向于通過(guò) CLI 訓(xùn)練可執(zhí)行文件啟動(dòng)。為了確保單元測(cè)試在每次訓(xùn)練運(yùn)行中都令人滿(mǎn)意,我在初始化線(xiàn)束之前向此實(shí)現(xiàn)添加了 pytest 運(yùn)行命令。

@click.command()
def train():
pytest.main()

# Training block

7、避免使用全局變量

全局變量在常規(guī)軟件工程中通常是一種不好的形式,在機(jī)器學(xué)習(xí)中也同樣糟糕。Jupyter 非常適合原型設(shè)計(jì),但當(dāng)事物被定義為常規(guī)單元時(shí),很容易出現(xiàn)錯(cuò)誤。即使你將一些邏輯重構(gòu)為函數(shù),它們?nèi)钥赡茉谌譅顟B(tài)下獲取變量。

作為一般工作流程,我完全在全局空間中制作原型。傳遞變量并確保張量大小正確更容易。在這里我通常只處理一個(gè)批次。

在開(kāi)始完整的訓(xùn)練運(yùn)行之前,我會(huì)將所有單元重構(gòu)為單獨(dú)的函數(shù)。這確保沒(méi)有全局變量泄漏。它之前已經(jīng)捕獲了一些微不足道的錯(cuò)誤,即同一個(gè)值被無(wú)意中重復(fù)使用多次,而不是在更大的列表中進(jìn)行迭代。

8、確保(靜態(tài))批次隨時(shí)間保持不變

添加自定義數(shù)據(jù)集、自定義加載器和自定義整理函數(shù)時(shí),批次可能會(huì)隨時(shí)間發(fā)生細(xì)微偏差。當(dāng)現(xiàn)場(chǎng)操作字典或聚合某些值時(shí),這種情況尤其容易發(fā)生。我使用此代碼片段來(lái)檢查隨時(shí)間推移的相等性。

毋庸置疑,如果你在數(shù)據(jù)加載器類(lèi)中引入隨機(jī)增強(qiáng),這將不起作用。對(duì)于這些情況,我會(huì)暫時(shí)禁用轉(zhuǎn)換,然后運(yùn)行此驗(yàn)證。你還可以有選擇地將應(yīng)隨時(shí)間保持不變的鍵列入白名單,同時(shí)允許隨機(jī)轉(zhuǎn)換中的鍵發(fā)生變化。

first_sample = next(iter(train_loader))
second_sample = next(iter(train_loader))

print("Will check equality...")
for key in first_sample.keys():
first_value = first_sample[key]
second_value = second_sample[key]

if isinstance(first_value, torch.Tensor):
if not torch.equal(first_value, second_value):
print(first_value)
print(second_value)
raise ValueError(f"Unequal iterations: {key} (torch tensor)")
else:
if first_value != second_value:
print(first_value)
print(second_value)
raise ValueError(f"Unequal iterations: {key}")
print("Success...")

9、合成生成不同大小的數(shù)據(jù)

在較大的網(wǎng)絡(luò)中,尤其是通過(guò)時(shí)間反向傳播,梯度可能會(huì)在網(wǎng)絡(luò)中較早消失。我發(fā)現(xiàn)一種調(diào)試這些問(wèn)題的有用方法是合成生成不同大小的新數(shù)據(jù)點(diǎn)。

如果你的數(shù)據(jù)加載器最終接受磁盤(pán)上的文件,那么這是一種自然選擇,這在我最終構(gòu)建的大多數(shù)大型架構(gòu)中都很常見(jiàn)。編寫(xiě)一個(gè)函數(shù),以正確的格式將新數(shù)據(jù)集轉(zhuǎn)儲(chǔ)到磁盤(pán)。輸出值在這里并不重要,因?yàn)榫W(wǎng)絡(luò)應(yīng)該只記住過(guò)度擬合期間的原始值。

tokenizer = Tokenizer()
labels = ["A", "B", "C"]

@contextmanager
def create_synthetic_datapoint(text_length):
random.sample(tokenizer.vocab, text_length)
random.choice(labels)

with tempfile.TemporaryDirectory() as directory:
yield directory

with create_synthetic_datapoint(50) as path:
train_dataset = MyDataset([path])

trainer.overfit(model, train_dataset)

10、盡可能使用 einops

每當(dāng)需要張量變換(查看、轉(zhuǎn)置、堆疊等)時(shí),我都會(huì)嘗試將其放入 einop 中。它們通過(guò)引用字符串值來(lái)表示軸的含義,從而使這些操作更具描述性。它們還可以假設(shè)一些維度,否則你可能需要 .shape 算法。我嘗試在這些字符串中使用完整的單詞或變量名稱(chēng),除非某些東西很明顯,例如 b 表示批處理。

x = rearrange(x, "b height width embedding -> b (height width) embedding")

我發(fā)現(xiàn),當(dāng)我離開(kāi)某個(gè)功能幾天后,這些 einops 使調(diào)試變得容易得多。

11、結(jié)束語(yǔ)

得益于出色的開(kāi)源項(xiàng)目和與出版物一起發(fā)布代碼的日益增長(zhǎng)的趨勢(shì),成功訓(xùn)練的道路變得越來(lái)越容易。但是,當(dāng)嘗試一些新穎的東西(無(wú)論是在數(shù)據(jù)集上還是使用新的模型架構(gòu))時(shí),成功之路仍然曲折。一個(gè)字符的索引錯(cuò)誤可能會(huì)導(dǎo)致結(jié)果從 SOTA 變?yōu)槊銖?qiáng)超過(guò)基線(xiàn)。

我有一位老同事說(shuō)“軟件中一切皆有可能,你只需要花足夠的時(shí)間來(lái)構(gòu)建它?!?ML 的挑戰(zhàn)在于有些事情是不可能的——至少在目前數(shù)據(jù)和架構(gòu)的最新水平下是不可能的。 ML 研究是盡可能減少邏輯錯(cuò)誤機(jī)會(huì)的過(guò)程。因?yàn)槭】赡苁且驗(yàn)槟呈赂静豢赡堋蛘咭驗(yàn)樗赡苁且粋€(gè)錯(cuò)誤。提前勤奮和防御是確保失敗是前者而不是后者的最佳方式。對(duì)合理的失敗感到坦然是讓實(shí)驗(yàn)真正取得成功的最好方法。

更多大模型API

冪簡(jiǎn)集成是國(guó)內(nèi)領(lǐng)先的API集成管理平臺(tái),專(zhuān)注于為開(kāi)發(fā)者提供全面、高效、易用的API集成解決方案。

冪簡(jiǎn)API平臺(tái)提供了多種維度發(fā)現(xiàn)API的功能:通過(guò)關(guān)鍵詞搜索API、從API Hub分類(lèi)瀏覽API、從開(kāi)放平臺(tái)分類(lèi)瀏覽企業(yè)間接尋找API等。

此外,冪簡(jiǎn)集成開(kāi)發(fā)者社區(qū)會(huì)編寫(xiě)API入門(mén)指南、多語(yǔ)言API對(duì)接指南、API測(cè)評(píng)等維度的文章,讓開(kāi)發(fā)者選擇符合自己需求的API。

原文鏈接:http://www.bimant.com/blog/debugging-tips-for-llms-training/

上一篇:

TOP 6 文生圖大模型

下一篇:

避免AI檢測(cè)的最佳釋義工具
#你可能也喜歡這些API文章!

我們有何不同?

API服務(wù)商零注冊(cè)

多API并行試用

數(shù)據(jù)驅(qū)動(dòng)選型,提升決策效率

查看全部API→
??

熱門(mén)場(chǎng)景實(shí)測(cè),選對(duì)API

#AI文本生成大模型API

對(duì)比大模型API的內(nèi)容創(chuàng)意新穎性、情感共鳴力、商業(yè)轉(zhuǎn)化潛力

25個(gè)渠道
一鍵對(duì)比試用API 限時(shí)免費(fèi)

#AI深度推理大模型API

對(duì)比大模型API的邏輯推理準(zhǔn)確性、分析深度、可視化建議合理性

10個(gè)渠道
一鍵對(duì)比試用API 限時(shí)免費(fèi)