6-bo‘lim
Yo'qotish funksiyasi
Xatoni bitta songa aylantirish - MSE, ikkilik krossentropiya va nima uchun tanlov muhim.
Ushbu bo‘lim mundarijasi
Tarmoq qanchalik xato qilayotganini bilmasak, uni to'g'rilay olmaymiz. Yo'qotish funksiyasi (*loss function*) butun xatoni bitta songa siqadi.
Talab: xatoni o'lchash #
import numpy as np
def sigmoid(z):
return 1.0 / (1.0 + np.exp(-z))
haqiqiy = np.array([1.0, 0.0, 1.0, 0.0])
bashorat = np.array([0.9, 0.2, 0.6, 0.1])
farq = haqiqiy - bashorat
print("farq:", farq)
print("oddiy yig'indi:", float(farq.sum()))
farq: [ 0.1 -0.2 0.4 -0.1]
oddiy yig'indi: 0.19999999999999998
Yig'indi 0.2 chiqdi. Lekin bu xatolar kichik degani
emas: musbat va manfiy xatolar bir-birini qoplaydi.
Eng yomon holat:
farq = np.array([100.0, -100.0])
farq.sum() # 0.0 - "xato yo'q"?
Model dahshatli xato qilyapti, o'lchov esa nolni ko'rsatadi.
Ikkita to'g'ri yechim bor:
| Usul | Formula | Nomi |
|---|---|---|
| Modul | mean(abs(y - ŷ)) | MAE |
| Kvadrat | mean((y - ŷ)²) | MSE |
Ikkalasi ham ishorani yo'q qiladi. Farqi - katta xatolarga munosabatda.
farq = np.array([100.0, -100.0])
print("yig'indi:", float(farq.sum()))
print("MAE: ", float(np.abs(farq).mean()))
print("MSE: ", float((farq ** 2).mean()))
yig'indi: 0.0
MAE: 100.0
MSE: 10000.0
O'rtacha kvadratik xato (MSE) #
MSE = (1/n) · Σ (y - ŷ)²
def mse(haqiqiy, bashorat):
return float(np.mean((haqiqiy - bashorat) ** 2))
haqiqiy = np.array([3.0, -0.5, 2.0, 7.0])
yaxshi = np.array([2.9, -0.4, 2.1, 7.2])
yomon = np.array([1.0, 2.0, 0.0, 3.0])
print("yaxshi model MSE:", round(mse(haqiqiy, yaxshi), 6))
print("yomon model MSE: ", round(mse(haqiqiy, yomon), 6))
yaxshi model MSE: 0.0175
yomon model MSE: 7.5625
for xato in [1.0, 2.0, 4.0, 10.0]:
print(f"xato = {xato:>5.1f} MAE = {xato:>6.1f} MSE = {xato**2:>8.1f}")
xato = 1.0 MAE = 1.0 MSE = 1.0
xato = 2.0 MAE = 2.0 MSE = 4.0
xato = 4.0 MAE = 4.0 MSE = 16.0
xato = 10.0 MAE = 10.0 MSE = 100.0
Ma'lumotda bitta g'alati namuna bo'lsa (masalan noto'g'ri yozilgan narx), MSE uni kvadratga oshiradi va model o'sha bitta xato atrofida buriladi.
| Vaziyat | Tanlov |
|---|---|
| Ma'lumot toza, katta xato jiddiy | MSE |
| Chetlangan qiymatlar bor | MAE yoki Huber |
| Tasniflash | Krossentropiya (pastda) |
MSE ning afzalligi - silliqligi: hosilasi hamma joyda uzluksiz. MAE ning hosilasi esa nolda mavjud emas (V ning burchagi), bu gradient tushishni biroz qiyinlashtiradi.
Amalda regressiya uchun MSE standart tanlov, chetlangan qiymatlar muammo bo'lsa esa Huber yo'qotishi ishlatiladi - u kichik xatolarda MSE, katta xatolarda MAE kabi ishlaydi.
MSE tasniflash uchun yaramaydi #
def mse(haqiqiy, bashorat):
return float(np.mean((haqiqiy - bashorat) ** 2))
haqiqiy = np.array([1.0])
for bashorat in [0.9, 0.5, 0.1, 0.01]:
b = np.array([bashorat])
print(f"bashorat = {bashorat:<5} MSE = {mse(haqiqiy, b):.4f}")
bashorat = 0.9 MSE = 0.0100
bashorat = 0.5 MSE = 0.2500
bashorat = 0.1 MSE = 0.8100
bashorat = 0.01 MSE = 0.9801
Model 1 bo'lishi kerak bo'lgan javobga 0.01 berdi -
ya'ni butunlay ishonch bilan xato qildi. Lekin MSE
atigi 0.98, ya'ni 0.1 berganidan sal kattaroq.
MSE ning chegarasi bor: yo'qotish hech qachon 1 dan
oshmaydi (chunki xato eng ko'pi bilan 1).
Ishonch bilan qilingan xato va ikkilanib qilingan xato deyarli bir xil jazolanadi.
Bundan tashqari, sigmoid bilan birga MSE ishlatilganda
gradient ikki marta kichrayadi: bir marta MSE dan, bir
marta sigmoid hosilasidan (≤ 0.25).
Natijada butunlay xato qilgan model juda sekin o'qiydi - bu "sekin o'qish muammosi" deb ataladi.
Yechim - krossentropiya: u ishonch bilan qilingan xatoni cheksizlikka yaqin jazolaydi.
Ikkilik krossentropiya #
L = -(1/n) · Σ [ y·log(ŷ) + (1-y)·log(1-ŷ) ]
def krossentropiya(haqiqiy, bashorat, eps=1e-12):
b = np.clip(bashorat, eps, 1.0 - eps)
return float(-np.mean(haqiqiy * np.log(b) + (1 - haqiqiy) * np.log(1 - b)))
haqiqiy = np.array([1.0])
for bashorat in [0.9, 0.5, 0.1, 0.01, 0.0001]:
b = np.array([bashorat])
print(f"bashorat = {bashorat:<8} KE = {krossentropiya(haqiqiy, b):>8.4f}")
bashorat = 0.9 KE = 0.1054
bashorat = 0.5 KE = 0.6931
bashorat = 0.1 KE = 2.3026
bashorat = 0.01 KE = 4.6052
bashorat = 0.0001 KE = 9.2103
Endi ishonch bilan qilingan xato keskin jazolanadi.
| Bashorat | MSE | Krossentropiya |
|---|---|---|
0.9 | 0.01 | 0.11 |
0.5 | 0.25 | 0.69 |
0.1 | 0.81 | 2.30 |
0.01 | 0.98 | 4.61 |
0.0001 | ~1.00 | 9.21 |
MSE 1 da to'xtaydi, krossentropiya esa cheksiz o'sadi.
log(0) - cheksizlik va nanFormulada log(ŷ) bor. Agar model aynan 0 bashorat qilsa
va haqiqiy javob 1 bo'lsa, log(0) = -inf chiqadi.
Shuning uchun kodda np.clip ishlatildi:
b = np.clip(bashorat, eps, 1.0 - eps)
Bu bashoratni [1e-12, 1 - 1e-12] oralig'iga qisadi.
Bu shunchaki ehtiyot chorasi emas - majburiy. Usiz
o'qitish jarayonida bir marta inf paydo bo'lsa, u
gradientlar orqali tarqaladi va butun tarmoq nan ga
aylanadi.
"Yo'qotish nan bo'ldi" - eng ko'p uchraydigan shikoyat,
va sabablarning birinchisi aynan shu.
xom = np.array([0.0])
haqiqiy = np.array([1.0])
with np.errstate(divide="ignore"):
qiymat = -float(haqiqiy * np.log(xom))
print("clip siz:", qiymat)
print("cheksizmi:", bool(np.isinf(qiymat)))
b = np.clip(xom, 1e-12, 1 - 1e-12)
print("clip bilan:", round(-float(haqiqiy * np.log(b)), 4))
clip siz: inf
cheksizmi: True
clip bilan: 27.631
<stdin>:10: DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error in future. Ensure you extract a single element from your array before performing this operation. (Deprecated NumPy 1.25.)
<stdin>:15: DeprecationWarning: Conversion of an array with ndim > 0 to a scalar is deprecated, and will error in future. Ensure you extract a single element from your array before performing this operation. (Deprecated NumPy 1.25.)
Nima uchun krossentropiya sigmoid bilan mos #
Bu ikkisining birga ishlatilishi tasodifiy emas.
def krossentropiya(haqiqiy, bashorat, eps=1e-12):
b = np.clip(bashorat, eps, 1.0 - eps)
return float(-np.mean(haqiqiy * np.log(b) + (1 - haqiqiy) * np.log(1 - b)))
h = 1e-6
for z_qiymat, y_qiymat in [(2.0, 1.0), (-1.0, 1.0), (0.5, 0.0), (3.0, 0.0)]:
z = np.array([z_qiymat])
y = np.array([y_qiymat])
sonli = (krossentropiya(y, sigmoid(z + h))
- krossentropiya(y, sigmoid(z - h))) / (2 * h)
formula = (sigmoid(z) - y).item()
print(f"z={z_qiymat:>5.1f} y={y_qiymat:.0f} "
f"sonli={sonli:>9.6f} a-y={formula:>9.6f} "
f"mos={np.isclose(sonli, formula, atol=1e-5)}")
z= 2.0 y=1 sonli=-0.119203 a-y=-0.119203 mos=True
z= -1.0 y=1 sonli=-0.731059 a-y=-0.731059 mos=True
z= 0.5 y=0 sonli= 0.622459 a-y= 0.622459 mos=True
z= 3.0 y=0 sonli= 0.952574 a-y= 0.952574 mos=True
To'rt holatda ham sonli hosila a - y formulasiga aynan
mos keldi.
dL/dz = ŷ - y - butun darslikdagi eng chiroyli natijaSigmoid va krossentropiyaning hosilalari bir-birini qisqartiradi, va natija hayratlanarli darajada oddiy:
dL/dz = ŷ - y
Ya'ni chiqish qatlamidagi gradient - shunchaki bashorat
bilan haqiqiy javob orasidagi farq. Sigmoid hosilasi
(≤ 0.25) ham, logarifm hosilasi ham ko'rinmaydi.
Bu 9-bo'limdagi orqaga tarqalish kodini bir necha marta soddalashtiradi. Xuddi shu natija softmax + ko'p sinfli krossentropiya uchun ham o'rinli (18-bo'lim).
Va bu 4-bo'limdagi to'yinish muammosini ham hal qiladi:
model butunlay xato qilganda ŷ - y katta bo'ladi,
sigmoid hosilasi esa gradientni bo'g'ib qo'ymaydi - chunki
u formulada umuman qatnashmaydi.
Aynan shu sabab tasniflashda doim sigmoid+krossentropiya juftligi ishlatiladi.
Paket bo'yicha yo'qotish #
def krossentropiya(haqiqiy, bashorat, eps=1e-12):
b = np.clip(bashorat, eps, 1.0 - eps)
return float(-np.mean(haqiqiy * np.log(b) + (1 - haqiqiy) * np.log(1 - b)))
haqiqiy = np.array([1.0, 0.0, 1.0, 1.0, 0.0])
bashorat = np.array([0.95, 0.1, 0.8, 0.3, 0.4])
har_biri = -(haqiqiy * np.log(bashorat) + (1 - haqiqiy) * np.log(1 - bashorat))
for h, b, l in zip(haqiqiy, bashorat, har_biri):
belgi = " <- eng katta hissa" if l == har_biri.max() else ""
print(f"y={h:.0f} ŷ={b:.2f} yo'qotish={l:.4f}{belgi}")
print(f"o'rtacha: {krossentropiya(haqiqiy, bashorat):.4f}")
y=1 ŷ=0.95 yo'qotish=0.0513
y=0 ŷ=0.10 yo'qotish=0.1054
y=1 ŷ=0.80 yo'qotish=0.2231
y=1 ŷ=0.30 yo'qotish=1.2040 <- eng katta hissa
y=0 ŷ=0.40 yo'qotish=0.5108
o'rtacha: 0.4189
Beshinchi namunadagi eng katta xato o'rtachaga eng katta hissa qo'shdi - va u o'qitishda ham eng kuchli signal beradi.
mean va sum - qaysi biriKo'p kodda yo'qotish sum bilan hisoblanadi, boshqalarda
mean bilan. Farqi muhimmi?
| Usul | Gradientga ta'siri |
|---|---|
sum | Paket kattalashsa gradient ham kattalashadi |
mean | Gradient paket hajmidan mustaqil |
mean afzal: paket hajmini 32 dan 128 ga o'zgartirganda
o'qitish tezligini qayta sozlashingiz shart emas.
sum ishlatilsa, paketni to'rt barobar kattalashtirish
gradientni ham to'rt barobar kattalashtiradi - va bu
og'irliklarni portlatib yuborishi mumkin.
Darslikda hamma joyda mean ishlatiladi.
Yo'qotish o'qitish davomida #
def krossentropiya(haqiqiy, bashorat, eps=1e-12):
b = np.clip(bashorat, eps, 1.0 - eps)
return float(-np.mean(haqiqiy * np.log(b) + (1 - haqiqiy) * np.log(1 - b)))
haqiqiy = np.array([1.0, 0.0, 1.0, 0.0])
bosqichlar = {
"boshlanish (tasodifiy)": np.array([0.5, 0.5, 0.5, 0.5]),
"biroz o'qidi": np.array([0.6, 0.4, 0.7, 0.3]),
"yaxshi o'qidi": np.array([0.9, 0.1, 0.85, 0.05]),
"deyarli mukammal": np.array([0.99, 0.01, 0.98, 0.02]),
}
for nom, b in bosqichlar.items():
print(f"{nom:<24} {krossentropiya(haqiqiy, b):.4f}")
boshlanish (tasodifiy) 0.6931
biroz o'qidi 0.4338
yaxshi o'qidi 0.1061
deyarli mukammal 0.0151
0.6931 - tasodifiy modelning "imzosi"Birinchi qator 0.6931 - bu ln(2).
Model hech nima bilmasa va har javobga 0.5 bersa,
krossentropiya aynan shu qiymatni beradi.
Bu juda foydali mo'ljal:
| Yo'qotish | Xulosa |
|---|---|
> 0.693 | Model tasodifdan yomonroq - kodda xato bor |
≈ 0.693 va tushmayapti | O'qish boshlanmadi (15-bo'lim) |
< 0.693 va tushmoqda | Yaxshi |
Ko'p sinfli holatda mo'ljal ln(sinflar_soni) bo'ladi:
o'nta sinf uchun ln(10) ≈ 2.30.
O'qitishni boshlaganingizda birinchi yo'qotish shu qiymatga yaqin bo'lishi kerak. Agar u juda katta bo'lsa - og'irliklar juda katta boshlangan (13-bo'lim).
print("ln(2) =", round(float(np.log(2)), 4))
print("ln(10) =", round(float(np.log(10)), 4))
ln(2) = 0.6931
ln(10) = 2.3026
- Farqlarni shunchaki qo'shib, qoplash muammosini ko'rsating.
- MAE va MSE ni bir xil ma'lumotda hisoblang.
- Xato 1, 2, 4, 10 bo'lganda MSE qanday o'sishini jadval qiling.
y=1uchun turli bashoratlarda MSE ni hisoblang.- Xuddi shu bashoratlar uchun krossentropiyani hisoblang.
- Ikkalasini jadvalda solishtiring.
log(0)ni sinab,clipning zarurligini ko'rsating.dL/dz = a - yni sonli hosila bilan tekshiring.- Paketdagi eng katta hissa qo'shgan namunani toping.
ln(2)valn(10)mo'ljallarini hisoblang.
Xulosa #
- Farqlarni qo'shmang - musbat va manfiy bir-birini qoplaydi.
- MAE chiziqli, MSE kvadratik jazolaydi.
- MSE chetlangan qiymatlarga sezgir, lekin silliq.
- Tasniflashda MSE yaramaydi - u
1da to'xtaydi. - Krossentropiya ishonch bilan qilingan xatoni cheksiz jazolaydi.
log(0)uchunnp.clipmajburiy - aks holdanan.- Sigmoid + krossentropiya da
dL/dz = ŷ - y- hammasi qisqaradi. - Yo'qotishda
meanishlating,sumemas. - Tasodifiy model uchun mo'ljal -
ln(2) = 0.693. - Birinchi yo'qotish mo'ljaldan katta bo'lsa - boshlash noto'g'ri.
Keyingi bo'limda hosila va gradient tushunchasini o'rganamiz - xatoni kamaytirish yo'nalishini topamiz.
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.