Date: 2020/07/25
Coder: CW
Foreword:
CW有時(shí)候逛Github會(huì)發(fā)現(xiàn)不少項(xiàng)目代碼中使用到了Meter這個(gè)類(lèi),meter這個(gè)詞的意思是儀表,從名稱(chēng)上來(lái)看,能feel到它應(yīng)該是用來(lái)度量和記錄某些統(tǒng)計(jì)量的,結(jié)合項(xiàng)目代碼的上下文也能看明白的確是這樣的意思。
但是,之前對(duì)Meter的理解也就止步于此,由于最近它在我逛Github時(shí)出現(xiàn)的頻率越來(lái)越高,因此就忍不住瞄了下相關(guān)源碼,現(xiàn)在我就把這成果記錄在本文,分享給大家以便快速了解下Meter的打開(kāi)方式。
Outline
I. Meter概述
II. 舉例:AverageValueMeter
III. 舉例:ConfusionMeter
Meter概述
Meter?這個(gè)類(lèi)是在torchnet.meter模塊中實(shí)現(xiàn)的,它其實(shí)是一個(gè)抽象類(lèi),也就是不會(huì)干活的家伙,也就裝裝逼,但能干活的比如ConfusionMeter、AverageValueMeter(后文會(huì)介紹)等都得膜拜它當(dāng)大佬(作為它的子類(lèi)),廢話(huà)不多說(shuō),先來(lái)看看doc string:

如上圖所述,它是用來(lái)“跟蹤”一些統(tǒng)計(jì)量的,也就是能夠在一段“歷程”中記錄下某個(gè)統(tǒng)計(jì)量在迭代過(guò)程中不斷變化的值,并統(tǒng)計(jì)相關(guān)的量。
作為大佬(抽象類(lèi)),它提供了以下接口供小弟(子類(lèi))們實(shí)現(xiàn)。

舉例:AverageValueMeter
Meter有很多子類(lèi),這里就AverageValueMeter來(lái)舉個(gè)例子說(shuō)明下其作用。

從名字看來(lái),AverageValueMeter返回的應(yīng)該是統(tǒng)計(jì)量的均值。哦,看了其實(shí)現(xiàn)的value()這個(gè)接口后,可以知道它還返回了標(biāo)準(zhǔn)差。由于它暴露給外界獲取值的只有value()這個(gè)接口,因此通過(guò)這個(gè)Meter并不能知道統(tǒng)計(jì)量每次迭代的最新值,僅僅能夠知道均值和標(biāo)準(zhǔn)差。
另外說(shuō)明下,self.n其實(shí)并不一定等于迭代次數(shù)。因?yàn)榭梢詫?duì)每次加入的數(shù)值設(shè)置單位量(相當(dāng)于權(quán)重),通常來(lái)說(shuō),每次迭代得到一個(gè)新的數(shù)值,單位量為1,代表多了一個(gè)數(shù),這樣的話(huà)self.n就等同于迭代次數(shù)。

重頭戲來(lái)了,看看每次迭代更新的過(guò)程中,它做了什么。
看下圖,如上所述,若加入數(shù)值時(shí)單位量不為1,那么到頭來(lái)self.n就不是迭代次數(shù)了,而是在整個(gè)迭代過(guò)程中單位量的總和。

這里對(duì)于均值和標(biāo)準(zhǔn)差需要稍微動(dòng)下腦筋進(jìn)行推導(dǎo),此處就均值的計(jì)算進(jìn)行下說(shuō)明。
self.mean = self.sum / self.n 這點(diǎn)毋庸置疑,OK開(kāi)始往下推導(dǎo)。
self.sum = sum_old + value,而sum_old=self.mean_old * (self.n - n),于是:
self.sum = self.mean_old * (self.n - n) + value,去括號(hào)重新組合下:
self.sum = self.mean_old * self.n + (value - n * self.mean_old)
從而得到 self.mean = self.mean_old + (value - n* self.mean_old) / self.n
舉例:ConfusionMeter
一個(gè)例子不過(guò)癮?再來(lái)個(gè)嘗嘗香不香!
顧名思義,ConfusionMeter是混淆矩陣形式的Meter。

self.conf就是混淆矩陣,conf是confusion的意思,初始化為0。

這個(gè)Meter暴露給外界的也就是這個(gè)混淆矩陣。

這里需要注意下,如果是K分類(lèi)(通過(guò)初始化是設(shè)置self.k)問(wèn)題,那么這里傳入的預(yù)測(cè)和目標(biāo)的各個(gè)值需要在[0, K-1]范圍內(nèi)。


target可以是二維的,對(duì)應(yīng)的是one-hot形式。

精華都在以下這張圖里,舉個(gè)例子來(lái)說(shuō)明。
假如是二分類(lèi)問(wèn)題,此時(shí)self.k=2,同時(shí)predicted和target的取值范圍都在[0, 1]內(nèi),那么x的取值就可能是0、1、2、3這4種情況。直觀(guān)上來(lái)看,處于邊界的兩種情況(0和3)代表預(yù)測(cè)效果較好,因?yàn)?的時(shí)候predicted和target都為0,而3的時(shí)候兩者都為1,也就是預(yù)測(cè)都正確了。
np.bincount會(huì)根據(jù)x的各個(gè)值劃分bin(區(qū)間),然后統(tǒng)計(jì)x中每個(gè)值出現(xiàn)的次數(shù),對(duì)應(yīng)到每個(gè)bin上(想象下條形圖那種結(jié)構(gòu))。最后再將bincount的結(jié)果reshape到kxk矩陣的形式。
