์ด ํํ ๋ฆฌ์ผ์ PyTorch์์ ๋์จ neural style transfer ๋ชจ๋ธ์ Apple CoreML ํ์์ผ๋ก ONNX์ ์ด์ฉํ์ฌ ๋ณํํ๋ ๋ฐฉ๋ฒ์ ์๊ฐํฉ๋๋ค. ๋ํ, ์ด ํํ ๋ฆฌ์ผ์ ์ด๋ป๊ฒ Apple ์ฅ์น๋ค์ ๋ฅ ๋ฌ๋ ๋ชจ๋ธ๋ค์ ์ฌ์ฉํ๋์ง ์๋ ค์ฃผ๊ณ ํนํ๋ ์ด๋ฒ ํํ ๋ฆฌ์ผ์์๋ ์นด๋ฉ๋ผ๋ก๋ถํฐ ์ค์๊ฐ ์คํธ๋ฆผ์ ์ด์ฉํฉ๋๋ค.
ONNX (Open Neural Network Exchange) ๋ ๋ฅ ๋ฌ๋ ๋ชจ๋ธ๋ค์ ๋ํํ๋ ๊ณต๊ฐ๋์ด์๋ ํ์์ ๋๋ค. ONNX๋ AI ๊ฐ๋ฐ์๋ค์ด ์ต์ฒจ๋จ์ ๋๊ตฌ๋ค๊ณผ ๋ชจ๋ธ๋ค์ ์กฐํฉ์ ๊ทธ๋ค์๊ฒ ๊ฐ์ฅ ์ ๋ง๋ ๊ฒ์ ์ฝ๊ฒ ์ ํํ๋๋ก ํด์ค๋๋ค. ONNX๋ ์ปค๋ฎค๋ํฐ์ ํํธ๋๋ค์ด ๊ฐ๋ฐํ๋ฉฐ ๋ํ ์ง์๋ฉ๋๋ค. ONNX์ ์ด๋ค ๋๊ตฌ๋ค์ด ์ง์๋๋์ง๋ onnx.ai ๋ฅผ ๋ฐฉ๋ฌธํ์ฌ ๋ ์์๋ณผ ์ ์์ต๋๋ค.
์ด๋ฒ ํํ ๋ฆฌ์ผ์์๋ 4๊ฐ์ง ์ค์ฌ ์ฌํญ๋ค์ ์๊ฐํด๋๋ฆฌ๊ฒ ์ต๋๋ค:
- PyTorch style transfer ๋ชจ๋ธ ๋ค์ด๋ก๋ (๋๋ ํ์ต์ํค๊ธฐ)
- PyTorch ๋ชจ๋ธ์ ONNX ๋ชจ๋ธ๋ก ๋ณํํ๊ธฐ
- ONNX ๋ชจ๋ธ์ CoreML ๋ชจ๋ธ๋ก ๋ณํํ๊ธฐ
- `style transfer iOS App ์์ CoreML ๋ชจ๋ธ ๋๋ฆฌ๊ธฐ`_
ํ์ฌ ๋ก์ปฌ์ ์ค์น๋์ด์๋ ํจํค์ง๋ค๊ณผ์ ์ถฉ๋์ ํผํ๊ธฐ ์ํด virtualenv๋ฅผ ์ฌ์ฉํ๊ฒ ์ต๋๋ค. ํํ ๋ฆฌ์ผ์์ Python 3.6 ๋ฒ์ ์ ์ฌ์ฉํ์ง๋ง ๋ค๋ฅธ ๋ฒ์ ๋ ์๋ํ๋๋ฐ ๋ฌด๋ฆฌ๊ฐ ์์ต๋๋ค.
python3.6 -m venv venv
source ./venv/bin/activate
PyTorch์ onnx-coreml ๋ณํํด์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ค์นํด์ผํฉ๋๋ค.
pip install torchvision onnx-coreml
iPhone ์์ iOS style transfer ์ดํ๋ฆฌ์ผ์ด์ ์ ์คํํ๋ ค๋ฉด XCode ๊ฐ ํ์ํฉ๋๋ค. Linux ์์๋ ๋ชจ๋ธ์ ๋ณํํ ์ ์์ง๋ง, iOS ์ดํ๋ฆฌ์ผ์ด์ ์ ์คํ ํ๋ ค๋ฉด Mac ์ด ํ์ํฉ๋๋ค.
์ด๋ฒ ํํ ๋ฆฌ์ผ์์ ์ฐ๋ฆฌ๋ https://github.com/pytorch/examples/tree/master/fast_neural_style ์ PyTorch ๋ก ๋ง๋ค์ด์ง style transfer ์ ์ด์ฉํ๊ฒ ์ต๋๋ค. ๋ค๋ฅธ PyTorch ๋ ONNX ๋ชจ๋ธ์ ์ฌ์ฉํ๊ธธ ์ํ๋ค๋ฉด ์ด๋ฒ ๋จ๊ณ๋ฅผ ์๋ตํด๋ ์ข์ต๋๋ค.
์ด ๋ชจ๋ธ๋ค์ ์ด๋ฏธ์ง์ style transfer ๊ฐ ์ ์ฉ๋๋๋ก ๋ง๋ค์ด์ ธ์ ๋น๋์ค์ ์ ์ฉํ๊ธฐ์๋ ์ต์ ํ๊ฐ ๋์ด์์ง ์์ ์ถฉ๋ถํ ๋น ๋ฅด์ง ์์ต๋๋ค. ํ์ง๋ง ํด์๋๋ฅผ ์ด๋ ์ ๋ ๋ฎ์ถ๋ค๋ฉด ๋น๋์ค์์ ์ถฉ๋ถํ ์๋์ ์๋๋ฉ๋๋ค.
๋ชจ๋ธ๋ค์ ๋ค์ด๋ฐ์๋ด ์๋ค.
git clone https://github.com/pytorch/examples
cd examples/fast_neural_style
์ง์ ๋ชจ๋ธ์ ํ๋ จ์ํค๊ธฐ ์ํ๋ค๋ฉด ๋ฐฉ๊ธ ํด๋ก ํ ์ ์ฅ์์ pytorch/examples ๋ฅผ ๋ฐฉ๋ฌธํ๋ฉด ์ด๋ป๊ฒ ํด์ผํ๋์ง์ ๋ํ ๋ ๋ง์ ์ ๋ณด๊ฐ ์์ต๋๋ค. ์ง๊ธ์ ์ ์ฅ์์์ ์ ๊ณตํด์ฃผ๋ ์คํฌ๋ฆฝํธ๋ฅผ ์ฌ์ฉํ์ฌ ๋ฏธ๋ฆฌ ํ๋ จ๋ ๋ชจ๋ธ์ ๋ค์ด๋ก๋ํ๊ฒ ์ต๋๋ค:
python download_saved_models.py
์ด ์คํฌ๋ฆฝํธ๋ ๋ฏธ๋ฆฌ ํ๋ จ๋ PyTorch ๋ชจ๋ธ๋ค์ ๋ค์ด๋ฐ๊ณ saved_models
ํด๋์ ์ ์ฅํฉ๋๋ค.
ํด๋์๋ 4๊ฐ์ง ํ์ผ candy.pth
, mosaic.pth
, rain_princess.pth
๊ทธ๋ฆฌ๊ณ udnie.pth
๊ฐ ํด๋์ ๋ค์ด ๋ฐ์์ก์ต๋๋ค.
์ด์ ์ฐ๋ฆฌ๋ ๋ฏธ๋ฆฌ ํ๋ จ๋ PyTorch ๋ชจ๋ธ๋ค์ saved_models
ํด๋์ .pth
ํ์ผ๋ก ๊ฐ์ง๊ณ ์์ด์ ๋์ค์ ์ ๋ชจ๋ธ๋ค์ ONNX ํ์์ผ๋ก ๋ณํ ํ ์ ์์ต๋๋ค.
๋ชจ๋ธ ์ ์๋ ๋ฐฉ๊ธ ์ ํด๋ก ํ๋ ์ ์ฅ์์ pytorch/examples ์ ์์ผ๋ฉฐ ๋จ ๋ช ์ค์ ํ์ด์ฌ ์ฝ๋๋ฅผ ์ด์ฉํด์ ONNX ๋ก ๋ณํ ํ ์ ์์ต๋๋ค.
์ธ๊ณต ์ ๊ฒฝ๋ง์ ์ค์ ๋ก ์คํํ๋ ๋์ ์ด๋ฌํ ๊ฒฝ์ฐ์๋ ์ฐ๋ฆฌ๋ torch.onnx._export
๋ฅผ ํธ์ถํ๋๋ฐ ์ด๊ฒ์ PyTorch ๊ฐ ์ ๊ณตํ๋ API ๋ก PyTorch ์์ ์ง์ ์ ์ผ๋ก ONNX ํ์์ ๋ชจ๋ธ๋ก ๋ณํํฉ๋๋ค.
ํ์ง๋ง ์ด๋ฒ ๊ฒฝ์ฐ์๋ ์ฐ๋ฆฌ๋ ์ ๊ฒ์ ํธ์ถ ์ํด๋ ๋๋๋ฐ ๊ทธ ์ด์ ๋ ์ ๋ฐ ๊ธฐ๋ฅ์ ์ฐ๋ฆฌ๋ฅผ ์ํด ๋์ ํด์ฃผ๋ ์คํฌ๋ฆฝํธ๊ฐ neural_style/neural_style.py
์ ์๊ธฐ ๋๋ฌธ์
๋๋ค.
You can also take a look at that script if you would like to apply it to other models.
๋ค๋ฅธ ๋ชจ๋ธ์ ์ ์คํฌ๋ฆฝํธ๋ฅผ ์ ์ฉํ๊ธธ ์ํ์๋ฉด ์คํฌ๋ฆฝํธ๋ฅผ ๋ณด๋๊ฒ๋ ์ข์ต๋๋ค.
PyTorch ์์ ONNX ํ์์ผ๋ก ๋ณํํ๋๊ฒ์ ๊ฒฐ๊ณผ์ ์ผ๋ก ๋น์ ์ ์ ๊ฒฝ๋ง์ ์ถ์ ํด ๋๊ฐ๋๊ฒ๊ณผ ๊ฐ์ต๋๋ค. ์ด API ํธ์ถ์ ๋ด๋ถ์ ์ผ๋ก ๊ทธ๋ํ๋ฅผ ์์ฑํด๋ด๊ธฐ ์ํด '๋๋ฏธ ๋ฐ์ดํฐ' ๋ฅผ ์ด์ฉํ์ฌ ์ ๊ฒฝ๋ง์ ์คํํฉ๋๋ค. ์ด๋ ๊ธฐ ๋๋ฌธ์ ์ ๋ ฅ๊ฐ์ผ๋ก style transfer ๋ฅผ ์ ์ฉํ ์ด๋ฏธ์ง๊ฐ ์ ๋ ฅ๊ฐ์ผ๋ก ํ์ํ๋ฉฐ ๊ธฐ๋ณธ์ ์ธ ๋น์ด์๋ ์ด๋ฏธ์ง์ฌ๋ ๋ฉ๋๋ค. ๊ทธ๋ฌ๋ ์ด๋ฏธ์ง์ ํฝ์ ํฌ๊ธฐ๋ ์ค์ํ๋ฐ ๊ทธ ์ด์ ๋ ํฝ์ ํฌ๊ธฐ๋ ๋ณํ๋ style transfer ๋ชจ๋ธ์ ํฌ๊ธฐ๋ก๋ ์ด์ฉ๋๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ข์ ํผํฌ๋จผ์ค๋ฅผ ์ป๊ธฐ ์ํด ์ฐ๋ฆฌ๋ 250x540 ์ ํด์๋๋ฅผ ์ฌ์ฉํ ์์ ์ ๋๋ค. FPS๋ณด๋ค style transfer์ ํ์ง์ ๋ ๋ง์ด ์ ๊ฒฝ ์ฐ์ ๋ค๋ฉด ๋ ํฐ ํด์๋๋ฅผ ์ฌ์ฉํ์ ๋ ๋ฉ๋๋ค.
ImageMagick ์ ์ฌ์ฉํ์ฌ ์ฐ๋ฆฌ๊ฐ ์ํ๋ ํฌ๊ธฐ์ ๋น์ด์๋ ์ด๋ฏธ์ง๋ฅผ ์์ฑํด๋ด ์๋ค. .. code-block:: bash
convert -size 250x540 xc:white png24:dummy.jpg
๊ทธ๋ฆฌ๊ณ PyTorch ๋ชจ๋ธ์ ๋ณํํ๋๋ฐ ์ฌ์ฉํด๋ด ๋๋ค.
python ./neural_style/neural_style.py eval --content-image dummy.jpg --output-image dummy-out.jpg --model ./saved_models/candy.pth --cuda 0 --export_onnx ./saved_models/candy.onnx
python ./neural_style/neural_style.py eval --content-image dummy.jpg --output-image dummy-out.jpg --model ./saved_models/udnie.pth --cuda 0 --export_onnx ./saved_models/udnie.onnx
python ./neural_style/neural_style.py eval --content-image dummy.jpg --output-image dummy-out.jpg --model ./saved_models/rain_princess.pth --cuda 0 --export_onnx ./saved_models/rain_princess.onnx
python ./neural_style/neural_style.py eval --content-image dummy.jpg --output-image dummy-out.jpg --model ./saved_models/mosaic.pth --cuda 0 --export_onnx ./saved_models/mosaic.onnx
์์ ๊ณผ์ ์ ๊ฑฐ์น๋ฉด 4๊ฐ์ ํ์ผ candy.onnx
, mosaic.onnx
, rain_princess.onnx
๊ทธ๋ฆฌ๊ณ udnie.onnx
,
๊ฐ .pth
ํ์ผ๋ค์ ๊ฐ๊ฐ ๋์๋์ด ์์ฑ๋์ด์์ด์ผ ํฉ๋๋ค.
์ด์ ์ฐ๋ฆฌ๋ ONNX ๋ชจ๋ธ๋ค์ด ์๊ธฐ ๋๋ฌธ์ Apple ์ฅ์น์์ ์คํ์ํค๊ธฐ ์ํด ๋ชจ๋ธ๋ค์ CoreML ๋ชจ๋ธ๋ก ๋ณํ์ํฌ ์ ์์ต๋๋ค.
์ด๋ ๊ฒ ํ๊ธฐ ์ํด, ์ฐ๋ฆฌ๋ ์ ์ ์ค์นํ onnx-coreml ์ปจ๋ฒํฐ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
์ด ์ปจ๋ฒํฐ๋ ์์ ์ค์น ๋จ๊ณ์์ ์ถ๊ฐ๋ convert-onnx-to-coreml
์คํฌ๋ฆฝํธ๋ฅผ ํฌํจํ๊ณ ์์ต๋๋ค.
์์ฝ๊ฒ๋ ์ด ์คํฌ๋ฆฝํธ๋ฅผ ์ฐ๋ฆฌ๊ฐ ์ํ๋ ๊ธฐ๋ฅ์ธ ์ ๊ฒฝ๋ง์ ์
๋ ฅ๊ฐ๊ณผ ์ถ๋ ฅ๊ฐ์ ์ด๋ฏธ์ง๋ก์ ํ์ํด์ฃผ์ง ๋ชปํ๊ณ
์ฐ๋ฆฌ๊ฐ ์ํ๋ ๊ธฐ๋ฅ์ ํ์ด์ฌ์์ ์ปจ๋ฒํฐ๋ฅผ ํธ์ถํด์ผ๋ง ์ง์๋ฉ๋๋ค.
style transfer ๋ชจ๋ธ์ ๋ณด๋ฉด (์๋ฅผ ๋ค๋ฉด .onnx ํ์ผ์ Netron๊ณผ ๊ฐ์ ์ดํ๋ฆฌ์ผ์ด์ ์์ ์ฌ๋๊ฒ) ์ฐ๋ฆฌ๋ ์ ๋ ฅ๊ฐ์ด '0' ์ผ๋ก ๋์ด์๊ณ ์ถ๋ ฅ๊ฐ์ด '186' ์ผ๋ก ๋์ด์๋๊ฑธ ํ์ธํ ์ ์์ต๋๋ค. ์ด๊ฒ๋ค์ PyTorch ์ ์ํด ํ ๋น๋ ์ซ์ id ๋ค ์ ๋๋ค. ์ฐ๋ฆฌ๋ ์ด๋ฌํ ๊ฐ๋ค์ ์ด๋ฏธ์ง๋ก์จ ํ์ํด์ผํฉ๋๋ค.
์ ๊ทธ๋์ ์ด์ onnx_to_coreml.py
๋ผ๊ณ ํ๋ ์์ ํ์ด์ฌ ํ์ผ์ ์์ฑํฉ๋๋ค. ์ด๊ฒ์ touch ๋ช
๋ น์ด๋ ๊ฐ์ฅ ์ข์ํ๋ ํธ์ง๊ธฐ๋ก ๋ค์์ ๋ช์ค์ ์ฝ๋๋ง ์ถ๊ฐํ๋ฉด ๋ง๋ค์ ์์ต๋๋ค.
import sys
from onnx import onnx_pb
from onnx_coreml import convert
model_in = sys.argv[1]
model_out = sys.argv[2]
model_file = open(model_in, 'rb')
model_proto = onnx_pb.ModelProto()
model_proto.ParseFromString(model_file.read())
coreml_model = convert(model_proto, image_input_names=['0'], image_output_names=['186'])
coreml_model.save(model_out)
์ด์ ์คํ์์ผ๋ด ์๋ค.
python onnx_to_coreml.py ./saved_models/candy.onnx ./saved_models/candy.mlmodel
python onnx_to_coreml.py ./saved_models/udnie.onnx ./saved_models/udnie.mlmodel
python onnx_to_coreml.py ./saved_models/rain_princess.onnx ./saved_models/rain_princess.mlmodel
python onnx_to_coreml.py ./saved_models/mosaic.onnx ./saved_models/mosaic.mlmodel
์ด์ saved_models
ํด๋์ CoreML ๋ชจ๋ธ์ด 4๊ฐ , candy.mlmodel
, mosaic.mlmodel
, rain_princess.mlmodel
and udnie.mlmodel
, ๊ฐ ์์ต๋๋ค.
์ด ์ ์ฅ์(README.md๋ฅผ ์ฝ๊ณ ๊ณ์๋ ํ์ฌ์ ์ ์ฅ์)๋ CoreML style transfer ๋ชจ๋ธ๋ค์ ํธ๋ํฐ ์นด๋ฉ๋ผ๋ก ์ค์๊ฐ ์นด๋ฉ๋ผ ์คํธ๋ฆผ์ ์ด์ฉํ์ฌ ์คํํ ์ ์๋ iOS ์ฑ์ ํฌํจํ๊ณ ์์ต๋๋ค. ์ด์ ์ ์ฅ์๋ฅผ ํด๋ก ํด๋ด ์๋ค.
git clone https://github.com/onnx/tutorials
๊ทธ๋ฆฌ๊ณ tutorials/examples/CoreML/ONNXLive/ONNXLive.xcodeproj
ํ๋ก์ ํธ๋ฅผ XCode ์์ ์ด์ด๋ด
์๋ค.
์ฐ๋ฆฌ๋ XCode 9.3 ๋ฒ์ ๊ณผ iPhone X๋ฅผ ์ฌ์ฉํ๋๊ฒ์ ์ถ์ฒํฉ๋๋ค. ์ค๋๋ ๊ธฐ๊ธฐ๋ ์ค๋๋ ๋ฒ์ ์ XCode ๋ฅผ ์ฌ์ฉํด ์คํํ๋๋ฐ๋ ์ด์๊ฐ ์์ ์๋ ์์ต๋๋ค.
Models/
ํด๋์ ํ๋ก์ ํธ๋ .mlmodel ํ์ผ๋ค์ด ํฌํจ๋์ด ์์ต๋๋ค. ์ฐ๋ฆฌ๋ ์ ํ์ผ๋ค์ ์ฐ๋ฆฌ๊ฐ ๋ฐฉ๊ธ ์์ฑํด๋ธ ๋ชจ๋ธ๋ค๋ก ๊ต์ฒดํด์ผํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ iPhone์ ์ด์ฉํด์ ์ฑ์ ์คํ์ํค๋ฉด ๋ชจ๋ ์ค๋น๊ฐ ๋๋ฌ์ต๋๋ค. ์คํฌ๋ฆฐ์ ํญํ๋ฉด์ ๋ชจ๋ธ๋ค์ ๋ฐ๊ฟ๋ณด๋๋ก ํฉ์๋ค.
์ฐ๋ฆฌ๋ ์ด ํํ ๋ฆฌ์ผ์ด ONNX ๊ฐ ๋ฌด์์ด๊ณ ์ด๋ป๊ฒ ์ ๊ฒฝ๋ง๋ค์ ํ๋ ์์ํฌ ์ฌ์ด์์ ๋ณํํ๋ฉด์ ์ฌ์ฉํ๋์ง ์ถฉ๋ถํ ์ค๋ช ์ด ๋์๊ธฐ๋ฅผ ๋ฐ๋๋๋ค. ์ด๋ฒ์๋ PyTorch์์ CoreML ๋ก style transfer ๋ชจ๋ธ๋ค์ ๋ณํํ์์ต๋๋ค.
์์ ์๊ฐํด๋๋ฆฐ ๋จ๊ณ๋ค์ ํ์ฉํ๋ฉฐ ์์ ๋กญ๊ฒ ์์ ๋ง์ ๋ชจ๋ธ์ ์คํํด ๋ณด์๊ธฐ๋ฅผ ๋ฐ๋๋๋ค. ํผ๋๋ฐฑ์ด๋ ์ค๋ฅ๊ฐ ์๋ค๋ฉด ์ธ์ ๋ ์ง ์๋ ค์ฃผ์ธ์.