DL4J中文文件/配置/記憶體工作間
什麼是工作間?
ND4J提供了一個額外的記憶體管理模型:工作間。這允許你在沒有用於堆外記憶體跟蹤的JVM垃圾回收器的情況下,重用迴圈工作負載的記憶體。換句話說,在工作間迴圈結束時,所有的陣列記憶體內容都會失效。工作間被整合到DL4J中進行訓練和推理。
基本思想很簡單:你可以在工作間(或空間)內執行你需要的操作,並且如果你要從其去除一個INDArray(即,將結果移出工作空間),只需呼叫INDArray.detach(),你將獲得一個獨立的INDArray副本。
神經網路
對於DL4J使用者來說,工作間提供了更好的效能,並且預設情況下從1.0.0-alpha開始啟用。因此,對於大多數使用者,不需要明確的工作間配置。
為了從工作間中受益,它們需要被啟用。你可以使用以下方式配置工作間模式:
在你的神經網路中使用 .trainingWorkspaceMode(WorkspaceMode.SEPARATE)
或 .inferenceWorkspaceMode(WorkspaceMode.SINGLE)
。
SEPARATE工作間和SINGLE工作間之間的差異是效能和記憶體佔用之間的折衷:
- SEPARATE 稍微慢一點,但是使用更少的記憶體。
- SINGLE 稍微快一點,但使用更多記憶體。
也就是說,可以使用不同的模式進行訓練和推理(即,使用SEPARATE進行訓練,並使用SINGLE進行推理,由於推理僅涉及前饋迴圈,而不涉及反向傳播或更新器)。
通過啟用工作間,在訓練期間使用的所有記憶體將被重用和跟蹤,而不會受到JVM GC干擾。唯一例外的是在內部使用前饋迴圈的工作間(如果啟用的話)的output()
方法。隨後,它將產生的INDArray
從工作間中分離出來,從而為您提供獨立的INDArray
,該INDArray
將由JVM GC處理。
請注意:在1.0.0-alpha發行版之後,DL4J中的工作間被重構——SEPARATE/SINGLE模式已經被廢棄,並且使用者應該使用ENABLED來代替。
垃圾回收器
如果你的訓練過程使用工作間,建議你禁用(或減少週期性GC呼叫的頻率)。可以這樣做:
// 這將限制GC呼叫的頻率為5000毫秒。 Nd4j.getMemoryManager().setAutoGcWindow(5000) // 或者你可以完全禁用它 Nd4j.getMemoryManager().togglePeriodicGc(false);
把它放到 model.fit(...)
呼叫之前。
ParallelWrapper & ParallelInference
對於ParallelWrapper
,還添加了工作間模式配置選項。這樣,每個訓練執行緒將使用一個單獨的工作間,連線到指定的裝置。
ParallelWrapper wrapper = new ParallelWrapper.Builder(model)
// DataSets 預獲取選項。每個工作機器的快取大小。
.prefetchBuffer(8)
//設定工作機器的數量為GPU的數量
.workers(2)
// 罕見的平均效能提高,但可能會降低模型準確率
.averagingFrequency(5)
// 如果設定為TRUE,則每個平均模型得分將被報告。
.reportScoreAfterAveraging(false)
// 3 選項在這裡: NONE, SINGLE, SEPARATE
.workspaceMode(WorkspaceMode.SINGLE)
.build();
迭代器
我們提供非同步預獲取迭代器、AsyncDataSetIterator
和AsyncMultiDataSetIterator
,它們通常在內部使用。
這些迭代器可選地使用特殊的迴圈工作間模式來獲得較小的記憶體佔用。在這種情況下,工作空間的大小將由從底層迭代器出來的第一個DataSet
的記憶體需求決定,而緩衝區大小由使用者定義。如果記憶體需求隨時間變化(例如,如果使用可變長度的時間序列),則工作間將被調整。
警告:如果你使用的是自定義迭代器或RecordReader,請確保在第一次next()呼叫中沒有初始化大型物件。在建構函式中這樣做,以避免不希望的工作間增長。
警告:使用了AsyncDataSetIterator
,DataSets應
在呼叫next()
資料集之前被使用。你不應該以任何方式儲存它們,也不應不呼叫detach()
。否則,在DataSet內用於INDArrays的記憶體最終將在AsyncDataSetIterator
內被覆蓋。
如果由於某種原因,你不希望將迭代器包裝到非同步預獲取器中(例如,用於除錯目的),則提供特殊的包裝器:AsyncShieldDataSetIterator
和AsyncShieldMultiDataSetIterator
。基本上,這些只是薄的包裝,防止預獲取。
評估
通常,評估假設使用model.output()方法,該方法本質上返回與工作空間分離的INDArray
。在訓練過程中定期評估的情況下,最好使用內建的方法進行評估。例如:
Evaluation eval = new Evaluation(outputNum);
ROC roceval = new ROC(outputNum);
model.doEvaluation(iteratorTest, eval, roceval);
這段程式碼將在iteratorTest
上執行一個單獨的週期,並且它將在不需要任何額外INDArray
分配的情況下更新兩個IEvaluation
實現(或更少/更多,如果你要求)。
工作間破壞
也有一些情況,比如,你缺少RAM,可能希望釋放你無法控制的所有工作空間;例如,在評估或訓練期間。
那麼可以這樣做:Nd4j.getWorkspaceManager().destroyAllWorkspacesForCurrentThread();
此方法將銷燬在呼叫執行緒中建立的所有工作空間。如果你自己在一些外部執行緒中建立了工作間,那麼可以在不再需要工作間之後,在該執行緒中使用相同的方法。
工作間異常
如果工作區使用不正確(例如,在自定義層或資料管道中的缺陷),你可能會看到一個錯誤訊息,如:
org.nd4j.linalg.exception.ND4JIllegalStateException: Op [set] Y argument uses leaked workspace pointer from workspace [LOOP_EXTERNAL]
For more details, see the ND4J User Guide: nd4j.org/userguide#workspaces-panic
DL4J的層工作間管理器
DL4J的層API包含一個“層工作區管理器”的概念。
這個類的思想是,它允許我們在給定工作間的不同的可能配置的情況下,輕鬆且精確地控制給定陣列的位置。例如,層外的啟用可以在推理期間放置在一個工作間中,而在訓練期間放置在另一個工作間中;這是出於效能原因。然而,使用層工作間管理器設計,層的實現者不需要為此而煩惱。
這在實踐中意味著什麼?通常很簡單…
- 當返回 (
activate(boolean training, LayerWorkspaceMgr workspaceMgr)
方法),確保返回的陣列已在ArrayType.ACTIVATIONS
(i.e., 使用 LayerWorkspaceMgr.create(ArrayType.ACTIVATIONS, …) 或類似)中定義 - 當返回啟用梯度 (
backpropGradient(INDArray epsilon, LayerWorkspaceMgr workspaceMgr)
),類似的返回一個在ArrayType.ACTIVATION_GRAD 中定義的陣列。
你還可以在適合的工作間使用一個在任何工作間定義的陣列,例如:LayerWorkspaceMgr.leverageTo(ArrayType.ACTIVATIONS, myArray)
注意,如果你沒有實現自定義層(而是隻想對MultiLayerNetwork/ComputationGraph之外的層執行轉發),那麼可以使用LayerWorkspaceMgr.noWorkspaces()
。
翻譯:風一樣的男子
有任何問題請聯絡微信