夸克APP端智能:文檔關鍵點檢測實踐與應用

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/c7/c7c73a83994db10394f5998ded9b8b81.gif","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"作者:順達","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最近夸克端智能小組在做端上的實時文檔檢測,即輸入一張RGB圖像,得到文檔的四個角的關鍵點的座標。整個pipelines屬於關鍵點檢測算法,因此最近對相關領域的論文進行閱讀和進行了實驗嘗試。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"將關鍵點檢測算法按照不同模塊進行拆分,可以分成以下幾個部分,每個部分都有相關的方法可以進行優化:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"圖片處理:包括數據光學增強,變換,resize,crop等操作,擴充圖片的多樣性;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"編碼:指的是在訓練中,如何將座標轉換成所需要的label,用於監督模型的輸出;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"網絡模型:指的是網絡結構,可以有backbone/FPN/detection head等部分組成;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"解碼:指的是如何將模型推理的結果轉換成所需要的座標形式,如笛卡爾座標系下的座標。","attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/cb/cb0766449eb4a2edda588c0dd7d950a7.webp","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"Related Works","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"關鍵點檢測中主要有兩條技術方案:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"類似人臉檢測,模型輸出的結果tensor通過fc層,直接得到一維的向量,通常是歸一化後關鍵點座標值;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"類似人體姿態估計,模型輸出的結果tensor通過argmax等方式,獲取heatmap中相應大的座標,最後將此座標恢復至原圖座標。","attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"近年來,基於heatmap來進行關鍵點檢測的方案居多,其主要原因是基於heatmap的效果要好於使用全連接層進行迴歸的方案。所以,我們採用的方案也是基於heatmap的,下面是近幾年的一些相關論文工作。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"DSNT","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[1] Nibali A , He Z , Morgan S , et al. Numerical Coordinate Regression with Convolutional Neural Networks[J]. 2018.","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"思路","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"目前,在模型輸出的heatmap到數值座標的轉換中,有兩種方式:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"通過對heatmap中取argmax,得到相應最大的點,以此來轉換成數值座標。此種方式具有較好的空間泛化性,但是由於在訓練中argmax是不可導的,通常使用heatmap來逼近編碼的高斯熱例圖,這會導致損失函數與最終評價指標的不一致。其次,在推理階段,只使用到最大響應的座標點來計算數值座標,而在訓練階段,所有座標點都對損失有貢獻。第三,通過heatmap轉換成數值座標,是會存在理論誤差下限的;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"通過在heatmap後接fc層,轉換成數值座標。此種方法讓梯度從數值座標回傳到input中,但是結果嚴重依賴與數據分佈(例如在訓練集中,一個物體一直出現在座標;而在測試集中,這個物體出現在右邊,這樣就會導致預測錯誤)。其次,通過fc轉換,丟失了heatmap的空間信息。","attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"針對上述的兩種方案,作者兼容了這兩種方案的優點(端到端優化和保持空間泛化性),提出一種可微分的方式來得到數值座標。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/fa/fa46a80ee0951f2524fc59190995e5f3.webp","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"具體步驟","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/08/08d7fbb65285a55386d73ef284f327ef.webp","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"模型的輸出1_K_H*W個heatmaps,其中K表示關鍵點的數量;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"將每個通道的heatmap歸一化,讓其值都爲非負且和爲1,從而得到 norm_heatmap 。這麼做的目的是,使用歸一化後的heatmap保證了預測的座標位於heatmap的空間範圍之內。同時, norm_heatmap 也可以理解成二維離散概率密度函數;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"生成 X 和 Y 矩陣,","attrs":{}},{"type":"katexinline","attrs":{"mathString":"X_{(i,j)} = \\frac{2j-(w+1)}{w}"}},{"type":"text","text":",","attrs":{}},{"type":"katexinline","attrs":{"mathString":"Y_{(i,j)} = \\frac{2i-(h+1)}{h}"}},{"type":"text","text":",分別表示x軸的索引和y軸的索引。可以理解成將圖片的左上角縮放到 (-1,-1) 和右下角縮放到 (1,1) ;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"將X 和 Y 矩陣分別與 norm_heatmap 點乘,從而得到最終的數值座標。這麼做的原因是, norm_heatmap 表示概率密度函數, X 矩陣表示索引,兩者點成表示預測x的均值。通過均值來表示最終的預測的座標,這樣的好處是,a)可微分;b)理論誤差下限小。","attrs":{}}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/3e/3e19c2b247c889b3f53afcae213ed456.webp","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"損失函數loss","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"dsnt模塊的損失函數由Euclidean loss 和JS正則約束組成。前者用於迴歸座標,後者用於約束生成的熱力圖更加接近高斯分佈。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"katexblock","attrs":{"mathString":"L_{euc}(u,p) = ||p-u||_2 "}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"katexblock","attrs":{"mathString":"L_D(Z,p) =JS(p(c)||N(p,I)))"}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"優點","attrs":{}}]},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"整套模型是端到端訓練的,損失函數與測試指標能對應;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"理論誤差下限很小;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"引入 X 矩陣和 Y 矩陣,可以理解成引入先驗,讓模型的學習難度降低;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"低分辨率的效果依然不錯。","attrs":{}}]}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"缺點","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在實驗中,發現當關鍵點位於圖片邊緣時,預測結果不好。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"DARK","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[1] Zhang F , Zhu X , Dai H , et al. Distribution-Aware Coordinate Representation for Human Pose Estimation[J]. 2019.","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"思路","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"作者發現將 heatmaps 解碼結果,對生成最終數值座標存在較大影響。因此研究了標準的座標解碼方式的不足,提出一種分佈已知的解碼方式和編碼方式,來提高模型的最終效果。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"標準的座標解碼過程是,獲得模型的 heatmaps 後,通過argmax找到最大響應點 m 和第二大響應點 s ,以此來計算最終的響應點 p :","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"katexblock","attrs":{"mathString":"p=m+0.25\\frac{s-m}{\\left | s-m \\right |_2} "}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這個公式意味着最大響應點向第二大響應點偏移0.25個像素,這麼做的目的是補償量化誤差。然後把響應點映射回原圖:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"katexblock","attrs":{"mathString":"\\hat{p} = \\lambda p "}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這也說明, heatmap 中最大響應點並不是與原圖的關鍵點精確對應,只是大概位置。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基於上面的痛點,作者基於分佈已知的前提(高斯分佈),提出新的解碼方式,解決如何從 heatmap 中得到精確的位置,最小化量化誤差。同時,提出了配套的編碼方式","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"具體步驟","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"解碼","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"假設輸出的 heatmap 符合高斯分佈,那麼 heatmap 就可以用下面函數表示","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a2/a2790d5b01f2da235c9dc0ba76001b14.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其中\\(\\mu\\)表示關鍵點映射到 heatmap 的位置。我們需要求\\(\\mu\\)的位置,因此將函數g轉換成最大似然函數","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/3f/3f5fec5d18c2b6bff704eff16a535ac9.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對\\(P(\\mu )\\)進行泰勒展開","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a5/a55e72ecd0230da5af14eee572f4ce5d.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其中,m表示在熱力圖中最大響應的位置。而\\(\\mu\\)在熱力圖對應的是極點,存在以下性質","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/a4/a40600e9a8680062cdbb198dffd254e6.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ca/ca2f617a603f7cb0ed5373b39dcb210f.jpeg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"結合上述公式,可以得到","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因此,爲了得到 heatmap 中\\(\\mu\\)的位置,可以通過 heatmap 的一階導數與二階導數求得。這步的作用是通過數學的方法來說明該移動距離。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"前面提及了假設輸出的 heatmap 符合高斯分佈,實際情況是不符合的,實際可能是多峯,因此需要對 heatmap 進行調製,讓其儘量滿足這個前提。具體做法是用高斯核函數來平滑 heatmap ,同時爲了保證幅值一致,要進行歸一化。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"katexblock","attrs":{"mathString":"{h}'=K\\circledast h"}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"katexblock","attrs":{"mathString":"{h}'=\\frac{{h}'-min({h}')}{max({h}')-min({h}')}*max(h) "}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/96/965864711108398db094b73b1fec2d1f.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"綜上所述,步驟是:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"對 heatmap 使用高斯核來調製,並且縮放;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"求一階導數和二階導數,來得到","attrs":{}},{"type":"katexinline","attrs":{"mathString":"\\mu"}},{"type":"text","text":";","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"將","attrs":{}},{"type":"katexinline","attrs":{"mathString":"\\mu"}},{"type":"text","text":"映射回原圖。","attrs":{}}]}]}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"編碼","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"編碼指的是將關鍵點映射到 heatmap 上,並且生成高斯分佈。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"之前工作的做法是現對座標進行下采樣,然後將點進行量化(floor,ceil,round),最後使用量化後的座標生成高斯函數。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因爲量化是不可導的,存在量化誤差,因此,作者提出不進行量化,使用float來生成高斯函數,這樣就能生成無偏 heatmap 。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"UDP","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[1] Huang J , Zhu Z , Guo F , et al. The Devil is in the Details: Delving into Unbiased Data Processing for Human Pose Estimation[J]. 2019.","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"思路","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"作者從數據處理和座標表示下手,以此來提高性能。作者發現,目前的數據處理方式是存在偏差的,特別是flip時,會與原數據不對齊;其次座標表徵也存在統計誤差。這兩個問題共同導致結果存在偏差。因此提出了一種數據處理方式unbiased data processing,解決圖像轉換和座標轉換帶來的誤差。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"具體步驟","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/2b/2b7cef6e17fc32945f87b496dad6507b.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"Unbiased Coordinate System Transformation","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在測試中,通常使用翻轉後的","attrs":{}},{"type":"katexinline","attrs":{"mathString":"{k}'_{o,flip}"}},{"type":"text","text":"與原始的","attrs":{}},{"type":"katexinline","attrs":{"mathString":"{k}'_o"}},{"type":"text","text":"進行疊加,來得到最終的預測結果。但是","attrs":{}},{"type":"katexinline","attrs":{"mathString":"{k}'_o"}},{"type":"text","text":"與","attrs":{}},{"type":"katexinline","attrs":{"mathString":"{\\hat{k}}'_o"}},{"type":"text","text":"並不一致,存在偏差。可以看到翻轉後的 heatmap 不與原來的 heatmap 對齊,會產生誤差,與分辨率有關。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/7e/7e0fe711c7f32f0a95c0ee461faa16e4.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因此作者建議使用 unit length 來代替圖片長度:","attrs":{}},{"type":"katexinline","attrs":{"mathString":"w=w^p-1"}},{"type":"text","text":"。這樣翻轉後的 heatmap 就對齊了。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/f0/f04e8629d6b894787d9b7c104647c2e2.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"Unbiased Keypoint Format Transformation","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"無偏的關鍵點轉換方式應該是可逆的,即","attrs":{}},{"type":"katexinline","attrs":{"mathString":"k=Decoding(Enoding(k))"}},{"type":"text","text":"。因此,作者提出了兩種方式:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Combined classification and regression format","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"借鑑了目標檢測中anchor的方式,假設需要預測的關鍵點","attrs":{}},{"type":"katexinline","attrs":{"mathString":"k=(m,n)"}},{"type":"text","text":",則將其轉換成如下。其中C表示關鍵點的位置範圍,X和Y表示需要預測的offset。最終解碼就是在熱力圖C上取到argmax,然後對X與Y的熱力圖上拿到對應位置的offset,最後進行相加得到數值座標。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/5f/5f86fc29cfa3d0d97111658b33aa64af.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Classification format","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"與DARK方式一致,即使用泰勒展開來逼近真實位置。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"AID","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[1] Huang J , Zhu Z , Huang G , et al. AID: Pushing the Performance Boundary of Human Pose Estimation with Information Dropping Augmentation[J]. 2020.","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"貢獻點","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/d2/d24e7e9f450d577aa8992f1b1c7eceb9.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於關鍵點檢測,外觀信息與約束信息同樣重要。而以往的工作通常是過擬合外觀信息,而忽略了約束信息。因此,本文希望通過information drop,可理解成掩膜,來強調約束信息。約束信息有利於在該關鍵點被遮擋時,預測出其準確位置。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"而以往工作沒有使用到information drop的原因是,使用該數據增強手段後指標下降。作者就通過實驗,發現information drop是有助於提高模型精度的,但需要修改響應的訓練策略:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"加倍訓練次數;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"先使用沒有mask的來訓練,得到一個比較好的模型後,再把mask手段加入繼續訓練。","attrs":{}}]}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"RSN","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[1] Cai Y , Wang Z , Luo Z , et al. Learning Delicate Local Representations for Multi-Person Pose Estimation[J]. 2020.","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"貢獻點","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文是2019年coco關鍵點檢測冠軍的方案。其本文的主要思想是,最大程度聚合具有相同空間尺寸的特徵,以此來獲得豐富的局部信息,局部信息有利於產生更加準確的位置。因此提出了RSN網絡,如下圖一所示。從圖來看,即融合不同感受野特徵。RSN的輸出包含了low-level準確的空間信息與high-level語義信息,空間信息有助於定位,語義信息有助於分類。但是這兩類信息給最終預測帶來的影響權重是不一致的,需要使用到PRM模塊來平衡,RPM模塊本質就是一個通道注意力和空間注意力模塊。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ed/edc6600c9ab23f0b21b88f429fadbd60.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/1b/1bc43b844cc7d2cf329f0c6d38f31391.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Lite-HRNet","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"[1] Yu C , Xiao B , Gao C , et al. Lite-HRNet: A Lightweight High-Resolution Network[J]. 2021.","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"貢獻點","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文出了一個高效的高分辨率網絡,是HRNet的輕量化版本,通過將ShuffleNet中的shuffle block引入到HRNet中。同時發現shuffleNet中大量使用了pointwise convolution(1_1卷積),是計算瓶頸,因此引入contional channel weight來取代shuffle block中的1_1卷積。網絡的整體結構如下圖所示。在模型中一致保留高分辨率特徵,並不斷融合high-level特徵。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/65/6528cbcbc96c966730eb6b3e4089e674.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在前面提及到的contional channel weight如下所示。左邊是ShuffleNet中的shuffle block,右圖是contional channel weight。可以看到,採用新模塊來取代了1*1的卷積,實現跨stage信息交流與局部信息交流。其具體做法包含了Cross-resolution weight computation和Spatial weight computation。這兩個模塊的本質是注意力機制。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/68/68a90f16279f18d76407b74f0717eff6.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"實驗優化結果","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"模型結構","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本次模型借鑑了CenterNet/RetiaFace/DBFace中的相關工作。本次的使用了dsnt的方案。主要原因是:需要運行在端上,實時性是首要考慮因素。dsnt在低分辨率的優勢明顯。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"MobileNet v3使用small版本,FPN中使用 Nearest Upsample + conv + bn + Relu 來進行上採樣。在訓練時使用了 keypoints , mask 和 center 分支;而預測時,只使用到了 keypoints 分支。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/13/13f716e4eed202558db5fd819b6583bd.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"優化策略","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在本次實驗中,使用到了以下幾種優化策略:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"使用 mask 與 center 分支來輔助學習。其中mask表示文檔的掩膜,center表示文檔的中心點;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"使用deep Supervise。使用4倍下采樣特徵圖與8倍下采樣特徵圖來進行訓練,使用相同的loss函數來監督這兩層;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"dsnt中對邊緣點的效果不佳,因此,對圖片進行padding,讓點不再位於圖片邊緣;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","text":"數據增強策略,除了常規的光學擾動增強外,還對圖片進行random crop、random erase和random flip等操作;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":5,"align":null,"origin":null},"content":[{"type":"text","text":"進行loss函數嘗試工作,對於關鍵點分支的loss,嘗試過 euclidean loss , l1 loss , l2 loss 和 smoothl1 loss ,最終 smoothl1 loss 的效果最佳。","attrs":{}}]}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"評價指標","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"MSE","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"用於在訓練中評價驗證集的均方誤差。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"katexblock","attrs":{"mathString":"mse = \\frac{\\sum |d_i - \\hat{d_i}|_2^2}{N} "}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"oks-mAP","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"oks用於評估預測與真實關鍵點之間的相似度,mAP的評估方式類似coco[0.5:0.05:0.95]的評價方式,這裏取[0.99:0.001:0.999]。其中,oks進行一定變換,\\(d_{p,i}\\)表示點的歐式距離,\\(S_p\\)表示該四邊形的面積。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"katexblock","attrs":{"mathString":"oks_{p,i} =e^{-\\frac{d_{p,i}^2}{2S_p}}"}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"耗時","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"耗時指的是在紅米8上,用MNN推理框架跑模型的平均時間。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"實驗結果","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"先構建一個baseline,baseline的模型爲 moblieNet v3 + fpn + ssh module + keypoints 分支 + dsnt ,其中,都沒有使用上述優化策略,使用4倍下采樣特徵圖作爲輸出。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/95/95be6c70113738d8743747c01128dc80.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在v2版本中替換不同的loss函數。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/04/0470d3773187edb54a47a3892b0f3a65.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"此外,還嘗試過其他無效的tricks:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"輔助任務有利於提高模型的指標,因此還加入了edge的分支來輔助學習。實驗下來,加入該分支反而損害模型的指標。可能原因是edge是利用gt關鍵點來生成的,可能某些edge並不是對應文檔真正的邊緣;","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"現階段是預測文檔的4個角,因此在增加4個點來進行預測,分別是4條邊的中心點,所以模型一共預測8個關鍵點。實驗結果顯示,指標也下降了。","attrs":{}}]}]}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"Demo 演示","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/s?__biz=Mzg4MDY0ODk0Ng==&mid=2247484038&idx=1&sn=b3409892067b7b1a2fe0a6c2f0c3af0a&chksm=cf70b51bf8073c0dd6aaf41bb82e52c6eb552e4a3faf6312eff0c0c6ce5f9f5d7a5264c6db04&token=498222590&lang=zh_CN#rd","title":"","type":null},"content":[{"type":"text","text":"Demo 視頻請點擊此文章尾部查看。","attrs":{}}]}]},{"type":"heading","attrs":{"align":null,"level":1},"content":[{"type":"text","text":"總結","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"綜上所述,在端上的文檔關鍵點檢測領域中,目前嘗試下來,是基於heatmap+dsnt的方案較優,oks-mAP的指標有提升空間。但是,對比使用fc層進行迴歸座標的方式,基於heatmap的方案中存在一個不足是:無法根據文檔的約束信息,來預測圖片外的關鍵點座標。此方案的不足,會導致文檔內容的缺失,擺正效果不佳的情況。因此,後續需要彌補此不足。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/0b/0b0ab19875525bd50aba09e2a5fa1892.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"link","attrs":{"href":"https://mp.weixin.qq.com/s?__biz=Mzg4MDY0ODk0Ng==&mid=2247483731&idx=1&sn=9466e57a0f56124e25719740fa932016&chksm=cf70b6cef8073fd8db82357a28c4d276c11abf63d416baec51130dbc84337bd5800de6cd70ee&token=1213689564&lang=zh_CN#rd","title":"","type":null},"content":[{"type":"text","text":"如何高效開發端智能算法?MNN 工作臺 Python 調試詳解","attrs":{}}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"關注我們,每週 3 篇移動技術實踐&乾貨給你思考!","attrs":{}}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章