Model formatlari: pickle xavfi va ONNX
Notanish odamdan kelgan fayl
Elektron pochtangizga xat keldi. Ilovada hisobot.exe fayli bor. Yuboruvchi — notanish.
Ishga tushirasizmi?
Albatta yo'q. Har bir odam biladi: notanish .exe faylini ochish — kompyuteringizni
begonaga topshirish demak.
Endi ikkinchi savol. Hamkasbingiz sizga model.pkl yubordi. Yoki internetdan tayyor model
yuklab oldingiz. Uni yuklaysizmi?
Ko'pchilik hech o'ylamay yuklaydi. Chunki u "shunchaki ma'lumot fayli" ko'rinadi.
Bu noto'g'ri. pickle fayli — ma'lumot emas, u ko'rsatmalar ro'yxati. Uni yuklash
.exe ishga tushirish bilan bir xil xavfga ega.
Shu bobda buni isbotlaymiz: hech qachon chaqirmagan funksiyangiz pickle.loads() paytida
o'zi bajariladi. Ekranda uning izi qoladi.
pickle — bu kod, ma'lumot emas
Python da model saqlashning odatiy usuli — pickle yoki joblib. Ikkalasi ham bir xil formatda
ishlaydi va ikkalasining ham bir xil xavfi bor.
Asosiy fakt: pickle.load() kod bajaradi. U ma'lumotni o'qimaydi — u obyektni qayta
quradi, va qayta qurish jarayoni istalgan funksiyani chaqirishi mumkin.
Buni xavfsiz ko'rsatamiz — zararli emas, shunchaki kutilmagan amal:
import pickle class ZararsizKorinadi: """Fayl ochilganda __reduce__ chaqiriladi va u ISTALGAN narsani qaytarishi mumkin.""" def __reduce__(self): # zararli emas: shunchaki matn qaytaradigan funksiya chaqiriladi return (str.upper, ("men yuklanishda bajarildim",)) xom = pickle.dumps(ZararsizKorinadi()) print("fayl hajmi:", len(xom), "bayt") print("yuklash natijasi:", pickle.loads(xom)) print() print("=> pickle.loads() FUNKSIYA CHAQIRDI. Biz uni chaqirmadik.")
fayl hajmi: 99 bayt yuklash natijasi: MEN YUKLANISHDA BAJARILDIM => pickle.loads() FUNKSIYA CHAQIRDI. Biz uni chaqirmadik.
str.upper o'rniga os.system yoki subprocess.run bo'lishi mumkin edi. Fayl ochilishi bilanoq.
Shuning uchun qoida qat'iy:
import pandas as pd show(pd.DataFrame([ {"holat": "O'z modelingiz, o'z serveringiz", "pickle xavfsizmi": "HA", "izoh": "Manbaga ishonasiz"}, {"holat": "Hamkasb yuborgan model", "pickle xavfsizmi": "EHTIYOT", "izoh": "Uning mashinasi buzilgan bo'lishi mumkin"}, {"holat": "Internetdan yuklangan model", "pickle xavfsizmi": "YO'Q", "izoh": "Hech qachon. ONNX yoki safetensors ishlating"}, {"holat": "Foydalanuvchi yuklagan fayl", "pickle xavfsizmi": "YO'Q", "izoh": "To'g'ridan-to'g'ri masofaviy kod bajarish"}, ]))
| holat | pickle xavfsizmi | izoh |
|---|---|---|
| O'z modelingiz, o'z serveringiz | HA | Manbaga ishonasiz |
| Hamkasb yuborgan model | EHTIYOT | Uning mashinasi buzilgan bo'lishi mumkin |
| Internetdan yuklangan model | YO'Q | Hech qachon. ONNX yoki safetensors ishlating |
| Foydalanuvchi yuklagan fayl | YO'Q | To'g'ridan-to'g'ri masofaviy kod bajarish |
22-bobdagi skops_trusted_types talabini eslang — MLflow aynan shu muammoni yumshatish uchun
qo'shgan.
Uch xil format
diagramma( { "joblib / pickle": (0, 0, 2.8, 1.1, "xizmat"), "ONNX": (3.6, 0, 2.8, 1.1, "saqlash"), "safetensors": (7.2, 0, 2.8, 1.1, "saqlash"), "Kod bajaradi\n(XAVF)": (0, 2.2, 2.8, 1.0, "oddiy"), "Faqat graf\n(xavfsiz)": (3.6, 2.2, 2.8, 1.0, "oddiy"), "Faqat vaznlar\n(xavfsiz)": (7.2, 2.2, 2.8, 1.0, "oddiy"), }, [ ("joblib / pickle", "Kod bajaradi\n(XAVF)"), ("ONNX", "Faqat graf\n(xavfsiz)"), ("safetensors", "Faqat vaznlar\n(xavfsiz)"), ], nom="model_formatlari.png", kenglik=12, izoh="ONNX va safetensors kod saqlamaydi — shuning uchun yuklash xavfsiz.", )

