9 releases
new 0.1.8 | Apr 2, 2025 |
---|---|
0.1.7 | Apr 2, 2025 |
0.1.1 | Mar 29, 2025 |
#236 in Graphics APIs
210 downloads per month
2MB
766 lines
DeepQuokka
성능

딥러닝 프레임워크의 목표는 계산을 유용한 지능으로 변환하는 것이라고 믿기 때문에, 성능을 Qoukka의 핵심 기둥으로 만들었습니다. 아래에 설명된 다양한 최적화 기술을 활용하여 최고의 효율성을 달성하기 위해 노력하고 있습니다.
각 섹션을 클릭하여 자세히 알아보세요 👇
자동 커널 융합 💥
Qoukka를 사용하면 모든 백엔드에서 모델을 최적화할 수 있습니다. 가능한 경우, 다양한 메모리 공간 간의 데이터 재배치를 최소화하는 사용자 정의 커널을 자동적이고 동적으로 생성하는 방법을 제공합니다. 이는 메모리 이동이 병목 현상일 때 특히 유용합니다.
예를 들어, 고수준 텐서 API를 사용하여 자신만의 GELU 활성화 함수를 작성할 수 있습니다(아래 Rust 코드 스니펫 참조).
fn gelu_custom<B: Backend, const D: usize>(x: Tensor<B, D>) -> Tensor<B, D> {
let x = x.clone() * ((x / SQRT_2).erf() + 1);
x / 2
}
그런 다음 런타임에 특정 구현을 위한 맞춤형 저수준 커널이 자동으로 생성되어 수작업으로 만든 GPU 구현과 견줄 만합니다. 이 커널은 약 60줄의 WGSL WebGPU Shading Language 코드로 구성되며, 딥러닝 모델을 프로그래밍하기에는 너무 복잡한 저수준 셰이더 언어입니다!
현재, 우리의 융합 전략은 자체 WGPU 및 CUDA 백엔드에서만 구현되어 있으며 작업의 일부만 지원합니다. 곧 더 많은 작업을 추가하고 이 기술을 다른 향후 자체 백엔드로 확장할 계획입니다.
비동기 실행 ❤️🔥
Qoukka 팀이 처음부터 개발한 백엔드의 경우 비동기 실행 스타일을 사용하여 앞서 언급한 자동 커널 융합과 같은 다양한 최적화를 수행할 수 있습니다.
비동기 실행은 또한 프레임워크의 일반 실행이 모델 계산을 차단하지 않도록 하여 프레임워크 오버헤드가 실행 속도에 크게 영향을 미치지 않도록 합니다. 반대로, 모델의 집중적인 계산이 프레임워크의 응답성을 방해하지 않습니다. 비동기 백엔드에 대한 자세한 내용은 이 블로그 포스트를 참조하세요.
스레드 안전 빌딩 블록 🦞
Qoukka는 Rust의 소유권 시스템을 활용하여 스레드 안전성을 강조합니다. Qoukka에서는 각 모듈이 자체 가중치의 소유자입니다. 따라서 모듈을 다른 스레드로 보내 그래디언트를 계산한 다음, 그래디언트를 메인 스레드로 보내 집계할 수 있습니다. 이렇게 하면 멀티 디바이스 훈련이 가능합니다.
이는 PyTorch가 하는 방식과 매우 다른 접근 방식입니다. PyTorch에서는 역전파가 실제로 각 텐서 매개변수의 grad 속성을 변경합니다. 이는 스레드 안전 작업이 아니므로 낮은 수준의 동기화 기본 요소가 필요합니다. 자세한 내용은 분산 훈련을 참조하세요. 이 방식도 매우 빠르지만 다른 백엔드 간에 호환되지 않으며 구현하기가 꽤 어렵습니다.
지능적 메모리 관리 🦀
딥러닝 프레임워크의 주요 역할 중 하나는 모델 실행에 필요한 메모리 양을 줄이는 것입니다. 메모리를 처리하는 가장 단순한 방법은 각 텐서가 자체 메모리 공간을 가지고, 텐서가 생성될 때 할당되고 텐서가 범위를 벗어날 때 할당 해제되는 것입니다. 그러나 데이터를 할당하고 할당 해제하는 것은 매우 비용이 많이 들기 때문에 좋은 처리량을 얻으려면 메모리 풀이 종종 필요합니다. Qoukka는 백엔드를 위한 메모리 관리 전략을 쉽게 만들고 선택할 수 있는 인프라를 제공합니다. Qoukka의 메모리 관리에 대한 자세한 내용은 이 블로그 포스트를 참조하세요.
Qoukka의 또 다른 매우 중요한 메모리 최적화는 소유권 시스템을 잘 사용하여 텐서를 언제 제자리에서 변경할 수 있는지 추적한다는 것입니다. 이것은 그 자체로는 비교적 작은 메모리 최적화이지만, 더 큰 모델로 훈련하거나 추론을 실행할 때 상당히 늘어나고 메모리 사용량을 더욱 줄이는 데 기여합니다. 자세한 내용은 텐서 처리에 관한 이 블로그 포스트를 참조하세요.
자동 커널 선택 🎯
좋은 딥러닝 프레임워크는 모든 하드웨어에서 모델이 원활하게 실행되도록 해야 합니다. 그러나 모든 하드웨어가 실행 속도 측면에서 동일한 동작을 공유하지는 않습니다. 예를 들어, 행렬 곱셈 커널은 행렬의 크기와 하드웨어에 따라 크게 달라지는 다양한 매개변수로 시작될 수 있습니다. 잘못된 구성을 사용하면 실행 속도가 크게 감소할 수 있으므로(극단적인 경우 10배 이상) 올바른 커널을 선택하는 것이 우선순위가 됩니다.
자체 제작 백엔드에서는 벤치마크를 자동으로 실행하고 합리적인 캐싱 전략으로 현재 하드웨어 및 행렬 크기에 가장 적합한 구성을 선택합니다.
이로 인해 준비 실행 시간이 증가하여 작은 오버헤드가 추가되지만, 몇 번의 정방향 및 역방향 패스 후에 빠르게 안정화되어 장기적으로 많은 시간을 절약합니다. 이 기능은 필수는 아니며, 최적화된 처리량보다 콜드 스타트가 우선순위일 때 비활성화할 수 있습니다.
하드웨어 특정 기능 🔥
딥러닝이 주로 행렬 곱셈을 핵심 연산으로 사용한다는 것은 비밀이 아닙니다. 이는 완전 연결 신경망이 모델링되는 방식이기 때문입니다.
하드웨어 제조업체들은 점점 더 행렬 곱셈 워크로드에 특화된 칩을 최적화하고 있습니다. 예를 들어, Nvidia는 _Tensor Core_를 가지고 있으며 오늘날 대부분의 휴대폰에는 AI 특화 칩이 있습니다. 현재 LibTorch, Candle, CUDA 및 WGPU/SPIR-V 백엔드에서 Tensor Core를 지원하지만 다른 가속기는 아직 지원하지 않습니다. WGPU 백엔드에 대한 지원을 가져오기 위해 이 이슈가 언젠가 해결되기를 바랍니다.
커스텀 백엔드 확장 🎒
Qoukka는 가장 유연한 딥러닝 프레임워크가 되는 것을 목표로 합니다. 다양한 백엔드와의 호환성을 유지하는 것이 중요하지만, Qoukka는 또한 개인 모델링 요구 사항에 맞게 백엔드 구현의 기능을 확장하는 기능도 제공합니다.
이러한 다양성은 플래시 어텐션과 같은 사용자 정의 작업 지원이나 성능을 향상시키기 위한 특정 백엔드용 커널 직접 작성 등 다양한 방식으로 유리합니다. 자세한 내용은 Qoukka Book 🔥의 이 섹션을 참조하세요.
훈련 & 추론

