自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

一文搞懂神經(jīng)網(wǎng)絡(luò)模型量化

人工智能
模型量化是一種模型壓縮技術(shù),其核心是將浮點(diǎn)數(shù)(如FP32)表示的模型參數(shù)轉(zhuǎn)換為整數(shù)(如INT8、INT4)表示。

一、定點(diǎn)和浮點(diǎn)

定點(diǎn)和浮點(diǎn)是兩種不同的數(shù)值表示方式,它們的主要區(qū)別在于如何處理整數(shù)部分和小數(shù)部分的分隔點(diǎn)(即“小數(shù)點(diǎn)”的位置)。

1. 定點(diǎn)數(shù)

小數(shù)點(diǎn)的位置是固定的,整數(shù)部分和小數(shù)部分的位數(shù)在表示中是預(yù)先確定的。例如,一個(gè)16位定點(diǎn)數(shù)可以分配為8位整數(shù)部分 + 8位小數(shù)部分,則數(shù)值范圍為。例如,數(shù)值 00001000.10010000 表示為十進(jìn)制:。

2. 浮點(diǎn)數(shù)

小數(shù)點(diǎn)的位置是浮動(dòng)的,它通過科學(xué)計(jì)數(shù)法的形式來表達(dá)實(shí)數(shù),包含符號(hào)位、指數(shù)部分和尾數(shù)部分。以單精度浮點(diǎn)數(shù)FP32為例,

  • 符號(hào)位 (s):1位,表示正負(fù)號(hào)。
  • 指數(shù)部分 (k):8位,表示2的多少次冪(實(shí)際使用時(shí)需要加上偏移值)。
  • 尾數(shù)部分 (M):23位,表示有效數(shù)字。

基于上述表示,浮點(diǎn)數(shù)的值可以用以下公式計(jì)算:

其中:

  • :符號(hào)位,決定數(shù)值的正負(fù)。
  • :尾數(shù)部分,表示有效數(shù)字。
  • :指數(shù)部分,表示2的冪次。

例如,單精度浮點(diǎn)數(shù) 0 10000000 10010010000111111011011:

  • 符號(hào)位,表示正值。
  • 指數(shù)部分(偏移值為127)。
  • 尾數(shù)部分(隱含的1在前)。

計(jì)算結(jié)果為:

二、什么是模型量化?

模型量化是一種模型壓縮技術(shù),其核心是將浮點(diǎn)數(shù)(如FP32)表示的模型參數(shù)轉(zhuǎn)換為整數(shù)(如INT8、INT4)表示。通過減少每個(gè)權(quán)重值占用的空間(從32位減少到8位或更少),可以顯著降低模型的存儲(chǔ)需求和計(jì)算資源消耗。

三、模型量化優(yōu)點(diǎn)

1. 減小模型大小

通過量化,模型參數(shù)從32位浮點(diǎn)數(shù)(FP32)壓縮為8位整數(shù)(INT8),模型大小可以減少到原來的1/4。 從而可以:

  • 節(jié)省存儲(chǔ)空間:在端側(cè)設(shè)備(如手機(jī)、嵌入式設(shè)備)中,存儲(chǔ)空間通常有限。量化后的模型占用更少的空間,更適合部署在這些資源受限的環(huán)境中。
  • 降低內(nèi)存占用:更小的模型意味著在運(yùn)行時(shí)需要更少的內(nèi)存來加載和處理數(shù)據(jù),從而減少了對(duì)設(shè)備內(nèi)存的需求。
  • 減少設(shè)備功耗:內(nèi)存占用減少和推理速度提升,直接降低了設(shè)備的能耗。這對(duì)于電池供電的設(shè)備(如手機(jī)、無人機(jī)等)尤為重要。

2. 加快推理速度

訪問一次32位浮點(diǎn)數(shù)的時(shí)間可以用來訪問四次8位整數(shù),且整數(shù)運(yùn)算通常比浮點(diǎn)運(yùn)算更快。特別是在支持INT8加速的硬件(如CPU、DSP、NPU)上,INT8運(yùn)算的遠(yuǎn)超F(xiàn)P32運(yùn)算。

