Nothing can help us endure dark times better than our faith.
事先了解下「物理內(nèi)存和虛擬內(nèi)存」,有助于閱讀和理解本文骡苞。
在 CUDA 編程中,內(nèi)存拷貝是非常費(fèi)時(shí)的一個(gè)動(dòng)作截酷。CPU 和 GPU 之間的總線是 PCI-Express吊骤,是雙向傳輸?shù)模g通過(guò) DMA(Direct Memory Access粪躬,直接內(nèi)存訪問(wèn))機(jī)制進(jìn)行數(shù)據(jù)拷貝袄友。
1.CUDA 固定內(nèi)存(Pinned Memory)
對(duì)于 CUDA 架構(gòu)而言殿托,主機(jī)端的內(nèi)存可分為兩種:
- 1)可分頁(yè)內(nèi)存(Pageable Memory)。
- 2)頁(yè)鎖定內(nèi)存(Page-locked Memory)剧蚣,或稱(chēng)固定內(nèi)存(Pinned Memory)支竹。
對(duì)于頁(yè)鎖定內(nèi)存,操作系統(tǒng)不會(huì)對(duì)其進(jìn)行分頁(yè)和交換操作鸠按,一定是存儲(chǔ)在物理內(nèi)存礼搁,不會(huì)存儲(chǔ)在虛擬內(nèi)存,因此待诅,GPU 可直接通過(guò) DMA 機(jī)制叹坦,在主機(jī)和 GPU 之間快速?gòu)?fù)制數(shù)據(jù)。而對(duì)于可分頁(yè)內(nèi)存卑雁,CUDA 驅(qū)動(dòng)會(huì)首先將 Pageable Memory 的數(shù)據(jù)拷貝到臨時(shí)的 Pinned Memory募书,然后再通過(guò) DMA 機(jī)制進(jìn)行數(shù)據(jù)傳輸。如下圖所示:
可見(jiàn)测蹲,從主機(jī)的頁(yè)鎖定內(nèi)存拷貝數(shù)據(jù)到 GPU 要更快的多莹捡。
但是,頁(yè)鎖定內(nèi)存也是更消耗物理內(nèi)存的扣甲。當(dāng)計(jì)算機(jī)的物理內(nèi)存充足時(shí)篮赢,可以設(shè)置為頁(yè)鎖定內(nèi)存齿椅。當(dāng)計(jì)算機(jī)的物理內(nèi)存不足或內(nèi)存交換過(guò)多時(shí),不建議使用頁(yè)鎖定內(nèi)存启泣,否則會(huì)嚴(yán)重影響應(yīng)用程序的性能涣脚。
C++ 中,通過(guò)操作系統(tǒng)接口 malloc() 在主機(jī)上分配可分頁(yè)內(nèi)存寥茫,通過(guò) CUDA 函數(shù) cudaHostAlloc() 在主機(jī)上分配頁(yè)鎖定內(nèi)存遣蚀。
2.torch.utils.data.DataLoader() 中的 pin_memory 參數(shù)
若創(chuàng)建 DataLoader 時(shí)設(shè)置 pin_memory=True,則返回放置在頁(yè)鎖定內(nèi)存中的批數(shù)據(jù)纱耻,使得將內(nèi)存的 Tensor 數(shù)據(jù)拷貝到 GPU 顯存變得更快芭梯。
因?yàn)?pin_memory 與電腦硬件性能有關(guān),由于不能確保每一個(gè)煉丹玩家都有高端設(shè)備弄喘,因此PyTorch 官網(wǎng)默認(rèn) pin_memory=False玖喘。