在鵬城實(shí)驗(yàn)室實(shí)習(xí)的時(shí)候,主要的工作是開發(fā)AI算子標(biāo)準(zhǔn)參考實(shí)現(xiàn)。參考實(shí)現(xiàn)是對(duì)算子標(biāo)準(zhǔn)的補(bǔ)充,旨在提供代碼級(jí)別的語義的規(guī)范,因此正確性是它的最重要屬性。
開發(fā)一個(gè)新的算子接口是比較繁瑣的,雖然標(biāo)準(zhǔn)文檔中對(duì)算子接口已有比較明確的定義,但是為了給予標(biāo)準(zhǔn)實(shí)現(xiàn)者最大的優(yōu)化空間,它沒有規(guī)定實(shí)現(xiàn)的細(xì)節(jié),這也給參考實(shí)現(xiàn)的開發(fā)增加了一點(diǎn)難度,因?yàn)槲以陂_發(fā)新算子的時(shí)候常常要對(duì)這個(gè)算子重新調(diào)研,找到它的具體實(shí)現(xiàn)邏輯,再開發(fā)對(duì)應(yīng)的接口。為了滿足正確性的要求,在開發(fā)完一個(gè)新算子后,需要對(duì)它進(jìn)行單元測(cè)試。這時(shí)候應(yīng)盡可能給出不同情況的樣例,然后將參考實(shí)現(xiàn)的結(jié)果與tensorflow、pytorch等框架的結(jié)果進(jìn)行對(duì)比。
開發(fā)了一些算子接口以后,我發(fā)現(xiàn)不同算子之間會(huì)存在大量重復(fù)代碼,經(jīng)常有復(fù)雜算子包含了簡(jiǎn)單算子代碼的情況出現(xiàn),比如maxpool會(huì)重復(fù)max的代碼。為了減少代碼開發(fā)的工作量、降低代碼維護(hù)難度,我先開發(fā)簡(jiǎn)單算子,然后讓復(fù)雜算子中重復(fù)了簡(jiǎn)單算子的代碼的部分替換成直接調(diào)用簡(jiǎn)單算子的方式。這種開發(fā)方式可能對(duì)性能要求高的算子庫不適用,但是參考實(shí)現(xiàn)追求的是正確性,不考慮性能,因此參考實(shí)現(xiàn)的所有算子都可以采取這種方法進(jìn)行開發(fā)。后來,參考實(shí)現(xiàn)的維護(hù)難度也降低了不少。
除了參考實(shí)現(xiàn),我們還開發(fā)了一套自動(dòng)化測(cè)試框架。對(duì)于不同的算子庫來說,只要遵循了算子標(biāo)準(zhǔn),那么它們對(duì)應(yīng)的算子接口應(yīng)該是差不多的:返回值是狀態(tài)碼,輸入輸出都在參數(shù)列表中,參數(shù)之間的前后順序也一致。對(duì)算子進(jìn)行正確性測(cè)試的邏輯也是一致的,即生成輸入樣例、算子運(yùn)算、對(duì)比結(jié)果。對(duì)于計(jì)算機(jī)來說,不同的地方在于數(shù)據(jù)結(jié)構(gòu)(張量等)和函數(shù)名。那么,我們只要把測(cè)試樣例和測(cè)試流程代碼提前寫好,讓用戶把自行開發(fā)的算子的函數(shù)名和創(chuàng)建張量等數(shù)據(jù)結(jié)構(gòu)的接口注冊(cè)到自動(dòng)化測(cè)試框架中,框架就可以自動(dòng)地對(duì)算子進(jìn)行正確性測(cè)試了。所以,自動(dòng)化測(cè)試框架的關(guān)鍵技術(shù)就是接口注冊(cè)機(jī)制。我們調(diào)研以后發(fā)現(xiàn),Google Test的“類型參數(shù)化”機(jī)制可以讓用戶在觸發(fā)測(cè)試的時(shí)候才指定測(cè)試代碼中某些變量的數(shù)據(jù)類型。我們就把“類型參數(shù)化”作為接口注冊(cè)機(jī)制的原型,通過宏把用戶的接口封裝到一個(gè)類中,用戶的接口就“假扮”成了一種數(shù)據(jù)類型,然后我們?cè)跍y(cè)試代碼中從對(duì)應(yīng)的變量里提取出用戶的接口,就可以實(shí)現(xiàn)接口注冊(cè)了。
完成以上工作以后,我發(fā)現(xiàn)最大的工作量不是寫代碼,而是寫代碼之前的調(diào)研和設(shè)計(jì)。我也曾試過草草調(diào)研之后就著手寫代碼,短期內(nèi)似乎是可行的,但是在后期只要遇到一個(gè)bug,我就得花大量時(shí)間去調(diào)試、調(diào)研,得不償失。運(yùn)籌帷幄之中,決勝千里之外。
作者:黎子毅