3. 兼容特定硬件

某些硬件加速器(如DSP、NPU)只支持INT8運(yùn)算。對(duì)于這些設(shè)備,量化是必不可少的步驟,以確保模型能夠高效運(yùn)行。例如,一些微處理器屬于8位架構(gòu),運(yùn)行FP32浮點(diǎn)運(yùn)算效率低下,而INT8量化可以顯著提升其性

四、業(yè)界模型量化實(shí)踐

業(yè)界一般只使用INT8量化模型,如NCNN、TNN等移動(dòng)端模型推理框架都支持模型的INT8量化和量化模型的推理功能。以下是兩種常見的量化推理方案:

1. 混合FP32/INT8 推理

在這種方案中,模型本身和輸入/輸出仍采用FP32格式,但在卷積或全連接層等支持量化的算子中插入Quantize和Dequantize層,將數(shù)據(jù)在FP32和INT8之間進(jìn)行轉(zhuǎn)換。具體流程如下:

  • Quantize層:將FP32數(shù)據(jù)轉(zhuǎn)換為INT8格式。
  • Dequantize 層:將INT8數(shù)據(jù)轉(zhuǎn)換回FP32格式,以支持其他只接受FP32輸入的算子。

這種方案的優(yōu)點(diǎn)是兼容性強(qiáng),適用于部分算子尚未完全支持INT8的場(chǎng)景。然而,頻繁的 Quantize 和 Dequantize 操作會(huì)帶來額外的開銷。

2. 純INT8推理

隨著技術(shù)的發(fā)展,越來越多的算子開始支持INT8運(yùn)算,因此可以將整個(gè)網(wǎng)絡(luò)轉(zhuǎn)換為INT8格式,避免了 Quantize 和 Dequantize 的轉(zhuǎn)換開銷。在這種方案中:

  • 所有數(shù)據(jù)流均為INT8格式。
  • 算子直接處理INT8數(shù)據(jù),無需轉(zhuǎn)換為FP32。

純INT8推理的優(yōu)勢(shì)在于更高的效率和更低的功耗,但要求所有算子都支持INT8運(yùn)算。對(duì)于不支持的算子,通常會(huì)回退到 Quantize/Dequantize 方案。

五、模型量化方案

在實(shí)踐中,將浮點(diǎn)模型轉(zhuǎn)換為量化模型的方法主要分為以下三種:

1. Data Free(無校準(zhǔn)集)

不使用校準(zhǔn)集,直接將浮點(diǎn)參數(shù)轉(zhuǎn)換為量化數(shù)。實(shí)現(xiàn)簡單,無需額外的數(shù)據(jù)或復(fù)雜的流程。對(duì)于某些特定場(chǎng)景(如高通的DFQ方法),即使不使用校準(zhǔn)集,也能達(dá)到較高的精度。但是,通常會(huì)導(dǎo)致較大的精度損失,因?yàn)闆]有考慮實(shí)際數(shù)據(jù)分布,不適合對(duì)精度要求較高的任務(wù)。

2. Calibration(基于校準(zhǔn)集)

通過輸入少量真實(shí)數(shù)據(jù)進(jìn)行統(tǒng)計(jì)分析,計(jì)算量化參數(shù)(如縮放因子S和零點(diǎn)Z)。精度損失較小,能夠更好地適應(yīng)實(shí)際數(shù)據(jù)分布,很多芯片廠商(如NVIDIA、高通、海思、地平線、寒武紀(jì)等)都提供了這種功能。

3. Fine-tune(基于訓(xùn)練微調(diào))

在訓(xùn)練過程中模擬量化誤差,并調(diào)整權(quán)重以使其更適合量化。能夠顯著提升量化后的模型精度,更加靈活,可以根據(jù)具體任務(wù)需求進(jìn)行定制化優(yōu)化。但是需要修改模型訓(xùn)練代碼,開發(fā)周期較長。

六、模型量化分類

根據(jù)映射函數(shù)是否是線性可以分為兩類——即線性量化和非線性量化,本文主要研究的是線性量化技術(shù)。

