Background
CreateML/CoreML이 나오면서 Apple 플랫폼에서 ML model과 관련된 학습과 이용이 가능해졌다. 이러한 ML 관련 API의 등장과 함께 내가 관심을 가지기 시작한 것이 있었으니..... Metal Perfomance Shader (이하, 'MPS')이다. MPS는 ML의 백엔드에서 이산형 부동소수점 데이터의 병렬 연산을 위해서 사용된다고 한다. 만약에.... 우리가 데이터의 연산 처리를 하는데, 고도의 연산 처리가 아니면서 각 데이터의 값이 서로 연관이 없을 때는 GPU의 병렬 연산 처리를 사용한다면 속도와 성능 개선에 큰 기여를 할 수 있을 것이다. 2016년부터 함수형 프로그래밍을 공부하면서, 극한의 병렬/비동기 연산에 대해서 어떻게 활용하고 적용할지에 대해서 고민을 많이 했다. 그리고 최근 프로젝트에서 이산형 데이터를 만나면 이를 활용하여 성능을 극한까지 끌여올리기 위해서 노력했다. 최근에 진행한 프로젝트 중에 오디오 관련 미디어 플레이어 프로젝트를 진행했는데, 여기서도 각 오디오 데이터의 디코딩/복호화/데이터 변환 등을 함수형 프로그래밍을 사용해서 병렬처리하도록 설계 및 구현을 진행했다. 하지만 CPU의 사용을 극한까지 끌여올려서 처리했을 뿐이다. 이를 GPU를 활용한다면 더욱 성능을 극한까지 활용할 수 있지 않을까 한다. 이미 진작에 MPS에 관심을 가지고 공부했지만, 시간이 나는 김에 이에 대해서 정리를 하려고 한다. CPU/GPU의 연산 처리 방식에 대해서 효율성이 궁금하신 분은 아래의 유명한 영상을 보면 이해가 빠를 것이다. 2020년 정도에 인공지능 조직에 몸 담고 있던 시절에 직장 선배님께서 공유해주셨던 영상이다.
https://youtube.com/shorts/CaIIjmYceSs?si=hq9lG8AimQ90MsJ3
Metal Perfomance Shader
주요 기능
- 이미지로부터 통계/히스토그램 데이터 추출
- 머신 러닝의 학습와 동작을 위한 Neural network 구축 및 사용
- 행렬 및 벡터 연산 지원
- 레이 트레이싱 가속화
주요 특징
- 고성능 GPU 연산 - Metal을 활용하여 빠른 병렬 연산 처리 지원
- 저전력 최적화 - Apple SoC 설계를 기반으로 전력 효율에 뛰어남
- 다양한 연산 지원 - 이미지 필터링, 블러, 행렬 곱셈, CNN, RNN, MLP (Multi-Layer Perception) 등의 고성능 연산 내장
사용 방법
Pipeline
[CPU] ---> [Metal Command Queue] ---> [GPU 실행: MPS 커널] ---> [결과 버퍼/텍스처]
In details
┌──────────────────────────────────────────────────┐
│ CPU │
│ Swift / Objective-C Code │
│ ├─ MTLDevice, MTLCommandQueue, MTLCommandBuffer │
│ ├─ MPS 커널 생성 및 encode() 호출 │
│ └─ commit() / waitUntilCompleted() │
└───────────────┬──────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────┐
│ GPU │
│ Metal Compute Pipeline │
│ ├─ Threadgroups → Threads │
│ ├─ MPSKernel (예: MPSMatrixMultiplication) │
│ ├─ Local / Global Memory Access │
│ ├─ SIMD Parallel Execution │
│ └─ 결과를 MTLBuffer/Texture에 저장 │
└──────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────┐
│ CPU │
│ 결과 읽기 / 후속 처리 (Core ML, Vision 등) │
└──────────────────────────────────────────────────┘- 'MPSSupportsMTLDevice(_:)'를 사용하여 현재 MPS 지원가능한 device인지를 확인
- MTLDevice, MTLCommandQueue, MTLCommandBuffer 등, Metal compute pipeline 구성을 위한 object를 생성
- 연산 목적에 따른 적절한 Kernal을 생성. Kernal은 멀티 스레딩을 지원하지 않기 때문에 멀티 스레딩을 지원한다면, 여분의 Kernal을 확보
- Kernal의 encoding method를 호출. command encoder를 생성하고, command buffer에 명령을 입력. command encoder가 종료되면 'endEncoding()'을 호출. 이 때, 추후 재사용 여부에 따라서 Kernal을 해제하거나 저장
- command buffer에 명령이 모두 입력되면, 'commit()'을 호출하여 GPU 동작을 시작
- 'waitUntilCompleted()' 혹은 'addCompletedHandler(_:)' 등을 사용하여 GPU의 작업이 완료되는 시점에 대한 동작 정의 가능
- 연산 결과를 CPU 혹은 후속 파이프라인으로 전달

Kernals
| 이미지 처리 | MPSImageGaussianBlur, MPSImageConvolution | 실시간 필터, AR 처리 |
| 비디오 | MPSImageHistogram, MPSImageMedian | 컬러 균형, 노이즈 제거 |
| 머신러닝 | MPSCNNConvolution, MPSCNNPooling, MPSMatrixMultiplication | Core ML 백엔드 |
| 수학 연산 | MPSVectorAddition, MPSUnaryKernel | 수학적 함수 계산 |
| 그래프 실행 | MPSGraph | 딥러닝 그래프 모델 실행 |
Code Example
import MetalPerformanceShaders
let device = MTLCreateSystemDefaultDevice()!
let commandQueue = device.makeCommandQueue()!
let commandBuffer = commandQueue.makeCommandBuffer()!
// 입력 텍스처 (예: 이미지를 Metal Texture로 변환)
let inputTexture: MTLTexture = ...
let outputTexture: MTLTexture = ...
// MPS 커널 생성
let gaussianBlur = MPSImageGaussianBlur(device: device, sigma: 10.0)
// GPU에 명령 인코딩
gaussianBlur.encode(commandBuffer: commandBuffer,
sourceTexture: inputTexture,
destinationTexture: outputTexture)
// 실행
commandBuffer.commit()
commandBuffer.waitUntilCompleted()
// outputTexture에 결과 이미지 저장됨'Programming > Mac & iOS' 카테고리의 다른 글
| [iOS] AVFoundation Foundation (0) | 2025.11.02 |
|---|---|
| [iOS] Core Video Foundation (0) | 2025.10.30 |
| [iOS] SwiftUI : View update에 대한 고찰 (0) | 2025.10.14 |
| [iOS] Swift Concurrency Foundation (0) | 2025.10.11 |
| [iOS] SwiftUI Foundation (0) | 2025.10.11 |