NumPy 코드 디버깅 및 프로파일링으로 성능 병목 현상 식별하기

Debug and Profile NumPy Code to Identify Performance Bottlenecks

NumPy는 데이터 과학자들이 다양한 데이터 작업을 수행하는 데 사용하는 파이썬 패키지입니다. 많은 다른 파이썬 패키지들이 NumPy를 기반으로 구축되어 있어 NumPy 사용법을 알아두는 것이 좋습니다.

NumPy 사용 경험을 향상시키기 위해서는 코드가 어디서 왜 성능이 저하되는지, 또는 최소한 우리의 기대치를 충족하지 못하는지 알아야 합니다. 이 글에서는 NumPy 코드의 성능 병목 현상을 확인하기 위한 다양한 디버깅 및 프로파일링 방법을 살펴보겠습니다.

NumPy 코드 디버깅

다른 무엇보다도 먼저, 우리의 코드가 완벽하게 실행되는지 확인해야 합니다. 그렇기 때문에 코드 프로파일링을 시도하기 전에 코드를 디버깅해야 합니다.

1. Assert 사용하기

디버깅을 수행하는 가장 쉬운 방법은 assert를 사용하여 코드 출력이 예상대로인지 확인하는 것입니다. 예를 들어, 다음과 같이 코드를 수행할 수 있습니다.

python

import numpy as np

arr = np.array([1, 2, 3])

assert arr.shape == (3,)

2. Python 디버거 사용하기

Python의 내장 디버거를 사용하여 코드를 검토하고 프로세스를 평가할 수 있습니다.

python

import pdb

실행 중간에 일시 중지해야 할 때 코드를 추가합니다.

pdb.set_trace()

3. Try와 Except 블록 사용하기

Try와 Except 블록을 사용하는 것도 디버깅하고 무엇이 잘못되고 있는지 알기 위한 좋은 방법입니다.

python

try:

a = np.array([1, 2, 3])

print(a[5])

except IndexError as e:

print("Caught an Error:", e)

출력:

Caught an Error: index 5 is out of bounds for axis 0 with size 3

NumPy 코드 프로파일링

디버깅 과정을 마치면, NumPy 코드 실행을 프로파일링하여 코드의 성능 병목 현상을 이해해 봅시다.

1. Time을 이용한 프로파일링

성능을 프로파일링하는 가장 간단한 방법은 수동으로 실행 시간을 이해하는 것입니다. 예를 들어, 다음 코드를 사용하여 더 자세히 알아볼 수 있습니다.

python

import time

start_time = time.time()

np.dot(np.random.rand(1000, 1000), np.random.rand(1000, 1000))

end_time = time.time()

print(f"Execution Time: {endtime - starttime} seconds")

출력:

Execution Time: 0.03861522674560547 seconds

코드 실행이 더 빨라지거나 느려지는지 확인하기 위해 다양한 코드 조합을 시도해볼 수 있습니다.

2. cProfile을 이용한 프로파일링

cProfile 패키지를 사용하여 더 자세히 프로파일링할 수 있습니다. 어떻게 작동하는지 살펴보겠습니다.

python

import cProfile

def mynumpyoperation():

np.dot(np.random.rand(1000, 1000), np.random.rand(1000, 1000))

cProfile.run('mynumpyoperation()')

출력:

7 function calls in 0.031 seconds

Ordered by: standard name

ncalls tottime percall cumtime percall filename:lineno(function)

1 0.016 0.016 0.031 0.031 :3(mynumpyoperation)

1 0.000 0.000 0.031 0.031 :1()

1 0.000 0.000 0.000 0.000 multiarray.py:741(dot)

1 0.000 0.000 0.031 0.031 {built-in method builtins.exec}

1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}

2 0.015 0.008 0.015 0.008 {method 'rand' of 'numpy.random.mtrand.RandomState' objects}

보시다시피, cProfile은 NumPy 코드의 전체 프로세스를 분석하고 세부 정보를 제공합니다. 프로세스가 호출된 횟수, 걸린 시간 및 어떤 메서드가 호출되었는지와 같은 정보를 제공합니다.

3. line_profiler를 이용한 프로파일링

line_profiler 패키지를 사용하여 NumPy 코드의 각 줄에 대한 세부 정보를 얻을 수도 있습니다. 먼저 패키지를 설치해야 합니다.

python

pip install line_profiler

패키지를 설치한 후, Jupyter Notebook에서 실행하는 경우 다음과 같은 매직 명령어를 사용합니다.

python

%loadext lineprofiler

프로파일링하고자 하는 NumPy 코드를 준비합시다.

python

import numpy as np

def matrix_multiplication(n):

a = np.random.rand(n, n)

b = np.random.rand(n, n)

result = np.dot(a, b)

return result

그런 다음, 코드가 내부적으로 어떻게 작동하는지 보기 위해 다음 매직 명령어를 사용합니다.

python

%lprun -f matrixmultiplication matrixmultiplication(500)

출력:

Timer unit: 1e-09 s

Total time: 0.0069203 s

File:

Function: matrix_multiplication at line 3

Line # Hits Time Per Hit % Time Line Contents

==============================================================

3 def matrix_multiplication(n):

4 1 2165161.0 2e+06 31.3 a = np.random.rand(n, n)

5 1 1824265.0 2e+06 26.4 b = np.random.rand(n, n)

6 1 2930093.0 3e+06 42.3 result = np.dot(a, b)

7 1 780.0 780.0 0.0 return result

결과는 위의 보고서와 유사할 것입니다. 성능 세부 정보와 성능 병목 현상이 어디에 있는지 확인할 수 있습니다.

4. memory_profiling을 이용한 프로파일링

마지막으로, 메모리 관점에서도 성능 병목 현상을 볼 수 있습니다. 이를 위해 memory_profiling 패키지를 사용할 수 있습니다.

python

pip install memory_profiler

Jupyter Notebook에서 메모리 프로파일링을 시작하기 위해 아래 매직 명령어를 사용합니다.

python

%loadext memoryprofiler

그런 다음, 실행하고자 하는 NumPy 코드를 준비하고 아래 매직 명령어를 사용하여 메모리 정보를 얻습니다.

python

def createlargearray():

a = [i for i in range(106)]

return sum(a)

%memit createlargearray()

출력:

peak memory: 5793.52 MiB, increment: 0.01 MiB

위 코드에서는 전체 프로세스에 대한 총 메모리 정보와 증가한 메모리 사용량을 얻을 수 있습니다. 이 정보는 특히 메모리가 제한된 경우에 중요합니다.

결론

NumPy 코드 디버깅 및 프로파일링은 성능 병목 현상이 어디에 있는지 이해하는 데 중요합니다. 이 글에서는 문제를 정확히 찾아내는 다양한 방법을 살펴보았습니다. 간단한 Python assert 명령어부터 memory_profiling과 같은 라이브러리까지, 다양한 방법으로 성능 정보를 얻을 수 있습니다.

이 글이 도움이 되었길 바랍니다!