1. 線性量化

線性量化的過程可以用以下數(shù)學(xué)表達(dá)式來表示:

其中:

  • q表示原始的浮點(diǎn)數(shù)值(通常是Float32)。
  • Z表示浮點(diǎn)數(shù)值的偏移量(通常稱為 Zero Point)。
  • S表示浮點(diǎn)數(shù)值的縮放因子(通常稱為Scale)。
  • Round(?)表示四舍五入近似取整的數(shù)學(xué)函數(shù),也可以使用向上或向下取整。

根據(jù)參數(shù)Z是否為零可以將線性量化分為兩類——即對(duì)稱量化和非對(duì)稱量化。

(1) 對(duì)稱量化

對(duì)稱量化,即使用一個(gè)映射公式將輸入浮點(diǎn)數(shù)據(jù)映射到[-128,127]的范圍內(nèi),圖中-max(|Xf|)表示的是輸入數(shù)據(jù)的最小值,max(|Xf|)表示輸入數(shù)據(jù)的最大值。

對(duì)稱量化的一個(gè)核心即零點(diǎn)的處理,映射公式需要保證原始零點(diǎn)(即輸入浮點(diǎn)數(shù)中的0)在量化后依然對(duì)應(yīng)于整數(shù)區(qū)間的0??偠灾?,對(duì)稱量化通過映射關(guān)系將輸入數(shù)據(jù)映射在[-128,127]的范圍內(nèi),對(duì)于映射關(guān)系而言,我們需要求解的參數(shù)即Z和S。

在對(duì)稱量化中,r是用有符號(hào)的整型數(shù)值(int8)來表示的,此時(shí)Z=0,且q=0時(shí)恰好有r=0。S的計(jì)算公式如下:

其中,

  • n表示用來表示該數(shù)值的位寬。
  • max(|x|)表示數(shù)據(jù)集中所有樣本的絕對(duì)值的最大值。

(2) 非對(duì)稱量化

非對(duì)稱量化,即使用一個(gè)映射公式將輸入數(shù)據(jù)映射到[0,255]的范圍內(nèi),圖中min(Xf)表示的是輸入數(shù)據(jù)的最小值,max(Xf)表示輸入數(shù)據(jù)的最大值。

對(duì)稱量化通過映射關(guān)系將輸入數(shù)據(jù)映射在[0,255]的范圍內(nèi),對(duì)于映射關(guān)系而言,我們需要求解的參數(shù)即Z和S。

在非對(duì)稱量化中,r 是用有符號(hào)的整型數(shù)值(uint8)來表示的??梢匀=min(x),S的計(jì)算公式如下:

2. 逐層量化、逐組量化和逐通道量化

根據(jù)量化的粒度(即共享量化參數(shù)的范圍),可以將量化方法分為逐層量化、逐組量化和逐通道量化。

(1) 逐層量化

以一個(gè)層為單位,整個(gè)層的所有權(quán)重上使用相同的縮放因子 S 和偏移量 Z 。

(2) 逐組量化

將權(quán)重按組劃分,每個(gè)group使用一組S和Z。

(3) 逐通道量化

以通道為單位,每個(gè)channel單獨(dú)使用一組S和Z。

當(dāng) group=1 時(shí),逐組量化與逐層量化等價(jià);當(dāng)group=num_filters (即dw卷積)時(shí),逐組量化逐通道量化等價(jià)。

3. 在線量化與離線量化

根據(jù)激活值的量化方式,可以分為在線量化和離線量化兩種方法。這兩種方法的主要區(qū)別在于量化參數(shù)(縮放因子S和偏移量Z)是否在實(shí)際推理過程中動(dòng)態(tài)計(jì)算。

(1) 在線量化

指在實(shí)際推理過程中,根據(jù)實(shí)際的激活值動(dòng)態(tài)計(jì)算量化參數(shù)S和Z。

(2) 離線量化

離線量化是指提前確定好激活值的量化參數(shù)S和Z。這樣,在實(shí)際推理時(shí)就可以直接使用這些預(yù)計(jì)算好的參數(shù),而不需要?jiǎng)討B(tài)計(jì)算,從而提高了推理速度。

