딥러닝이나 데이터 분석을 조금이라도 찍먹 해보신 분들이라면 numpy 라이브러리에 대해 다들 들어보셨을 겁니다.
Numpy는 벡터 및 행렬 을 도와주는 고성능 수치 계산 라이브러리입니다. 파이썬에서 기본 자료형 중 list도 얼핏보면 numpy의 ndarray와 비슷해보이는데 어떤 차이점이 있어서 numpy에서는 더 빠른 계산이 가능한 것일까요?
우선 Numpy의 가장 큰 특징은 C언어로 구현이 되어있다는 것입니다. 구글링을 해보면 numpy의 핵심 기능이 C언어로 구현되어있어 속도가 빠르다는 글들을 쉽게 찾아 볼 수 있죠.
그렇다면 왜 C언어로 작성을 해야 속도가 빠른 것일까요?
SIMD (Single Instruction Multi Data)
SIMD란 병렬 컴퓨팅의 한 종류로, 하나의 명령어로 여러 개의 값을 동시에 계산하는 방식입니다. (wiki 참조) 이렇게만 설명하면 감이 잘 안오실 수도 있습니다.
그럼 SISD (Single Instruction Single Data)와 비교하여 한 번 SIMD를 이해해볼까요? 전산에서 한 프로세서가 한번에 하나의 명령어를 처리할 때 하나의 메모리에 저장되어 있는 한 데이터를 이용하여 처리하는 것을 일컫는 것을 의미합니다. (wiki 참조)
SISD는 다음과 같이 A0+B0, A1+B1, …, A3+B3 연산을 수행하기 위해서 총 4번의 연산 과정이 필요합니다. 그러나 SIMD는 1번의 연산만으로 4번의 연산을 수행할 수 있습니다. 이것만 봐도 당연히 기존 SISD보다 SIMD로 구현하는 것이 더 성능도 효율적이며 특히 벡터/행렬 연산이 필요한 데이터 구조에 더욱 적합하다는 것은 느낌이 오겠죠?
그럼 SIMD는 SISD와 다르게 어떻게 한 번에 여러 연산을 할 수 있을까요? 그냥 누구나 SIMD로 동작하게 할 수 있는 것일까요?
가장 중요한 것은 연산을 담당하는 ALU가 여러 연산을 한 번에 계산 할 수도 있도록 해주어야 한다는 것입니다. 이를 위해 CPU는 레지스터를 쪼개서 여러 값을 넣어 사용합니다. 그리고 이러한 SIMD 기법은 C/C++ 언어의 SIMD Intrinsic를 사용하여 구현해주어야 합니다.
그렇다면 파이썬으로는 왜 SIMD를 구현할 수 없을까요?
C언어와 Python 리스트 구조
우선 파이썬 리스트의 특징에 대해 살펴보도록 하겠습니다. 파이썬 언어의 가장 큰 특징은 동적 타입 언어라는 것입니다. 따라서 파이썬 리스트에는 동일한 타입의 데이터만 넣을 필요도 없습니다. int를 넣었다가, float를 넣었다가, string을 넣었다가, 마음대로 할 수 있습니다. 어떻게 파이썬 리스트는 동적으로 할당이 가능한 것일까요? 파이썬 리스트 구조를 함께 살펴보도록 합시다.
파이썬 리스트 구조는 이중 포인터 형식으로 되어있습니다. 값이 바로 들어있는 것이 아니라 ob_item에 각 데이터가 들어있는 주소 값을 저장해두고, 그 주소를 따라가야 비로소 실제 데이터가 들어있는 것이죠. 따라서 여러가지 데이터 타입을 하나의 리스트 안에 넣을 수가 있습니다.
아래와 같이 리스트의 메모리 size를 확인해보면 int를 넣든, string을 넣든 사이즈가 동일한 이유도 실제 값이 아니라 데이터가 들어있는 주소를 저장하고 있기 때문입니다.
1
2
3
4
5
6
7
import sys
listA = [1, 2, 3, 4]
print(sys.getsizeof(listA)) # 120
listB = ["가", "나", "다", "라"]
print(sys.getsizeof(listB)) # 120
또한 주목해서 보아야할 점은 데이터 객체가 각기 다른 곳에 흩어져있으므로 주소가 연속적으로 배치되지 않을 수 있다는 점입니다.
그렇다면 numpy array의 구조는 어떻게 다를까요? numpy는 단일 포인터로 바로 데이터 값이 저장되어있다는 것, 그리고 주소가 파이썬 리스트와 달리 연속으로 할당되어있다는 것을 확인할 수 있습니다.
SIMD가 레지스터를 쪼개서 여러 개의 값을 한 번에 병렬로 계산하기 위해서는 데이터가 메모리 상에 정렬이 되어 있어야 합니다. 그러나 파이썬은 데이터가 메모리 상에 정렬되어있음을 보장할 수 없고, 또한 동일한 데이터 타입만으로 구성이 되어있지 않죠. 따라서 파이썬으로는 SIMD 구현이 불가능한 것입니다.
Numpy Array가 빠른 추가적인 요인
마지막으로 numpy array가 python list보다 빠른 이유는 바로 캐시 hit ratio 때문입니다. 앞에서 말했듯이 파이썬 리스트의 데이터들은 각자 다른 곳에 떨어져 있을 수 있습니다. 따라서 numpy array와 비교했을 때 파이썬 리스트는 캐시 미스가 더 높아져 속도가 느리다고 합니다.
참고 자료
[Numpy가 빠른 이유] https://devocean.sk.com/blog/techBoardDetail.do?ID=163631
[SIMD] https://m.blog.naver.com/fs0608/221650925743 https://blog.naver.com/PostView.naver?blogId=sorkelf&logNo=221126168094&parentCategoryNo=&categoryNo=3&viewDate=&isShowPopularPosts=true&from=search