์ ๋ถ๋ ์๋์ง๋ง, ๋ชจ๋ฐ์ผ ๊ธฐ๊ธฐ์์์ ์ ํ๋ฆฌ์ผ์ด์ ๊ณผ ML ๋ชจ๋ธ ์ถ๋ก ์ฌ์ฉ ์ฌ๋ก์ ์ฑ๋ฅ(์ง์ฐ์๊ฐ)์ ๋งค์ฐ ์ค๋ํ ์ฌํญ์ ๋๋ค.
์ค๋๋ PyTorch๋ GPU, DSP, NPU์ ๊ฐ์ ํ๋์จ์ด ๋ฐฑ์๋๊ฐ ์ฌ์ฉ ๊ฐ๋ฅํ ๋๊น์ง CPU ๋ฐฑ์๋์์ ๋ชจ๋ธ์ ์คํํฉ๋๋ค.
์ด ๋ ์ํผ์์ ๋ฐฐ์ธ ๋ด์ฉ์:
- ๋ชจ๋ฐ์ผ ๊ธฐ๊ธฐ์์ ์คํ ์๊ฐ์ ์ค์ด๋๋ฐ ๋์์ด ๋ (์ฑ๋ฅ์ ๋์ด๊ณ , ์ง์ฐ์๊ฐ์ ์ค์ด๋) ๋ชจ๋ธ ์ต์ ํ ๋ฐฉ๋ฒ
- ๋ฒค์น๋งํน(์ต์ ํ๊ฐ ์ฌ์ฉ ์ฌ๋ก์ ๋์์ด ๋์๋์ง ํ์ธ) ํ๋ ๋ฐฉ๋ฒ
๋ชจ๋ฐ์ผ ๊ธฐ๊ธฐ์์ ์คํ ์๊ฐ์ ์ค์ด๋๋ฐ ๋์์ด ๋ (์ฑ๋ฅ์ ๋์ด๊ณ , ์ง์ฐ์๊ฐ์ ์ค์ด๋) ๋ชจ๋ธ์ ์ต์ ํ๋ฅผ ์ํ ์ค๋น๋ถํฐ ์์ํฉ๋๋ค.
์ฒซ๋ฒ์งธ๋ก ์ ์ด๋ ๋ฒ์ ์ด 1.5.0 ์ด์์ธ PyTorch๋ฅผ conda๋ pip์ผ๋ก ์ค์นํฉ๋๋ค.
conda install pytorch torchvision -c pytorch
๋๋
pip install torch torchvision
๋ชจ๋ธ ์ฝ๋:
import torch from torch.utils.mobile_optimizer import optimize_for_mobile class AnnotatedConvBnReLUModel(torch.nn.Module): def __init__(self): super(AnnotatedConvBnReLUModel, self).__init__() self.conv = torch.nn.Conv2d(3, 5, 3, bias=False).to(dtype=torch.float) self.bn = torch.nn.BatchNorm2d(5).to(dtype=torch.float) self.relu = torch.nn.ReLU(inplace=True) self.quant = torch.quantization.QuantStub() self.dequant = torch.quantization.DeQuantStub() def forward(self, x): x = x.contiguous(memory_format=torch.channels_last) x = self.quant(x) x = self.conv(x) x = self.bn(x) x = self.relu(x) x = self.dequant(x) return x model = AnnotatedConvBnReLUModel()
torch.quantization.QuantStub
์ torch.quantization.DeQuantStub()
์ ๋ฏธ์ฌ์ฉ ์คํ
(stub)์ด๋ฉฐ, ์์ํ(quantization) ๋จ๊ณ์ ์ฌ์ฉํฉ๋๋ค.
fuse_modules์ ์์ํ ํจํค์ง ๋ด๋ถ์ ์๋ค๋ ๊ฒ์ ํผ๋ํ์ง ๋ง์ญ์์ค.
fuse_modules์ ๋ชจ๋ torch.nn.Module
์์ ๋์ํฉ๋๋ค.
torch.quantization.fuse_modules
์ ๋ชจ๋๋ค์ ๋ฆฌ์คํธ๋ฅผ ํ๋์ ๋ชจ๋๋ก ๊ฒฐํฉํฉ๋๋ค.
์ด๊ฒ์ ์๋ ์์์ ๋ชจ๋๋ค๋ง ๊ฒฐํฉ์ํต๋๋ค:
- Convolution, Batch normalization
- Convolution, Batch normalization, Relu
- Convolution, Relu
- Linear, Relu
์ด ์คํฌ๋ฆฝํธ๋ ์ด์ ์ ์ ์ธ๋ ๋ชจ๋ธ์์ Convolution, Batch Normalization, Relu๋ฅผ ๊ฒฐํฉํฉ๋๋ค.
torch.quantization.fuse_modules(model, [['conv', 'bn', 'relu']], inplace=True)
PyTorch ์์ํ์ ๋ํ ๋ด์ฉ์ the dedicated tutorial ์์ ์ฐพ์ ์ ์์ต๋๋ค.
๋ชจ๋ธ์ ์์ํ๋ ์ฐ์ฐ์ int8๋ก ์ฎ๊ธฐ๋ฉด์ ๋์คํฌ์์ ๋ชจ๋ธ ํฌ๊ธฐ๋ฅผ ์ค์ด๊ธฐ๋ ํฉ๋๋ค. ์ด๋ฐ ํฌ๊ธฐ ๊ฐ์๋ ๋ชจ๋ธ์ ์ฒ์ ์ฝ์ด ๋ค์ผ ๋ ๋์คํฌ ์ฝ๊ธฐ ์ฐ์ฐ์ ์ค์ด๋๋ฐ ๋์์ ์ฃผ๊ณ ๋จ(RAM)์ ์ด๋๋ ์ค์ ๋๋ค. ์ด๋ฌํ ๋ ์์์ ๋ชจ๋ฐ์ผ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฑ๋ฅ์ ๋งค์ฐ ์ค์ํ ์ ์์ต๋๋ค. ์ด ์ฝ๋๋ ๋ชจ๋ธ ๋ณด์ (calibration) ํจ์๋ฅผ ์ํด ์คํ ์ ์ฌ์ฉํด์ ์์ํ๋ฅผ ํฉ๋๋ค. ์ฌ๊ธฐ ์์ ๊ด๋ จ๋ ์ฌํญ์ ์ฐพ์ ์ ์์ต๋๋ค.
model.qconfig = torch.quantization.get_default_qconfig('qnnpack') torch.quantization.prepare(model, inplace=True) # ๋ชจ๋ธ ๋ณด์ def calibrate(model, calibration_data): # ๋ชจ๋ธ ๋ณด์ ์ฝ๋ return calibrate(model, []) torch.quantization.convert(model, inplace=True)
Torch mobile_optimizer ํจํค์ง๋ ์คํฌ๋ฆฝํธ๋ ๋ชจ๋ธ์ ์ด์ฉํด์ ๋ช ๊ฐ์ง ์ต์ ํ๋ฅผ ์ํํ๊ณ , ์ด๋ฌํ ์ต์ ํ๋ conv2d์ ์ ํ ์ฐ์ฐ์ ๋์์ด ๋ฉ๋๋ค. ์ด ํจํค์ง๋ ์ต์ ํ๋ ํ์์ผ๋ก ๋ชจ๋ธ ๊ฐ์ค์น๋ฅผ ์ฐ์ ํจํค์งํ๋ฉฐ(pre-packs) ๋ค์ ์ฐ์ฐ์ด relu์ด๋ฉด ์์ ์ฐ์ฐ๋ค๊ณผ relu ์ฐ์ฐ์ ๊ฒฐํฉ ์ํต๋๋ค.
๋จผ์ ์ด์ ๋จ๊ณ์์๋ถํฐ ๊ฒฐ๊ณผ ๋ชจ๋ธ์ ์์ฑํฉ๋๋ค:
torchscript_model = torch.jit.script(model)
๋ค์์ optimize_for_mobile
์ ํธ์ถํ๊ณ ๋์คํฌ์ ๋ชจ๋ธ์ ์ ์ฅํฉ๋๋ค.
torchscript_model_optimized = optimize_for_mobile(torchscript_model) torch.jit.save(torchscript_model_optimized, "model.pt")
Channels Last(NHWC) ๋ฉ๋ชจ๋ฆฌ ํ์์ PyTorch 1.4.0์์ ๋์ ๋์์ต๋๋ค. ์ด ํ์์ ์ค์ง 4์ฐจ์ ํ ์๋ง์ ์ง์ํฉ๋๋ค. ์ด ๋ฉ๋ชจ๋ฆฌ ํ์์ ๋๋ถ๋ถ์ ์ฐ์ฐ์, ํนํ ํฉ์ฑ๊ณฑ ์ฐ์ฐ์ ๋ ๋์ ๋ฉ๋ชจ๋ฆฌ ์ง์ญ์ฑ์ ์ ๊ณตํฉ๋๋ค. ์ธก์ ๊ฒฐ๊ณผ๋ MobileNetV2 ๋ชจ๋ธ์์ ๊ธฐ๋ณธ Channels First(NCHW) ํ์์ ๋นํด 3๋ฐฐ์ ์๋ ํฅ์์ ๋ณด์ฌ ์ค๋๋ค.
์ด ๋ ์ํผ๋ฅผ ์์ฑํ๋ ์์ ์์๋, PyTorch Android ์๋ฐ API๋ Channels Last ๋ฉ๋ชจ๋ฆฌ ํ์์ผ๋ก ๋ ์ ๋ ฅ์ ์ง์ํ์ง ์์ต๋๋ค. ํ์ง๋ง ๋ชจ๋ธ ์ ๋ ฅ์ ์ํด ์ด ๋ฉ๋ชจ๋ฆฌ ํ์์ผ๋ก ๋ณํํ๋ฉด TorchScript ๋ชจ๋ธ ์์ค์์ ์ฌ์ฉ์ด ๊ฐ๋ฅํฉ๋๋ค.
def forward(self, x):
x = x.contiguous(memory_format=torch.channels_last)
...
์ด ๋ณํ์ ์ ๋ ฅ์ด Channels Last ๋ฉ๋ชจ๋ฆฌ ํ์์ด๋ฉด ๋น์ฉ์ด ๋ค์ง ์์ต๋๋ค. ๊ฒฐ๊ตญ์๋ ๋ชจ๋ ์ฐ์ฐ์๊ฐ Channels Last ๋ฉ๋ชจ๋ฆฌ ํ์์ ์ ์งํ๋ฉด์ ์์ ์ ํฉ๋๋ค.
๋ ์ํผ์์ ์ด ๋ถ๋ถ์ Android์๋ง ํด๋นํฉ๋๋ค.
๋ฉ๋ชจ๋ฆฌ๋ Android ์ฑ๋ฅ์ ๋งค์ฐ ์ค์ํ ์์์ ๋๋ค. ์ค๋๋ ๋๋ฐ์ด์ค์์ ํนํ๋ ๋ ์ค์ํฉ๋๋ค. ํ ์๋ ์๋นํ ์์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํ์๋ก ํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ํ์ค ์ปดํจํฐ ๋น์ ํ ์๋ 1*3*224*224๊ฐ์ ์์๋ฅผ ํฌํจํฉ๋๋ค. ๋ฐ์ดํฐ ํ์ ์ด float์ด๊ณ 588kb ๋ฉ๋ชจ๋ฆฌ๊ฐ ํ์ํ๋ค๊ณ ๊ฐ์ ํ ๊ฒฝ์ฐ์ ๋๋ค.
FloatBuffer buffer = Tensor.allocateFloatBuffer(1*3*224*224); Tensor tensor = Tensor.fromBlob(buffer, new long[]{1, 3, 224, 224});
์ฌ๊ธฐ์์ ๋ค์ดํฐ๋ธ ๋ฉ๋ชจ๋ฆฌ๋ฅผ java.nio.FloatBuffer
๋ก ํ ๋นํ๊ณ ์ ์ฅ์๊ฐ ํ ๋น๋ ๋ฒํผ์ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ๊ฐ๋ฆฌํฌ org.pytorch.Tensor
๋ฅผ ๋ง๋ญ๋๋ค.
๋๋ถ๋ถ์ ์ฌ์ฉ ์ฌ๋ก์์ ๋ชจ๋ธ ์๋ฐฉํฅ ์ ๋ฌ์ ๋จ ํ ๋ฒ๋ง ํ์ง ์๊ณ , ์ผ์ ํ ๋น๋๋ก ํน์ ๊ฐ๋ฅํ ํ ๋นจ๋ฆฌ ์งํํฉ๋๋ค.
๋ง์ฝ ๋ชจ๋ ๋ชจ๋ ์๋ฐฉํฅ ์ ๋ฌ์ ์ํด ๋ฉ๋ชจ๋ฆฌ ํ ๋น์ ์๋ก ํ๋ค๋ฉด - ๊ทธ๊ฑด ์ต์ ํ๊ฐ ์๋๋๋ค. ๋์ ์, ์ด์ ๋จ๊ณ์์ ํ ๋นํ ๋์ผํ ๋ฉ๋ชจ๋ฆฌ์ ์ ๋ฐ์ดํฐ๋ฅผ ์ฑ์ฐ๊ณ ๋ชจ๋ ์๋ฐฉํฅ ์ ๋ฌ์ ๋์ผํ ํ ์ ๊ฐ์ฒด์์ ๋ค์ ์คํํจ์ผ๋ก์จ ๋์ผํ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฌ์ฌ์ฉ ํ ์ ์์ต๋๋ค.
์ฝ๋๊ฐ ์ด๋ค ์์ผ๋ก ๊ตฌ์ฑ์ด ๋์ด ์๋์ง๋ pytorch android application example ์์ ํ์ธํ ์ ์์ต๋๋ค.
protected AnalysisResult analyzeImage(ImageProxy image, int rotationDegrees) { if (mModule == null) { mModule = Module.load(moduleFileAbsoluteFilePath); mInputTensorBuffer = Tensor.allocateFloatBuffer(3 * 224 * 224); mInputTensor = Tensor.fromBlob(mInputTensorBuffer, new long[]{1, 3, 224, 224}); } TensorImageUtils.imageYUV420CenterCropToFloatBuffer( image.getImage(), rotationDegrees, 224, 224, TensorImageUtils.TORCHVISION_NORM_MEAN_RGB, TensorImageUtils.TORCHVISION_NORM_STD_RGB, mInputTensorBuffer, 0); Tensor outputTensor = mModule.forward(IValue.from(mInputTensor)).toTensor(); }
๋ฉค๋ฒ ๋ณ์ mModule
, mInputTensorBuffer
, mInputTensor
๋ ๋จ ํ ๋ฒ ์ด๊ธฐํ๋ฅผ ํ๊ณ
๋ฒํผ๋ org.pytorch.torchvision.TensorImageUtils.imageYUV420CenterCropToFloatBuffer
๋ฅผ ์ด์ฉํด์ ๋ค์ ์ฑ์์ง๋๋ค.
PyTorch 1.13 ์ด์๋ถํฐ ์ฌ์ฉ ๊ฐ๋ฅ
ํ์ดํ ์น ๋ชจ๋ฐ์ผ์ ๋ก๋ฉ ์๋๊ฐ ๋ ๋น ๋ฅธ FlatBuffer(ํ๋ซ๋ฒํผ) ๊ธฐ๋ฐ ํ์ผ ํ์๋ ์ง์ํฉ๋๋ค.
FlatBuffer์ Pickle(ํผํด) ๊ธฐ๋ฐ ๋ชจ๋ธ ํ์ผ์ ๋ชจ๋ ๋์ผํ _load_for_lite_interpreter
(Python)
๋๋ _load_for_mobile
(C++) API๋ก ๋ถ๋ฌ์ฌ ์ ์์ต๋๋ค.
FlatBuffer ํ์์ ์ฌ์ฉํ๋ ค๋ฉด model._save_for_lite_interpreter('path/to/file.ptl')
์์ผ๋ก
๋ชจ๋ธ ํ์ผ์ ์์ฑํ๋ ๋์ , ๋ค์ ๋ช
๋ น์ ์คํํ๋ฉด ๋ฉ๋๋ค:
๋ค์์ ์ฌ์ฉํ์ฌ ์ ์ฅ
model._save_for_lite_interpreter('path/to/file.ptl', _use_flatbuffer=True)
์ธ์ _use_flatbuffer
๋ฅผ ์ถ๊ฐ๋ก ์ฌ์ฉํ์ฌ zip ํ์ผ ๋์ FlatBuffer ํ์ผ์
๋ง๋ญ๋๋ค. ์ด๋ ๊ฒ ์์ฑ๋ ํ์ผ์ ๋ถ๋ฌ์ค๋ ์๋๊ฐ ๋ ๋นจ๋ผ์ง๋๋ค.
์๋ฅผ ๋ค์ด ResNet-50์ ์ฌ์ฉํ๊ณ ๋ค์ ์คํฌ๋ฆฝํธ๋ฅผ ์คํํฉ๋๋ค:
import torch from torch.jit import mobile import time model = torch.hub.load('pytorch/vision:v0.10.0', 'deeplabv3_resnet50', pretrained=True) model.eval() jit_model = torch.jit.script(model) jit_model._save_for_lite_interpreter('/tmp/jit_model.ptl') jit_model._save_for_lite_interpreter('/tmp/jit_model.ff', _use_flatbuffer=True) import timeit print('Load ptl file:') print(timeit.timeit('from torch.jit import mobile; mobile._load_for_lite_interpreter("/tmp/jit_model.ptl")', number=20)) print('Load flatbuffer file:') print(timeit.timeit('from torch.jit import mobile; mobile._load_for_lite_interpreter("/tmp/jit_model.ff")', number=20))
๋ค์๊ณผ ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ์ป์ ์ ์์ต๋๋ค:
Load ptl file: 0.5387594579999999 Load flatbuffer file: 0.038842832999999466
์ค์ ๋ชจ๋ฐ์ผ ๊ธฐ๊ธฐ์์๋ ์๋ ํฅ์ ํญ์ด ๋ ์๊ฒ ์ง๋ง, ๊ทธ๋ผ์๋ ๋ก๋ฉ ์๊ฐ์ด 3๋ฐฐ์์ 6๋ฐฐ๊น์ง ๋จ์ถ๋๋ ํจ๊ณผ๋ฅผ ๊ธฐ๋ํ ์ ์์ต๋๋ค.
### FlatBuffer ๊ธฐ๋ฐ ๋ชจ๋ฐ์ผ ๋ชจ๋ธ์ ์ฌ์ฉํ์ง ์๋ ์ด์
๊ทธ๋ฌ๋, FlatBuffer ํ์์๋ ๊ณ ๋ คํด์ผ ํ ๋ช ๊ฐ์ง ์ ํ ์ฌํญ์ด ์์ต๋๋ค:
- PyTorch 1.13 ์ด์์์๋ง ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ฐ๋ผ์, ์ด์ ๋ฒ์ ์ PyTorch๋ก ์ปดํ์ผ๋ ํด๋ผ์ด์ธํธ ์ฅ์น์์๋ ๋ถ๋ฌ์ค์ง ๋ชปํ ์ ์์ต๋๋ค.
- Flatbuffer ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ํ์ผ ํฌ๊ธฐ์ ๋ํด 4GB์ ์ ํ์ ๋๊ณ ์์ต๋๋ค. ๋ฐ๋ผ์ ๋์ฉ๋ ๋ชจ๋ธ์๋ ์ ํฉํ์ง ์์ต๋๋ค.
๋ฒค์น๋งํน(์ต์ ํ๊ฐ ์ฌ์ฉ ์ฌ๋ก์ ๋์์ด ๋์๋์ง ํ์ธ)ํ๋ ์ต๊ณ ์ ๋ฐฉ๋ฒ์ ์ต์ ํ๋ฅผ ํ๊ณ ์ถ์ ํน์ ํ ์ฌ์ฉ ์ฌ๋ก๋ฅผ ์ธก์ ํ๋ ๊ฒ์ ๋๋ค. ์ฑ๋ฅ ์ธก์ ํ์๊ฐ ํ๊ฒฝ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
PyTorch ๋ฐฐํฌํ์ ๋ชจ๋ธ ์๋ฐฉํฅ ์ ๋ฌ์ ์คํํ๋ ๋ฐฉ์์ ์ฌ์ฉํด์ ์ํ ๊ทธ๋๋ก์(naked) ๋ฐ์ด๋๋ฆฌ๋ฅผ ๋ฒค์น๋งํนํ๋ ์๋จ์ ์ ๊ณตํฉ๋๋ค. ์ด ์ ๊ทผ๋ฒ์ ์ ํ๋ฆฌ์ผ์ด์ ๋ด๋ถ์์ ์ํํ๋ ๋ฐฉ๋ฒ๋ณด๋ค ๋ ์์ ์ ์ธ ์ธก์ ์น๋ฅผ ์ ๊ณตํฉ๋๋ค.
๋ ์ํผ์์ ์ด ๋ถ๋ถ์ Android์๋ง ํด๋นํฉ๋๋ค.
๋ฒค์น๋งํน์ ์ํด ๋จผ์ ๋ฒค์น๋งํฌ ๋ฐ์ด๋๋ฆฌ๋ฅผ ๋น๋ํด์ผ ํฉ๋๋ค:
<from-your-root-pytorch-dir> rm -rf build_android BUILD_PYTORCH_MOBILE=1 ANDROID_ABI=arm64-v8a ./scripts/build_android.sh -DBUILD_BINARY=ON
์ด ๊ณณ์ arm64 ๋ฐ์ด๋๋ฆฌ๊ฐ ์์ด์ผ ํฉ๋๋ค: build_android/bin/speed_benchmark_torch
.
์ด ๋ฐ์ด๋๋ฆฌ๋ --model=<path-to-model>
, --input_dim="1,3,224,224"
์ ์
๋ ฅ์ ์ํ ์ฐจ์ ์ ๋ณด๋ก ๋ฐ๊ณ --input_type="float"
์ผ๋ก ์
๋ ฅ ํ์
์ ์ธ์๋ก ๋ฐ์ต๋๋ค.
Android ๋๋ฐ์ด์ค๋ฅผ ์ฐ๊ฒฐํ ์ ์ด ์์ผ๋ฉด, speedbenchark_torch ๋ฐ์ด๋๋ฆฌ์ ๋ชจ๋ธ์ ํฐ์ผ๋ก ํธ์ํฉ๋๋ค:
adb push <speedbenchmark-torch> /data/local/tmp adb push <path-to-scripted-model> /data/local/tmp
์ด์ ๋ชจ๋ธ์ ๋ฒค์น๋งํนํ ์ค๋น๊ฐ ๋์์ต๋๋ค:
adb shell "/data/local/tmp/speed_benchmark_torch --model=/data/local/tmp/model.pt" --input_dims="1,3,224,224" --input_type="float" ----- output ----- Starting benchmark. Running warmup runs. Main runs. Main run finished. Microseconds per iter: 121318. Iters per second: 8.24281
iOS์ ๊ฒฝ์ฐ , ๋ฒค์น๋งํน์ ๋๊ตฌ๋ก TestApp ์ ์ฌ์ฉํฉ๋๋ค.
๋จผ์ optimize_for_mobile
๋ฉ์๋๋ฅผ TestApp/benchmark/trace_model.py ์ ์๋ ํ์ด์ฌ ์คํฌ๋ฆฝํธ์ ์ ์ฉํฉ๋๋ค. ๊ฐ๋จํ ์๋์ ๊ฐ์ด ์ฝ๋๋ฅผ ์์ ํฉ๋๋ค.
import torch import torchvision from torch.utils.mobile_optimizer import optimize_for_mobile model = torchvision.models.mobilenet_v2(pretrained=True) model.eval() example = torch.rand(1, 3, 224, 224) traced_script_module = torch.jit.trace(model, example) torchscript_model_optimized = optimize_for_mobile(traced_script_module) torch.jit.save(torchscript_model_optimized, "model.pt")
์ด์ python trace_model.py
๋ฅผ ์คํํฉ์๋ค. ๋ชจ๋ ๊ฒ์ด ์ ์๋ํ๋ค๋ฉด ๋ฒค์น๋งํน ๋๋ ํ ๋ฆฌ ๋ด๋ถ์ ์ต์ ํ๋ ๋ชจ๋ธ์ ์์ฑํ ์ ์์ด์ผ ํฉ๋๋ค.
๋ค์์ ์์ค์์๋ถํฐ PyTorch ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋น๋ํฉ๋๋ค.
BUILD_PYTORCH_MOBILE=1 IOS_ARCH=arm64 ./scripts/build_ios.sh
์ด์ ์ต์ ํ๋ ๋ชจ๋ธ๊ณผ PyTorch๊ฐ ์ค๋น๋์๊ธฐ์ XCode ํ๋ก์ ํธ๋ฅผ ๋ง๋ค๊ณ ๋ฒค์น๋งํนํ ์๊ฐ์ ๋๋ค. ์ด๋ฅผ ์ํด XCode ํ๋ก์ ํธ๋ฅผ ์ค์ ํ๋ ๋ฌด๊ฑฐ์ด ์์ ์ ์ํํ๋ ๋ฃจ๋น ์คํฌ๋ฆฝํธ setup.rb ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
ruby setup.rb
์ด์ TestApp.xcodeproj ๋ฅผ ์ด๊ณ iPhone์ ์ฐ๊ฒฐํ๋ฉด ์ค๋น๊ฐ ๋๋ฌ์ต๋๋ค. ์๋๋ iPhoneX์์์ ์์ ๊ฒฐ๊ณผ์ ๋๋ค.
TestApp[2121:722447] Main runs TestApp[2121:722447] Main run finished. Milliseconds per iter: 28.767 TestApp[2121:722447] Iters per second: : 34.762 TestApp[2121:722447] Done.