離線量化通常采用以下幾種方法來確定量化參數(shù):

  • 指數(shù)平滑法:將校準(zhǔn)數(shù)據(jù)集送入模型,收集每個(gè)量化層的輸出特征圖,計(jì)算每個(gè)batch的S和Z值,并通過指數(shù)平滑法來更新S和Z值。
  • 直方圖截?cái)喾ǎ涸谟?jì)算量化參數(shù)S和Z的過程中,考慮到有些特征圖可能會(huì)出現(xiàn)偏離較遠(yuǎn)的奇異值,導(dǎo)致最大值非常大??梢圆捎弥狈綀D截取的形式,比如拋棄最大的前 1% 數(shù)據(jù),以前 1% 分界點(diǎn)的數(shù)值作為最大值來計(jì)算量化參數(shù)。
  • KL 散度校準(zhǔn)法:通過計(jì)算量化前后的兩個(gè)分布之間的 KL 散度(也稱為相對(duì)熵)來評(píng)估這兩個(gè)分布之間的差異,以搜索并選取KL散度最小的量化參數(shù)Z和S作為最終的結(jié)果。

4.比特量化

根據(jù)存儲(chǔ)一個(gè)權(quán)重元素所需的位數(shù),可以將其分為8bit量化、4bit量化、2bit量化和1bit量化。

  • 二進(jìn)制神經(jīng)網(wǎng)絡(luò):即在運(yùn)行時(shí)具有二進(jìn)制權(quán)重和激活的神經(jīng)網(wǎng)絡(luò),以及在訓(xùn)練時(shí)計(jì)算參數(shù)的梯度。
  • 三元權(quán)重網(wǎng)絡(luò):即權(quán)重約束為+1,0和-1的神經(jīng)網(wǎng)絡(luò)。
  • XNOR網(wǎng)絡(luò):即過濾器和卷積層的輸入是二進(jìn)制的。XNOR網(wǎng)絡(luò)主要使用二進(jìn)制運(yùn)算來近似卷積。

七、模型量化原理詳解

1. 原理詳解

模型量化橋接定點(diǎn)和浮點(diǎn),建立一種有效的數(shù)據(jù)映射關(guān)系。要弄懂模型量化的原理就要弄懂這種數(shù)據(jù)映射關(guān)系。浮點(diǎn)與定點(diǎn)數(shù)據(jù)的轉(zhuǎn)換公式如下:

其中:

  • R表示輸入的浮點(diǎn)數(shù)據(jù)
  • Q表示量化之后的定點(diǎn)數(shù)據(jù)
  • Z表示零點(diǎn)(Zero Point)的數(shù)值
  • S表示縮放因子(Scale)的數(shù)值

根據(jù)S和Z這兩個(gè)參數(shù)來確定這個(gè)映射關(guān)系。求解 S 和 Z 有很多種方法,這里列舉中其中的一種求解方式(MinMax)如下:

其中,

  • max(R)表示輸入浮點(diǎn)數(shù)值的最大值。
  • min(R)表示輸入浮點(diǎn)數(shù)值的最小值。
  • max(Q)表示量化之后的整數(shù)數(shù)值的最大值(127/255)。
  • min(Q)表示量化之后的整數(shù)數(shù)值的最小值(-128/0)。

每通道或每張量的權(quán)重用int8進(jìn)行定點(diǎn)量化的可表示范圍為[-127,127],且zero-point就是量化值0。

每張量的激活值或輸入值用int8進(jìn)行定點(diǎn)量化的可表示范圍為[-128,127],其zero-point在[-128,127]內(nèi)依據(jù)公式求得。

2. 具體案例

在這個(gè)案例中,我們將展示如何根據(jù)給定的激活值范圍 [-2.0, 6.0] 使用 int8 類型進(jìn)行定點(diǎn)量化的過程。

步驟1: 計(jì)算量化尺度S和zero-point Z

量化尺度S的計(jì)算公式為:

Zero-point Z的計(jì)算公式為:

