- 필자는 NumPy에 대한 불만을 주제로 여러 예시와 함께 문제점을 설명함
- 간단한 배열 연산은 NumPy로 쉽지만, 차원이 늘어나면 복잡성과 혼란이 급격히 증가함
-
브로드캐스팅과 고급 인덱싱 등 NumPy의 설계는 명확성과 추상화 측면에서 부족함
- 명시적으로 축을 지정하는 대신 추측과 시행착오에 의존하는 코드 작성이 필수임
- 개선된 배열 언어에 대한 아이디어를 제시하며 구체적인 대안을 다음 글에서 소개할 예정임
서론: NumPy에 대한 애증
- 필자는 오랜 기간 NumPy을 사용해왔지만, 그 한계에 많이 실망했음을 밝힘
- NumPy는 파이썬에서 배열 연산을 위한 필수적이고 영향력 있는 라이브러리임
- PyTorch 등의 현대 머신러닝 라이브러리에도 NumPy와 유사한 문제들이 존재함
NumPy의 쉬운 점과 어려운 점
- 기본적인 선형 방정식 풀이와 같은 간단한 연산은 명확하고 우아한 문법으로 가능함
- 그러나 배열 차원이 높아지거나 연산이 복잡해지면, for 루프 없이 일괄 처리가 필요해짐
- 루프를 쓰지 못하는 환경(GPU 연산 등)에서는 특이한 벡터화 문법이나 특별한 함수 호출 방식이 필요함
- 하지만 이러한 함수들의 정확한 사용법이 모호하고 문서만으로도 명확하게 알기 어려움
- 실제로 numpy의 linalg.solve 함수는 고차원 배열인 경우 어떻게 써야 올바른지 누구도 확신하기 힘듦
NumPy의 문제점
- NumPy는 다차원 배열의 일부 또는 특정 축에 연산을 적용하는 데 일관된 이론이 부족함
- 배열 차원이 2 이하일 때는 명확하지만, 3차원 이상에서는 각 배열마다 연산 대상 축의 지정이 불분명함
- 명시적으로 차원을 맞추기 위해 None 사용, 브로드캐스팅, np.tensordot 등 복잡한 방법을 강제함
- 이러한 방식은 실수 유발, 코드 가독성 저하, 버그의 가능성 증가를 초래함
반복문과 명확성
- 실제로 반복문을 허용한다면 더욱 간결하고 명확한 코드 작성이 가능함
- 반복문 코드가 덜 세련돼 보일 수 있으나, 명확성 측면에서는 큰 장점이 있음
- 반면, 배열 차원이 바뀌면 transpose나 축 순서를 일일이 고민해야 하고, 복잡성이 증가함
np.einsum: 예외적으로 좋은 함수
-
np.einsum은 축의 이름을 지정할 수 있는 유연한 도메인 특화 언어를 제공하여 강력함
- einsum은 연산의 의도가 명확하고 일반화도 뛰어나, 복잡한 축 연산을 명시적으로 구현 가능함
- 하지만 einsum과 유사한 방식의 연산 지원이 일부 연산에 한정되고, 예를 들어 linalg.solve에는 못 씀
브로드캐스팅의 문제점
- NumPy의 핵심 트릭인 브로드캐스팅은 차원이 안 맞을 때 자동으로 맞춰주는 기능임
- 간단한 경우에는 편리하지만, 실제로는 차원을 명확하게 알기 어렵게 만들고, 오류 사례가 많음
- 브로드캐스팅이 암묵적이라 코드를 읽을 때 매번 연산이 어떻게 작동하는지 확인해야 함
인덱싱의 불명확함
- NumPy의 고급 인덱싱은 배열 shape 예측이 매우 어렵고 불명확함
- 다양한 인덱싱 조합에 따라 결과 배열의 shape가 달라지므로, 실제로 다뤄본 경험 없이는 예측이 곤란함
- 인덱싱 규칙 설명 문서도 길고 복잡하여, 익히는 데 큰 시간 소모를 유발함
- 단순 인덱싱만 쓰려고 해도 특정 연산에서는 어쩔 수 없이 고급 인덱싱을 사용하게 됨
NumPy 함수 설계의 한계
- 많은 NumPy 함수들은 특정 배열 shape에만 최적화되어 있음
- 고차원 배열에는 추가적인 axes 인자, 별도 함수명, 관례를 사용해야 하고, 함수마다 일관성이 없음
- 추상화와 재사용이 기본인 프로그래밍 원칙에 역행하는 구조임
- 특정 문제를 해결하는 함수를 써도, 다양한 배열과 축에 재적용하려면 아예 다른 코드로 다시 작성해야 함
실제 예시: self-attention 구현
- self-attention 구현을 NumPy로 작성할 때, 반복문을 쓰면 명확하나, 벡터화를 강제하면 코드가 복잡해짐
- 다중 헤드 attention과 같이 고차원 연산이 필요할 때, einsum과 축 변환을 복합적으로 써야 하고 코드가 난해해짐
결론 및 대안
- 필자는 NumPy가 "다른 배열 언어들보다 나쁜 점이 많지만 그만큼 시장에서 중요해진 유일한 선택지"임을 밝힘
- NumPy의 여러 문제점(브로드캐스팅, 인덱싱 불명확성, 함수의 비일관성 등)을 극복하기 위해 개선된 배열 언어의 프로토타입을 만들었음을 예고함
- 구체적인 개선안(새로운 배열 언어 API)은 추후 별도의 글에서 소개할 계획임