RPC Kullanarak CUDA + CUDA ile LLM Çıkarımı


RPC Kullanarak CUDA + CUDA ile LLM Çıkarımı

Giriş:

Daha önce CUDA ile SYCL koşan iki ekran kartını RPC üzerinden birleştirip test etmiştik. Bu denemeden sonra CUDA + CUDA yaptığımda nasıl bir sonuç alabileceğimi merak ettim. O sebeple laptop üzerindeki 4080 mobile gpuyu bu denkleme eklemeye karar verdim. Yani İntel A770 dışarı, 4080 Mobile içeri şeklinde ilerleyelim dedik. 4080 tarafında bir VM passthrough yerine direkt docker üzerinden kullandık. 1080ti tarafında ise aradaki kubernetesi kaldırıp 1080ti bir VM de passthrough ve Ana RPC sunucusu bir başka VM'de işleyecek şekilde ayarladık.

Bir önceki testimize kıyasla 4080 zaten laptopta mevcut kullanım altında, ekran ona emanet. Bu sebeple vrami tamamen kullanamıyoruz, bu tarafta gpu kullanımını da biraz sorgulayarak kabul etmekte fayda var. Total olarak 23GB gibi bir vram mevcut, fakat efektif kullanımda bunu 18GB gibi düşünebiliriz. Bu sebeple tercih ettiğimiz model de değişecek.

Altapıyı hatırlayalım ve link hızlarımıza bakalım.

root@virtbase:~# lspci | grep -i vga
0e:00.0 VGA compatible controller: NVIDIA Corporation GP102 [GeForce GTX 1080 Ti] (rev a1)

root@virtbase:~# lspci -vv -s 0e:00.0 | grep -E "LnkCap:|LnkSta:"
        LnkCap: Port #2, Speed 8GT/s, Width x16, ASPM L0s L1, Exit Latency L0s <512ns, L1 <4us
        LnkSta: Speed 2.5GT/s (downgraded), Width x4 (downgraded)

01:00.0 VGA compatible controller: NVIDIA Corporation AD104M [GeForce RTX 4080 Max-Q / Mobile] (rev a1)
root@EWUL13:~# lspci -vv -s 01:00.0 | grep -E "LnkCap:|LnkSta:"
        LnkCap: Port #0, Speed 16GT/s, Width x16, ASPM L1, Exit Latency L1 <16us
        LnkSta: Speed 2.5GT/s (downgraded), Width x8 (downgraded)

Gelişme:

1080ti için konteynerimizde bir değişiklik yapmadık, aynı konteyneri imajını kullanmaya devam edebilir. Zamanında Dockerfile içerisinde bir commite adreslemediğimiz için mevcut en güncel commit ile derliyorduk, bu sebeple bütün konteynerler farklı llama.cpp versiyonlarla derlenmesin diye tekrar eş zamanlı olarak yeniden derledik.

4080 tarafında ise 1080ti a kıyasla bir üst CUDA versiyonu tarafından destekleniyor yani driver (610) ve cuda(13.3.1) versiyonu farklı. Bunun için de ona yeni bir dockerfile içerisinde CUDA 13.3.1 versiyonu ve aynı runtime ile konteyner oluşturduk.

Ana RPC sunucusu da aynı şekilde bir değişikliğe uğramadan sadece yeniden konteyner derlendi ve kullanıldı.

Bütün bu tarafta değişen şeyler şu şekilde.

Ana RPC sunucusunun:

  • OpenStack/Magnum dan dışarıya çıktı, host üzerinde direkt bir VMe geçti. İç-içe sanallaştırma azaldı.
  • RPC için kullandığı ip adresleri değişti
  • LLM modeli değişti

1080ti:

  • OpenStack Magnum dan dışarıya çıktı, host üzerinde direkt bir VMe geçti. İç-içe sanallaştırma azaldı.

4080 mobile:

  • Host OS üzerinde direkt bir konteyner içerisinde, işletim sisteminin kullanımı ile beraberce LLM koşuyor (Xorg, Firefox karta ortak...).

Sonuç:

Peki bu sefer ne oldu. Modelimiz unsloth tarafından gpt-oss-20b-Q4_K_M.gguf.

Yükleme sonrası 4080 tarafında kullanılan vram 7208MiB, 1080ti tarafında kullanılan vram 7450Mib yani totalde 14.3GiB gibi bir modeli dağıtık şekilde 2 gpuya yüklemiş olduk.

Dikkat çeken şöyle bir durum mevcut. CUDA ile llama.cpp derlediğimizde token üretimini hızlandırmak için bir graph oluşturduğunu anlıyoruz, fakat GPU versiyonlarımız ve CUDA tarafında bunlarca kullanılan/sağlanan özelliklerden dolayı birisi bu graph özelliğini desteklerken diğeri desteklemiyor. O sebeple konteynerlarda şöyle loglar görüyoruz. Bunu yaşamamak için ikisinde de graph özelliğini rpc derlerken kapatmak mantıklı olabilir, denklemden bir değişken daha çıkmış olacaktır fakat 4080 tarafında en ufak bir fayda dahi gösteriyorsa bunu da kaçırmış oluruz. Ha ayrıca bu tarafta da Memory Leak olduğuna dair kapanmamış bir issue mevcut.