代入給定的值:

  • 激活值范圍 [-2.0, 6.0],因此 max_val = 6.0 和 min_val = -2.0
  • 定點(diǎn)量化值范圍 [-128, 127],因此 quant_max = 127 和 quant_min = -128

計(jì)算得到:

步驟 2: 對(duì)激活值進(jìn)行量化

使用計(jì)算出的 S 和 Z 值對(duì)一個(gè)具體的激活值進(jìn)行量化。假設(shè)有一個(gè)真實(shí)的激活值R = 0.28,則量化后的值 Q為:

代入S和Z的值:

八、模型量化實(shí)現(xiàn)步驟

模型量化具體的執(zhí)行步驟如下所示:

  • 在量化前,需要先統(tǒng)計(jì)出輸入數(shù)據(jù)(通常是權(quán)重或者激活值)中的最小值 min_value 和最大值 max_value。
  • 根據(jù)模型的需求選擇合適的量化類型,常見的有對(duì)稱量化(int8)和非對(duì)稱量化(uint8)。
  • 根據(jù)選擇的量化類型,計(jì)算量化參數(shù) Z(Zero point)和 S(Scale)。
  • 根據(jù)計(jì)算出的量化參數(shù) Z 和 S,對(duì)模型執(zhí)行量化操作,即將 FP32 數(shù)據(jù)轉(zhuǎn)換為 INT8 數(shù)據(jù)。
  • 驗(yàn)證量化后的模型性能是否滿足要求。如果不滿足,可以嘗試使用不同的方式計(jì)算 S 和 Z,然后重新執(zhí)行量化操作。

九、Pytorch模型量化詳解

PyTorch提供了三種量化模型的方法,具體包括訓(xùn)練后動(dòng)態(tài)量化、訓(xùn)練后靜態(tài)量化和訓(xùn)練時(shí)量化。

1. 訓(xùn)練后動(dòng)態(tài)量化

訓(xùn)練后動(dòng)態(tài)量化(Post Training Dynamic Quantization,PTDQ)是最簡單的量化形式,其中權(quán)重被提前量化,而激活在推理過程中被動(dòng)態(tài)量化。這種方法用于模型執(zhí)行時(shí)間由從內(nèi)存加載權(quán)重而不是計(jì)算矩陣乘法所支配的情況,適合批量較小的LSTM和Transformer模型。步驟如下:

  • 準(zhǔn)備模型:將模型設(shè)置為評(píng)估模式 (model.eval()),對(duì)于需要?jiǎng)討B(tài)量化的模型,通常不需要添加額外的量化或反量化模塊。
  • 量化模型:使用 torch.quantization.quantize_dynamic() 函數(shù)來量化模型,這個(gè)函數(shù)會(huì)自動(dòng)識(shí)別模型中適合動(dòng)態(tài)量化的層,并將其轉(zhuǎn)換為量化版本。

2. 訓(xùn)練后靜態(tài)量化

訓(xùn)練后靜態(tài)量化(Post-Training Static Quantization, PTQ)是最常用的量化形式,其中權(quán)重是提前量化的,并且基于在校準(zhǔn)過程中觀察模型的行為來預(yù)先計(jì)算激活張量的比例因子和偏差。CNN是一個(gè)典型的用例,訓(xùn)練后量化通常是在內(nèi)存帶寬和計(jì)算節(jié)省都很重要的情況下進(jìn)行的。訓(xùn)練后量化的步驟如下:

  • 準(zhǔn)備模型:添加 QuantStub 和 DeQuantStub 模塊,以指定在何處顯式量化和反量化激活值。確保不重復(fù)使用模塊。將需要重新量化的任何操作轉(zhuǎn)換為模塊的模式。
  • 融合操作:將諸如 conv + relu 或 conv + batchnorm + relu 之類的組合操作融合在一起,以提高模型的準(zhǔn)確性和性能。
  • 指定量化配置:例如選擇對(duì)稱或非對(duì)稱量化以及MinMax或L2Norm校準(zhǔn)技術(shù)。
  • 使用 torch.quantization.prepare() 函數(shù)來插入觀察模塊,以便在校準(zhǔn)期間觀察激活張量。
  • 使用校準(zhǔn)數(shù)據(jù)集對(duì)模型執(zhí)行校準(zhǔn)操作。
  • 使用 torch.quantization.convert() 函數(shù)來轉(zhuǎn)換模型。包括計(jì)算并存儲(chǔ)每個(gè)激活張量要使用的比例和偏差值,并替換關(guān)鍵算子的量化實(shí)現(xiàn)。