ONNX va safetensors kod saqlamaydi — shuning uchun yuklash xavfsiz.
| Format | Nima saqlaydi | Xavfsizmi | Til |
|---|---|---|---|
pickle / joblib |
Python obyekti + kod | Yo'q | Faqat Python |
| ONNX | Hisoblash grafi | Ha | C++, Java, Go, JS... |
| safetensors | Faqat tensorlar | Ha | Asosan chuqur o'rganish |
| PMML | XML modeli | Ha | Eski, cheklangan |
Modelni ONNX ga o'tkazamiz
shu faylni yaratingsrc/quvur/format.py
"""Model formatlari: joblib va ONNX o'rtasida o'tkazish.""" from pathlib import Path from typing import Any import numpy as np def onnx_ga(model, xususiyat_soni: int, yol: str | Path) -> Path: """sklearn modelini ONNX ga o'tkazadi.""" from skl2onnx import to_onnx namuna = np.zeros((1, xususiyat_soni), dtype=np.float32) onx = to_onnx(model, namuna, options={id(model): {"zipmap": False}}) p = Path(yol) p.write_bytes(onx.SerializeToString()) return p def onnx_sessiya(yol: str | Path): """ONNX modelini yuklaydi. Hech qanday kod bajarilmaydi.""" import onnxruntime as ort s = ort.InferenceSession(str(yol), providers=["CPUExecutionProvider"]) return s def onnx_ehtimol(sessiya, X) -> np.ndarray: """Broker ehtimolini qaytaradi.""" kirish = sessiya.get_inputs()[0].name chiqish = [o.name for o in sessiya.get_outputs()] natija = sessiya.run(chiqish, {kirish: np.asarray(X, dtype=np.float32)}) ehtimollar = natija[-1] return np.asarray(ehtimollar)[:, 1]
Avval model borligiga ishonch hosil qilamiz (bu bobni alohida o'qiyotgan bo'lsangiz ham ishlashi uchun):
python3 -c " import sys, pathlib; sys.path.insert(0, 'src') if not pathlib.Path('sinov_model.joblib').exists(): import joblib, pandas as pd from sklearn.ensemble import RandomForestClassifier from sklearn.model_selection import train_test_split from quvur.xususiyat import tayyorla d = pd.read_csv('../datasets/ijara.csv') x, y = tayyorla(d), d['broker'] Xtr, _, ytr, _ = train_test_split(x, y, test_size=0.25, stratify=y, random_state=42) m = RandomForestClassifier(n_estimators=150, min_samples_leaf=3, random_state=42, n_jobs=1).fit(Xtr, ytr) joblib.dump(m, 'sinov_model.joblib') print('model yaratildi (25-bobdagidek)') else: print('model allaqachon bor') "
model yaratildi (25-bobdagidek)
python3 -c " import sys; sys.path.insert(0, 'src') import joblib, pandas as pd from quvur.format import onnx_ga from quvur.xususiyat import XUSUSIYATLAR m = joblib.load('sinov_model.joblib') p = onnx_ga(m, len(XUSUSIYATLAR), 'model.onnx') print('ONNX yozildi:', p.name, p.stat().st_size // 1024, 'KB') print('joblib :', __import__('pathlib').Path('sinov_model.joblib').stat().st_size // 1024, 'KB') "
ONNX yozildi: model.onnx 6970 KB joblib : 14368 KB
Natijalar bir xilmi
Format o'zgarganda bashorat o'zgarmasligi kerak. Buni tekshirish majburiy:
python3 -c " import sys; sys.path.insert(0, 'src') import joblib, numpy as np, pandas as pd from quvur.format import onnx_sessiya, onnx_ehtimol from quvur.xususiyat import tayyorla d = pd.read_csv('../datasets/ijara.csv').head(500) x = tayyorla(d) m = joblib.load('sinov_model.joblib') sk = m.predict_proba(x)[:, 1] s = onnx_sessiya('model.onnx') on = onnx_ehtimol(s, x.values) farq = np.abs(sk - on) print(f'eng katta farq : {farq.max():.2e}') print(f'o\'rtacha farq : {farq.mean():.2e}') print(f'bir xil qaror : {int((( sk>0.5)==(on>0.5)).sum())} / {len(sk)}') "
eng katta farq : 4.61e-07 o'rtacha farq : 1.07e-07 bir xil qaror : 500 / 500 [0;93m2026-09-29 19:03:26.773363602 [W:onnxruntime:Default, device_discovery.cc:164 DiscoverDevicesForPlatform] GPU device discovery failed: device_discovery.cc:89 ReadFileContents Failed to open file: "/sys/class/drm/card0/device/vendor"[m
Farq 10⁻⁶ tartibida — bu float32 ga o'tkazish natijasi (2-bobdagi suzuvchi nuqta mavzusi).
Qarorlar esa to'liq bir xil.
O'tkazishdan keyin ALBATTA solishtiring
Format o'tkazish jim ravishda buzilishi mumkin: zipmap sozlamasi, tur aylantirish, qo'llab
quvvatlanmaydigan operator. Model yuklanadi va javob qaytaradi — lekin boshqa javob.
Har o'tkazishdan keyin yuzlab namunada predict_proba ni solishtiring va qarorlar mosligini
tekshiring. Buni testga aylantiring (25-bob).
Tezlik: ONNX nima uchun ishlatiladi
Xavfsizlik — ONNX ga o'tishning bitta sababi. Ikkinchisi tezlik, va u kutilmagan joyda ko'rinadi.
Savol: sklearn modeli bitta qatorni bashorat qilish uchun nima qiladi?
U predict_proba() ni chaqiradi. U esa ichida: kirishni tekshiradi, numpy massivga
aylantiradi, 150 ta daraxtni Python sikli bilan aylanib chiqadi, natijalarni yig'adi,
pandas ga qaytaradi.
Bu ishlarning ko'pi bitta qator uchun ortiqcha. Ular minglab qator uchun mo'ljallangan — o'shanda tayyorgarlik xarajati butun to'plamga taqsimlanadi.
Lekin veb-servisda sizga bitta qator keladi. Har so'rovda. Va har safar o'sha tayyorgarlik qaytadan bajariladi.
ONNX esa boshqacha ishlaydi: model oldindan oddiy matematik amallar grafigiga
aylantirilgan va C++ da bajariladi. Python sikli yo'q, pandas yo'q, tekshiruv yo'q.
Farqni o'lchaymiz — bitta qator uchun va katta to'plam uchun alohida.
python3 -c " import sys, time; sys.path.insert(0, 'src') import joblib, numpy as np, pandas as pd from quvur.format import onnx_sessiya, onnx_ehtimol from quvur.xususiyat import tayyorla d = pd.read_csv('../datasets/ijara.csv') x = tayyorla(d) m = joblib.load('sinov_model.joblib') s = onnx_sessiya('model.onnx') bitta = x.head(1); bitta_np = bitta.values.astype('float32') def olch(f, n): f(); t0 = time.perf_counter() for _ in range(n): f() return (time.perf_counter() - t0) / n * 1000 print('BITTA qator (xizmat holati):') print(f' sklearn : {olch(lambda: m.predict_proba(bitta), 200):.3f} ms') print(f' ONNX : {olch(lambda: onnx_ehtimol(s, bitta_np), 200):.3f} ms') print() toplam = x.head(2000); toplam_np = toplam.values.astype('float32') print('2000 qator (to\'plam holati):') print(f' sklearn : {olch(lambda: m.predict_proba(toplam), 20):.2f} ms') print(f' ONNX : {olch(lambda: onnx_ehtimol(s, toplam_np), 20):.2f} ms') "
BITTA qator (xizmat holati): sklearn : 2.721 ms ONNX : 0.006 ms 2000 qator (to'plam holati): sklearn : 21.30 ms ONNX : 3.91 ms [0;93m2026-09-29 19:03:28.128867557 [W:onnxruntime:Default, device_discovery.cc:164 DiscoverDevicesForPlatform] GPU device discovery failed: device_discovery.cc:89 ReadFileContents Failed to open file: "/sys/class/drm/card0/device/vendor"[m
Bitta qatorda farq eng katta — va aynan shu xizmat holati (27-bob): foydalanuvchi bitta e'lon yuboradi, javob kerak.
Sababi: sklearn har chaqiruvda pandas/numpy tekshiruvlarini bajaradi. ONNX esa oldindan
tuzilgan grafni bajaradi, ortiqcha qatlamsiz.
Yuklash vaqti
Server ishga tushganda model yuklanadi. Bu vaqt ham muhim:
python3 -c " import sys, time; sys.path.insert(0, 'src') sys.path.insert(0, 'src') def olch(f, n=8): f(); t0 = time.perf_counter() for _ in range(n): f() return (time.perf_counter() - t0) / n * 1000 import joblib from quvur.format import onnx_sessiya print(f'joblib yuklash : {olch(lambda: joblib.load(\"sinov_model.joblib\")):.1f} ms') print(f'ONNX yuklash : {olch(lambda: onnx_sessiya(\"model.onnx\")):.1f} ms') "
joblib yuklash : 292.9 ms ONNX yuklash : 80.9 ms [0;93m2026-09-29 19:03:32.858970678 [W:onnxruntime:Default, device_discovery.cc:164 DiscoverDevicesForPlatform] GPU device discovery failed: device_discovery.cc:89 ReadFileContents Failed to open file: "/sys/class/drm/card0/device/vendor"[m
Qaysi formatni qachon
import pandas as pd show(pd.DataFrame([ {"holat": "Tajriba, lokal ish", "format": "joblib", "sabab": "Eng oson, sklearn obyekti saqlanadi"}, {"holat": "Xizmat (inference)", "format": "ONNX", "sabab": "Tez, xavfsiz, tildan mustaqil"}, {"holat": "Model boshqa jamoaga beriladi", "format": "ONNX", "sabab": "Ular Python ishlatmasligi mumkin"}, {"holat": "Chuqur o'rganish vaznlari", "format": "safetensors", "sabab": "Tez va xavfsiz yuklash"}, {"holat": "Telefon/brauzerda ishlash", "format": "ONNX", "sabab": "onnxruntime-web, mobil qo'llab-quvvatlash"}, {"holat": "Modelni qayta o'qitish kerak", "format": "joblib", "sabab": "ONNX faqat inference uchun"}, ]))
| holat | format | sabab |
|---|---|---|
| Tajriba, lokal ish | joblib | Eng oson, sklearn obyekti saqlanadi |
| Xizmat (inference) | ONNX | Tez, xavfsiz, tildan mustaqil |
| Model boshqa jamoaga beriladi | ONNX | Ular Python ishlatmasligi mumkin |
| Chuqur o'rganish vaznlari | safetensors | Tez va xavfsiz yuklash |
| Telefon/brauzerda ishlash | ONNX | onnxruntime-web, mobil qo'llab-quvvatlash |
| Modelni qayta o'qitish kerak | joblib | ONNX faqat inference uchun |
Oxirgi qator muhim: ONNX ni qayta o'qitib bo'lmaydi. U faqat oldinga yurish (inference) grafini
saqlaydi. Shuning uchun amalda ikkalasi saqlanadi: joblib — o'qitish uchun, ONNX — xizmat
uchun.
Xususiyat kodini birga qadoqlash
23-bobda aytilgan muammo: model xususiyat tayyorlash kodisiz ma'nosiz. ONNX buni qisman
yechadi — tayyorlashni Pipeline ga qo'shsangiz, u ham grafga tushadi:
python3 -c " import sys; sys.path.insert(0, 'src') import numpy as np, pandas as pd from sklearn.pipeline import make_pipeline from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LogisticRegression from sklearn.model_selection import train_test_split from quvur.format import onnx_ga, onnx_sessiya, onnx_ehtimol from quvur.xususiyat import XUSUSIYATLAR, tayyorla d = pd.read_csv('../datasets/ijara.csv') x, y = tayyorla(d), d['broker'] Xtr, Xte, ytr, yte = train_test_split(x, y, test_size=0.25, stratify=y, random_state=42) kv = make_pipeline(StandardScaler(), LogisticRegression(max_iter=2000, random_state=42)).fit(Xtr, ytr) onnx_ga(kv, len(XUSUSIYATLAR), 'quvur.onnx') s = onnx_sessiya('quvur.onnx') a = kv.predict_proba(Xte.head(200))[:, 1] b = onnx_ehtimol(s, Xte.head(200).values) print('Pipeline (scaler + model) ONNX ga tushdi') print(f'eng katta farq: {np.abs(a-b).max():.2e}') print('=> StandardScaler ham grafga kirdi — xizmatda alohida kod kerak emas') "
Pipeline (scaler + model) ONNX ga tushdi eng katta farq: 7.55e-08 => StandardScaler ham grafga kirdi — xizmatda alohida kod kerak emas [0;93m2026-09-29 19:03:34.657746020 [W:onnxruntime:Default, device_discovery.cc:164 DiscoverDevicesForPlatform] GPU device discovery failed: device_discovery.cc:89 ReadFileContents Failed to open file: "/sys/class/drm/card0/device/vendor"[m
StandardScaler ning o'rtacha va standart og'ishi ONNX fayl ichida saqlandi. Bu 3-bobdagi
o'qitish/xizmat nomuvofiqligini kamaytiradi: normallashtirish kodi endi model bilan birga yuradi.
Xulosa
| Tushuncha | Asosiy fikr |
|---|---|
pickle xavfi |
loads() kod bajaradi — ishonchsiz fayl ochmang |
joblib ham shunday |
Bir xil format, bir xil xavf |
| ONNX | Hisoblash grafi; kod yo'q, shuning uchun xavfsiz |
| Tildan mustaqil | C++, Java, Go, brauzer — Python shart emas |
| Solishtirish majburiy | O'tkazish jim buzilishi mumkin — yuzlab namunada tekshiring |
| Tezlik | Farq bitta qatorda eng katta — bu aynan xizmat holati |
| ONNX cheklovi | Qayta o'qitib bo'lmaydi; ikkala format saqlanadi |
Pipeline |
Scaler ham grafga tushadi — nomuvofiqlik kamayadi |
Talaba ishi
onnx_gagazipmap: Truebering (sukut qiymat). Chiqish shakli qanday o'zgaradi va nega biz uniFalseqildik?- ONNX va joblib natijalarini solishtiradigan test yozing (25-bob uslubida). Qancha namuna yetarli deb hisoblaysiz?
RandomForesto'rnigaGradientBoostingni ONNX ga o'tkazing. Hajm va tezlik qanday farq qiladi?- ONNX faylni matn muharririda oching. Nima ko'rinadi? Bu nima uchun
pickledan xavfsizroq ekanini tushuntiradimi?
Bu bobni bepul o'qidingiz.
Kitob o'rgatadi, lekin sizning kodingiz nega ishlamaganini ayta olmaydi. Kursda uy vazifangiz tekshiriladi.