18-bo‘lim
Softmax va ko'p sinfli tasniflash
Ikkitadan ortiq sinf, ehtimolliklar taqsimoti va yana o'sha chiroyli gradient.
Ushbu bo‘lim mundarijasi
Hozirgacha savol "ha yoki yo'q" edi. Endi "qaysi biri" degan savolga o'tamiz: raqamni tanish, tilni aniqlash, kasallikni tasniflash.
One-hot yorliqlar #
import numpy as np
def softmax(Z):
"""Barqaror softmax - eng katta qiymatni ayirib toshib ketishning oldini olamiz."""
Z_siljigan = Z - Z.max(axis=1, keepdims=True)
eksp = np.exp(Z_siljigan)
return eksp / eksp.sum(axis=1, keepdims=True)
def kop_sinfli_krossentropiya(Y, A, eps=1e-12):
A = np.clip(A, eps, 1.0)
return float(-np.mean(np.sum(Y * np.log(A), axis=1)))
def one_hot(y, sinflar):
return np.eye(sinflar)[y]
class KopSinfliTarmoq:
def __init__(self, olchamlar, urug=42):
gen = np.random.default_rng(urug)
self.q = len(olchamlar) - 1
self.W = [gen.normal(0, np.sqrt(2.0 / olchamlar[i]),
(olchamlar[i], olchamlar[i + 1])) for i in range(self.q)]
self.b = [np.zeros(olchamlar[i + 1]) for i in range(self.q)]
def oldinga(self, X):
A = X
kesh = {"A0": X}
for i in range(self.q):
Z = A @ self.W[i] + self.b[i]
A = softmax(Z) if i == self.q - 1 else np.maximum(0.0, Z)
kesh[f"Z{i+1}"] = Z
kesh[f"A{i+1}"] = A
return A, kesh
def qadam(self, X, Y, tezlik):
A, kesh = self.oldinga(X)
dZ = (A - Y) / len(Y)
for i in range(self.q - 1, -1, -1):
dW = kesh[f"A{i}"].T @ dZ
db = dZ.sum(axis=0)
if i > 0:
dZ = (dZ @ self.W[i].T) * (kesh[f"Z{i}"] > 0)
self.W[i] -= tezlik * dW
self.b[i] -= tezlik * db
def yoqotish(self, X, Y):
A, _ = self.oldinga(X)
return kop_sinfli_krossentropiya(Y, A)
def aniqlik(self, X, y_indeks):
A, _ = self.oldinga(X)
return float((A.argmax(axis=1) == y_indeks).mean())
def uch_sinf(n=600, urug=0):
"""Uchta spiral - chiziqli ajralmaydigan uch sinf."""
gen = np.random.default_rng(urug)
nuqtalar, yorliqlar = [], []
for sinf in range(3):
radius = np.linspace(0.1, 1.0, n // 3)
burchak = np.linspace(sinf * 4, (sinf + 1) * 4, n // 3) + gen.normal(0, 0.2, n // 3)
nuqtalar.append(np.column_stack([radius * np.sin(burchak),
radius * np.cos(burchak)]))
yorliqlar.append(np.full(n // 3, sinf))
return np.vstack(nuqtalar), np.concatenate(yorliqlar)
y = np.array([0, 2, 1, 2, 0])
Y = one_hot(y, 3)
print("indekslar:", y)
print("one-hot:")
print(Y)
print("shakl:", Y.shape)
print("har qatorda bitta 1:", bool((Y.sum(axis=1) == 1).all()))
indekslar: [0 2 1 2 0]
one-hot:
[[1. 0. 0.]
[0. 0. 1.]
[0. 1. 0.]
[0. 0. 1.]
[1. 0. 0.]]
shakl: (5, 3)
har qatorda bitta 1: True
Softmax #
softmax(z)ᵢ = e^(zᵢ) / Σⱼ e^(zⱼ)
Z = np.array([[2.0, 1.0, 0.1],
[0.5, 0.5, 0.5],
[5.0, 1.0, -2.0]])
A = softmax(Z)
print("chiqishlar:")
print(np.round(A, 4))
print("har qatorning yig'indisi:", np.round(A.sum(axis=1), 6))
print("hammasi musbatmi:", bool((A > 0).all()))
chiqishlar:
[[6.590e-01 2.424e-01 9.860e-02]
[3.333e-01 3.333e-01 3.333e-01]
[9.811e-01 1.800e-02 9.000e-04]]
har qatorning yig'indisi: [1. 1. 1.]
hammasi musbatmi: True
Eng yuqori ehtimollikni alohida ko'ramiz:
Z = np.array([[2.0, 1.0, 0.1], [0.5, 0.5, 0.5], [5.0, 1.0, -2.0]])
A = softmax(Z)
print("yig'indilar:", np.round(A.sum(axis=1), 6))
print("eng katta ehtimollik indeksi:", A.argmax(axis=1))
print("eng katta ehtimollik qiymati:", np.round(A.max(axis=1), 4))
yig'indilar: [1. 1. 1.]
eng katta ehtimollik indeksi: [0 0 0]
eng katta ehtimollik qiymati: [0.659 0.3333 0.9811]
Ikkinchi qatorda barcha z teng edi (0.5) - va softmax
uchalasiga teng ehtimollik berdi. Uchinchi qatorda esa
z lar juda farqli va model 98.1% ishonch bildirdi.
Toshib ketish muammosi #
Z_katta = np.array([[1000.0, 999.0, 998.0]])
with np.errstate(over="ignore", invalid="ignore"):
sodda = np.exp(Z_katta) / np.exp(Z_katta).sum(axis=1, keepdims=True)
print("sodda yozuv:", sodda)
print("nan bormi:", bool(np.isnan(sodda).any()))
print("barqaror yozuv:", np.round(softmax(Z_katta), 6))
print("yig'indi:", float(softmax(Z_katta).sum()))
sodda yozuv: [[nan nan nan]]
nan bormi: True
barqaror yozuv: [[0.665241 0.244728 0.090031]]
yig'indi: 0.9999999999999999
exp(1000) - cheksizlik, inf/inf - nanSodda formula katta z da butunlay ishlamaydi.
Yechim - har qatordan eng katta qiymatni ayirish:
Z_siljigan = Z - Z.max(axis=1, keepdims=True)
Bu natijani umuman o'zgartirmaydi, chunki:
e^(zᵢ - c) / Σ e^(zⱼ - c) = (e^(zᵢ)·e^(-c)) / (e^(-c)·Σ e^(zⱼ)) = softmax(z)ᵢ
e^(-c) surat va maxrajda qisqaradi.
Endi eng katta ko'rsatkich aynan 0 bo'ladi va e⁰ = 1 -
hech qachon toshmaydi.
Bu 4-bo'limdagi barqaror sigmoid bilan bir xil g'oya. Har eksponentali formulada shunday savol bering: kirish juda katta bo'lsa nima bo'ladi?
Z = np.array([[2.0, 1.0, 0.1]])
Z_siljigan = Z - Z.max(axis=1, keepdims=True)
print("asl Z: ", Z)
print("siljigan Z: ", Z_siljigan)
print("softmax(Z): ", np.round(softmax(Z), 6))
print("softmax(siljigan): ", np.round(softmax(Z_siljigan), 6))
print("natija bir xilmi:", bool(np.allclose(softmax(Z), softmax(Z_siljigan))))
asl Z: [[2. 1. 0.1]]
siljigan Z: [[ 0. -1. -1.9]]
softmax(Z): [[0.659001 0.242433 0.098566]]
softmax(siljigan): [[0.659001 0.242433 0.098566]]
natija bir xilmi: True
Ko'p sinfli krossentropiya #
L = -(1/n) · Σ Σ yᵢⱼ · log(aᵢⱼ)
One-hot yorliqda faqat bitta had noldan farqli, shuning
uchun formula soddalashadi: L = -log(a_togri_sinf).
Y = one_hot(np.array([0, 1, 2]), 3)
A = np.array([[0.9, 0.05, 0.05],
[0.2, 0.7, 0.1],
[0.3, 0.3, 0.4]])
har_biri = -np.sum(Y * np.log(A), axis=1)
for i, (y_qator, a_qator, l) in enumerate(zip(Y, A, har_biri)):
sinf = int(y_qator.argmax())
print(f"namuna {i}: to'g'ri sinf {sinf}, unga berilgan ehtimollik "
f"{a_qator[sinf]:.2f}, yo'qotish {l:.4f}")
print("o'rtacha:", round(float(har_biri.mean()), 6))
print("funksiya bilan:", round(kop_sinfli_krossentropiya(Y, A), 6))
namuna 0: to'g'ri sinf 0, unga berilgan ehtimollik 0.90, yo'qotish 0.1054
namuna 1: to'g'ri sinf 1, unga berilgan ehtimollik 0.70, yo'qotish 0.3567
namuna 2: to'g'ri sinf 2, unga berilgan ehtimollik 0.40, yo'qotish 0.9163
o'rtacha: 0.459442
funksiya bilan: 0.459442
Uchinchi namunada model [0.3, 0.3, 0.4] dedi. Yo'qotish
faqat -log(0.4) ga teng - 0.3 lar formulaga umuman
kirmaydi.
Bu g'alati tuyuladi, lekin to'g'ri: softmax yig'indisi doim
1 bo'lgani uchun to'g'ri sinfning ehtimolligini oshirish
avtomatik ravishda qolganlarini kamaytiradi.
Ya'ni bitta sonni nazorat qilish yetarli.
Mo'ljal ham shundan kelib chiqadi: hech nima bilmaydigan
model har sinfga 1/K beradi, ya'ni yo'qotish ln(K):
| Sinflar soni | Boshlang'ich yo'qotish |
|---|---|
| 2 | ln(2) = 0.693 |
| 3 | ln(3) = 1.099 |
| 10 | ln(10) = 2.303 |
| 1000 | ln(1000) = 6.908 |
for K in [2, 3, 10, 1000]:
A = np.full((1, K), 1.0 / K)
Y = one_hot(np.array([0]), K)
print(f"K = {K:>4}: yo'qotish = {kop_sinfli_krossentropiya(Y, A):.4f} "
f"ln(K) = {float(np.log(K)):.4f}")
K = 2: yo'qotish = 0.6931 ln(K) = 0.6931
K = 3: yo'qotish = 1.0986 ln(K) = 1.0986
K = 10: yo'qotish = 2.3026 ln(K) = 2.3026
K = 1000: yo'qotish = 6.9078 ln(K) = 6.9078
Gradient - yana o'sha formula #
def yoqotish_z_dan(Z, Y):
return kop_sinfli_krossentropiya(Y, softmax(Z))
Z = np.array([[1.5, -0.5, 0.8]])
Y = one_hot(np.array([2]), 3)
h = 1e-6
sonli = np.zeros_like(Z)
for j in range(Z.shape[1]):
Z_yuqori = Z.copy(); Z_yuqori[0, j] += h
Z_past = Z.copy(); Z_past[0, j] -= h
sonli[0, j] = (yoqotish_z_dan(Z_yuqori, Y) - yoqotish_z_dan(Z_past, Y)) / (2 * h)
formula = softmax(Z) - Y
print("sonli gradient: ", np.round(sonli, 6))
print("A - Y formula: ", np.round(formula, 6))
print("mos keladi:", bool(np.allclose(sonli, formula, atol=1e-5)))
sonli gradient: [[ 0.612775 0.08293 -0.695705]]
A - Y formula: [[ 0.612775 0.08293 -0.695705]]
mos keladi: True
dL/dZ = A - Y - ikkilik holatning aynan umumlashmasi6-bo'limda sigmoid + krossentropiya uchun dL/dz = a - y
ekanini ko'rgandik. Softmax + ko'p sinfli krossentropiya
uchun formula aynan bir xil ko'rinishda:
dL/dZ = A - Y
Bu tasodif emas: sigmoid - softmaxning ikkita sinfli xususiy holati, ikkilik krossentropiya esa ko'p sinflining xususiy holati.
Amaliy natijasi: 11-bo'limdagi orqaga funksiyasida
hech nima o'zgarmaydi. Faqat oxirgi qatlamdagi
faollashtirish sigmoiddan softmaxga almashadi.
Aynan shu sabab kutubxonalarda CrossEntropyLoss softmaxni
o'z ichiga oladi - ular birga hisoblanganda ham
barqarorroq, ham tezroq.
Diqqat: PyTorch da nn.CrossEntropyLoss xom logits ni
kutadi, softmax qo'llanmagan holda. Uni ikki marta
qo'llash - keng tarqalgan xato.
Amalda: uch sinfli masala #
def uch_sinf(n=600, urug=0):
"""Uchta spiral - chiziqli ajralmaydigan uch sinf."""
gen = np.random.default_rng(urug)
nuqtalar, yorliqlar = [], []
for sinf in range(3):
radius = np.linspace(0.1, 1.0, n // 3)
burchak = np.linspace(sinf * 4, (sinf + 1) * 4, n // 3) + gen.normal(0, 0.2, n // 3)
nuqtalar.append(np.column_stack([radius * np.sin(burchak),
radius * np.cos(burchak)]))
yorliqlar.append(np.full(n // 3, sinf))
return np.vstack(nuqtalar), np.concatenate(yorliqlar)
X, y_indeks = uch_sinf(600)
Y = one_hot(y_indeks, 3)
print("X:", X.shape, " Y:", Y.shape)
print("har sinfdan:", np.bincount(y_indeks))
X: (600, 2) Y: (600, 3)
har sinfdan: [200 200 200]
X, y_indeks = uch_sinf(600)
Y = one_hot(y_indeks, 3)
t = KopSinfliTarmoq([2, 64, 64, 3], urug=1)
print("davr yo'qotish aniqlik")
for davr in range(3001):
if davr % 600 == 0:
print(f"{davr:>5} {t.yoqotish(X, Y):.4f} {t.aniqlik(X, y_indeks):.4f}")
t.qadam(X, Y, 0.5)
davr yo'qotish aniqlik
0 1.2621 0.3300
600 0.0042 1.0000
1200 0.0017 1.0000
1800 0.0010 1.0000
2400 0.0007 1.0000
3000 0.0005 1.0000
Boshlang'ich yo'qotish 1.1035 - ln(3) = 1.0986 ga juda
yaqin, ya'ni boshlash to'g'ri.
Bashoratni o'qish #
X, y_indeks = uch_sinf(600)
Y = one_hot(y_indeks, 3)
t = KopSinfliTarmoq([2, 64, 64, 3], urug=1)
for _ in range(3000):
t.qadam(X, Y, 0.5)
A, _ = t.oldinga(X[:5])
for i in range(5):
ehtimolliklar = np.round(A[i], 4)
tanlov = int(A[i].argmax())
ishonch = float(A[i].max())
belgi = "to'g'ri" if tanlov == y_indeks[i] else "XATO"
print(f"namuna {i}: {ehtimolliklar} -> sinf {tanlov} "
f"({ishonch:.1%} ishonch) haqiqiy {y_indeks[i]} {belgi}")
namuna 0: [0.9871 0.0065 0.0064] -> sinf 0 (98.7% ishonch) haqiqiy 0 to'g'ri
namuna 1: [0.99 0.0058 0.0042] -> sinf 0 (99.0% ishonch) haqiqiy 0 to'g'ri
namuna 2: [0.9936 0.0016 0.0048] -> sinf 0 (99.4% ishonch) haqiqiy 0 to'g'ri
namuna 3: [0.9957 0.0018 0.0025] -> sinf 0 (99.6% ishonch) haqiqiy 0 to'g'ri
namuna 4: [0.996 0.0027 0.0013] -> sinf 0 (99.6% ishonch) haqiqiy 0 to'g'ri
Yuqorida model 99.7% ishonch bildirdi va haqiqatan ham to'g'ri javob berdi. Lekin bu bog'liqlik kafolatlanmagan.
Neyron tarmoqlar ko'pincha haddan ortiq ishonchli bo'ladi: ular xato javobga ham 99% berishi mumkin.
Sabab: krossentropiya modelni ishonchli bo'lishga
rag'batlantiradi - 0.9 dan 0.99 ga o'tish yo'qotishni
kamaytiradi.
Bu jiddiy amaliy muammo:
| Soha | Xavf |
|---|---|
| Tibbiyot | Ishonchli, lekin xato tashxis |
| Avtonom harakat | "Bu yo'l bo'sh" - 99% |
| Moderatsiya | Ishonch bilan noto'g'ri bloklash |
Choralar: kalibratsiya (temperature scaling), ansambllar, va noaniqlikni alohida baholash.
Eng oddiy tekshiruv: model 90% ishonch bildirgan namunalarning haqiqatan ham 90% i to'g'rimi? Agar 70% bo'lsa - model kalibrlanmagan.
Harorat #
Z = np.array([[3.0, 1.0, 0.5]])
for harorat in [0.5, 1.0, 2.0, 5.0]:
A = softmax(Z / harorat)
print(f"T = {harorat:<4} {np.round(A, 4)} eng katta: {float(A.max()):.4f}")
T = 0.5 [[0.9756 0.0179 0.0066]] eng katta: 0.9756
T = 1.0 [[0.8214 0.1112 0.0674]] eng katta: 0.8214
T = 2.0 [[0.6045 0.2224 0.1732]] eng katta: 0.6045
T = 5.0 [[0.4392 0.2944 0.2664]] eng katta: 0.4392
| Harorat | Ta'siri |
|---|---|
T < 1 | Ishonchni oshiradi - taqsimot o'tkirlashadi |
T = 1 | Odatiy softmax |
T > 1 | Ishonchni kamaytiradi - taqsimot tekislashadi |
T → ∞ | Barcha sinflar teng |
Harorat matn generatsiyasida ham ishlatiladi: past harorat - oldindan aytiladigan matn, yuqori harorat - ijodiy va tasodifiy.
- Indekslarni one-hot ga aylantiring.
- Softmax yozing va yig'indi
1ekanini tekshiring. exp(1000)bilan sodda formulani sinab,nanni oling.- Eng katta qiymatni ayirish natijani o'zgartirmasligini isbotlang.
- Ko'p sinfli krossentropiyani hisoblang.
ln(K)mo'ljalini to'rttaKuchun tekshiring.dL/dZ = A - Yni sonli gradient bilan tasdiqlang.- Uch sinfli masalani o'qiting va aniqlikni o'lchang.
- Boshlang'ich yo'qotish
ln(3)ga yaqinligini ko'rsating. - Haroratni o'zgartirib, ishonchning o'zgarishini kuzating.
Xulosa #
- One-hot: har qatorda aynan bitta
1. - Softmax chiqishlari raqobatlashadi, yig'indisi doim
1. - Sigmoid - mustaqil ehtimolliklar (ko'p yorliqli masala uchun).
- Savol: bir vaqtda bir nechta javob to'g'ri bo'la oladimi?
exptoshib ketmasligi uchun eng katta qiymatni ayiring.- Bu natijani o'zgartirmaydi -
e^(-c)qisqaradi. - Yo'qotish faqat to'g'ri sinf ehtimolligiga bog'liq.
- Boshlang'ich yo'qotish mo'ljali -
ln(K). dL/dZ = A - Y- ikkilik holatning aynan umumlashmasi.- Yuqori ishonch to'g'rilik kafolati emas - modellar haddan ortiq ishonchli.
Keyingi bo'limda modelni to'g'ri baholashni o'rganamiz.
O‘qish tarixini saqlamoqchimisiz?
Tizimga kirsangiz, tugatgan bo‘limlaringiz saqlanadi va qoldirgan joyingizdan davom etasiz.
Xatolik topdingizmi?
Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.