2-bo‘lim

NumPy - vektorlar va matritsalar

Vektorlashtirish, shakllar, translyatsiya va matritsa ko'paytmasi - tarmoq kodining butun asosi.

🕑 19 daqiqa o‘qish 📄 1 016 so‘z 👁 1 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. Massiv yaratish
  2. Vektorlashtirish
  3. Translyatsiya (broadcasting)
  4. Matritsa ko'paytmasi
  5. O'q (axis) bo'yicha yig'ish
  6. Tasodifiy sonlar va takrorlanuvchanlik
  7. Shaklni o'zgartirish
  8. Xulosa

Neyron tarmoq kodi deyarli butunlay matritsa amallaridan iborat. Shu sababli NumPy ni bilish - tarmoqni tushunishning yarmi.

Massiv yaratish #

Python
import numpy as np
Python
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)
Natija
vektor  shakli: (3,) o'lchov: 1
matrisa shakli: (3, 2) o'lchov: 2
turi: float64
Yaratish usuliNatija
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
Python
print(np.arange(0, 1, 0.25))
print(np.linspace(0, 1, 5))
Natija
[0.   0.25 0.5  0.75]
[0.   0.25 0.5  0.75 1.  ]
arange oxirini qo'shmaydi, linspace qo'shadi

Bu farq juda ko'p xatoga sabab bo'ladi:

BuyruqElementlar soniOxirgi qiymat
np.arange(0, 1, 0.25)40.75
np.linspace(0, 1, 5)51.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.

Python
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)
Natija
[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.

Python
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)
Natija
natijalar bir xil: True
NumPy tezroq: True
kamida 10 barobar: True
Aniq vaqtni emas, munosabatni o'lchang

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.

Python
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)
Natija
[[11. 22. 33.]
 [14. 25. 36.]]

qator ikkala satrga ham qo'shildi - garchi shakllari (2, 3) va (3,) bo'lsa ham.

Translyatsiya - shakllar qanday moslashtiriladi Ishlaydi: (2, 3) matritsa + (3,) qator - 2 marta cho'ziladi = (2, 3) natija Qoida - o'ngdan chapga solishtiriladi: 1. O'lchamlar teng bo'lsa - mos keladi. 2. Biri 1 bo'lsa - u cho'ziladi. 3. Biri umuman yo'q bo'lsa - 1 deb hisoblanadi. Ishlamaydi: (2, 3) + (2,) o'ngdan: 3 va 2 - teng emas, 1 ham emas
Shakllar o'ngdan chapga taqqoslanadi
Python
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)
Natija
[[11. 12. 13.]
 [24. 25. 26.]]

Bu safar (2, 1) gorizontal yo'nalishda cho'zildi.

Python
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))
Natija
operands could not be broadcast together with shapes (2,3) (2,) 
Translyatsiya jimgina noto'g'ri natija berishi mumkin

Yuqoridagi xato - yaxshi holat: NumPy to'xtatdi.

Yomon holat esa shakllar tasodifan mos kelib qolganda yuz beradi:

Python
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:

ChoraQanday
Shakllarni chop etingprint(a.shape, b.shape)
Tasdiqlangassert 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:

Python
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)
Natija
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.

Python
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)
Natija
[[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).

AmalMa'nosi
a * bElementma-element ko'paytirish
a @ bMatritsa ko'paytmasi
np.dot(a, b)@ bilan bir xil (vektorlarda skalyar ko'paytma)
a.TTransponirlash
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 juftlik
Python
a = np.array([[1, 2], [3, 4]])
b = np.array([[10, 20], [30, 40]])
AmalNatija
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 *.

Python
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)
Natija
a * b:
[[ 10  40]
 [ 90 160]]
a @ b:
[[ 70 100]
 [150 220]]

O'q (axis) bo'yicha yig'ish #

Python
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)
Natija
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 usuli

axis=N - "N-o'lcham yo'qoladi" degani.

ShaklAmalNatija 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:

Python
db = gradient.sum(axis=0)        # paketdagi barcha namunalar bo'yicha

Tasodifiy sonlar va takrorlanuvchanlik #

Python
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))
Natija
[ 0.3047 -1.04    0.7505]
bir xilmi: True
Urug'siz tajriba - takrorlab bo'lmaydigan tajriba

Neyron tarmoq og'irliklari tasodifiy boshlanadi. Urug' (seed) belgilanmasa, har ishga tushirish boshqa natija beradi.

Oqibati:

VaziyatMuammo
"Kecha ishlayotgan edi"Endi ishlamayapti - sabab noma'lum
Ikki sozlamani solishtirishFarq sozlamadanmi yoki tasodifdanmi?
Xatoni takrorlashIloji yo'q

Shuning uchun har tajribada urug' belgilang:

Python
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 #

Python
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)
Natija
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.

Amaliy topshiriq
  1. (3, 4) shaklli nollar matritsasini yarating.
  2. arange va linspace farqini misolda ko'rsating.
  3. Vektorga * 2, ** 2 va > 0 amallarini qo'llang.
  4. (2, 3) matritsaga (3,) vektorni qo'shing.
  5. (2, 1) ustunni qo'shib, farqni ko'ring.
  6. (2,) bilan qo'shishga urinib, xatoni o'qing.
  7. a * b va a @ b natijalarini solishtiring.
  8. sum(axis=0) va sum(axis=1) shakllarini chop eting.
  9. keepdims=True ning shaklga ta'sirini ko'ring.
  10. Bir xil urug' bilan ikkita generator yaratib, natijani solishtiring.

Xulosa #

  • arange oxirini qo'shmaydi, linspace qo'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=True translyatsiya uchun shaklni saqlaydi.
  • default_rng(urug') - takrorlanadigan tajriba uchun majburiy.

Keyingi bo'limda bitta neyronni to'liq quramiz va uning qaror chegarasini ko'ramiz.

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.