4-bo‘lim
Faollashtirish funksiyalari
Sigmoid, tanh, ReLU va ularning hosilalari - nima uchun chiziqsizlik bo'lmasa tarmoq ma'nosini yo'qotadi.
Ushbu bo‘lim mundarijasi
Oldingi bo'limda neyron faqat to'g'ri chiziq chiza olishini ko'rdik. Faollashtirish funksiyasi shu cheklovni yo'q qiladi - u chiziqli natijani egadi.
Chiziqsizlik nima uchun shart #
Ikkita chiziqli qatlamni ketma-ket qo'yamiz:
import numpy as np
X = np.array([[1.0, 2.0], [3.0, -1.0], [0.5, 0.5]])
W1 = np.array([[0.5, -0.2, 0.3], [0.1, 0.4, -0.6]])
b1 = np.array([0.1, 0.0, -0.1])
W2 = np.array([[1.0], [-0.5], [0.8]])
b2 = np.array([0.2])
ikki_qatlam = (X @ W1 + b1) @ W2 + b2
# xuddi shu narsani bitta qatlamga siqamiz
W_teng = W1 @ W2
b_teng = b1 @ W2 + b2
bitta_qatlam = X @ W_teng + b_teng
print("ikki qatlam: ", np.round(ikki_qatlam.ravel(), 6))
print("bitta qatlam: ", np.round(bitta_qatlam.ravel(), 6))
print("bir xilmi:", np.allclose(ikki_qatlam, bitta_qatlam))
ikki qatlam: [-0.1 3.32 0.35]
bitta qatlam: [-0.1 3.32 0.35]
bir xilmi: True
Yuqoridagi natija butun sohaning asosiy faktini ko'rsatadi: chiziqli qatlamlar zanjiri - baribir bitta chiziqli qatlam.
Yuz qatlam qo'ysangiz ham, ular bitta matritsaga siqiladi:
(X @ W1) @ W2 @ W3 ... @ Wn = X @ (W1 @ W2 @ W3 ... @ Wn)
Ya'ni chiziqsizliksiz "chuqur o'qitish" degan narsa umuman mavjud emas - qanchalik chuqur bo'lmasin, tarmoq 3-bo'limdagi bitta chiziqdan nariga o'ta olmaydi.
Faollashtirish funksiyasi - shunchaki qo'shimcha emas, u butun g'oyaning sharti.
Sigmoid #
σ(z) = 1 / (1 + e^(-z))
def sigmoid(z):
return 1.0 / (1.0 + np.exp(-z))
z = np.array([-6.0, -2.0, -0.5, 0.0, 0.5, 2.0, 6.0])
print(np.round(sigmoid(z), 4))
[0.0025 0.1192 0.3775 0.5 0.6225 0.8808 0.9975]
| Xususiyat | Qiymat |
|---|---|
| Chiqish oralig'i | (0, 1) |
z = 0 da | Aynan 0.5 |
Katta musbat z | 1 ga yaqinlashadi |
Katta manfiy z | 0 ga yaqinlashadi |
| Ma'nosi | Ehtimollik kabi o'qiladi |
np.exp katta manfiy sonda toshib ketadiSodda yozuv katta manfiy z da ogohlantirish beradi:
sigmoid(np.array([-1000.0]))
np.exp(1000) cheksizlikka aylanadi. Natija 0.0 bo'lib
chiqadi - to'g'ri javob - lekin yo'lda RuntimeWarning
paydo bo'ladi va ba'zi holatlarda nan ham.
Barqaror yozuv ikki shoxga bo'linadi:
def sigmoid_barqaror(z):
musbat = z >= 0
natija = np.empty_like(z, dtype=np.float64)
natija[musbat] = 1.0 / (1.0 + np.exp(-z[musbat]))
eksp = np.exp(z[~musbat])
natija[~musbat] = eksp / (1.0 + eksp)
return natija
Bu 18-bo'limdagi softmax uchun ham bir xil naqsh: eksponenta bilan ishlaganda doim toshib ketishni o'ylang.
def sigmoid_barqaror(z):
musbat = z >= 0
natija = np.empty_like(z, dtype=np.float64)
natija[musbat] = 1.0 / (1.0 + np.exp(-z[musbat]))
eksp = np.exp(z[~musbat])
natija[~musbat] = eksp / (1.0 + eksp)
return natija
z = np.array([-1000.0, -10.0, 0.0, 10.0, 1000.0])
print(np.round(sigmoid_barqaror(z), 6))
print("nan bormi:", bool(np.isnan(sigmoid_barqaror(z)).any()))
[0.00000e+00 4.50000e-05 5.00000e-01 9.99955e-01 1.00000e+00]
nan bormi: False
Sigmoidning hosilasi #
Gradient tushish uchun hosila kerak bo'ladi (7-bo'lim). Sigmoidda u juda chiroyli:
σ'(z) = σ(z) · (1 - σ(z))
def sigmoid(z):
return 1.0 / (1.0 + np.exp(-z))
def sigmoid_hosila(z):
s = sigmoid(z)
return s * (1.0 - s)
z = np.array([-6.0, -2.0, 0.0, 2.0, 6.0])
print("sigmoid: ", np.round(sigmoid(z), 4))
print("hosila: ", np.round(sigmoid_hosila(z), 4))
sigmoid: [0.0025 0.1192 0.5 0.8808 0.9975]
hosila: [0.0025 0.105 0.25 0.105 0.0025]
Hosila z = 0 da eng katta (0.25) va chetlarda deyarli
nolga tushadi.
Buni sonli hosila bilan tekshiramiz:
def sigmoid(z):
return 1.0 / (1.0 + np.exp(-z))
def sigmoid_hosila(z):
s = sigmoid(z)
return s * (1.0 - s)
z = np.array([-2.0, -0.5, 0.0, 1.0, 3.0])
h = 1e-6
sonli = (sigmoid(z + h) - sigmoid(z - h)) / (2 * h)
print("formula:", np.round(sigmoid_hosila(z), 8))
print("sonli: ", np.round(sonli, 8))
print("mos keladi:", np.allclose(sigmoid_hosila(z), sonli))
formula: [0.10499359 0.23500371 0.25 0.19661193 0.04517666]
sonli: [0.10499359 0.23500371 0.25 0.19661193 0.04517666]
mos keladi: True
Yuqoridagi tekshiruv gradient tekshiruvi (*gradient checking*) deb ataladi va u 11-bo'limda butun tarmoq uchun ishlatiladi.
G'oyasi: hosilaning ta'rifi - kichik h uchun
f'(x) ≈ (f(x + h) - f(x - h)) / (2h)
Agar sizning formula bo'yicha hisoblagan gradientingiz shu sonli qiymatga mos kelmasa - formulada xato bor.
h qiymati | Muammo |
|---|---|
Juda katta (1e-2) | Yaqinlashish aniq emas |
1e-6 | Odatda eng yaxshi muvozanat |
Juda kichik (1e-12) | Suzuvchi nuqta xatosi ustun keladi |
Markaziy farq (f(x+h) - f(x-h)) oldinga farqdan
(f(x+h) - f(x)) ancha aniqroq - shuning uchun doim shuni
ishlating.
Yo'qolayotgan gradient #
def sigmoid(z):
return 1.0 / (1.0 + np.exp(-z))
def sigmoid_hosila(z):
s = sigmoid(z)
return s * (1.0 - s)
for z in [0.0, 2.0, 4.0, 6.0, 8.0, 10.0]:
h = float(sigmoid_hosila(np.array([z]))[0])
print(f"z = {z:>4.1f} hosila = {h:.8f}")
z = 0.0 hosila = 0.25000000
z = 2.0 hosila = 0.10499359
z = 4.0 hosila = 0.01766271
z = 6.0 hosila = 0.00246651
z = 8.0 hosila = 0.00033524
z = 10.0 hosila = 0.00004540
z = 10 da hosila 0.000045 - deyarli nol.
Orqaga tarqalishda gradientlar ko'paytiriladi (9-bo'lim).
Har qatlam sigmoid ishlatsa, har qadamda gradient eng ko'pi
bilan 0.25 ga ko'payadi.
O'nta qatlamda:
0.25¹⁰ ≈ 0.00000095
Birinchi qatlamlarga yetib boradigan gradient shunchalik kichikki, ular umuman o'qimaydi.
Bu muammo 1990-yillarda chuqur tarmoqlarni amalda qo'llanmaydigan qilib qo'ydi. Uch yechim topildi:
| Yechim | Bo'lim |
|---|---|
| ReLU faollashtirish | Shu bo'lim |
| To'g'ri boshlash (Xavier, He) | 13 |
| Normalizatsiya va qoldiq ulanishlar | Ilg'or mavzular |
Amaliy xulosa: yashirin qatlamlarda sigmoid ishlatmang.
print("0.25 ** 10 =", 0.25 ** 10)
print("0.25 ** 20 =", 0.25 ** 20)
0.25 ** 10 = 9.5367431640625e-07
0.25 ** 20 = 9.094947017729282e-13
Tanh #
tanh(z) = (e^z - e^(-z)) / (e^z + e^(-z))
z = np.array([-3.0, -1.0, 0.0, 1.0, 3.0])
print("tanh: ", np.round(np.tanh(z), 4))
print("hosila:", np.round(1.0 - np.tanh(z) ** 2, 4))
tanh: [-0.9951 -0.7616 0. 0.7616 0.9951]
hosila: [0.0099 0.42 1. 0.42 0.0099]
| Sigmoid bilan taqqoslash | tanh |
|---|---|
| Oralig'i | (-1, 1) - markazi nolda |
| Maksimal hosila | 1.0 (sigmoidda 0.25) |
| Yo'qolayotgan gradient | Bor, lekin kamroq |
Sigmoid chiqishi doim musbat (0 dan 1 gacha). Bu
keyingi qatlamning barcha kirishlari musbat bo'lishini
anglatadi.
Natijada gradientlar ham bir xil ishorada bo'ladi va og'irliklar zigzag bilan yangilanadi - to'g'ridan-to'g'ri emas.
tanh chiqishi esa -1 dan 1 gacha, o'rtacha qiymati
nolga yaqin. Bu o'qitishni sezilarli tezlashtiradi.
Xuddi shu sabab 17-bo'limda ma'lumotni normallashtirish tavsiya etiladi: kirishlarni ham nolga markazlash kerak.
ReLU #
ReLU(z) = max(0, z)
def relu(z):
return np.maximum(0.0, z)
def relu_hosila(z):
return (z > 0).astype(np.float64)
z = np.array([-3.0, -0.5, 0.0, 0.5, 3.0])
print("relu: ", relu(z))
print("hosila:", relu_hosila(z))
relu: [0. 0. 0. 0.5 3. ]
hosila: [0. 0. 0. 1. 1.]
| Afzalligi | Izoh |
|---|---|
Hosila 1 yoki 0 | Gradient yo'qolmaydi |
| Juda tez | Faqat taqqoslash, eksponenta yo'q |
| Siyraklik | Neyronlarning bir qismi nolga tushadi |
def relu(z):
return np.maximum(0.0, z)
def sigmoid_hosila_qiymati(z):
s = 1.0 / (1.0 + np.exp(-z))
return s * (1.0 - s)
z = 8.0
print("sigmoid hosilasi z=8 da:", f"{sigmoid_hosila_qiymati(z):.8f}")
print("ReLU hosilasi z=8 da: ", float(z > 0))
print("10 qatlamdan keyin sigmoid:", f"{sigmoid_hosila_qiymati(z) ** 10:.2e}")
print("10 qatlamdan keyin ReLU: ", float(z > 0) ** 10)
sigmoid hosilasi z=8 da: 0.00033524
ReLU hosilasi z=8 da: 1.0
10 qatlamdan keyin sigmoid: 1.79e-35
10 qatlamdan keyin ReLU: 1.0
z < 0 bo'lganda hosila aniq nol. Agar neyron barcha
namunalarda manfiy z bersa, uning gradienti doim nol
bo'ladi - va u hech qachon o'qimaydi.
Bu "o'lik ReLU" (dying ReLU) muammosi. Odatiy sabab - juda katta o'qitish tezligi (15-bo'lim): bitta katta qadam og'irliklarni shunday siljitadiki, neyron butunlay o'chib qoladi.
Yechimlar:
| Variant | Formula | Izoh |
|---|---|---|
| Leaky ReLU | max(0.01z, z) | Manfiyda kichik qiyalik |
| ELU | z yoki α(eᶻ-1) | Silliq, sekinroq |
| GELU | Silliq taqribiy | Transformerlarda standart |
Amalda ReLU ko'p hollarda yetarli. Agar tarmoq o'qimayotgan bo'lsa, "nechta neyron doim nol beryapti?" degan savolni bering - bu tez-tez javob bo'lib chiqadi.
def leaky_relu(z, qiyalik=0.01):
return np.where(z > 0, z, qiyalik * z)
def leaky_relu_hosila(z, qiyalik=0.01):
return np.where(z > 0, 1.0, qiyalik)
z = np.array([-3.0, -0.5, 0.5, 3.0])
print("leaky relu:", leaky_relu(z))
print("hosila: ", leaky_relu_hosila(z))
leaky relu: [-0.03 -0.005 0.5 3. ]
hosila: [0.01 0.01 1. 1. ]
O'lik neyronni ko'rish #
gen = np.random.default_rng(7)
X = gen.normal(0, 1, (200, 10))
# ataylab yomon boshlangan qatlam: barcha siljishlar juda manfiy
W = gen.normal(0, 0.5, (10, 8))
b = np.full(8, -5.0)
A = np.maximum(0.0, X @ W + b)
olik = (A == 0).all(axis=0)
print("har neyron uchun nolga teng chiqishlar ulushi:")
print(np.round((A == 0).mean(axis=0), 3))
print("butunlay o'lik neyronlar soni:", int(olik.sum()), "/ 8")
har neyron uchun nolga teng chiqishlar ulushi:
[0.995 1. 1. 0.995 1. 1. 1. 1. ]
butunlay o'lik neyronlar soni: 6 / 8
Sakkiz neyrondan oltitasi barcha 200 namunada nol qaytardi - ular o'qish imkoniyatini butunlay yo'qotgan. Qolgan ikkitasi ham deyarli o'lik: ular namunalarning 99.5% ida nol beradi.
- Ikkita chiziqli qatlamni bitta matritsaga siqing va tenglikni tasdiqlang.
- Sigmoidni yozib,
[-6, 6]oralig'ida qiymatlarini chop eting. sigmoid(-1000)ni sodda va barqaror yozuvda solishtiring.- Sigmoid hosilasini sonli hosila bilan tekshiring.
0.25 ** 10ni hisoblang va yo'qolayotgan gradientni tushuntiring.tanhva uning hosilasini chop eting.- Nima uchun "markazi nolda" bo'lish yaxshi ekanini ayting.
- ReLU va uning hosilasini yozing.
- Leaky ReLU ni yozib, manfiy qiymatdagi farqni ko'ring.
- Siljishni
-5qilib, o'lik neyronlar sonini hisoblang.
Xulosa #
- Faollashtirishsiz yuz qatlam ham bitta qatlamga siqiladi.
- Sigmoid
(0, 1)beradi - ehtimollik kabi o'qiladi. np.expkatta manfiy sonda toshadi - barqaror yozuvni biling.σ'(z) = σ(z)(1 - σ(z))- hosila chiqish orqali ifodalanadi.- Sigmoid hosilasi eng ko'pi bilan
0.25. - Sonli hosila (
(f(x+h)-f(x-h))/2h) - formulani tekshirish usuli. 0.25¹⁰ ≈ 1e-6- yo'qolayotgan gradient.tanhmarkazi nolda va hosilasi1gacha - sigmoiddan yaxshiroq.- ReLU hosilasi
1yoki0- gradient yo'qolmaydi. - ReLU o'lishi mumkin - Leaky ReLU yoki kichikroq o'qitish tezligi.
Keyingi bo'limda bu qismlarni birlashtiramiz va to'liq oldinga tarqalishni quramiz.
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.