【ChatGPT】大語言模型使用案例1——查詢API和相關(guān)知識

當(dāng)人們聽說圖書館已經(jīng)收集齊全所有的書籍時,首先得到的是一種奇特的幸福感。人們都覺得自己是一座完整無缺的秘密寶庫的主人。任何個人或世界的問題都可以在某個六角形里找到有說服力的答案?!菍ふ艺咄耍粋€人要找到……的機會幾乎等于零。 ——豪爾赫·路易斯·博爾赫斯《通天塔圖書館》
現(xiàn)在,以ChatGPT為代表,眾多大語言模型 (LLM) 并駕齊驅(qū),快速走進人們生產(chǎn)生活中。如果你想向別人提問有關(guān)機器學(xué)習(xí)、編程或其他各種主題,你可以在這里找到幫助。
但是,如果你想得到最有價值的回答,你需要知道如何巧妙地提問。那么,本文展示一些成功使用ChatGPT的例子,同時介紹一些提問的原則,以便獲得最準(zhǔn)確、最有用的回答。(*此開頭由ChatGPT生成,做了少許修改)

案例:實驗室提出需求,模型要部署在邊端設(shè)備上。因此,需要評估模型。向AI提問關(guān)于評估模型的“thop”庫和使用。
**Human:** 你知道thop庫嗎?
**AI:** `作為AI助手,我不太清楚關(guān)于“thop庫”的具體細節(jié)。但是,根據(jù)我的了解,thop是一種計算模型量和計算量的工具,可以幫助深度學(xué)習(xí)開發(fā)人員優(yōu)化神經(jīng)網(wǎng)絡(luò)模型。thop庫能夠計算模型的FLOPs和參數(shù)數(shù)量,從而評估模型的計算復(fù)雜性和規(guī)模,以便進行優(yōu)化和構(gòu)建更高效的神經(jīng)網(wǎng)絡(luò)。`
**Human:** 是的,就是你說的thop。你知道這個庫如何使用嗎?
**AI:** `thop庫主要用于計算深度神經(jīng)網(wǎng)絡(luò)的FLOPs和參數(shù)數(shù)量,幫助我們評估模型的計算量和復(fù)雜度。使用thop庫的步驟如下:
1. 安裝thop庫,可以使用pip進行安裝:`pip install thop`
2. 導(dǎo)入thop庫:`from thop import profile`
3. 定義模型并輸入模型輸入數(shù)據(jù):`model = YourModel()`,`inputs = torch.randn(...)`
4. 調(diào)用thop庫中的`profile`函數(shù)計算模型的FLOPs和參數(shù)數(shù)量:`flops, params = profile(model, inputs)`
5. 打印計算結(jié)果:`print("FLOPs: ", flops, " Params: ", params)`
需要注意的是,計算FLOPs和參數(shù)數(shù)量需要使用PyTorch框架中的模型,如果您使用的是其他框架,可能需要進行一些適配操作。此外,thop庫在計算FLOPs和參數(shù)數(shù)量時只考慮了模型中的操作數(shù)量,對于不同的設(shè)備和優(yōu)化器對計算速度的影響并沒有考慮。因此,計算結(jié)果僅供參考,實際性能以實際測試為準(zhǔn)。`
**Human:** 請問FLOPs和Params計算出的單位是什么?
**AI:** `FLOPs是一種表示計算量的單位,全稱為“floating point operations per second”,即每秒鐘浮點運算次數(shù)。在深度學(xué)習(xí)中,F(xiàn)LOPs常常被用作衡量模型計算復(fù)雜度的指標(biāo)。在thop庫中,計算出的FLOPs單位為GFLOPs,即10億次浮點運算。
而Params是模型中可訓(xùn)練參數(shù)的數(shù)量,通常以“萬”、“百萬”、“千萬”為單位進行表示。在thop庫中,計算出的Params數(shù)量的單位為“個”。`
**Human:** 對于不同大小的輸入,thop得到的FLOPs和Params會變化嗎?是否存在某種線性關(guān)系?
**AI:** `是的,對于不同大小的輸入,thop得到的FLOPs和Params數(shù)量通常會發(fā)生變化。這是因為模型需要針對不同大小的輸入進行不同的計算和存儲。例如,卷積層需要為輸入圖像和卷積核的不同大小分配不同的內(nèi)存空間,這樣計算過程中才能保證正確性和有效性。
對于FLOPs和輸入大小之間的關(guān)系,通常存在一種線性關(guān)系。當(dāng)輸入大小增加時,模型需要進行更多的計算和存儲,因此FLOPs數(shù)量也會相應(yīng)地增加。但這種關(guān)系可能受到模型的具體操作和結(jié)構(gòu)的影響,在一定程度上可能存在非線性影響。
對于Params和輸入大小之間的關(guān)系,通常不會發(fā)生明顯的變化。模型的參數(shù)數(shù)量通常由模型結(jié)構(gòu)和超參數(shù)等因素決定,輸入大小的變化對Params數(shù)量的影響較小。`
**Human:** torchstats和這個有什么區(qū)別?
**AI:** `torchstats和thop都是用于分析PyTorch模型的工具,但是它們的功能和使用方法略有不同。
torchstats主要用于:(1)統(tǒng)計模型各個層的輸出尺寸、參數(shù)數(shù)量和占用內(nèi)存量;(2)對模型進行梯度和權(quán)重的可視化;(3)尋找由于輸入的維度而導(dǎo)致的內(nèi)存錯誤。因此,torchstats主要關(guān)注模型的內(nèi)存使用和參數(shù)的信息。
而thop主要用于:(1)計算深度神經(jīng)網(wǎng)絡(luò)的FLOPs和參數(shù)數(shù)量;(2)幫助優(yōu)化模型,降低模型的計算負擔(dān)和復(fù)雜度。因此,thop主要關(guān)注模型的計算復(fù)雜性和計算量。
綜上所述,torchstats和thop都是對PyTorch模型進行分析的工具,但它們的關(guān)注點略有不同。如果您想關(guān)注模型的內(nèi)存使用情況、權(quán)重和梯度的可視化以及尋找內(nèi)存錯誤,可以選擇torchstats工具;如果您希望了解模型的運算要求、計算量和對于不同輸入的計算復(fù)雜度,可以選擇thop工具。`
**Human:** 你能寫一個示范程序,使用thop比較多個不同的模型性能嗎?
**AI:** `當(dāng)然可以,下面是一個使用thop比較不同模型計算復(fù)雜度的示范代碼:
```python
import torch
from thop import profile
import torchvision.models as models
# 定義模型列表
model_list = [
? ? models.resnet18(),
? ? models.resnet34(),
? ? models.resnet50(),
? ? models.vgg16(),
? ? models.alexnet(),
? ? models.densenet121(),
? ? models.densenet161(),
? ? models.mobilenet_v2()
]
# 隨機生成輸入數(shù)據(jù),大小為(1, 3, 224, 224)
inputs = torch.randn(1, 3, 224, 224)
# 使用thop計算模型的FLOPs和參數(shù)數(shù)量,并打印結(jié)果
for model in model_list:
? ? flops, params = profile(model, inputs)
? ? print("Model: ", model.__class__.__name__)
? ? print("FLOPs: ", flops / 1e9, " GFLOPs")
? ? print("Params: ", params / 1e6, " Million\n")
```
這個示范程序使用了PyTorch中的一些常用模型,比如ResNet、VGG、AlexNet和MobileNet。程序隨機生成了一個大小為(1, 3, 224, 224)的輸入數(shù)據(jù),然后遍歷模型列表,分別使用thop計算每個模型的FLOPs和參數(shù)數(shù)量,并打印計算結(jié)果。在實際應(yīng)用中,可以根據(jù)自己的需要修改參考代碼中的模型列表和輸入數(shù)據(jù)大小,以及更改打印結(jié)果的格式。`
**Human:** 我可以使用thop計算模型中某些層的運算量嗎?
**AI:** `是的,thop庫還支持計算模型中某些指定層的FLOPs和參數(shù)數(shù)量。這對于模型調(diào)試和算法優(yōu)化非常有用。
假設(shè)您想要計算模型中第1到第3層的FLOPs和參數(shù)數(shù)量,可以使用如下代碼:
```python
import torch
from thop import profile, clever_format
import torchvision.models as models
# 定義模型
model = models.resnet18()
# 定義輸入數(shù)據(jù)
inputs = torch.randn(1, 3, 224, 224)
# 使用thop計算第1到第3層的FLOPs和參數(shù)數(shù)量
flops, params = profile(model, inputs,
? ? ? ? ? ? ? ? ? ? ? ? custom_ops={
? ? ? ? ? ? ? ? ? ? ? ? ? ? torch.nn.Conv2d:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? lambda x:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (x.input_shape[0]*x.kernel_size[0]*x.kernel_size[1]*x.input_channels//x.groups,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?x.input_shape[0]*x.output_channels//x.groups*(x.output_shape[2]//x.stride[0])*(x.output_shape[3]//x.stride[1]),
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?x.kernel_size[0]*x.kernel_size[1]*x.input_channels//x.groups*x.output_channels//x.groups),
? ? ? ? ? ? ? ? ? ? ? ? ? ? torch.nn.BatchNorm2d:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? lambda x: (x.input_shape[0]*x.num_features,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?2*x.num_features),
? ? ? ? ? ? ? ? ? ? ? ? ? ? torch.nn.Linear:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? lambda x: (x.input_shape[0]*x.in_features,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?x.input_shape[0]*x.out_features)
? ? ? ? ? ? ? ? ? ? ? ? },
? ? ? ? ? ? ? ? ? ? ? ? # 計算第1到第3層的FLOPs和參數(shù)數(shù)量
? ? ? ? ? ? ? ? ? ? ? ? # 輸入idxs列表
? ? ? ? ? ? ? ? ? ? ? ? # 輸出數(shù)量是給出的。
? ? ? ? ? ? ? ? ? ? ? ? idxs=list(range(3)))
# 將結(jié)果轉(zhuǎn)換為可讀性更好的格式
flops, params = clever_format([flops, params], "%.2f")
# 打印結(jié)果
print("FLOPs: ", flops)
print("Params: ", params)
```
需要注意的是,我們需要使用`custom_ops`參數(shù)自定義特定層的計算方法。在這個示范程序中,我們?yōu)閌Conv2d`、`BatchNorm2d`和`Linear`層分別定義了計算FLOPs和參數(shù)數(shù)量的Lambda函數(shù)。
當(dāng)我們使用`profile`函數(shù)時,還需要傳入`idxs`參數(shù)來指定我們想要計算的層數(shù)。在這個示范程序中,我們使用`list(range(3))`指定要計算前三層的FLOPs和參數(shù)數(shù)量。
最后,我們使用`clever_format`函數(shù)將結(jié)果轉(zhuǎn)換為更易讀的格式,并打印計算結(jié)果。`
**Human:** custom_ops參數(shù)的作用是什么?
**AI:** ``custom_ops`參數(shù)是thop庫中profile函數(shù)的一個參數(shù),用于為特定類型的操作自定義計算FLOPs和參數(shù)數(shù)量的函數(shù)。這個參數(shù)主要用于支持那些不在thop庫默認覆蓋范圍內(nèi)的操作,這些操作可能是您自己特定的操作、定制的操作或者包含了輕量級操作的自定義模塊。
舉個例子,假設(shè)在您的模型中,您定義了一個自定義模塊`MyConv2d`來實現(xiàn)卷積操作。如果您直接使用thops庫計算模型的FLOPs和參數(shù)數(shù)量,那么該自定義模塊不會被默認覆蓋,也就無法進行計算。這個時候,您可以使用`custom_ops`參數(shù)來為這個自定義模塊定義一個自定義的計算函數(shù),讓thop庫計算該模塊的FLOPs和參數(shù)數(shù)量。
具體而言,您可以使用`custom_ops`參數(shù)來自定義任何類型的操作,只需要傳入任何類型的Python對象作為key(通常是torch.nn下的模塊、函數(shù)或其它可調(diào)用對象),以及一個能夠返回FLOPs和參數(shù)數(shù)量的函數(shù)作為value。在這個函數(shù)中,您需要根據(jù)傳入的模塊、參數(shù)和輸入形狀等信息計算相應(yīng)的FLOPs和參數(shù)數(shù)量,然后將結(jié)果返回。
需要注意的是,如果您沒有自定義任何操作,那么可以省略`custom_ops`參數(shù)。如果您的模型只包含thop庫默認支持的操作,那么thop會自動推斷每個操作的FLOPs和參數(shù)數(shù)量。如果您的模型中包含自定義操作,那么使用thop庫之前,需要自定義這些操作的計算方式。`
**Human:** thop的實現(xiàn)是遍歷模型的module并使用hook計算所有module嗎?為什么無法計算自定義模塊?
**AI:** `是的,thop的實現(xiàn)是通過Hook機制對模型中的Module進行遍歷,并在遍歷過程中計算每個Module的FLOPs和參數(shù)數(shù)量。
當(dāng)我們使用thop計算一個模型的FLOPs和參數(shù)數(shù)量時,thop會遍歷模型中所有的Module,對每個Module都注冊一個forward_hook,在Module前向計算結(jié)束后,會將該Module計算得到的FLOPs和參數(shù)數(shù)量累加到整個模型的總FLOPs和參數(shù)數(shù)量中。
關(guān)于為什么無法計算自定義模塊,可能原因是自定義模塊的類名不在thop支持的計算操作范圍內(nèi),或者沒有為自定義模塊寫專門的計算FLOPs和參數(shù)數(shù)量的函數(shù)。
thop支持的計算操作范圍包括常見的torch.nn下的常用操作,包括Conv2d、ConvTranspose2d、Linear、MaxPool2d等,同時還支持一些torchvision.models下的預(yù)訓(xùn)練模型,例如alexnet、vgg、resnet等。
如果您的自定義模塊的類名與這些操作不一致,那么thop就無法自動計算其FLOPs和參數(shù)數(shù)量。要解決這個問題,您可以使用`custom_ops`參數(shù)來為自定義模塊寫一個專門的計算函數(shù),并傳遞給thop庫的profile函數(shù)。具體而言,您需要使用`custom_ops`參數(shù)來傳遞一個字典,其中key為自定義模塊的類名,value為計算FLOPs和參數(shù)數(shù)量的lambda函數(shù)。在lambda函數(shù)中,您需要根據(jù)模塊的輸入輸出形狀以及模塊本身的參數(shù)信息等,手動計算FLOPs和參數(shù)數(shù)量。
需要注意的是,如果自定義模塊包含輕量級操作或者需要特殊處理的操作,那么需要在lambda函數(shù)中自行實現(xiàn)這些特殊處理,例如計算深度可分離卷積的FLOPs。`
**Human:** 如果自定義模塊的名稱不在thop支持的模塊中,但其它的子模塊所有名稱和操作都是thop支持的,那么thop是否能夠正確計算呢?
**AI:** `如果自定義模塊的名稱不在thop支持的模塊中,但是其它的子模塊都是thop支持的,那么thop能夠正確計算其它子模塊的FLOPs和參數(shù)數(shù)量,但是不能計算包含自定義模塊的子模塊的FLOPs和參數(shù)數(shù)量。
具體而言,thop在計算模型的FLOPs和參數(shù)數(shù)量時是遍歷模型中所有的Module,并使用hook機制對每個Module進行計算。如果一個Module的類名不在thop支持的范圍內(nèi),那么thop會忽略這個Module,不會對其進行計算。因此,如果自定義模塊的類名不在thop支持的范圍內(nèi),那么thop就無法對其進行計算,這也就導(dǎo)致了無法計算包含自定義模塊的子模塊的FLOPs和參數(shù)數(shù)量。
解決這個問題的方法是,使用`custom_ops`參數(shù)為自定義模塊寫一個專門的計算函數(shù),并手動計算FLOPs和參數(shù)數(shù)量。具體而言,您需要在`custom_ops`參數(shù)中傳遞一個字典,其中key為自定義模塊的類名,value為計算FLOPs和參數(shù)數(shù)量的函數(shù)。在這個函數(shù)中,您需要根據(jù)自定義模塊的輸入輸出形狀、參數(shù)、以及自定義模塊包含的所有子模塊的FLOPs和參數(shù)數(shù)量等信息,手動計算FLOPs和參數(shù)數(shù)量。這樣,thop就可以正確計算包含自定義模塊的子模塊的FLOPs和參數(shù)數(shù)量了。`
**Human:** 我指的是,此自定義模塊的子模塊全部是支持的,但很顯然,自定義模塊本身名稱是不可能在thop庫中。這種情況也能夠正確計算嗎?
**AI:** `如果自定義模塊本身名稱不在thop庫中,但是自定義模塊的子模塊全部在thop庫支持的模塊中,那么thop仍然能夠正確地計算模型的FLOPs和參數(shù)數(shù)量。
具體來說,當(dāng)thop對模型進行遍歷時,對于包含自定義模塊的子模塊,thop會遞歸地遍歷它們的子模塊,并統(tǒng)計它們的FLOPs和參數(shù)數(shù)量。這樣,自定義模塊的子模塊的FLOPs和參數(shù)數(shù)量依然能夠被正確計算,并且會被累加到整個模型的FLOPs和參數(shù)數(shù)量中。
需要注意的是,盡管自定義模塊的名稱不在thop庫中,但是自定義模塊的實現(xiàn)方式必須符合模塊的定義規(guī)范,即包含forward方法和parameters方法。否則,thop可能會無法正確計算模型的FLOPs和參數(shù)數(shù)量。
總之,只要自定義模塊的子模塊在thop庫支持的范圍內(nèi),并且實現(xiàn)符合規(guī)范,那么thop就能夠正確地計算模型的FLOPs和參數(shù)數(shù)量。`
**Human:** 一個thop無法計算的模塊可能是怎樣的?
**AI:** `一個 thop 無法計算的模塊通常是由以下幾種情況導(dǎo)致的:
1. 類型不支持:thop 目前只能計算支持的 torch.nn 下的常用操作,包括 Conv2d、ConvTranspose2d、Linear、MaxPool2d、AdaptiveAvgPool2d 等,并且支持 torchvision.models 下一些預(yù)訓(xùn)練模型,如 AlexNet、VGG、ResNet 等。如果模型中存在未被支持的操作,如自定義的操作或其他類型的操作,thop 將無法計算它們對應(yīng)的 FLOPs 和參數(shù)數(shù)量。
2. 動態(tài)形狀:如果模型中存在輸入或輸出形狀(shape)與實際運行時不一致(如使用輸入圖像中的寬高作為網(wǎng)絡(luò)輸入大小),或者通過 Resize、Upsample 等方法得到的形狀是在運行時動態(tài)生成的,thop 將無法計算這些動態(tài)形狀對應(yīng)的 FLOPs 和參數(shù)數(shù)量。
3. 控制流:如果模型中存在使用 if、while 等流程控制語句控制每個 batch 數(shù)據(jù)的不同分支執(zhí)行不同計算的情況,thop 難以知曉模型運行時的具體情況,也無法計算這種模型的 FLOPs 和參數(shù)數(shù)量。
4. 不同運算間耦合:thop 無法對不同的計算層之間的耦合進行精確建模。比如模型中存在一個乘法運算需要另外一個計算層的輸出,那么如果不了解另外那個計算層的輸出情況,就會導(dǎo)致 FLOPs 計算不準(zhǔn)確,這就是 thop 現(xiàn)有的限制。不過實際中,這類情況發(fā)生的概率較小。
針對上述情況,可以通過手動計算 FLOPs 的方式得到準(zhǔn)確的 FLOPs 和參數(shù)數(shù)量,或者通過修改模型結(jié)構(gòu)來去除這些限制。`