CoreML: PyTorch Modellerini CoreML Modellerine Dönüştürme
PyTorch modellerinizi CoreML’de kullanın!
Merhaba TurkishKit okuyucuları! 🖖 Bugün sizlerle birlikte CoreML uygulamanıza PyTorch modellerini eklemeyi konuşacağız.
PyTorch’dan CoreML’e
WWDC2020'den önce, PyTorch modellerini CoreML modellerine dönüştürmek zordu ve bazı modeller dönüştürülemiyordu. Bunun nedeni önceki modelleri dönüştürürken open source olan ONNX’in kullanılmasıydı. ONNX open source olduğundan yeniliklere adapte olmakta zorlanmaktaydı.
Apple artık PyTorch modellerini CoreML modellerine dönüştürebilmek için aracı olarak TorchScript kullanmaktadır. Böylece daha fazla model, eskisi kadar kısıtlama olmadan dönüştürülebiliyor. 🤩
Tracing ve Scripting
Tracing ve scripting, modelleri birbirlerine dönüştürürken ne kadarını dönüştüreceğinizi belirlemektedir. Bu kavramları açıklamadan önce aralarındaki farkı aşağıdaki görselle göstermek doğru olur.
Tracing vs Scripting
Bir PyTorch modeli soldaki gibidir. Soldaki modelde görebileceğiniz üzere bir tane output’a ulaşabilmek için birden fazla yol vardır. Bu yolların tamamını CoreML modelinize dönüştürmeye “scripting” denir.
Sağdaki diyagramda output’a giden tek yol vardır. Bu yol PyTorch modelinden alınmıştır. Bu diyagram bir “tracing” örneğidir.
Peki modellerimizi dönüştürürken hangi yöntemi kullanmalıyız🧐? Apple mühendisleri, olabildiğince tracing kullanmamızı önermektedir çünkü tracing, modelleri basitleştirir ve kullanımı kolaylaştırır. Scripting kullanmadan önce, eğer mümkünse, en etkili yöntem, scripting ve tracing kullanmaktır. Eğer bu da mümkün değilse, scripting kullanmanız gerekir.
Tracing
Şimdiye kadar iki tane sistemi karşılaştırdık ancak hiç ne olduklarından bahsetmedik. Tracing, yukarıdaki diyagramdan da görüldüğü gibi bir modelin tek bir yolunu dönüştürmektir.
Tracing yaparken ilk PyTorch modelinizi TorchScript modeline, sonra oluşturulan TorchScript modelini CoreML modeline dönüştürmek gerektir. Bunu yapabilmenin en kolay yolu, PyTorch’un JIT tracer modülünü kullanmaktır.
Gelin tracing’i bir örnek üzerinden görelim:
Öncelikle çok basit bir PyTorch module layer kolamamız gerekecekir. Bu, tracing mekanizmasını öğrenebilmek için kullanacağımız modüldür.
Aşağıdaki kodlar python dili kullanılarak yazılmıştır.
import torch
import torch.nn as nn
import torch.nn.functional as F # Layer modülü oluşturmak
class Layer(nn.Module):
def __init__(self, dims):
super(Layer, self).__init__()
self.conv1 = nn.Conv2d(*dims)
def forward(self, x):
x = F.relu(self.conv1(x))
x = F.max_pool2d(x, (2, 2))
return x# Birkaç tane layer kullanarak basit bir network oluşturmak
class SimpleNet(nn.Module):
def __init__(self):
super(SimpleNet, self).__init__()
self.layer1 = Layer((3, 6, 3))
self.layer2 = Layer((6, 16, 1))
def forward(self, x):
x = self.layer1(x)
x = self.layer2(x)
return x# Networkü tanımlak
model = SimpleNet()
Bundan sonra input’umuzu tanımlayarak “JIT Tracer” kullanmamız gerekecek.
example = torch.rand(1, 3, 224, 224) # Input
traced = torch.jit.trace(model, example) # TorchScript tracing başlatmak
Son olarak modelimizi dönüştürmek için alttaki kodu yazmamız yeterli olacak.
traced.save(“model.pt”) # Modeli dönüştürücüye yollamak
Böylece “tracing” işlemini PyTorch scriptini TorchScript’e çevirerek başarmış olduk.
Şimdi modelimizi TorchScript modeline çevirdiğimize göre CoreML modeline dönüştürme işlemine başlayabiliriz. Bu noktada “MobileNetV2” modelini kullanarak bir dönüştürme yapılacak. Bu modele, Torchvision kütüphanesinden ulaşabilirsiniz.
import torch
import torchvision
# MobileNetV2 önceden eğitilmiş model yüklemek
torch_model = torchvision.models.mobilenet_v2(pretrained=True)torch_model.eval()
Başta farklı bir model üzerinde detaylı bir şekilde “tracing” gördük. “Tracing” işlemini bu modelde de uygulamamız gerekecek.
# Random data ile tracing
example_input = torch.rand(1, 3, 224, 224)
traced_model = torch.jit.trace(torch_model, example_input)
Unified Conversion API kullanarak TorchScript modelini CoreML modeline dönüştürmemiz gerekecektir.
import coremltools as ct
model = ct.convert(
traced_model,
inputs=[ct.ImageType(name="input_1",shape=example_input.shape)],
classifier_config = ct.ClassifierConfig(class_labels)
)
Modeli CoreML modeline dönüştürdükten sonra aşağıdaki kod ile kaydetmeniz gerekecek.
model.save("MobileNetV2.mlmodel")
Bir CoreML modelini “tracing” kullanarak dönüştürmek işte bu kadar basit! 😉
Scripting
Bazı modeller için “tracing” yöntemi için uygun olmayabiliyor. Mesela modelinizin farklı “input”lara göre farklı yollar kullanarak bir “output” vermesini istiyorsanız “tracing” kullanarak doğru bir dönüştürme yapamayabilirsiniz. Bu noktada yardıma “scripting” geliyor.
Zaten önceden de bahsettiğimiz gibi “scripting”, modeli dönüştürürken tek bir yol değil, tüm yolları dönüştürmektedir. Bu tracing’den biraz daha uğraşlı ve zor olmasına rağmen bazı durumlarda daha avantajlı olabilir.
“Scripting” yapabilmek için PyTorch’un “JIT script” modülü kullanılmaktadır.
Hadi gelin bir örnek üzerinden scripting işlemini inceleyelim:
Öncelikle bir örnek model yazarak başlayalım. Eğer “input” tensör’ü sıfırdan küçük bir sayı ise bu kod bloku iki kere çalıştırılacaktır. Bunun dışındaki durumlarda kod bloku bir kere çalıştırılacaktır.
class _LoopBody(nn.Module):
def __init__(self, channels):
super(_LoopBody, self).__init__()
conv = nn.Conv2d(
in_channels=channels,
out_channels=channels,
kernel_size=3,
padding=1,
)
self.conv = conv def forward(self, x):
x = self.conv(x)
x = F.relu(x)
return x class ControlFlowNet(nn.Module):
def __init__(self, num_channels: int):
super(ControlFlowNet, self).__init__()
self.loop_body = _LoopBody(num_channels)
def forward(self, x):
avg = torch.mean(x)
if avg.item() < 0:
loop_count = 2
else:
loop_count = 1
for _ in range(loop_count):
x = self.loop_body(x)
return x
Kodda da görebildiğimiz üzere, input değeri değiştikçe output’a ulaşma yolu değiştiği için bu modeli tracing ile dönüştürmek doğru olmaz. Bu nedenle scripting kullanılması gerektir.
“JIT script” kullanarak öncellikle bu modeli TorchScript modeline sonra da CoreML modeline dönüştürmek gerekir.
# TorchScript modeline dönüştürmek
model = ControlFlowNet(num_channels=3)
scripted_model = torch.jit.script(model) # CoreML modeline dönüştürmek
import coremltools
mlmodel = coremltools.converters.convert(
scripted_model,
inputs=[coremltools.TensorType(shape=(1, 3, 64, 64))],
)
Scripting kullanarak PyTorch modelinizi CoreML modeline dönüştürmüş oldunuz! Görebildiğiniz gibi model hazırlandıktan sonra dönüştürme işleminde çok büyük bir uğraş olmamaktadır. 😊
Scripting ve Tracing’i Beraber Kullanmak
Scripting modelin tamamını dönüştürmektedir. Bu yüzden modelinizi bölümlere bölüp bazı kısımları tracing, ihtiyacınız olanları da scripting ile dönüştürmeniz iyi bir seçim olacaktır. 🙋♀️
Mesela eğer modelinizde hangi fonksiyonun en iyi çalıştığını input’a göre belirleyecekseniz ve bu en iyi çalışan fonksiyonu tespit ettikten sonra sürekli aynı fonksiyonu kullanacaksanız scripting ve tracing’i birlikte kullanmak iyi bir karar olabilir. Böylece modeliniz optimal yolu keşfettikten sonra çalışırken sürekli o yolu kullanabilir.
Bu sefer hem input’a göre değişen hem de sabit bir fonksiyonu olan bir model yaratalım. Önceden tanımlamış olduğunuz modelin “ControlFlowNet” sınıfına aşağıdaki değişiklikleri yapalım ki kontrol akışını takip edebilelim.
class ControlFlowNet2(nn.Module):
def __init__(self, num_channels: int):
super(ControlFlowNet2, self).__init__()
self.loop_body = _LoopBody(num_channels)
self.loop_body = torch.jit.trace(self.loop_body, torch.randn(1,3,64,64)) def forward(self, x):
avg = torch.mean(x)
if avg.item() < 0:
loop_count = 2
else:
loop_count = 1
for _ in range(loop_count):
x = self.loop_body(x)
return x
“JIT script” modülü, dönüştürülen modeldeki “loop_body”yi gördükten sonra bunun bir TorchScript modeline dönüştürülmüş olduğunu anlayacak ve atlayacaktır.
Bu noktada modeli oluşturabilir ve CoreML modeline dönüştürebilirsiniz. Aşağıdaki kod önceden yaptığımız gibi modeli CoreML modeline dönüştürecektir:
model = ControlFlowNet2(num_channels=3)
scripted_model = torch.jit.script(model) import coremltools
mlmodel = coremltools.converters.convert(
scripted_model,
inputs=[coremltools.TensorType(shape=(1, 3, 64, 64))],
)
Tebrikler! Bu makalenin sonuna geldiniz! 🥳 Bu makalede birlikte PyTorch modellerini CoreML modellerine çevirmenin yeni ve daha etkili yöntemlerinden bahsettik. “Tracing” ve “scripting”in ne olduğunu, nasıl yapıldığını ve ne zaman kullanılması gerektiğini öğrendik. Bir sonraki makalede görüşmek üzere. 👋