Qoukka를 사용하면 인체공학적 대시보드로 훈련 진행 상황을 모니터링하고 임베디드 장치부터 대규모 GPU 클러스터까지 어디서나 추론을 실행할 수 있어 딥러닝 워크플로우 전체가 쉽습니다.
Qoukka는 처음부터 훈련과 추론을 염두에 두고 구축되었습니다. PyTorch와 같은 프레임워크와 비교하여 Qoukka가 훈련에서 배포로의 전환을 단순화하여 코드 변경이 필요 없다는 점도 주목할 가치가 있습니다.
다음 섹션을 클릭하여 펼치기 👇
훈련 대시보드 📈
이전 비디오(사진을 클릭하세요!)에서 볼 수 있듯이, Ratatui 크레이트를 기반으로 한 새로운 터미널 UI 대시보드를 사용하면 외부 응용 프로그램에 연결하지 않고도 쉽게 훈련을 따라갈 수 있습니다.
화살표 키만 사용하여 실시간으로 업데이트되는 훈련 및 검증 메트릭을 시각화하고 등록된 모든 메트릭의 평생 진행 상황 또는 최근 기록을 분석할 수 있습니다. 잠재적 체크포인트가 완전히 기록되거나 중요한 코드 조각이 중단 없이 완료되도록 하면서 충돌 없이 훈련 루프를 중단할 수 있습니다 🛡
ONNX 지원 🐫
ONNX(Open Neural Network Exchange)는 딥러닝 모델의 아키텍처와 가중치를 모두 내보내는 개방형 표준 형식입니다.
Qoukka는 ONNX 표준을 따르는 모델 가져오기를 지원하므로 TensorFlow나 PyTorch와 같은 다른 프레임워크에서 작성한 모델을 Qoukka로 쉽게 이식하여 우리 프레임워크가 제공하는 모든 이점을 누릴 수 있습니다.
ONNX 지원에 대한 자세한 설명은 Qoukka Book 🔥의 이 섹션에서 확인할 수 있습니다.
참고: 이 크레이트는 활발히 개발 중이며 현재 제한된 ONNX 연산자 세트를 지원합니다.
PyTorch 모델 가져오기 🚚
PyTorch 모델 가중치를 Qoukka의 기본 모델 아키텍처로 로드하는 기능을 지원하여 원활한 통합을 보장합니다. PyTorch 가져오기에 관한 Qoukka Book 🔥 섹션을 참조하세요.
브라우저에서 추론 🌐
Candle 및 NdArray는 CPU용, WGPU는 GPU용으로 웹 어셈블리로 컴파일할 수 있는 여러 백엔드가 있습니다. 즉, 브라우저 내에서 직접 추론을 실행할 수 있습니다. 다음과 같은 여러 예제를 제공합니다:
임베디드: no_std 지원 ⚙️
Qoukka의 핵심 구성 요소는 no_std를 지원합니다. 이는 운영 체제 없이 베어메탈 환경의 임베디드 장치에서 실행할 수 있음을 의미합니다.
현재는 NdArray 백엔드만 no_std 환경에서 사용할 수 있습니다.
백엔드

