Geliştirme
Uzantı oluşturma
Scellis sahiplik çizgisini alışılmadık bir yere çeker: Bakımcı yalnızca üç şeyin sahibidir — gramerin, denetleyicinin ve referans oracle'ının. Başka hiçbir şeyin değil. Her örnek sizindir. Bakımcının hesaplayabildiği her şeyi arayüzden siz de yazabilirsiniz — motor yaması olmadan, onay kuyruğu olmadan. Tasarımın arkasındaki ilke açık sözlüdür: “bir kullanıcı bensiz bir Laplace operatörü yazamıyorsa, zemin benimdir, onun değil.” Bu sayfa bu iddianın pratik turudur: neler yazılabilir, yazılmış bir op somut olarak neye benzer, bir çekirdek güveni nasıl kazanır — ve kodunuz Catalog'da zaten var olanların üzerine nasıl kurulur.
Yazılabilir yüzey#
Yazılabilir yüzey, platformun kendi söz dağarcığıdır — uçtan uca; kenara vidalanmış bir eklenti nişi değil:
- Hesaplama: bloklar — gövdesi veri-olarak-graf olan kompozit bloklar ve sandbox içinde çalışan fonksiyon blokları — artı şekil ve tip davranışını bildiren op'lar ve CPU referanslarıyla eşlenmiş GPU çekirdekleri.
- Eğitim: gradyan kuralları, optimizer'lar, zamanlayıcılar, kayıp fonksiyonları, metrikler, PEFT adaptör türleri ve iş birlikli eğitimin üzerinde koştuğu toplulaştırma stratejileri.
- Arayüz ve veri: görüntüleyiciler, bağlayıcılar, biçim codec'leri, modeller, veri kümeleri — ve bunların hepsini taşıyan Pack'ler.
Bakımcının elinde tuttuğu tam olarak üç gramerdir: op'ların sözleşmelerini bildirdiği bir şekil/imza dili; depolama tamponlarını, uniform'ları ve workgroup paylaşımlı geçici alanı kapsayan bir tampon-bağlama ABI'si; ve bir backward (VJP) temsili. Geri kalan her şey bu gramerlerin üzerine yazılmış birer örnektir — ve motor gramerleri genel biçimde yorumladığı için dispatch anında bir yerleşiği bir kullanıcı varlığından ayırt edemez. Fark, katalogdaki bir köken rozetinden ibarettir; asla ayrı bir kod yolu değildir.
Yazılmış bir op'un anatomisi#
Yazarlık, Studio'nun op şemasından ürettiği bir formda gerçekleşir — aynı kaydı Copilot da taslak olarak hazırlayabilir, çünkü aynı API üzerinden yazar. Altta yatan kaydın tek bir biçimi vardır:
- name: user/ada/mish # namespaced — never shadows a builtin
version: 1
summary: "Mish activation: out = a * tanh(softplus(a))"
taxonomy: webir.op.elementwise
inputs: [{ name: a, dtype: [f32], shape: ["..."] }]
outputs: [{ name: out, dtype: [f32], shape: ["..."] }]
tolerance: { class: tight } # justified against the op's semantics
determinism: { debug: deterministic, prod: deterministic_within_tolerance }
gradients: { kind: elementwise, vjp_rule: "grad_out * mish'(a)" }
kernels: { forward: [{ id: user/ada/mish_f32, when: { dtype: f32 } }] }Her alan denetlenen bir sözleşmedir, belgeleme değil. Kimlik ad-alanlıdır (user/<owner>/<name>): bir kullanıcı op'u yerleşiğin yanında durur, asla onun yerinde değil. Şekil dizgileri yorumlanan bir imzadır — çıktı boyutu veri değerlerine bağlı olan bir op bunu, en kötü durum sınırıyla birlikte açıkça bildirir; bellek böylece planlanabilir kalır. Tolerans sınıfı op'un anlamsal kategorisine karşı gerekçelendirilmek zorundadır: bir matris çarpımı, uygunluk denetiminden kaçmak için loose beyan edemez. Determinizm de kademe kademe bildirilir — debug, prod, fast — asla sessizce varsayılana düşmez.
Çekirdek ve referansı#
Yazılan çekirdekler kısıtlı bir lehçe değildir. Bağlama ABI'si okunan ve yazılan depolama tamponlarını, uniform'ları ve workgroup paylaşımlı geçici alanı kapsar — yani karo düzenli bir matris çarpımı, bir indirgeme ya da bir stencil yazılabilirdir; yalnızca eleman bazlı bir eşleme değil. Yukarıdaki op için asgari bir forward çekirdeği:
@group(0) @binding(0) var<storage, read> in0 : array<f32>;
@group(0) @binding(1) var<storage, read_write> out : array<f32>;
@group(0) @binding(2) var<uniform> p : Params;
@compute @workgroup_size(256, 1, 1)
fn main(@builtin(global_invocation_id) gid : vec3<u32>) {
let i = gid.x;
if (i >= p.outNumel) { return; }
let x = in0[i];
out[i] = x * tanh(log(1.0 + exp(x))); // must match the reference within "tight"
}Güven, eşleme kuralıyla başlar. WGSL'in yanına bir referans implementasyonu koyarsınız — kapalı bir skaler gramerde ya da daha düşük güven tavanıyla sandbox JS olarak. Uygunluk koşucusu test durumları üretir, ikisini de çalıştırır ve beyan edilen tolerans sınıfı içinde uyum ister. Geçmek, çekirdekle birlikte yolculuk eden ve katalogda görünen hash'e bağlı bir ConformanceReceipt üretir — doğruluk yüzeyinde her yerleşiği denetleyen rejimin ve altındaki IR merdiveninin ta kendisi.
Dürüst bir ayrıntı: Receipt profile bağlıdır. Eşlemeyi yalnızca üzerinde koştuğu GPU zarfında kanıtlar; farklı bir cihaz sınıfında denetim yerelde yeniden koşar. Receipt'ler asla içe aktarılmış güven olarak yolculuk etmez — bu, test edilenden fazlasını iddia etmek olurdu.
Not
Uygunluk, güvenilir etkinleştirmeyi ve paylaşmayı kapılar — sizin kendi döngünüzü asla. Henüz uygunluk kazanmamış çekirdeğinizi kendi cihazınızda her zaman çalıştırabilirsiniz: yazın, çalıştırın, inceleyin, düzeltin, yeniden çalıştırın.
Gradyanlar ve reducer'lar da güveni kanıtla kazanır#
Bildirilen bir backward, sıradan bir kompoze op-grafıdır — forward ile aynı ifade gücünde — ve sizin kendi forward'ınıza karşı sonlu farklarla, zorunlu bir negatif kontrol dahil, gradyan denetiminden geçirilir. Açıkça söylenir: gradyan denetimi güçlü bir gerek koşuldur, biçimsel bir kanıt değil. Kullanıcı beyanlı bir reducer bir adım daha ileri gider — beyan ettiği cebir (birleşme, değişme) etkinleştirmeden önce özellik testinden geçer; çünkü yanlış beyan edilmiş bir birleştirici, ağaç indirgemesiyle sessizce yanlış sayılara varırdı.
Kataloğu bir kütüphane gibi yeniden kullanın#
Yazdığınız bir gövde sıfırdan değil, kataloğun tamamından başlar. Tasarım ilkesi şöyle okunur: “pandas'ı içe aktarıp bir DataFrame kullanmak gibi” — herhangi bir yazılmış gövdenin içinden diğer varlıkları tek bir denetimli yüzey üzerinden çağırırsınız:
// Inside any authored body: the governed call surface.
const y = ctx.op("core/softmax", x, { axis: -1 }); // a builtin, resolved by name
const z = ctx.call("user/kim/zscore@3", y); // another author's block
const s = ctx.tensor.matmul(z, w); // the tensor-algebra surface
// Every reference resolves through YOUR pinned uses closure —
// never against "whatever happens to be newest".Defter tutmak sizin işiniz değildir. Bağımlılık kenarları çağrı noktalarınızdan otomatik türetilir ve yazım anında çözülen sürümlere tam olarak sabitlenir; lockfile bunların hash'lerini kaydeder. Sonrasında her çalışma zamanı çağrısı bu sabitleme üzerinden çözülür — çağrı yüzeyi ile bildirilen kapanış aynı kümedir: çağırdığınız şey, tam olarak kilitlediğiniz şeydir. Yazılan bir varlık bu yüzden kuruluş gereği yeniden üretilebilirdir ve çevrimdışı çalıştırması güvenlidir; bir bağımlılık döngüsü ya da çözülemeyen bir sabitleme yüksek sesle reddedilir — asla “en yeni kazanır”a çözülmez.
İki özellik kompozisyonu dürüst tutar. Etkiler kapanış boyunca geçişlidir: saf beyan edilmiş bir fonksiyon, ağ etkisi taşıyan bir yardımcıyı sessizce çağıramaz; çağrılanın etkileri bütün zincire sayılır ve onay bu birleşim üzerinden istenir. Güven ise temkinli birleşir: çağrılan, çağrı zincirindeki en katı güven kademesinde çalışır — güvenilmeyen kod, güvenilen çağıranlar üzerinden kendini aklayamaz.
Tek denetim, tek çıta — ve dürüst adlar#
Yazılan her varlık, kaydının tamamı üzerinde yazarlık denetiminden geçer — oluşturulurken ve her düzenlemede yeniden. Bu, her yerleşiği denetleyen denetimin ta kendisidir: eksik ya da kısmi bilgi reddedilir ve ret, neyin eksik olduğunu adıyla söyler. Yerleşikler değişmezdir; birini “düzenlemek” size ait, kökeni kayıtlı, birinci sınıf bir kopya fork'lar. Kendi varlıklarınızı ise aynı doğrulanmış yol üzerinden yerinde düzenlersiniz.
Geçersiz kılma ve adlandırma da dürüst kalır. Yazılabilir bir bağlama sözleşmesi bildiren her op geçersiz kılınabilir — geçersiz kılma kümesi bir katalog sorgusudur, sabit kodlanmış bir liste değil — ve kendi cihazınızda çalışma alanınızın çekirdeği kurulu Pack'inkini, o da yerleşiği geçer. Ama bir kullanıcı op'u asla bir yerleşiğin kimliğine bürünemez: yazılan kimlikler user/<owner>/<name> altında yaşar ve çıplak bir yerleşik adı her zaman core op'a çözülür. Geçersiz kılma yerel bir dispatch tercihidir; kimliğe bürünme yapısal olarak kapalıdır.
Yayımlama ayrı bir adımdır#
Güven kademeleri — unverified, community, verified, official — yapıt başına kazanılır ve yazarlıktan bağımsızdır: kullanıcı varlıkları verified kazanabilir. Bir varlık cihazınızdan ayrılmaya hazır olduğunda onu paketler, tarayıcınızda imzalar ve yayımlama kapılarından geçirirsiniz: çözülmüş bir lockfile, geçerli olduğu yerde uygunluk kanıtı, eksiksiz üstveri ve açık bir lisans. Bu yol — ve karşı tarafta kuranların ve satın alanların ne gördüğü — Pack'ler ve yayımlama sayfasının konusudur. Yazdığınız şey bir eğitim bileşeniyse artık Model View seçicilerinde, hazır gelen her bileşen gibi görünür — bkz. Tarayıcıda model eğitme.