2-bo‘lim
NumPy - vektorlar va matritsalar
Vektorlashtirish, shakllar, translyatsiya va matritsa ko'paytmasi - tarmoq kodining butun asosi.
Ushbu bo‘lim mundarijasi
Neyron tarmoq kodi deyarli butunlay matritsa amallaridan iborat. Shu sababli NumPy ni bilish - tarmoqni tushunishning yarmi.
Massiv yaratish #
import numpy as np
vektor = np.array([1.0, 2.0, 3.0])
matrisa = np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]])
print("vektor shakli:", vektor.shape, "o'lchov:", vektor.ndim)
print("matrisa shakli:", matrisa.shape, "o'lchov:", matrisa.ndim)
print("turi:", matrisa.dtype)
vektor shakli: (3,) o'lchov: 1
matrisa shakli: (3, 2) o'lchov: 2
turi: float64
| Yaratish usuli | Natija |
|---|---|
np.zeros((2, 3)) | Nollar |
np.ones((2, 3)) | Birlar |
np.full((2, 3), 0.5) | Bir xil qiymat |
np.arange(0, 1, 0.25) | Qadam bilan ketma-ketlik |
np.linspace(0, 1, 5) | Teng bo'lingan ketma-ketlik |
np.eye(3) | Birlik matritsa |
print(np.arange(0, 1, 0.25))
print(np.linspace(0, 1, 5))
[0. 0.25 0.5 0.75]
[0. 0.25 0.5 0.75 1. ]
arange oxirini qo'shmaydi, linspace qo'shadiBu farq juda ko'p xatoga sabab bo'ladi:
| Buyruq | Elementlar soni | Oxirgi qiymat |
|---|---|---|
np.arange(0, 1, 0.25) | 4 | 0.75 |
np.linspace(0, 1, 5) | 5 | 1.0 |
arange qadam oladi va oxirini chiqarib tashlaydi
(Python range kabi). linspace esa nechta nuqta
kerakligini oladi va ikkala chetni ham qo'shadi.
Kasr qadam bilan arange ni ishlatmang - suzuvchi nuqta
xatosi tufayli elementlar soni kutilmagan bo'lishi mumkin.
Grafik chizish yoki oraliq bo'lish uchun linspace.
Vektorlashtirish #
Har amal butun massivga birdan qo'llanadi.
x = np.array([1.0, 2.0, 3.0, 4.0])
print(x * 2)
print(x ** 2)
print(np.sqrt(x))
print(x > 2.5)
[2. 4. 6. 8.]
[ 1. 4. 9. 16.]
[1. 1.41421356 1.73205081 2. ]
[False False True True]
Sikl yozilmadi - lekin har element ustida amal bajarildi.
import time
katta = np.arange(1_000_000, dtype=np.float64)
boshlandi = time.perf_counter()
natija_sikl = [q * 2 for q in katta]
sikl_vaqti = time.perf_counter() - boshlandi
boshlandi = time.perf_counter()
natija_numpy = katta * 2
numpy_vaqti = time.perf_counter() - boshlandi
print("natijalar bir xil:", np.allclose(natija_sikl, natija_numpy))
print("NumPy tezroq:", numpy_vaqti < sikl_vaqti)
print("kamida 10 barobar:", sikl_vaqti / numpy_vaqti > 10)
natijalar bir xil: True
NumPy tezroq: True
kamida 10 barobar: True
Yuqoridagi misolda soniyalar chop etilmadi - faqat "tezroqmi" va "10 barobardanmi" degan savollarga javob berildi.
Sabab: aniq vaqt mashinaga, yuklamaga va Python versiyasiga
bog'liq. Bugun 0.08 soniya bo'lgan natija ertaga 0.15
bo'lishi mumkin - va bu hech nimani anglatmaydi.
Tezlikni o'lchaganda doim shunday yozing: "A B dan N barobar tez" - bu barqaror va tekshiriladigan da'vo.
Chindan aniq o'lchov kerak bo'lsa, timeit moduli bir necha
marta takrorlaydi va eng yaxshi natijani oladi.
Translyatsiya (broadcasting) #
Turli shakldagi massivlar ustida amal bajarilganda NumPy kichigini cho'zadi.
matrisa = np.array([[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0]])
qator = np.array([10.0, 20.0, 30.0])
print(matrisa + qator)
[[11. 22. 33.]
[14. 25. 36.]]
qator ikkala satrga ham qo'shildi - garchi shakllari
(2, 3) va (3,) bo'lsa ham.
matrisa = np.array([[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0]])
ustun = np.array([[10.0], [20.0]]) # shakli (2, 1)
print(matrisa + ustun)
[[11. 12. 13.]
[24. 25. 26.]]
Bu safar (2, 1) gorizontal yo'nalishda cho'zildi.
matrisa = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
notogri = np.array([10.0, 20.0]) # (2,) - mos kelmaydi
try:
matrisa + notogri
except ValueError as xato:
print(str(xato))
operands could not be broadcast together with shapes (2,3) (2,)
Yuqoridagi xato - yaxshi holat: NumPy to'xtatdi.
Yomon holat esa shakllar tasodifan mos kelib qolganda yuz beradi:
oldindan = np.array([[0.1], [0.9]]) # (2, 1) - ustun
haqiqiy = np.array([0.0, 1.0]) # (2,) - qator
xato = haqiqiy - oldindan # (2, 2) !!!
Siz ikkita sonli farq kutgansiz, NumPy esa to'rtta son qaytardi - va hech qanday xato bermadi.
Bu neyron tarmoqlarda eng ko'p uchraydigan jimgina xato: yo'qotish g'alati kamayadi, gradient noto'g'ri, sabab esa ko'rinmaydi.
Himoya:
| Chora | Qanday |
|---|---|
| Shakllarni chop eting | print(a.shape, b.shape) |
| Tasdiqlang | assert a.shape == b.shape |
| Ustun/qator ni aniq belgilang | .reshape(-1, 1) yoki .ravel() |
O'qitish sikli yozganda assert qo'yish - bir daqiqa vaqt
oladi, lekin soatlab qidiruvdan saqlaydi.
Yuqoridagi xavfli holatni ko'ramiz:
oldindan = np.array([[0.1], [0.9]])
haqiqiy = np.array([0.0, 1.0])
kutilmagan = haqiqiy - oldindan
print("shakli:", kutilmagan.shape)
print(kutilmagan)
togri = haqiqiy - oldindan.ravel()
print("to'g'ri shakl:", togri.shape, togri)
shakli: (2, 2)
[[-0.1 0.9]
[-0.9 0.1]]
to'g'ri shakl: (2,) [-0.1 0.1]
Matritsa ko'paytmasi #
Neyron tarmoqdagi eng muhim amal.
kirishlar = np.array([[1.0, 2.0],
[3.0, 4.0],
[0.5, 0.5]]) # 3 ta namuna, 2 ta belgi
ogirliklar = np.array([[0.1, 0.2, 0.3],
[0.4, 0.5, 0.6]]) # 2 kirish -> 3 neyron
chiqish = kirishlar @ ogirliklar
print(chiqish)
print("shakl:", kirishlar.shape, "@", ogirliklar.shape, "->", chiqish.shape)
[[0.9 1.2 1.5 ]
[1.9 2.6 3.3 ]
[0.25 0.35 0.45]]
shakl: (3, 2) @ (2, 3) -> (3, 3)
Uchta namuna birdan hisoblandi. Aynan shu sabab tarmoqqa ma'lumot bittalab emas, paket bo'lib beriladi (14-bo'lim).
| Amal | Ma'nosi |
|---|---|
a * b | Elementma-element ko'paytirish |
a @ b | Matritsa ko'paytmasi |
np.dot(a, b) | @ bilan bir xil (vektorlarda skalyar ko'paytma) |
a.T | Transponirlash |
np.sum(a, axis=0) | Ustunlar bo'yicha yig'indi |
np.sum(a, axis=1) | Satrlar bo'yicha yig'indi |
* va @ - eng ko'p chalkashtiriladigan juftlika = np.array([[1, 2], [3, 4]])
b = np.array([[10, 20], [30, 40]])
| Amal | Natija |
|---|---|
a * b | [[10, 40], [90, 160]] - har element o'z jufti bilan |
a @ b | [[70, 100], [150, 220]] - satr x ustun |
Ikkalasi ham (2, 2) qaytaradi - shuning uchun shakl
tekshiruvi bu xatoni tutmaydi.
Qoida: og'irliklarni qo'llash - doim @. Gradientlarni
ko'paytirish (zanjir qoidasi, 9-bo'lim) - odatda *.
a = np.array([[1, 2], [3, 4]])
b = np.array([[10, 20], [30, 40]])
print("a * b:"); print(a * b)
print("a @ b:"); print(a @ b)
a * b:
[[ 10 40]
[ 90 160]]
a @ b:
[[ 70 100]
[150 220]]
O'q (axis) bo'yicha yig'ish #
m = np.array([[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0]])
print("hammasi: ", m.sum())
print("axis=0 (ustunlar yig'indisi):", m.sum(axis=0))
print("axis=1 (satrlar yig'indisi): ", m.sum(axis=1))
print("shakllar:", m.sum(axis=0).shape, m.sum(axis=1).shape)
hammasi: 21.0
axis=0 (ustunlar yig'indisi): [5. 7. 9.]
axis=1 (satrlar yig'indisi): [ 6. 15.]
shakllar: (3,) (2,)
Uchta ustun uchta yig'indi berdi, ikkita satr - ikkita. Shakldan qaysi o'q ishlatilganini darhol bilish mumkin.
axis ni eslab qolishning oson usuliaxis=N - "N-o'lcham yo'qoladi" degani.
| Shakl | Amal | Natija shakli |
|---|---|---|
(2, 3) | sum(axis=0) | (3,) - birinchi o'lcham yo'qoldi |
(2, 3) | sum(axis=1) | (2,) - ikkinchi o'lcham yo'qoldi |
(2, 3) | sum(axis=0, keepdims=True) | (1, 3) - saqlanadi |
keepdims=True ayniqsa foydali: u translyatsiya uchun
shaklni saqlaydi va yuqoridagi (2, 2) xatosining oldini
oladi.
Tarmoqda siljish gradienti aynan shunday hisoblanadi:
db = gradient.sum(axis=0) # paketdagi barcha namunalar bo'yicha
Tasodifiy sonlar va takrorlanuvchanlik #
gen = np.random.default_rng(42)
a = gen.normal(0, 1, 3)
gen2 = np.random.default_rng(42)
b = gen2.normal(0, 1, 3)
print(np.round(a, 4))
print("bir xilmi:", np.array_equal(a, b))
[ 0.3047 -1.04 0.7505]
bir xilmi: True
Neyron tarmoq og'irliklari tasodifiy boshlanadi. Urug' (seed) belgilanmasa, har ishga tushirish boshqa natija beradi.
Oqibati:
| Vaziyat | Muammo |
|---|---|
| "Kecha ishlayotgan edi" | Endi ishlamayapti - sabab noma'lum |
| Ikki sozlamani solishtirish | Farq sozlamadanmi yoki tasodifdanmi? |
| Xatoni takrorlash | Iloji yo'q |
Shuning uchun har tajribada urug' belgilang:
gen = np.random.default_rng(42)
Eski kodda np.random.seed(42) ko'rasiz - u global holatni
o'zgartiradi va boshqa kutubxonalarga ham ta'sir qiladi.
Yangi kodda default_rng ishlating: u mustaqil
generator yaratadi.
Muhim ogohlantirish: urug' belgilangani model yaxshi degani emas. U faqat natijani takrorlanadigan qiladi. Modelni baholashda bir necha turli urug' bilan sinash kerak (19-bo'lim).
Shaklni o'zgartirish #
x = np.arange(6.0)
print("asl: ", x, x.shape)
print("(2, 3): ", x.reshape(2, 3).tolist())
print("(3, 2): ", x.reshape(3, 2).tolist())
print("ustun: ", x.reshape(-1, 1).shape)
print("tekis: ", x.reshape(2, 3).ravel().shape)
asl: [0. 1. 2. 3. 4. 5.] (6,)
(2, 3): [[0.0, 1.0, 2.0], [3.0, 4.0, 5.0]]
(3, 2): [[0.0, 1.0], [2.0, 3.0], [4.0, 5.0]]
ustun: (6, 1)
tekis: (6,)
-1 "bu o'lchamni o'zing hisobla" degani - reshape(-1, 1)
har qanday vektorni ustunga aylantiradi.
(3, 4)shaklli nollar matritsasini yarating.arangevalinspacefarqini misolda ko'rsating.- Vektorga
* 2,** 2va> 0amallarini qo'llang. (2, 3)matritsaga(3,)vektorni qo'shing.(2, 1)ustunni qo'shib, farqni ko'ring.(2,)bilan qo'shishga urinib, xatoni o'qing.a * bvaa @ bnatijalarini solishtiring.sum(axis=0)vasum(axis=1)shakllarini chop eting.keepdims=Truening shaklga ta'sirini ko'ring.- Bir xil urug' bilan ikkita generator yaratib, natijani solishtiring.
Xulosa #
arangeoxirini qo'shmaydi,linspaceqo'shadi.- Vektorlashtirish sikldan o'n barobardan ko'p tez.
- Tezlikni aniq soniyada emas, munosabatda o'lchang.
- Translyatsiya shakllarni o'ngdan chapga solishtiradi.
(2, 1) - (2,)jimgina(2, 2)beradi - eng xavfli xato.*elementma-element,@matritsa ko'paytmasi.- Ikkalasi bir xil shakl qaytarishi mumkin - shakl tekshiruvi yetarli emas.
axis=N- "N-o'lcham yo'qoladi".keepdims=Truetranslyatsiya uchun shaklni saqlaydi.default_rng(urug')- takrorlanadigan tajriba uchun majburiy.
Keyingi bo'limda bitta neyronni to'liq quramiz va uning qaror chegarasini ko'ramiz.
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.