Tüm Yazılar
KategoriAI
Okuma Süresi
9 dk
Yayın Tarihi
2026-10-15
Kelime Sayısı
1.443kelime

Kahveni hazırla - bu içerikli bir makale!

SwiftAI: saf Swift ile klasik makine öğrenmesi ve güvenle yüklenen model dosyaları

Özet

SwiftAI 2.0 modelleri bağımlılıksız olarak cihazda nasıl eğitiyor, ölçüyor ve kaydediyor; model dosyasını decode etmek neden güvenilmez girdi sayılıyor.

  • Core ML, başka bir yerde eğitilmiş bir modeli çalıştırmakta iyidir.
  • Akla gelen ilk Apple alternatifi Create ML.
  • Paketi Xcode'da File › Add Package Dependencies… menüsünden https://github.com/muhittincamdali/SwiftAI.git adresiyle ya da Package.swift içinde from: "2.0.0" ile ekleyebilirsin.
  • Kaynak kod: [github.com/muhittincamdali/SwiftAI](https://github.com/muhittincamdali/SwiftAI)
SwiftAI: saf Swift ile klasik makine öğrenmesi ve güvenle yüklenen model dosyaları

İçindekiler


Problem

Core ML, başka bir yerde eğitilmiş bir modeli çalıştırmakta iyidir. Ama elinde bir sayı tablosu

olan bir uygulama geliştiricisi bu veriyle Swift'te, cihazın üzerinde bir lojistik regresyon ya da

random forest eğitmek ve modelin ne kadar iyi olduğunu ölçmek istediğinde pek yardımcı olmaz.

Apple'ın bu iş için sunduğu araç Create ML: framework'ü iOS 15'ten beri tablo verisi üzerinde

sınıflandırma ve regresyon modellerini Mac'in yanı sıra cihazda da eğitebiliyor. Bilinen diğer

yollar ise dönüştürme adımı olan bir Python araç zinciri ya da bir sunucu.

SwiftAI bu daha dar iş için yazılmış bir Swift paketi: sayı tablolarında sınıflandırma, regresyon,

kümeleme ve boyut indirgeme. Veriyi CSV metninden ya da dizilerden yüklersin, bölersin, tek bir

fonksiyon çağrısıyla modeli eğitirsin, ölçersin ve uygulamada yüklemek üzere JSON olarak

kaydedersin. Paketin hiçbir bağımlılığı yok.

Güncel kütüphane, 14 Ekim 2026'da yayımlanan 2.0.0 sürümü. Bu sürüm 1.0.0'ın devamı değil. Repo

Ağustos 2025'te uygulama mimarisi katmanları ve Vision/NLP kodu içeren geniş kapsamlı bir "AI

framework" olarak açıldı. 1.0.0 sürümü 2 Şubat 2026'da yayımlandı; üç gün sonra uygulama mimarisi

modülleri silindi ve yerlerine daha küçük bir makine öğrenmesi çekirdeği yazıldı. Haziran 2026'da

bu çekirdek sadeleştirildi: testler tek bir yer tutucu dosyaya indi, birkaç küçük stub katman

eklendi. Ekim 2026'da kütüphane baştan kuruldu. CHANGELOG'daki 2.0.0 kaydı da bununla açılıyor:

1.0.0 API'lerinin hiçbiri kalmadı, Alamofire gibi bağımlılıklar da kaldırıldı.

Tasarım kararları ve alternatifler

Create ML yerine düz Swift. Akla gelen ilk Apple alternatifi Create ML. SwiftAI'nin farkları

repoda görülebiliyor: her algoritma okunabilir Swift kaynağı; eğitilmiş model JSON olarak

kaydedilen ve decode sırasında doğrulanan Codable bir değer; her rastgele adım bir seed alıyor;

sonuçlar scikit-learn 1.9.1 ile test ediliyor; paket tvOS 15 ve watchOS 8'i de destekliyor. Apple'ın

dokümanı ise Create ML'i tvOS 16'dan itibaren listeliyor, watchOS için hiç listelemiyor.

Tek, düz ve doğrulanmış bir matris. Matrix; rows, columns ve satır sırasıyla dizilmiş tek

bir [Double] tutuyor. Alternatif olan [[Double]] yazması kolay ama her satırı ayrı ayırıyor ve

satırların aynı uzunlukta olacağını garanti edemiyor. Bitişik bir bellek alanı doğrudan

vDSP_mmulD'ye verilebiliyor; şekil de veri pakete girdiği anda bir kez kontrol ediliyor. Bir

test, Accelerate çarpımıyla taşınabilir çarpımın rastgele matrislerde aynı sonucu verdiğini

doğruluyor.

Eğitilmiş modeller static func fit ile üretilen değişmez değerler. scikit-learn değiştirilebilir

bir nesne ve model.fit(X, y) kullanır. Swift'te bu her yerde var ve her tahminde "bu model

eğitildi mi?" kontrolü demek. LogisticRegression.fit(data) yeni bir değer döndürdüğü için elindeki

model her zaman eğitilmiş oluyor; value type olduğu için de thread'ler arasında paylaşılabiliyor.

Ortak davranış protocol'lerde. Sınıflandırıcılar Classifier'a (ve

ProbabilisticClassifier'a), regresyon modelleri Regressor'a uyuyor. accuracy(on:) ve evaluate(on:) protocol extension'larında bir kez yazılı; böylece çapraz doğrulama,

Pipeline ve raporlar her modelle çalışıyor.

Sınırda hata fırlat, içeride güven. Veri ya da ayar alan her fonksiyon bunları doğruluyor ve

neyin değişmesi gerektiğini söyleyen bir SwiftAIError fırlatıyor: NaN değerler, yanlış feature

sayısı, taşan toplamlar, aralık dışı ayarlar, sayı olmayan CSV satırları. Mobil bir uygulamanın bir NaN yüzünden çökmesi kabul edilemez; her yerde

optional döndürmek ise hatanın nedenini kaybettirir.

En küçük kareler için normal denklemler değil, Householder QR. Normal denklemler XᵀX üzerinde

çalışır ve bu matrisin koşul sayısı verininkinin karesidir. QR doğrudan veri üzerinde çalıştığı

için neredeyse eş-doğrusal feature'larda daha fazla doğru basamak korunuyor. Lojistik regresyon,

scikit-learn ile aynı amaç fonksiyonu (L2 cezalı cross-entropy) üzerinde L-BFGS kullanıyor; bu da

sonuçları karşılaştırılabilir kılıyor.

Python bağımlılığı olmayan bir referans. Testler scikit-learn'ü çalıştırmıyor. scikit-learn

1.9.1'den alınmış sayıları sabit olarak içeriyor ve onlarla karşılaştırıyor: lojistik regresyon

olasılıkları 1e-5, PCA 1e-10 hassasiyetle. CI saf Swift olarak kalıyor ama "hesap doğru mu?"

sorusunun yine dışarıdan bir cevabı var.

Tekrarlanabilir rastgelelik. Bölmeler, bootstrap örnekleri, k-means++ başlangıcı ve ağ

ağırlıkları SplitMix64 tabanlı SeededGenerator'dan çekiliyor. Paket, standart kütüphanenin

random(in:using:) ve shuffle(using:) fonksiyonları yerine kendi indeks örneklemesini ve

Fisher–Yates karıştırmasını kullanıyor; böylece dizi araç zincirine bağlı değil. Random forest,

ağaçları DispatchQueue.concurrentPerform ile paralel eğitmeden önce her ağaç için sırayla bir seed

çekiyor. Bir test aynı seed'in aynı ormanı verdiğini

kontrol ediyor.

Çocukları ebeveynden sonra gelen dizi olarak ağaçlar. Karar ağacı, kökü ilk sırada olan bir

node dizisi olarak saklanıyor ve her çocuğun indeksi ebeveyninkinden büyük. Bu kural sayesinde kökten bir yaprağa yürümek en

fazla nodes.count adımda bitiyor. Class tabanlı bir ağaç yazması daha kolay olurdu, ama Codable,

Equatable ve Sendable için ek iş gerektirirdi ve yüklenen bir dosya döngü içerebilirdi.

Gerçek bir hata: uygulamayı çökerten model dosyası

Her modelin Codable olması, kaydedilmiş bir modelin bir dosyadan ya da ağdan gelebileceği

anlamına geliyor; yani decode bir güven sınırı. Matrix decode kodunun ilk sürümü values.count

ile rows * columns'u karşılaştırıyordu.

`e78b273` commit'i neyin yanlış

gittiğini anlatıyor: rows ve columns değerleri 2^32 (ya da 2^62 ve 4) olan bir dosyada bu

çarpım taşıyordu ve Swift'te tam sayı taşması programı durduruyor (trap). Özel hazırlanmış bir

model dosyasını okumak, hata fırlatmak yerine uygulamayı çökertiyordu.

Düzeltme Core/Validation.swift içindeki küçük bir yardımcı:

swift
1func checkedProduct(_ lhs: Int, _ rhs: Int) -> Int? {
2 guard lhs >= 0, rhs >= 0 else { return nil }
3 let (product, overflow) = lhs.multipliedReportingOverflow(by: rhs)
4 return overflow ? nil : product
5}

Artık checkedProduct(rows, columns) değer sayısına eşit değilse decode DecodingError

fırlatıyor; başlatıcılar da şekli adıyla anan bir mesajla duruyor. Parametreli bir test 2^32 × 2^32,

2^62 × 4 ve negatif şekilleri JSONDecoder'a veriyor ve trap değil hata bekliyor.

Aynı sınıftan sorunlar başka yerlerde de çıktı. Sürüm notlarına göre ağaç decode'u artık geriye

işaret eden çocuk bağlantılarını reddediyor (aksi halde tahmin sonsuz döngüye girebilirdi) ve

birbirine uymayan sinir ağı katmanları da reddediliyor; kodda Perceptron.swift, ağın parametre

sayısını aynı checkedProduct ile hesaplıyor. İlgili bir düzeltme,

`278f246`, regresyon metriklerinin

(MSE, MAE ve R²) NaN ve sonsuz değerlerde NaN skor döndürmek yerine hata fırlatmasını sağladı. Aynı

commit, bir sınıflandırma metriği olan logLoss'un NaN içeren olasılık satırlarını reddetmesini de

sağladı; bu satırlar daha önce clipping'den geçiyordu, çünkü max(NaN, eps) NaN döner.

İki küçük ders daha çıktı. Eski .gitignore, içinde models/ gibi makine

öğrenmesi kuralları olan genel bir şablondu; büyük/küçük harf duyarsız bir dosya sisteminde bu kural

Sources/SwiftAI/Models klasörüne de uyuyordu ve dosya değiştirilene kadar model protocol'leri

commit edilemedi (`be68a92`).

PR #19'da ise iOS derlemesi kırıldı, çünkü

örnek any Classifier<String> kullanıyordu; bu parametreli existential iOS 16 runtime'ı istiyor,

paket ise iOS 15'i destekliyor. Yerine tahmin closure'ı tutan küçük bir sarmalayıcı kondu

(`17235ce`).

Kullanım

Paketi Xcode'da File › Add Package Dependencies… menüsünden

https://github.com/muhittincamdali/SwiftAI.git adresiyle ya da Package.swift içinde

from: "2.0.0" ile ekleyebilirsin. README'deki hızlı başlangıç, paketle birlikte gelen 150 iris

çiçeği üzerinde bir random forest eğitiyor:

swift
1import SwiftUI
2import SwiftAI
3 
4struct ContentView: View {
5 var body: some View {
6 Text(irisSummary())
7 .padding()
8 }
9 
10 func irisSummary() -> String {
11 do {
12 // 1. Split the built-in iris flowers into training and test samples.
13 let (training, test) = try Dataset.iris.stratifiedSplit(testFraction: 0.2, seed: 42)
14 // 2. Train a random forest on the training samples.
15 let model = try RandomForestClassifier.fit(training, seed: 42)
16 // 3. Measure it on the test samples and classify a new flower.
17 let accuracy = try model.accuracy(on: test)
18 let species = try model.predict([6.3, 2.8, 5.1, 1.5])
19 return "Test accuracy: \(accuracy.formatted(.percent))\nNew flower: \(species)"
20 } catch {
21 return error.localizedDescription
22 }
23 }
24}

Feature'ların ölçeklenmesi gerektiğinde Pipeline, scaler'ı yalnız eğitim verisine fit ediyor;

böylece test verisi ona sızmıyor ve sonraki her örnek aynı şekilde ölçekleniyor:

swift
1let (training, test) = try Dataset.iris.stratifiedSplit(testFraction: 0.3, seed: 1)
2let model = try Pipeline.fit(training, transformer: StandardScaler.fit) { scaled in
3 try LogisticRegression.fit(scaled)
4}
5let report = try model.evaluate(on: test)
6print(report) // precision, recall and F1 per class
7print(report.confusionMatrix)

Örnekler Examples/ModelLab/ModelLab/ReadmeSamples.swift dosyasında duruyor; ModelLab örnek uygulaması bu dosyayı derliyor, test target'ı da onu bir

sembolik bağ üzerinden derleyip her örneği çalıştırıyor. README'deki bir örnek derlenmez hale

gelirse testler kırılıyor. v2.0.0 tag'inde swift test 20 suite içinde 133 test çalıştırıyor.

Sınırlar

  • Yalnız sayılar. Dataset, feature'ları [Double] olarak tutuyor. Kategorik sütun, eksik

değer (NaN reddediliyor) ve sparse matris yok; CSV dosyasında hedef dışındaki her sütun sayı

olmalı.

  • Küçük veri. Yayımlanmış bir benchmark yok ve k-en yakın komşu kaba kuvvetle çalışıyor. Büyük

veri setleri hedef değil.

  • Derin öğrenme değil. NeuralNetworkClassifier ve NeuralNetworkRegressor, Adam ve erken

durdurmayla eğitilen küçük çok katmanlı perceptron'lar. Evrişimli ve tekrarlayan ağlar ile GPU

eğitimi kapsam dışı.

  • Eksik modeller. README'deki yol haritası doğrusal destek vektör makinelerini, lasso ve

elastic-net regresyonu, polinom feature dönüştürücüsünü, gradient-boosted ağaçları ve doğrusal

modellerle ağaçların Core ML'e aktarımını listeliyor. Bunların hiçbiri henüz yok.

  • İmza değil, yapısal kontrol. Bir model dosyasını yüklemek şekilleri, değerleri ve yapıyı

kontrol ediyor. Dosyanın nereden geldiğini doğrulamıyor.

  • Güncel araç zinciri. Paket swift-tools-version: 6.2 kullanıyor; bu yüzden kullanan

projelerin Xcode 26 ya da üstüne ihtiyacı var. En düşük platformlar iOS 15, macOS 12, tvOS 15,

watchOS 8 ve visionOS 1; ModelLab örnek uygulaması iOS 17 ya da macOS 14 istiyor.

Kaynak kod: github.com/muhittincamdali/SwiftAI

Etiketler

#swift#machine-learning#swift-package#on-device#codable
Muhittin Çamdalı

Muhittin Çamdalı

Senior Mobile Engineer

12+ yıllık deneyime sahip Senior Mobile Engineer. iOS, Flutter ve React Native ile mobil ürünler geliştiriyorum; full-stack ve AI-native çalışıyorum.

iOS Geliştirme Haberleri

Haftalık Swift tips, SwiftUI tricks ve iOS best practices. Spam yok, sadece değerli içerik.

Onay e-postasındaki bağlantıyı açıp “Aboneliğimi onayla” düğmesine bastığında aboneliğin başlar. Bültende açılma/tıklama istatistikleri tutulur; dilediğin an tek tıkla ayrılabilirsin. Gizlilik

Paylaş

İlgili İçerik