iToverDose/Yazılım· 25 NISAN 2026 · 08:00

Derin Öğrenme Çerçevesi Rust ile Yapıldı - Bölüm 3: Crates.io'ya Giden Yol

Derin öğrenme çerçevesini Rust'ta yapılandırma ve crates.io'ya yayınlama süreci

DEV Community3 dk okuma0 Yorumlar

Derin öğrenme çerçevesini Rust'ta yapılandırmaya çalışırken, ilk olarak neden grafik tabanlı bir çerçevenin gerekli olduğunu açıkladım. Daha sonra, GPU arka ucunu wgpu kullanarak yazdım ve TransformerBlockı eğitmeyi başardım. Ancak, her iki yazı da aynı gerçeğe dikkat çekti: kod iyiydi, ancak proje diğer insanlar tarafından kullanılmaya hazır değildi.

Bu yazı, bu açığı kapatma sürecini anlatıyor. Altı aşama çalışma, v0.2.0'dan v0.3.1'e güncelleme ve şimdi bir crate olarak görünen bir proje.

Planımda altı aşama vardı:

  • 1. Aşama: Temizlik ve tutarlılık - tüm uyarıları gidermek.
  • 2. Aşama: API güvenilirliği - kullanıcıların HashMap ile elle yönetimini önlemek için deklaratif katman API.
  • 3. Aşama: GPU tamamlanması - her CPU işlemi için bir WGSL ikizi oluşturmak.
  • 4. Aşama: Performans (v0.5'e ertelendi).
  • 5. Aşama: Ekosistem - RoPE'nin doğru şekilde yapılması, Slice/Concat primitifleri, CI.
  • 6. Aşama: Önceki sürüm için cilalama - fmt, clippy, docs.rs, CNN örneği.

1. Aşama - 121 Uyarıdan Sıfıra

İlk yapacağım şey, cargo build --release --all-targets komutunu çalıştırmaktı. Çıktı bir tam ekran boyunca sürdü:

warning: rustyasg (bin "rustyasg") 121 uyarı (14 yinelenen) üretti warning: rustyasg (lib) 21 uyarı üretti

142 uyarı, sanki birisi bir yerlerde ilgisini kaybetti gibi görünüyordu, ancak bulduğum şey komikti: src/main.rs dosyası aşağıdaki satırlarla başlıyordu:

mod analysis; mod asg; mod autograd; mod gui_viewer; // ... yedi satır daha

Bu, ikili dosyayı tüm kütüphaneyi ayrı bir crate olarak derleme idi. Yani, main.rs tarafından dokunulmayan her bir pub struct nn/ içinde "hiç kullanılmadı" uyarısı verdi - ve onların çok sayıda olduğu gerçeğini göz önünde bulundurursak, bu durum 100 yanlış uyarının ortadan kaldırılmasına yol açtı. Onları use rustyasg::* ile değiştirdim.

Gerisi gerçek temizlikti: rand::thread_rng için rand::rng kullanmak, kullanılmayan importlar, let minus_one = lit_scalar(-1.0) gibi hiçbir zaman okunmayan değişkenler ve rotate_half fonksiyonu gibi RoPE'de bulunan ancak aslında sadece bir cos ekleyen bir yığın işlev.

2. Aşama - Deklaratif Katman API

Bu, en çok endişelendiğim değişiklikti, çünkü bu, her bir v0.2 kullanıcısı için bir kırılma değişikliği idi. main.rs dosyasına bakın:

let layer1 = Linear::new(&ctx, "layer1");
// ...
let mut initial_shapes = HashMap::new();
initial_shapes.insert("x".to_string(), (vec![4, 2], DType::F32));
initial_shapes.insert("layer1.weights".to_string(), (vec![2, 8], DType::F32));
initial_shapes.insert("layer1.bias".to_string(), (vec![1, 8], DType::F32));
// ...

if name.contains("w_q.weights") || name.contains("w_k.weights") || ... { shape = vec![embed_dim, embed_dim]; } else if name.contains("linear1.weights") { shape = vec![embed_dim, ff_hidden_dim]; }

Bu, dize eşleştirmesi ile parametre şekillerini belirleme şekliydi. name.contains("w_q") binary'de gördüğümde, Phase 2'nin ne olması gerektiğini anladım.

Çözüm: katmanların kendi şekil bilgilerini sahip olması gerekiyordu. Her bir nn::* yapıcısı boyutlar alır ve katman self-kaydetme ile GraphContext ile kayıt edilir:

pub fn new(ctx: &Rc<RefCell<GraphContext>>, name: &str, in_f: usize, out_f: usize) -> Self { let weights = Tensor::new_parameter_with_shape( ctx, &format!("{}{}{}", name, ".weights"), vec![in_f, out_f], Initializer::XavierUniform, ); // ve bias için de aynı şekilde... }

Arka planda GraphContext yeni bir parameter_meta: HashMap aldı, burada ParameterMeta şekil, dtype ve bir Initializer taşır. Ardından iki yardımcı yöntem döngüyü tamamlar:

ctx.build_shape_map(&input_shapes)
// → ShapeInference beslemesi
cctx.init_parameters(&mut runtime_data)
// → ağırlıkları örnekler

Ayrıca, dokuz standart başlatıcı ile nn::init yazdım - Sıfırlar, Birler, Sabit, Uniform, Normal, Xavier (uniform/normal), Kaiming (uniform/normal) - çünkü katmanlar kullanıcı adına başlatıcıları seçerse, varsayılanların iyi varsayılanlar olması gerekir.

Kullanıcı açısından fark şaşırtıcıdır. main.rs önce 270 satırdı ve el ile yazılmış 50 satırlık şekil_dispatch bloğu vardı. Phase 2'den sonra 225 satırdı ve şekil_dispatch tek bir satır:

ShapeInference::run_with_context(&mut graph, &ctx.borrow(), &input_shapes)?;

XOR örneği 275 satırdan 190 satıra düştü ve açıklık kaybı yaşamadan.

3. Aşama - GPU Tamamlanması

Phase 3'ün başlangıcında, cargo run --release -- --gpu komutunu TransformerBlock demo'sunda çalıştırdığınızda, aşağıdaki hata mesajı alırdınız:

thread 'main' panicked: UnimplementedOperation("node type not supported on GPU: LayerNorm { input: 0, gamma: 10, beta: 11, eps: 1e-5 }")

README, aylarca "✅ GPU arka ucu" demişti. Yalan söylüyordu. LayerNorm GPU'da bir bileşik işlem değil - özel bir NodeType - ve kimse WGSL shader'lerini yazmamıştı.

Onları yazdım. Sadece LayerNorm için dört shader:

  • LayerNorm (ileri): her satır için bir işçi.
  • LayerNormBackward (∂L/∂x): formül dx = inv_std * (dy·γ - mean(dy·γ) - x_norm·mean(dy·γ·x_norm)) - her satır için iki indirgeme geçişi önce fi.

Geleceğe yönelik olarak, derin öğrenme çerçevesini Rust'ta oluşturma ve geliştirme sürecinin önemli adımlarını tamamladık. Crates.io'ya yayınlama ve daha geniş bir topluluğa ulaşma hedefine ulaşmak için daha fazla çalışma yapılması gerekiyor. Ancak, bu aşamada elde edilen ilerleme, Rust topluluğunun derin öğrenme alanına katkıda bulunma potansiyelini gösteriyor.

Yapay zeka özeti

Rust'ta derin öğrenme çerçevesi oluşturma ve geliştirme süreci - crates.io'ya yayınlama

Yorumlar

00
YORUM BIRAK
ID #U66392

0 / 1200 KARAKTER

İnsan doğrulaması

9 + 3 = ?

Editör onayı sonrası yayına girer

Moderasyon · Spam koruması aktif

Henüz onaylı yorum yok. İlk yorumu sen bırak.