Mashinali o’rganish
Kirish
Bizning asosiy maqsadimiz ushbu fanlarni bosqichma-bosqich o’rganish. Shuning uchun ushbu bobda biz Mashinali o’rganish fanini o’rganishni boshlaymiz. Ushbu fan boshlovchilarga og’irlik qimasligi uchun birinchi qisqacha ta’rif berib, undan so’ng amaliy masala yechishni boshlaymiz. Keyinchalik esa ushbu mashinali o’rganish masalarini matematik ko’rnishda tasvirlashni batafsil o’rganamiz. Albatta ushbu amaliy masalada biz oldingi qismlarda o’rgangan bilimlarnimizni ishga solamiz. O’quvchiga oldin aytib o’tilganidek, shu vaqtgacha berilgan masalarni va topshiriqlarni ishlab chiqish qattiq tavsiya etamiz.
Machinali o’rganish - sun’iy intellektning o’rganish sohasi bo’lib, u statistik algoritmlarning umumlashtirish qobilyatini takomillashtiradi hamda vazifalarni odamning oshkor ko’rsatmalarisiz bajaradi. Ushbu ta’rif ko’pchilik o’quvchilarga tushunarsiz bo’lishi turgan gap shuning uchun, bu fanining asosiy metod turlariga qisqacha to’xtalib, keyin masalaga o’tamiz. Ushbu turlarning eng muhimlari: o’qituvchili (supervised) va o’qituvchisiz (unsupervised) o’rganish. Ushbu turlar ham bir qancha yana ichki turlarga ajaratiladi. Bular haqida keyinchalik so’z yuritamiz.
Biz ushbu qo’llanmada bir qator algoritmlarni keltirishni ko’zlaganmiz. Shuning uchun ham ularni ba’zida algoritm, model yoki usul deb almashtirib ishlatamiz. Albatta bular o’rtasida faqrlar mavjud va bu farqlarni bi
Amaliy masala
Masala. Ta’savur qilaylik bizga rasm berilgan va ushbu rasmda faqat 0 dan 9 bo’lgan raqamlardan faqat bittasi yozilgan. Biz shu rasmda qanday raqam borligini anqilovchi dastur yozishimiz kerak. Albatta, bu dastur Mashinali o’rganish algoritmi asosida bo’ladi.
Rasmni xotirada saqlash. Buning uchun biz, avvalo, bu rasmlar qanday mashina xotirasida saqlanishini tushunishimiz zarur bo’ladi. Soddalik uchun rasm faqat oq va qora rangdan iborat hamda o’lchami 28 pikselga 28 piksel bo’lsin deymiz. Rasmlar har doim piksellarda beriladi hamda har bir piksel 0 dan 255 gacha bitta raqam bilan ifodalanadi. Masalan, tim qora rangning qiymati 0 bo’lsa, eng oppoq rang 255 bo’ladi. Shunday qilib biz rasmni juda kichkina katakchalarga ajratib ularga 0 dan 255 gacha bo’lgan raqamlardan rangiga mosini qo’yib qo’yamiz va ularni shu ko’rinishda xotirada saqlaymiz. Ushbu, har xil turdagi ma’lumotlarni son ko’rinishda mashina xotirasida saqlash uchun tasvirlash kodlash yoki (encode) deyiladi.
Namunaviy rasmlar to’plami. Mashinali o’rganish fanida bunday rasmlardan tashkil topgan bir qancha tayyor namunalar mavjud bo’lib, ulardan mutaxasislar o’zlarning ilmiy ishlarida foydalanishadi hamda natijalarni shu asosida baholashadi. Ulardan hozirgi bizning sodda masalamizga mosi bu MNIST rasmlar to’plami. Unda jami 70000 dona rasm bo’lib, har bir rams 28 ga 28 pikseldan iborat hamda ular qo’lda yozib chiqilgan. Quyida ulardan ba’zi namunalar.
Yuqoridagi rasmda to’plamdan har bir raqamning 10 tadan turli xil ko’rinishini chiqardik. E’tibor berib qarasak, ular qo’lda yozilganligi va bir biridan tubdan farq qilishini ko’rishimiz mumkin. Bu kabi namunalar, rasmlar, bizga algoritmni o’rgatish uchun kerak bo’ladi. Odatda inson biror narsadan bitta yoki bir nechta namuna ko’rganda uni esalab qoladi hamda keyinchalik uni boshqa narsalardan osongina farqlay oladi. Lekin mashina uchun o’rgatilgan algoritmlar bu kabi narsa hozircha unchalik qodir emas. Bu haqida ham keyinchalik batafsil mulohaza qilamiz, nega ekanligini.
Algoritm. Demak bizga shulardan biror rasm berilsa, biz yozgan kod ushbu ramsda qaysi raqam borligini chiqarishi kerak. Yuqorida aytganimizdek, har bir rasm 28 ga 28 piksel o’lchamda bo’lib, jami 784 ta 0 dan 255 gacha bo’lgan sonlar bilan ifodalangan. Biz yuqorida o’qituvchili mashinali o’rganish turini yozgan edik. Hozir ushbu turdagi algoritm bilan joriy masalani yechamiz.
MNIST rasmlar to’plamida jami 70000 rasm mavjud hamda bu rasmlar ikki qismga bo’lingan: algoritmni o’rgatish uchun 60000 dona rasm va qolgan 10000 donasi esa ushbu algoritmni sinash uchun. Ushbu 70000 ta rasmning har biri uchun ularda qanday raqam turgani ham bizga ma’lum. Agar sizdam ushbu holatda, “biz qanday masala yechamiz degan savol tug’ilsa?”. Biz avval 60000 ta rasm va ularda qanday raqam borligini bilgan holda algoritmni o’rgatib olamiz. Keyin esa sinov to’plamdagi 10000 ta rasmda qaysi raqam joylashganini algoritm orqali aniqlaymiz. Oxirida esa bizning algoritm aniqlagan natija bilan sinov to’plamda bo’lgan haqiqiy natijalarni solishtiramiz hamda shu orqali biz algoritmni qanday ishlayotganini baholaymiz.
Albatta ushbu jarayonda algorimtni tushunish bizga qiyinchilik tug’diradi. Shuning uchun keling amaliy tushunishga o’taylik. Tassavur qilaylik bizga sinov to’plamdan bitta rasm keldi (uning qiymatlari keladi), biz u rasmni bizda oldindan mavjud bo’lgan 60000 ta rasmga solishtirib ko’ramiz va ularning ichidan bu rasmga eng yaqinini topamiz. Shundan so’ng, bizga berilgan rasmda joylashgan raqam sifatida topilgan eng yaqin rasmning raqami olamiz. Ya’ni, sodda qilib aytsak, rasmda qanday raqam joylashgani unga eng yaqin bo’lgan rasmda qanday raqam joylashgan bo’lsa, shu bilan bir xil hisoblanadi.
Biz ikki rasm bir-biriga qanday yaqinligini bilish uchun ular o’rtasidagi masofa topamiz. Masofani esa ikki vektor orasidagi masofa sifatida qarashimiz mumkin. Vektorlar orasidagi masofani ifodalashning bir qancha usullari mavjud va ularning o’ziga xos afzaliklar va kamchiliklari bor. Biz soddalik uchun ikki vektor orasidagi masofa sifatida ikki rasmdagi mos piksellarning qiymatlarning ayirmasining absolutni (masalan, ya’ni moduli) olamiz. Lekin bu qiymatlar jami 784 (chunki har bir ramsda shuncha piksell bor). Bular hammasi bir xil ma’noni (piksellar o’rtasidagi mutloq farq) agnlatgani uchun ularning yig’indisini topamiz. Oxir oqibatda ushbu yig’indi bizga ikki rasm orasidagi masofani beradi. Quyidagi kodda dastlab berilgan 60000 ta rasmni yuklash keltirilgan.
[1]:
# o'rgatuvchi to'plamni olaylik
# funksiyani import qilish
from datasets import MNIST_train
# ushbu funksiyada ikkita qiymat bor
# 1-rasmlar, 2- ularning mos raqamlari
images, digits = MNIST_train()
print(f"O'rgatuvchi tanlanmada {len(images)} ta rasm bor")
O'rgatuvchi tanlanmada 60000 ta rasm bor
Oldingi koda biz birinchi 60000 ta rasmdan iborat bo’lgan to’plamni ikkita o’zgaruvchiga yuklab oldik, bular images
hamda digits
. Buni amalga oshirish uchun avval shunga mos funkisya yozdik. Odatda funksiyalarni o’zimiz ham yaratishimiz va ulardan qayta-qayta foydalanishimiz mumkin huddi biz len
funksiyasi kabi. Ushbu mavzuni keyinchalik o’rganib chiqamiz, chunki bu funksiya avvaldan datasets.py
fayliga yozib qo’ydik, shu sababdab siz azizlardan faqat tayyor funksiyani
o’zimizning kodimizga qanday chaqirish (import qilish) va undan foydalanishni o’rganishni so’raymiz. Tayyor e’lon qilingan o’zgaruvchi yoki mavjud funskiyani chaqirish uchun biz avval from
kalit so’zini yozamiz, keyin ushbu o’zgaruvchilar yoki funksiya qaysi faylida ekanligni bildirish uchun fayl nomni yozamiz va oxirida esa import
kalit so’zidan keyin, ushbu fayldagi qaysi o’zgaruvchilar yoki funksiyalar kerak bo’lsa, ularning nomalarini birma-bir vergul orqali joriy kod qismiga yozib
chiqamiz. Yuqorida esa, from datasets import MNIST_train
, bu yerda datasets
fayl nomni (to’liq nomi datasets.py
, py
bu kengaytma shuning uchun uni tashlab ketamiz), keyingisi esa MNIST_train
bu funksiya nomi. Bu funksiya hozircha hech qanday parameterga ega emas va u 2 ta qiymat qaytaradi. Ushbu qiymatlarni ikkita alohida o’zgaruvchiga yuklash uchun biz vergul bila shu o’zgaruvchilar nomidan keyin tenglik belgisini qo’yib MNIST_train()
funksiyasini chaqirdik, ya’ni
images, digits = MNIST_train()
. Keling ushbu rasmlarning birinchisining 200 pikseldan to 228 gacha qiymatlarini va unda qanday raqam turgani ko’raylik.
[2]:
# yuqoridagi kod yozilgan deymiz
i = 0
print('Uning raqami: ', digits[0])
print('200 dan 228 qiymatlari: ')
while i < 28:
# 1-rasm uchun bitta indeks, ya'ni 0
# keyingi indeks esa uning qiymati uchun
# bitta qatorda chop qilish uchun: end=' '
print(images[0][i+200], end=' ')
i = i + 1
Uning raqami: 5
200 dan 228 qiymatlari:
0 0 0 49 238 253 253 253 253 253 253 253 253 251 93 82 82 56 39 0 0 0 0 0 0 0 0 0
Boshqacharoq holatda
[3]:
# yuqoridagi kod yozilgan deymiz
print('Uning raqami: ', digits[0])
print('200 dan 228 qiymatlari: ')
print(images[0][200:228], end=' ')
Uning raqami: 5
200 dan 228 qiymatlari:
[ 0 0 0 49 238 253 253 253 253 253 253 253 253 251 93 82 82 56
39 0 0 0 0 0 0 0 0 0]
Biz yuqoridagi funksiya oraqli olingan rasmlar quyidagicha o’lchamda birinchi asosiy ro’yxatda jami 60000 ta rasm bor va har bir rasm 784 ta raqam bilan ichki ro’yxat ko’rinishida ifodalangan. Ya’ni bu vektor ko’rnishga o’tkazilgan rasmda keltirilgandek 28 ga 28 o’lchamli ro’yxat ichida yana ro’yxat emas. Buni amalga oshirish juda sodda keyinchalik bu haqida o’rni kelganda batafsil ma’lumot beramiz. Bundan keyingi kod esa 1-rasm va 10-rasm orasidagi farqni topib berishga misoldir.
[8]:
# rasmlarni alohida o'zgaruvchilarga
# yuklaymiz qulaylik uchun
image_1 = images[0]
image_2 = images[10]
# yig'indi bo'lgani uchun
# boshlang'ich qiymat 0 ga teng
s = 0
# sanash uchun
i = 0
while i < 784:
# ikki rasm o'rtasidagi farq
diff = image_1[i] - image_2[i]
# masofa manifiy bo'lmasligi
# uchun uni musbatga aylantiramiz
abs_dist = abs(diff)
# jami yig'indiga qo'shamiz
s = s + abs_dist
# sanashni oshirish
i = i + 1
print('1- va 10-ramslar orasidagi masofa: ', s)
1- va 10-ramslar orasidagi masofa: 24255
Funksiya ko’rinishida quyidagicha bo’ladi:
[7]:
def distance(image_1, image_2):
# yig'indi bo'lgani uchun
# boshlang'ich qiymat 0 ga teng
s = 0
# sanash uchun
i = 0
while i < 784:
# ikki rasm o'rtasidagi farq
diff = image_1[i] - image_2[i]
# masofa manifiy bo'lmasligi
# uchun uni musbatga aylantiramiz
abs_dist = abs(diff)
# jami yig'indiga qo'shamiz
s = s + abs_dist
# sanashni oshirish
i = i + 1
return s
dist = distance(images[0], images[10])
print('1- va 10-ramslar orasidagi masofa: ', dist)
1- va 10-ramslar orasidagi masofa: 24255
Yuqoridagi kodda quyidagilarni ketma-ket bajardik:
ikkita ramsni qulaylik uchun alohida o’zgaruvchilarga yuklab oldik, bular
image_1
vaimage_2
har bir mos piksellar o’rtasidagi masofani yig’ib borish uchun,
s = 0
oldikwhile
takrorlash operatori orqali vektorlarning piksellarni orasidagi masofalarni har bir elementi bo’yicha birma-bir hisoblab chiqamiz.ikki piksel orasidagi farqni oldik,
diff = image_1[i] - image_2[i]
masofa musbat bo’lishi kerak, shuning uchun farqning modulini olamiz,
abs_dist = abs(diff)
.abs()
funksiyasi bizga ixtiyoriy haqiqiy soning musbat qiymatini hisoblab beradi. Masalan, unga 5 qiymat bersak bizga 5 qaytaradi, agar -5 qiymat bersak unda ham uning musbat qiymati bo’lgan 5 qaytaradi.Oxirida esa masofalarni yig’dik va sanagichni bittaga oshirdik.
Keyingi bosqichlarda oson bo’lishi uchun yuqoridagi kodni funksiya sifatida distances.py
fayliga yozib qoydik. U ikkita vektor qabul qiladi hamda ular orasidagi yuqorida ko’rsatilgan masofaning qiymatni hisoblaydi va qaytaradi. Uni quyidagicha chaqirib ishlatishimiz mumkin.
[9]:
from distances import distance
image_1 = images[0]
image_2 = images[10]
s = distance(image_1, image_2)
print('1- va 10-ramslar orasidagi masofa: ', s)
1- va 10-ramslar orasidagi masofa: 24255
Bizda ikki rasm orasida masofa mavjud bo’lsa, u holda rasmni mavjud rasmlar bilan solishtirish orqali qaysi rasmga eng yaqin ekanligini aniqlashimiz mumkin bo’ladi. Buning uchun qidirish algoritmidan foydalanamiz:
while
orqali takrorlash hosil qilamiz60000 ta rasmdan iborat to’plamdan ramslarni bittalab olib
bizga berilgan rasm bilan o’rtasidagi masofani topamiz
agar masofa oldingi masofadan kichik bo’lsa, u holda shu rasmning nechanchi o’rinda turganligini eslab qolamiz
takrorlashdan so’ng eng yaqin rasmning indeksi orqali uning raqamini aniqlaymiz hamda uni bizga berilgan rasmning raqmi deb javob qaytaramiz.
Quyidagi kod ushbu jarayoni amalga oshiradi. Buning uchun avval biz 1000 ta rasmdan iborat bo’lgan sinov to’plamni xotiraga yuklab olishimiz kerak bo’ladi. Buning uchun ham bizda tayyor funksiya bor, u MNIST_test
xudi oldinigisi kabi ishlatiladi. Faqat o’zgaruvchilarning nomiga test
qo’shimchalarini qo’shamiz oldingi o’zgaruvchilardan farqlash uchun.
[10]:
# to'plamlarni yuklash
from datasets import MNIST_train, MNIST_test
images, digits = MNIST_train()
test_images, test_digits = MNIST_test()
# ixtiyoriy rasm sinov to'plamdan
k = 0
img = test_images[k]
# eng yaqin masofa
# boshida u juda katta son
min_dist = 1000000000000
# eng yaqin ramsning indeks
# noma'lum
min_ind = -1
# sanagich
i = 0
# bizda 60000 ta rasm bor
# solishtirish uchun
while i < len(images):
# joriy rasm
curr_img = images[i]
# joriy rams bilan sinov rasm ortasidagi
# masofa
dist = distance(curr_img, img)
# joriy rasm oldingisidan yaqinroqmi
if min_dist > dist:
# shunday bo'lsa
# yaqin masofa yangisiga o'tadi
min_dist = dist
# indeks ham o'zgaradi
min_ind = i
# sanagichni oshirish
i = i + 1
# natijalarni chop etish
print("Haqiyqiy javob: ", test_digits[k])
# min_ind - eng yaqin rasm indeksi
print("Algoritm topgan javob: ", digits[min_ind])
Haqiyqiy javob: 7
Algoritm topgan javob: 7
Yuqorida biz algoritmni sinov to’plamdagi 1-rasm uchun ishlatib ko’rdik, natijalar to’g’iri chiqidi. Quyidagi jadvalda bir nechata ishlatishlari natijasi keltirilgan.
Sinov to’plamdagi rasm indeksi |
Haqiqiy javob (qaysi raqamligi) |
Algoritmning javobi(qaysi raqamligi) |
---|---|---|
0 |
7 |
7 |
10 |
0 |
0 |
355 |
8 |
8 |
Yuqorida biz sinov qilgan hamma indekslarda natijalar bir xil chiqayabdi, lekin aslida unday emas, chunki har doim algorimtda xatolik bo’ladi. Bu haqida keyinchalik batafsil mulohasa yuritamiz. Hozirgi algoritmning o’rtacha bahosi esa 98%, ya’ni birinchi 100 ta rasmdan 98 tasini to’g’iri topa oladi. Bu juda yuqori natija chunki masalamiz juda sodda. Yuroqidagi kodning hamma sinov rasmlarni tekshirish uchun takomillashtirib, uni experiments.py
faylida nearest_neighboor_mnist()
funksiyasi
sifatida hosil qildik. Lekin biz uni hamma rasmlar bilan ishlatsak taxminan 33 soatdan ko’p vaqt ketib qoladi. Ushbu algorimtning kamchilik va yutuqlarini batafsil mulohaza qilamiz.
[8]:
from experiments import nearest_neighboor_mnist
accuracy = nearest_neighboor_mnist(100)
print('Ushbu metodning aniqligi: ', accuracy * 100, '%')
Ushbu metodning aniqligi: 98.0 %