데코레이터는 Python 컨텍스트 관리자의 특정 구현입니다. 이 기사에서는 Pytorch GPU 디버깅의 예를 통해 이를 사용하는 방법을 설명합니다. 모든 상황에서 작동하지 않을 수도 있지만 매우 유용하다는 것을 알았습니다.
메모리 누수를 디버깅하는 방법에는 여러 가지가 있습니다. 이 문서에서는 코드에서 문제가 있는 줄을 식별하는 유용한 방법을 보여줍니다. 이 방법을 사용하면 간결하게 특정 위치를 찾는 데 도움이 될 수 있습니다.
문제가 발생하는 경우 일반적이고 일반적으로 사용되는 방법은 디버거를 사용하여 다음 예와 같이 한 줄씩 검사하는 것입니다.
작동하지만 이러한 작업은 번거롭게 들립니다. 필요할 때 호출할 수 있는 함수로 캡슐화할 수 있으므로 기존 코드를 수정할 필요가 거의 없으므로 데코레이터의 기능을 도입하게 됩니다.
데코레이터는 코드의 어떤 부분에도 래핑될 수 있습니다. 여기서는 추가 텐서가 있는지 확인하기 위해 데코레이터를 사용합니다. 또한 실행 전후에 텐서의 수를 계산해야 하기 때문에 카운터도 필요합니다. 패턴은 다음과 같습니다:
def memleak_wrapper(func): def wrap(*args, **kwargs): print("num tensors start is ...") out = func(*args, **kwargs) print("num tensors end is ...") return out return wrap@memleak_wrapper def function_to_debug(x): print(f"put line(s) of code here. Input is {x}") out = x + 10 return outout = function_to_debug(x=1000) print(f"out is {out}") #输入类似这样 #num tensors start is ... #put line(s) of code here. Input is 1000 #num tensors end is ... #outis 1010
이 코드를 실행하려면 확인하려는 코드 줄을 함수(function_to_debug)에 넣어야 합니다. 하지만 여전히 많은 코드를 수동으로 삽입해야 하기 때문에 이것이 최선은 아닙니다. 또 다른 점은 코드 블록이 둘 이상의 변수를 생성하는 경우 이러한 다운스트림 변수를 사용하기 위한 추가 솔루션을 찾아야 한다는 것입니다.
위 문제를 해결하기 위해 함수 데코레이터 대신 컨텍스트 관리자를 사용할 수 있습니다. 컨텍스트 관리자의 가장 널리 사용되는 예는 with 문을 사용하여 컨텍스트를 인스턴스화하는 것입니다. 가장 일반적인 것은 다음과 같습니다.
with open("file") as f: …
Python의 contextlib 라이브러리를 사용하면 Python 사용자는 쉽게 컨텍스트 관리자를 직접 만들 수 있습니다. 따라서 이 기사에서는 위에서 데코레이터를 사용하려고 시도한 작업을 완료하기 위해 ContextDecorator를 사용할 것입니다. 개발과 사용이 더 쉽기 때문입니다.
from contextlib import ContextDecorator class check_memory_leak_context(ContextDecorator): def __enter__(self): print('Starting') return self def __exit__(self, *exc): print('Finishing') return False
ContextDecorator에는 컨텍스트에 들어가거나 나갈 때 호출되는 enter() 및 exit()라는 두 가지 메서드가 있습니다. __exit__의 *exc 매개변수는 들어오는 예외를 나타냅니다.
이제 위에서 언급한 문제를 해결하기 위해 이를 사용해 보겠습니다.
총 텐서 수를 계산해야 하기 때문에 계산 과정을 get_n_tensors() 함수로 캡슐화하여 컨텍스트의 시작과 끝에서 텐서 수를 계산할 수 있습니다. :
class check_memory_leak_context(ContextDecorator): def __enter__(self): self.start = get_n_tensors() return self def __exit__(self, *exc): self.end = get_n_tensors() increase = self.end — self.start if increase > 0: print(f”num tensors increased with" f"{self.end — self.start} !”) else: print(”no added tensors”) return False
증가가 있으면 콘솔에 출력하세요.
get_n_tensor()는 가비지 수집기(gc)를 사용하고 pytorch에 맞게 사용자 정의되었지만 다른 라이브러리에 맞게 쉽게 수정할 수 있습니다.
import gc def get_n_tensors(): tensors= [] for obj in gc.get_objects(): try: if (torch.is_tensor(obj) or (hasattr(obj, ‘data’) and torch.is_tensor(obj.data))): tensors.append(obj) except: pass return len(tensors)
이제 작동합니다. 코드의 모든 줄(또는 블록)에 이것을 사용합니다. 컨텍스트:
x = arbitrary_operation(x) ... with check_memory_leak_context(): y = x[0].permute(1, 2, 0).cpu().detach().numpy() x = some_harmless_operation() ... x = another_arbitrary_operation(x)
컨텍스트 데코레이터로 묶인 줄 내에 새 텐서가 생성되면 인쇄됩니다.
이것은 매우 좋은 코드 조각입니다. 개발 중에 별도의 파일에 넣을 수 있습니다. 이 문서의 전체 코드는 다음과 같습니다.
https://gist.github.com/MarkTension /4783697ebd5212ba500cdd829b364338
마지막으로 이 작은 기사가 컨텍스트 관리자가 무엇인지, 컨텍스트 데코레이터를 사용하는 방법, 디버그 Pytorch에 적용하는 방법을 이해하는 데 도움이 되기를 바랍니다.
위 내용은 컨텍스트 데코레이터를 사용하여 Pytorch 메모리 누수 문제 디버깅의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!