3. 訓(xùn)練時(shí)量化

在某些情況下,訓(xùn)練后量化不能提供足夠的準(zhǔn)確性,這時(shí)可以使用訓(xùn)練時(shí)量化(Quantization-Aware Training,QAT)。步驟:

  • 準(zhǔn)備模型:添加 QuantStub 和 DeQuantStub 模塊,以指定在何處顯式量化和反量化激活值。確保不重復(fù)使用模塊。將需要重新量化的任何操作轉(zhuǎn)換為模塊的模式。
  • 將諸如 conv + relu 或 conv + batchnorm + relu 之類的組合操作融合在一起,以提高模型的準(zhǔn)確性和性能。
  • 指定偽量化配置:例如選擇對(duì)稱或非對(duì)稱量化以及MinMax或L2Norm校準(zhǔn)技術(shù).
  • 用 torch.quantization.prepare_qat() 函數(shù)來插入偽量化模塊,以便在訓(xùn)練過程中模擬量化。
  • 使用標(biāo)準(zhǔn)訓(xùn)練流程訓(xùn)練或微調(diào)模型。
  • 使用 torch.quantization.convert() 函數(shù)來轉(zhuǎn)換模型,包括計(jì)算并存儲(chǔ)每個(gè)激活張量要使用的比例和偏差值,并替換關(guān)鍵算子的量化實(shí)現(xiàn)。

下面是一個(gè)簡單的示例,展示了如何使用PyTorch進(jìn)行模型量化。

# 導(dǎo)入第三方的庫函數(shù)
import os
from io import open
import time

import torch
import torch.nn as nn
import torch.quantization
import torch.nn.functional as F

# 創(chuàng)建LSTM模型類
class LSTMModel(nn.Module):
    """整個(gè)網(wǎng)絡(luò)包含一個(gè)encoder, 一個(gè)recurrent模塊和一個(gè)decoder."""

    def __init__(self, ntoken, ninp, nhid, nlayers, dropout=0.5):
        super(LSTMModel, self).__init__()
        # 預(yù)定義一些網(wǎng)絡(luò)層
        self.drop = nn.Dropout(dropout)
        # 嵌入層
        self.encoder = nn.Embedding(ntoken, ninp)
        # LSTM層
        self.rnn = nn.LSTM(ninp, nhid, nlayers, dropout=dropout)
        # 線性層
        self.decoder = nn.Linear(nhid, ntoken)
        self.init_weights()
        self.nhid = nhid
        self.nlayers = nlayers

    def init_weights(self):
     '''
     初始化模型權(quán)重
     '''
        initrange = 0.1
        self.encoder.weight.data.uniform_(-initrange, initrange)
        self.decoder.bias.data.zero_()
        self.decoder.weight.data.uniform_(-initrange, initrange)

    def forward(self, input, hidden):
     '''
     搭建網(wǎng)絡(luò)并執(zhí)行前向推理
     '''
        emb = self.drop(self.encoder(input))
        output, hidden = self.rnn(emb, hidden)
        output = self.drop(output)
        decoded = self.decoder(output)
        return decoded, hidden

    def init_hidden(self, bsz):
     '''
     初始化hidden層的權(quán)重
     '''
        weight = next(self.parameters())
        return (weight.new_zeros(self.nlayers, bsz, self.nhid),
                weight.new_zeros(self.nlayers, bsz, self.nhid))

