Starcoder2 Quantization Deneyi

Cahit Barkin Ozer
6 min readMay 6, 2024

Starcoder2'yle farklı nicemlerde (quantization) çıkarım (inference) yapıp çıktı kalitesi, çıkarım süresi ve kaplanılan gpu hafızası gibi değişkenlerini yorumluyoruz.

English:

Bu deneyde “bigcode/starcoder2–15b-instruct-v0.1” modelinin 32bit multi gpu, 32 bit single gpu, 16bit single gpu, 16 bit brain float single gpu, 8 bit single gpu, 4 bit single gpu şeklinde çeşitli quantizasyon formatlarında çalıştırılmıştır.

Inference kodu starcoder2–15b huggingface sayfasında söylenen şekilde hazırlanmıştır (8bit ve 4bit sonradan değiştirilmiştir): [https://huggingface.co/bigcode/starcoder2-15b]

Her model cevabından sonra kernel restart edilmiş ve böylece gpu hafızasının tamamen boşaldığı görülmüş sonra bir sonraki deneye geçilmiştir.

Modele verilen promptlar kısa tutulmuş, zero shot yapılmış, modellere sampling yapılmamış ve promptların çıktılar üzerinde etkiye sebep olmaması için promptlara prompt engineerin uygulanmamıştır.

Fp16 ile bf16 farkı nedir?

ENG:

“While bf16 has a worse precision than fp16, it has a much much bigger dynamic range. Therefore, if in the past you were experiencing overflow issues while training the model, bf16 will prevent this from happening most of the time.”

TR:

“Bf16'nın hassasiyeti FP16'ya göre daha kötü olsa da çok daha büyük bir dinamik aralığa sahiptir. Bu nedenle geçmişte modeli eğitirken taşma sorunları yaşıyorsanız bf16 çoğu zaman bunun olmasını engelleyecektir.”

[https://huggingface.co/docs/transformers/v4.16.2/en/performance]

Inference Kodları

Gerekli kütüphanelerin import edilmesi

Requirements.txt:

accelerate==0.28.0
bitsandbytes==0.43.0
transformers==4.39.0
huggingface-hub==0.21.4
python-multipart==0.0.7
torch==2.2.1

Imports:

import logging
import torch
import os
from transformers import AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig

Modelin yüklenme kısmı

32multi

Bu yapıda gpu memory’si tam olarak 2 yarıya ayrılarak çalışırlar.

os.environ["CUDA_VISIBLE_DEVICES"] = "4,5"
MODEL = "bigcode/starcoder2–15b-instruct-v0.1"
model = AutoModelForCausalLM.from_pretrained(MODEL, cache_dir="./model", device_map="auto")

32single

os.environ["CUDA_VISIBLE_DEVICES"] = "5"
model = AutoModelForCausalLM.from_pretrained(MODEL, cache_dir="./model").to("cuda")

Fp16

os.environ["CUDA_VISIBLE_DEVICES"] = "5"
model = AutoModelForCausalLM.from_pretrained(MODEL, cache_dir="./model", device_map="auto", torch_dtype=torch.float16)

Bf16

os.environ["CUDA_VISIBLE_DEVICES"] = "5"
model = AutoModelForCausalLM.from_pretrained(MODEL, cache_dir="./model", device_map="auto", torch_dtype=torch.bfloat16)

8bit

8bit ve 4bit quantizate ettiğimiz modeler ile inference yaparken uyarı alınmıştır, bu uyarı aratıldığında şu açıklama bulunmuştur:

ENG:

“An important part of Tensorflow is that it is supposed to be fast. With a suitable installation, it works with CPUs, GPUs, or TPUs. Part of going fast means that it uses different code depending on your hardware. Some CPUs support operations that other CPUs do not, such as vectorized addition (adding multiple variables at once). Tensorflow is simply telling you that the version you have installed can use the AVX (Advanced Vector Extensions) and AVX2 operations and is set to do so by default in certain situations (say inside a forward or back-prop matrix multiply), which can speed things up. This is not an error, it is just telling you that it can and will take advantage of your CPU to get that extra speed out.”

TR:

Tensorflow’un önemli bir kısmı hızlı olmasının gerekli olmasıdır. Uygun bir kurulumla CPU’lar, GPU’lar veya TPU’larla çalışır. Hızlı gitmenin bir kısmı, donanımınıza bağlı olarak farklı kod kullanması anlamına gelir. Bazı CPU’lar, vektörleştirilmiş ekleme (aynı anda birden fazla değişken ekleme) gibi diğer CPU’ların desteklemediği işlemleri destekler. Tensorflow size basitçe yüklediğiniz sürümün AVX (Gelişmiş Vektör Uzantıları) ve AVX2 işlemlerini kullanabileceğini ve belirli durumlarda (örneğin ileri veya geri prop matris çarpımı içinde) varsayılan olarak bunu yapacak şekilde ayarlandığını, bunun da hızı artırabileceğini söylüyor. şeyler kadar. Bu bir hata değil, sadece size ekstra hız elde etmek için CPU’nuzdan yararlanabileceğini ve yararlanacağını söylüyor.

Ayrıca inference hızının yavaşlığı ile ilgili bir ticket şu adreste açılmış: [https://discuss.huggingface.co/t/correct-usage-of-bitsandbytesconfig/33809/4]. Orada önerilen üzere “llm_int8_threshold=200.0” parametresi de koda eklenmiştir. Bu parametre koda eklendiğinde 1.5 dk gibi absürt inference süresi 30 küsür saniyelere düşmüştür. Bu süre yine de çoktur ancak absürt değildir.

os.environ["CUDA_VISIBLE_DEVICES"] = "5"
quantization_config = BitsAndBytesConfig(load_in_8bit=True, llm_int8_threshold=200.0)
model = AutoModelForCausalLM.from_pretrained(MODEL, cache_dir="./model", quantization_config=quantization_config, low_cpu_mem_usage= True)

4bit

Yalnızca load_in_4bit=True şeklinde kullanıldığında : “Input type into Linear4bit is torch.float16, but bnb_4bit_compute_dtype=torch.float32 (default). This will lead to slow inference or training speed.” Uyarısı alınmaktadır. Bunun anlamı direct 4bit float ağırlıklarla modelin kullanımının olmadığıdır bundan dolayı diğer parametreler de verilmektedir. Aşağıdaki parametreli yapıda model 4bit yüklenmekte ardından 16 bit compute edilebilir hale gelmektedir.

os.environ["CUDA_VISIBLE_DEVICES"] = "5"
quantization_config = BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_use_double_quant=True, bnb_4bit_quant_type="nf4", bnb_4bit_compute_dtype=torch.float16)
model = AutoModelForCausalLM.from_pretrained(MODEL, cache_dir="./model", quantization_config=quantization_config, low_cpu_mem_usage = True)

Modele isteğin atıldığı kısım

Bu kısımda yalnızca soru her deneyde değişir onun dışında kod parçası aynı kalır. Deney sonuçlarını etkilememesi için sampling (temperature, top_k ve top_p değerleri) aktive edilmemiştir.

tokenizer = AutoTokenizer.from_pretrained(MODEL)
inputs = tokenizer.encode("java staircase from stars", return_tensors="pt").to("cuda")
#outputs = model.generate(inputs, max_new_tokens=640, pad_token_id=tokenizer.eos_token_id, do_sample=True, temperature=0.1, top_k=50, top_p=0.95)
outputs = model.generate(inputs, max_length=512, pad_token_id=tokenizer.eos_token_id)
answer = tokenizer.decode(outputs[0], skip_special_tokens=True)
print(answer)

1.Deney: “Java staircase from stars”

32multi

Inference süresi 25.9s, cevap kalitesi orta(yıldız yerine hashtag kullanılmış), gpu hafızası 31.374Gb + 31.372Gb = 62.748Gb

32single

Inference süresi 23.4s, cevap kalitesi orta(yıldız yerine hashtag kullanılmış), gpu hafızası 62.392Gb

Fp16

Inference süresi 17.0s, cevap kalitesi orta(yıldız yerine hashtag kullanılmış), gpu hafızası 31.430Gb

Bf16

Inference süresi 17.7s, cevap kalitesi orta(yıldız yerine hashtag kullanılmış), gpu hafızası 31.414Gb

8bit

Inference süresi 36.8s, cevap kalitesi iyi, gpu hafızası 10.020Gb

4bit

Inference süresi 35.1, cevap kalitesi iyi (yıldız yerine hashtag kullanılmış), gpu hafızası 10.020Gb

2.Deney: “A Python FastAPI service app that does create read update delete operations on strings that are called prompt”

Bu örnekte Python ile çalışılmış ve biraz daha yaratıcılığa imkan verilmiştir.

32multi

Inference süresi 22.7s, cevap kalitesi iyi(kurulum adımları ve URI’lar verildikten sonra kod veriliyor), gpu hafızası 31.472Gb + 31.472Gb = 62.944 Gb

32single

Inference süresi 22.8s, cevap kalitesi iyi, gpu hafızası 62.392 Gb

Fp16

Inference süresi 16.6s, Cevap kalitesi iyi, gpu hafızası 31.430Gb

Bf16

Inference süresi 16.3s, Cevap kalitesi iyi, gpu hafızası 31.430Gb

8bit

Inference süresi 34.7, Cevap kalitesi orta, gpu hafızası 10.020Gb

4bit

Inference süresi 34.7s, Cevap kalitesi orta, gpu hafızası 10.020Gb.

Sonuç

Cevap kalitesi nicemler arasında değişiklik gösterir ve her model için ayrı ayrı belirtilmiştir. Fp16 ve Bf16 nicemleri, tüm deneylerde en hızlı çıkarım süresine sahiptir. 8bit ve 4bit modeller, en az GPU hafızasını kullanırken, çıkarım süresi de en uzundur. Pytorch’un bu sayfasında [https://pytorch.org/docs/stable/quantization.html] nicemli modellerin daha hızlı olduğu belirtilmiştir bundan dolayı burada yazılımsal (BitsAndBytesConfig veya diğer sınıflarda veya bu sınıfların kullanımında) veya donanımsal bir anomali olduğu sonucuna varılmıştır.

Eğer bunun neden olabileceğine dair bir tahmininiz varsa yorumlarda belirtirseniz sevinirim.

--

--

Cahit Barkin Ozer

Daha fazla şey öğrenmek ve daha iyi olmak isteyen bir yazılım mühendisi.