وهو مختبر بسيط ودقيق لإدارة الذاكرة CUDA لـ Pytorch ، وهو يتكون من أجزاء مختلفة عن الذاكرة:
سمات:
line_profiler Style Cuda Memory Profiler مع API بسيط.%mlrun / %%mlrun Line / Cell Magic.جدول المحتويات
pip install pytorch_memlabpip install git+https://github.com/stonesjtu/pytorch_memlabتحدث أخطاء خارج الذاكرة في Pytorch بشكل متكرر ، للمبرمجين الجدد والمبرمجين ذوي الخبرة. سبب شائع هو أن معظم الناس لا يتعلمون حقًا فلسفة إدارة الذاكرة الأساسية لـ Pytorch و GPU. لقد كتبوا رموز الذاكرة في كفاءة وشكاوا من تناول Pytorch من ذاكرة CUDA.
في هذا الريبو ، سأشارك بعض الأدوات المفيدة للمساعدة في تصحيح OOM ، أو لفحص الآلية الأساسية إذا كان أي شخص مهتمًا به.
Profiler للذاكرة هو تعديل لـ Python's line_profiler ، فهو يعطي معلومات استخدام الذاكرة لكل سطر من التعليمات البرمجية في الوظيفة/الطريقة المحددة.
import torch
from pytorch_memlab import LineProfiler
def inner ():
torch . nn . Linear ( 100 , 100 ). cuda ()
def outer ():
linear = torch . nn . Linear ( 100 , 100 ). cuda ()
linear2 = torch . nn . Linear ( 100 , 100 ). cuda ()
linear3 = torch . nn . Linear ( 100 , 100 ). cuda ()
work ()بعد الانتهاء من البرنامج النصي أو مقاطعة لوحة المفاتيح ، فإنه يعطي معلومات التوصيف التالية إذا كنت في دفتر Jupyter:

أو المعلومات التالية إذا كنت في محطة نصية فقط:
## outer
active_bytes reserved_bytes line code
all all
peak peak
0.00B 0.00B 7 def outer():
40.00K 2.00M 8 linear = torch.nn.Linear(100, 100).cuda()
80.00K 2.00M 9 linear2 = torch.nn.Linear(100, 100).cuda()
120.00K 2.00M 10 inner()
## inner
active_bytes reserved_bytes line code
all all
peak peak
80.00K 2.00M 4 def inner():
120.00K 2.00M 5 torch.nn.Linear(100, 100).cuda()
يمكن العثور على شرح لما يعنيه كل عمود في وثائق الشعلة. يمكن تمرير اسم أي حقل من memory_stats() display() لعرض الإحصاء المقابل.
إذا كنت تستخدم ديكور profile ، يتم جمع إحصائيات الذاكرة أثناء عمليات التشغيل المتعددة ويتم عرض الحد الأقصى فقط في النهاية. نقدم أيضًا واجهة برمجة تطبيقات أكثر مرونة تسمى profile_every التي تطبع معلومات الذاكرة في كل أوقات تنفيذ الوظيفة. يمكنك ببساطة استبدال @profile بـ @profile_every(1) لطباعة استخدام الذاكرة لكل تنفيذ.
يمكن أيضًا خلط @profile و @profile_every للحصول على مزيد من السيطرة على التفاصيل الدقيقة.
class Net ( torch . nn . Module ):
def __init__ ( self ):
super (). __init__ ()
@ profile
def forward ( self , inp ):
#do_somethingset_target_gpu . اختيار GPU على مستوى العالم ، مما يعني أنه يجب عليك تذكر أي وحدة معالجة الرسومات التي تقوم بتوصيفها خلال العملية برمتها: import torch
from pytorch_memlab import profile , set_target_gpu
@ profile
def func ():
net1 = torch . nn . Linear ( 1024 , 1024 ). cuda ( 0 )
set_target_gpu ( 1 )
net2 = torch . nn . Linear ( 1024 , 1024 ). cuda ( 1 )
set_target_gpu ( 0 )
net3 = torch . nn . Linear ( 1024 , 1024 ). cuda ( 0 )
func () يمكن العثور على المزيد من العينات في test/test_line_profiler.py
تأكد من تثبيت IPython ، أو قمت بتثبيت pytorch-memlab مع pip install pytorch-memlab[ipython] .
أولاً ، قم بتحميل الامتداد:
% load_ext pytorch_memlab هذا يجعل %mlrun و %%mlrun Line/Cell Magics متاحة للاستخدام. على سبيل المثال ، في خلية جديدة ، قم بتشغيل ما يلي لتكوين خلية كاملة
% % mlrun - f func
import torch
from pytorch_memlab import profile , set_target_gpu
def func ():
net1 = torch . nn . Linear ( 1024 , 1024 ). cuda ( 0 )
set_target_gpu ( 1 )
net2 = torch . nn . Linear ( 1024 , 1024 ). cuda ( 1 )
set_target_gpu ( 0 )
net3 = torch . nn . Linear ( 1024 , 1024 ). cuda ( 0 ) أو يمكنك استدعاء Profiler لبيان واحد على عبر %mlrun Cell Magic.
import torch
from pytorch_memlab import profile , set_target_gpu
def func ( input_size ):
net1 = torch . nn . Linear ( input_size , 1024 ). cuda ( 0 )
% mlrun - f func func ( 2048 ) انظر %mlrun? للمساعدة في الحجج التي يتم دعمها. يمكنك تعيين جهاز GPU على ملف تعريف الملف الشخصي ، وإلقاء نتائج التنميط إلى ملف ، وإرجاع كائن LineProfiler للتفتيش بعد الرصيد.
اكتشف المزيد عن طريق التحقق من دفتر جوبتر التجريبي
نظرًا لأن Memory Profiler يعطي فقط معلومات استخدام الذاكرة الإجمالية عن طريق الخطوط ، يمكن الحصول على معلومات أكثر استخدامًا للذاكرة من قبل مراسل الذاكرة .
يكرر مراسل الذاكرة جميع كائنات Tensor ويحصل على كائن UntypedStorage ( Storage سابقًا) للحصول على استخدام الذاكرة الفعلي بدلاً من Tensor.size السطحي.
انظر UntypedStorage للحصول على معلومات مفصلة
import torch
from pytorch_memlab import MemReporter
linear = torch . nn . Linear ( 1024 , 1024 ). cuda ()
reporter = MemReporter ()
reporter . report ()المخرجات:
Element type Size Used MEM
-------------------------------------------------------------------------------
Storage on cuda:0
Parameter0 (1024, 1024) 4.00M
Parameter1 (1024,) 4.00K
-------------------------------------------------------------------------------
Total Tensors: 1049600 Used Memory: 4.00M
The allocated memory on cuda:0: 4.00M
-------------------------------------------------------------------------------
import torch
from pytorch_memlab import MemReporter
linear = torch . nn . Linear ( 1024 , 1024 ). cuda ()
inp = torch . Tensor ( 512 , 1024 ). cuda ()
# pass in a model to automatically infer the tensor names
reporter = MemReporter ( linear )
out = linear ( inp ). mean ()
print ( '========= before backward =========' )
reporter . report ()
out . backward ()
print ( '========= after backward =========' )
reporter . report ()المخرجات:
========= before backward =========
Element type Size Used MEM
-------------------------------------------------------------------------------
Storage on cuda:0
weight (1024, 1024) 4.00M
bias (1024,) 4.00K
Tensor0 (512, 1024) 2.00M
Tensor1 (1,) 512.00B
-------------------------------------------------------------------------------
Total Tensors: 1573889 Used Memory: 6.00M
The allocated memory on cuda:0: 6.00M
-------------------------------------------------------------------------------
========= after backward =========
Element type Size Used MEM
-------------------------------------------------------------------------------
Storage on cuda:0
weight (1024, 1024) 4.00M
weight.grad (1024, 1024) 4.00M
bias (1024,) 4.00K
bias.grad (1024,) 4.00K
Tensor0 (512, 1024) 2.00M
Tensor1 (1,) 512.00B
-------------------------------------------------------------------------------
Total Tensors: 2623489 Used Memory: 10.01M
The allocated memory on cuda:0: 10.01M
-------------------------------------------------------------------------------
import torch
from pytorch_memlab import MemReporter
linear = torch . nn . Linear ( 1024 , 1024 ). cuda ()
linear2 = torch . nn . Linear ( 1024 , 1024 ). cuda ()
linear2 . weight = linear . weight
container = torch . nn . Sequential (
linear , linear2
)
inp = torch . Tensor ( 512 , 1024 ). cuda ()
# pass in a model to automatically infer the tensor names
out = container ( inp ). mean ()
out . backward ()
# verbose shows how storage is shared across multiple Tensors
reporter = MemReporter ( container )
reporter . report ( verbose = True )المخرجات:
Element type Size Used MEM
-------------------------------------------------------------------------------
Storage on cuda:0
0.weight (1024, 1024) 4.00M
0.weight.grad (1024, 1024) 4.00M
0.bias (1024,) 4.00K
0.bias.grad (1024,) 4.00K
1.bias (1024,) 4.00K
1.bias.grad (1024,) 4.00K
Tensor0 (512, 1024) 2.00M
Tensor1 (1,) 512.00B
-------------------------------------------------------------------------------
Total Tensors: 2625537 Used Memory: 10.02M
The allocated memory on cuda:0: 10.02M
-------------------------------------------------------------------------------
import torch
from pytorch_memlab import MemReporter
lstm = torch . nn . LSTM ( 1024 , 1024 ). cuda ()
reporter = MemReporter ( lstm )
reporter . report ( verbose = True )
inp = torch . Tensor ( 10 , 10 , 1024 ). cuda ()
out , _ = lstm ( inp )
out . mean (). backward ()
reporter . report ( verbose = True ) كما هو موضح أدناه ، يشير (->) إلى إعادة استخدام نفس مخرجات التخزين الخلفية:
Element type Size Used MEM
-------------------------------------------------------------------------------
Storage on cuda:0
weight_ih_l0 (4096, 1024) 32.03M
weight_hh_l0(->weight_ih_l0) (4096, 1024) 0.00B
bias_ih_l0(->weight_ih_l0) (4096,) 0.00B
bias_hh_l0(->weight_ih_l0) (4096,) 0.00B
Tensor0 (10, 10, 1024) 400.00K
-------------------------------------------------------------------------------
Total Tensors: 8499200 Used Memory: 32.42M
The allocated memory on cuda:0: 32.52M
Memory differs due to the matrix alignment
-------------------------------------------------------------------------------
Element type Size Used MEM
-------------------------------------------------------------------------------
Storage on cuda:0
weight_ih_l0 (4096, 1024) 32.03M
weight_ih_l0.grad (4096, 1024) 32.03M
weight_hh_l0(->weight_ih_l0) (4096, 1024) 0.00B
weight_hh_l0.grad(->weight_ih_l0.grad) (4096, 1024) 0.00B
bias_ih_l0(->weight_ih_l0) (4096,) 0.00B
bias_ih_l0.grad(->weight_ih_l0.grad) (4096,) 0.00B
bias_hh_l0(->weight_ih_l0) (4096,) 0.00B
bias_hh_l0.grad(->weight_ih_l0.grad) (4096,) 0.00B
Tensor0 (10, 10, 1024) 400.00K
Tensor1 (10, 10, 1024) 400.00K
Tensor2 (1, 10, 1024) 40.00K
Tensor3 (1, 10, 1024) 40.00K
-------------------------------------------------------------------------------
Total Tensors: 17018880 Used Memory: 64.92M
The allocated memory on cuda:0: 65.11M
Memory differs due to the matrix alignment
-------------------------------------------------------------------------------
يلاحظ:
عند إعادة التوجيه باستخدام
grad_mode=True، يحافظ Pytorch على المخازن المؤقتة على التوتر من أجل الانتشار الخلفي المستقبلي ، في مستوى C. لذلك لن يتم إدارة هذه المخازن المؤقتة أو جمعها بواسطة Pytorch. ولكن إذا قمت بتخزين هذه النتائج الوسيطة كمتغيرات Python ، فسيتم الإبلاغ عنها.
يمكنك أيضًا تصفية الجهاز للإبلاغ عنها عن طريق تمرير الوسائط الإضافية: report(device=torch.device(0))
مثال فاشل بسبب المخازن المؤقتة الموتر الجانبية لـ Pytorch
في المثال التالي ، يتم إنشاء مخزن مؤقت مؤقت في inp * (inp + 2) لتخزين كل من inp و inp + 2 ، للأسف يعرف Python فقط وجود INP ، لذلك فقدنا ذاكرة 2M ، وهو نفس حجم Tensor inp .
import torch
from pytorch_memlab import MemReporter
linear = torch . nn . Linear ( 1024 , 1024 ). cuda ()
inp = torch . Tensor ( 512 , 1024 ). cuda ()
# pass in a model to automatically infer the tensor names
reporter = MemReporter ( linear )
out = linear ( inp * ( inp + 2 )). mean ()
reporter . report ()المخرجات:
Element type Size Used MEM
-------------------------------------------------------------------------------
Storage on cuda:0
weight (1024, 1024) 4.00M
bias (1024,) 4.00K
Tensor0 (512, 1024) 2.00M
Tensor1 (1,) 512.00B
-------------------------------------------------------------------------------
Total Tensors: 1573889 Used Memory: 6.00M
The allocated memory on cuda:0: 8.00M
Memory differs due to the matrix alignment or invisible gradient buffer tensors
-------------------------------------------------------------------------------
في بعض الأحيان ، يرغب الناس في استباق مهمتك الجارية ، لكنك لا ترغب في توفير نقطة تفتيش ثم تحميلها ، في الواقع كل ما يحتاجون إليه هو موارد GPU (عادةً ما تكون موارد وحدة المعالجة المركزية وذاكرة وحدة المعالجة المركزية دائمًا ما تكون احتياطية في مجموعات GPU) ، حتى تتمكن من تحريك جميع مساحاتك من وحدات GPU إلى وحدة المعالجة المركزية ثم إيقاف مهمتك حتى يتم تشغيل إشارة إعادة التشغيل ، بدلاً من ذلك من محفوظات حدود التحقيق والتحميل.
لا تزال تتطور ..... ولكن يمكنك الاستمتاع بـ:
from pytorch_memlab import Courtesy
iamcourtesy = Courtesy ()
for i in range ( num_iteration ):
if something_happens :
iamcourtesy . yield_memory ()
wait_for_restart_signal ()
iamcourtesy . restore ()Memory_Reporter ، لا يتم تغطية الموترات المتوسطة بشكل صحيح ، لذلك قد ترغب في إدراج مثل هذه المنطق المجاملة بعد backward أو قبل forward .لقد عانيت كثيرًا من استخدام استخدام الذاكرة الغريب خلال 3 سنوات من تطوير نماذج التعلم العميقة الفعالة ، وبالطبع تعلمت الكثير من مجتمع المصادر المفتوحة العظيمة.
DataFrame.drop لـ Pandas 1.5+ MemReporter (#24)MemReporter line_profiler لم يتم العثور عليه