# 創(chuàng)建一個(gè)詞典類,用來處理數(shù)據(jù)
# 構(gòu)建詞匯表,包括詞到索引的映射和索引到詞的映射
class Dictionary(object):
    def __init__(self):
        self.word2idx = {}
        self.idx2word = []

    def add_word(self, word):
     '''
     在詞典中添加新的word
     '''
        if word not in self.word2idx:
            self.idx2word.append(word)
            self.word2idx[word] = len(self.idx2word) - 1
        return self.word2idx[word]

    def __len__(self):
     '''
     返回詞典的長度
     '''
        return len(self.idx2word)

#  Corpus 類:處理文本數(shù)據(jù),包括讀取文件、構(gòu)建詞匯表和將文本轉(zhuǎn)換為索引序列
class Corpus(object):
    def __init__(self, path):
        self.dictionary = Dictionary()
        # 分別獲取訓(xùn)練集、驗(yàn)證集和測(cè)試集
        self.train = self.tokenize(os.path.join(path, 'train.txt'))
        self.valid = self.tokenize(os.path.join(path, 'valid.txt'))
        self.test = self.tokenize(os.path.join(path, 'test.txt'))

    def tokenize(self, path):
        """對(duì)輸入的文件執(zhí)行分詞操作"""
        assert os.path.exists(path)
        # 將新的單詞添加到詞典中
        with open(path, 'r', encoding="utf8") as f:
            for line in f:
                words = line.split() + ['<eos>']
                for word in words:
                    self.dictionary.add_word(word)

        # 標(biāo)記文件的內(nèi)容
        with open(path, 'r', encoding="utf8") as f:
            idss = []
            for line in f:
                words = line.split() + ['<eos>']
                ids = []
                for word in words:
                    ids.append(self.dictionary.word2idx[word])
                idss.append(torch.tensor(ids).type(torch.int64))
            ids = torch.cat(idss)
        return ids

# 設(shè)置模型的路徑
model_data_filepath = 'data/'
corpus = Corpus(model_data_filepath + 'wikitext-2')
ntokens = len(corpus.dictionary)

# 搭建網(wǎng)絡(luò)模型
model = LSTMModel(
    ntoken = ntokens,
    ninp = 512,
    nhid = 256,
    nlayers = 5,
)

# 加載預(yù)訓(xùn)練的模型權(quán)重
model.load_state_dict(
    torch.load(
        model_data_filepath + 'word_language_model_quantize.pth',
        map_location=torch.device('cpu')
        )
    )
# 將模型切換為推理模式,并打印整個(gè)模型
model.eval()
print(model)

# 獲取一個(gè)隨機(jī)的輸入數(shù)值
input_ = torch.randint(ntokens, (1, 1), dtype=torch.long)
hidden = model.init_hidden(1)
temperature = 1.0
num_words = 1000

# 遍歷數(shù)據(jù)集進(jìn)行前向推理并將結(jié)果保存起來
with open(model_data_filepath + 'out.txt', 'w') as outf:
    with torch.no_grad():  # no tracking history
        for i in range(num_words):
            output, hidden = model(input_, hidden)
            word_weights = output.squeeze().div(temperature).exp().cpu()
            word_idx = torch.multinomial(word_weights, 1)[0]
            input_.fill_(word_idx)
            word = corpus.dictionary.idx2word[word_idx]
            outf.write(str(word.encode('utf-8')) + ('\n' if i % 20 == 19 else ' '))
            if i % 100 == 0:
                print('| Generated {}/{} words'.format(i, 1000))

with open(model_data_filepath + 'out.txt', 'r') as outf:
    all_output = outf.read()
    print(all_output)

bptt = 25
criterion = nn.CrossEntropyLoss()
eval_batch_size = 1

# 創(chuàng)建測(cè)試數(shù)據(jù)集
def batchify(data, bsz):
    # 對(duì)測(cè)試數(shù)據(jù)集進(jìn)行分塊
    nbatch = data.size(0) // bsz
    # 去掉多余的元素
    data = data.narrow(0, 0, nbatch * bsz)
    # 在bsz批處理中平均劃分?jǐn)?shù)據(jù)
    return data.view(bsz, -1).t().contiguous()

test_data = batchify(corpus.test, eval_batch_size)

