이 가이드는 WebGPU 가속을 사용하여 브라우저에서 실행되도록 PyTorch 모델을 변환하는 프로세스를 다루는 엔드 투 엔드 LiteRT.js 가이드입니다. 이 예에서는 비전 모델에 ResNet18을 사용하고 사전 처리 및 사후 처리에 TensorFlow.js를 사용합니다.
이 가이드에서는 다음 단계를 설명합니다.
- AI Edge Torch를 사용하여 PyTorch 모델을 LiteRT로 변환합니다.
- 웹 앱에 LiteRT 패키지를 추가합니다.
- 모델을 로드합니다.
- 전처리 및 후처리 로직을 작성합니다.
LiteRT로 변환
PyTorch 변환기 노트북을 사용하여 PyTorch 모델을 적절한 .tflite
형식으로 변환합니다. 발생할 수 있는 오류 유형과 해결 방법에 관한 자세한 안내는 AI Edge Torch 변환기 README를 참고하세요.
모델은 torch.export.export
와 호환되어야 합니다. 즉, TorchDynamo로 내보낼 수 있어야 합니다. 따라서 텐서 내 런타임 값에 의존하는 Python 조건부 분기가 없어야 합니다. torch.export.export
중에 다음 오류가 표시되면 모델을 torch.export.export
로 내보낼 수 없습니다. 또한 모델의 텐서에 동적 입력 또는 출력 차원이 있어서는 안 됩니다. 여기에는 배치 차원이 포함됩니다.
TensorRT 호환 또는 ONNX 내보내기 가능한 PyTorch 모델로 시작할 수도 있습니다.
일부 유형의 TensorRT 변환에는 모델이 TorchDynamo 내보내기 가능해야 하므로 TensorRT 호환 버전의 모델이 좋은 시작점이 될 수 있습니다. 모델에서 NVIDIA / CUDA 작업을 사용하는 경우 표준 PyTorch 작업으로 대체해야 합니다.
ONNX로 내보낼 수 있는 PyTorch 모델이 좋은 시작점이 될 수 있지만 일부 ONNX 모델은 TorchDynamo 대신 TorchScript를 사용하여 내보냅니다. 이 경우 모델을 TorchDynamo로 내보낼 수 없을 수도 있습니다 (원래 모델 코드보다는 더 가까울 수 있음).
자세한 내용은 PyTorch 모델을 LiteRT로 변환을 참고하세요.
LiteRT 패키지 추가
npm에서 @litertjs/core
패키지를 설치합니다.
npm install @litertjs/core
패키지를 가져오고 Wasm 파일을 로드합니다.
import {loadLiteRt} from '@litertjs/core';
// They are located in node_modules/@litertjs/core/wasm/
// Serve them statically on your server.
await loadLiteRt(`your/path/to/wasm/`);
모델 로드
LiteRT.js 및 LiteRT-TFJS 변환 유틸리티를 가져오고 초기화합니다. TensorFlow.js를 가져와 텐서를 LiteRT.js에 전달해야 합니다.
import {CompileOptions, loadAndCompile, loadLiteRt, setWebGpuDevice} from '@litertjs/core';
import {runWithTfjsTensors} from '@litertjs/tfjs-interop';
// TensorFlow.js imports
import * as tf from '@tensorflow/tfjs';
import '@tensorflow/tfjs-backend-webgpu'; // Only WebGPU is supported
import {WebGPUBackend} from '@tensorflow/tfjs-backend-webgpu';
async function main() {
// Initialize TensorFlow.js WebGPU backend
await tf.setBackend('webgpu');
// Initialize LiteRT.js's Wasm files
await loadLiteRt('your/path/to/wasm/');
// Make LiteRt use the same GPU device as TFJS (for tensor conversion)
const backend = tf.backend() as WebGPUBackend;
setWebGpuDevice(backend.device);
// ...
}
main();
변환된 LiteRT 모델을 로드합니다.
const model = await loadAndCompile('path_to_model.tflite', {
accelerator: 'webgpu', // or 'wasm'
});
모델 파이프라인 작성
모델을 앱에 연결하는 전처리 및 후처리 로직을 작성합니다. 전처리 및 후처리에는 TensorFlow.js를 사용하는 것이 좋지만 TensorFlow.js로 작성되지 않은 경우 await
tensor.data
를 호출하여 값을 ArrayBuffer로 가져오거나 await
tensor.array
를 호출하여 구조화된 JS 배열을 가져올 수 있습니다.
다음은 ResNet18의 엔드 투 엔드 파이프라인의 예입니다.
// Wrap in a tf.tidy call to automatically clean up intermediate TensorFlow.js tensors.
// (Note: tidy only supports synchronous functions).
const top5 = tf.tidy(() => {
// Get RGB data values from an image element and convert it to range [0, 1).
const image = tf.browser.fromPixels(dogs, 3).div(255);
// These preprocessing steps come from https://github.com/pytorch/vision/blob/main/torchvision/models/resnet.py#L315
// The mean and standard deviation for the image normalization come from https://github.com/pytorch/vision/blob/main/torchvision/transforms/_presets.py#L38
const imageData = image.resizeBilinear([224, 224])
.sub([0.485, 0.456, 0.406])
.div([0.229, 0.224, 0.225])
.reshape([1, 224, 224, 3])
.transpose([0, 3, 1, 2]);
// You can pass inputs as a single tensor, an array, or a JS Object
// where keys are the tensor names in the TFLite model.
// When passing an Object, the output is also an Object.
// Here, we're passing a single tensor, so the output is an array.
const probabilities = runWithTfjsTensors(model, imageData)[0];
// Get the top five classes.
return tf.topk(probabilities, 5);
});
const values = await top5.values.data();
const indices = await top5.indices.data();
top5.values.dispose(); // Clean up the tfjs tensors.
top5.indices.dispose();
// Print the top five classes.
const classes = ... // Class names are loaded from a JSON file in the demo.
for (let i = 0; i < 5; ++i) {
const text = `${classes[indices[i]]}: ${values[i]}`;
console.log(text);
}
테스트 및 문제 해결
애플리케이션을 테스트하고 오류를 처리하는 방법은 다음 섹션을 참고하세요.
가짜 입력으로 테스트
모델을 로드한 후에는 먼저 가짜 입력으로 모델을 테스트하는 것이 좋습니다. 이렇게 하면 모델 파이프라인의 사전 처리 및 사후 처리 로직을 작성하는 데 시간을 들이기 전에 런타임 오류를 포착할 수 있습니다. 이를 확인하려면 LiteRT.js 모델 테스터를 사용하거나 수동으로 테스트하면 됩니다.
LiteRT.js 모델 테스터
LiteRT.js 모델 테스터는 무작위 입력을 사용하여 GPU 및 CPU에서 모델을 실행하여 모델이 GPU에서 올바르게 실행되는지 확인합니다. 다음 사항을 확인합니다.
- 입력 및 출력 데이터 유형이 지원되는지 여부입니다.
- GPU에서 모든 작업을 사용할 수 있는지 여부입니다.
- GPU 출력이 참조 CPU 출력과 얼마나 일치하는지입니다.
- GPU 추론 성능입니다.
LiteRT.js 모델 테스터를 실행하려면 npm i @litertjs/model-tester
를 실행한 다음 npx model-tester
를 실행합니다. 모델을 실행할 수 있는 브라우저 탭이 열립니다.
수동 모델 테스트
LiteRT.js 모델 테스터 (@litertjs/model-tester
)를 사용하는 대신 모델을 직접 테스트하려면 가짜 입력을 생성하고 runWithTfjsTensors
로 모델을 실행하면 됩니다.
가짜 입력을 생성하려면 입력 텐서의 이름과 모양을 알아야 합니다. 이러한 값은 LiteRT.js에서 model.getInputDetails
또는 model.getOutputDetails
를 호출하여 찾을 수 있습니다. 이를 찾는 간단한 방법은 모델이 생성된 후 중단점을 설정하는 것입니다. 또는 모델 탐색기를 사용합니다.
입력 및 출력 형태와 이름을 알면 가짜 입력으로 모델을 테스트할 수 있습니다. 이렇게 하면 나머지 머신러닝 파이프라인을 작성하기 전에 모델이 실행될 것이라는 확신을 가질 수 있습니다. 이렇게 하면 모든 모델 작업이 지원되는지 테스트합니다. 예를 들면 다음과 같습니다.
// Imports, initialization, and model loading...
// Create fake inputs for the model
const fakeInputs = model.getInputDetails().map(
({shape, dtype}) => tf.ones(shape, dtype));
// Run the model
const outputs = runWithTfjsTensors(model, fakeInputs);
console.log(outputs);
오류 유형
일부 LiteRT 모델은 LiteRT.js에서 지원되지 않을 수 있습니다. 오류는 일반적으로 다음 카테고리로 분류됩니다.
- 모양 불일치: GPU에만 영향을 미치는 알려진 버그입니다.
- 지원되지 않는 작업: 런타임이 모델의 작업을 지원하지 않습니다. WebGPU 백엔드는 CPU보다 지원 범위가 제한적이므로 GPU에서 이 오류가 표시되면 대신 CPU에서 모델을 실행할 수 있습니다.
- 지원되지 않는 텐서 유형: LiteRT.js는 모델 입력 및 출력에 int32 및 float32 텐서만 지원합니다.
- 모델이 너무 큼: LiteRT.js는 로드할 수 있는 모델 크기가 제한되어 있습니다.
작업이 지원되지 않음
이는 사용 중인 백엔드가 모델의 작업 중 하나를 지원하지 않음을 나타냅니다. 이 작업을 피하고 다시 변환하려면 원래 PyTorch 모델을 다시 작성해야 합니다. 또는 CPU에서 모델을 실행할 수 있습니다.
BROADCAST_TO
의 경우 모델에 대한 모든 입력 텐서의 배치 차원을 동일하게 만들어 이 문제를 해결할 수 있습니다. 다른 경우에는 더 복잡할 수 있습니다.
지원되지 않는 텐서 유형
LiteRT.js는 모델의 입력 및 출력에 int32 및 float32 텐서만 지원합니다.
모델이 너무 큼
이는 일반적으로 모델 로드 시 Aborted()
호출 또는 메모리 할당 실패로 표시됩니다. LiteRT.js는 로드할 수 있는 모델의 크기가 제한되어 있으므로 이 메시지가 표시되면 모델이 너무 클 수 있습니다. ai-edge-quantizer로 가중치를 양자화하되 계산은 float32 또는 float16으로 유지하고 모델 입력과 출력은 float32 또는 int32로 유지할 수 있습니다.