4080mobile:
Accepted client connection
ggml_backend_cuda_graph_compute: CUDA graph warmup complete
ggml_backend_cuda_graph_compute: CUDA graph warmup reset
ggml_backend_cuda_graph_compute: CUDA graph warmup complete

1080ti:
Accepted client connection
ggml_cuda_graph_set_enabled: disabling CUDA graphs due to GPU architecture
ggml_cuda_graph_set_enabled: disabling CUDA graphs due to GPU architecture

CUDA + SYCL kullandığımızda 7 token saniye gibi bir yere adreslemiştik, gpularımız ise çok düşük kullanımlarla çalışmıştı. CUDA + CUDA için şimdi duruma bir göz atalım.

llama-server  | 26.07.321.601 I slot print_timing: id  3 | task 1203 | n_decoded =   2268, tg =  50.24 t/s, tg_3s =  47.92 t/s
llama-server  | 26.10.337.029 I slot print_timing: id  3 | task 1203 | n_decoded =   2418, tg =  50.21 t/s, tg_3s =  49.74 t/s
llama-server  | 26.13.341.406 I slot print_timing: id  3 | task 1203 | n_decoded =   2562, tg =  50.07 t/s, tg_3s =  47.93 t/s
llama-server  | 26.16.356.827 I slot print_timing: id  3 | task 1203 | n_decoded =   2707, tg =  49.96 t/s, tg_3s =  48.09 t/s
llama-server  | 26.17.132.543 I slot print_timing: id  3 | task 1203 | prompt eval time =    2047.80 ms /   972 tokens (    2.11 ms per token,   474.66 tokens per second)
llama-server  | 26.17.132.549 I slot print_timing: id  3 | task 1203 |        eval time =   54956.09 ms /  2745 tokens (   20.02 ms per token,    49.95 tokens per second)
llama-server  | 26.17.132.550 I slot print_timing: id  3 | task 1203 |       total time =   57003.89 ms /  3717 tokens
llama-server  | 26.17.132.550 I slot print_timing: id  3 | task 1203 |    graphs reused =       3917

Bu sefer kullanılan teknoloji değişmediği için, RPC üzerinden git-gellerde bir tercüme gereksinimi yaşanmadı. Teorik performansta A770'in değerleri 4080 Mobile değerlerinin üzerinde aslında, fakat kullanılan ortamın CUDA tarafında olan merkeziliği ve Nvidianın yıllardır bu alanın öncüsü olması tabiki muazzam etkilere sebep oluyor. Bir önceki denememizde 7 token saniye gibi bir aralıktaydık, burada ise 48-50 token saniyeleri görüyoruz. Bütün bunlar gerçekleşirken gpu kullanım oranları ise bir önceki denememize göre farklılık gösteriyor.

GPUların her ikisi içinde minimum kullanım %25 seviyesinde kalıyor, ortalama kullanım her zaman bunun üzerinde. Göz kararı söyleyebilleceğim 4080 için %30 oturduğu değer oluyor, 1080ti tarafında ise bu durum %30 ve sürekli üzerine çıktığı durumlar oluyor hatta 1080ti %70lere varan anlık yüklenmeler bile görebiliyor.

Aynı modeli aynı context boyutu ile (131072) sadece laptopta çalıştırıp 10 layer i GPU üzerinde olacak şekilde ayarlarssak eğer, 30-32 token saniye gibi bir değer görüyoruz. Burada da GPU kullanımı %25ler civarında oluyor ve üretebildiğimiz tarafta 30 token saniye gibi bir değer görebiliyoruz. Tabiki bu gözlemde sistem CPU ve RAM yüklerini tamamen görmezden geliyorum, 13980hx 64GB-5200 gibi bir sistemden bahsediyoruz.

Yöntem GPU Kul. %Maks GPU Kul. %Min Token Saniye
CUDA + SYCL (A770/1080TI) 40/12 10/3 7-8
CUDA + CUDA (4080/1080TI) 30/70 25/25 48-50

İşin özetine gelecek olursak eğer, hala son kullanıcıya verecek kıymette olduğunu düşünmüyorum. Ana RPC sunucusu sıkça hataya düşebiliyor, hatta bu hataları prompttaki bazı kelimelere bile adresledim diyebilirim, evet o kelimeyi gönderdiğim tüm promptlarda ana RPC sunucusu çöküyor :) Fakat bu bir kenara bırakıp 30 token saniyeden 48 token saniyeye çıkışı düşünecek olursak:

  • Denemeler yapılacak ortamlarda kullanılabilir
  • Gerçekten vram ihtiyacımız olan durumlarda kullanılabilir
  • Sadece bu yol çıkış yolumuz olacak ise kullanılabilir

Bu maddeler haricinde bence hala yeri ve zamanı değil. Tabi tüm bunları söylerken aradaki networkün 1G olduğunu da söylemekte fayda var.

Bir önceki CUDA + SYCL yazısına aşağıdan ulaşabilirsiniz:

Referanslar:

Teşekkür:

Ana fotoğraf: Michael Jasmund orijinaline Unsplash üzerinden ulaşabilirsiniz.

Previous