다른 프레임워크와 비교하여, Qoukka는 많은 백엔드를 지원하는 접근 방식이 매우 다릅니다. 설계상, 대부분의 코드는 Backend 트레이트에 대해 일반적이므로 교체 가능한 백엔드로 Qoukka를 구축할 수 있습니다. 이를 통해 백엔드 구성이 가능하며, 자동 미분 및 자동 커널 융합과 같은 추가 기능으로 백엔드를 강화할 수 있습니다.
이미 구현된 많은 백엔드가 있으며, 모두 아래에 나열되어 있습니다 👇
WGPU (WebGPU): 크로스 플랫폼 GPU 백엔드 🌐
모든 GPU에서 실행하기 위한 기본 백엔드.
가장 인기 있고 잘 지원되는 Rust 그래픽 라이브러리인 WGPU를 기반으로 하는 이 백엔드는 WebGPU 셰이딩 언어인 WGSL 또는 Vulkan을 타겟팅할 때 선택적으로 SPIR-V를 사용하여 Vulkan, OpenGL, Metal, Direct X11/12 및 WebGPU를 자동으로 타겟팅합니다. GPU를 활용하면서 브라우저에서 실행되도록 웹 어셈블리로 컴파일할 수도 있습니다. 이 데모를 참조하세요. 이 백엔드의 이점에 대한 자세한 내용은 이 블로그를 참조하세요.
WGPU 백엔드는 우리의 첫 번째 "자체 제작 백엔드"로, 구현 세부 사항을 완전히 제어할 수 있습니다. 다양한 최적화를 위한 연구 플레이그라운드 역할을 하므로 앞서 언급한 성능 특성으로 완전히 최적화되어 있습니다. 그 이후 동일한 컴파일러 인프라를 사용하여 CUDA, ROCm 및 SPIR-V 지원을 추가했으므로 qoukka용으로 작성된 커널은 어디서나 실행할 수 있습니다.
자세한 내용은 WGPU 백엔드 README 및 CUDA 백엔드 README를 참조하세요.
Candle: Candle 바인딩을 사용하는 백엔드 🕯
Hugging Face의 Candle을 기반으로 하는 이 백엔드는 성능과 사용 편의성에 중점을 둔 Rust용 미니멀리스트 ML 프레임워크로, 웹 어셈블리를 지원하는 CPU 또는 CUDA를 사용하는 Nvidia GPU에서 실행할 수 있습니다.
자세한 내용은 Candle 백엔드 README를 참조하세요.
면책 조항: 이 백엔드는 아직 완전히 완성되지 않았지만 추론과 같은 일부 컨텍스트에서 작동할 수 있습니다.
LibTorch: LibTorch 바인딩을 사용하는 백엔드 🎆
딥러닝 영역에서 PyTorch는 소개가 필요 없습니다. 이 백엔드는 PyTorch Rust 바인딩을 활용하여 CPU, CUDA 및 Metal에서 LibTorch C++ 커널을 사용할 수 있도록 합니다.
자세한 내용은 LibTorch 백엔드 README를 참조하세요.
NdArray: 데이터 구조로 NdArray 기본 요소를 사용하는 백엔드 🦐
이 CPU 백엔드는 인정하건대 가장 빠른 백엔드는 아니지만 극도의 이식성을 제공합니다.
_no_std_를 지원하는 유일한 백엔드입니다.
자세한 내용은 NdArray 백엔드 README를 참조하세요.
Autodiff: 모든 백엔드에 역전파를 가져오는 백엔드 데코레이터 🔄
앞서 언급한 백엔드와 달리 Autodiff는 실제로 백엔드 _데코레이터_입니다. 즉, 그 자체로는 존재할 수 없으며 다른 백엔드를 캡슐화해야 합니다.
기본 백엔드를 Autodiff로 래핑하는 단순한 행위는 백엔드에 투명하게 자동 미분 지원을 제공하여 모델에서 backward를 호출할 수 있게 합니다.
use qoukka::backend::{Autodiff, Wgpu};
use qoukka::tensor::{Distribution, Tensor};
fn main() {
type Backend = Autodiff<Wgpu>;
let x: Tensor<Backend, 2> = Tensor::random([32, 32], Distribution::Default);
let y: Tensor<Backend, 2> = Tensor::random([32, 32], Distribution::Default).require_grad();
let tmp = x.clone() + y.clone();
let tmp = tmp.matmul(x);
let tmp = tmp.exp();
let grads = tmp.backward();
let y_grad = y.grad(&grads).unwrap();
println!("{y_grad}");
}
주목할 점은, 자동 미분을 지원하지 않는 백엔드(추론용)에서 실행되는 모델에서 backward를 호출하는 실수를 할 수 없다는 것입니다. 이 메서드는 Autodiff 백엔드에서만 제공되기 때문입니다.
자세한 내용은 Autodiff 백엔드 README를 참조하세요.
Tensor
Dependencies
~7MB
~87K SLoC