İçindekiler
- Problem
- Tasarım kararları ve alternatifler
- Gerçek bir hata: uygulamayı çökerten model dosyası
- Kullanım
- Sınırlar
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 : product5}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 SwiftUI2import SwiftAI3 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.localizedDescription22 }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 in3 try LogisticRegression.fit(scaled)4}5let report = try model.evaluate(on: test)6print(report) // precision, recall and F1 per class7print(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.
NeuralNetworkClassifierveNeuralNetworkRegressor, 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.2kullanı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

