Унших хугацаа: 5 минут
Зиак гүний сургалтын систем хэрхэн кодчилох талаар ярилцая. Хэдхэн хоногийн өмнө бичсэн энэ нийтлэлд онолын талаарх бүх хэрэгтэй зүйлсийг ярьсан. Хэрвээ уншаагүй бол эндээс, бас эндээс хиймэл оюун ухааны талаарх нийтлэл бас уншаад үзээрэй. Анхааруулахад уншиж эхлэхээсээ өмнө кола, пепси, цай, пиво, ганц хундага, мокка, капучино, айриш коффее ч юм уу юугаа ч ууж толгойгоо сэргээдэг юм тэрийгээ ууж сэргээж байгаад уншаарай. Миний бичиж байсан хамгийн хүн ойлгоход хэцүү fuck-up нийтлэл биш ч гэсэн бичигдсэн материал нь дэлхийн шилдэг их сургуулиудын нэг улирлын онолын материалын түүвэртэй дүүцэхүйц.
Өмнөх нийтлэлд онолын талаас хэрэгтэй бүх зүйлс (яахав ганц хоёр “no one really cares to bother” юм орхисон л доо) бичсэн болохоор энд шууд python, pytorch-д код бичих талаас нь яаж яагаад гэдэг талаас нь бичнэ. Эхлээд python-д бичсэн гүний сүлжээний талаар:
Mэдээж numpy сан ашиглаж янз бүрийн матрикc үйлдлүүдийг хийнэ. Ямар гараараа бичиж бүүр тийм хүй нэгдлийн байдал руу үсрэлтэй ч биш дээ тийм ээ. Эхний мөрөнд numpy-аа дуудаж ирээд scipy-аас ганц sigmoid функц бас дуудав. Тэр sigmoid-г бол гараараа бичсэн ч болно. Ямар ч ялгаа гарахгүй.
Дараа нь гүний сүлжээний классаа train, query гэх хоёр функцтэй үүсгэж байна. Query бол өгөгдөл оруулаад гүний давхаргаас сүлжээний гаралт хүртэл нэг тооцоо хийх forward propagation функц. Харин train бол нэг forward, backward propagation хийх явцыг удирдах юм. Backward хийсний дараа тэндээ уг сүлжээнийхээ weight-г ч бас өөрчлөлт хийнэ. Тэрний томъёог санаж байгаа биз?
Мэдээж классаа үүсгэхдээ уг сүлжээний оролт, гүний, гаралтын давхарга чухам ямархуу байхыг зааж өгнө. Энэ гүний сургалтын сүлжээ маань зөвхөн сургалтын зориулалтаар учраас гурван давхарга бүхий сүлжээ. Үүний хажуугаар сурах эрчийг ч тодотгож өгөхөөр класаа зохион байгуулав. Яахав хүмүүс өөрөөр бичихийг хүсэл өөрсдөө учраа олно биз.
За класс үүсгэж байхад яг юу болох талаар харвал:
Оролт, гүн, гаралтын давхаргаа шууд заагаад үүсгэж байгааг түрүүн харсан байх харин энд бол гүний сүлжээний weight-г жирийн тархацаас жишээлж татаж авав. Эдгээр тоо маань сургалтын явцад өөрчлөгдөх учраас энэ тоо маань таамгаар гаргаж ирсэн тоо байх л чухал. оролтоос гүний давхарга уруу орох завсарт байх weight-н матрикс. Үүнтэй адил бол гүний давхаграас гаралт руу тооцоо хийхэд хэрэглэгдэх матрикс. Бусдаар ч тэгээд нам жим дээ, харин сургалт хийх явц бол:
inputs, targets бол зөвхөн оруулж ирж буй датагаа яг numpy array болгож байгаа л илүү үйлдэл. Чухал биш. Харин тэрний дараачийн мөрүүдэд тооцоолол хийж байгаа байдал бүгд төстэй. Ньюронд ирэх өгөгдлүүдийг нийлүүлэх үйлдийг гээд дотоод үржвэр хийж аваад тэрийгээ ньюроны идэвхжүүлэгч функц руу оруулаад гаралтыг нь дараачийн ньюронд өгөгдөл болгоно. Харин нэгэнт гаралт дээр ирсэний дараа output_error-оор хэр их алдаатай байгааг баримжаалаад тэр алдаагаа буцааж гүний сүлжээгээр давалгаалуулчихна. Яахав цунами шиг том давалгаалахгүй ч Дагваа аварга дэвжээгээ дэлсэхэд Япон доргидог шиг юм тэр сүлжээндээ болно оо болно.
Жишээ гүний сүлжээ маань гурван давхар учраас хоёр алдааны тооцоо хийгдэнэ. Тэр нь юу вэ гэхээр гүний давхаргаас гаралт руу нэг, оролтоос гүний давхарга руу нэг. Тэдгээрийг тус тус бодоод харгалзах weight-үүдийг түрүүчийн нийтлэлд гаргалгааг нь хийсэн томъёоны дагуу өөрчилчихөж байгааг сүүлийн хэдэн мөрөнд харж болно.
Гүний сургалтын систем ер нь ингэсхийгээд болчихож буй бол тэрийг шалгаж үзэх, оруулсан өгөгдөлд таарах таамаг гаргаж ирэх фунц мэдээж хэрэг болох ба тэрийг query гээд биччихэв:
Яг нөгөө forward propagation. Угаасаа өгөгдлөөс эхлээд гүний давхаргуудаар явсаар байгаад гаралт дээр очиж тооцоолол хийгдэн үр дүн гаргах л үүрэгтэй юм.
Нэгэнт гүний давхаргын системээ бичсэнээс хойш одоо бол үүнийгээ сургах хэрэгтэй:
Энд neural_network гээд зэргэлдээ файлаас сая бичсэн класаа NN гэж нэрээр дуудаж оруулав. Тэгээд MNIST маань пиксель бүхий вектор болох учаас өгөгдөл давхаргаа тэр ёсоор оруулаад 10н тоо таниж сурах систем болохоор тэрний дагуу гаралтаа тохируулаад, гүний давхаргыг бол атаа таван тэнгэрийнхээ аясыг харж байгаад л зайсангаас бөө дуудуулж байгаад бүүмт ламтангаар адислуулаад л 100 гээд өгчихсөн юм. Сургах эрчийг 0.1 гэж алтан дундаж тоогоор оруулж өгсөн бол epochs буюу хэр олон удаа сургалт явуулахыг бол 2 гээд бага тоо оноочихсон. 2000 ч гэж болно л доо. Чухам ямархуу сургах эрч, сургах тоо хэрэгтэй вэ гэдгийг олон туршилт хийж байж л шийднэ шүү дээ.
Одоо тэгээд хэд сургах гэж оноосон тоогоор сургалтын дата бүрт байх жишээ бүрт сургах процессоо хийнэ шүү дээ. Энд бол яг NN класаа дуудаж train фунцыг нь дуудаж байгаагаас бусад нь бол дан өгөгдөл датагаа янзалж байгаа үйлдлүүд. Өгөгдөл маань зураг учраас тэрийг 0-1 утгатай болгохын тулд 255-р хуваагаад, 0.01-г нэмж яг тэгээс жаахан холдуулж байгаа юм. Яагаад гэхээр sigmoid маань ямар ч тоог 0-1 хооронд болгох ч хэзээ ч яг таг 0, 1 болгохгүй болохоор өгөгдөл датагаа тэдгээр хязгаараас холдуулж байгаа юм. Заавал ингэж гараар бүх тооцоог хийж байхаар уг зурагны хар цагаан утгыг оруулаад элдэв нэмэлт юм хийлгүйгээр шууд сургалт хийж болно л доо. Энд бол өгөгдөл датагаа заавал, бүүр заавал нэг хэвд оруулж янзлах хэрэгтэй гэдгийг үзүүлэх гэж л ингэж бичсэн юм. Яагаад тэгэх ёстойг онол бичсэн нийтлэлээс уншаарай.
Сургах явц бол ингээд л болоо. Энэ гүний сургалтын системийг тест хийгээд үзэхэд 95%-н нарийвчлалтай. Яахав одоо ч угаасаа стандарт болсон үзүүлэлт л дээ. Keras, tensorflow, pytorc гэх мэт сургалтын хэрэгсэлд MNIST-г таних энгийн систем бичээд үзэхэд үзүүлэлт нь 93-96% хавьцаа гарна. Эргээд дээрх кодуудыг харж үзвэл өгөгдөл датагаа бэлдэхээс бусад нь их амархан байгаа биз. Нэг тийм тэдгээрхийг бүгдийг нь бэлэн функц болгочихоод өгөгдөл датагаа нэг хэвд оруулж янзлаад тэр бэлэн функцүүдээ дуудаад ашиглаад сууж баймаар санагдаж байгаа биз?
Яг энийг нөгөө гүний сургалтын хэрэгслүүд хийдэг юм. Сургалтын хэрэгтэй функцуудыг өгөгдөл дата нь янзлагдсан байна гэж тооцоолж бичээд, тэр функцуудын ажиллагааг хурдасгах тал дээр их нарийн ажилладаг. Дан python дээр бичсэн тэр код CPU-нд л ажиллах бол янз бүрийн гүний сургалтын хэрэгслүүд дээр бичсэн бол GPU энэ тэрд дуудагдаж хэдэн зуу дахин хурдан ажиллана.
Гэснээс Pytorch дээр бичсэн гүний сургалтын систем харж үзвэл:
Энд өмнөх шигээ 784, 10 гэх тоо байгаа бол гүний давхаргыг энд 200 гэж өгөв. Pytorch нэгэнт машин сургалтанд зориулагдаж бичсэн хэрэгсэл учраас ньюрон мэт бол цаанаасаа байлгүй яахав. Дээр бол nn.Sequence гэж дараалсан ньюрон үүсгэх класс дуудаад тэрэнд өөрийнхөө сүлжээг хэдэн давхаргатай, давхарга бүр ямар activation function-тэй гэдгийг зааж өгөөд л ашиглачихаж байгаа юм. nn.Linear бол өмнөх жишээний дотоод үржвэр, nn.ReLu бол sigmoid-оос арай өөр activation function, nn.LogSoftmax бол sigmoid-н ерөнхий хэлбэр нь. Энэ жишээнд бол дундаа хоёр гүний давхаргатай гүний сүлжээ бичигдэв. Nn.Linear-н эхний параметер тухайн ньюроны өгөгдөл авах хэмжээс бол дараагийнх нь гаргах өгөгдлийн хэмжээс.
Гүний сүлжээг үүсгэх нь ийм шулуухан бол сургах нь ч бүүр амар:
Сургах эрч бол тодорхой. Critetion-оор pytorch-ид алдаа тооцоох функээ тэмдэглэдэг уламжлалтай бол optimiser харин алдаа багасгах тооцоо хийх функц. Энд pytorch-д бичигдсэн байгаа бэлэн функцүүдээс шууд дуудаж ирээд л туршилтаа хийж болох болохоор их амар. Одоо тэгээд л сургалт хийх тоо тутам сургах гэж бэлдсэн дата бүрт сургалтаа явуулна даа. Optimiser.zero_grad() гэж сургалтын эхэн бүрт тухайн сургалтын алдаа олох gradient-г тэглэж эхэлж байгаа ба оролтоос гаралт хийх бүх тооцоог ганц model.forward() гэж дуудаад, алдаагаа нөгөө criterion-оор олоод буцааж давалгаалахыг бол зүгээр л model.backward() гээд тооцох бол, алдаа багасгах gradient олохдоо optimiser.step() гээд л болоо.
Гүний сургалтын систем бичих бол ердөөсөө ингээд л болоо. Чухам яагаад ингэж ийм тооцоонууд хийгдэв гэдгийг онол бичсэн нийтлэлээс уншиж үзнэ буй за. Бусдаар тэгээд юу байхав дээ. Python болон Pytorch дээрх кодыг бүтнээр нь эндээс jupyter-ээр харж үзээрэй. Гэснээс deep reinforcement learning гэж сонссон уу?
Д.Төмөртогтох
2019.03.19
Image source: Photo by Markus Spiske on Unsplash