11"""
22미분자동화(autograd) 저장된 텐서를 위한 Hooks
3- ===========================================
3+ ================================================
44
55"""
66
77
88######################################################################
9- # 파이토치는 일반적으로 역전파를 사용하여 기울기를 계산합니다.
10- # 그러나 특정 작업에서는 역전파를 수행하기 위한 중간결과를 저장해야 합니다.
11- # 이번 튜토리얼에서는 이러한 텐서를 저장/검색하는 방법과 패킹/언패킹 프로세스를 제어하기위한 hooks을 정하는 방법을 안내합니다.
9+ # 파이토치는 일반적으로 역전파를 사용하여 기울기를 계산합니다.
10+ # 그러나 특정 작업에서는 역전파를 수행하기 위한 중간결과를 저장해야 합니다.
11+ # 이번 튜토리얼에서는 이러한 텐서를 저장/검색하는 방법과 패킹/언패킹 프로세스를 제어하기위한 hooks을 정하는 방법을 안내합니다.
1212
1313# 이 튜토리얼에서는 사용자가 역전파가 이론상에서 작동하는 방식에 익숙하다고 가정합니다. 아니라면, 아래의 자료를 먼저 읽어보세요.
1414# https://colab.research.google.com/drive/1aWNdmYt7RcHMbUk-Xz2Cv5-cGFSWPXe0#scrollTo=AHcEJ6nXUb7W
1515
1616######################################################################
1717# 저장된 tensor
18- # -------------
18+ # -------------------
1919
2020
2121######################################################################
22- # 모델의 훈련은 일반적으로 모델을 인퍼런스하는 것보다 학습하는 과정에서 메모리를 더 많이 사용합니다.
23- # 대략적으로 말하면 파이토치는 역전파를 호출하는데 필요한 계산 그래프를 저장해야하므로 추가 메모리 사용량이 있기 때문입니다.
22+ # 모델의 훈련은 일반적으로 모델을 인퍼런스하는 것보다 학습하는 과정에서 메모리를 더 많이 사용합니다.
23+ # 대략적으로 말하면 파이토치는 역전파를 호출하는데 필요한 계산 그래프를 저장해야하므로 추가 메모리 사용량이 있기 때문입니다.
2424# 이 튜토리얼의 한가지 목표는 이러한 이해에 대한 미세 조정을 실행하는 것입니다.
2525#
2626# 사실, 이 그래프 자체로는 가끔은 그다지 많은 메모리를 사용하진 않습니다. 여타의 텐서들을 복제하지 않는 것 처럼요.
27- # 그러나, 그래프는 *참조* 를 유지할 수 있습니다.
28- # 그렇지 않으면 범위를 벗어난 텐서를 : **저장된 텐서** 라고 명명할 수 있습니다.
27+ # 그러나, 그래프는 *참조* 를 유지할 수 있습니다.
28+ # 그렇지 않으면 범위를 벗어난 텐서를 : **저장된 텐서** 라고 명명할 수 있습니다.
2929
3030
3131######################################################################
32- # (일반적으로)모델을 훈련하는데 평가보다 더 많은 메모리를 소하게 되는 이유는 무엇일까요?
33- # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
32+ # (일반적으로) 모델을 훈련하는데 평가보다 더 많은 메모리를 사용하는 이유는 무엇일까요?
33+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3434
3535
3636######################################################################
3737# 간단한 예제를 시작해봅시다: :math: `y = a \mapsto \cdot b` , 이것은 미분량(그래디언트)로 알고있는 :math: `y`,로 각각 :math: `a` and
38- # :math: `b`:로 상정합니다.
39-
38+ # :math: `b`:로 상정합니다.
4039
41- .. math :: \frac {\partial y }{\partial a } = b
42- .. math :: \frac {\partial y }{\partial b } = a
40+ # .. math:: \frac{\partial y}{\partial a} = b
41+ # .. math:: \frac{\partial y}{\partial b} = a
4342
4443
4544import torch
4948y = a * b
5049
5150#################################################################
52- # torchviz를 사용해서, 계산그래프를 시각화 할 수 있습니다.
53- .. figure :: https :// user - images .githubusercontent .com / 8019486 / 130124513 - 72e016 a3 - c36f - 42 b9 - 88e2 - 53 baf3e016c5 .png
54- :width : 300
55- :align : center
51+ # torchviz를 사용해서, 계산그래프를 시각화 할 수 있습니다.
52+ # .. figure:: https://user-images.githubusercontent.com/8019486/130124513-72e016a3-c36f-42b9-88e2-53baf3e016c5.png
53+ # :width: 300
54+ # :align: center
5655
5756
5857######################################################################
5958# 이 예제에서 파이토치는 중간 값 :math: `a` 및 :math: `b` 를 저장하여 역방향 동안 기울기를 계산합니다.
6059#
61- .. figure :: https :// user - images .githubusercontent .com / 8019486 / 130124538 - 3 da50977 - 6 f0b - 46 d0 - 8909 - 5456 ade9b598 .png
62- :width : 300
63- :align : center
60+ # .. figure:: https://user-images.githubusercontent.com/8019486/130124538-3da50977-6f0b-46d0-8909-5456ade9b598.png
61+ # :width: 300
62+ # :align: center
6463
6564
6665######################################################################
7170
7271
7372######################################################################
74- # 계산 그래프가 깊어질수록 *저장된 텐서*가 더 많이 저장됩니다. 한편, 텐서는 그래프가 아니었다면 범위를 벗어나게 됩니다.
73+ # 계산 그래프가 깊어질수록 *저장된 텐서*가 더 많이 저장됩니다. 한편, 텐서는 그래프가 아니었다면 범위를 벗어나게 됩니다.
7574
7675def f (x ):
7776 return x * x
@@ -80,14 +79,14 @@ def f(x):
8079y = f (f (f (x )))
8180
8281######################################################################
83- .. figure :: https :// user - images .githubusercontent .com / 8019486 / 130124570 - f1074098 - 1 bb3 - 459 e - bf5a - 03 bf6f65b403 .png
84- :width : 500
85- :align : center
82+ # .. figure :: https://user-images.githubusercontent.com/8019486/130124570-f1074098-1bb3-459e-bf5a-03bf6f65b403.png
83+ # :width: 500
84+ # :align: center
8685
8786######################################################################
8887# 위의 예제에서 미분(grad)없이 실행하면 범위내의 ``x`` 와 ``y`` 는 유지되지만
8988# 그래프에서는 ``f(x)``와 ``f(f(x)`가 추가로 저장됩니다.
90- # 따라서 훈련 중 정방향 경로를 실행하면 평가중에 (더 정확하게는 자동미분(auto grad)가 필요하지 않은 경우보다) 메모리 사용비중이 더 많아지게 됩니다.
89+ # 따라서 훈련 중 정방향 경로를 실행하면 평가중에 (더 정확하게는 자동미분(auto grad)가 필요하지 않은 경우보다) 메모리 사용비중이 더 많아지게 됩니다.
9190
9291
9392######################################################################
@@ -108,7 +107,7 @@ def f(x):
108107
109108
110109######################################################################
111- # 그러나 이것은 항상 같은 결과를 보여주지 않습니다.
110+ # 그러나 이것은 항상 같은 결과를 보여주지 않습니다.
112111
113112a = torch .randn (5 , requires_grad = True )
114113y = torch .exp (a )
@@ -119,7 +118,7 @@ def f(x):
119118######################################################################
120119# 내부적으로는 파이토치는 참조주기를 방지하기 위해서 텐서 ``y``를 **패킹** 및 **언패킹** 했습니다
121120# 경험상, 역전파 저장된 텐서에 엑세스하면 원래 텐서와 동일한 텐서의 객체가 생성된다는 결과를 기대해서는 *안됩니다.*
122- # 그러나 동일한 *저장소*를 공유합니다.
121+ # 그러나 동일한 *저장소*를 공유합니다.
123122
124123######################################################################
125124# 저장된 텐서 hooks
@@ -147,10 +146,10 @@ def unpack_hook(x):
147146
148147
149148######################################################################
150- # ``pack_hook`` 함수는 작업이 역전파를 위해 텐서를 저장할 때 마다 호출됩니다. 그러면
149+ # ``pack_hook`` 함수는 작업이 역전파를 위해 텐서를 저장할 때 마다 호출됩니다. 그러면
151150# ``pack_hook``의 출력이 원래 텐서 대신 계산 그래프에 저장됩니다.
152- # ``unpack_hook``은 해당 반환 값을 사용하여 역방향 전달 중에 실제로 사용된 텐서를 새 텐서로 계산합니다.
153- # 일반적으로 ``unpack_hook(pack_hook(t))`` 가 ``t`` 와 같길 기대합니다.
151+ # ``unpack_hook``은 해당 반환 값을 사용하여 역방향 전달 중에 실제로 사용된 텐서를 새 텐서로 계산합니다.
152+ # 일반적으로 ``unpack_hook(pack_hook(t))`` 가 ``t`` 와 같길 기대합니다.
154153
155154
156155x = torch .randn (5 , requires_grad = True )
@@ -161,22 +160,22 @@ def unpack_hook(x):
161160
162161
163162######################################################################
164- # 한 가지 주의할 점은 ``unpack_hook``이 올바른 값을 가진 텐서를 파생할 수 있는 한
165- # ``pack_hook``의 출력은 *모든 파이썬 객체*가 될 수 있다는 것입니다.
163+ # 한 가지 주의할 점은 ``unpack_hook``이 올바른 값을 가진 텐서를 파생할 수 있는 한
164+ # ``pack_hook``의 출력은 *모든 파이썬 객체*가 될 수 있다는 것입니다.
166165
167166######################################################################
168167# 몇 가지 특이한 예제들
169- # ~~~~~~~~~~~~~~~~~~~~
168+ # ~~~~~~~~~~~~~~~~~~~~~~~~
170169
171170
172171
173172######################################################################
174- # 먼저, 가능성을 설명하기 위해서 몇 가지 어리석어보이는 예가 있지만 아마 하고싶지 않을 수도 있습니다.
173+ # 먼저, 가능성을 설명하기 위해서 몇 가지 어리석어보이는 예가 있지만 아마 하고싶지 않을 수도 있습니다.
175174
176175######################################################################
177176# **반환 및 int**
178177#
179- # 파이썬 리스트의 인덱스반환
178+ # 파이썬 리스트의 인덱스반환
180179#
181180# 상대적으로는 상관없지만 논란의 여지가 있는 유용성
182181
@@ -199,7 +198,7 @@ def unpack(x):
199198######################################################################
200199# **튜플의 반환**
201200#
202- # 일부 텐서와 함수를 반환하고 압축을 푸는 방법은 현재 형태로는 유용하지 않을 것입니다.
201+ # 일부 텐서와 함수를 반환하고 압축을 푸는 방법은 현재 형태로는 유용하지 않을 것입니다.
203202
204203def pack (x ):
205204 delta = torch .randn (* x .size ())
@@ -231,22 +230,22 @@ def unpack(packed):
231230
232231
233232######################################################################
234- # 이러한 예제는 실제로 유용하지 않을 것이지만 ``pack_hook``의 출력이 원래 텐서의 내용을 검색하기에 충분한 정보를 포함하는 한
235- # 실제로 모든 Python의 객체가 될 수 있음을 보여줍니다.
236- # 다음 섹션에서는 더 유용한 응용프로그램에 중점을 두겠습니다.
233+ # 이러한 예제는 실제로 유용하지 않을 것이지만 ``pack_hook``의 출력이 원래 텐서의 내용을 검색하기에 충분한 정보를 포함하는 한
234+ # 실제로 모든 Python의 객체가 될 수 있음을 보여줍니다.
235+ # 다음 섹션에서는 더 유용한 응용프로그램에 중점을 두겠습니다.
237236
238237######################################################################
239238# 텐서를 CPU에 저장하기
240- # ~~~~~~~~~~~~~~~~~~~~
239+ # ~~~~~~~~~~~~~~~~~~~~~~~~
241240
242241
243242
244243######################################################################
245- # 매우 빈번하게, 계산 그래프를 수반하는 텐서는 GPU에 있습니다.
246- # 그래프에 이러한 텐서에 대한 참조를 유지하는 것은 대부분의 모델이 평가중에 정상적으로 수행되었을 때
247- # 훈련중에 GPU 메모리가 부족하게 만드는 원인이 됩니다.
244+ # 매우 빈번하게, 계산 그래프를 수반하는 텐서는 GPU에 있습니다.
245+ # 그래프에 이러한 텐서에 대한 참조를 유지하는 것은 대부분의 모델이 평가중에 정상적으로 수행되었을 때
246+ # 훈련중에 GPU 메모리가 부족하게 만드는 원인이 됩니다.
248247#
249- # hooks는 이를 구현하는 매우 간단한 방법을 제공합니다.
248+ # hooks는 이를 구현하는 매우 간단한 방법을 제공합니다.
250249
251250
252251
@@ -292,8 +291,8 @@ def forward(self, x):
292291#
293292# 물론 네트워크 특정부분만 CPU에 저장하여 절충안을 조정할 수 있습니다.
294293#
295- # 예를 들어, 모든 모듈을 감싸두고 해당 텐서를 CPU에 저장하는 특별한
296- # ``nn.Module`` 을 정의할 수 있습니다.
294+ # 예를 들어, 모든 모듈을 감싸두고 해당 텐서를 CPU에 저장하는 특별한
295+ # ``nn.Module`` 을 정의할 수 있습니다.
297296
298297class SaveToCpu (nn .Module ):
299298 def __init__ (self , module ):
@@ -317,12 +316,12 @@ def forward(self, *args, **kwargs):
317316
318317######################################################################
319318# 텐서를 디스크에 저장하기
320- # ~~~~~~~~~~~~~~~~~~~~~~
319+ # ~~~~~~~~~~~~~~~~~~~~~~~~~~~
321320
322321
323322
324323######################################################################
325- # 마찬가지로, 이러한 텐서를 디스크에 저장하고 싶을 수 도 있습니다. 다시 말하지만 이것은 앞서말한 hooks로 달성할 수 있습니다.
324+ # 마찬가지로, 이러한 텐서를 디스크에 저장하고 싶을 수 도 있습니다. 다시 말하지만 이것은 앞서말한 hooks로 달성할 수 있습니다.
326325
327326######################################################################
328327# 단순한 버전의 아마 이럴것입니다.
@@ -342,8 +341,8 @@ def unpack_hook(name):
342341
343342
344343######################################################################
345- # 위의 코드가 나쁜 이유는 디스크에 저장된 파일이 누출되고 해당 파일을 지울수도 없기 때문입니다.
346- # 이 문제를 해결하는 것은 그렇게 간단하지 않아 보입니다.
344+ # 위의 코드가 나쁜 이유는 디스크에 저장된 파일이 누출되고 해당 파일을 지울수도 없기 때문입니다.
345+ # 이 문제를 해결하는 것은 그렇게 간단하지 않아 보입니다.
347346#
348347# 잘못된 버전 - 힌트: 이렇게 하지 마시오.
349348
@@ -365,9 +364,9 @@ def unpack_hook(name):
365364
366365
367366######################################################################
368- # 위의 코드가 작동하지 않는 이유는 ``unpack_hook``가 여러번 호출되기 때문입니다.
367+ # 위의 코드가 작동하지 않는 이유는 ``unpack_hook`` 가 여러번 호출되기 때문입니다.
369368# 먼저 압축을 풀 때 파일을 삭제하면 처음에, 저장된 텐서에 엑세스시에 사용할 수 없습니다.
370- # 두 번째에는 오류가 발생합니다.
369+ # 두 번째에는 오류가 발생합니다.
371370
372371x = torch .ones (5 , requires_grad = True )
373372with torch .autograd .graph .saved_tensors_hooks (pack_hook , unpack_hook ):
@@ -382,7 +381,7 @@ def unpack_hook(name):
382381
383382######################################################################
384383# 이문제를 해결하기위해 이점을 활용하는 hooks의 버전을 작성할 수 있습니다.
385- # 파이토치가 저장된 데이터를 자동으로 해제(삭제)한다는 사실이 더이상 필요하지 않을 때입니다.
384+ # 파이토치가 저장된 데이터를 자동으로 해제(삭제)한다는 사실이 더이상 필요하지 않을 때입니다.
386385
387386class SelfDeletingTempFile ():
388387 def __init__ (self ):
@@ -402,12 +401,10 @@ def unpack_hook(temp_file):
402401
403402######################################################################
404403# ``backward`` 를 호출하면 ``pack_hook`` 이 삭제되고,
405- # 파일이 제거되도록 하므로 더 이상 파일이 누출되지 않습니다.
404+ # 파일이 제거되도록 하므로 더 이상 파일이 누출되지 않습니다.
406405#
407406# 다음과 같은 방식으로 모델에 사용할 수 있습니다.
408407
409-
410- # Only save on disk tensors that have size >= 1000
411408# 사이즈 >=1000인 텐서만이 디스크에 저장될 수 있습니다.
412409
413410SAVE_ON_DISK_THRESHOLD = 1000
@@ -437,9 +434,10 @@ def forward(self, *args, **kwargs):
437434
438435
439436######################################################################
440- # 이 마지막 예에서는
441- # 반드시 저장해야하며 이 기능을 ``nn.DataParallel`` 와 어떻게 조합하는 텐서들에 대해 어떻게 필터하는지에 대한 증명을 해보았습니다.
437+ # 이 마지막 예제에서는 저장해야 하는 (여기에서는 원소의 수가 1000 이상인) 텐서들을 골라내는 방법과
438+ # 이 기능을 ``nn.DataParallel`` 과 함께 사용하는 방법을 살펴보았습니다.
442439
443440
444441######################################################################
445- # 만일 여기까지 따라오셨다면, 축하합니다! 당신은 저장된 텐서 hooks을 어떻게 사용하는지 그리고 계산 메모리의 절충안에서 몇 가지 시나리오를 유용하게 사용할 수 있습니다!
442+ # 여기까지 잘 따라오셨나요? 축하합니다!
443+ # 이제 저장된 텐서 hooks을 어떻게 사용하는지와 연산 시 메모리 관리(trade-offs)에 유용하게 사용할 수 있는 방법을 알게 되셨습니다.
0 commit comments