便利性和性能通常成反比。如果程式碼很容易使用,那麼它的最佳化程度就較低。如果優化的話就不太方便了。高效率的程式碼需要更接近實際運作的內容、運作方式的細節。
我在我們正在進行的為癌症研究運行和優化 DeepCell 細胞分割的工作中遇到了一個例子。 DeepCell AI 模型可以預測哪些像素最有可能位於細胞中。從那裡,我們從最可能的像素“洪水填充”,直到到達單元格邊界(低於某個閾值)。
這個過程的一部分涉及平滑預測細胞內的小間隙,這可能由於多種原因而發生,但在生物學上是不可能的。 (想想甜甜圈孔,而不是細胞的多孔膜。)
補洞演算法是這樣的:
這是維基百科文章中歐拉數的範例;圓(僅直線部分)的歐拉特徵為零,而圓盤(「填充」圓)的值為 1。
不過,我們在這裡不是討論定義或計算歐拉數。我們將討論該庫計算歐拉數的簡單路徑為何效率很低。
首先要做的事情。我們透過使用 Speedscope 查看此設定檔注意到了這個問題:
它顯示在 Regionprops 上花費了約 32 毫秒(約 15%)。這個視圖是左重的,如果我們進入時間軸視圖並放大,我們會得到這個:
(請注意,我們執行了兩次,因此此處約為 16 毫秒,其他地方約為 16 毫秒,未顯示。)
這立即令人懷疑:使用 find_objects 尋找物件的「有趣」部分是第一個條子,0.5 毫秒。它傳回一個元組列表,而不是生成器,所以當它完成時就完成了。那麼其他的東西又怎麼樣呢?我們正在建構 RegionProperties 物件。讓我們放大其中之一。
這些小條子(我們不會放大)是自訂 __setattr__ 呼叫:RegionProperties 物件支援別名,例如,如果您設定屬性 ConvexArea,它會重定向到標準屬性 area_convex。即使我們沒有使用它,我們仍然會使用屬性轉換器。
此外:我們甚至沒有使用區域屬性中計算的大部分屬性。我們只關心歐拉數:
props = regionprops(np.squeeze(label_img.astype('int')), cache=False) for prop in props: if prop.euler_number反過來,它僅使用區域屬性的最基本方面:find_objects 檢測到的圖像區域(原始圖像的切片)。
因此,我們將程式碼更改為 fill_holes 程式碼,以簡單地繞過regionprops通用函數。相反,我們呼叫 find_objects 並將生成的圖像子區域傳遞給 euler_number 函數(而不是 RegionProperties 物件上的方法)。
這是拉取請求:deepcell-imaging#358 跳過 Regionprops 建置
透過跳過中間對象,我們的 fill_holes 操作得到了不錯的效能提升:
影像尺寸 前 後 加速 26萬像素 48ms 40ms 8 毫秒 (17%) 1.4億像素 15.6s 11.7秒 3.9秒(25%) 對於較大的圖像,4s 約佔整體運行時間的 3%——不是大部分,但也不算太差。
免責聲明: 提供的所有資源部分來自互聯網,如果有侵犯您的版權或其他權益,請說明詳細緣由並提供版權或權益證明然後發到郵箱:[email protected] 我們會在第一時間內為您處理。
Copyright© 2022 湘ICP备2022001581号-3