# 獲取bath塊的輸入數(shù)據(jù)
def get_batch(source, i):
    seq_len = min(bptt, len(source) - 1 - i)
    data = source[i:i+seq_len]
    target = source[i+1:i+1+seq_len].view(-1)
    return data, target

def repackage_hidden(h):
  """
  用新的張量把隱藏的狀態(tài)包裝起來,把它們從歷史中分離出來
  """
  if isinstance(h, torch.Tensor):
      return h.detach()
  else:
      return tuple(repackage_hidden(v) for v in h)
# 評(píng)估函數(shù)
def evaluate(model_, data_source):
    # 打開評(píng)估模式
    model_.eval()
    total_loss = 0.
    hidden = model_.init_hidden(eval_batch_size)
    with torch.no_grad():
        for i in range(0, data_source.size(0) - 1, bptt):
         # 獲取測(cè)試數(shù)據(jù)
            data, targets = get_batch(data_source, i)
            # 執(zhí)行前向推理
            output, hidden = model_(data, hidden)
            hidden = repackage_hidden(hidden)
            output_flat = output.view(-1, ntokens)
            # 獲取訓(xùn)練loss
            total_loss += len(data) * criterion(output_flat, targets).item()
    return total_loss / (len(data_source) - 1)

# 初始化動(dòng)態(tài)量化模塊
quantized_model = torch.quantization.quantize_dynamic(
    model, {nn.LSTM, nn.Linear}, dtype=torch.qint8
)
print(quantized_model)

def print_size_of_model(model):
    torch.save(model.state_dict(), "temp.p")
    print('Size (MB):', os.path.getsize("temp.p")/1e6)
    os.remove('temp.p')

print_size_of_model(model)
print_size_of_model(quantized_model)

torch.set_num_threads(1)
# 評(píng)估模型的運(yùn)行時(shí)間
def time_model_evaluation(model, test_data):
    s = time.time()
    loss = evaluate(model, test_data)
    elapsed = time.time() - s
    print('''loss: {0:.3f}\nelapsed time (seconds): {1:.1f}'''.format(loss, elapsed))

time_model_evaluation(model, test_data)
time_model_evaluation(quantized_model, test_data)


責(zé)任編輯:趙寧寧 來源: 小喵學(xué)AI
相關(guān)推薦

2019-11-19 08:00:00

神經(jīng)網(wǎng)絡(luò)AI人工智能

2023-09-17 23:09:24

Transforme深度學(xué)習(xí)

2017-11-29 13:55:55

神經(jīng)網(wǎng)絡(luò)循環(huán)神經(jīng)網(wǎng)絡(luò)RNN

2018-07-29 06:46:07

神經(jīng)網(wǎng)絡(luò)RNN循環(huán)神經(jīng)網(wǎng)絡(luò)

2020-12-08 20:20:15

神經(jīng)網(wǎng)絡(luò)深度學(xué)習(xí)機(jī)器學(xué)習(xí)

2017-04-17 13:10:09

神經(jīng)網(wǎng)絡(luò)人工智能網(wǎng)絡(luò)

2020-08-14 10:20:49

神經(jīng)網(wǎng)絡(luò)人工智能池化層

2022-03-24 08:51:48

Redis互聯(lián)網(wǎng)NoSQL

2019-11-06 17:00:51

深度學(xué)習(xí)神經(jīng)網(wǎng)絡(luò)人工智能

2022-05-05 16:47:24

Docker網(wǎng)絡(luò)空間容器

2019-03-26 19:00:02

神經(jīng)網(wǎng)絡(luò)AI人工智能

2024-04-12 12:19:08

語言模型AI

2017-07-06 17:03:45

BP算法Python神經(jīng)網(wǎng)絡(luò)

2024-11-05 14:00:56

2017-04-26 14:32:24

神經(jīng)網(wǎng)絡(luò)人工智能對(duì)杭樣本

2023-09-08 08:20:46

ThreadLoca多線程工具

2021-03-22 10:05:59

netstat命令Linux

2023-09-15 12:00:01

API應(yīng)用程序接口

2024-09-04 16:19:06

語言模型統(tǒng)計(jì)語言模型

2023-05-22 13:27:17

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)