chore(i18n): sync translations with latest source changes (chunk 4/4, 60 changes)

This commit is contained in:
localizeflow[bot] 2026-04-06 20:21:20 +00:00
parent 7a16e4d00e
commit 15889730ce
60 changed files with 19703 additions and 0 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,183 @@
# ការរកឃើញវត្ថុ
ម៉ូដែលចាត់ថ្នាក់រូបភាព ដែលយើងបានប្រើរហូតមកដល់ឡើយ បានយករូបភាពមួយ ហើយបង្កើតលទ្ធផលជាក្រុមវិនិច្ឆ័យមួយ ដូចជា ចំណាត់ថ្នាក់ 'លេខ' ក្នុងបញ្ហា MNIST។ ទោះបីជាយ៉ាងណាក៏ដោយ នៅក្នុងករណីជាច្រើន យើងមិនត្រឹមតែចង់ដឹងថារូបភាព នោះបង្ហាញវត្ថុទេ - យើងចង់អាចកំណត់ទីតាំងពេញលេញរបស់វា។ នេះគឺជាចំណុចដ៏សំខាន់នៃ **ការរកឃើញវត្ថុ**
## [សំណួរមុខបង្ហាត់](https://ff-quizzes.netlify.app/en/ai/quiz/21)
![ការរកឃើញវត្ថុ](../../../../../translated_images/km/Screen_Shot_2016-11-17_at_11.14.54_AM.b4bb3769353287be.webp)
> រូបពី [គេហទំព័រ YOLO v2](https://pjreddie.com/darknet/yolov2/)
## វិធីសាស្រ្តសាមញ្ញសម្រាប់ការរកឃើញវត្ថុ
ហ្មត់ដើម្បីស្វែងរកចម្លែកនៅលើរូបភាពមួយ វិធីសាស្រ្តសាមញ្ញសម្រាប់ការរកឃើញវត្ថុអាចមានដូចខាងក្រោម៖
1. បំបែករូបភាពទៅជាចំនួនផ្ទៃតូចៗ
2. ប្រតិបត្តិចាត់ថ្នាក់រូបភាពលើផ្ទៃតូចនីមួយៗ។
3. ផ្ទៃតូចដែលបង្កើតអាស៊ីវ២០១យស័គ្នាថាប់ខ្ពស់គួរត្រូវបានគិតថាមានវត្ថុដែលត្រូវបានស្នើសុំ។
![ការរកឃើញវត្ថុសាមញ្ញ](../../../../../translated_images/km/naive-detection.e7f1ba220ccd08c6.webp)
> *រូបពី [សៀវភៅកិច្ចវាយតម្លៃ](ObjectDetection-TF.ipynb)*
ទោះជាក៏ដោយ វិធីសាស្រ្តនេះមិនមែនល្អទេ ព្រោះវាគ្រាន់តែអនុញ្ញាតឲ្យកម្មវិធីកំណត់ប្រអប់ដែកដោះថ្លៃរបស់វត្ថុបានយ៉ាងមិនច្បាស់លាស់។ សម្រាប់ទីតាំងពិតប្រាកដជាងនេះ យើងត្រូវបើកការប៉ាន់ស្មានចំនួន **ចុះបញ្ជាក់** ដើម្បីទាយទ្រង់ទ្រាយនៃប្រអប់ដែកដោះថ្លៃ - ហើយសម្រាប់វា យើងត្រូវការបណ្ដុំទិន្នន័យជាក់លាក់។
## ការចុះបញ្ជាក់សម្រាប់ការរកឃើញវត្ថុ
[បទបង្ហាញនេះ](https://towardsdatascience.com/object-detection-with-neural-networks-a4e2c46b4491) មានការណែនាំយ៉ាងល្អបំព្រងសម្រាប់រកឃើញរាងកាយ។
## ឯកសារទិន្នន័យសម្រាប់ការរកឃើញវត្ថុ
អ្នកប្រហែលជាគួរបានជួបប្រទៈឯកសារទិន្នន័យដូចខាងក្រោមសម្រាប់ការងារនេះ៖
* [PASCAL VOC](http://host.robots.ox.ac.uk/pascal/VOC/) - 20 ចំណាត់ថ្នាក់
* [COCO](http://cocodataset.org/#home) - វត្ថុទូទៅនៅក្នុងបរិបទ។ មាន 80 ចំណាត់ថ្នាក់ ប្រអប់ដែកដោះថ្លៃ និងម៉ាសបំបែក
![COCO](../../../../../translated_images/km/coco-examples.71bc60380fa6cceb.webp)
## គោលដៅសម្រាប់ការរកឃើញវត្ថុ
### ការបន្តិតគ្នានៃការចូលគ្នា
ពេលសម្រាប់ចាត់ថ្នាក់រូបភាព វាប្រសើរងាយស្រួលវាស់ថាតើកម្មវិធីបញ្ចប់ល្អទេ ក្រោយមកសម្រាប់ការរកឃើញវត្ថុ យើងត្រូវវាស់ទាំងត្រឹមត្រូវនៃចំណាត់ថ្នាក់ ក៏ដូចជាការច្បាស់លាស់នៃទីតាំងប្រអប់ដែកដោះថ្លៃ។ សម្រាប់ចំណុចចុងក្រោយនេះ យើងប្រើអ្វីដែលហៅថា **ការបន្តិតគ្នានៃការចូលគ្នា** (IoU), ដែលវាស់ថាតើប្រអប់ពីរឬផ្ទៃពីរប្រហែលគ្នាពីរប៉ុណ្ណា។
![IoU](../../../../../translated_images/km/iou_equation.9a4751d40fff4e11.webp)
> *រូប 2 ពី [បទបង្ហាញល្អឥតខ្ចោះលើ IoU](https://pyimagesearch.com/2016/11/07/intersection-over-union-iou-for-object-detection/)*
គំនិតគឺងាយៗ - យើងចែកផ្ទៃនៃការបន្តិតគ្នារវាងរូបរាងពីរដោយផ្ទៃនៃសមាសធាតុរបស់ពួកវា។ សម្រាប់ផ្ទៃដូចគ្នា ពិតប្រាកដថា IoU នឹងស្មើ 1 ខណៈដែលសម្រាប់ផ្ទៃមិនរំលោភគ្នា យ៉ាងស្រឡះវានឹងស្មើ 0។ គ្រាន់តែវានឹងប្រែប្រួលពី 0 ទៅ 1។ យើងធម្មតាទៅគិតលទ្ធផលតែប្រអប់ដែកដែលមាន IoU មួយលើសតម្លៃណាមួយ។
### Precision ធៀបមធ្យម
សន្មតថា យើងចង់វាស់ថាសម្គាល់បានល្អប៉ុណ្ណាដល់ចំណាត់ថ្នាក់វត្ថុមួយ $C$។ ដើម្បីវាស់វា យើងប្រើគោលដៅ **Precision ធៀបមធ្យម** ដែលគណនាដូចខាងក្រោម៖
1. គិតតួតម្លៃ Precision-Recall ដែលបង្ហាញភាពត្រឹមត្រូវដោយផ្អែកលើតម្លៃសម្ងាត់នៃការរកឃើញ (ពី 0 ទៅ 1)។
2. ភាពយោងទៅលើកម្រិតសម្ងាត់ យើងនឹងទទួលបានចំនួនវត្ថុគ្រប់គ្រាន់ ឬទាបក្នុងរូបភាព មិនដូចគ្នានៃតម្លៃ precision និង recall។
3. កោងនឹងដូចនេះ៖
<img src="https://github.com/shwars/NeuroWorkshop/raw/master/images/ObjDetectionPrecisionRecall.png"/>
> *រូបពី [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop)*
Precision ធៀបមធ្យមសម្រាប់ចំណាត់ថ្នាក់មួយ $C$ គឺជាផ្ទៃក្រោមកោងនេះ។ យ៉ាងច្បាស់លាស់, ឈានចុះមាត្រដ្ឋាន Recall ត្រូវបានចែកជាមូលដ្ឋាន 10 និង Precision ត្រូវបានគណនារួមលើចំណុចទាំងនោះ៖
$$
AP = {1\over11}\sum_{i=0}^{10}\mbox{Precision}(\mbox{Recall}={i\over10})
$$
### AP និង IoU
យើងនឹងគិតតែវត្ថុដែលបានរកឃើញ ដែល IoU មានតម្លៃលើសចំណុចណាមួយ។ ឧទាហរណ៍ នៅក្នុង PASCAL VOC dataset មានការអនុម័តថា $\mbox{IoU Threshold} = 0.5$, ខណៈនៅក្នុង COCO AP ត្រូវបានវាស់សម្រាប់តម្លៃ $\mbox{IoU Threshold}$ ប្រែប្រួល។
<img src="https://github.com/shwars/NeuroWorkshop/raw/master/images/ObjDetectionPrecisionRecallIoU.png"/>
> *រូបពី [NeuroWorkshop](http://github.com/shwars/NeuroWorkshop)*
### Precision ធៀបមធ្យមមធ្យម - mAP
គោលដៅសំខាន់សម្រាប់ការរកឃើញវត្ថុ ហៅថា **Precision ធៀបមធ្យមមធ្យម****mAP**។ វាជាតម្លៃ Precision ធៀបមធ្យម មធ្យមបង្ហាញច្រេសចេញពីចំណាត់ថ្នាក់ទាំងអស់របស់វត្ថុ ហើយពេលខ្លះផងដែរតាម $\mbox{IoU Threshold}$។ ក្នុងសេចក្ដីលម្អិត ការគណនា **mAP** ត្រូវបានពិពណ៌នានៅ
[ក្នុងបទបង្ហាញនេះ](https://medium.com/@timothycarlen/understanding-the-map-evaluation-metric-for-object-detection-a07fe6962cf3)), និង [នៅទីនេះជាមួយឧទាហរណ៍កូដ](https://gist.github.com/tarlen5/008809c3decf19313de216b9208f3734)។
## វិធីសាស្រ្តផ្សេងៗសម្រាប់ការរកឃើញវត្ថុ
មានឈ្នះទាំងពីរប្រភេទធំសំខាន់នៃវីធីសាស្រ្តរកឃើញវត្ថុ៖
* **Region Proposal Networks** (R-CNN, Fast R-CNN, Faster R-CNN)។ គំនិតសំខាន់គឺបង្កើត **តំបន់ចំណាប់អារម្មណ៍** (ROI) ហើយបើក CNN លើពួកវា ដើម្បីស្វែងរកការបញ្ចេញអតិបរមា។ វាដូចជាវិធីសាស្រ្តសាមញ្ញ បើទេថា ROI ត្រូវបានបង្កើតដោយវិធីសាស្រ្តខ្ពស់ជាង។ ខុសត្រូវធំមួយនៃវិធីសាស្រ្តដូចនេះ គឺពួកវាដំណើរការជាអាចយឺត ព្រោះយើងត្រូវការបង្ហោះ CNN ម៉ូដែលជាច្រើនលើរូបភាព។
* វិធីសាស្រ្ត **មួយដំណើរ** (YOLO, SSD, RetinaNet)។ នៅក្នុងស្ថាបត្យកម្មទាំងនេះ យើងរចនាបណ្ដាញឲ្យទាយក្លៈនិង ROI ទាំងពីរនៅក្នុងមួយដំណើរ។
### R-CNN: Region-Based CNN
[R-CNN](http://islab.ulsan.ac.kr/files/announcement/513/rcnn_pami.pdf) ប្រើ [Selective Search](http://www.huppelen.nl/publications/selectiveSearchDraft.pdf) ដើម្បីបង្កើតរចនាសម្ព័ន្ធជាស្រទាប់នៃតំបន់ ROI ដែលបន្ទាប់មកត្រូវបានបញ្ជូនតាមរយៈ CNN feature extractors និង SVM-classifiers ដើម្បីកំណត់ចំណាត់ថ្នាក់វត្ថុ ហើយក៏ប្រើការចុះបញ្ជាក់ស៊ុមខ្សែដើម្បីកំណត់ *ទ្រង់ទ្រាយប្រអប់ដែកដោះថ្លៃ* ។ [អត្ថបទផ្លូវការជាភាសាអង់គ្លេស](https://arxiv.org/pdf/1506.01497v1.pdf)
![RCNN](../../../../../translated_images/km/rcnn1.cae407020dfb1d1f.webp)
> *រូបពី van de Sande et al. ICCV11*
![RCNN-1](../../../../../translated_images/km/rcnn2.2d9530bb83516484.webp)
> *រូបភាពពី [បទបង្ហាញនេះ](https://towardsdatascience.com/r-cnn-fast-r-cnn-faster-r-cnn-yolo-object-detection-algorithms-36d53571365e)*
### F-RCNN - Fast R-CNN
វិធីសាស្រ្តនេះស្រដៀងនឹង R-CNN ប៉ុន្តែតំបន់ ត្រូវបានកំណត់ក្រោយពីស្រទាប់កំណត់បង្រួមត្រូវបានអនុវត្ត។
![FRCNN](../../../../../translated_images/km/f-rcnn.3cda6d9bb4188875.webp)
> រូបពី [អត្ថបទផ្លូវការ](https://www.cv-foundation.org/openaccess/content_iccv_2015/papers/Girshick_Fast_R-CNN_ICCV_2015_paper.pdf), [arXiv](https://arxiv.org/pdf/1504.08083.pdf), 2015
### Faster R-CNN
គំនិតសំខាន់នៃវិធីសាស្រ្តនេះ គឺប្រើបណ្តាញសរសៃប្រព័ន្ធសរសៃប្រព័ន្ធក្នុងការទាយ ROI - ហៅថា *Region Proposal Network*។ [អត្ថបទ](https://arxiv.org/pdf/1506.01497.pdf), 2016
![FasterRCNN](../../../../../translated_images/km/faster-rcnn.8d46c099b87ef30a.webp)
> រូបពី [អត្ថបទផ្លូវការ](https://arxiv.org/pdf/1506.01497.pdf)
### R-FCN: Region-Based Fully Convolutional Network
អាល់គ្រុិធីមនេះលឿនជាង Faster R-CNN ផងដែរ។ គំនិតសំខាន់មានដូចខាងក្រោម៖
1. យើងដកលក្ខណៈប្រើ ResNet-101
1. លក្ខណៈត្រូវបានកែប្រែដោយ **Position-Sensitive Score Map**។ គ្រប់វត្ថុពីចំណាត់ថ្នាក់ $C$ ត្រូវបានបែងចែកជាតំបន់ $k\times k$, ហើយយើងបណ្តុះដើម្បីទាយផ្នែកនៃវត្ថុ។
1. សម្រាប់មួយផ្នែកពីតំបន់ $k\times k$ បណ្ដាញទាំងមូលបោះឆ្នោតសម្រាប់ចំណាត់ថ្នាក់វត្ថុ ហើយចំណាត់ថ្នាក់វត្ថុដែលមានការបោះឆ្នោតអតិបរមាត្រូវបានជ្រើស។
![r-fcn image](../../../../../translated_images/km/r-fcn.13eb88158b99a3da.webp)
> រូបពី [អត្ថបទផ្លូវការ](https://arxiv.org/abs/1605.06409)
### YOLO - You Only Look Once
YOLO គឺជាអាល់គ្រុិធីមមួយដំណើរដំណើរការនៅពេលជាក់ស្តែង។ គំនិតសំខាន់បានដូចខាងក្រោម៖
* រូបភាពត្រូវបានបំបែកទៅជាតំបន់ $S\times S$
* សម្រាប់តំបន់នីមួយៗ **CNN** ទាយ $n$ វត្ថុដែលអាចមាន, *រង្វង់ប្រអប់ដែកដោះថ្លៃ* និង *ជំនឿជោះ=ប្រហែល* * IoU
![YOLO](../../../../../translated_images/km/yolo.a2648ec82ee8bb4e.webp)
> រូបពី [អត្ថបទផ្លូវការ](https://arxiv.org/abs/1506.02640)
### អាល់គ្រុិធីមផ្សេងទៀត
* RetinaNet: [អត្ថបទផ្លូវការ](https://arxiv.org/abs/1708.02002)
- [ការអនុវត្ត PyTorch នៅក្នុង Torchvision](https://pytorch.org/vision/stable/_modules/torchvision/models/detection/retinanet.html)
- [ការអនុវត្ត Keras](https://github.com/fizyr/keras-retinanet)
- [ការរកឃើញវត្ថុជាមួយ RetinaNet](https://keras.io/examples/vision/retinanet/) ក្នុងនំៀងគំរូ Keras
* SSD (Single Shot Detector): [អត្ថបទផ្លូវការ](https://arxiv.org/abs/1512.02325)
## ✍️ វិជ្ជាសកម្ម៖ ការរកឃើញវត្ថុ
បន្តការសិក្សារបស់អ្នកនៅក្នុងកំណត់ហេតុបន្ទាប់៖
[ObjectDetection.ipynb](ObjectDetection.ipynb)
## សញ្ញាប្រុងប្រយ័ត្ន
នៅក្នុងមេរៀននេះ អ្នកបានធ្វើដំណើរយ៉ាងឆាប់រហ័សលើវិធីសាស្រ្តផ្សេងៗទាំងស្រុងដែលអាចរកឃើញវត្ថុបាន!
## 🚀 챌린지
អានអត្ថបទ និងកំណត់ហេតុនេះអំពី YOLO ហើយសាកល្បងវាជាមួយខ្លួនអ្នកផ្ទាល់
* [អត្ថបទល្អ](https://www.analyticsvidhya.com/blog/2018/12/practical-guide-object-detection-yolo-framewor-python/) ពិពណ៌នាអំពី YOLO
* [គេហទំព័រផ្លូវការ](https://pjreddie.com/darknet/yolo/)
* Yolo: [អនុវត្ត Keras](https://github.com/experiencor/keras-yolo2), [កំណត់ហេតុចំណាត់ថ្នាក់ជាជំហាន](https://github.com/experiencor/basic-yolo-keras/blob/master/Yolo%20Step-by-Step.ipynb)
* Yolo v2: [អនុវត្ត Keras](https://github.com/experiencor/keras-yolo2), [កំណត់ហេតុចំណាត់ថ្នាក់ជាជំហាន](https://github.com/experiencor/keras-yolo2/blob/master/Yolo%20Step-by-Step.ipynb)
## [សំណួរផុតមុខបង្ហាត់](https://ff-quizzes.netlify.app/en/ai/quiz/22)
## សង្ខេប & សិក្សាផ្ទាល់ខ្លួន
* [ការរកឃើញវត្ថុ](https://tjmachinelearning.com/lectures/1718/obj/) ដោយ Nikhil Sardana
* [ការប្រៀបធៀបល្អនៃអាល់គ្រិទឹមរកឃើញវត្ថុ](https://lilianweng.github.io/lil-log/2018/12/27/object-detection-part-4.html)
* [ការត្រួតពិនិត្យអាល់គ្រីទឹមរៅជ្រៅសម្រាប់ការរកឃើញវត្ថុ](https://medium.com/comet-app/review-of-deep-learning-algorithms-for-object-detection-c1f3d437b852)
* [ការណែនាំជាជំហានទៅអាល់គ្រីទឹមរកឃើញវត្ថុមូលដ្ឋាន](https://www.analyticsvidhya.com/blog/2018/10/a-step-by-step-introduction-to-the-basic-object-detection-algorithms-part-1/)
* [ការអនុវត្ត Faster R-CNN ក្នុង Python សម្រាប់ការរកឃើញវត្ថុ](https://www.analyticsvidhya.com/blog/2018/11/implementation-faster-r-cnn-python-object-detection/)
## [កិច្ចការផ្ទះ៖ ការរកឃើញវត្ថុ](lab/README.md)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការបដិសេធ**៖
ឯកសារនេះបានបកប្រែដោយប្រើសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេលដែលយើងខិតខំស្វែងរកភាពត្រឹមត្រូវ សូមយល់ព្រមថាការបកប្រែអotomatically អាចមានកំហុសឬភាពមិនត្រឹមត្រូវ។ ឯកសារដើមនៅភាសាទីសាស្ត្រគួរត្រូវបានគេយកទៅជាអ្នកប្រើប្រាស់អំណាច។ សម្រាប់ព័ត៌មានសំខាន់ៗ សូមណែនាំឱ្យប្រើការបកប្រែដោយអ្នកជំនាញមនុស្ស។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកប្រែវែកញែកណាមួយដែលកើតឡើងដោយការប្រើប្រាស់ការបកប្រែនេះឡើយ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,70 @@
# ការរកមុខក្បាលដោយប្រើទិន្នន័យ Hollywood Heads Dataset
ភារកិច្ចមេរៀនពី [AI for Beginners Curriculum](https://github.com/microsoft/ai-for-beginners) ។
## ភារកិច្ច
ការរាប់ចំនួនមនុស្សនៅលើចរន្តកាមេរ៉ាសុវត្ថិភាព វីដេអូ គឺជាភារកិច្ចសំខាន់មួយ ដែលអាចអនុញ្ញាតឲ្យយើងប៉ាន់ស្មានចំនួនមាតឹកានៅក្នុងហាងម៉ូដម៉ាឌែល ម៉ោងវិស្សមកាលនៅភោជនីយដ្ឋាន និងផ្សេងៗទៀត។ ដើម្បីដោះស្រាយភារកិច្ចនេះ យើងត្រូវបានបាច់ត្រូវអាចរកមុខក្បាលមនុស្សពីទិសភាពផ្សេងៗគ្នា។ ដើម្បីបណ្តុះម៉ូដែលរកមុខតំណាងរូបវត្ថុសម្រាប់រកមុខក្បាលមនុស្ស យើងអាចប្រើ [Hollywood Heads Dataset](https://www.di.ens.fr/willow/research/headdetection/) ។
## ទិន្នន័យ
[Hollywood Heads Dataset](https://www.di.ens.fr/willow/research/headdetection/release/HollywoodHeads.zip) មានមុខក្បាលមនុស្សចំនួន 369,846 ដែលបានពិពណ៌នាឡើងក្នុង 224,740 ស៊េរីរូបភាពខ្សែភាពយន្តពីភាពយន្ត Hollywood ។ វាត្រូវបានផ្ដល់ជាការរូបបែប [https://host.robots.ox.ac.uk/pascal/VOC/](../../../../../../lessons/4-ComputerVision/11-ObjectDetection/lab/PASCAL VOC) ដែលសម្រាប់រូបភាពនីមួយៗ មានឯកសារ XML អธิบายដែលមើលទៅដូចជា៖
```xml
<annotation>
<folder>HollywoodHeads</folder>
<filename>mov_021_149390.jpeg</filename>
<source>
<database>HollywoodHeads 2015 Database</database>
<annotation>HollywoodHeads 2015</annotation>
<image>WILLOW</image>
</source>
<size>
<width>608</width>
<height>320</height>
<depth>3</depth>
</size>
<segmented>0</segmented>
<object>
<name>head</name>
<bndbox>
<xmin>201</xmin>
<ymin>1</ymin>
<xmax>480</xmax>
<ymax>263</ymax>
</bndbox>
<difficult>0</difficult>
</object>
<object>
<name>head</name>
<bndbox>
<xmin>3</xmin>
<ymin>4</ymin>
<xmax>241</xmax>
<ymax>285</ymax>
</bndbox>
<difficult>0</difficult>
</object>
</annotation>
```
ក្នុងទិន្នន័យនេះ មានតែមួយចំណាត់ថ្នាក់របស់វត្ថុគឺ `head` ហើយសម្រាប់មុខក្បាលនីមួយៗ អ្នកទទួលបានតំបន់ចំណងបណ្ដោយទំហំ (bounding box) ។ អ្នកអាចអាន XML ដោយប្រើបណ្ណាល័យ Python ឬប្រើ [បណ្ណាល័យនេះ](https://pypi.org/project/pascal-voc/) ដើម្បីដោះស្រាយទ្រង់ទ្រាយ PASCAL VOC ដោយផ្ទាល់ ។
## បណ្តុះម៉ូដែលរកមុខវត្ថុ
អ្នកអាចបណ្តុះម៉ូដែលរកមុខវត្ថុដោយប្រើមធ្យោបាយដូចខាងក្រោម៖
* ប្រើ [Azure Custom Vision](https://docs.microsoft.com/azure/cognitive-services/custom-vision-service/quickstarts/object-detection?tabs=visual-studio&WT.mc_id=academic-77998-cacaste) និង Python API របស់វា ដើម្បីបណ្តុះម៉ូដែលវិញ្ញាសានៅពពក។ Custom vision មិនអាចប្រើរូបភាពលើសរយៈរាប់រយសម្រាប់បណ្តុះម៉ូដែលទេ ដូច្នេះអ្នកប្រហែលជា​ត្រូវកំណត់ទិន្នន័យ។
* ប្រើឧទាហរណ៍ពី [មេរៀន Keras](https://keras.io/examples/vision/retinanet/) ដើម្បីបណ្តុះម៉ូដែល RetunaNet។
* ប្រើ [torchvision.models.detection.RetinaNet](https://pytorch.org/vision/stable/_modules/torchvision/models/detection/retinanet.html) ដែលបង្កើតដោយ torchvision ។
## លទ្ធផលសំខាន់
ការរកមុខវត្ថុគឺជាភារកិច្ចដែលត្រូវបានទាមទារញឹកញាប់នៅក្នុងឧស្សាហកម្ម។ ទោះបីជាមានសេវាកម្មខ្លះៗដែលអាចប្រើសម្រាប់បំពេញភារកិច្ចនេះ (ដូចជា [Azure Custom Vision](https://docs.microsoft.com/azure/cognitive-services/custom-vision-service/quickstarts/object-detection?tabs=visual-studio&WT.mc_id=academic-77998-cacaste)) ក៏ដោយ វាសំខាន់ណាស់ក្នុងការយល់ដឹងពីរបៀបដែលបច្ចេកវិទ្យារកមុខវត្ថុដំណើរការ ហើយអាចបណ្តុះម៉ូដែលរបស់អ្នកឯងបានផង។
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការបដិសេធ**៖
ឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេលដែលយើងខិតខំរកភាពត្រឹមត្រូវ សូមយល់ថាការបកប្រែដោយស្វ័យប្រវត្តិអាចមានកំហុស ឬភាពមិនถูกត្រូវ។ ឯកសារដើមក្នុងភាសាទូទៅគួរត្រូវបានចាត់ទុកជាផលិតផលផ្លូវការ។ សម្រាប់ព័ត៌មានសំខាន់ៗ ការបកប្រែដោយអ្នកជំនាញផ្នែកមនុស្សគឺត្រូវបានណែនាំ។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកប្រែខុសៗណាមួយដែលកើតឡើងពីការប្រើប្រាស់ការបកប្រែនេះទេ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,73 @@
# ការបែងចែក
យើងបានរៀនអំពី ការកំណត់វត្ថុ មុននេះ ដើម្បីអាចកំណត់ទីតាំងវត្ថុផ្សេងៗនៅក្នុងរូបភាពដោយប៉ាន់ប្រមាណប្រអប់រាក់ទំាងខ្លួនរបស់វា។ ទោះយ៉ាងណា សម្រាប់បេសកកម្មខ្លះ យើងមិនត្រឹមតែត្រូវការប្រអប់រាក់ទំនងទេ តែត្រូវការចំណុចឆ្លុះត្រង់ប្រាកដពាក់ព័ន្ធនឹងវត្ថុ។ បេសកកម្មនេះហៅថា **ការបែងចែក**
## [សំណួរពីមុនវគ្គសិក្សា](https://ff-quizzes.netlify.app/en/ai/quiz/23)
ការបែងចែកអាចមើលឃើញជាការចាត់ថ្នាក់ពិជ័យបិទ (pixel classification) ដែលសម្រាប់ **ពិជ័យបិទ** រាល់ចំណុចក្នុងរូបភាព យើងត្រូវប៉ាន់ប្រមាណចំណាត់ថ្នាក់របស់វា (ជាមួយនឹង *ផ្ទៃខាងក្រោយ* ជាកំណាត់ថ្នាក់មួយ)។ មានអាល់គោរីធម៍បែងចែកចម្បងពីរប្រភេទ៖
* **ការបែងចែកវាបញ្ញាតិ (Semantic segmentation)** ប្រាប់តែចំណាត់ថ្នាក់ពីពិជ័យបិទ ហើយមិនបំបែកចេញពីវត្ថុផ្សេងៗដែលមានចំណាត់ថ្នាក់ដូចគ្នាសោះទេ
* **ការបែងចែកអវត្តមាន (Instance segmentation)** បំបែកចំណាត់ថ្នាក់ជាច្រើនអវត្តមានផ្សេងៗ។
សម្រាប់ការបែងចែកអវត្តមាន ចិញ្ចើមទាំងនេះគឺជាវត្ថុខុសៗគ្នា ប៉ុន្តសម្រាប់ការបែងចែកវាបញ្ញាតិ ចិញ្ចើមទាំងអស់ត្រូវបានតំណាងដោយចំណាត់ថ្នាក់តែមួយ។
<img src="../../../../../translated_images/km/instance_vs_semantic.eee9812bebf8cd45.webp" width="50%">
> រូបភាពពី [វិប្បដិសារមួយនេះ](https://nirmalamurali.medium.com/image-classification-vs-semantic-segmentation-vs-instance-segmentation-625c33a08d50)
មានសំណុំរចនាសម្ព័ន្ធណឺរចម្រាស់នានាសម្រាប់ការបែងចែក ប៉ុន្តាឧបករណ៍ទាំងអស់មានរចនាសម្ព័ន្ធដូចគ្នា។ មួយវិធីវិញ វាស្រដៀងនឹង autoencoder ដែលអ្នកបានរៀនមុននេះ ប៉ុន្តែជំនួសការបំបែករូបភាពដើម គោលបំណងរបស់យើងគឺបំបែក **ម៉ាស**។ ដូច្នេះ បណ្តាញបែងចែកមានផ្នែកដូចខាងក្រោម៖
* **Encoder** យកលក្ខណៈពីរូបភាពបញ្ចូល
* **Decoder** បម្លែងលក្ខណៈនោះទៅជារੂបម៉ាស ដែលមានទំហំដូចគ្នា និងចំនួនឆានែលស្របទៅនឹងចំនួនចំណាត់ថ្នាក់
<img src="../../../../../translated_images/km/segm.92442f2cb42ff4fa.webp" width="80%">
> រូបភាពពី [ការចេញផ្សាយនេះ](https://arxiv.org/pdf/2001.05566.pdf)
យើងគួរតែល្បែងអំពីមុខងារបាត់បង់ដែលប្រើសម្រាប់ការបែងចែក។ នៅពេលប្រើ autoencoder ត្រងចាស់ មុននេះ យើងត្រូវតែមិនចាំបាច់វាយតម្លៃភាពស្រដៀងរវាងរូបភាពពីរដោយប្រើ mean square error (MSE)។ សម្រាប់ការបែងចែក រាល់ចំណុចនៅក្នុងរូបភាពម៉ាសគោលតំណាងឲ្យលេខចំណាត់ថ្នាក់ (one-hot-encoded ក្នុងទិសដៅទីបី) ដូច្នេះយើងត្រូវប្រើមុខងារបាត់បង់ដែលជាចម្បងសម្រាប់ចាត់ថ្នាក់ ជា cross-entropy loss ដែលគិតជាមធ្យមលើពិជ័យបិទទាំងអស់។ ប្រសិនបើម៉ាសជាប៊ីណារី នោះប្រើ **binary cross-entropy loss** (BCE)។
> ✅ One-hot encoding គឺជាវិធី encoding ចំណាត់ថ្នាក់ទៅជាវិកទ័រដែលមានប្រវែងស្មើនឹងចំនួនចំណាត់ថ្នាក់។ សូមមើល [អត្ថបទនេះ](https://datagy.io/sklearn-one-hot-encode/) ស្តីពីបច្ចេកទេសនេះ។
## ការបែងចែកសម្រាប់រូបភាពវេជ្ជសាស្ត្រ
ក្នុងមេរៀននេះ យើងនឹងឃើញការបែងចែកក្នុងសកម្មភាព ដោយហ្វឹកហាត់បណ្តាញក្នុងការទទួលស្គាល់ nevi មនុស្ស (ដែលហៅថា moles) នៅក្នុងរូបភាពវេជ្ជសាស្ត្រ។ យើងនឹងប្រើ <a href="https://www.fc.up.pt/addi/ph2%20database.html">PH<sup>2</sup> Database</a> សម្រាប់រូបភាព dermoscopy ។ សំណុំទិន្នន័យនេះមានរូបភាពចំនួន ២០០ រូបភាព ពីបីចំណាត់ថ្នាក់៖ nevus ទូទៅ, nevus ផ្សេងទៀងបន្តិច, និង melanoma។ រូបភាពទាំងអស់ក៏មាន **ម៉ាស** ផ្សេងសម្រាប់បង្ហាញសភាព nevi ដែរ។
> ✅ បច្ចេកវិទ្យានេះសមរម្យយ៉ាងខ្លាំងសម្រាប់ក្របខណ្ឌវេជ្ជសាស្ត្រ ប៉ុន្តអ្នកអាចគិតថានឹងមានកម្មវិធីផ្សេងទៀតអ្វីខ្លះនៅក្នុងពិភពពិត?
<img alt="navi" src="../../../../../translated_images/km/navi.2f20b727910110ea.webp"/>
> រូបភាពពី PH<sup>2</sup> Database
យើងនឹងហ្វឹកហាត់ម៉ូដែលដើម្បីបែងចែក nevi ពីផ្ទៃខាងក្រោយរបស់វា។
## ✍️ រៀនប្រាកដ៖ Semantic Segmentation
បើកកំណត់ត្រាខាងក្រោម ដើម្បីរៀនបន្ថែមអំពីរចនាសម្ព័ន្ធ semantic segmentation ផ្សេងៗ សម្លឹងលើការអនុវត្តន៍ និងមើលវាផ្ទាល់។
* [Semantic Segmentation Pytorch](SemanticSegmentationPytorch.ipynb)
* [Semantic Segmentation TensorFlow](SemanticSegmentationTF.ipynb)
## [សំណួរបន្ទាប់វគ្គសិក្សា](https://ff-quizzes.netlify.app/en/ai/quiz/24)
## សេចក្ដីសន្និដ្ឋាន
ការបែងចែកជាបច្ចេកវិទ្យាដ៏មានឥទ្ធិពលខ្លាំងសម្រាប់ចាត់ថ្នាក់រូបភាព ដំណើរការលើសពីប្រអប់រាក់ទំនងទៅកាន់ការចាត់ថ្នាក់ជាទម្រង់ចំណុចមួយៗ។ វាជាបច្ចេកវិទ្យាមួយដែលប្រើនៅក្នុងរូបភាពវេជ្ជសាស្ត្រ និងកម្មវិធីដទៃទៀត។
## 🚀 챌린지
ការបែងចែករាងកាយគឺជាបេសកកម្មទូទៅមួយសម្រាប់រូបភាពមនុស្ស។ បេសកកម្មសំខាន់ផ្សេងទៀតរួមមាន **ការរកព្រំដែនឆ្អឹង** និង **ការរកទីតាំងរូបរាង**។ សាកល្បងប្រើបណ្ណាល័យ [OpenPose](https://github.com/CMU-Perceptual-Computing-Lab/openpose) ដើម្បីមើលថាតើការរកទីតាំងរូបរាងអាចប្រើបានយ៉ាងដូចម្តេច។
## សិក្សាដោយខ្លួនឯង និងពិនិត្យវិញ
អត្ថបទ [វិគីភីឌា](https://wikipedia.org/wiki/Image_segmentation) នេះផ្ដល់ទិដ្ឋភាពទូទៅល្អអំពីកម្មវិធីផ្សេងៗនៃបច្ចេកវិទ្យានេះ។ សូមស្វែងយល់បន្ថែមដោយខ្លួនឯងអំពីផ្នែករងនៃការបែងចែកអវត្តមាន និង Panoptic segmentation ក្នុងវិស័យនេះ។
## [ភារកិច្ច](lab/README.md)
ក្នុងមន្ទីរពិសោធន៍នេះ សូមសាកល្បង **ការបែងចែករាងកាយមនុស្ស** ដោយប្រើ [Segmentation Full Body MADS Dataset](https://www.kaggle.com/datasets/tapakah68/segmentation-full-body-mads-dataset) ពី Kaggle។
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការព្រមាន**៖
ឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាកម្មបកប្រែកម្មវិធី AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ បើទោះបីយើងខិតខំប្រឹងប្រែងក្នុងការធ្វើឱ្យបានត្រឹមត្រូវក៏ដោយ សូមយល់ព្រមថាការបកប្រែដោយស្វ័យប្រវត្តិនេះអាចមានកំហុស ឬការខ្វះខាតមួយចំនួន។ ឯកសារដើមក្នុងភាសាមាតុភាសា គួរត្រូវបានរាប់បញ្ចូលជាអ្នកផ្តល់ព័ត៌មានដែលគួរជឿទុកចិត្ត។ សម្រាប់ព័ត៌មានសំខាន់ៗ ការបកប្រែមនុស្សដែលមានជំនាញគឺជាការផ្ដល់អនុសាសន៍។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកប្រែខុសប្លែកណាមួយដោយសារការប្រើប្រាស់ការបកប្រែនេះនោះទេ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,26 @@
# ការបែងចែករាងកាយមនុស្ស
កិច្ចការពិសោធន៍ពី [មូលដ្ឋានដំណើរការសម្រាប់អ្នកចាប់ផ្តើម AI](https://github.com/microsoft/ai-for-beginners)។
## ការងារ
ក្នុងការផលិត​វីដេអូ ឧទាហរណ៍ នៅក្នុងការទស្សនាការព្យាករណ៍អាកាសធាតុ យើងភាគច្រើនត្រូវការកាត់រូបភាពមនុស្សពីកាមេរ៉ា និងដាក់វាលើវីដេអូផ្សេងទៀត។ វាត្រូវបានធ្វើជាធម្មតាដោយប្រើបច្ចេកទេស **chroma key** ដែលមនុស្សត្រូវបានថតនៅចំពោះមុខផ្ទៃខាងក្រោយពណ៌ស្មើគ្នា ហើយផ្ទៃខាងក្រោយនោះត្រូវបានយកចេញ។ នៅក្នុងកិច្ចការពិសោធន៍នេះ យើងនឹងបណ្តុះបណ្តាលម៉ូដែលបណ្ដាញគ្រចះដើម្បីកាត់រូបរាងម៉ូដែលមនុស្ស។
## ឌាទាសែត
យើងនឹងប្រើ [Segmentation Full Body MADS Dataset](https://www.kaggle.com/datasets/tapakah68/segmentation-full-body-mads-dataset) ពី Kaggle។ ទាញយកឌាតាសែតដោយដៃពី Kaggle។
## សៀវភៅកំណត់ត្រាដើម
ចាប់ផ្តើមកិច្ចការពិសោធន៍ដោយបើក [BodySegmentation.ipynb](BodySegmentation.ipynb)
## អ្វីដែលទទួលបាន
ការបែងចែករាងកាយគឺជាការងារដែលទូទៅមួយ ដែលយើងអាចធ្វើបានជាមួយរូបភាពមនុស្ស។ ការងារសំខាន់ផ្សេងទៀតរួមមាន **ការបង្កើតខ្នងកាយ** និង **ការតាមដានបែបបទ**។ សូមសង្កេតទៅក្នុងបណ្ណាល័យ [OpenPose](https://github.com/CMU-Perceptual-Computing-Lab/openpose) ដើម្បីមើលថាតើការងារទាំងអស់នេះអាចអនុវត្តបានយ៉ាងដូចម្តេច។
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការបដិសេធ**៖
ឯកសារនេះបានបកប្រែជាភាសាខ្មែរ ដោយប្រើសេវាបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេលយើងខិតខំផ្តល់ការបកប្រែបានត្រឹមត្រូវ សូមយល់ដឹងថាការបកប្រែដោយស្វ័យប្រវត្តិអាចមានកំហុស ឬភាពមិនត្រឹមត្រូវ។ ឯកសារដើមក្នុងភាសាមូលដ្ឋាន គួរត្រូវបានគិតថាជាមូលដ្ឋានត្រឹមត្រូវជាផ្លូវការ។ សម្រាប់ព័ត៌មានចាំបាច់ គណៈករណីបកប្រែដោយអ្នកជំនាញមនុស្សគឺត្រូវបានផ្តល់អាទិភាព។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបម្លែងតម្លៃខុសណាមួយដែលកើតឡើងពីការប្រើប្រាស់ការបកប្រែនេះឡើយ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,20 @@
# ការមើលឃើញរបស់កុំព្យូទ័រ
![សង្ខេបមាតិកាការមើលឃើញរបស់កុំព្យូទ័រ ក្នុងរូបគំនូរ](../../../../translated_images/km/ai-computervision.6506ebebac3fbf76.webp)
នៅក្នុងផ្នែកនេះយើងនឹងរៀនអំពី៖
* [ការណែនាំអំពីការមើលឃើញរបស់កុំព្យូទ័រ និង OpenCV](06-IntroCV/README.md)
* [បណ្តាញប្រសាទបង្រួម](07-ConvNets/README.md)
* [បណ្តាញដែលបានបណ្តុះបណ្តាលមុន និងការសិក្សាបម្រុងចុះ](08-TransferLearning/README.md)
* [Autoencoders](09-Autoencoders/README.md)
* [បណ្តាញប្រកួតប្រែងបង្កើត](10-GANs/README.md)
* [ការស្គាល់វត្ថុ](11-ObjectDetection/README.md)
* [ការបែងចែកមានអត្ថន័យ](12-Segmentation/README.md)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការបដិសេធ**៖
ឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈ​ពេល​យើងខិតខំ​សម្រាប់ភាពត្រឹមត្រូវ សូមចាប់អារម្មណ៍ថាការបកប្រែ​ដោយស្វ័យ​ប្រវត្តិ​អាចមានកំហុស ឬ ភាពមិនត្រឹមត្រូវ។ ឯកសារដើម​នៅក្នុងភាសាទៅតាមដើមគួរត្រូវបានចាត់ទុកជាអ្នកផ្តល់ព័ត៌មានសំខាន់ជាចម្បង។ សម្រាប់ព័ត៌មានសំខាន់ខ្លាំងៗ ការបកប្រែពីមនុស្សអ្នកជំនាញត្រូវបានផ្ដល់អនុសាសន៍។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកប្រែខុសប្រសិនបើបានបន្ទាប់ពីការប្រើប្រាស់ការបកប្រែនេះឡើយ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,80 @@
# បង្ហាញអត្ថបទជាទង់ស័រ
## [ប្រឡងមុនម៉ោងសិក្សា](https://ff-quizzes.netlify.app/en/ai/quiz/25)
## ការបែងចែកប្រភេទអត្ថបទ
នៅ Throughout ផ្នែកដំបូងនៃផ្នែកនេះ យើងនឹងផ្តោតលើភារកិច្ច **ការបែងចែកប្រភេទអត្ថបទ**។ យើងនឹងប្រើប្រភេទទិន្នន័យ [AG News](https://www.kaggle.com/amananandrai/ag-news-classification-dataset) ដែលមានអត្ថបទពហុមេរៀនដូចតទៅ៖
* ប្រភេទ៖ Sci/Tech
* ចំណងជើង៖ ក្រុមហ៊ុននៅរដ្ឋ Ky. ឈ្នះជំនួយសិក្សាអំពី Peptides (AP)
* រូបមន្ត៖ AP - ក្រុមហ៊ុនមួយដែលបានបង្កើតឡើងដោយអ្នកស្រាវជ្រាវគីមីនៅសាកលវិទ្យាល័យ Louisville ឈ្នះជំនួយដើម្បីអភិវឌ្ឍ...
គោលដៅរបស់យើងគឺបែងចែកអត្ថបទនោះទៅក្នុងប្រភេទមួយដែលផ្អែកលើអត្ថបទ។
## ការបង្ហាញអត្ថបទ
បើយើងចង់ដោះស្រាយភារកិច្ចក្នុងវិស័យក្រុមហ៊ុនមនុស្ស (NLP) ជាមួយបណ្តាញប្រសាទ យើងត្រូវការពិធីមួយសម្រាប់បង្ហាញអត្ថបទជាទង់ស័រ។ កុំព្យូទ័របានតំណាងឲ្យតួអក្សរឬតួអក្សរជាលេខដែលតំណាងឲ្យពុម្ពអក្សរនៅលើអេក្រង់របស់អ្នកដោយប្រើកូដដូចជា ASCII ឬ UTF-8។
<img alt="រូបភាពបង្ហាញឌីយ៉ាងផ្ទួនតួអក្សរទៅជាកំណត់ត្រា ASCII និងប៊ីណារី" src="../../../../../translated_images/km/ascii-character-map.18ed6aa7f3b0a7ff.webp" width="50%"/>
> [ប្រភពរូបភាព](https://www.seobility.net/en/wiki/ASCII)
ជាមនុស្ស យើងយល់ពីអ្វីដែលអក្សរនីមួយៗ **តំណាងឱ្យ** ហើយថាតើតួអក្សរទាំងអស់រួមគ្នាដើម្បីបង្កើតពាក្យមួយក្នុងប្រយោគ។ ទោះជាយ៉ាងណា កុំព្យូទ័រមិនមានការយល់ដឹងដូចនេះទេ ហើយបណ្តាញប្រសាទត្រូវរៀនអត្ថន័យក្នុងអំឡុងការបណ្តុះបណ្តាល។
ហេតុនេះ យើងអាចប្រើវិធីផ្សេងៗនៅពេលបង្ហាញអត្ថបទ៖
* **ការបង្ហាញនៅលើកម្រិតតួអក្សរ**, នៅពេលយើងបង្ហាញអត្ថបទដោយការព្យាបាលឲ្យតួអក្សរនីមួយៗជាលេខ។ ដោយយោងថាយើងមានតួអក្សរផ្សេងគ្នា *C* ក្នុងឯកសារអត្ថបទរបស់យើង ពាក្យ *Hello* នឹងត្រូវបានបង្ហាញជាទង់ស័រដូចជា 5x*C*។ តួអក្សរនីមួយៗនឹងតំណាងឲ្យជួរឈរទង់ស័រមួយក្នុងការវាយលេខមួយនៅលើបណ្ដាញ។
* **ការបង្ហាញនៅលើកម្រិតពាក្យ**, ដែលនៅទីនេះយើងបង្កើត **វចនានុក្រម** របស់ពាក្យទាំងអស់ក្នុងអត្ថបទរបស់យើង ហើយបន្ទាប់មកបង្ហាញពាក្យដោយការវាយលេខមួយនៅលើបណ្ដាញ។ វិធីនេះល្អជាងការល្វែងមើល ពីព្រោះតួអក្សរតែមួយមិនមានអត្ថន័យច្រើនពីរៀងឡើយ ហើយដោយប្រើមាតិកាអត្ថន័យកម្រិតខ្ពស់ - ពាក្យ - យើងពង្រីកភារកិច្ចសម្រាប់បណ្តាញប្រសាទ។ ទោះជាយ៉ាងណា ដោយសារទំហំវចនានុក្រមធំ យើងត្រូវគ្រប់គ្រងទង់ស័រសំរួលមួយមានវាយតម្លៃខ្ពស់។
ដោយមិនព្រមានអំពីការបង្ហាញណាមួយ យើងត្រូវបំលែងអត្ថបទជាជួរនៃ **តូខែន** មួយ ដោយតូខែនមួយអាចជា តួអក្សរ ពាក្យ ឬក៏វាគ្រប់គ្រាន់ជាការផ្នែកនៃពាក្យមួយ។ បន្ទាប់មក យើងបំលែងតូខែនជាលេខ ដែលនៅជាប់អ្នកប្រើ **វចនានុក្រម** ហើយលេខនេះអាចចូលទៅក្នុងបណ្តាញប្រសាទដោយការវាយលេខមួយនៅលើបណ្ដាញ។
## N-Grams
ក្នុងភាសារធម្មជាតិ អត្ថន័យត្រឹមត្រូវនៃពាក្យអាចកំណត់បានតែតាមបរិបទប៉ុណ្ណោះ។ ឧទាហរណ៍ អត្ថន័យនៃ *neural network* និង *fishing network* ផ្ទុយគ្នាយ៉ាងសំខាន់។ មួយក្នុងវិធីធ្វើឲ្យមានការយកចិត្តទុកដាក់ទៅនឹងនេះគឺការបង្កើតគំរូលើចំឡែកពាក្យពីរដោយពិចារណាពាក្យពីរក្នុងសញ្ញាប័ត្រ។ ដូច្នេះ ប្រយោគ *I like to go fishing* នឹងត្រូវបានបង្ហាញជាសំណុំតូខែន៖ *I like*, *like to*, *to go*, *go fishing*។ បញ្ហាជាមួយវិធីនេះគឺទំហំនៃវចនានុក្រមកើនឡើងយ៉ាងមានន័យ ហើយការចងក្រងដូចជា *go fishing* និង *go shopping* ត្រូវបានបង្ហាញជាតូខែនខុសៗគ្នាដែលមិនមានសំណាក់ចំនួនសប្រាថ្នាទេទោះបីជាកិរិយាស័ព្ទដូចគ្នាក៏ដោយ។
ក្នុងករណីខ្លះ យើងអាចពិចារណាការប្រើ tri-grams គឺការចងក្រងពាក្យបីផងដែរ។ វិធីនេះហៅថា **n-grams**។ អញ្ចឹងហើយ វាធ្វើអោយមានអត្ថន័យក្នុងការប្រើ n-grams ជាមួយការបង្ហាញកម្រិតតួអក្សរ ដែលនៅនោះn-grams នឹងស្រដៀងទៅកាន់សម្លេងផ្សេងៗ។
## Bag-of-Words និង TF/IDF
នៅពេលដោះស្រាយភារកិច្ចដូចជាការបែងចែកអត្ថបទ យើងត្រូវបាននឹងត្រូវមានវិធីបង្ហាញអត្ថបទជាវ៉ិចទ័រដែលមានទំហំនិរន្តរមួយ ដែលយើងនឹងប្រើជាចូលឯកសារសម្រាប់ម៉ាស៊ីនចម្រោះចុងក្រោយ។ មួយក្នុងវិធីសាមញ្ញបំផុត ធ្វើបានយ៉ាងនេះគឺការរួមបញ្ចូលពាក្យនីមួយៗ ឧទាហរណ៍ដោយបូកនោះ។ បើយើងបញ្ចូលការវាយលេខមួយនៅលើបណ្ដាញនៃពាក្យនីមួយៗ យើងនឹងទទួលបានវ៉ិចទ័រដែលបង្ហាញពីមាឌដងដែលពាក្យនីមួយៗមានក្នុងអត្ថបទ។ ការបង្ហាញអត្ថបទបែបនេះហៅថា **bag of words** (BoW)។
<img src="../../../../../translated_images/km/bow.3811869cff59368d.webp" width="90%"/>
> រូបភាពដោយអ្នកនិពន្ធ
BoW ច្បាស់ជាតំណាងថាពាក្យណាបង្ហាញនៅក្នុងអត្ថបទ និងបរិមាណណាដែលវាបង្ហាញ ដែលពិតជាអាចជាសញ្ញាល្អមួយនៃអ្វីដែលអត្ថបទនោះជាអំពី។ ឧទាហរណ៍ អត្ថបទព្រឹត្តិការណ៍ស្ថានការណ៍នយោបាយត្រូវមានពាក្យដូចជា *president* និង *country* ខណ:ការចេញផ្សាយវិទ្យាសាស្រ្តអាចមានពាក្យដូចជា *collider*, *discovered* ល។ ដូច្នេះ មាឌពាក្យអាចជាសញ្ញាល្អសម្រាប់មាតិកាអត្ថបទ។
បញ្ហានៃ BoW គឺពាក្យទូទៅមួយចំនួន ដូចជា *and*, *is* បង្ហាញក្នុងភាគច្រើននៃអត្ថបទ ហើយពួកវាមានមាឌខ្ពស់បំផុត ហើយបិទបាំងពាក្យដែលសំខាន់ពិតប្រាកដ។ យើងអាចបន្ថយសារៈសំខាន់របស់ពាក្យទាំងនេះដោយគិតពីមាឌដែលពាក្យមានក្នុងកម្រិតឯកសារជារួម។ នេះជាគំនិតសំខាន់នៅពីក្រោយវិធី TF/IDF ដែលបានរៀនបន្ថែមក្នុងសៀវភៅសំរាប់មេរៀននេះ។
យ៉ាងណាមិញ គ្មានវិធីណាមួយក្នុងនោះអាចយក **អត្ថន័យ** នៃអត្ថបទបានពេញលេញ។ យើងត្រូវម៉ូឌែលបណ្តាញប្រសាទកាន់តែមានសមត្ថភាពខ្ពស់ក្នុងការធ្វើបែបនេះ ដែលយើងនឹងពិភាក្សាពេលក្រោយក្នុងផ្នែកនេះ។
## ✍️ លំហែង៖ ការបង្ហាញអត្ថបទ
បន្តសិក្សារបស់អ្នកនៅក្នុងសៀវភៅខាងក្រោម៖
* [ការបង្ហាញអត្ថបទជាមួយ PyTorch](TextRepresentationPyTorch.ipynb)
* [ការបង្ហាញអត្ថបទជាមួយ TensorFlow](TextRepresentationTF.ipynb)
## 결론
ដល់បច្ចុប្បន្ន យើងបានសិក្សាបច្ចេកទេសដែលអាចបន្ថែមទំងន់មាឌកំណត់ទៅលើពាក្យផ្សេងៗ។ ទោះជាយ៉ាងណា វាមិនអាចបង្ហាញអត្ថន័យ ឬលំដាប់បានទេ។ ដូចជាអ្នកភាសាសិក្សាឈ្មោះ J. R. Firth បាននិយាយនៅឆ្នាំ 1935 ថា "អត្ថន័យពេញលេញនៃពាក្យមួយគឺតែងតែមានបរិបទ ហើយមិនមានការសិក្សាអត្ថន័យក្រៅបរិបទដែលអាចទទួលបានយ៉ាងមែនទេ។" យើងនឹងរៀនក្រោយក្នុងវគ្គនេះពីរបៀបទាក់ទាញព័ត៌មានបរិបទពីអត្ថបទដោយប្រើម៉ូឌែលភាសា។
## 🚀 បញ្ហាប្រឈម
សូមសាកល្បងលំហែផ្សេងទៀតដោយប្រើ bag-of-words និងម៉ូឌែលទិន្នន័យផ្សេងៗ។ អ្នកអាចទទួលបានបំណងប្លែកពីការប្រកួតនេះនៅលើ [Kaggle](https://www.kaggle.com/competitions/word2vec-nlp-tutorial/overview/part-1-for-beginners-bag-of-words)
## [ប្រឡងបន្ទាប់ម៉ោងសិក្សា](https://ff-quizzes.netlify.app/en/ai/quiz/26)
## ពិនិត្យឡើងវិញ & សិក្សាឯករាជ្យ
ហាត់ជំនាញរបស់អ្នកជាមួយនឹងការបញ្ចូលអត្ថបទនិងបច្ចេកទេស bag-of-words នៅលើ [Microsoft Learn](https://docs.microsoft.com/learn/modules/intro-natural-language-processing-pytorch/?WT.mc_id=academic-77998-cacaste)
## [កិច្ចការតាមសៀវភៅ](assignment.md)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការបដិសេធ** ៖
ឯកសារនេះត្រូវបានបកប្រែក្នុងការប្រើប្រាស់សេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេលដែលយើងខិតខំសំដែងភាពច្បាស់លាស់ សូមយល់ថាការបកប្រែអូតូម៉ាតិកអាចមានកំហុស ឬអត្រានៃកំហុស។ ឯកសារដើមក្នុងភាសាមូលដ្ឋានត្រូវបានគេយកជាយោងហើយជាថ្នាក់ដើម។ សម្រាប់ព័ត៌មានសំខាន់ៗ និយាយបកប្រែដោយមនុស្សជំនាញត្រូវបានណែនាំ។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកប្រែខុសណាមួយដែលកើតមានពីការប្រើប្រាស់ការបកប្រែនេះទេ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,571 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# មុខងារបែងចែកអត្ថបទ\n",
"\n",
"ដូចដែលយើងបានរំលឹក អេភាសីយើងនឹងផ្តោតលើមុខងារបែងចែកអត្ថបទសាមញ្ញមួយ dựa trên **AG_NEWS** ភាពទិន្នន័យ ដែលជា​ការបែងចែកសេចក្តីដំបូន្មានព័ត៌មានទៅក្នុងមួយចំណាត់ថ្នាក់ពីរាបបួន៖ ពិភពលោក កីឡា ពាណិជ្ជកម្ម និង វិទ្យាសាស្រ្ត/បច្ចេកវិទ្យា។\n",
"\n",
"## ព្រំប្រៃទិន្នន័យ\n",
"\n",
"ព្រំប្រៃទិន្នន័យនេះត្រូវបានសាងសង់គ្នាចូលក្នុងម៉ូឌុល [`torchtext`](https://github.com/pytorch/text) ដូច្នេះ យើងអាចចូលដំណើរការយ៉ាងងាយស្រួល។\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import torch\n",
"import torchtext\n",
"import os\n",
"import collections\n",
"os.makedirs('./data',exist_ok=True)\n",
"train_dataset, test_dataset = torchtext.datasets.AG_NEWS(root='./data')\n",
"classes = ['World', 'Sports', 'Business', 'Sci/Tech']"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"នៅទីនេះ `train_dataset` និង `test_dataset` មានប្រមាញ់ដែលត្រឡប់វ៉ាល្យូមនៃស្លាក (ចំនួនថ្នាក់) និងអត្ថបទដោយលំដាប់ ជាឧទាហរណ៍ៈ\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(3,\n",
" \"Wall St. Bears Claw Back Into the Black (Reuters) Reuters - Short-sellers, Wall Street's dwindling\\\\band of ultra-cynics, are seeing green again.\")"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"list(train_dataset)[0]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ដូច្នេះ យើងចេញសារព័ត៌មានថ្មី ១០ ចំណងជើងដំបូងពីឃ្លាំងទិន្នន័យរបស់យើង៖\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"**Sci/Tech** -> Wall St. Bears Claw Back Into the Black (Reuters) Reuters - Short-sellers, Wall Street's dwindling\\band of ultra-cynics, are seeing green again.\n",
"**Sci/Tech** -> Carlyle Looks Toward Commercial Aerospace (Reuters) Reuters - Private investment firm Carlyle Group,\\which has a reputation for making well-timed and occasionally\\controversial plays in the defense industry, has quietly placed\\its bets on another part of the market.\n",
"**Sci/Tech** -> Oil and Economy Cloud Stocks' Outlook (Reuters) Reuters - Soaring crude prices plus worries\\about the economy and the outlook for earnings are expected to\\hang over the stock market next week during the depth of the\\summer doldrums.\n",
"**Sci/Tech** -> Iraq Halts Oil Exports from Main Southern Pipeline (Reuters) Reuters - Authorities have halted oil export\\flows from the main pipeline in southern Iraq after\\intelligence showed a rebel militia could strike\\infrastructure, an oil official said on Saturday.\n",
"**Sci/Tech** -> Oil prices soar to all-time record, posing new menace to US economy (AFP) AFP - Tearaway world oil prices, toppling records and straining wallets, present a new economic menace barely three months before the US presidential elections.\n"
]
}
],
"source": [
"for i,x in zip(range(5),train_dataset):\n",
" print(f\"**{classes[x[0]]}** -> {x[1]}\")\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ដោយសារតែទិន្នន័យជា iterator បើយើងចង់ប្រើទិន្នន័យជាច្រើនដងយើងត្រូវបម្លែងវាទៅជាបរមាណៈ list:\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"train_dataset, test_dataset = torchtext.datasets.AG_NEWS(root='./data')\n",
"train_dataset = list(train_dataset)\n",
"test_dataset = list(test_dataset)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ការបំបែកពាក្យ\n",
"\n",
"ឥឡូវនេះយើងត្រូវបំលែងអត្ថបទទៅជាខ្ទង់ **លេខ** ដែលអាចត្រូវបានតំណាងជាទិន្ស័រ។ ប្រសិនបើយើងចង់តំណាងជារាយនាមអក្សរពាក្យ ត្រូវធ្វើពីរជំហាន៖\n",
"* ប្រើ **tokenizer** ដើម្បីបំបែកអត្ថបទទៅជាប្រភេទពាក្យ **tokens**\n",
"* បង្កើត **vocabulary** សម្រាប់ពាក្យទាំងនោះ។\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"['he', 'said', 'hello']"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tokenizer = torchtext.data.utils.get_tokenizer('basic_english')\n",
"tokenizer('He said: hello')"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"counter = collections.Counter()\n",
"for (label, line) in train_dataset:\n",
" counter.update(tokenizer(line))\n",
"vocab = torchtext.vocab.vocab(counter, min_freq=1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ប្រើវាក្យសព្ទ យើងអាចបំលែងខ្សែអក្សរដែលបានបំបែករបស់យើងទៅជាសំណុំលេខបានយ៉ាងងាយស្រួលៈ\n"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Vocab size if 95810\n"
]
},
{
"data": {
"text/plain": [
"[599, 3279, 97, 1220, 329, 225, 7368]"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"vocab_size = len(vocab)\n",
"print(f\"Vocab size if {vocab_size}\")\n",
"\n",
"stoi = vocab.get_stoi() # dict to convert tokens to indices\n",
"\n",
"def encode(x):\n",
" return [stoi[s] for s in tokenizer(x)]\n",
"\n",
"encode('I love to play with my words')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ការបង្ហាញអត្ថបទជាថង់ពាក្យ\n",
"\n",
"ដោយសារពាក្យសម្គាល់អត្ថន័យ ម្តងម្កាលយើងអាចរកឃើញអត្ថន័យនៃអត្ថបទតាមរយៈការមើលតែពាក្យនីមួយៗ ដោយមិនគិតពីលំដាប់របស់ពួកវានៅក្នុងប្រយោគ។ ឧទាហរណ៍ សម្រាប់ការតែងចំណាត់ថ្នាក់ព័ត៌មាន ពាក្យដូចជា *អាកាសធាតុ*, *ហេីយគ្រាប់ទឹកកក* មានសក្តានុពលបង្ហាញពី *ការព្យាករណ៍អាកាសធាតុ* ខណៈពាក្យដូចជា *ភាគហ៊ុន*, *ដុល្លារ* នឹងចាត់ទុកថាជា *ព័ត៌មានហិរញ្ញវត្ថុ*។\n",
"\n",
"**ថង់ពាក្យ** (BoW) គឺជាការបង្ហាញវ៉ិចទ័រដែលប្រើប្រាស់ធម្មតាពិសេសច្រើនបំផុត។ ពាក្យនីមួយៗ ត្រូវបានភ្ជាប់ទៅនឹងឧSobatាយវ៉ិចទ័រ ដោយធាតុវ៉ិចទ័រមានចំនួនករណីកើតឡើងនៃពាក្យនៅក្នុងឯកសារដែលបានផ្ដល់។\n",
"\n",
"![រូបភាពបង្ហាញពីរបៀបដែលការបង្ហាញវ៉ិចទ័រថង់ពាក្យត្រូវបានផ្ទុកនៅក្នុងអង្គចងចាំ។](../../../../../translated_images/km/bag-of-words-example.606fc1738f1d7ba9.webp) \n",
"\n",
"> **សំគាល់**: អ្នកគួរតែគិតថា BoW ជា៉ការសរុបវ៉ិចទ័រ one-hot-encoded សម្រាប់ពាក្យនីមួយៗនៅក្នុងអត្ថបទ។\n",
"\n",
"​ខាង​ក្រោម​ជា​ឧទាហរណ៍​នៃ​របៀប​បង្កើត​ការ​បង្ហាញ​ថង់ពាក្យ​ប្រើ​ប្រាស់​បណ្ណាល័យ Scikit Learn ក្នុងភាសា python ៖\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1, 1, 0, 2, 0, 0, 0, 0, 0]], dtype=int64)"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from sklearn.feature_extraction.text import CountVectorizer\n",
"vectorizer = CountVectorizer()\n",
"corpus = [\n",
" 'I like hot dogs.',\n",
" 'The dog ran fast.',\n",
" 'Its hot outside.',\n",
" ]\n",
"vectorizer.fit_transform(corpus)\n",
"vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ដើម្បីគណនាពុម្ពទំនុកចិត្ត bag-of-words ពីតំណាងវ៉ិកទ័រនៃឃ្លាសន្និដ្ឋាន AG_NEWS របស់យើង យើងអាចប្រើមុខងារដូចខាងក្រោម៖\n"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"tensor([2., 1., 2., ..., 0., 0., 0.])\n"
]
}
],
"source": [
"vocab_size = len(vocab)\n",
"\n",
"def to_bow(text,bow_vocab_size=vocab_size):\n",
" res = torch.zeros(bow_vocab_size,dtype=torch.float32)\n",
" for i in encode(text):\n",
" if i<bow_vocab_size:\n",
" res[i] += 1\n",
" return res\n",
"\n",
"print(to_bow(train_dataset[0][1]))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **កំណត់សម្គាល់:** នៅទីនេះយើងកំពុងប្រើអថេរ `vocab_size` កម្រិតសកល ដើម្បីបញ្ជាក់ទំហំលំនាំដើមនៃវាក្យសព្ទ។ ពីព្រោះទំហំពាក្យសព្ទជាញែកខ្លាំងជារឿយៗ យើងអាចកំណត់ទំហំវាក្យសព្ទទៅតែពាក្យដែលមានភាពញឹកញាប់ខ្ពស់បំផុត។ សូមព្យាយាមកាត់បន្ថយតម្លៃ `vocab_size` ហើយរត់កូដខាងក្រោម ហើយមើលថាវាមានឥទ្ធិពលយ៉ាងណាលើភាពត្រឹមត្រូវ។ អ្នកគួរត្រូវរំពឹងថា ភាពត្រឹមត្រូវនឹងធ្លាក់ចុះបន្តិច ប៉ុន្តែមិនខ្លាំងទេ ដើម្បីសំរាប់ការសមត្ថភាពខ្ពស់ជាងមុន។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ការបណ្តុះបណ្តាលអ្នកចាត់ថ្នាក់ BoW\n",
"\n",
"ឥឡូវនេះដែលយើងបានរៀនថាតើធ្វើដូចម្តេចដើម្បីបង្កើតតំណាងបង្គោលពាក្យ Bag-of-Words នៃអត្ថបទរបស់យើងហើយ យើងចង់បណ្តុះបណ្តាលអ្នកចាត់ថ្នាក់សម្រាប់វា។ ជាមួយនេះ ដំបូង យើងត្រូវបម្លែងទិន្នន័យសម្រាប់ការបណ្តុះបណ្តាលដោយរបៀបគឺ ដំណាក់កាលតំណាងពាក្យតាមទីតាំងទាំងអស់ត្រូវបានបម្លែងទៅជាតំណាង Bag-of-Words។ នេះអាចសម្រេចបានដោយផ្ទេរអនុគមន៍ `bowify` ជាព៉ារ៉ាម៉ែត្រ `collate_fn` ទៅឲ្យ `DataLoader` នៃ torch ដែលមានស្តង់ដារ៖\n"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [],
"source": [
"from torch.utils.data import DataLoader\n",
"import numpy as np \n",
"\n",
"# this collate function gets list of batch_size tuples, and needs to \n",
"# return a pair of label-feature tensors for the whole minibatch\n",
"def bowify(b):\n",
" return (\n",
" torch.LongTensor([t[0]-1 for t in b]),\n",
" torch.stack([to_bow(t[1]) for t in b])\n",
" )\n",
"\n",
"train_loader = DataLoader(train_dataset, batch_size=16, collate_fn=bowify, shuffle=True)\n",
"test_loader = DataLoader(test_dataset, batch_size=16, collate_fn=bowify, shuffle=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ឥឡូវនេះចូរអនុស្សាណារៀបចំបណ្តាញសរសេរមួយសម្រាប់ចំណាត់ថ្នាក់សាមញ្ញ ដែលមានស្រទាប់ខាងស្រទាប់តែមួយ។ ទំហំវ៉ិចទ័រចូលមានទំហំស្មើនឹង `vocab_size` ហើយទំហំចេញឆបគ្នានឹងចំនួនថ្នាក់ (4)។ ពីព្រោះយើងកំពុងដោះស្រាយបញ្ហាចំណាត់ថ្នាក់ ការជំរុញចុងក្រោយគឺជា `LogSoftmax()`។\n"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [],
"source": [
"net = torch.nn.Sequential(torch.nn.Linear(vocab_size,4),torch.nn.LogSoftmax(dim=1))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ឥឡូវនេះយើងនឹងកំណត់រង្វិលបណ្តុះបណ្តាល PyTorch ស្តង់ដារ។ ព្រោះតែកំណត់ទិន្នន័យរបស់យើងមានទំហំធំជាងមធ្យម សម្រាប់គោលបំណងបង្រៀនយើងនឹងបណ្តុះបណ្តាលគ្រាន់តែកំណត់មួយទេ ហើយខ្លះពេលម្យ៉ាងទៀតក៏អាចបណ្តុះបណ្តាលតិចជាងមួយកំណត់ផង (ការ​បញ្ជាក់​ពាក្យបញ្ជា `epoch_size` អនុញ្ញាតឲ្យយើងកំណត់ដែនកំណត់ការបណ្តុះបណ្តាល)។ យើងក៏នឹងរាយការណ៍ភាពត្រឹមត្រូវបណ្តុះបណ្តាលដែលបានសង្ស័យក្នុងអំឡុងពេលបណ្តុះបណ្តាលផងដែរ; ភាគរយនៃការរាយការណ៍ត្រូវបានកំណត់ដោយការបញ្ជាក់ពាក្យបញ្ជា `report_freq`។\n"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [],
"source": [
"def train_epoch(net,dataloader,lr=0.01,optimizer=None,loss_fn = torch.nn.NLLLoss(),epoch_size=None, report_freq=200):\n",
" optimizer = optimizer or torch.optim.Adam(net.parameters(),lr=lr)\n",
" net.train()\n",
" total_loss,acc,count,i = 0,0,0,0\n",
" for labels,features in dataloader:\n",
" optimizer.zero_grad()\n",
" out = net(features)\n",
" loss = loss_fn(out,labels) #cross_entropy(out,labels)\n",
" loss.backward()\n",
" optimizer.step()\n",
" total_loss+=loss\n",
" _,predicted = torch.max(out,1)\n",
" acc+=(predicted==labels).sum()\n",
" count+=len(labels)\n",
" i+=1\n",
" if i%report_freq==0:\n",
" print(f\"{count}: acc={acc.item()/count}\")\n",
" if epoch_size and count>epoch_size:\n",
" break\n",
" return total_loss.item()/count, acc.item()/count"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3200: acc=0.8028125\n",
"6400: acc=0.8371875\n",
"9600: acc=0.8534375\n",
"12800: acc=0.85765625\n"
]
},
{
"data": {
"text/plain": [
"(0.026090790722161722, 0.8620069296375267)"
]
},
"execution_count": 25,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"train_epoch(net,train_loader,epoch_size=15000)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## BiGrams, TriGrams និង N-Grams\n",
"\n",
"ការកំណត់មួយនៃវិធីសាស្រ្តថតពាក្យ (bag of words) គឺពាក្យខ្លះជាផ្នែកមួយនៃការបង្កើតអត្ថាធិប្បាយពាក្យច្រើនពាក្យ ដូចជាឧទាហរណ៍ ពាក្យ 'hot dog' មានន័យខុសពីពាក្យ 'hot' និង 'dog' ក្នុងបរិបទផ្សេងៗ។ ប្រសិនបើយើងបង្ហាញពាក្យ 'hot' និង 'dog' ជានិរន្តរភាពដោយវ៉ិចទ័រដូចគ្នា វាអាចបង្កការជ្រុះច្រឡំចំពោះម៉ូដែលរបស់យើង។\n",
"\n",
"ដើម្បីដោះស្រាយបញ្ហានេះ, **ការតំណាង N-gram** ត្រូវបានប្រើជាញឹកញាប់ក្នុងវិធីសាស្រ្តចាត់ថ្នាក់ឯកសារ, ដែលប្រេកង់នៃពាក្យរាល់ខ្ទង់ពាក្យពីរឬបីពាក្យគឺជាលក្ខណៈសំខាន់សំរាប់ការបណ្តុះបណ្តាលម៉ាស៊ីនចាត់ថ្នាក់។ ក្នុងការតំណាង bigram, ឧទាហរណ៍យើងនឹងបន្ថែមដំណាក់កាលពាក្យទាំងអស់ទៅក្នុងវ៉ុកាប្យូលារី ខៀវបន្ថែមពីពាក្យដើម។\n",
"\n",
"ខាងក្រោមជាឧទាហរណ៍ពីរបៀបបង្កើតការតំណាង bigram bag of word ដោយប្រើ Scikit Learn៖\n"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Vocabulary:\n",
" {'i': 7, 'like': 11, 'hot': 4, 'dogs': 2, 'i like': 8, 'like hot': 12, 'hot dogs': 5, 'the': 16, 'dog': 0, 'ran': 14, 'fast': 3, 'the dog': 17, 'dog ran': 1, 'ran fast': 15, 'its': 9, 'outside': 13, 'its hot': 10, 'hot outside': 6}\n"
]
},
{
"data": {
"text/plain": [
"array([[1, 0, 1, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],\n",
" dtype=int64)"
]
},
"execution_count": 26,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bigram_vectorizer = CountVectorizer(ngram_range=(1, 2), token_pattern=r'\\b\\w+\\b', min_df=1)\n",
"corpus = [\n",
" 'I like hot dogs.',\n",
" 'The dog ran fast.',\n",
" 'Its hot outside.',\n",
" ]\n",
"bigram_vectorizer.fit_transform(corpus)\n",
"print(\"Vocabulary:\\n\",bigram_vectorizer.vocabulary_)\n",
"bigram_vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ចំណុចខ្វះខាតសំខាន់នៃវិធីសាស្រ្ត N-gram គឺទំហំវេយ្យាករណ៍ចាប់ផ្តើមរីកចម្រើនយ៉ាងឆាប់រហ័ស ។ ក្នុងការអនុវត្តន៍ ពួកយើងត្រូវការចងក្រងការ​តំណាង N-gram ជាមួយបច្ចេកទេស​ការកាត់បន្ថយ​រាងវេកទិសខ្លះៗ ដូចជា *embeddings* ដែលយើងនឹងពិភាក្សានៅឯកតាចុងក្រោយ។\n",
"\n",
"ដើម្បីប្រើប្រាស់ការតំណាង N-gram នៅក្នុងទិន្នន័យ **AG News** របស់យើង យើងត្រូវតែបង្កើតវេយ្យាករណ៍ ngram ពិសេស ៖\n"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Bigram vocabulary length = 1308842\n"
]
}
],
"source": [
"counter = collections.Counter()\n",
"for (label, line) in train_dataset:\n",
" l = tokenizer(line)\n",
" counter.update(torchtext.data.utils.ngrams_iterator(l,ngrams=2))\n",
" \n",
"bi_vocab = torchtext.vocab.vocab(counter, min_freq=1)\n",
"\n",
"print(\"Bigram vocabulary length = \",len(bi_vocab))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"យើងអាចប្រើកូដដូចខាងលើដើម្បីបណ្តុះម៉ាស៊ីនចាត់ថ្នាក់ ប៉ុន្តែវានឹងប្រើអង្គចងចាំខ្លាំងណាស់។ នៅឯកត្តាបន្ទាប់ យើងនឹងបណ្តុះម៉ាស៊ីនចាត់ថ្នាក់ bigram ដោយប្រើ embeddings។\n",
"\n",
"> **សម្គាល់:** អ្នកអាចទុកតែ ngrams ដែលបញ្ចេញឡើងក្នុងអត្ថបទច្រើនជាងចំនួនដែលបានបញ្ជាក់។ វានឹងធានាថា bigrams ដែលមានកំណត់នឹងត្រូវដកចេញ ហើយនឹងបន្ថយវិមាត្រជាប្រសើរណាស់។ ដើម្បីធ្វើដូចនេះ សូមកំណត់ប៉ារ៉ាម៉ែត្រ `min_freq` ទៅតម្លៃខ្ពស់ជាងនេះ ហើយមើលការផ្លាស់ប្តូរវែងនៃវចនានុក្រម។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Term Frequency Inverse Document Frequency TF-IDF\n",
"\n",
"ក្នុងការតំណាង BoW, ការបង្ហាញពាក្យត្រូវបានគិតសោយាក់កម្រ, មិនគិតថាពាក្យនោះជាពាក្យអ្វីនោះទេ។ ទោះជាយ៉ាងណា, គឺច្បាស់ថាពាក្យដែលមានប្រេកង់ច្រើន ដូចជា *a*, *in* ល។ មានសារៈសំខាន់តិចជាងបច្ចេកទេសពិសេស។ ជាការពិត, ក្នុងភារកិច្ច NLP ភាគច្រើនពាក្យខ្លះមានទំនាក់ទំនងសំខាន់ជាងពាក្យផ្សេងទៀត។\n",
"\n",
"**TF-IDF** មានន័យថា **term frequencyinverse document frequency**។ វាជាបម្លែងពីបាវពាក្យដែលជំនួសដោយតម្លៃពីរបៀប 0/1 ដែលបង្ហាញពីការបង្ហាញរបស់ពាក្យមួយក្នុងឯកសារ ដែលមានតម្លៃជាចំនួនទសភាគ ដែលទាក់ទងនឹងប្រេកង់នៃការបង្ហាញពាក្យនៅក្នុងក្រុមឯកសារ។\n",
"\n",
"យ៉ាងជាក់លាក់, ទម្ងន់ $w_{ij}$ នៃពាក្យ $i$ នៅក្នុងឯកសារ $j$ ត្រូវបានកំណត់ដូចជា៖\n",
"$$\n",
"w_{ij} = tf_{ij}\\times\\log({N\\over df_i})\n",
"$$\n",
"ដែល\n",
"* $tf_{ij}$ គឺជាចំនួនការបង្ហាញនៃ $i$ នៅក្នុង $j$, គឺតម្លៃ BoW ដែលយើងបានឃើញមុន\n",
"* $N$ គឺជាចំនួនឯកសារ​នៅក្នុងប្រមូលផ្តុំ\n",
"* $df_i$ គឺជាចំនួនឯកសារដែលមានពាក្យ $i$ នៅក្នុងប្រមូលផ្តុំទាំងមូល\n",
"\n",
"តម្លៃ TF-IDF $w_{ij}$ បន្ថែមឡើងជាផ្តាច់មុខទៅនឹងចំនួនដងដែលពាក្យមួយប្រែប្រួលក្នុងឯកសារ ហើយត្រូវបានពន្លាក់ដោយចំនួនឯកសារនៅក្នុងក្រុមឯកសារដែលមានពាក្យនោះ ដែលជួយកែសម្រួលសម្រាប់ការពិតថាពាក្យខ្លះបង្ហាញញឹកញាប់ជាងពាក្យផ្សេងៗ។ ឧទាហរណ៍ ប្រសិនបើពាក្យបង្ហាញនៅក្នុង *គ្រប់* ឯកសារនៅក្នុងប្រមូលផ្តុំ, $df_i=N$, ហើយ $w_{ij}=0$, ហើយពាក្យទាំងនោះនឹងត្រូវបានមិនគិតទេ។\n",
"\n",
"អ្នកអាចបង្កើតបច្ចេកទេសវ៉េកទ័រ TF-IDF របស់អត្ថបទដោយងាយស្រួលជាមួយ Scikit Learn:\n"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[0.43381609, 0. , 0.43381609, 0. , 0.65985664,\n",
" 0.43381609, 0. , 0. , 0. , 0. ,\n",
" 0. , 0. , 0. , 0. , 0. ,\n",
" 0. ]])"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from sklearn.feature_extraction.text import TfidfVectorizer\n",
"vectorizer = TfidfVectorizer(ngram_range=(1,2))\n",
"vectorizer.fit_transform(corpus)\n",
"vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## និទស្សន៏\n",
"\n",
"ទោះបីជាការបង្ហាញ TF-IDF ផ្តល់ទំងន់ប្រេកង់ចំពោះពាក្យផ្សេងៗក៏ដោយ វាមិនអាចបង្ហាញអត្ថន័យឬលំដាប់បានទេ។ ដូចដែលវចនករល្បី J. R. Firth បាននិយាយនៅឆ្នាំ ១៩៣៥ ថា “អត្ថន័យពេញលេញនៃពាក្យមួយគឺជានិរិច្ឆេទតែប៉ុណ្ណោះ ហើយការសិក្សាអត្ថន័យដោយមិនពាក់ព័ន្ធនឹងបរិបទមិនអាចយកត្រឹមត្រូវបានទេ។”។ យើងនឹងរៀនបន្ថែមនៅពេលក្រោយក្នុងវគ្គថ្នាក់របៀបចាប់យកព័ត៌មានបរិបទពីអត្ថបទដោយប្រើគំរូភាសា។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**ការពិបាក**៖\nឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេលដែលយើងខិតខំសម្រាប់ភាពត្រឹមត្រូវ សូមយកចិត្តទុកដាក់ថាបកប្រែដោយស្វ័យប្រវត្តិក្នុងខ្លះអាចមានកំហុសឬភាពមិនត្រឹមត្រូវ។ ឯកសារដែលមានភាសាមូលដ្ឋានគួរត្រូវបានគេចាត់ទុកជាផ្លូវការមួយ។ សម្រាប់ព័ត៌មានសំខាន់ៗ ការបកប្រែដោយអ្នកជំនាញមនុស្សគឺមានការផ្តល់អនុសាសន៍។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំឬការបកស្រាយខុសឆ្គងដែលកើតឡើងពីការប្រើប្រាស់បកប្រែនេះឡើយ។\n<!-- CO-OP TRANSLATOR DISCLAIMER END -->\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "16af2a8bbb083ea23e5e41c7f5787656b2ce26968575d8763f2c4b17f9cd711f"
},
"kernelspec": {
"display_name": "Python 3.8.12 ('py38')",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.12"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@ -0,0 +1,641 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# ការប្រភេទអត្ថបទ\n",
"\n",
"ក្នុងមូឌុលនេះ យើង​នឹងចាប់​ផ្តើម​ជាមួយ​ការងារ​ប្រភេទ​អត្ថបទ​រឹងមួយ​ដែលមានមូលដ្ឋានលើ **[AG_NEWS](http://www.di.unipi.it/~gulli/AG_corpus_of_news_articles.html)**៖ យើង​នឹងចាត់ថ្នាក់​ចំណងជើង​ព័ត៌មាន​ទៅក្នុង​ប្រភេទ​មួយពីចំនួន ៤ គឺ​ពិភពលោក កីឡា អាជីវកម្ម និង វិទ្យាសាស្ត្រ/បច្ចេកវិទ្យា។\n",
"\n",
"## សំណុំទិន្នន័យ\n",
"\n",
"ដើម្បី​ផ្ទុក​សំណុំទិន្នន័យ យើង​នឹង​ប្រើ​អ្នកប្រើប្រាស់ API របស់ **[TensorFlow Datasets](https://www.tensorflow.org/datasets)**។\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import tensorflow as tf\n",
"from tensorflow import keras\n",
"import tensorflow_datasets as tfds\n",
"\n",
"# In this tutorial, we will be training a lot of models. In order to use GPU memory cautiously,\n",
"# we will set tensorflow option to grow GPU memory allocation when required.\n",
"physical_devices = tf.config.list_physical_devices('GPU') \n",
"if len(physical_devices)>0:\n",
" tf.config.experimental.set_memory_growth(physical_devices[0], True)\n",
"\n",
"dataset = tfds.load('ag_news_subset')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ឥឡូវនេះយើងអាចចូលប្រើផ្នែកបណ្តុះបណ្តាល និងផ្នែកសាកល្បងនៃសំណុំទិន្នន័យដោយប្រើ `dataset['train']` និង `dataset['test']` តាមលំដាប់៖\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Length of train dataset = 120000\n",
"Length of test dataset = 7600\n"
]
}
],
"source": [
"ds_train = dataset['train']\n",
"ds_test = dataset['test']\n",
"\n",
"print(f\"Length of train dataset = {len(ds_train)}\")\n",
"print(f\"Length of test dataset = {len(ds_test)}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"មកបោះពុម្ពចេញចំណងជើងព័ត៌មានថ្មី ១០ ប្រធានចុងពីកំណត់ត្រារបស់យើង៖\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3 (Sci/Tech) -> b'AMD Debuts Dual-Core Opteron Processor' b'AMD #39;s new dual-core Opteron chip is designed mainly for corporate computing applications, including databases, Web services, and financial transactions.'\n",
"1 (Sports) -> b\"Wood's Suspension Upheld (Reuters)\" b'Reuters - Major League Baseball\\\\Monday announced a decision on the appeal filed by Chicago Cubs\\\\pitcher Kerry Wood regarding a suspension stemming from an\\\\incident earlier this season.'\n",
"2 (Business) -> b'Bush reform may have blue states seeing red' b'President Bush #39;s quot;revenue-neutral quot; tax reform needs losers to balance its winners, and people claiming the federal deduction for state and local taxes may be in administration planners #39; sights, news reports say.'\n",
"3 (Sci/Tech) -> b\"'Halt science decline in schools'\" b'Britain will run out of leading scientists unless science education is improved, says Professor Colin Pillinger.'\n",
"1 (Sports) -> b'Gerrard leaves practice' b'London, England (Sports Network) - England midfielder Steven Gerrard injured his groin late in Thursday #39;s training session, but is hopeful he will be ready for Saturday #39;s World Cup qualifier against Austria.'\n"
]
}
],
"source": [
"classes = ['World', 'Sports', 'Business', 'Sci/Tech']\n",
"\n",
"for i,x in zip(range(5),ds_train):\n",
" print(f\"{x['label']} ({classes[x['label']]}) -> {x['title']} {x['description']}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ការបម្លែងអត្ថបទទៅជាវិចទ័រ\n",
"\n",
"ឥឡូវនេះយើងត្រូវការបម្លែងអត្ថបទទៅជា **លេខ** ដែលអាចត្រូវបានតំណាងជាទង់សរ។ ប្រសិនបើយើងចង់បានការតំណាងនៅកម្រិតពាក្យ យើងត្រូវធ្វើរឿងពីរនេះ៖\n",
"\n",
"* ប្រើ **tokenizer** ដើម្បីបំបែកអត្ថបទទៅជាផ្នែកតូចៗ (**tokens**)។\n",
"* បង្កើត **វ៉ុកាប្យូលារី** សម្រាប់ those tokens នោះ។\n",
"\n",
"### ការកំណត់ទំហំវ៉ុកាប្យូលារី\n",
"\n",
"ក្នុងឧទាហរណ៍ឯកទេស AG News ទំហំវ៉ុកាប្យូលារីគឺធំបំផុត មានពាក្យលើស ១០០,០០០។ ជាទូទៅ យើងមិនត្រូវការពាក្យដែលមានកម្រិតតិចក្នុងអត្ថបទទេ &mdash; មានតែប៉ុន្មានវាក្សត្រ​ដែលមានពាក្យនោះ ហើយម៉ូដែលនឹងមិនបានរៀនពីពួកវា។ ដូច្នេះ វាមានន័យថាត្រូវកំណត់ទំហំវ៉ុកាប្យូលារីឲ្យតូចជាងនេះដោយផ្ញើអាគឺម៉ង់ទៅកាន់អ្នកបង្កើត vectorizer:\n",
"\n",
"ការ​ដំណើរការ​ទាំងពីរ​នេះ​អាច​ត្រូវបាន​គ្រប់គ្រង​ដោយ​ការ​ស្រទាប់ **TextVectorization** ។ យើងមកបង្កើតវត្ថុ vectorizer ហើយបន្ទាប់មកហៅវិធី `adapt` ដើម្បីឆែកអត្ថបទទាំងអស់និងបង្កើតវ៉ុកាប្យូលារី។\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"vocab_size = 50000\n",
"vectorizer = keras.layers.experimental.preprocessing.TextVectorization(max_tokens=vocab_size)\n",
"vectorizer.adapt(ds_train.take(500).map(lambda x: x['title']+' '+x['description']))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **ចំណាំ** ថា​យើង​កំពុង​ប្រើ​តែ​ផ្នែក​មួយ​នៃ​សំណុំ​ទិន្នន័យ​ទាំងមូល ដើម្បី​បង្កើត​ពាក្យសម្បត្តិ បង្រៀនគ្នា​ដើម្បី​ចំណាយ​ពេល​តែ្វ​រហ័ស និង​មិន​បាច់​ឲ្យ​អ្នក​រង់ចាំ។ ទោះ​យ៉ាង​ណា​យើង​កំពុង​រក្សា​ឲ្យ​មាន​ហានិភ័យ​ថា​ពាក្យ​ខ្លះ​ពី​សំណុំ​ទិន្នន័យ​ទាំង​មូល​នោះ နឹង​មិនមាន​នៅ​ក្នុង​ពាក្យសម្បត្តិ​នោះ​ទេ ហើយ​នឹង​ត្រូវ​មិនគិត​ទៅ​វិញ​ពេល​បណ្ដុះបណ្ដាល។ ដូច្នេះ​ការ​ប្រើ​កំណត់​ទំហំ​ពាក្យសម្បត្តិ​ទាំងមូល និង​រត់​តាម​សំណុំ​ទិន្នន័យ​ទាំងមូល​នៅ​ពេល `adapt` គួរតែ​បង្កើន​ភាពត្រឹមត្រូវ​ចុងក្រោយ ប៉ុន្តែ​មិន​បាន​ធំ​ទេ។\n",
"\n",
"ឥឡូវ​នេះ​យើង​អាច​ចូលដំណើរការ​ពាក្យសម្បត្តិ​ពិតប្រាកដ:\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['', '[UNK]', 'the', 'to', 'a', 'in', 'of', 'and', 'on', 'for']\n",
"Length of vocabulary: 5335\n"
]
}
],
"source": [
"vocab = vectorizer.get_vocabulary()\n",
"vocab_size = len(vocab)\n",
"print(vocab[:10])\n",
"print(f\"Length of vocabulary: {vocab_size}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ដោយប្រើឧបករណ៍បំលែងវ៉ិចទ័រ យើងអាចបំលែងអត្ថបទណាមួយទៅជាសំណុំលេខបានយ៉ាងងាយស្រួល៖\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<tf.Tensor: shape=(7,), dtype=int64, numpy=array([ 112, 3695, 3, 304, 11, 1041, 1], dtype=int64)>"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"vectorizer('I love to play with my words')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ការទ្រទ្រង់អត្ថបទដោយក្មេងពាក្យ\n",
"\n",
"ដោយសារពាក្យតំណាងឲ្យ​អត្ថន័យ កម្រិតខ្លះ យើងអាចរកឃើញ​អត្ថន័យ​របស់​អត្ថបទមួយ​តាមរយៈ​ការ​មើល​រូបមន្តពាក្យ​ផ្តាច់មុខដោយមិនគិតពីរបៀបរៀបចំ​របស់​ពួកវា​ក្នុង​ប្រយោគ។ ឧទាហរណ៍ ដោយពិចារណាក្រោមបែបបទផ្សាយព័ត៌មាន ពាក្យដូចជា *អាកាសធាតុ* និង *ព្រិល* មានន័យប្រាប់​ពី *ការព្យាករណ៍អាកាសធាតុ* ខណៈពេលដែលពាក្យដូចជា *ភាគហ៊ុន* និង *ដុល្លារ* នឹងរាប់បញ្ចូលទៅក្នុង *ព័ត៌មានហិរញ្ញវត្ថុ* ។\n",
"\n",
"**ការទ្រទ្រង់ជាម៉ូដែល Bag-of-words** (BoW) គឺជាការទ្រទ្រង់វ៉ិចទ័រដែលងាយស្រួលយល់បំផុតតាមលំនាំប្រពៃណី។ ពាក្យនីមួយៗត្រូវបានភ្ជាប់ទៅនឹងការរូបរាងវ៉ិចទ័រមួយ ហើយធាតុវ៉ិចទ័រមួយមានចំនួនករណីនៃពាក្យនីមួយៗដែលមាននៅក្នុងឯកសារដែលបានផ្តល់។\n",
"\n",
"![រូបភាពបង្ហាញរបៀប​ដែលការទ្រទ្រង់ជាវ៉ិចទ័រម៉ូដែល Bag-of-words ត្រូវបានបង្ហាញក្នុងអង្គចងចាំ។](../../../../../translated_images/km/bag-of-words-example.606fc1738f1d7ba9.webp) \n",
"\n",
"> **ចំណាំ**៖ អ្នកក៏អាចគិតថា BoW គឺជាការបូកគណនារូបរាងវ៉ិចទ័រ one-hot-encoded សម្រាប់ពាក្យនីមួយៗនៅក្នុងអត្ថបទ។\n",
"\n",
"ខាងក្រោមជាឧទាហរណ៍​នៃ​របៀប​បង្កើតការទ្រទ្រង់ bag-of-words ដោយប្រើ thư viện python Scikit Learn:\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[1, 1, 0, 2, 0, 0, 0, 0, 0]], dtype=int64)"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from sklearn.feature_extraction.text import CountVectorizer\n",
"sc_vectorizer = CountVectorizer()\n",
"corpus = [\n",
" 'I like hot dogs.',\n",
" 'The dog ran fast.',\n",
" 'Its hot outside.',\n",
" ]\n",
"sc_vectorizer.fit_transform(corpus)\n",
"sc_vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"យើងក៏អាចប្រើប្រាស់កម្មវិធី Keras vectorizer ដែលយើងបានកំណត់ខាងលើ ដើម្បីបម្លែងលេខពាក្យនីមួយៗទៅជាការអ៊ិនកូដមួយកំឡុង ហើយបូកវ៉ិចទ័រទាំងអស់នោះឡើង៖\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([0., 5., 0., ..., 0., 0., 0.], dtype=float32)"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def to_bow(text):\n",
" return tf.reduce_sum(tf.one_hot(vectorizer(text),vocab_size),axis=0)\n",
"\n",
"to_bow('My dog likes hot dogs on a hot day.').numpy()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **ចំណាំ**: អ្នកប្រហែលជាភ្ញាក់ផ្អើលថាលទ្ធផលខុសពីឧទាហរណ៍មុននេះ។ ការរឿងនោះស្ថិតនៅក្នុងឧទាហរណ៍ Keras ដែលប្រវែងនៃវ៉ិកទ័រត្រូវបានផ្គូរផ្គងនឹងទំហំវចនានុក្រម ដែលបានសាងសង់ពីទិន្នន័យ AG News ទាំងមូល ខណៈនៅក្នុងឧទាហរណ៍ Scikit Learn យើងបានសង់វចនានុក្រមពីអត្ថបទគំរូក្នុងពេលជាក់លាក់។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## បណ្តុះបណ្តាលអ្នកចាត់ថ្នាក់ BoW\n",
"\n",
"ឥឡូវនេះដែលយើងបានរៀនយ៉ាងដឹងថាតើធ្វើដូចម្តេចដើម្បីបង្កើតការបង្ហាញ bag-of-words សម្រាប់អត្ថបទរបស់យើងហើយ ចូរបណ្តុះបណ្តាលអ្នកចាត់ថ្នាក់មួយដែលប្រើវា។ ជាដំបូង យើងត្រូវបំលែង dataset របស់យើងទៅជាការបង្ហាញ bag-of-words។ វាអាចត្រូវបានសំរេចដោយប្រើមុខងារ `map` ដូចខាងក្រោម៖\n"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"batch_size = 128\n",
"\n",
"ds_train_bow = ds_train.map(lambda x: (to_bow(x['title']+x['description']),x['label'])).batch(batch_size)\n",
"ds_test_bow = ds_test.map(lambda x: (to_bow(x['title']+x['description']),x['label'])).batch(batch_size)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ឥឡូវយើងខ្លាំងកំណត់បណ្តាញសរសៃប្រស фотографииាទម្នាក់ជាកម្មវិធីចំណាត់ថ្នាក់សាមញ្ញមួយដែលមានថាសភ្ជាប់តែមួយ។ ទំហំបញ្ចូលគឺ `vocab_size` ហើយទំហំបញ្ចូលតំណាងឲ្យចំនួនថ្នាក់ (4)។ ព្រោះយើងកំពុងដោះស្រាយបញ្ហាការចំណាត់ថ្នាក់, មុខងារជំរុញចុងក្រោយគឺ **softmax**៖\n"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"938/938 [==============================] - 66s 70ms/step - loss: 0.6144 - acc: 0.8427 - val_loss: 0.4416 - val_acc: 0.8697\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x20c70a947f0>"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = keras.models.Sequential([\n",
" keras.layers.Dense(4,activation='softmax',input_shape=(vocab_size,))\n",
"])\n",
"model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])\n",
"model.fit(ds_train_bow,validation_data=ds_test_bow)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Since we have 4 classes, an accuracy of above 80% is a good result.\n",
"\n",
"## ការបណ្តុះបណ្តាលព្យាករណ៍ជាបណ្ដាញតែមួយ\n",
"\n",
"ដោយសារតែ vectorizer ក៏ជាស្រទាប់ Keras ផងដែរ យើងអាចកំណត់បណ្ដាញមួយដែលរួមមានវា ហើយបណ្តុះបណ្តាលវាជាចុងទៅចុង។ ដូច្នេះយើងមិនចាំបាច់ vectorize សំណុំទិន្នន័យដោយប្រើ `map` ទេ អ្នកអាចផ្តល់សំណុំទិន្នន័យដើមទៅការបញ្ចូលរបស់បណ្ដាញ។\n",
"\n",
"> **កំណត់ចំណាំ**: យើងនៅតែត្រូវតែប្រើម៉ាប់ទៅលើសំណុំទិន្នន័យរបស់យើងដើម្បីផ្លាស់ប្ដូរបន្ទះពីវចនានុក្រម (ដូចជា `title`, `description` និង `label`) ទៅជា tuples។ ទោះយ៉ាងណា នៅពេលផ្ទុកទិន្នន័យពីឌីស អាចកសាងសំណុំទិន្នន័យជាមួយរចនាសម្ព័ន្ធដែលត្រូវការជាលើកដំបូង។\n"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"model\"\n",
"_________________________________________________________________\n",
" Layer (type) Output Shape Param # \n",
"=================================================================\n",
" input_1 (InputLayer) [(None, 1)] 0 \n",
" \n",
" text_vectorization (TextVec (None, None) 0 \n",
" torization) \n",
" \n",
" tf.one_hot (TFOpLambda) (None, None, 5335) 0 \n",
" \n",
" tf.math.reduce_sum (TFOpLam (None, 5335) 0 \n",
" bda) \n",
" \n",
" dense_2 (Dense) (None, 4) 21344 \n",
" \n",
"=================================================================\n",
"Total params: 21,344\n",
"Trainable params: 21,344\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n",
"938/938 [==============================] - 73s 77ms/step - loss: 0.6057 - acc: 0.8414 - val_loss: 0.4202 - val_acc: 0.8736\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x20c721521f0>"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def extract_text(x):\n",
" return x['title']+' '+x['description']\n",
"\n",
"def tupelize(x):\n",
" return (extract_text(x),x['label'])\n",
"\n",
"inp = keras.Input(shape=(1,),dtype=tf.string)\n",
"x = vectorizer(inp)\n",
"x = tf.reduce_sum(tf.one_hot(x,vocab_size),axis=1)\n",
"out = keras.layers.Dense(4,activation='softmax')(x)\n",
"model = keras.models.Model(inp,out)\n",
"model.summary()\n",
"\n",
"model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])\n",
"model.fit(ds_train.map(tupelize).batch(batch_size),validation_data=ds_test.map(tupelize).batch(batch_size))\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Bigrams, trigrams និង n-grams\n",
"\n",
"កំណត់ហេតុមួយនៃវិធីសាស្រ្ត bag-of-words គឺពាក្យខ្លះជាផ្នែកនៃអត្ថបទពេញលេញមួយដែលមានពាក្យច្រើន, ឧទាហរណ៍, ពាក្យ 'hot dog' មានអត្ថន័យខុសគ្នាឥតខ្ចោះពីពាក្យ 'hot' និង 'dog' នៅក្នុងបរិបទផ្សេងទៀត។ ប្រសិនបើយើងបង្ហាញពាក្យ 'hot' និង 'dog' ជារូបមន្តដូចគ្នាទាំងអស់ វាអាចធ្វើឱ្យម៉ូដែលរបស់យើងបូកស្រួល។\n",
"\n",
"ដើម្បីដោះស្រាយបញ្ហានេះ, **ការតំណាងនៃ n-gram** ត្រូវបានប្រើយ៉ាងធម្មតា ក្នុងវិធីសាស្រ្តចំណាត់ថ្នាក់ឯកសារ ដែលដែលបរិមាណនៃពាក្យនីមួយៗ bi-word ឬ tri-word ជាសមាសធាតុមានប្រយោជន៍សម្រាប់បណ្តុះបណ្តាលអ្នកចំណាត់ថ្នាក់។ នៅក្នុងការតំណាង bigram, ឧទាហរណ៍, យើងនឹងបន្ថែមគូពាក្យទាំងអស់ទៅវចនានុក្រម បន្ថែមផងដល់ពាក្យដើម។\n",
"\n",
"ខាងក្រោមជាឧទាហរណ៍នៃវិធីបង្កើតការតំណាង bag of word bigram ដោយប្រើ Scikit Learnៈ\n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Vocabulary:\n",
" {'i': 7, 'like': 11, 'hot': 4, 'dogs': 2, 'i like': 8, 'like hot': 12, 'hot dogs': 5, 'the': 16, 'dog': 0, 'ran': 14, 'fast': 3, 'the dog': 17, 'dog ran': 1, 'ran fast': 15, 'its': 9, 'outside': 13, 'its hot': 10, 'hot outside': 6}\n"
]
},
{
"data": {
"text/plain": [
"array([[1, 0, 1, 0, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],\n",
" dtype=int64)"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"bigram_vectorizer = CountVectorizer(ngram_range=(1, 2), token_pattern=r'\\b\\w+\\b', min_df=1)\n",
"corpus = [\n",
" 'I like hot dogs.',\n",
" 'The dog ran fast.',\n",
" 'Its hot outside.',\n",
" ]\n",
"bigram_vectorizer.fit_transform(corpus)\n",
"print(\"Vocabulary:\\n\",bigram_vectorizer.vocabulary_)\n",
"bigram_vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ចំនុចខ្សោយសំខាន់នៃវិធីសាស្រ្ត n-gram គឺទំហំវាក្យសម្ពន្ធ​ក្នុងភាសា​ចាប់ផ្តើមតែបង្កើនយ៉ាងលឿនខ្លាំង។ ក្នុងការអនុវត្តថ្មីៗនេះ យើងត្រូវការរួមបញ្ចូល​តំណាង n-gram ជាមួយនឹងបច្ចេកទេសកាត់បន្ថយវិមាត្រ មួយដូចជា *embeddings* ដែលយើងនឹងពិភាក្សានៅក្នុងឯកតាតទៅមុខ។\n",
"\n",
"ដើម្បីប្រើតំណាង n-gram ក្នុងឃ្លាំងទិន្នន័យ **AG News** របស់យើង យើងត្រូវបញ្ជូនចូលប៉ារ៉ាម៉ែត្រ `ngrams` ទៅក្នុងអ្នកបង្កើត `TextVectorization` របស់យើង។ ប្រវែងនៃវាក្យសម្ពន្ធ bigram គឺ **ធំជាងយ៉ាងសំខាន់** ក្នុងករណីរបស់យើងវាធ្វើបានលើស 1.3 លានសញ្ញានៅឡើយ! ដូចនេះវាអាចមានអត្ថប្រយោជន៍ក្នុងការរំលងត្រីកោណ bigram ដោយចំនួនដែលសមរម្យ។\n",
"\n",
"យើងអាចប្រើកូដដូចខាងលើដដែលដើម្បីបណ្តុះបណ្តាលអ្នកចាត់ថ្នាក់ ក៏ប៉ុន្តែ វាកើតមានការប្រើប្រាស់អង្គចងចាំមិនមានប្រសិទ្ធភាពទេ។ នៅឯកតាទៅមុខយើងនឹងបណ្តុះបណ្តាលអ្នកចាត់ថ្នាក់ bigram ប្រើ embeddings។ នៅពេលនេះ អ្នកអាចសាកល្បងបណ្តុះបណ្តាលអ្នកចាត់ថ្នាក់ bigram ក្នុងសៀវភៅកំណត់ត្រានេះ ហើយមើលថាតើអ្នកអាចទទួលបានភាពច្បាស់លាស់ខ្ពស់ជាងមុនទេ។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ការគណនាផ្ទាល់ដោយស្វ័យប្រវត្តិរបស់វ៉ិចទ័រប៊លស័រ BoW\n",
"\n",
"នៅក្នុងឧទាហរណ៍ខាងលើ យើងបានគណនាវ៉ិចទ័រប៊លស័រ BoW ដោយដៃ ដោយបូកសំឡេងបញ្ចូលមួយ-កម្រាស់នៃពាក្យមួយៗ។ ទោះបីជាយ៉ាងណា កំណែចុងក្រោយនៃ TensorFlow អនុញ្ញាតឱ្យយើងគណនាវ៉ិចទ័រប៊លស័រ BoW ដោយស្វ័យប្រវត្តិ ដោយផ្តល់ប៉ារ៉ាម៉ែត្រ `output_mode='count` ទៅដល់អ្នកបង្កើតវ៉ិចទ័រ។ វានាំឲ្យការកំណត់និងបណ្តុះបណ្តាលម៉ូដែលរបស់យើងក្លាយជាស្រួលយ៉ាងច្រើន៖\n"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Training vectorizer\n",
"938/938 [==============================] - 7s 7ms/step - loss: 0.5929 - acc: 0.8486 - val_loss: 0.4168 - val_acc: 0.8772\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x20c725217c0>"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = keras.models.Sequential([\n",
" keras.layers.experimental.preprocessing.TextVectorization(max_tokens=vocab_size,output_mode='count'),\n",
" keras.layers.Dense(4,input_shape=(vocab_size,), activation='softmax')\n",
"])\n",
"print(\"Training vectorizer\")\n",
"model.layers[0].adapt(ds_train.take(500).map(extract_text))\n",
"model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])\n",
"model.fit(ds_train.map(tupelize).batch(batch_size),validation_data=ds_test.map(tupelize).batch(batch_size))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ការពេញនិយមពាក្យ - អត្រាប្រាក់ឯកសារវិទ្យុបញ្ច្រាស (TF-IDF)\n",
"\n",
"ក្នុងការបង្ហាញ BoW,ការ កើតឡើងនៃពាក្យត្រូវបានវាស់គ្រប់យ៉ាង ដោយប្រើប្រាស់បច្ចេកវិទ្យាដូចគ្នាដោយមិនគិតពីពាក្យ។ ទោះយ៉ាងណា វCLEARថាពាក្យដែលកើតឡើងជាញឹកញាប់ដូចជា *a* និង *in* មានសារៈសំខាន់តិចជាងសម្រាប់ការធ្វើចំណាត់ថ្នាក់ជាងពាក្យឯកទេស។ ក្នុងភារកិច្ច NLP ភាគច្រើនពាក្យខ្លះមានសារៈសំខាន់ជាងអ្វីៗផ្សេងទៀត។\n",
"\n",
"**TF-IDF** មានន័យថា **ការពេញនិយមពាក្យ - អត្រាប្រាក់ឯកសារវិទ្យុបញ្ច្រាស**។ វាជារបៀបបំលែង bag-of-words មួយ ដែលជំនួសជំនួសតម្លៃ 0/1 ដែលបង្ហាញពីការបង្ហាញខ្លួននៃពាក្យក្នុងឯកសារ ដោយប្រើតម្លៃទសភាគដែលពាក់ព័ន្ធនឹងការកើតឡើងច្រើននៃពាក្យនៅក្នុងសៀវភៅឯកសារ។\n",
"\n",
"យ៉ាងជាក់លាក់ ការវាស់ទំងន់ $w_{ij}$ របស់ពាក្យ $i$ នៅក្នុងឯកសារ $j$ ត្រូវបានកំណត់ជា៖\n",
"$$\n",
"w_{ij} = tf_{ij}\\times\\log({N\\over df_i})\n",
"$$\n",
"ដែល\n",
"* $tf_{ij}$ គឺ​ចំនួនករណីកើតឡើងនៃ $i$ ក្នុង $j$ ឧ. តម្លៃ BoW ដែលយើងបានឃើញមុន\n",
"* $N$ គឺចំនួនឯកសារនៅក្នុងកម្រង\n",
"* $df_i$ គឺចំនួនឯកសារដែលមានពាក្យ $i$ ក្នុងកម្រងទាំងមូល\n",
"\n",
"តម្លៃ TF-IDF $w_{ij}$ កើនឡើងបរិមាណផ្គួសៗទៅនឹងចំនួននៃពេលដែលពាក្យមួយបង្ហាញក្នុងឯកសារ ហើយត្រូវបានលៃតម្រូវដោយចំនួនឯកសារនៅក្នុងសៀវភៅដែលមានពាក្យនោះ ដែលជួយឲ្យត្រូវតែចៀសវាងពីការពិតដែលមានពាក្យមួយចំនួនបង្ហាញជាញឹកញាប់ជាងពាក្យផ្សេងៗ។ ឧទាហរណ៍ ប្រសិនបើពាក្យបង្ហាញនៅក្នុង *គ្រប់* ឯកសារនៅក្នុងកម្រង, $df_i=N$ ហើយ $w_{ij}=0$, ហើយពាក្យទាំងនោះនឹងត្រូវបានមិនគិតទាំងស្រុង។\n",
"\n",
"អ្នកអាចបង្កើតវ៉ិចទ័រ TF-IDF នៃអត្ថបទបានយ៉ាងងាយស្រួលដោយប្រើ Scikit Learn:\n"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[0.43381609, 0. , 0.43381609, 0. , 0.65985664,\n",
" 0.43381609, 0. , 0. , 0. , 0. ,\n",
" 0. , 0. , 0. , 0. , 0. ,\n",
" 0. ]])"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from sklearn.feature_extraction.text import TfidfVectorizer\n",
"vectorizer = TfidfVectorizer(ngram_range=(1,2))\n",
"vectorizer.fit_transform(corpus)\n",
"vectorizer.transform(['My dog likes hot dogs on a hot day.']).toarray()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"នៅក្នុង Keras ស្រទាប់ `TextVectorization` អាចគណនាប្រមាណភាព TF-IDF ដោយស្វ័យប្រវត្តិដោយផ្ទេរព៉ារ៉ាម៉ែត្រ `output_mode='tf-idf'`។ សូមធ្វើម្តងទៀតនូវកូដដែលយើងបានប្រើខាងលើ ដើម្បីមើលថា តើការប្រើ TF-IDF មានបង្កើនភាពត្រឹមត្រូវឬអត់៖\n"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Training vectorizer\n",
"938/938 [==============================] - 12s 12ms/step - loss: 0.4197 - acc: 0.8662 - val_loss: 0.3432 - val_acc: 0.8849\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x20c729dfd30>"
]
},
"execution_count": 17,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = keras.models.Sequential([\n",
" keras.layers.experimental.preprocessing.TextVectorization(max_tokens=vocab_size,output_mode='tf-idf'),\n",
" keras.layers.Dense(4,input_shape=(vocab_size,), activation='softmax')\n",
"])\n",
"print(\"Training vectorizer\")\n",
"model.layers[0].adapt(ds_train.take(500).map(extract_text))\n",
"model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])\n",
"model.fit(ds_train.map(tupelize).batch(batch_size),validation_data=ds_test.map(tupelize).batch(batch_size))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## សេចក្ដីសន្នឹម\n",
"\n",
"ទោះបីជារូបមន្ត TF-IDF ផ្ដល់ទម្ងន់ប្រេកង់ទៅពាក្យផ្សេងៗក៏ដោយ វាមិនអាចបង្ហាញអត្ថន័យ ឬលំដាប់បានឡើយ។ ដូចដែលអ្នកភាសាល្បី J. R. Firth បាននិយាយនៅឆ្នាំ 1935 ថា \"អត្ថន័យពេញលេញនៃពាក្យមួយតែងតែមានបរិបទ ហើយការសិក្សាអំពីអត្ថន័យដែលមិនពាក់ព័ន្ធនឹងបរិបទមិនអាចយកទៅពិចារណាឲ្យបានចាប់អារម្មណ៍ឡើយ។\" យើងនឹងរៀនពីរបៀបចាប់យកព័ត៌មានបរិបទពីអត្ថបទដោយប្រើម៉ូដែលភាសាបន្ថែមនៅពេលក្រោយក្នុងវគ្គសិក្សា។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**ការ​ប្រកាស​ការពារ**៖ \nឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេល​យើងខ្ញុំ​ព្យាយាម​ធានា​ភាព​ត្រឹមត្រូវ សូមយល់ដឹងថា​ការ​បកប្រែ​ដោយ​ស្វ័យ​ប្រវត្តិ​អាច​មាន​កំហុស​ឬ​ភាព​មិន​ត្រឹមត្រូវ។ ឯកសារ​ដើម​ក្នុង​ភាសា​ដើម​គួរត្រូវ​បាន​គេចាត់ទុក​ជា​ប្រភព​ដើម​ដែលមាន​សិទិ្ធ​ផ្លូវការ។ សម្រាប់​ព័ត៌មាន​សំខាន់ៗ ការបកប្រែ​ដោយ​មនុស្ស​ជំនាញ​ជា​ការ​ពេញចិត្ត​ជាង។ យើង​មិន​ទទួលខុសត្រូវ​ចំពោះ​ការ​យល់ខុស ឬ​ការបកប្រែ​ខុស​ណាមួយ​ដែល​កើត​ឡើង​ពី​ការ​ប្រើប្រាស់​ការ​បកប្រែ​នេះទេ។\n<!-- CO-OP TRANSLATOR DISCLAIMER END -->\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "0cb620c6d4b9f7a635928804c26cf22403d89d98d79684e4529119355ee6d5a5"
},
"kernel_info": {
"name": "conda-env-py37_tensorflow-py"
},
"kernelspec": {
"display_name": "py37_tensorflow",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.12"
},
"nteract": {
"version": "nteract-front-end@1.0.0"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,10 @@
# Assignment: Notebooks
ដោយប្រើកំណត់ចំណាំដែលភ្ជាប់ជាមួយមេរៀននេះ (ថ្នាក់ PyTorch ឬ TensorFlow) ធ្វើការរត់ម្ដងទៀតដោយប្រើទិន្នន័យផ្ទាល់ខ្លួនរបស់អ្នក ប្រហែលមួយដែលបានយកពី Kaggle ជាមួយនឹងការផ្តល់ឯកសារ។ សរសេរឡើងវិញកំណត់ចំណាំដើម្បីរំលេចលទ្ធផលផ្ទាល់ខ្លួនរបស់អ្នក។ សាកល្បងប្រើទិន្នន័យឆ្លាតវៃខ្លះដែលអាចធ្វើអោយមានភាពភ្ញាក់ផ្អើល ដូចជា [នេះអំពីការមើលឃើញ UFO](https://www.kaggle.com/datasets/NUFORC/ufo-sightings) ពី NUFORC។
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការបដិសេធ**:
ឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ បើទោះបីយើងខិតខំប្រឹងប្រែងដើម្បីទទួលបានភាពត្រឹមត្រូវ ក៏សូមយល់ថាការបកប្រែដោយស្វ័យប្រវត្តិអាចមានកំហុសឬភាពមិនត្រឹមត្រូវខ្លះ។ អ្នកគួរត្រូវយកឯកសារដើមដែលមានភាសាម្តេចជាផ្លូវការជាប្រភពសម្រាប់ព័ត៌មាន។ សម្រាប់ព័ត៌មានសំខាន់ៗណាស់ ការបកប្រែដោយអ្នកជំនាញមនុស្សត្រូវបានណែនាំ។ យើងមិនទទួលខុសត្រូវចំពោះកំហុស ឬការយល់ច្រឡំដែលកើតឡើងពីការប្រើប្រាស់ការបកប្រែនេះឡើយ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,720 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Embeddings\n",
"\n",
"នៅក្នុងឧទាហរណ៍មុនរបស់​យើង យើងបាន​ប្រតិបត្តិ​លើ​វ៉ិចទ័រ bag-of-words ដែលមានខ្សែបណ្តោយខ្ពស់ `vocab_size` និង​យើងបាន​បម្លែង​យ៉ាងច្បាស់ពី​វ៉ិចទ័រ​តំណរភាគទូលាយ ទាប ទៅជាតំណាង​តែមួយ-ក្តៅ​ដែលរាយបញ្ចាំងតិចតួច។ តំណាងតែមួយ-ក្តៅ​នេះ​មិន​មានប្រសិទ្ធភាព​ក្នុង​ការផ្ទុកចងចាំទេ បន្ថែម​ពីនេះ រាល់ពាក្យ​ត្រូវបានចាត់ទុក​ឯករាជ្យពីគ្នា ប្រែថា​វ៉ិចទ័រដែលបាន encode តែមួយ-ក្តៅ​មិនបង្ហាញន័យស្រដៀងគ្នាណាមួយ​រវាងពាក្យទេ។\n",
"\n",
"នៅក្នុងឯកតានេះ យើងនឹងបន្ត​សហការជាមួយ​ទិន្នន័យ **News AG**។ ដើម្បីចាប់ផ្តើម មកយើងផ្ទុកទិន្នន័យ និងទទួលយក​និយមន័យខ្លះ​ពីសៀវភៅកំណត់ហេតុមុន។\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Loading dataset...\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"d:\\WORK\\ai-for-beginners\\5-NLP\\14-Embeddings\\data\\train.csv: 29.5MB [00:01, 18.8MB/s] \n",
"d:\\WORK\\ai-for-beginners\\5-NLP\\14-Embeddings\\data\\test.csv: 1.86MB [00:00, 11.2MB/s] \n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Building vocab...\n",
"Vocab size = 95812\n"
]
}
],
"source": [
"import torch\n",
"import torchtext\n",
"import numpy as np\n",
"from torchnlp import *\n",
"train_dataset, test_dataset, classes, vocab = load_dataset()\n",
"vocab_size = len(vocab)\n",
"print(\"Vocab size = \",vocab_size)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## តើ embedding ជាអ្វី?\n",
"\n",
"គំនិតនៃ **embedding** គឺជារៀបរាប់​ពាក្យ​ជាវ៉ិចទ័រដ៏រឹងមាំដែលមានវិមាត្រកថ្លៃទាប ជាដើមដែលបញ្ជាក់អត្ថន័យ​យោងទៅលើពាក្យមួយ។ យើង​នឹងពិភាក្សាពីរបៀបកសាង word embeddings មានន័យ​ក្នុង​ពេលក្រោយ ប៉ុន្តែ​នាពេលនេះ hãyគិតថា embeddings ជាវិធីកាត់បន្ថយវិមាត្រនៃវ៉ិចទ័រពាក្យមួយ។\n",
"\n",
"ដូច្នេះ, ស្រទាប់ embedding នឹងទទួលពាក្យមួយជាឧបត្ថម្ភ និងបង្កើតវ៉ិចទ័រចេញ​មួយដែលមាន `embedding_size` បានកំណត់។ ក្នុងន័យមួយវាស្រដៀងទៅនឹងស្រទាប់ `Linear` តែជំនួសវិចទ័រពោលជា one-hot encoded វា​អាចទទួលលេខពាក្យដោយផ្ទាល់ជាឧបត្ថម្ភបាន។\n",
"\n",
"ដោយប្រើស្រទាប់ embedding ជាស្រទាប់ដំបូងក្នុងបណ្តាញរបស់យើង យើងអាចបម្លែងពីគំរូ bag-of-words ទៅគំរូ **embedding bag** ដែលនៅទីនោះយើងបម្លែងពាក្យនីមួយៗក្នុងអត្ថបទជាវ៉ិចទ័រពាក់ព័ន្ធ embedding ហើយបន្ទាប់មកគណនាអនុគមន៍សរុបលើវ៉ិចទ័រទាំងនោះ ដូចជា `sum`, `average` ឬ `max`។\n",
"\n",
"![រូបភាពបង្ហាញឧទាហរណ៍ embedding classifier សម្រាប់ពាក្យជាច្រើនក្នុងលំដាប់។](../../../../../translated_images/km/embedding-classifier-example.b77f021a7ee67eee.webp)\n",
"\n",
"បណ្តាញនឺរ៉ាល់នៃ classifer របស់យើង នឹងចាប់ផ្តើមជាមួយស្រទាប់ embedding បន្ទាប់ស្រទាប់ aggregation និងចុងក្រោយជាស្រទាប់ linear classifier៖\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"class EmbedClassifier(torch.nn.Module):\n",
" def __init__(self, vocab_size, embed_dim, num_class):\n",
" super().__init__()\n",
" self.embedding = torch.nn.Embedding(vocab_size, embed_dim)\n",
" self.fc = torch.nn.Linear(embed_dim, num_class)\n",
"\n",
" def forward(self, x):\n",
" x = self.embedding(x)\n",
" x = torch.mean(x,dim=1)\n",
" return self.fc(x)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### ការដោះស្រាយទំហំលំដាប់អថេរ\n",
"\n",
"ជាលទ្ធផលនៃស្ថាបត្យកម្មនេះ minibatches ទៅបណ្ដាញរបស់យើងនឹងត្រូវបានបង្កើតឡើងដោយវិធីជាក់លាក់មួយ។ នៅឯកតាមុននេះ នៅពេលប្រើ bag-of-words តង់ស័រទាំងអស់ក្នុង minibatch មានទំហំពេលស្មើគ្នា `vocab_size` មិនគិតទំហំជាក់លាក់នៃលំដាប់អត្ថបទរបស់យើងឡើយ។ ពេលយើងផ្លាស់ទៅប្រើបន្ទាត់ពាក្យ word embeddings យើងនឹងបានចំនួនពាក្យប្រែប្រួលនៅក្នុងគំរូអត្ថបទនីមួយៗ ហើយពេលបញ្ចូលគំរូទាំងនោះចូលក្នុង minibatches យើងនឹងត្រូវអនុវត្តការបញ្ចូលបន្ថែម padding មួយចំនួន។\n",
"\n",
"នេះអាចធ្វើបានដោយប្រើបច្ចេកទេសដដែលគឺផ្តល់មុខងារ `collate_fn` ទៅដល់ datasource៖\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"def padify(b):\n",
" # b is the list of tuples of length batch_size\n",
" # - first element of a tuple = label, \n",
" # - second = feature (text sequence)\n",
" # build vectorized sequence\n",
" v = [encode(x[1]) for x in b]\n",
" # first, compute max length of a sequence in this minibatch\n",
" l = max(map(len,v))\n",
" return ( # tuple of two tensors - labels and features\n",
" torch.LongTensor([t[0]-1 for t in b]),\n",
" torch.stack([torch.nn.functional.pad(torch.tensor(t),(0,l-len(t)),mode='constant',value=0) for t in v])\n",
" )\n",
"\n",
"train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=16, collate_fn=padify, shuffle=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### ការបណ្តុះបណ្តាលម៉ាស៊ីនចាត់ថ្នាក់ embedding\n",
"\n",
"ឥឡូវនេះដែលយើងបានកំណត់ dataloader ត្រឹមត្រូវហើយ យើងអាចបណ្តុះបណ្តាលម៉ូដែលដោយប្រើមុខងារ training ដែលយើងបានកំណត់នៅឯកតាមុន៖\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3200: acc=0.6415625\n",
"6400: acc=0.6865625\n",
"9600: acc=0.7103125\n",
"12800: acc=0.726953125\n",
"16000: acc=0.739375\n",
"19200: acc=0.75046875\n",
"22400: acc=0.7572321428571429\n"
]
},
{
"data": {
"text/plain": [
"(0.889799795315499, 0.7623160588611644)"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"net = EmbedClassifier(vocab_size,32,len(classes)).to(device)\n",
"train_epoch(net,train_loader, lr=1, epoch_size=25000)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **កំណត់សម្គាល់**: យើងកំពុង ONLY បណ្តុះបណ្តាលសម្រាប់កំណត់ត្រា 25,000 នៅទីនេះ (តិចជាងមួយស្ទង់ពេញ) ដើម្បីជួយការសន្សំសំចៃពេលវេលា ប៉ុន្តែអ្នកអាចបន្តការបណ្តុះបណ្តាល សរសេរពិធីសាស្រ្តមួយសម្រាប់បណ្តុះបណ្តាលជាច្រើនស្ទង់ និងសាកល្បងជាមួយប៉ារ៉ាម៉ែត្រការសិក្សា ដើម្បីទទួលបានភាពត្រឹមត្រូវខ្ពស់ជាងមុន។ អ្នកគួរតែអាចទៅដល់ភាពត្រឹមត្រូវប្រហែល ៩០%។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### EmbeddingBag ស្រទាប់ និង តំណាងរាងលំដាប់រៀងពីរយៈវែរីយ៉ាប៊ុល\n",
"\n",
"នៅក្នុងស្ថาปត្យកម្មមុន យើង​ត្រូវការបន្ថែម​ចន្លោះ​ទទេ​ទៅលើ​លំដាប់​ទាំងអស់ដើម្បីឲ្យវា​មានប្រវែង​ដូចគ្នា​ដើម្បីដាក់វាទៅក្នុង minibatch។ វា​មិនមែន​ជា​របៀបមានប្រសិទ្ធភាព​បំផុត​ក្នុងការតំណាង​លំដាប់​វែរីយ៉ាប៊ុល​នោះទេ - វិធានមួយផ្សេងគឺប្រើ​វ៉ិចទ័រ **offset** ដែលនឹងរក្សាទុកចន្លោះ offset របស់​លំដាប់ទាំងអស់​ដែលបានរក្សាទុក​ក្នុង​វ៉ិចទ័រធំបន្ទាត់មួយ។\n",
"\n",
"![Image showing an offset sequence representation](../../../../../translated_images/km/offset-sequence-representation.eb73fcefb29b46ee.webp)\n",
"\n",
"> **ចំណាំ**: នៅក្នុងរូបភាពខាងលើ យើងបង្ហាញ​លំដាប់​តួអក្សរ ប៉ុន្តែនៅក្នុងឧទាហរណ៍របស់យើង កំពុង​ដំណើរការជាលំដាប់​ពាក្យ។ ទោះយ៉ាងណា 원칙​ទូទៅ​ក្នុងការតំណាងលំដាប់ជាមួយវ៉ិចទ័រ offset នៅតែដូចគ្នា។\n",
"\n",
"ដើម្បីធ្វើការ​ជាមួយតំណាង offset យើងប្រើស្រទាប់ [`EmbeddingBag`](https://pytorch.org/docs/stable/generated/torch.nn.EmbeddingBag.html)។ វាស្រដៀងនឹង `Embedding` ប៉ុន្តែវាបានទទួល​ខ្សែវ៉ិចទ័រ និង offset វ៉ិចទ័រជាជាច្រើននូវការបញ្ចូល ហើយវាក៏រួមបញ្ចូលជាមួយស្រទាប់ averaging ដែលអាចជាផ្នែក `mean`, `sum` ឬ `max` ផងដែរ។\n",
"\n",
"នេះគឺជាបណ្តាញដែលបានកែសម្រួលដែលប្រើ `EmbeddingBag`៖\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"class EmbedClassifier(torch.nn.Module):\n",
" def __init__(self, vocab_size, embed_dim, num_class):\n",
" super().__init__()\n",
" self.embedding = torch.nn.EmbeddingBag(vocab_size, embed_dim)\n",
" self.fc = torch.nn.Linear(embed_dim, num_class)\n",
"\n",
" def forward(self, text, off):\n",
" x = self.embedding(text, off)\n",
" return self.fc(x)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ដើម្បីរៀបចំទិន្នន័យសម្រាប់ហ្វឹកហាត់ យើងត្រូវការផ្តល់មុខងារបម្លែងមួយ ដែលនឹងរៀបចំពាក្យកំណត់អូស៖\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"def offsetify(b):\n",
" # first, compute data tensor from all sequences\n",
" x = [torch.tensor(encode(t[1])) for t in b]\n",
" # now, compute the offsets by accumulating the tensor of sequence lengths\n",
" o = [0] + [len(t) for t in x]\n",
" o = torch.tensor(o[:-1]).cumsum(dim=0)\n",
" return ( \n",
" torch.LongTensor([t[0]-1 for t in b]), # labels\n",
" torch.cat(x), # text \n",
" o\n",
" )\n",
"\n",
"train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=16, collate_fn=offsetify, shuffle=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"សូមកត់សម្គាល់ថា ខុសពីគំរូទាំងអស់មុននេះ បណ្ដាញរបស់យើងឥឡូវនេះទទួលបានប៉ារាម៉ែត្រ​ពីរចូលគ្នា៖ វិចទ័រទិន្នន័យ និងវិចទ័រជំហរ ដែលមានទំហំខុសគ្នា។ ដូចគ្នានេះ អ្នកដំណើរការទិន្នន័យរបស់យើងក៏ផ្ដល់ឲ្យយើងនូវតម្លៃចំនួន៣មិនមែនត្រឹមតែ២ទេ៖ វិចទ័រទាំងអត្ថបទ និងជំហរត្រូវបានផ្ដល់ឲ្យជាលក្ខណៈពិសេស។ ដូច្នេះ យើងត្រូវកែប្រែ slightly ប្រតិបត្ដិការបណ្តុះបណ្តាលរបស់យើង ដើម្បីដោះស្រាយបញ្ហានេះ៖\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3200: acc=0.6153125\n",
"6400: acc=0.6615625\n",
"9600: acc=0.6932291666666667\n",
"12800: acc=0.715078125\n",
"16000: acc=0.7270625\n",
"19200: acc=0.7382291666666667\n",
"22400: acc=0.7486160714285715\n"
]
},
{
"data": {
"text/plain": [
"(22.771553103007037, 0.7551983365323096)"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"net = EmbedClassifier(vocab_size,32,len(classes)).to(device)\n",
"\n",
"def train_epoch_emb(net,dataloader,lr=0.01,optimizer=None,loss_fn = torch.nn.CrossEntropyLoss(),epoch_size=None, report_freq=200):\n",
" optimizer = optimizer or torch.optim.Adam(net.parameters(),lr=lr)\n",
" loss_fn = loss_fn.to(device)\n",
" net.train()\n",
" total_loss,acc,count,i = 0,0,0,0\n",
" for labels,text,off in dataloader:\n",
" optimizer.zero_grad()\n",
" labels,text,off = labels.to(device), text.to(device), off.to(device)\n",
" out = net(text, off)\n",
" loss = loss_fn(out,labels) #cross_entropy(out,labels)\n",
" loss.backward()\n",
" optimizer.step()\n",
" total_loss+=loss\n",
" _,predicted = torch.max(out,1)\n",
" acc+=(predicted==labels).sum()\n",
" count+=len(labels)\n",
" i+=1\n",
" if i%report_freq==0:\n",
" print(f\"{count}: acc={acc.item()/count}\")\n",
" if epoch_size and count>epoch_size:\n",
" break\n",
" return total_loss.item()/count, acc.item()/count\n",
"\n",
"\n",
"train_epoch_emb(net,train_loader, lr=4, epoch_size=25000)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Semantic Embeddings: Word2Vec\n",
"\n",
"នៅក្នុងឧទាហរណ៍មុនរបស់យើង ស្រទាប់ embedding ម៉ូដែលបានរៀនផែនទីពាក្យទៅរាងតំណាងវ៉ិចទ័រ ទោះជាយ៉ាងណា រាងតំណាងនេះមិនមានន័យsemantic ច្រើនទេ។ វានឹងល្អបើរៀនរាងតំណាងវ៉ិចទ័រដូច្នេះ ដែលពាក្យស្រដៀងគ្នា ឬពាក្យប្រហាក់ប្រហែលនឹងផ្គូផ្គងទៅនឹងវ៉ិចទ័រដែលនៅជិតគ្នាប្រកបដោយចម្ងាយវ៉ិចទ័រ (ឧ. ចម្ងាយអ៊ីយូគ្ល៊ីដៀន) ។\n",
"\n",
"ដើម្បីធ្វើបានដូច្នេះ យើងត្រូវបណ្ដុះម៉ូដែល embedding របស់យើងលើការប្រមូលផ្តុំអត្ថបទធំៗដោយវិធីពិសេសមួយ។ វិធីដំបូងៗក្នុងការបណ្ដុះ semantic embeddings មួយឈ្មោះ [Word2Vec](https://en.wikipedia.org/wiki/Word2vec)។ វាមានព្រណិតប្រាជ្ញាផ្លូវការចម្បងពីរដែលប្រើប្រព័ន្ធផ្សព្វផ្សាយរាងតំណាងរាងពាក្យមួយ៖\n",
"\n",
" - **Continuous bag-of-words** (CBoW) — ក្នុងសំណុំប្រាជ្ញាផ្លូវការនេះ យើងបណ្ដុះម៉ូដែលឲ្យទស្សនាពាក្យមួយពីបរិបទជុំវិញ។ ផ្តល់អោយ ngram $(W_{-2},W_{-1},W_0,W_1,W_2)$ គោលបំណងម៉ូដែលគឺទស្សនាពាក្យ $W_0$ ពី $(W_{-2},W_{-1},W_1,W_2)$។\n",
" - **Continuous skip-gram** គឺលើកលែងពី CBoW។ ម៉ូដែលប្រើបណ្តោយបរិបទវ៉ីនដូជុំវិញ ដើម្បីទស្សនាពាក្យបច្ចុប្បន្ន។\n",
"\n",
"CBoW ឆាប់រហ័ស ខណៈដែល skip-gram យឺតជាង ប៉ុន្តែប្រសើរជាងក្នុងការតំណាងពាក្យដែលមិនមានប្រជាជនច្រើន។\n",
"\n",
"![រូបភាពបង្ហាញអាល់ហ្គរីធึម CBoW និង Skip-Gram ដើម្បីបំលែងពាក្យទៅវ៉ិចទ័រ។](../../../../../translated_images/km/example-algorithms-for-converting-words-to-vectors.fbe9207a726922f6.webp)\n",
"\n",
"ដើម្បីសាកល្បង embedding word2vec ដែលបានបណ្ដុះរួចនៅលើឃ្លាំងទិន្នន័យ Google News អស់យើងអាចប្រើបណ្ណាល័យ **gensim** ។ ខាងក្រោម យើងស្វែងរកពាក្យដែលស្រដៀងគ្នាច្រើនជាងគេជាមួយពាក្យ 'neural'\n",
"\n",
"> **Note:** រស់រាន់ពេលអ្នកបង្កើតវ៉ិចទ័រពាក្យដំបូង ការទាញយកវានឹងចំណាយពេលខ្លះ!\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"import gensim.downloader as api\n",
"w2v = api.load('word2vec-google-news-300')"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"neuronal -> 0.7804799675941467\n",
"neurons -> 0.7326500415802002\n",
"neural_circuits -> 0.7252851724624634\n",
"neuron -> 0.7174385190010071\n",
"cortical -> 0.6941086649894714\n",
"brain_circuitry -> 0.6923246383666992\n",
"synaptic -> 0.6699118614196777\n",
"neural_circuitry -> 0.6638563275337219\n",
"neurochemical -> 0.6555314064025879\n",
"neuronal_activity -> 0.6531826257705688\n"
]
}
],
"source": [
"for w,p in w2v.most_similar('neural'):\n",
" print(f\"{w} -> {p}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"យើងអាចគណនាការតំណាងវ៉ែកទ័រពីពាក្យដើម្បីប្រើក្នុងការបណ្តុះមូឌែលចាត់ថ្នាក់ (យើងបង្ហាញតែ ២០ ធាតុដំបូងនៃវ៉ែកទ័រដើម្បីភាពច្បាស់):\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([ 0.01226807, 0.06225586, 0.10693359, 0.05810547, 0.23828125,\n",
" 0.03686523, 0.05151367, -0.20703125, 0.01989746, 0.10058594,\n",
" -0.03759766, -0.1015625 , -0.15820312, -0.08105469, -0.0390625 ,\n",
" -0.05053711, 0.16015625, 0.2578125 , 0.10058594, -0.25976562],\n",
" dtype=float32)"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"w2v.word_vec('play')[:20]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"រឿងល្អណាស់អំពីសេចក្តីចងក្រងសម្ភារៈន័យគឺអ្នកអាចត្រួតពិនិត្យកូដចុះបញ្ជីវ៉ិចទ័រដើម្បីផ្លាស់ប្តូរអត្ថន័យ។ ឧទាហរណ៍ យើងអាចស្នើសុំស្វែងរកពាក្យមួយដែលការតំនាងវ៉ិចទ័របស់វានឹងនៅជិតពាក្យ *king* និង *woman* ចំបង ហើយឆ្ងាយពីពាក្យ *man*៖\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"('queen', 0.7118192911148071)"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"w2v.most_similar(positive=['king','woman'],negative=['man'])[0]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ទាំង CBoW និង Skip-Grams ជា embedding ទាំងពីរដែល “ទាយ” គឺដោយពួកវាទទួលយកតែបរិបទក្នុងតំបន់ជិតៗ។ Word2Vec មិនប្រើប្រាស់អត្ថប្រយោជន៍ពីបរិបទសកលឡើយ។\n",
"\n",
"**FastText** សាងសង់លើ Word2Vec ដោយរៀនតំណាងវ៉ិកទ័រសម្រាប់ពាក្យនីមួយៗ និង n-gram តួអក្សរដែលមានក្នុងពាក្យនីមួយៗ។ តម្លៃនៃតំណាងទាំងនេះនឹងត្រូវបានរាប់បូកជាមធ្យមទៅវ៉ិកទ័រតែមួយនៅក្នុងជំហានបណ្តុះបណ្តាលមួយៗ។ បើទោះបីជាវានាំឲ្យមានការគណនាថែមទៀតច្រើនក្នុងការបណ្តុះបណ្តាលមុនក៏ដោយ វាអនុញ្ញាតឲ្យ embedding ពាក្យអាចបង្ហាញព័ត៌មានក្រោមពាក្យ។\n",
"\n",
"វិធីផ្សេងទៀត គឺ **GloVe** អនុវត្តគំនិតម៉ាត្រីសco-occurrence ហើយប្រើវិធីណឺរ៉ាល់ដើម្បីបំបែកម៉ាត្រីស co-occurrence ទៅជាវ៉ិកទ័រពាក្យដែលមានការបង្ហាញពត៌មានច្រើន និងមិនមែនជារូបមន្តលាញ់។\n",
"\n",
"អ្នកអាចលេងជាមួយឧទាហរណ៍ដោយផ្លាស់ប្តូរ embeddings ទៅជា FastText និង GloVe ព្រោះ gensim គាំទ្រម៉ូដែល embedding ពាក្យជាច្រើនផ្សេងទៀត។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ការប្រើប្រាស់ការកំណត់តម្លៃជាមុនក្នុង PyTorch\n",
"\n",
"យើងអាចកែប្រែឧទាហរណ៍ខាងលើដើម្បីបញ្ចូល matrix នៅលើស្រទាប់ embedding របស់យើងជាមុនជាមួយនឹងការកំណត់តម្លៃពាក្យដែលមានអត្ថន័យ ដូចជា Word2Vec។ យើងត្រូវគិតគូរថា និយមន័យនៃការកំណត់តម្លៃជាមុន និងអត្ថបទរបស់យើងប្រហែលជាមិនត្រូវគ្នា ដូច្នេះយើងនឹងផ្តាច់តម្លៃទម្លាក់សម្រាប់ពាក្យដែលខ្វះដោយតម្លៃចៃដន្យ:\n"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Embedding size: 300\n",
"Populating matrix, this will take some time...Done, found 41080 words, 54732 words missing\n"
]
}
],
"source": [
"embed_size = len(w2v.get_vector('hello'))\n",
"print(f'Embedding size: {embed_size}')\n",
"\n",
"net = EmbedClassifier(vocab_size,embed_size,len(classes))\n",
"\n",
"print('Populating matrix, this will take some time...',end='')\n",
"found, not_found = 0,0\n",
"for i,w in enumerate(vocab.get_itos()):\n",
" try:\n",
" net.embedding.weight[i].data = torch.tensor(w2v.get_vector(w))\n",
" found+=1\n",
" except:\n",
" net.embedding.weight[i].data = torch.normal(0.0,1.0,(embed_size,))\n",
" not_found+=1\n",
"\n",
"print(f\"Done, found {found} words, {not_found} words missing\")\n",
"net = net.to(device)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ឥឡូវនេះយើងចាប់ផ្តើមបណ្តុះម៉ូឌែលរបស់យើង។ សូមចំណាំថា ពេលវេលាដែលត្រូវការដើម្បីបណ្ដុះម៉ូឌែលនេះធ្វើបានយូរជាងឧទាហរណ៍មុនសម្រាប់ស្វ័យប្រវត្តន៍ធំជាងនេះហើយដែលមានប៉ារ៉ាម៉ែត្រច្រើនជាង។ ផងដែរ ដោយសារតែហេតុនេះ យើងប្រហែលជាត្រូវការបណ្តុះម៉ូឌែលរបស់យើងលើឧទាហរណ៍ច្រើនជាងនេះបើចង់ជៀសវាងការស្វ័យប្រវត្តិ។\n"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3200: acc=0.6359375\n",
"6400: acc=0.68109375\n",
"9600: acc=0.7067708333333333\n",
"12800: acc=0.723671875\n",
"16000: acc=0.73625\n",
"19200: acc=0.7463541666666667\n",
"22400: acc=0.7560714285714286\n"
]
},
{
"data": {
"text/plain": [
"(214.1013875559821, 0.7626759436980166)"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"train_epoch_emb(net,train_loader, lr=4, epoch_size=25000)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"នៅក្នុងករណីរបស់យើង យើងមិនឃើញការកើនឡើងយ៉ាងខ្លាំងនៅក្នុងភាពត្រឹមត្រូវទេ ដែលអាចជាសារជាផ្ទុយគ្នានៃវចនានុក្រម។ \n",
"ដើម្បីឆ្លើយតបទៅនឹងបញ្ហានៃវចនានុក្រមខុសគ្នា យើងអាចប្រើចំណុចដោះស្រាយដូចខាងក្រោមមួយ៖ \n",
"* ធ្វើការបណ្តុះបណ្តាលម៉ូដែល word2vec ម្តងទៀតលើវចនានុក្រមរបស់យើង \n",
"* ផ្ទុកទិន្នន័យរបស់យើងជាមួយវចនានុក្រមពីម៉ូដែល word2vec ដែលបានបណ្តុះបណ្តាលរួចហើយ។ វចនានុក្រមដែលប្រើសម្រាប់ផ្ទុកទិន្នន័យអាចកំណត់បាននៅពេលផ្ទុក។ \n",
"\n",
"វិធីសាស្រ្តចុងក្រោយមើលទៅងាយស្រួលជាងលើសពីព្រោះស៊ុម PyTorch `torchtext` មានការគាំទ្របង្កើត embeddings ជាផ្នែកមួយក្នុងខ្លួន។ យើងអាច ឧទាហរណ៍ បង្កើតវចនានុក្រមមានមូលដ្ឋានលើ GloVe ដូចខាងក្រោមនេះ៖\n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"100%|█████████▉| 399999/400000 [00:15<00:00, 25411.14it/s]\n"
]
}
],
"source": [
"vocab = torchtext.vocab.GloVe(name='6B', dim=50)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Loaded vocabulary has the following basic operations:\n",
"* `vocab.stoi` ឌិចសិនាឡរី អនុញ្ញាតឱ្យយើងបម្លែងពាក្យទៅជាអុិនដិចក្នុងឌិចសិនាឡរី\n",
"* `vocab.itos` ធ្វើការប្រែប្រួលផ្ទុយ - បម្លែងលេខទៅជាពាក្យ\n",
"* `vocab.vectors` គឺជាអារេនៃវ៉ិកទ័រអ៊ាំប៊ីឌិញ ដូច្នេះដើម្បីទទួលបានអ៊ាំប៊ីឌីងរបស់ពាក្យ `s` យើងត្រូវប្រើ `vocab.vectors[vocab.stoi[s]]`\n",
"\n",
"នេះគឺជាឧទាហរណ៍នៃការគ្រប់គ្រងអ៊ាំប៊ីឌីងដើម្បីបង្ហាញលើសមីការនេះ **kind-man+woman = queen** (ខ្ញុំបានកែប្រែសមាមាត្រតិចតួចដើម្បីឲ្យវាដំណើរការ):\n"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'queen'"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# get the vector corresponding to kind-man+woman\n",
"qvec = vocab.vectors[vocab.stoi['king']]-vocab.vectors[vocab.stoi['man']]+1.3*vocab.vectors[vocab.stoi['woman']]\n",
"# find the index of the closest embedding vector \n",
"d = torch.sum((vocab.vectors-qvec)**2,dim=1)\n",
"min_idx = torch.argmin(d)\n",
"# find the corresponding word\n",
"vocab.itos[min_idx]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ដើម្បីបណ្តុះបណ្តាលម៉ាស៊ីនចម្រាញ់ប្រភេទដោយប្រើ embeddings ទាំងនោះ សិនមុនយើងត្រូវបំលែងឱ្យប្រើពាក្យសម្គាល់ GloVe លើសំណុំទិន្នន័យរបស់យើង៖\n"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [],
"source": [
"def offsetify(b):\n",
" # first, compute data tensor from all sequences\n",
" x = [torch.tensor(encode(t[1],voc=vocab)) for t in b] # pass the instance of vocab to encode function!\n",
" # now, compute the offsets by accumulating the tensor of sequence lengths\n",
" o = [0] + [len(t) for t in x]\n",
" o = torch.tensor(o[:-1]).cumsum(dim=0)\n",
" return ( \n",
" torch.LongTensor([t[0]-1 for t in b]), # labels\n",
" torch.cat(x), # text \n",
" o\n",
" )"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ដូចដែលយើងបានឃើញខាងលើ វិកទ័រសម្រាប់បញ្ចូលទាំងអស់ត្រូវបានផ្ទុកនៅក្នុងម៉ាទ្រីស `vocab.vectors`។ វាធ្វើឲ្យមានភាពងាយស្រួលយ៉ាងខ្លាំងក្នុងការបញ្ចូលទំងន់ទាំងនោះទៅក្នុងទម្រង់ទំងន់នៃស្រទាប់ embedding ដោយប្រើការចម្លងធម្មតា៖\n"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
"net = EmbedClassifier(len(vocab),len(vocab.vectors[0]),len(classes))\n",
"net.embedding.weight.data = vocab.vectors\n",
"net = net.to(device)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ឥឡូវនេះរួចដំណើរការបណ្ដុះបណ្ដាលម៉ូដែលរបស់យើង ហើយមើលថាតើយើងទទួលបានលទ្ធផលកាន់តែល្អឬយ៉ាងដូចម្តេច៖\n"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3200: acc=0.6271875\n",
"6400: acc=0.68078125\n",
"9600: acc=0.7030208333333333\n",
"12800: acc=0.71984375\n",
"16000: acc=0.7346875\n",
"19200: acc=0.7455729166666667\n",
"22400: acc=0.7529464285714286\n"
]
},
{
"data": {
"text/plain": [
"(35.53972978646833, 0.7575175943698017)"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=16, collate_fn=offsetify, shuffle=True)\n",
"train_epoch_emb(net,train_loader, lr=4, epoch_size=25000)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"មួយក្នុងចំណោមហេតុផលដែលយើងមិនឃើញការកើនឡើងយ៉ាងសំខាន់នៃភាពទាន់សម័យគឺដោយសារតែកម្រិតពាក្យខ្លះពីទិន្នន័យរបស់យើងបានបាត់បង់ក្នុងវាក្យសព្ទ GloVe ដែលបានបណ្តុះមុន ហើយដូច្នេះពួកវាត្រូវបានរំលងផ្តាច់។ ដើម្បីទ្រាក់ទ្រង់លើការពិតនេះ យើងអាចបណ្តុះ embeddings ផ្ទាល់ខ្លួនលើទិន្នន័យរបស់យើងបាន។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Contextual Embeddings\n",
"\n",
"ការពេញលេញចម្បងមួយនៃតំណាងការជួសជុលពីមុនដែលមានសមត្ថភាពនៃ pretrained embedding representations ដូចជា Word2Vec គឺបញ្ហានៃការប្រែប្រួលអត្ថន័យពាក្យ។ នៅពេល pretrained embeddings អាចចាប់យកអត្ថន័យខ្លះៗនៃពាក្យនៅក្នុងបរិបទជាមួយ ក៏ប៉ុន្តែអត្ថន័យដែលអាចមានទាំងអស់របស់ពាក្យត្រូវបានអចិន្រ្ត័យទៅក្នុង embedding ដូចគ្នា។ វាអាចបង្កើតបញ្ហាក្នុងម៉ូដែលក្រោយ, ពោលគឺពាក្យជាច្រើនដូចជា ពាក្យ 'play' មានអត្ថន័យខុសគ្នាច្រើនអាស្រ័យលើបរិបទដែលពួកវាត្រូវបានប្រើ។\n",
"\n",
"ឧទាហរណ៍ ពាក្យ 'play' នៅក្នុងប្រយោគទាំងពីរនោះមានអត្ថន័យខុសគ្នាក្រោមមួយ:\n",
"- ខ្ញុំបានទៅបង្ហាញ **play** នៅលើឆាកតេអាទឺរ។\n",
"- John ចង់ **play** ជាមួយមិត្តភក្តិរបស់គាត់។\n",
"\n",
"pretrained embeddings នៅលើនេះតំណាងឲ្យទាំងពីរអត្ថន័យនៃពាក្យ 'play' នៅក្នុង embedding ដូចគ្នា។ ដើម្បីដោះស្រាយកំណត់នេះ, យើងត្រូវតែបង្កើត embeddings បញ្ជាក់លើជារបៀប **language model**, ដែលបានបណ្តុះបណ្តាលលើនិទស្សន៍ធំមួយនៃអត្ថបទ ហើយ*ដឹង*ថាពាក្យអាចត្រូវបានដាក់ជាមួយគ្នា​របៀបខុសៗគ្នា​នៅក្នុងបរិបទផ្សេងៗ។ ការពិភាក្សាពី contextual embeddings គឺក្រៅប្រធានបទសម្រាប់ មេរៀននេះ ប៉ុន្តែយើងនឹងត្រឡប់មកមើលពួកវាទៀតនៅពេលនិយាយអំពី language models ក្នុងឯកត្តបន្ទាប់។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**ការព្រមាន**៖\nឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេលយើងព្យាយាមរក្សាការពិតច្បាស់ សូមយល់ឲ្យបានថាការបកប្រែដោយស្វ័យប្រវត្តិសាច់បាច់អាចមានកំហុស ឬការមិនត្រឹមត្រូវនៅខ្លះ។ ឯកសារដើមដែលមានភាសាដើមគួរត្រូវបានគិតថាជាធនធានផ្លូវការជាចម្បង។ សម្រាប់ព័ត៌មានសំខាន់ ការបកប្រែដោយមនុស្សជំនាញត្រូវបានផ្តល់អាទិភាព។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបំភ្លឺខុសចេញពីការប្រើប្រាស់ការបកប្រែនេះឡើយ។\n<!-- CO-OP TRANSLATOR DISCLAIMER END -->\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "0cb620c6d4b9f7a635928804c26cf22403d89d98d79684e4529119355ee6d5a5"
},
"kernelspec": {
"display_name": "py37_pytorch",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.12"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@ -0,0 +1,691 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ការបញ្ចូល (Embeddings)\n",
"\n",
"នៅក្នុងឧទាហរណ៍មុនរបស់យើង យើងបានដំណើរការលើវ៉ិកទ័រកញ្ចប់ពាក្យដែលមានវិមាត្រខ្ពស់ជាមួយប្រវែង `vocab_size` ហើយយើងបានបម្លែងយ៉ាងច្បាស់លាស់ពីវ៉ិកទ័រតំណាងទីតាំងវិមាត្រទាបទៅជាការតំណាង one-hot ដែលមានភាពរាយស្រឡាយ។ ការតំណាង one-hot នេះមិនប្រសើរដល់មេម៉ូរីទេ។ លើសពីនេះទៀត ពាក្យនីមួយៗត្រូវបានគេព្យាយាមឲ្យមានភាពឯករាជ្យពីគ្នា ដូច្នេះវ៉ិកទ័រដែលបាន encode ជា one-hot មិនបង្ហាញអត្ថន័យស្រដៀងគ្នារវាងពាក្យទេ។\n",
"\n",
"នៅក្នុងឯកតានេះ យើងនឹងបន្តស្វែងយល់អំពីទិន្នន័យ **News AG**។ ដើម្បីចាប់ផ្តើម ចូរយើងផ្ទុកទិន្នន័យ ហើយយកនិយមន័យខ្លះៗពីឯកតាមុន។\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import tensorflow as tf\n",
"from tensorflow import keras\n",
"import tensorflow_datasets as tfds\n",
"import numpy as np\n",
"\n",
"ds_train, ds_test = tfds.load('ag_news_subset').values()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### embedding គឺជាអ្វី?\n",
"\n",
"គំនិតនៃ **embedding** គឺដើម្បីតំណាងឱ្យពាក្យដោយប្រើវ៉ិចទ័រចំនួនតិចដែលមានមាតិកាត្រូវគ្នានឹង អត្ថបទនៃពាក្យនោះ។ យើងនឹងពិភាក្សាថាតើធ្វើដើម្បីបង្កើត embedding ដែលមានន័យយ៉ាងដូចម្តេច ប៉ុន្តេលៅពេលនេះ មកគិតថា embedding គឺជា វិធីសាស្រ្តមួយសម្រាប់កាត់បន្ថយវិមាត្ររបស់វ៉ិចទ័រពាក្យ។\n",
"\n",
"ដូចនេះ ស្រទាប់ embedding នេះទទួលពាក្យជាអញ្ញាត និងបង្កើតវ៉ិចទ័រចេញដែលមានវិមាត្រត្រូវបានបញ្ជាក់ដោយ `embedding_size`។ មានន័យថា វាស្រដៀងនឹងស្រទាប់ `Dense` មួយ ប៉ុន្តែប្ដូរពីការទទួលវ៉ិចទ័រចែកបែប one-hot encoded ជា ចំនួនពាក្យ។\n",
"\n",
"ដោយប្រើស្រទាប់ embedding ជាស្រទាប់ដំបូងក្នុងបណ្តាញរបស់យើង យើងអាចប្ដូរពី bag-of-words ទៅម៉ូដែល **embedding bag** ដែលយើងចាប់ផ្តើមផ្លាស់ប្ដូរពីពាក្យនីមួយៗទៅ embedding ផ្ទាល់ខ្លួន រួចបញ្ចូលករណីហាងសម្រាប់ embed ផ្សេងៗទាំងអស់ ឧទាហរណ៍ `sum`, `average` ឬ `max`។\n",
"\n",
"![រូបភាពបង្ហាញពី embedding classifier សម្រាប់ ពាក្យលំដាប់ប្រាំ។](../../../../../translated_images/km/embedding-classifier-example.b77f021a7ee67eee.webp)\n",
"\n",
"បណ្តាញសរសេរ neural network របស់យើងមានស្រទាប់ដូចខាងក្រោម៖\n",
"\n",
"* ស្រទាប់ `TextVectorization` ដែលទទួលខ្សែអក្សរជាអញ្ញាត ហើយបង្កើត tensor នៃលេខ​តំណាង​ពាក្យ។ យើងនឹងបញ្ជាក់ទំហំវាកប៊ូលារីវិធីសាស្រ្តមួយ `vocab_size` ហើយមិនបញ្ជូនពាក្យដែលប្រើប្រាស់តិចតួច។ ទម្រង់ input នឹងមានទំហំនៅ 1 ហើយទម្រង់ output នឹងមានទំហំ $n$ ពីព្រោះយើងនឹងទទួលបាន $n$ token ក្នុងលទ្ធផល ដែលមួយក្នុងនោះមានលេខពី 0 រហូតដល់ `vocab_size`។\n",
"* ស្រទាប់ `Embedding` ដែលទទួលលេខ $n$ ហើយបញ្ជ្រាបលេខនីមួយៗទៅជាវ៉ិចទ័រចម្បងដែលមានប្រវែងបញ្ជាក់ (100 ក្នុងឧទាហរណ៍របស់យើង)។ ដូច្នេះ tensor input ដែលមានទំហំ $n$ នឹងបំលែងទៅជា tensor ទំហំ $n\\times 100$។\n",
"* ស្រទាប់ aggregation ដែលគណនាមធ្យមនៃ tensor នេះរង្វង់ឯកតាដំបូង គឺវានឹងគណនាមធ្យមនៃពាក្យទាំងអស់ $n$ ទៅជាតិចុងក្រោយ។ ដើម្បីអនុវត្តស្រទាប់នេះ យើងនឹងប្រើស្រទាប់ `Lambda` ហើយផ្ទុកមុខងារ ដែលគណនាមធ្យម។ អ្នកនឹងបាន output ទំហំ 100 ដែលជាតំណាងលេខសំរាប់ភាគីសរុបនៃរៀងក្នុង input ទាំងមូល។\n",
"* ស្រទាប់ចុងក្រោយ `Dense` classifier រូបភាព linear។\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"sequential\"\n",
"_________________________________________________________________\n",
" Layer (type) Output Shape Param # \n",
"=================================================================\n",
" text_vectorization (TextVec (None, None) 0 \n",
" torization) \n",
" \n",
" embedding (Embedding) (None, None, 100) 3000000 \n",
" \n",
" lambda (Lambda) (None, 100) 0 \n",
" \n",
" dense (Dense) (None, 4) 404 \n",
" \n",
"=================================================================\n",
"Total params: 3,000,404\n",
"Trainable params: 3,000,404\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n"
]
}
],
"source": [
"vocab_size = 30000\n",
"batch_size = 128\n",
"\n",
"vectorizer = keras.layers.experimental.preprocessing.TextVectorization(max_tokens=vocab_size,input_shape=(1,))\n",
"\n",
"model = keras.models.Sequential([\n",
" vectorizer, \n",
" keras.layers.Embedding(vocab_size,100),\n",
" keras.layers.Lambda(lambda x: tf.reduce_mean(x,axis=1)),\n",
" keras.layers.Dense(4, activation='softmax')\n",
"])\n",
"model.summary()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"នៅក្នុងការបោះពុម្ព `summary` នៅជួរឈរដែលមាន **output shape** កម្រិត tensor ដំបូង `None` បណ្ដាប់ទៅនឹងទំហំ minibatch ហើយកម្រិតទីពីរបណ្ដាប់ទៅនឹងប្រវែងនៃលំដាប់ token ។ លំដាប់ token ទាំងអស់ក្នុង minibatch មានប្រវែងខុសគ្នា។ យើងនឹងពិភាក្សា​អំពីវិធីដោះស្រាយវា​នៅក្នុងផ្នែកបន្ទាប់។\n",
"\n",
"ឥឡូវនេះយើងមកហ្វឹកហាត់បណ្ដាញ៖\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Training vectorizer\n",
"938/938 [==============================] - 20s 20ms/step - loss: 0.7891 - acc: 0.8155 - val_loss: 0.4470 - val_acc: 0.8642\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x22255515100>"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def extract_text(x):\n",
" return x['title']+' '+x['description']\n",
"\n",
"def tupelize(x):\n",
" return (extract_text(x),x['label'])\n",
"\n",
"print(\"Training vectorizer\")\n",
"vectorizer.adapt(ds_train.take(500).map(extract_text))\n",
"\n",
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'])\n",
"model.fit(ds_train.map(tupelize).batch(batch_size),validation_data=ds_test.map(tupelize).batch(batch_size))"
]
},
{
"cell_type": "markdown",
"metadata": {
"nteract": {
"transient": {
"deleting": false
}
}
},
"source": [
"> **សម្គាល់** ថា​យើងកំពុងបង្កើតម៉ូឌែលវ៉ិចទ័រជាមួយនឹងទិន្នន័យជាផ្នែកមួយ។ វាត្រូវបានធ្វើឡើងដើម្បីបន្ថែមល្បឿនដំណើរការ ហើយវាអាចនាំឲ្យមានស្ថានភាពដែលមិនមានតួអក្សរទាំងអស់ពីអត្ថបទរបស់យើងក្នុងវាគាគារទេ។ ក្នុងករណីនេះ តួអក្សរទាំងនោះនឹងត្រូវបានមិនគិតជាប់ណាមួយ ដែលអាចនាំឲ្យមានភាពត្រឹមត្រូវតិចតួចទាបជាងមុន។ ទោះជាយ៉ាងណា នៅក្នុងជីវិតពិត ផ្នែកមួយនៃអត្ថបទភាគច្រើនផ្តល់នូវការប៉ាន់ប្រមាណវាគាគារដែលល្អ។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### ដោះស្រាយទំហំតួអក្សរបម្រែបម្រួល\n",
"\n",
"យើងមកយល់ពីរបៀបដែលការបណ្តុះបណ្តាលកើតឡើងក្នុង minibatches។ ក្នុងឧទាហរណ៍ខាងលើ, តួអង់ត្រីមានវិមាត្រតែមួយ, ហើយយើងប្រើ minibatches យ៉ាងយឺត 128 ដូច្នេះទំហំពិតនៃតួអង់ត្រាជា $128 \\times 1$។ ទោះបីជារួចហើយ, ចំនួនតួអក្សរនៅក្នុងប្រយោគនីមួយៗគឺខុសគ្នា។ ប្រសិនបើយើងអនុវត្តស្រទាប់ `TextVectorization` ទៅលើបញ្ចូលតែមួយ, ចំនួនតួអក្សរដែលត្រូវបានត្រឡប់មកនឹងខុសគ្នា, អាស្រ័យទៅលើរបៀបដែលអត្ថបទត្រូវបានបំបែកតួអក្សរ៖\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"tf.Tensor([ 1 45], shape=(2,), dtype=int64)\n",
"tf.Tensor([ 112 1271 1 3 1747 158], shape=(6,), dtype=int64)\n"
]
}
],
"source": [
"print(vectorizer('Hello, world!'))\n",
"print(vectorizer('I am glad to meet you!'))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"យ៉ាងไรก็ตาม ពេលយើងអនុវត្តកម្មវិធីវ៉ិចទ័រជូនលំដាប់ច្រើន វាត្រូវតែបង្កើតទិន្ស័រដែលមានរូបរាងជា​មូរដេដែក ដូច្នេះវាបំពេញធាតុដែលមិនបានប្រើដោយស្លាក PAD (ដែលក្នុងករណីរបស់យើងគឺលេខសូន្យ):\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<tf.Tensor: shape=(2, 6), dtype=int64, numpy=\n",
"array([[ 1, 45, 0, 0, 0, 0],\n",
" [ 112, 1271, 1, 3, 1747, 158]], dtype=int64)>"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"vectorizer(['Hello, world!','I am glad to meet you!'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"នៅទីនេះ​យើង​អាច​មើលឃើញ​ការ​បញ្ចូលៈ\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([[[ 1.53059261e-02, 6.80514947e-02, 3.14026810e-02, ...,\n",
" -8.92002955e-02, 1.52911525e-04, -5.65562584e-02],\n",
" [ 2.57456154e-01, 2.79364467e-01, -2.03605562e-01, ...,\n",
" -2.07474351e-01, 8.31158683e-02, -2.03911960e-01],\n",
" [ 3.98201384e-02, -8.03454965e-03, 2.39790026e-02, ...,\n",
" -7.18549127e-04, 2.66963355e-02, -4.30646613e-02],\n",
" [ 3.98201384e-02, -8.03454965e-03, 2.39790026e-02, ...,\n",
" -7.18549127e-04, 2.66963355e-02, -4.30646613e-02],\n",
" [ 3.98201384e-02, -8.03454965e-03, 2.39790026e-02, ...,\n",
" -7.18549127e-04, 2.66963355e-02, -4.30646613e-02],\n",
" [ 3.98201384e-02, -8.03454965e-03, 2.39790026e-02, ...,\n",
" -7.18549127e-04, 2.66963355e-02, -4.30646613e-02]],\n",
"\n",
" [[ 1.89674050e-01, 2.61548996e-01, -3.67433839e-02, ...,\n",
" -2.07366899e-01, -1.05442435e-01, -2.36952081e-01],\n",
" [ 6.16133213e-02, 1.80511594e-01, 9.77298319e-02, ...,\n",
" -5.46628237e-02, -1.07340455e-01, -1.06589928e-01],\n",
" [ 1.53059261e-02, 6.80514947e-02, 3.14026810e-02, ...,\n",
" -8.92002955e-02, 1.52911525e-04, -5.65562584e-02],\n",
" [-4.84890305e-02, -8.41715634e-02, 1.51529670e-01, ...,\n",
" 1.28192469e-01, -7.77286515e-02, 1.26041949e-01],\n",
" [-4.17212099e-02, -5.60694858e-02, 4.08860669e-02, ...,\n",
" 8.70475471e-02, 8.92383084e-02, 1.67974353e-01],\n",
" [ 2.85779923e-01, 4.57767487e-01, 4.52292450e-02, ...,\n",
" -1.97419018e-01, -2.04659685e-01, -2.79758364e-01]]],\n",
" dtype=float32)"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model.layers[1](vectorizer(['Hello, world!','I am glad to meet you!'])).numpy()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **កំណត់ចំណាំ**: ដើម្បីកាត់បន្ថយបរិមាណ padding ឲ្យតិចបំផុត នៅក្នុងករណីខ្លះវាមានហេតុផលក្នុងការរៀបចំលំដាប់រាល់លំដាប់ក្នុងប្រមូលទិន្នន័យទៅតាមលំដាប់កើនឡើងនៃកាំង (ឬ ផ្ទាល់ខ្លួន គឺចំនួននៃតូកិន)។ នេះនឹងធានាថា មីនីបៀចនីមួយៗមានលំដាប់ដែលមានប្រវែងស្រដៀងគ្នា។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Semantic embeddings: Word2Vec\n",
"\n",
"ក្នុងឧទាហរណ៍មុនរបស់យើង ស្រទាប់ embedding យល់ដឹងត្រួតពិនិត្យដើម្បីផែនទីពាក្យទៅតំណាងវ៉ិចទ័រប៉ុន្តែ តំណាងទាំងនេះគ្មានអត្ថន័យសម្របសម្រួលទេ។ វានឹងមានប្រយោជន៍សម្រាប់រៀនតំណាងវ៉ិចទ័រដែលយ៉ាងណាក៏ដោយពាក្យស្រដៀងគ្នា ឬពាក្យប្រើប្រាស់ជំនួសគ្នា ត្រូវតែផ្គូផ្គងទៅនឹងវ៉ិចទ័រដែលនៅជិតគ្នានៅលើបាតុភូតវ៉ិចទ័រខ្លះ (ឧទាហរណ៍ចំរូងអ៊ុយកីឡេដៀន)។\n",
"\n",
"ដើម្បីធ្វើការនេះ យើងចាំបាច់ត្រូវ pretrained ម៉ូដែល embedding របស់យើងលើកំណត់ត្រាអត្ថបទដែលធំជាងគេដោយប្រើបច្ចេកទេសដូចជា [Word2Vec](https://en.wikipedia.org/wiki/Word2vec)។ វាមានមូលដ្ឋានលើស្ថាបត្យកម្មសំខាន់ពីរ ដែលត្រូវបានប្រើក្នុងការផលិតតំណាងចែកចាយនៃពាក្យ៖\n",
"\n",
" - **Continuous bag-of-words** (CBoW) ដែលយើងបណ្តុះម៉ូដែលដើម្បីបញ្ជាក់ទោលពាក្យមួយពីបរិបទជុំវិញ។ បើដាក់ ngram $(W_{-2},W_{-1},W_0,W_1,W_2)$ គោលបំណងម៉ូដែលគឺបញ្ជាក់ទោល $W_0$ ពី $(W_{-2},W_{-1},W_1,W_2)$។\n",
" - **Continuous skip-gram** គឺអាចវិជ្ជមាន CBoW។ ម៉ូដែលប្រើបរិបទជុំវិញនៃពាក្យបរិបទ ដើម្បីបញ្ជាក់ទោលពាក្យបច្ចុប្បន្ន។\n",
"\n",
"CBoW លឿនជាង ហើយបើទោះបីជា skip-gram ជាប្រភេទយឺតជាងក៏ដោយ វាដំណើរការល្អជាងក្នុងការបង្ហាញពាក្យដែលតិចធ្លាប់ប្រើ។\n",
"\n",
"![រូបភាពបង្ហាញពីអាល់ក្គរីធម៍ CBoW និង Skip-Gram ដើម្បីបម្លែងពាក្យទៅជាវ៉ិចទ័រ។](../../../../../translated_images/km/example-algorithms-for-converting-words-to-vectors.fbe9207a726922f6.webp)\n",
"\n",
"ដើម្បីសាកល្បងជាមួយ embedding Word2Vec ដែលបាន pretrained លើកំណត់ត្រា Google News dataset យើងអាចប្រើបណ្ណាល័យ **gensim**។ ខាងក្រោមយើងស្វែងរកពាក្យដែលស្រដៀងគ្នាមានអ្នកទំនងជាមួយពាក្យ 'neural'។\n",
"\n",
"> **Note:** នៅពេលអ្នកបង្កើតវ៉ិចទ័រពាក្យលើកដំបូង ការទាញយកវាអាចចំណាយពេលខ្លះ!\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"import gensim.downloader as api\n",
"w2v = api.load('word2vec-google-news-300')"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"neuronal -> 0.7804799675941467\n",
"neurons -> 0.7326500415802002\n",
"neural_circuits -> 0.7252851724624634\n",
"neuron -> 0.7174385190010071\n",
"cortical -> 0.6941086649894714\n",
"brain_circuitry -> 0.6923246383666992\n",
"synaptic -> 0.6699118614196777\n",
"neural_circuitry -> 0.6638563275337219\n",
"neurochemical -> 0.6555314064025879\n",
"neuronal_activity -> 0.6531826257705688\n"
]
}
],
"source": [
"for w,p in w2v.most_similar('neural'):\n",
" print(f\"{w} -> {p}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"យើងអាចដកចេញបេក្ខវិស័យវ៉ិចទ័រពីពាក្យ ផងដែរ ដើម្បីប្រើប្រាស់ក្នុងការបណ្តុះម៉ូដែលចំណាត់ថ្នាក់។ បេក្ខវិស័យមានបន្ទុក ៣០០ ប្រភេទ ប៉ុន្តែក្នុងនេះយើងបង្ហាញតែក្នុង ២០ ប្រភេទដំបូងនៃវ៉ិចទ័រដែលមានភាពច្បាស់៖\n"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([ 0.01226807, 0.06225586, 0.10693359, 0.05810547, 0.23828125,\n",
" 0.03686523, 0.05151367, -0.20703125, 0.01989746, 0.10058594,\n",
" -0.03759766, -0.1015625 , -0.15820312, -0.08105469, -0.0390625 ,\n",
" -0.05053711, 0.16015625, 0.2578125 , 0.10058594, -0.25976562],\n",
" dtype=float32)"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"w2v['play'][:20]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"រឿងដ៏អស្ចារ្យអំពីការ​អញ្ចូលទិន្នន័យ​អត្ថន័យ​គឺ​អ្នកអាច​ត្រួតពិនិត្យ​កូដ​វ៉ិកទ័រ​ដោយផ្អែក​លើ​អត្ថន័យ​បាន។ ឧទាហរណ៍ យើង​អាចសួរឱ្យ​រកពាក្យ​មួយដែល​គំនូសវ៉ិកទ័រ​របស់វា​នៅជិត​បំផុត​នឹងពាក្យ *king* និង *woman* ហើយ​នៅឆ្ងាយ​បំផុត​ពីពាក្យ *man*៖\n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"('queen', 0.7118192911148071)"
]
},
"execution_count": 14,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"w2v.most_similar(positive=['king','woman'],negative=['man'])[0]"
]
},
{
"cell_type": "markdown",
"metadata": {
"tags": []
},
"source": [
"ឧទាហរណ៍ខាងលើប្រើមន្តសិទ្ធិ GenSym ខ្លះៗ ប៉ុន្តែលទ្ធផលមួយដែលជាចម្បងគឺសាមញ្ញណាស់។ រឿងចម្លែកមួយអំពី embeddings គឺអ្នកអាចអនុវត្តប្រតិបត្តិការវ៉ិចទ័រធម្មតានៅលើវ៉ិចទ័រនៃ embeddings ហើយវានឹងបញ្ចេញនូវប្រតិបត្តិការលើ **អត្ថន័យ** ពាក្យ។ ឧទាហរណ៍ខាងលើអាចបង្ហាញជាទម្រង់ប្រតិបត្តិការវ៉ិចទ័រ៖ យើងគណនាវ៉ិចទ័រនៃពាក្យដែលសមរម្យនឹង **KING-MAN+WOMAN** (ប្រតិបត្តិការនៃ `+` និង `-` ត្រូវបានអនុវត្តលើតំណាងវ៉ិចទ័រនៃពាក្យដែលសមរម្យ) ហើយបន្ទាប់មកស្វែងរកពាក្យដែលនៅជិតបំផុតនៅក្នុងវចនានុក្រមទៅវ៉ិចទ័រនោះ៖\n"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'queen'"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# get the vector corresponding to kind-man+woman\n",
"qvec = w2v['king']-1.7*w2v['man']+1.7*w2v['woman']\n",
"# find the index of the closest embedding vector \n",
"d = np.sum((w2v.vectors-qvec)**2,axis=1)\n",
"min_idx = np.argmin(d)\n",
"# find the corresponding word\n",
"w2v.index_to_key[min_idx]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **ចំណាំ**៖ យើងត្រូវបានបន្ថែមអនុគ្រោះតូចៗទៅកន្លែងវ៉ិកទ័រ *man* និង *woman* - ព្យាយាមដកវាចេញដើម្បីមើលថាអ្វីបានកើតឡើង។\n",
"\n",
"ដើម្បីស្វែងរកវ៉ិកទ័រតំបន់ក្បាលបំផុត យើងប្រើ ឧបករណ៍ TensorFlow ដើម្បីគណនាវ៉ិកទ័ររបស់ចម្ងាយរវាងវ៉ិកទ័ររបស់យើងនិងវ៉ិកទ័រទាំងអស់នៅក្នុងពាក្យសព្ទ ហើយបន្ទាប់មកស្វែងរកសន្ទស្សន៍នៃពាក្យតូចបំផុតដោយប្រើ `argmin`។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ខណៈពេល Word2Vec ดูเหมือนจะเป็นវិធីដ៏អស្ចារ្យសម្រាប់បង្ហាញអត្ថន័យពាក្យ វាមានគុណវិបត្តិជាច្រើន រួមមាន៖\n",
"\n",
"* ទាំងពីរម៉ូដែល CBoW និង skip-gram គឺជាការបញ្ចាក់អembedding **predictive embeddings** ហើយវាទទួលយកតែបរិបទក្នុងសហគមន៍បន្តិចបន្តួចប៉ុណ្ណោះ។ Word2Vec មិនយកប្រយោជន៍ពីបរិបទជាសកលនោះទេ។\n",
"* Word2Vec មិនគិតពីរាងកាយពាក្យ **morphology** គឺ ន័យថា អត្ថន័យនៃពាក្យអាចអាស្រ័យលើផ្នែកផ្សេងៗនៃពាក្យ ដូចជាមูลដ្ពៃ។\n",
"\n",
"**FastText** ព្យាយាមដោះស្រាយលំដាប់ទីពីរនេះ ហើយបន្ថែមលើ Word2Vec ដោយរៀនវ៉ិចទ័រដែលតំណាងឲ្យដល់ពាក្យនីមួយៗ និងអក្សរ n-gram ដែលត្រូវបានរកឃើញក្នុងពាក្យនីមួយៗ។ តម្លៃនៃការតំណាងទាំងនេះបន្ទាប់មកត្រូវបានរាប់មធ្យមទៅជា​វ៉ិចទ័រមួយនៅក្នុងជំហានបណ្ដុះបណ្ដាលរៀងរាល់ដង។ ខណៈដែលនេះបន្ថែមកំណត់ឡើងនៃការគណនា​ក្នុងការបណ្ដុះបណ្ដាលជាមុន វាក៏អាចអោយ​ word embeddings ចាប់យកព័ត៌មានក្រោមពាក្យបាន។\n",
"\n",
"វិធីមួយផ្សេងទៀត គឺ **GloVe** ដែលប្រើវិធីផ្សេងទៀតសម្រាប់ word embeddings ដោយផ្អែកលើការបែងចែកម៉ាទ្រីសពាក្យ-បរិបទ។ ជាដំបូង វាសង់ម៉ាទ្រីសដ៏ធំបូកនឹងរាប់ចំនួនករណី​ពីពាក្យក្នុងបរិបទផ្សេងៗ ហើយបន្ទាប់មកវាព្យាយាមតំណាងម៉ាទ្រីសនេះជាទំហំតិចដើម្បីបន្ថយការបាត់បង់ក្នុងការបង្កើតឡើងវិញ។\n",
"\n",
"បណ្ណាល័យ gensim គាំទ្រនូវ word embeddings ទាំងនេះ ហើយអ្នកអាចសាកល្បងជាមួយពួកវា​ដោយផ្លាស់ប្តូរកូដផ្ទុកម៉ូដែលខាងលើ។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ការប្រើប្រាស់ embeddings ដែលបានបណ្តុះបណ្តាលរួចហើយនៅក្នុង Keras\n",
"\n",
"យើងអាចកែប្រែឧទាហរណ៍ខាងលើ ដើម្បីបំពេញមាត្រដ្ឋានក្នុងស្រទាប់ embedding របស់យើងជាមុនជាមួយ embedding ផ្នែកអត្ថន័យ ដូចជា Word2Vec។ ពាក្យសម្ព័ន្ធនៃ embedding ដែលបានបណ្តុះបណ្តាលរួច និងអត្ថបទខុនតាក់ស៍ មានសក្តានុពលដែលមិនត្រូវគ្នា ដូច្នេះយើងត្រូវជ្រើសរើសមួយ។ នៅទីនេះ យើងស្វែងយល់ពីជម្រើសពីរដែលអាចធ្វើបាន៖ ការប្រើប្រាស់ពាក្យសម្ព័ន្ធ tokenizer និងការប្រើប្រាស់ពាក្យសម្ព័ន្ធពី embedding Word2Vec។\n",
"\n",
"### ការប្រើប្រាស់ពាក្យសម្ព័ន្ធ tokenizer\n",
"\n",
"ពេលប្រើប្រាស់ពាក្យសម្ព័ន្ធ tokenizer ពាក្យខ្លះពីពាក្យសម្ព័ន្ធនឹងមាន embedding Word2Vec ត្រូវគ្នា ហើយពាក្យខ្លះនឹងអាចបាត់បង់។ ដោយសារតែទំហំពាក្យសម្ព័ន្ធរបស់យើងគឺ `vocab_size` និងប្រវែងវ៉ិចទ័រ embedding របស់ Word2Vec គឺ `embed_size` ស្រទាប់ embedding នឹងត្រូវតំណាងដោយមាត្រដ្ឋានទំរង់ `vocab_size`$\\times$`embed_size`។ យើងនឹងបំពេញមាត្រដ្ឋាននេះដោយឆ្លងកាត់ពាក្យសម្ព័ន្ធ៖\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"tags": []
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Embedding size: 300\n",
"Populating matrix, this will take some time...Done, found 4551 words, 784 words missing\n"
]
}
],
"source": [
"embed_size = len(w2v.get_vector('hello'))\n",
"print(f'Embedding size: {embed_size}')\n",
"\n",
"vocab = vectorizer.get_vocabulary()\n",
"W = np.zeros((vocab_size,embed_size))\n",
"print('Populating matrix, this will take some time...',end='')\n",
"found, not_found = 0,0\n",
"for i,w in enumerate(vocab):\n",
" try:\n",
" W[i] = w2v.get_vector(w)\n",
" found+=1\n",
" except:\n",
" # W[i] = np.random.normal(0.0,0.3,size=(embed_size,))\n",
" not_found+=1\n",
"\n",
"print(f\"Done, found {found} words, {not_found} words missing\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"សម្រាប់ពាក្យដែលមិនមាននៅក្នុងវចនានុក្រម Word2Vec យើងអាចទុកវាជា សូន្យ ឬបង្កើតវ៉ិចទ័រដោយចៃដន្យ។\n",
"\n",
"ឥឡូវនេះយើងអាចកំណត់ស្រទាប់ embedding មួយជាមួយទំងន់ដែលបានបណ្តុះរួចហើយ៖\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"emb = keras.layers.Embedding(vocab_size,embed_size,weights=[W],trainable=False)\n",
"model = keras.models.Sequential([\n",
" vectorizer, emb,\n",
" keras.layers.Lambda(lambda x: tf.reduce_mean(x,axis=1)),\n",
" keras.layers.Dense(4, activation='softmax')\n",
"])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ឥឡូវនេះ យើងមកបណ្តុះបណ្តាលម៉ូឌែលរបស់យើង។\n"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"938/938 [==============================] - 10s 10ms/step - loss: 1.1075 - acc: 0.7822 - val_loss: 0.9134 - val_acc: 0.8175\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x2220226ef10>"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'])\n",
"model.fit(ds_train.map(tupelize).batch(batch_size),\n",
" validation_data=ds_test.map(tupelize).batch(batch_size))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **សម្គាល់**: សូមកត់សម្គាល់ថា យើងកំណត់ `trainable=False` នៅពេលបង្កើត `Embedding` ដែលមានន័យថាយើងមិនបណ្តុះបណ្តាលឡើងវិញស្រទាប់ Embedding នោះទេ។ វាអាចបណ្តាលអោយកម្រិតទំនាក់ទំនងក័រម្លិចបន្តិច ប៉ុន្តែវា прискорює​ ការបណ្តុះបណ្តាល។\n",
"\n",
"### ការប្រើប្រាស់វចនានុក្រម embedding\n",
"\n",
"បញ្ហាមួយជាមួយវិធីសាស្រ្តមុនគឺវចនានុក្រមដែលប្រើនៅក្នុង TextVectorization និង Embedding គឺខុសគ្នា។ ដើម្បីដោះស្រាយបញ្ហានេះ យើងអាចប្រើដំណោះស្រាយដូចខាងក្រោមមួយណាមួយ៖\n",
"* បណ្តុះបណ្តាលម៉ូដែល Word2Vec ម្តងទៀតលើវចនានុក្រមរបស់យើង។\n",
"* បង្ហាញទិន្នន័យរបស់យើងជាមួយវចនានុក្រមពីម៉ូដែល Word2Vec ដែលបានបណ្តុះក្រោយ។ វចនានុក្រមដែលប្រើសម្រាប់បញ្ចូលទិន្នន័យអាចកំណត់នៅពេលបញ្ចូល។\n",
"\n",
"វិធីសាស្រ្តទីពីរមើលទៅងាយស្រួលជាង ដូចនេះយើងចាប់ផ្តើមអនុវត្តវា។ ជាទីមុន យើងនឹងបង្កើតស្រទាប់ `TextVectorization` ជាមួយវចនានុក្រមដែលបានកំណត់ ដែលយកចេញពី embeddings របស់ Word2Vec ៖\n"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
"vocab = list(w2v.vocab.keys())\n",
"vectorizer = keras.layers.experimental.preprocessing.TextVectorization(input_shape=(1,))\n",
"vectorizer.set_vocabulary(vocab)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"បណ្ណាល័យ word embeddings របស់ gensim មានមោទនភាពមួយដែលមានប្រយោជន៍ គឺ `get_keras_embeddings` ដែលនឹងបង្កើតស្រទាប់ embeddings នៃ Keras ដែលផ្ទាល់សម្រាប់អ្នកដោយស្វ័យប្រវត្តិ។\n"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch 1/5\n",
"938/938 [==============================] - 20s 14ms/step - loss: 1.3377 - acc: 0.4978 - val_loss: 1.2995 - val_acc: 0.5647\n",
"Epoch 2/5\n",
"938/938 [==============================] - 10s 10ms/step - loss: 1.2587 - acc: 0.5722 - val_loss: 1.2339 - val_acc: 0.5842\n",
"Epoch 3/5\n",
"938/938 [==============================] - 10s 10ms/step - loss: 1.1980 - acc: 0.5884 - val_loss: 1.1826 - val_acc: 0.5954\n",
"Epoch 4/5\n",
"938/938 [==============================] - 12s 13ms/step - loss: 1.1503 - acc: 0.6002 - val_loss: 1.1417 - val_acc: 0.6018\n",
"Epoch 5/5\n",
"938/938 [==============================] - 11s 12ms/step - loss: 1.1120 - acc: 0.6097 - val_loss: 1.1083 - val_acc: 0.6104\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x2220ccb81c0>"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = keras.models.Sequential([\n",
" vectorizer, \n",
" w2v.get_keras_embedding(train_embeddings=False),\n",
" keras.layers.Lambda(lambda x: tf.reduce_mean(x,axis=1)),\n",
" keras.layers.Dense(4, activation='softmax')\n",
"])\n",
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'])\n",
"model.fit(ds_train.map(tupelize).batch(128),validation_data=ds_test.map(tupelize).batch(128),epochs=5)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"មូលហេតុមួយដែលធ្វើឲ្យយើងមិនឃើញភាពត្រឹមត្រូវខ្ពស់ជាងនេះ គឺព្រោះពាក្យជាច្រើនពីឃ្លាសំណុំនៃទិន្នន័យរបស់យើងខាតនៅក្នុងវចនានុក្រម GloVe ដែលបានបណ្តុះបណ្តាលមុន ហើយដូច្នេះពួកវាត្រូវបានអះអាងចោល។ ដើម្បីទប់ស្កាត់បញ្ហានេះ យើងអាចបណ្តុះបណ្តាលការបង្ហាញបែប embeddings មួយផ្ទាល់លើមូលដ្ឋានទិន្នន័យរបស់យើង។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ពន្យល់ផ្ទៃក្នុងបរិបទ\n",
"\n",
"កំណត់ខ្លាំងមួយនៃការបង្ហាញអត្តសញ្ញាណដែលបានបណ្ដុះបណ្ដាលជាមុនជារូបភាពដូចជា Word2Vec គឺថា ទោះបីត្រូវចាប់អត្ថន័យនៃពាក្យមួយក៏ដោយ ពួកវាមិនអាចបំបែកតាមអត្ថន័យផ្សេងៗបាននោះទេ។ នេះអាចបណ្តាលបញ្ហាក្នុងម៉ូដែលដែលយើងប្រើបន្ទាប់។\n",
"\n",
"ឧទាហរណ៍ពាក្យ 'play' មានអត្ថន័យខុសគ្នានៅក្នុងប្រយោគទាំងពីរនេះ៖\n",
"- ខ្ញុំបានទៅចូលរួម **play** នៅក្នុងក្រហម។\n",
"- John ចង់ **play** ជាមួយមិត្តភក្តិរបស់គាត់។\n",
"\n",
"ការបង្ហាញអត្តសញ្ញាណដែលបានបណ្ដុះបណ្ដាលជាមុនដែលយើងបានគិតពីនេះ បង្ហាញពីអត្ថន័យទាំងពីរនៃពាក្យ 'play' នៅក្នុងរូបភាពដើម្បីតែមួយ។ ដើម្បីរំដោះកំណត់ខ្លាំងនេះ យើងត្រូវតែបង្កើតការបង្ហាញអត្តសញ្ញាណដែលផ្អែកលើ **ម៉ូដែលភាសា** ដែលត្រូវបានបណ្តុះបណ្តាលលើប័ណ្ណអត្ថបទច្រើន និង *ដឹង* ថាពាក្យអាចត្រូវបានដាក់ក្នុងបរិបទផ្សេងៗគ្នាយ៉ាងដូចម្តេច។ ការពិភាក្សាពីការបង្ហាញអត្តសញ្ញាណផ្ទៃក្នុងបរិបទ នៅក្រៅពីសកម្មភាពសិក្សានេះ ប៉ុន្តែយើងនឹងត្រឡប់មកវិញនៅពេលនិយាយអំពីម៉ូដែលភាសាក្នុងឯកតាបន្ទាប់។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**ការព្រមាន**៖ \nឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេលយើងខំប្រឹងប្រែងដើម្បីឲ្យមានភាពត្រឹមត្រូវ សូមយកចិត្តទុកដាក់ថាការបកប្រែដោយស្វ័យប្រវត្តិក្នុងរហៈពេលខ្លីអាចមានកំហុស ឬភាពមិនត្រឹមត្រូវ។ ឯកសារដើមនៅភាសាតំបន់របស់វា គួរត្រូវបានគេចាត់ទុកជា ប្រភពផ្លូវការជាធរមាន។ សម្រាប់ព័ត៌មានចំរូងចំរាស សូមប្រើការបកប្រែដោយអ្នកជំនាញមនុស្ស។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកប្រែខុសផ្សេងទៀតដែលខ្លួនកើតឡើងពីការប្រើប្រាស់ការបកប្រែនេះឡើយ។\n<!-- CO-OP TRANSLATOR DISCLAIMER END -->\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "0cb620c6d4b9f7a635928804c26cf22403d89d98d79684e4529119355ee6d5a5"
},
"kernel_info": {
"name": "conda-env-py37_tensorflow-py"
},
"kernelspec": {
"display_name": "py37_tensorflow",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.12"
},
"nteract": {
"version": "nteract-front-end@1.0.0"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,72 @@
# សេចក្ដីបញ្ចូល
## [ប្រឡងមុនម៉ោងបង្រៀន](https://ff-quizzes.netlify.app/en/ai/quiz/27)
នៅពេលបណ្តុះបណ្តាលឧបករណ៍ចាត់ថ្នាក់ដោយផ្អែកលើ BoW ឬ TF/IDF យើងបានប្រតិបត្តិលើវ៉ិចទ័រក្បាល-ពុំខ្នាតខ្ពស់ `vocab_size` ហើយយើងបានបម្លែងយ៉ាងច្បាស់ពីវ៉ិចទ័រចំណាំតំណោយតិចទៅកាន់តំណាងមួយកន្លែងតែមួយពិបាកសម្គាល់។ ប៉ុន្តែនោះ តំណាងមួយកន្លែងតែមួយនេះ មិនមានប្រសិទ្ធភាពផ្នែកចងចាំទេ។ បន្ថែមពីនេះ ពាក្យនីមួយៗត្រូវបានចាត់ទុកដោយឡែកពីមួយទៅមួយទៀត, គឺវ៉ិចទ័រដែលបានបំលែងតាមរយៈមួយកន្លែងមួយមិនបង្ហាញពីស្រដៀងគ្នាផ្នែកអត្ថន័យរវាងពាក្យទេ។
គំនិត **embeddings** គឺតំណាងពាក្យដោយវ៉ិចទ័រដែលមានកម្រិតខ្ទង់តិចជាង ដែលប្រហែលជា បង្ហាញពីអត្ថន័យវេជ្ជសាស្ត្រពាក្យនោះ។ យើងនឹងពិភាក្សាពីរបៀបបង្កើត embeddings មានន័យបច្ចុប្បន្នក្នុងពេលក្រោយ ប៉ុន្តែជារបៀបដំបូង យើងសូមគិត embeddings ដូចជាវិធីសាស្រ្តបន្ថយខ្ទង់មានទំហំវ៉ិចទ័រពាក្យ។
ដូចនេះ ស្រទាប់ embedding នឹងទទួលពាក្យមួយជាចូល និងបង្កើតវ៉ិចទ័រចេញ ដែលមានទំហំ `embedding_size` ដែលបានកំណត់។ ដោយក្នុងន័យមួយ វាស្រដៀងនឹងស្រទាប់ `Linear` ជាខ្លាំង ប៉ុន្តែជំហាននេះ មិនបង្ហាញវ៉ិចទ័រតាមរយៈមួយកន្លែងតែមួយទេ វាអាចទទួលលេខពាក្យជាចូលធ្វើអោយយើងជៀសវាងការបង្កើតវ៉ិចទ័រធំៗមួយកន្លែងតែមួយបាន។
ដោយប្រើស្រទាប់ embedding ជាស្រទាប់ដំបូង ក្នុងបណ្ដាញឧបករណ៍ចាត់ថ្នាក់របស់យើង យើងអាចប្តូរពីគំរូ bag-of-words ទៅគំរូ **embedding bag**, ដែលត្រូវបានបម្លែងពាក្យនីមួយៗក្នុងអត្ថបទទៅជា embedding តាមសមាសភាព បន្ទាប់មកគណនា​រាងអង្គការណាដែលមានសារសំខាន់លើ embedding ទាំងអស់ ដូចជា `sum`, `average``max`
![រូបភាពបង្ហាញឧបករណ៍ចាត់ថ្នាក់_embedding_សម្រាប់ពាក្យចំនួនប្រាំក្នុងលំដាប់។](../../../../../translated_images/km/embedding-classifier-example.b77f021a7ee67eee.webp)
> រូបភាពដោយអ្នកនិពន្ធ
## ✍️ ការអនុវត្ត: Embeddings
បន្តរៀនរបស់អ្នកនៅក្នុងកំណត់ត្រាគណនាគណនីដូចខាងក្រោម៖
* [Embeddings ជាមួយ PyTorch](EmbeddingsPyTorch.ipynb)
* [Embeddings ជាមួយ TensorFlow](EmbeddingsTF.ipynb)
## Semantic Embeddings: Word2Vec
ខណៈពេលស្រទាប់ embedding បានរៀនបម្លែងពាក្យទៅជា​តំណាងវ៉ិចទ័រ ប៉ុន្តែ តំណាងនេះមិនប្រាកដថាមានន័យសម្រាប់អត្ថន័យបែបសម្រង់បែបណានោះទេ។ វានឹងល្អប្រសើរជាងកាលណាបានរៀន​តំណាងវ៉ិចទ័រ ដែលពាក្យដែលស្រដៀងគ្នាន ឬពាក្យសំដែងបទស្រដៀងគ្នា មានវ៉ិចទ័រដែលនៅជិតគ្នាតាមចម្ងាយវ៉ិចទ័រមួយ (ឧ. ចម្ងាយអ៊៉ុយឡីដ)។
ដើម្បីធ្វើបានបែបនេះ យើងត្រូវផ្តល់ការបណ្តុះបណ្តាលមុនលើគំរូ embedding របស់យើង ជាមួយនឹងការប្រមូលអត្ថបទធំមួយយ៉ាងជាក់លាក់។ របៀបមួយក្នុងការបណ្តុះបណ្តាល embedding សម្រង់គឺហៅថា [Word2Vec](https://en.wikipedia.org/wiki/Word2vec)។ វាប្រើលើស្ថាបត្យកម្មសំខាន់ពីរដែលប្រើក្នុងការផលិត​តំណាងចែកចាយនៃពាក្យ៖
- **Continuous bag-of-words** (CBoW) — ក្នុងស្ថាបត្យកម្មនេះ យើងបណ្តុះគំរូឲ្យទាយពាក្យមួយពីបរិបទជុំវិញ។ ដោយផ្តល់ ngram $(W_{-2},W_{-1},W_0,W_1,W_2)$ គោលបំណងគំរូគឺទាយ $W_0$ ពី $(W_{-2},W_{-1},W_1,W_2)$។
- **Continuous skip-gram** ជាផ្ទុយនឹង CBoW។ គំរូប្រើច្រកបរិបទពាក្យជុំវិញ ដើម្បីទាយពាក្យបច្ចុប្បន្ន។
CBoW មានល្បឿនរហ័ស ខណៈដែល skip-gram យឺតជាង ប៉ុន្តែធ្វើការល្អជាងក្នុងការតំណាងពាក្យដែលមិនញឹកញាប់។
![រូបភាពបង្ហាញទាំងអalgorithm CBoW និង Skip-Gram សម្រាប់បម្លែងពាក្យទៅវ៉ិចទ័រ។](../../../../../translated_images/km/example-algorithms-for-converting-words-to-vectors.fbe9207a726922f6.webp)
> រូបភាពពី [ឯកសារ​នេះ](https://arxiv.org/pdf/1301.3781.pdf)
Word2Vec pre-trained embeddings (បែបដូចគំរូទៀតច្រើន ដូចជា GloVe) ក៏អាចប្រើជំនួសស្រទាប់ embedding ក្នុងបណ្ដាញប្រព័ន្ធប្រសាទបានផងដែរ។ ប៉ុន្តែ យើងត្រូវដោះស្រាយចំពោះវាក្យសព្ទ ពីព្រោះវាក្យសព្ទដែលប្រើក្នុងការបណ្តុះបណ្តាល Word2Vec/GloVe ចម្លែកពីវាក្យសព្ទក្នុងផ្នែកអត្ថបទរបស់យើង។ សូមមើលក្នុងកំណត់ត្រាគណនាក្នុងលើដើម្បីឃើញរបៀបដោះស្រាយបញ្ហានេះ។
## Contextual Embeddings
គន្លឹះមួយនៃកំណត់ខួបនៃការតំណាង embedding ដែលបានបណ្តុះមុនដូចជា Word2Vec គឺបញ្ហាការប្រែឯកសារអត្ថន័យពាក្យ។ ខណៈពេល embedding ដែលបានបណ្តុះមុនអាចចាប់យកអត្ថន័យមួយចំនួនរបស់ពាក្យនៅក្នុងបរិបទបាន ប៉ុន្តែមានន័យគ្រប់យ៉ាងរបស់ពាក្យត្រូវបានបំលែងទៅ embedding ដូចគ្នា។ វាអាចបណ្តាលបញ្ហាលំបាកក្នុងគំរូក្រោយៗ ព្រោះពាក្យជាច្រើនដូចជា ពាក្យ 'play' មានន័យខុសគ្នាអាស្រ័យលើបរិបទដែលវាត្រូវបានប្រើ។
ឧទាហរណ៍ ពាក្យ 'play' នៅក្នុងប្រយោគទាំងពីរនេះ មានន័យខុសគ្នាខ្លាំង៖
- ខ្ញុំបានទៅទស្សនាការលេងក្នុងរឿងនៅឯទៀតឆាក។
- John ចង់ **លេង** ជាមួយមិត្តភក្តិរបស់គាត់។
embedding ដែលបានបណ្តុះមុនខាងលើ តំណាងទាំងពីរនេះនៃពាក្យ 'play' ក្នុង embedding ដូចគ្នា។ ដើម្បីដោះស្រាយកំណត់ខួបនេះ យើងត្រូវបង្កើត embeddings អាស្រ័យលើ **ម៉ូដែលភាសា** ដែលបានបណ្តុះលើឯកសារអត្ថបទធំ និង *ដឹង* របៀបដាក់ពាក្យជាប់គ្នានៅក្នុងបរិបទផ្សេងៗ។ ការពិភាក្សាពី contextual embeddings មិនមែនជាវិសាលភាពសម្រាប់មេរៀននេះទេ ប៉ុន្តែយើងនឹងត្រឡប់មកវិញនៅពេលនិយាយពីម៉ូដែលភាសានៅពេលក្រោយក្នុងវគ្គនេះ។
## សេចក្ដីសន្និដ្ឋាន
ក្នុងមេរៀននេះ អ្នកបានស្វែងយល់ពីរបៀបបង្កើត និងប្រើស្រទាប់ embedding នៅក្នុង TensorFlow និង Pytorch ដើម្បីបញ្ជូនអត្ថន័យវេជ្ជសាស្ត្រនៃពាក្យបានល្អប្រសើរជាងមុន។
## 🚀 ការប្រកួតប្រជែង
Word2Vec ត្រូវបានប្រើសម្រាប់កម្មវិធីចម្លែកមួយចំនួន រួមមានការបង្កើតបទចម្រៀង និងកាពិការសាស្ត្រា។ សូមមើល [អត្ថបទនេះ](https://www.politetype.com/blog/word2vec-color-poems) ដែលនិយាយពីរបៀបដែលអ្នកនិពន្ធប្រើ Word2Vec ដើម្បីបង្កើតកាពិការសាស្ត្រា។ និងមើលវីដេអូ [នេះដោយ Dan Shiffmann](https://www.youtube.com/watch?v=LSS_bos_TPI&ab_channel=TheCodingTrain) ដើម្បីស្គាល់ការពន្យល់ផ្សេងទៀតអំពីបច្ចេកទេសនេះ។ បន្ទាប់មកសាកល្បងអនុវត្តបច្ចេកទេសទាំងនេះទៅលើអត្ថបទផ្ទាល់ខ្លួនរបស់អ្នកប្រហែលមកពី Kaggle។
## [ប្រឡងបន្ទាប់ម៉ោងបង្រៀន](https://ff-quizzes.netlify.app/en/ai/quiz/28)
## ការពិនិត្យឡើងវិញ & សិក្សាឯកត្ត
អានឯកសារនេះអំពី Word2Vec៖ [ការប៉ាន់ប្រមាណប្រពៃណីនៃតំណាងពាក្យនៅក្នុងប្រងេះវ៉ិចទ័រ](https://arxiv.org/pdf/1301.3781.pdf)
## [ការងារ៖ កំណត់ត្រា](assignment.md)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការបដិសេធ**៖
ឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈដែលយើងខិតខំប្រឹងប្រែងដើម្បីឱ្យបានភាពត្រឹមត្រូវ សូមចំណាំថា ការបកប្រែដោយស្វ័យប្រវត្តិអាចមានកំហុស ឬភាពមិនត្រឹមត្រូវផ្សេងៗ។ ឯកសារដើមក្នុងភាសាមូលដ្ឋានរបស់វាគួរត្រូវបានគេចាត់ទុកជាដើមទុនផ្លូវការ។ សម្រាប់ព័ត៌មានសំខាន់ៗ យើងផ្តល់អនុសាសន៍ឱ្យប្រើការបកប្រែដោយមនុស្សជំនាញវិជ្ជាជីវៈ។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកផ្សេងពីការប្រើប្រាស់ការបកប្រែនេះឡើយ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,10 @@
# កិច្ចកម្ម៖ ប្រដាប់កំណត់កំណត់ត្រា
ប្រើប្រាស់ប្រដាប់កំណត់កំណត់ត្រាដែលពាក់ព័ន្ធនឹងមេរៀននេះ (ចំពោះកំណែ PyTorch ឬ TensorFlow) ធ្វើការចាប់ផ្តើមបញ្ចប់វាឡើងវិញដោយប្រើឯកសារទិន្នន័យផ្ទាល់ខ្លួនរបស់អ្នក ប្រហែលមួយនៅពី Kaggle ដោយមានការផ្តល់ឱ្យឈ្មោះតាមសិទ្ធិ។ សរសេរ ប្រដាប់កំណត់កំណត់ត្រាឡើងវិញ ដើម្បីបំភ្លឺលើការស្វែងរកផ្ទាល់ខ្លួនរបស់អ្នក។ ព្យាយាមប្រើប្រាស់ប្រភេទទិន្នន័យផ្សេងទៀត ហើយចាប់យកការស្វែងរករបស់អ្នក ដោយប្រើអត្ថបទដូចជា [បទចំរៀង Beatles ទាំងនេះ](https://www.kaggle.com/datasets/jenlooper/beatles-lyrics)។
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការបដិសេធ**៖
ឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈយើងខំប្រឹងសម្រាប់ភាពត្រឹមត្រូវ សូមយល់ព្រមថាបកប្រែដោយស្វ័យប្រវត្តិអាចមានកំហុស ឬភាពមិនត្រឹមត្រូវ។ ឯកសារដើមក្នុងភាសាមូលដ្ឋានគួរត្រូវបានរក្សាទុកជាឯកសារយោងដ៏មានអំណាច។ សម្រាប់ព័ត៌មានសំខាន់ៗ សូមណែនាំឲ្យប្រើការបកប្រែដោយមនុស្សវិជ្ជាជីវៈ។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំនិងការបកប្រែខុសពីការប្រើប្រាស់បកប្រែនេះឡើយ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,570 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "NXTSugt6ieXh"
},
"source": [
"## បណ្តុះបណ្តាលម៉ូដែល CBoW\n",
"\n",
"សៀវភៅកំណត់ត្រានេះជាផ្នែកមួយនៃ [ការបណ្តុះបណ្តាល AI សម្រាប់អ្នកចាប់ផ្តើម](http://aka.ms/ai-beginners)\n",
"\n",
"ក្នុងឧទាហរណ៍នេះ យើងនឹងមើលការបណ្តុះបណ្តាលម៉ូដែលភាសា CBoW ដើម្បីទទួលបានកន្លែងបញ្ចូល Word2Vec ផ្ទាល់ខ្លួនរបស់យើង។ យើងនឹងប្រើទិន្នន័យ AG News ជាគម្របខ្ទង់អត្ថបទ។\n"
]
},
{
"cell_type": "code",
"source": [
"import torch\n",
"import torchtext\n",
"import os\n",
"import collections\n",
"import builtins\n",
"import random\n",
"import numpy as np"
],
"metadata": {
"id": "q-UiiJUKaxHj"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")"
],
"metadata": {
"id": "TFbR8CZaTZ1q"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"source": [
"ដំបូងតែងយកសំណុំទិន្នន័យរបស់យើង ហើយកំណត់ tokenizer និងវាក្យសព្ទ។ យើងនឹងកំណត់ `vocab_size` ទៅ ៥០០០ ដើម្បីកំណត់ការគណនាបន្តិច។\n"
],
"metadata": {
"id": "HIwC7lI5T-ov"
}
},
{
"cell_type": "code",
"source": [
"def load_dataset(ngrams = 1, min_freq = 1, vocab_size = 5000 , lines_cnt = 500):\n",
" tokenizer = torchtext.data.utils.get_tokenizer('basic_english')\n",
" print(\"Loading dataset...\")\n",
" test_dataset, train_dataset = torchtext.datasets.AG_NEWS(root='./data')\n",
" train_dataset = list(train_dataset)\n",
" test_dataset = list(test_dataset)\n",
" classes = ['World', 'Sports', 'Business', 'Sci/Tech']\n",
" print('Building vocab...')\n",
" counter = collections.Counter()\n",
" for i, (_, line) in enumerate(train_dataset):\n",
" counter.update(torchtext.data.utils.ngrams_iterator(tokenizer(line),ngrams=ngrams))\n",
" if i == lines_cnt:\n",
" break\n",
" vocab = torchtext.vocab.Vocab(collections.Counter(dict(counter.most_common(vocab_size))), min_freq=min_freq)\n",
" return train_dataset, test_dataset, classes, vocab, tokenizer"
],
"metadata": {
"id": "wdZuygtgiuLG"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"train_dataset, test_dataset, _, vocab, tokenizer = load_dataset()"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "4d1nU1gsivGu",
"outputId": "949fe272-ae0e-49f5-c373-6703458b3a74"
},
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Loading dataset...\n",
"Building vocab...\n"
]
}
]
},
{
"cell_type": "code",
"source": [
"def encode(x, vocabulary, tokenizer = tokenizer):\n",
" return [vocabulary[s] for s in tokenizer(x)]"
],
"metadata": {
"id": "1XDYNhG8ToFV"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "LIlQk6_PaHVY"
},
"source": [
"## ម៉ូដែល CBoW\n",
"\n",
"CBoW រៀនទាយពាក្យមួយ dựa trênពាក្យជាប់ជាង $2N$ ។ ឧទាហរណ៍ បើ $N=1$ យើងនឹងទទួលបានគូដូចខាងក្រោមពីប្រយោគ *I like to train networks*: (like,I), (I, like), (to, like), (like,to), (train,to), (to, train), (networks, train), (train,networks)។ នៅទីនេះ ពាក្យដំបូងគឺពាក្យជាប់ដែលប្រើជាការបញ្ចូល ហើយពាក្យទីពីរជាពាក្យដែលយើងកំពុងទាយ។\n",
"\n",
"ដើម្បីសង់បណ្តាញដើម្បីទាយពាក្យបន្ទាប់ យើងត្រូវផ្គត់ផ្គង់ពាក្យជាប់ជាការបញ្ចូល ហើយទទួលបានលេខពាក្យជាលទ្ធផល។ រចនាសម្ព័ន្ធនៃបណ្តាញ CBoW មានដូចខាងក្រោម៖\n",
"\n",
"* ពាក្យបញ្ចូលត្រូវបានបញ្ចូនតាមស្រទាប់អំបិល។ ស្រទាប់អំបិលនេះជាស្រទាប់ embedding Word2Vec របស់យើង ដូច្នេះយើងនឹងកំណត់វាផ្ទាល់ជាអថេរ `embedder`។ យើងនឹងប្រើទំហំ embedding = 30 ក្នុងឧទាហរណ៍នេះ ទោះបីជាអ្នកអាចចង់សាកល្បងមិនលើសនេះ (word2vec ផ្ទាល់មួយមាន 300)\n",
"* វិទិក embedding នឹងត្រូវបញ្ចូនទៅស្រទាប់តែមួយដែលនឹងទាយពាក្យលទ្ធផល។ ដូច្នេះវាមានម៉េជ័រ `vocab_size`។\n",
"\n",
"សម្រាប់លទ្ធផល ប្រសិនបើយើងប្រើ `CrossEntropyLoss` ជាអនុគមន៍ខាត ត្រូវផ្គត់ផ្គង់តែលេខពាក្យជាលទ្ធផលដែលរំពឹងទុក ដោយគ្មានការអ៊ិនកូដ one-hot។\n"
]
},
{
"cell_type": "code",
"source": [
"vocab_size = len(vocab)\n",
"\n",
"embedder = torch.nn.Embedding(num_embeddings = vocab_size, embedding_dim = 30)\n",
"model = torch.nn.Sequential(\n",
" embedder,\n",
" torch.nn.Linear(in_features = 30, out_features = vocab_size),\n",
")\n",
"\n",
"print(model)"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "akKTcKQKkfl2",
"outputId": "da687e3e-a8ec-4c1a-e456-ab8cd6ac7dad"
},
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Sequential(\n",
" (0): Embedding(5002, 30)\n",
" (1): Linear(in_features=30, out_features=5002, bias=True)\n",
")\n"
]
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Nud6jgGPaHVa"
},
"source": [
"## ការរៀបចំ​ទិន្នន័យ​បណ្តុះបណ្តាល\n",
"\n",
"ឥឡូវនេះមកកត់កម្ម​មុខងារ​ផ្លូវការ​ដែល​នឹងគណនា​ជួរពាក្យ CBoW ពី​អត្ថបទ។ មុខងារនេះ​នឹង​អនុញ្ញាត​ឱ្យ​យើង​បញ្ជាក់​ទំហំ​បង្អួច និង​នឹង​ត្រឡប់​មក​ជូន​សំណុំ​ជួរ - ពាក្យ​បញ្ចូល និង​ពាក្យ​ផលបញ្ចេញ។ សូមចំណាំថា មុខងារនេះអាចប្រើប្រាស់លើពាក្យ ហើយក៏អាចប្រើលើវ៉ិចទ័រ/តិនស័រ ដែលនឹងអនុញ្ញាតឲ្យយើង encode អត្ថបទ មុននឹងផ្ញើវាទៅមុខងារ `to_cbow` ។\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "x-dsXygOieXn",
"outputId": "c2218280-e540-40ba-9546-efe48d0d714f"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"[['like', 'I'], ['to', 'I'], ['I', 'like'], ['to', 'like'], ['train', 'like'], ['I', 'to'], ['like', 'to'], ['train', 'to'], ['networks', 'to'], ['like', 'train'], ['to', 'train'], ['networks', 'train'], ['to', 'networks'], ['train', 'networks']]\n",
"[[232, 172], [5, 172], [172, 232], [5, 232], [0, 232], [172, 5], [232, 5], [0, 5], [1202, 5], [232, 0], [5, 0], [1202, 0], [5, 1202], [0, 1202]]\n"
]
}
],
"source": [
"def to_cbow(sent,window_size=2):\n",
" res = []\n",
" for i,x in enumerate(sent):\n",
" for j in range(max(0,i-window_size),min(i+window_size+1,len(sent))):\n",
" if i!=j:\n",
" res.append([sent[j],x])\n",
" return res\n",
"\n",
"print(to_cbow(['I','like','to','train','networks']))\n",
"print(to_cbow(encode('I like to train networks', vocab)))"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "XVaaDLjaaHVb"
},
"source": [
"មកត្រៀមប្រមូលទិន្នន័យសម្រាប់បណ្តុះបណ្តាល។ យើងនឹងឆ្លងកាត់ព្រឹត្តិការណ៍ទាំងអស់ ហៅ `to_cbow` ដើម្បីទទួលបានបញ្ជីគូពាក្យ និងបន្ថែមគូទាំងនោះទៅ `X` និង `Y`។ ដើម្បីកាន់តែប្រសើរប្រើពេលវេលា យើងនឹងគិតត្រឹមតែព័ត៌មាន ១០,០០០ ឯកសារដំបូងប៉ុណ្ណោះ - អ្នកអាចលះបង់ការកំណត់នេះបានយ៉ាងងាយស្រួល ប្រសិនបើអ្នកមានពេលវេលាច្រើន ហើយចង់ទទួលបានការបញ្ចូលពាក្យល្អជាងនេះ :)\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "54b-Gd9TieXo"
},
"outputs": [],
"source": [
"X = []\n",
"Y = []\n",
"for i, x in zip(range(10000), train_dataset):\n",
" for w1, w2 in to_cbow(encode(x[1], vocab), window_size = 5):\n",
" X.append(w1)\n",
" Y.append(w2)\n",
"\n",
"X = torch.tensor(X)\n",
"Y = torch.tensor(Y)"
]
},
{
"cell_type": "markdown",
"source": [
"យើងនឹងបម្លែងទិន្នន័យនោះទៅជាចំណុចទិន្នន័យមួយ ហើយបង្កើត dataloader:\n"
],
"metadata": {
"id": "cwWy0PzXWhN5"
}
},
{
"cell_type": "code",
"source": [
"class SimpleIterableDataset(torch.utils.data.IterableDataset):\n",
" def __init__(self, X, Y):\n",
" super(SimpleIterableDataset).__init__()\n",
" self.data = []\n",
" for i in range(len(X)):\n",
" self.data.append( (Y[i], X[i]) )\n",
" random.shuffle(self.data)\n",
"\n",
" def __iter__(self):\n",
" return iter(self.data)"
],
"metadata": {
"id": "mfoAcGPFZU8p"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "e4NQ_-5waHVc"
},
"source": [
"យើងក៏នឹងបម្លែងទិន្នន័យនោះទៅជាឈុតទិន្នន័យមួយផងដែរ ហើយបង្កើត dataloader:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "AbLUcojlieXo"
},
"outputs": [],
"source": [
"ds = SimpleIterableDataset(X, Y)\n",
"dl = torch.utils.data.DataLoader(ds, batch_size = 256)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "pKQr7sXeaHVc"
},
"source": [
"ឥឡូវនេះយើងនឹងធ្វើការបណ្តុះបណ្តាលពិតប្រាកដ។ យើងនឹងប្រើ `SGD` អុបទីម៉ាយហ្ស័រជាមួយអត្រាអានុបញ្ញាតិខ្ពស់។ អ្នកក៏អាចសាកល្បងលេងជាមួយអុបទីម៉ាយហ្ស័រផ្សេងទៀតដូចជា `Adam`។ យើង​នឹង​បណ្តុះ​បណ្តាលរយៈពេល ១០ epoch ជាចាប់ផ្តើម - ហើយ​អ្នក​អាច​រត់​កូដ​នេះ​ម្តងទៀត ប្រសិនបើ​ចង់​បាន ការបាត់បង់ (loss) ទាបជាងនេះ។\n"
]
},
{
"cell_type": "code",
"source": [
"def train_epoch(net, dataloader, lr = 0.01, optimizer = None, loss_fn = torch.nn.CrossEntropyLoss(), epochs = None, report_freq = 1):\n",
" optimizer = optimizer or torch.optim.Adam(net.parameters(), lr = lr)\n",
" loss_fn = loss_fn.to(device)\n",
" net.train()\n",
"\n",
" for i in range(epochs):\n",
" total_loss, j = 0, 0, \n",
" for labels, features in dataloader:\n",
" optimizer.zero_grad()\n",
" features, labels = features.to(device), labels.to(device)\n",
" out = net(features)\n",
" loss = loss_fn(out, labels)\n",
" loss.backward()\n",
" optimizer.step()\n",
" total_loss += loss\n",
" j += 1\n",
" if i % report_freq == 0:\n",
" print(f\"Epoch: {i+1}: loss={total_loss.item()/j}\")\n",
"\n",
" return total_loss.item()/j"
],
"metadata": {
"id": "HeeCYKr_KF1w"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"source": [
"train_epoch(net = model, dataloader = dl, optimizer = torch.optim.SGD(model.parameters(), lr = 0.1), loss_fn = torch.nn.CrossEntropyLoss(), epochs = 10)"
],
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "KVgwGtDHgDlT",
"outputId": "2447833f-f0e3-4566-c33d-addbfe2f451d"
},
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Epoch: 1: loss=5.664632366860172\n",
"Epoch: 2: loss=5.632101973960962\n",
"Epoch: 3: loss=5.610399051405015\n",
"Epoch: 4: loss=5.594621561080262\n",
"Epoch: 5: loss=5.582538017415446\n",
"Epoch: 6: loss=5.572900234519603\n",
"Epoch: 7: loss=5.564951676341915\n",
"Epoch: 8: loss=5.558288112064614\n",
"Epoch: 9: loss=5.552576955031129\n",
"Epoch: 10: loss=5.547634165194347\n"
]
},
{
"output_type": "execute_result",
"data": {
"text/plain": [
"5.547634165194347"
]
},
"metadata": {},
"execution_count": 16
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "W8u2qXZmaHVd"
},
"source": [
"## សាកល្បង Word2Vec\n",
"\n",
"ដើម្បីប្រើប្រាស់ Word2Vec យើងចាប់ផ្តើមយកវ៉ិចទ័រដែលស្របគ្នានឹងពាក្យទាំងអស់ក្នុងវាក្យសម្ព័ន្ធរបស់យើង:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "r8TatcXjkU_t"
},
"outputs": [],
"source": [
"vectors = torch.stack([embedder(torch.tensor(vocab[s])) for s in vocab.itos], 0)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "3OcX21UOaHVd"
},
"source": [
"មកមើលឧទាហរណ៍ មើលពីរបៀបដែលពាក្យ **Paris** ត្រូវបានរៀបចំជាទំព័រជួរៈ\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "bz6tAeLzieXp",
"outputId": "5b20850e-4342-45e9-f840-cfac2b4d61d8"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"tensor([-0.0915, 2.1224, -0.0281, -0.6819, 1.1219, 0.6458, -1.3704, -1.3314,\n",
" -1.1437, 0.4496, 0.2301, -0.3515, -0.8485, 1.0481, 0.4386, -0.8949,\n",
" 0.5644, 1.0939, -2.5096, 3.2949, -0.2601, -0.8640, 0.1421, -0.0804,\n",
" -0.5083, -1.0560, 0.9753, -0.5949, -1.6046, 0.5774],\n",
" grad_fn=<EmbeddingBackward>)\n"
]
}
],
"source": [
"paris_vec = embedder(torch.tensor(vocab['paris']))\n",
"print(paris_vec)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "pHTJlaeYaHVd"
},
"source": [
"វា​គឺជា​វិស្សមកាល​ក្នុង​ការ​ប្រើ Word2Vec ដើម្បី​ស្វែងរក​ពាក្យ​បញ្ញត្តិ​មួយស្មើ។ មុខងារ​ក្រោមនេះ​នឹង​បង្វិល​ទៅ​វិញ​នូវ​ពាក្យ​ដែល​ខ្ទង់ជិត `n` ទៅនឹង​ការ​បញ្ចូល​មួយ។ ដើម្បី​រក​ពួកវា​យើង​គណនា​គម្លាត​នៃ $|w_i - v|$ ដែល $v$ គឺជា​វ៉ិចទ័រ​តំណាងឱ្យ​ពាក្យ​បញ្ចូល​របស់​យើង ហើយ $w_i$ គឺជា​ការ​អ៊ិនកូដ​របស់​ពាក្យ​លេខ $i$ ក្នុង​ពាក្យសម្រង់។ យើង​ក្រោយមក​តម្រៀប​អារេ ហើយ​ដក​អនុសីត​គឺ `argsort` ហើយ​យក​ធាតុ `n` ដំបូង​នៃ​បញ្ជី ដែល​អ៊ិនកូដ​មាត្រានៃ​ទីតាំង​នៃ​ពាក្យ​ខ្ទង់​ជិត​ក្នុង​ពាក្យសម្រង់។\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "NlZyi-_olFar",
"outputId": "b5dbb163-88c4-4d5a-eaf2-6751f700e98c"
},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"['microsoft', 'quoted', 'lp', 'rate', 'top']"
]
},
"metadata": {},
"execution_count": 56
}
],
"source": [
"def close_words(x, n = 5):\n",
" vec = embedder(torch.tensor(vocab[x]))\n",
" top5 = np.linalg.norm(vectors.detach().numpy() - vec.detach().numpy(), axis = 1).argsort()[:n]\n",
" return [ vocab.itos[x] for x in top5 ]\n",
"\n",
"close_words('microsoft')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "-dQq7xeAln0U",
"outputId": "66f768c3-c248-4bfd-ce4f-c8ffc6d0dd0d"
},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"['basketball', 'lot', 'sinai', 'states', 'healthdaynews']"
]
},
"metadata": {},
"execution_count": 51
}
],
"source": [
"close_words('basketball')"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "fJXqK26b29sa",
"outputId": "78f0baba-ffd0-485a-dd87-0a12bedfd7fa"
},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
"['funds', 'travel', 'sydney', 'japan', 'business']"
]
},
"metadata": {},
"execution_count": 77
}
],
"source": [
"close_words('funds')"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "My0VeTDd3Ji8"
},
"source": [
"## លទ្ធផល\n",
"\n",
"ការប្រើប្រាស់បច្ចេកវិទ្យាឆ្លាតវៃដូចជា CBoW គឺអាចបណ្តុះបណ្តាលម៉ូឌែល Word2Vec បាន។ អ្នកក៏អាចសាកល្បងបណ្តុះបណ្តាលម៉ូឌែល skip-gram ដែលត្រូវបានបណ្តុះបណ្តាលឱ្យទាយពាក្យជិតខាងមួយដែលផ្ដោតលើពាក្យកណ្តាល និងមើលថាវាធ្វើការល្អប៉ុណ្ណាដែរ។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**ការ​បញ្ជាក់​ថា​មិន​មាន​ភិក្ខុ**៖ \nឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator) ។ ក្នុង​អំឡុង​ខណៈពេល​យើង​ព្យាយាម​រក្សា​ភាសា​ឲ្យ​ត្រឹមត្រូវ សូម​ជ្រាបថា​ការ​បកប្រែ​ដោយ​ស្វ័យប្រវត្តិ​អាច​មាន​កំហុស ឬ​មិន​ត្រឹមត្រូវ​បាន។ ឯកសារ​ដើម​ក្នុង​ភាសា​មាតុភាសា​ត្រូវ​បាន​គេ​យក​ឲ្យ​ជា​លទ្ធផល​មាន​សុពលភាព។ សម្រាប់​ព័ត៌មាន​សំខាន់ៗ យើង​ស្នើ​ឲ្យ​បកប្រែ​ដោយ​មនុស្ស​ជំនាញ​វិជ្ជាជីវៈ។ យើង​មិន​ទទួល​ខុសត្រូវ​សម្រាប់​ការ​ច្របូកច្របល់ ឬ​ការ​បកប្រែ​មិន​ត្រឹមត្រូវ​ណាមួយ​ដែល​កើត​ឡើង​ពី​ការ​ប្រើប្រាស់​ការ​បកប្រែ​នេះ​នោះ​ទេ។\n<!-- CO-OP TRANSLATOR DISCLAIMER END -->\n"
]
}
],
"metadata": {
"colab": {
"collapsed_sections": [],
"name": "CBoW-PyTorch.ipynb",
"provenance": []
},
"interpreter": {
"hash": "16af2a8bbb083ea23e5e41c7f5787656b2ce26968575d8763f2c4b17f9cd711f"
},
"kernelspec": {
"display_name": "Python 3.8.12 ('py38')",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.12"
},
"orig_nbformat": 4,
"gpuClass": "standard"
},
"nbformat": 4,
"nbformat_minor": 0
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,50 @@
# ការគំរូភាសា
ការបញ្ចូលអត្ថន័យជា semantic embeddings ដូចជា Word2Vec និង GloVe គឺជាជំហានដំបូងទៅរក **ការគំរូភាសា** - បង្កើតមូដែលដែលយ៉ាងណាមួយអាច *យល់* (ឬ *តំណាង*) ទ្រព្យសម្បត្តិនៃភាសា។
## [សំណួរប្រលងមុនម៉ោងបង្រៀន](https://ff-quizzes.netlify.app/en/ai/quiz/29)
គំនិតសំខាន់នៅពីក្រោយការគំរូភាសាគឺការបណ្តុះបណ្តាលនៅលើទិន្នន័យមិនមានស្លាក ជារបៀបមិនគ្រប់គ្រង។ វាមានសារៈសំខាន់ព្រោះយើងមានចំនួនអត្ថបទមិនមានស្លាកច្រើន ខណៈដែលចំនួនអត្ថបទមានស្លាកតែងតែមានកំណត់ដោយកំលាំងដែលយើងអាចចំណាយដើម្បីស្លាក។ ភាគច្រើន ពួកយើងអាចបង្កើតមូដែលភាសាដែលអាច **ព្យាករណ៍ពាក្យដែលអាបាន** នៅក្នុងអត្ថបទ ព្រោះវាស្រួលក្នុងការលាក់ពាក្យចៃដន្យមួយក្នុងអត្ថបទ និងប្រើវាជាគំរូបណ្តុះបណ្តាល។
## បណ្តុះបណ្តាល Embeddings
ក្នុងឧទាហរណ៍មុនៗរបស់យើង យើងបានប្រើ semantic embeddings ដែលបានបណ្តុះបណ្តាលរួចហើយ ប៉ុន្តែវាគួរឲ្យចាប់អារម្មណ៍ក្នុងការមើលថាតើ embeddings ទាំងនោះអាចបណ្តុះបណ្តាលយ៉ាងដូចម្តេច។ មានគំនិតប៉ុន្មានដែលអាចប្រើបាន៖
* **N-Gram** ការគំរូភាសា ពេលដែលយើងព្យាករណ៍ token មួយដោយមើលទៅ N tokens មុន (N-gram)
* **Continuous Bag-of-Words** (CBoW) ពេលដែលយើងព្យាករណ៍ token កណ្តាល $W_0$ ក្នុងលំដាប់ token $W_{-N}$, ..., $W_N$។
* **Skip-gram**, ដែលយើងព្យាករណ៍ក្រុម token ជាប់ខ្នៅ {$W_{-N},\dots, W_{-1}, W_1,\dots, W_N$} ពី token កណ្តាល $W_0$។
![image from paper on converting words to vectors](../../../../../translated_images/km/example-algorithms-for-converting-words-to-vectors.fbe9207a726922f6.webp)
> រូបភាពពី [អត្ថបទនេះ](https://arxiv.org/pdf/1301.3781.pdf)
## ✍️ សៀវភៅកត់ត្រាឧទាហរណ៍៖ បណ្តុះបណ្តាលម៉ូដែល CBoW
បន្តការសិក្សារបស់អ្នកនៅក្នុងសៀវភៅកត់ត្រាខាងក្រោម៖
* [បណ្តុះបណ្តាល CBoW Word2Vec ជាមួយ TensorFlow](CBoW-TF.ipynb)
* [បណ្តុះបណ្តាល CBoW Word2Vec ជាមួយ PyTorch](CBoW-PyTorch.ipynb)
## សេចក្តីសន្និដ្ឋាន
ក្នុងមេរៀនមុន យើងបានឃើញថា word embeddings ធ្វើការដូចជាមនុស្សមេដឹកនាំ! ឥឡូវនេះយើងដឹងថាការបណ្តុះបណ្តាល word embeddings មិនមែនជាការងារលំបាកណាស់ទេ ហើយយើងគួរតែអាចបណ្តុះបណ្តាល word embeddings របស់ខ្លួនសម្រាប់អត្ថបទជាក់លាក់ខ្លះ ប្រសិនបើត្រូវការជា។
## [សំណួរប្រលងបន្ទាប់ពីម៉ោងបង្រៀន](https://ff-quizzes.netlify.app/en/ai/quiz/30)
## សិក្សាស្វ័យប្រវត្តិ និងពិនិត្យឡើងវិញ
* [មេរៀន PyTorch ផ្លូវការអំពីការគំរូភាសា](https://pytorch.org/tutorials/beginner/nlp/word_embeddings_tutorial.html).
* [មេរៀន TensorFlow ផ្លូវការអំពីការបណ្តុះបណ្តាលម៉ូដែល Word2Vec](https://www.TensorFlow.org/tutorials/text/word2vec).
* ការប្រើប្រាស់ បណ្ណាល័យ **gensim** សម្រាប់បណ្តុះបណ្តាល embeddings ដែលប្រើប្រាស់គ្រប់គ្រាន់ក្នុងជួរឈរខ្លីៗ ត្រូវបានពិពណ៌នាទៅ [ក្នុងឯកសារនេះ](https://pytorch.org/tutorials/beginner/nlp/word_embeddings_tutorial.html).
## 🚀 [កិច្ចការផ្ទះ៖ បណ្តុះបណ្តាលម៉ូដែល Skip-Gram](lab/README.md)
នៅក្នុងមន្ទីរពិសោធន៍ យើងឆ្លើយបញ្ហាឱ្យអ្នកកែប្រែកូដពីមេរៀននេះដើម្បីបណ្តុះបណ្តាលម៉ូដែល skip-gram ជំនួស CBoW។ [អានព័ត៌មានលម្អិត](lab/README.md)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការបដិសេធ**៖
ឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេលយើងខំប្រឹងប្រែងសម្រាប់ភាពត្រឹមត្រូវ សូមជ្រាបថាការបកប្រែដោយស្វ័យប្រវត្តិអាចមានកំហុសឬការមិនត្រឹមត្រូវខ្លះៗ។ ឯកសារដើមនៅក្នុងភាសាដើមគួរត្រូវបានគេចាត់ទុកជាដើមទុនផ្លូវការជាងគេ។ សម្រាប់ព័ត៌មានសំខាន់ៗ គួរតែប្រើការបកប្រែដោយអ្នកជំនាញមនុស្សជាការណែនាំ។ យើងមិនទទួលបន្ទុកចំពោះការយល់ច្រឡំ ឬការបកប្រែខុសអ្វីៗដែលកើតឡើងពីការប្រើប្រាស់ការបកប្រែនេះទេ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,33 @@
# ការបណ្តុះបណ្តាលម៉ូឌែល Skip-Gram
ការងារពហុភាសាចេញពី [មេរៀន AI សម្រាប់អ្នកចាប់ផ្ដើម](https://github.com/microsoft/ai-for-beginners)។
## បេសកកម្ម
ក្នុងមេរៀននេះ អ្នកត្រូវតែបណ្តុះបណ្តាលម៉ូឌែល Word2Vec ដោយប្រើជំនាញ Skip-Gram។ បណ្តុះបណ្តាលបណ្ដាញជាមួយ embedding ដើម្បីទាក់ទង់ពាក្យជិតខាងនៅក្នុងបញ្ចាំង Skip-Gram ដែលមានទទឹង $N$-tokens។ អ្នកអាចប្រើ [កូដពីមេរៀននេះ](../CBoW-TF.ipynb) ហើយកែប្រែវាបន្តិច។
## សំណុំទិន្នន័យ
អ្នកអាចប្រើសៀវភៅណាមួយគ្រប់ប្រភេទបាន។ អ្នកអាចស្វែងរកអត្ថបទឥតគិតថ្លៃជាច្រើននៅ [Project Gutenberg](https://www.gutenberg.org/), ឧទាហរណ៍ នេះគឺជាលីងផ្ទាល់ទៅកាន់ [រឿង Alice's Adventures in Wonderland](https://www.gutenberg.org/files/11/11-0.txt)) រៀបរៀងដោយ Lewis Carroll។ ឬអ្នកអាចប្រើរឿងរបៀបរបស់ Shakespeare ដែលអ្នកអាចទាញយកដោយប្រើកូដខាងក្រោម៖
```python
path_to_file = tf.keras.utils.get_file(
'shakespeare.txt',
'https://storage.googleapis.com/download.tensorflow.org/data/shakespeare.txt')
text = open(path_to_file, 'rb').read().decode(encoding='utf-8')
```
## ស្វែងយល់!
បើអ្នកមានពេលវេលា និងចង់ទទួលបានការយល់ដឹងជ្រាលជ្រៅក្នុងប្រធាននេះ សូមព្យាយាមស្វែងរករឿងខ្លះៗ៖
* តើទំហំ embedding ធ្វើឲ្យលទ្ធផលមានភាពប៉ះពាល់យ៉ាងដូចម្តេច?
* តើរចនាប័ទ្មអត្ថបទផ្សេងៗធ្វើឲ្យលទ្ធផលមានភាពខុសគ្នាយ៉ាងដូចម្តេច?
* យកពាក្យប្រភេទខុសគ្នា និងពាក្យនិយមរបស់ពួកវា ចាប់យកតំណាងវ៉ិចទ័រ រួចប្រើ PCA ដើម្បីកាត់បន្ថយវិមាត្រទៅជាពីរ ហើយគូសពួកវានៅលើទីតាំង 2D។ តើអ្នកមើលឃើញលំនាំណាមួយទេ?
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការបដិសេធ**៖
ឯកសារនេះត្រូវបានបំលែងភាសាដោយប្រើសេវាកម្មបំលែងភាសា AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេលដែលយើងខិតខំធានារឿងភាពត្រឹមត្រូវ សូមយល់ឲ្យដឹងថាបំលែងភាសាដោយស្វ័យប្រវត្តិនេះអាចមានកំហុស ឬភាពមិនត្រឹមត្រូវ។ ឯកសារដើមជាភាសាទូទៅគួរត្រូវបានគេពិចារណាថាជាធនធានច្បាស់លាស់។ សម្រាប់ព័ត៌មានសំខាន់ៗ យើងស្នើឲ្យប្រើការបំលែងភាសារដោយអ្នកជំនាញមនុស្ស។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកស្រាយខុសណាមួយដែលកើតឡើងពីការប្រើប្រាស់បំលែងភាសានេះឡើយ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,91 @@
# បណ្ដាញប្រសាសន៍ផ្ទូតឆ្ពោះមុខវិញ
## [សំណួរប្រឡងមុនពេលសិក្សា](https://ff-quizzes.netlify.app/en/ai/quiz/31)
នៅក្នុងផ្នែកមុនៗ យើងបានប្រើប្រាស់តំណាងអត្ថន័យមានអត្ថន័យជាច្រើននៃអត្ថបទ និងឧបករណ៍ថ្នាក់ប៉ុណ្ណាយ្រិតមួយសាមញ្ញនៅលើអំពើបញ្ចូល។ រចនាសម្ព័ន្ធនេះធ្វើការចាប់យកន័យសរុបទាំងមូលនៃពាក្យនៅក្នុងប្រយោគ អ្វីដែលមិនបានគិតគូរពី **លំដាប់** នៃពាក្យទេ ព្រោះអនុបទបញ្ចូលមេដឹកនាំលើវាមិនទទួលបានព័ត៌មាននេះពីអត្ថបទដើមឡើយ។ ព្រោះម៉ូដែលទាំងនេះអត់អាចម៉ូដែលលំដាប់ពាក្យបាន អ្នកមិនអាចដោះស្រាយបញ្ហាស្មុគស្មាញ ឬចម្រូងចម្រាសដូចជា ការបង្កើតអត្ថបទ ឬការឆ្លើយសំណួរបាននោះទេ។
ដើម្បីចាប់យកន័យនៃរលកអត្ថបទមួយ យើងត្រូវប្រើសArchitecture បណ្ដាញប្រសាសន៍មួយផ្សេងទៀត ដែលហៅថា **បណ្ដាញប្រសាសន៍ផ្ទូតឆ្ពោះមុខវិញ** ឬ RNN។ ក្នុង RNN យើងផ្តល់ប្រយោគរបស់យើងតាមរយៈបណ្ដាញម៉ាស៊ីនមួយព្រមទាំងនិមួយៗនៃសញ្ញា ហើយបណ្ដាញបង្កើត**ស្ថានភាព**មួយ ដែលយើងនាំទៅផ្តល់បណ្ដាញម្តងទៀតជាមួយសញ្ញាបន្ទាប់។
![RNN](../../../../../translated_images/km/rnn.27f5c29c53d727b5.webp)
> រូបភាពដោយអ្នកនិពន្ធ
ផ្ដល់លំដាប់បញ្ចូលនៃរ៉ូតេខ្សែ X<sub>0</sub>,...,X<sub>n</sub> RNN បង្កើតជាសំណុំឯកត្តាបណ្ដាញប្រសាសន៍ ហើយបណ្តុះបណ្តាលសំណុំនេះពីដើមដល់ចុង ដោយប្រើវិធីត្រលប់ក្រោយ។ ឯកត្តាបណ្ដាញនីមួយៗទទួលយកគូ (X<sub>i</sub>,S<sub>i</sub>) ជាបញ្ចូល ហើយផលិត S<sub>i+1</sub> ជា​ផលលទ្ធផល។ ស្ថានភាពចុងក្រោយ S<sub>n</sub> ឬ (លទ្ធផល Y<sub>n</sub>) ចូលទៅក្នុងឧបករណ៍ថ្នាក់ប៉ុណ្ណាយ្រិតដើម្បីបង្កើតលទ្ធផល។ ឯកត្តាបណ្ដាញទាំងអស់ចែករំលែកទំងន់ដដែល ហើយបានបណ្តុះបណ្តាលពីដើមដល់ចុង ដោយប្រើម្តងត្រលប់ក្រោយតែមួយ។
ដោយសារតែវ៉ិចទ័រស្ថានភាព S<sub>0</sub>,...,S<sub>n</sub> ត្រូវបានផ្តល់ក្នុងបណ្ដាញ វាអាចរៀនអំពីភាពទាក់ទងរវាងពាក្យ។ ឧទាហរណ៍ ពេលពាក្យ *មិន* បង្ហាញនៅណាមួយក្នុងលំដាប់ វាអាចរៀនដើម្បីបដិសេធធាតុមួយចំនួនក្នុងវ៉ិចទ័រស្ថានភាព ដើម្បីបណ្តាលអោយមានការបដិសេធ។
> ✅ ព្រោះទំងន់របស់ឯកត្តាបណ្ដាញ RNNទាំងអស់លើរូបភាពខាងលើត្រូវបានចែករំលែក រូបភាពដូចគ្នាក៏អាចត្រូវបង្ហាញជា​ឯកត្តាមួយ (នៅខាងស្តាំ) ជាមួយច្រវាក់ប្រតិកម្មឡើងវិញ ដែលផ្ញើស្ថានភាពលទ្ធផលរបស់បណ្ដាញត្រឡប់ទៅការបញ្ចូលវិញ។
## រចនាសម្ព័ន្ធរបស់កោសិកា RNN
យើងមកមើលថាតើកោសិកា RNN សាមញ្ញត្រូវបានដាក់អ្វីខ្លះ។ វាទទួលយកស្ថានភាពមុន S<sub>i-1</sub> និងសញ្ញាបច្ចុប្បន្ន X<sub>i</sub> ជាបញ្ចូល ហើយត្រូវបង្កើតស្ថានភាពលទ្ធផល S<sub>i</sub> (ហើយពេលខ្លះយើងក៏ចាប់អារម្មណ៍លើលទ្ធផលផ្សេង Y<sub>i</sub> ដូចជា ក្នុងករណីបណ្ដាញបង្កើត)។
កោសិកា RNN សាមញ្ញមាន​ ម៉ាទ្រីចទម្ងន់ពីរ ក្នុងនោះមួយបម្លែងសញ្ញាបញ្ចូល (ហៅវា W) និងមួយផ្សេងបម្លែងស្ថានភាពបញ្ចូល (H)។ ក្នុងករណីនេះ លទ្ធផលនៃបណ្ដាញគណនាជា &sigma;(W&times;X<sub>i</sub>+H&times;S<sub>i-1</sub>+b) ដែល &sigma; គឺជា អនុគមន៍សកម្ម និង b គឺ បាញ់បន្ថែម។
<img alt="RNN Cell Anatomy" src="../../../../../translated_images/km/rnn-anatomy.79ee3f3920b3294b.webp" width="50%"/>
> រូបភាពដោយអ្នកនិពន្ធ
នៅករណីជាច្រើន រ៉ូតេខ្សែបញ្ចូលត្រូវបានផ្លាស់ប្តូរតាមស្រទាប់បញ្ចូលមុនពេលចូល RNN ដើម្បីកាត់បន្ថយវិមាត្រ។ ក្នុងករណីនេះ ប្រសិនបើវិមាត្រ វ៉ិចទ័របញ្ចូលគឺ *emb_size* និងវ៉ិចទ័រស្ថានភាពគឺ *hid_size* តែទំហំ W គឺ *emb_size*&times;*hid_size* ហើយទំហំ H គឺ *hid_size*&times;*hid_size*។
## អង្គចងចាំរយៈពេលខ្លី និងវែង (LSTM)
មួយក្នុងចំណោមបញ្ហាសំខាន់ៗនៃ RNN ចាស់ៗគឺបញ្ហា **សហន្សំកម្រាស់បាត់បង់**។ ព្រោះ RNN ត្រូវបានបណ្តុះបណ្តាលពីដើមដល់ចុងក្នុងមួយការត្រលប់ក្រោយទេវអាចមានកម្រិតពិបាកក្នុងការបញ្ជូនកំហុសទៅស្រទាប់ដំបូងៗ ក្នុងបណ្ដាញ ហើយដូច្នេះ បណ្ដាញមិនអាចរៀនទំនាក់ទំនងរវាងរ៉ូតេខ្សែនៅចម្ងាយបាន។ វិធីមួយដើម្បីជៀសវាងបញ្ហានេះគឺដាក់បញ្ចូល **ការគ្រប់គ្រងស្ថានភាពឲ្យច្បាស់លាស់** ដោយប្រើនូវអ្វីគេហៅថា **ច្រវាក់**។ មានរចនាសម្ព័ន្ធពីរដែលល្បីល្បាញ: **អង្គចងចាំរយៈពេលខ្លី និងវែង** (LSTM) និង **ឧបករណ៍ច្រវាក់ផ្ទេរបន្ទាត់** (GRU)។
![Image showing an example long short term memory cell](../../../../../lessons/5-NLP/16-RNN/images/long-short-term-memory-cell.svg)
> ប្រភពរូបភាព TBD
បណ្ដាញ LSTM ត្រូវបានរៀបចំដូច RNN សាមញ្ញ ប៉ុន្តែមានស្ថានភាពពីរត្រូវបានផ្ញើពីស្រទាប់ទៅស្រទាប់៖ ស្ថានភាពពិតប្រាកដ C និងវ៉ិចទ័រលាក់ H។ នៅក្នុងឯកត្តាណាមួយ វ៉ិចទ័រលាក់ H<sub>i</sub> ត្រូវបានភ្ជាប់ជាមួយបញ្ចូល X<sub>i</sub> ហើយគ្រប់គ្រងអ្វីដែលកើតឡើងទៅស្ថានភាព C តាមរយៈ **ច្រវាក់**។ ច្រវាក់នីមួយៗគឺជាបណ្ដាញប្រសាសន៍ ដែលមានអនុគមន៍ស៊ីហ្គម៉ូយ៉ោង (លទ្ធផលក្នុងជួរពី [0,1]) ដែលអាចគិតថាជាវ៉ាក់ម៉ាស់លើអថេរស្ថានភាព។ មានច្រវាក់ដូចខាងក្រោម (ពីឆ្វេងទៅស្តាំនៅក្នុងរូបភាពខាងលើ)៖
* ច្រវាក់ **ភ្លេច** ទទួលវ៉ិចទ័រលាក់ ហើយកំណត់ថាធាតុណានៃវ៉ិចទ័រ C យើងត្រូវភ្លេច ហើយធាតុណាត្រូវឲ្យផ្លាស់ដំណើរការ។
* ច្រវាក់ **បញ្ចូល** ទទួលព័ត៌មានពីវ៉ិចទ័របញ្ចូល និងវ៉ិចទ័រលាក់ ហើយបញ្ចូលព័ត៌មានទៅស្ថានភាព។
* ច្រវាក់ **លទ្ធផល** បម្លែងស្ថានភាពតាមរយៈស្រទាប់លីនេអ៊ែរ ដែលមានអនុគមន៍ *tanh* ហើយជ្រើសរើសធាតុខ្លះៗនៅក្នុងវ៉ិចទ័រលាក់ H<sub>i</sub> ដើម្បីបង្កើតស្ថានភាពថ្មី C<sub>i+1</sub>
ធាតុនៃស្ថានភាព C អាចគិតថាជាគ្រឿងញៀនលើក្សណ៍ ដែលអាចបិទបើកបាន។ ឧទាហរណ៍ នៅពេលយើងប្រទះឈ្មោះ *Alice* ក្នុងលំដាប់ នោះយើងអាចកំណត់ថាវាសំដៅលើតួអក្សរមួយជាប្រភេទស្រី ហើយជំរុញប៊្លាកនៅក្នុងស្ថានភាព ដែលយើងមាននាមប្រុសម្នាក់ក្នុងប្រយោគ។ នៅពេលក្រោយប្រទះប្រយោគ * និង Tom* យើងនឹងដាក់ប៊្លាកថាមាននាមពហុ។ ដូច្នេះ ដោយការគ្រប់គ្រងស្ថានភាពយើងអាចអនុញ្ញាតឱ្យតាមដានលក្ខណៈវេយ្យាករណ៍នៃផ្នែកប្រយោគបាន។
> ✅ សម្រង់ដ៏ល្អសម្រាប់យល់ពីរចនាសម្ព័ន្ធក្នុង LSTM គឺអត្ថបទល្អនេះ [Understanding LSTM Networks](https://colah.github.io/posts/2015-08-Understanding-LSTMs/) ដោយ Christopher Olah។
## បណ្ដាញ RNN មុខ និងច្រើនស្រទាប់
យើងបានពិភាក្សាពីបណ្ដាញបញ្ចូលតែមួយទិស ពីចំណុចចាប់ផ្តើម រហូតដល់ចុង។ វាល្អសមរម្យ ព្រោះវាស្រដៀងនឹងរបៀបដែលយើងអាន និងស្តាប់សន្ទនា។ ទោះជាយ៉ាងណា ព្រោះនៅក្នុងករណីជាច្រើន យើងអាចចូលដំណើរការលំដាប់បញ្ចូលដោយចៃដន្យ យើងអាចគួរត្រពិនិត្យការគណនាបញ្ចូលនៅទិសទាំងពីរ។ បណ្ដាញបែបនេះហៅថា **បណ្ដាញ RNN មុខ និងសម្រា** (bidirectional RNNs)។ នៅពេលប្រើបណ្ដាញបែបនេះ យើងត្រូវការវ៉ិចទ័រស្ថានភាពលាក់ពីរផ្នែក សម្រាប់ទិសនីមួយៗ។
បណ្ដាញបញ្ចូល (recurrent network) មួយ មិនថាមានទិសតែមួយ ឬសម្រា ក៏មានកម្លាំងក្នុងការចាប់យកលំនាំណាមួយក្នុងលំដាប់ ហើយអាចរក្សាទុកវាទៅក្នុងវ៉ិចទ័រស្ថានភាព ឬផ្ញើវាទៅលទ្ធផល។ ដូចជាបណ្ដាញ convolutional យើងអាចបង្កើតស្រទាប់បញ្ចូលមួយទៀតលើស្រទាប់ដំបូង ដើម្បីចាប់យកលំនាំកម្រិតខ្ពស់ និងបង្កើតលំនាំពីលំនាំកម្រិតទាបដែលបានបំបែកដោយស្រទាប់ដំបូង។ វារួមបញ្ចូលយើងដល់ពាក្យថា **បណ្ដាញ RNN ច្រើនស្រទាប់** ដែលមានពីរឬច្រើនបណ្ដាញបញ្ចូល ដែលលទ្ធផលអំពីស្រទាប់មុន ត្រូវបានផ្គត់ផ្គង់ទៅស្រទាប់បន្ទាប់ជាបញ្ចូល។
![Image showing a Multilayer long-short-term-memory- RNN](../../../../../translated_images/km/multi-layer-lstm.dd975e29bb2a59fe.webp)
*រូបភាព​ពី [អត្ថបទដ៏អស្ចារ្យនេះ](https://towardsdatascience.com/from-a-lstm-cell-to-a-multilayer-lstm-network-with-pytorch-2899eb5696f3) ដោយ Fernando López*
## ✍️ កិច្ចការអនុវត្ត៖ Embeddings
បន្តការរៀនរបស់អ្នកនៅក្នុងសៀវភៅដំណើរការខាងក្រោម៖
* [RNNs ជាមួយ PyTorch](RNNPyTorch.ipynb)
* [RNNs ជាមួយ TensorFlow](RNNTF.ipynb)
## សង្ខេប
នៅក្នុងផ្នែកនេះ យើងបានឃើញថា RNN អាចត្រូវបានប្រើសម្រាប់ចំណាត់ថ្នាក់លំដាប់ ប៉ុន្តែនៅពិតវាអាចដោះស្រាយបញ្ហាច្រើនទៀតដូចជា ការបង្កើតអត្ថបទ ការប្រែសម្រួលម៉ាស៊ីន និងផ្សេងៗទៀត។ យើងនឹងពិចារណានូវបញ្ហានោះនៅផ្នែកបន្ទាប់។
## 🚀 តេស្តសាកល្បង
អានឯកសារមួយចំនួនអំពី LSTM និងពិចារណនេះក្នុងការអនុវត្ត៖
- [Grid Long Short-Term Memory](https://arxiv.org/pdf/1507.01526v1.pdf)
- [Show, Attend and Tell: Neural Image Caption
Generation with Visual Attention](https://arxiv.org/pdf/1502.03044v2.pdf)
## [សំណួរប្រឡងបន្ទាប់ពីសិក្សា](https://ff-quizzes.netlify.app/en/ai/quiz/32)
## ការត្រួតពិនិត្យ និងរៀនដោយខ្លួនឯង
- [Understanding LSTM Networks](https://colah.github.io/posts/2015-08-Understanding-LSTMs/) ដោយ Christopher Olah។
## [កិច្ចការជាសៀវភៅ](assignment.md)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការបញ្ជាក់**៖
ឯកសារនេះត្រូវបានបម្លែងភាសាដោយប្រើសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពួកយើងខិតខំរកភាពត្រឹមត្រូវ សូមយល់ដឹងថា ការបកប្រែដោយស្វ័យប្រវត្តិស័ព្ទអាចមានកំហុសឬភាពមិនច្បាស់លាស់។ ឯកសារដើមក្នុងភាសាមាតុភូមិគួរត្រូវបានគិតជារឿងដ៏មានអំណាចជាឯកសារដើម។ សម្រាប់ព័ត៌មានសំខាន់ៗ សូមណែនាំឲ្យប្រើបកប្រែដោយមនុស្សជំនាញ។ ពួកយើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកស្រាយឆ្គងណាមួយដែលផុសចេញពីការប្រើប្រាស់ការបកប្រែនេះទេ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,479 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# បណ្តាញខួរក្បាលសត្វពីរដង\n",
"\n",
"នៅក្នុងមូឌុលមុននេះ យើងបានប្រើប្រាស់តំណាងអត្ថន័យសំបូររបស់អត្ថបទ និងកូនម៉ាស៊ីនចាត់ថ្នាក់រេច<E19F81>rប់លើបន្ទាត់លើបន្ថែម។ វិ​ស្ថា​នីយ​បា​នេះ​ធ្វើ​ឲ្យ​ចាប់យក​អត្ថន័យ​សម្រង់​នៃ​ពាក្យ​ក្នុង​ប្រយោគ​មួយ ប៉ុន្តែ​វា​មិនគិត​លំដាប់​នៃ​ពាក្យ​ទេ ពីព្រោះ​ប្រតិបត្តិការបញ្ចូលលើបន្ថែមបានដកអោយព័ត៌មាននេះចេញពីអត្ថបទដើម។ ដោយសារតែម៉ូដែលទាំងនេះមិនអាចនឹកស្រមៃលំដាប់ពាក្យបាន ក៏ពួកវាមិនអាចដោះស្រាយបញ្ហាស្មុគស្មាញឬអវិជ្ជមានជាទូទៅដូចជាការបង្កើតអត្ថបទ ឬការឆ្លើយសំណួរបានទេ។\n",
"\n",
"ដើម្បីចាប់យកអត្ថន័យនៃលំដាប់អត្ថបទ យើងត្រូវតែប្រើប្រាស់ស្ថាបត្យកម្មបណ្តាញខួរក្បាលមួយផ្សេងទៀត ដែលហៅថា **បណ្តាញខួរក្បាលសត្វពីរដង** ឬ RNN។ ក្នុង RNN យើងបញ្ជូនប្រយោគរបស់យើងតាមបណ្តាញមួយសញ្ញាមួយ ពេលហើយបណ្តាញបង្កើត **អារម្មណ៍** មួយ ហើយយើងបញ្ជូនអារម្មណ៍នោះទៅបណ្តាញម្ដងទៀតជាមួយសញ្ញាបន្ទាប់។\n",
"\n",
"<img alt=\"RNN\" src=\"../../../../../translated_images/km/rnn.27f5c29c53d727b5.webp\" width=\"60%\"/>\n",
"\n",
"ដោយឧទាហរណ៍ លំដាប់បញ្ចូលនៃពាក្យ $X_0,\\dots,X_n$ RNN បង្កើតជាលំដាប់ប្លុកបណ្តាញខួរក្បាលហើយហ្វឹកហាត់លំដាប់នេះពីដើមដល់ចប់ដោយប្រើការផ្ទេរវិលក្រោយ។ ប្លុកបណ្តាញនីមួយៗទទួលយកគូ $(X_i,S_i)$ ជាបញ្ចូល ហើយបង្កើត $S_{i+1}$ ជាលទ្ធផល។ អារម្មណ៍ចុងក្រោយ $S_n$ ឬលទ្ធផល $X_n$ ត្រូវបញ្ចូលទៅកាន់កូនម៉ាស៊ីនចាត់ថ្នាក់បន្ទាត់ដើម្បីផលិតលទ្ធផល។ ប្លុកបណ្តាញទាំងអស់មានទម្ងន់ដូចគ្នា ហើយត្រូវបានហ្វឹកហាត់ពីដើមដល់ចប់តាមរយៈការផ្ទេរវិលក្រោយមួយ។\n",
"\n",
"ដោយសារតែវ៉ិចទ័រ​អារម្មណ៍ $S_0,\\dots,S_n$ ត្រូវបានបញ្ជូនតាមបណ្តាញ វាអាចសិក្សាអំពីការទាក់ទងនៅក្នុងលំដាប់រវាងពាក្យបាន។ ឧទាហរណ៍ នៅពេលពាក្យ *not* បង្ហាញនៅកន្លែងណាមួយក្នុងលំដាប់ វាអាចរៀនបដិសេធធាតុខ្លះក្នុងវ៉ិចទ័រ​អារម្មណ៍ បាន ដែលធ្វើឱ្យមានអារម្មណ៍បដិសេធ។\n",
"\n",
"> ដោយសារតែទម្ងន់របស់ប្លុក RNN ទាំងអស់នៅក្នុងរូបភាពត្រូវបានចែករំលែក រូបភាពដូចគ្នាអាចត្រូវបានបង្ហាញជាប្លុកមួយ (នៅខាងស្ដាំ) ដែលមានវដ្តបញ្ចូនត្រឡប់មួយ ដែលបញ្ជូនអារម្មណ៍លទ្ធផលនៃបណ្តាញត្រលប់ទៅបញ្ចូលវិញ។\n",
"\n",
"តោះមើលពីរបៀបដែលបណ្តាញខួរក្បាលសត្វពីរដងអាចជួយយើងបែងចែកថ្នាក់ទិន្នន័យព័ត៌ថ្មីរបស់យើងបានយ៉ាងដូចម្តេច។\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Loading dataset...\n",
"Building vocab...\n"
]
}
],
"source": [
"import torch\n",
"import torchtext\n",
"from torchnlp import *\n",
"train_dataset, test_dataset, classes, vocab = load_dataset()\n",
"vocab_size = len(vocab)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## កម្មវិធីចាត់ថ្នាក់ RNN ងាយស្រួល\n",
"\n",
"ក្នុងករណី RNN ងាយស្រួល ឯកតាដងៗដែលមានការក្រឡេកចម្លើយគឺជាបណ្ដាញបន្ទាត់មួយសាមញ្ញ ដែលទទួលវ៉ិចទ័របញ្ចូលដែលបានបញ្ចូលជាប្រភេទ concatenated និងវ៉ិចទ័រស្ថានភាព ហើយបង្កើតវ៉ិចទ័រស្ថានភាពថ្មី។ PyTorch តំណាងឱ្យឯកតានេះជាមួយថ្នាក់ `RNNCell` ហើយបណ្តាញនៃឯកតាដូចនេះ - ជាស្រទាប់ `RNN`។\n",
"\n",
"ដើម្បីកំណត់កម្មវិធីចាត់ថ្នាក់ RNN មួយ យើងនឹងអនុវត្តស្រទាប់ embedding ដើម្បីបន្ថយវិមាត្រពាក្យវចនានុក្រមបញ្ចូល ហើយបន្ទាប់មកមានស្រទាប់ RNN នៅលើវា៖\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"class RNNClassifier(torch.nn.Module):\n",
" def __init__(self, vocab_size, embed_dim, hidden_dim, num_class):\n",
" super().__init__()\n",
" self.hidden_dim = hidden_dim\n",
" self.embedding = torch.nn.Embedding(vocab_size, embed_dim)\n",
" self.rnn = torch.nn.RNN(embed_dim,hidden_dim,batch_first=True)\n",
" self.fc = torch.nn.Linear(hidden_dim, num_class)\n",
"\n",
" def forward(self, x):\n",
" batch_size = x.size(0)\n",
" x = self.embedding(x)\n",
" x,h = self.rnn(x)\n",
" return self.fc(x.mean(dim=1))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **ចំណាំ:** យើងប្រើស្រទាប់ embedding មិនបានបណ្តុះបណ្តាលនៅទីនេះសម្រាប់ភាពសាមញ្ញ ប៉ុន្តាសម្រាប់លទ្ធផលកាន់តែប្រសើរជាងនេះ យើងអាចប្រើស្រទាប់ embedding ដែលបានបណ្តុះបណ្តាលជាមុនជាមួយ Word2Vec ឬ GloVe embeddings ដូចដែលបានពណ៌នាកន្លងមក។ សម្រាប់ការយល់ដឹងកាន់តែច្បាស់ អ្នកអាចចង់ផ្លាស់ប្តូរកូដនេះឲ្យដំណើរការជាមួយ embeddings ដែលបានបណ្តុះបណ្តាលជាមុន។\n",
"\n",
"ក្នុងករណីរបស់យើង យើងនឹងប្រើអ្នកផ្ទុកទិន្នន័យដែលមានការ padding ដូច្នេះរាល់ថ្មបាច់នីមួយៗនឹងមានចំនួនខ្សែប្រវែងដូចគ្នា។ ស្រទាប់ RNN នឹងទទួលខ្សែប្រវែងនៃតង់ស័រអ៊ំប៊ែិត្ត ហើយផ្ដល់លទ្ធផលពីរយ៉ាង៖\n",
"* $x$ គឺជាខ្សែប្រវែងនៃលទ្ធផលកោសិកា RNN ក្នុងគ្រប់ជំហាន\n",
"* $h$ គឺជា រដ្ឋភាពលាក់ចុងក្រោយ សម្រាប់ធាតុខ្ទង់ចុងក្រោយនៃខ្សែប្រវែង\n",
"\n",
"បន្ទាប់មក យើងអនុវត្តកំណត់ចំណាត់ថ្នាក់បន្ទាត់ដែលភ្ជាប់ពេញលេញ ដើម្បីទទួលចំនួនថ្នាក់។\n",
"\n",
"> **ចំណាំ:** RNNs គឺពិបាកក្នុងការបណ្តុះបណ្តាលហើយ ពីព្រោះเมื่อកោសិកា RNN ត្រូវបានបង្ហាញក្នុងខ្សែប្រវែង តុល្យភាពចំនួនស្រទាប់ដែលចូលរួមក្នុងការធ្វើប្រតិកម្មបន្ទាប់ក្រោយគឺច្រើនខ្លាំង។ ដូច្នេះយើងត្រូវជ្រើសរើសអត្រាសិក្សាចំនួនតូច ហើយបណ្តុះបណ្តាលបណ្ដាញលើឯកសារទិន្នន័យធំដើម្បី ផលិតលទ្ធផលល្អ។ វាអាចយកពេលយូរអង្វែង ដូច្នេះការប្រើប្រាស់ GPU ត្រូវបានអនុសាសន៍។\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3200: acc=0.3090625\n",
"6400: acc=0.38921875\n",
"9600: acc=0.4590625\n",
"12800: acc=0.511953125\n",
"16000: acc=0.5506875\n",
"19200: acc=0.57921875\n",
"22400: acc=0.6070089285714285\n",
"25600: acc=0.6304296875\n",
"28800: acc=0.6484027777777778\n",
"32000: acc=0.66509375\n",
"35200: acc=0.6790056818181818\n",
"38400: acc=0.6929166666666666\n",
"41600: acc=0.7035817307692308\n",
"44800: acc=0.7137276785714286\n",
"48000: acc=0.72225\n",
"51200: acc=0.73001953125\n",
"54400: acc=0.7372794117647059\n",
"57600: acc=0.7436631944444444\n",
"60800: acc=0.7503947368421052\n",
"64000: acc=0.75634375\n",
"67200: acc=0.7615773809523809\n",
"70400: acc=0.7662642045454545\n",
"73600: acc=0.7708423913043478\n",
"76800: acc=0.7751822916666666\n",
"80000: acc=0.7790625\n",
"83200: acc=0.7825\n",
"86400: acc=0.7858564814814815\n",
"89600: acc=0.7890513392857142\n",
"92800: acc=0.7920474137931034\n",
"96000: acc=0.7952708333333334\n",
"99200: acc=0.7982258064516129\n",
"102400: acc=0.80099609375\n",
"105600: acc=0.8037594696969697\n",
"108800: acc=0.8060569852941176\n"
]
}
],
"source": [
"train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=16, collate_fn=padify, shuffle=True)\n",
"net = RNNClassifier(vocab_size,64,32,len(classes)).to(device)\n",
"train_epoch(net,train_loader, lr=0.001)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## កម្មវិធីរំលងអង្រួនខ្លី (LSTM)\n",
"\n",
"បញ្ហាសំខាន់មួយនៃ RNN ចាស់ៗគឺបញ្ហាដែលបានហៅថា **vanishing gradients**។ ដោយសារតែ RNN ត្រូវបណ្តុះបណ្តាលពីដើមទៅចុងតាមរយៈការផ្ទេរសារត្រឡប់មួយដង វាជួបប្រទៈនឹងការលំបាកក្នុងការផ្ទេរព្យាករណ៍​បញ្ហាទៅកាន់ស្រទាប់ដើមនៃបណ្តាញ ហេតុនេះបណ្តាញមិនអាចរៀនទំនាក់ទំនងរវាងតូកុនដែលឆ្ងាយបានទេ។ មួយក្នុងចំណោមវិធីដើម្បីជៀសវាងបញ្ហានេះគឺការណែនាំ **ការគ្រប់គ្រងស្ថិតិوض្ធពិត** ដោយប្រើអ្វីដែលហៅថា **ទ្វារ (gates)**។ មានរចនាសម្ព័ន្ធពីរដែលគេស្គាល់ច្បាស់ជាងគេសម្រាប់ប្រភេទនេះគឺ **ការចងចាំរយៈពេលខ្លីយូរ (Long Short Term Memory)** (LSTM) និង **Gated Relay Unit** (GRU)។\n",
"\n",
"![Image showing an example long short term memory cell](../../../../../lessons/5-NLP/16-RNN/images/long-short-term-memory-cell.svg)\n",
"\n",
"បណ្តាញ LSTM ត្រូវបានរៀបចំភាពដូចនឹង RNN ប៉ុន្តែមានស្ថានភាពពីរដែលត្រូវបញ្ជូនពីស្រទាប់ទៅស្រទាប់គឺស្ថានភាពពិត $c$ និងវ៉ិចទ័រលាក់ $h$។ នៅក្នុងគ្រប់ផ្នែកមួយ, វ៉ិចទ័រលាក់ $h_i$ ត្រូវបានបញ្ចូលជាមួយនឹងបញ្ជូល $x_i$ ហើយពួកវាគ្រប់គ្រងពីមានអ្វីកើតឡើងចំពោះស្ថានភាព $c$ តាមរយៈ **ទ្វារ (gates)**។ ទ្វារនីមួយៗគឺជាបណ្តាញប្រភេទណឺរ៉លដែលមានសកម្មភាព sigmoid (ផលចេញនៅចន្លោះ $[0,1]$) ដែលអាចគិតជាម៉ាសចុចប៊ីតប៉ុន្មានពេលគុណជាមួយវ៉ិចទ័រស្ថានភាព។ មានទ្វារដូចខាងក្រោម (ពីឆ្វេងទៅស្ដាំនៅក្នុងរូបភាពខាងលើ):\n",
"* **ទ្វារលុបចោល (forget gate)** កាន់កាប់វ៉ិចទ័រលាក់ ហើយកំណត់មាត្រដ្ឋានណានៃវ៉ិចទ័រ $c$ ដែលយើងត្រូវលុបចោល និងណាដែលត្រូវបញ្ជូនតាមចូល។\n",
"* **ទ្វារបញ្ចូល (input gate)** ទទួលបានព័ត៌មានពីបញ្ចូលនិងវ៉ិចទ័រលាក់ ហើយបញ្ចូលវាទៅក្នុងស្ថានភាព។\n",
"* **ទ្វារចេញ (output gate)** បម្លែងស្ថានភាពតាមរយៈស្រទាប់ប៉ារ៉ាឡែលជាមួយសកម្មភាព $\\tanh$ បន្ទាប់មកជ្រើសរើសមួយចំនួននៃមាត្រដ្ឋានរបស់វា ដោយប្រើវ៉ិចទ័រលាក់ $h_i$ ដើម្បីបញ្ចេញស្ថានភាពថ្មី $c_{i+1}$។\n",
"\n",
"មាត្រដ្ឋាននៃស្ថានភាព $c$ អាចគិតបានជាផ្លាកខ្លះៗដែលអាចបិទបិទ និងបើកបាន។ ឧទាហរណ៍, នៅពេលយើងជួបឈ្មោះ *Alice* ក្នុងខ្សែអក្សរ, យើងអាចចង់សន្មតថាវាសំដៅដល់តួអក្សរនារី ហើយលើកផ្លាកក្នុងស្ថានភាពថាយើងមាននាមស្រីក្នុងវាក្យបញ្ជា។ នៅពេលពួកយើងជួបប្រកាស *and Tom* យើងនឹងលើកផ្លាកថាយើងមាននាមពហុ។ ដូច្នេះដោយការគ្រប់គ្រងស្ថានភាពយើងអាចរក្សាទុកគុណលក្ខណៈវេយ្យាករណ៍នៃផ្នែកវាក្យបាន។\n",
"\n",
"> **ចំណាំ**: អត្ថបទដ៏ល្អសម្រាប់យល់ពីរចនាសម្ព័ន្ធខាងក្នុងនៃ LSTM គឺអត្ថបទល្អនេះ [Understanding LSTM Networks](https://colah.github.io/posts/2015-08-Understanding-LSTMs/) ដោយ Christopher Olah។\n",
"\n",
"ខណៈដែលរចនាសម្ព័ន្ធខាងក្នុងនៃកោសិកា LSTM អាចមើលទៅស្មុគស្មាញ, PyTorch យកការអនុវត្តនេះលាក់នៅក្នុងថ្នាក់ `LSTMCell` ហើយផ្តល់អOBJECT `LSTM` សម្រាប់តំណាងស្រទាប់ LSTM ពេញលេញ។ ដូច្នេះ ការអនុវត្តន៍អ្នកចាត់ថ្នាក់ LSTM នឹងខុសគ្នានៅតែមានមូលដ្ឋានដូច RNN សាមញ្ញដែលយើងបានឃើញខាងលើ៖\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"class LSTMClassifier(torch.nn.Module):\n",
" def __init__(self, vocab_size, embed_dim, hidden_dim, num_class):\n",
" super().__init__()\n",
" self.hidden_dim = hidden_dim\n",
" self.embedding = torch.nn.Embedding(vocab_size, embed_dim)\n",
" self.embedding.weight.data = torch.randn_like(self.embedding.weight.data)-0.5\n",
" self.rnn = torch.nn.LSTM(embed_dim,hidden_dim,batch_first=True)\n",
" self.fc = torch.nn.Linear(hidden_dim, num_class)\n",
"\n",
" def forward(self, x):\n",
" batch_size = x.size(0)\n",
" x = self.embedding(x)\n",
" x,(h,c) = self.rnn(x)\n",
" return self.fc(h[-1])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ឥឡូវនេះសូមបណ្ដុះបណ្ដាលបណ្តាញរបស់យើង។ សូមចំណាំថាការបណ្ដុះបណ្ដាល LSTM ក៏យឺតដូចគ្នា ហើយអ្នកប្រហែលជាចាត់ទុកមិនមែនមានកម្រិតភាពត្រឹមត្រូវកើនឡើងច្រើននៅដើមនៃការបណ្ដុះបណ្ដាលឡើយ។ លើសពីនេះ អ្នកប្រហែលជាត្រូវតែជាមួយនឹងប៉ារ៉ាម៉ែត្រ `lr` នូវអត្រាការសិក្សាដើម្បីស្វែងរកអត្រាការសិក្សាដែលធ្វើឱ្យមានល្បឿនការបណ្ដុះបណ្ដាលសមរម្យ ហើយនៅមិនបង្ករឱ្យសារជាតិអង្គចងចាំស្តុកច្រើនពេកឡើយ។\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3200: acc=0.259375\n",
"6400: acc=0.25859375\n",
"9600: acc=0.26177083333333334\n",
"12800: acc=0.2784375\n",
"16000: acc=0.313\n",
"19200: acc=0.3528645833333333\n",
"22400: acc=0.3965625\n",
"25600: acc=0.4385546875\n",
"28800: acc=0.4752777777777778\n",
"32000: acc=0.505375\n",
"35200: acc=0.5326704545454546\n",
"38400: acc=0.5557552083333334\n",
"41600: acc=0.5760817307692307\n",
"44800: acc=0.5954910714285714\n",
"48000: acc=0.6118333333333333\n",
"51200: acc=0.62681640625\n",
"54400: acc=0.6404779411764706\n",
"57600: acc=0.6520138888888889\n",
"60800: acc=0.662828947368421\n",
"64000: acc=0.673546875\n",
"67200: acc=0.6831547619047619\n",
"70400: acc=0.6917897727272727\n",
"73600: acc=0.6997146739130434\n",
"76800: acc=0.707109375\n",
"80000: acc=0.714075\n",
"83200: acc=0.7209134615384616\n",
"86400: acc=0.727037037037037\n",
"89600: acc=0.7326674107142858\n",
"92800: acc=0.7379633620689655\n",
"96000: acc=0.7433645833333333\n",
"99200: acc=0.7479032258064516\n",
"102400: acc=0.752119140625\n",
"105600: acc=0.7562405303030303\n",
"108800: acc=0.76015625\n",
"112000: acc=0.7641339285714286\n",
"115200: acc=0.7677777777777778\n",
"118400: acc=0.7711233108108108\n"
]
},
{
"data": {
"text/plain": [
"(0.03487814127604167, 0.7728)"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"net = LSTMClassifier(vocab_size,64,32,len(classes)).to(device)\n",
"train_epoch(net,train_loader, lr=0.001)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ស្វ៊ីស៊ីសលៃត់ដាក់ជាបញ្ចុះ\n",
"\n",
"ក្នុងឧទាហរណ៍របស់យើង យើងត្រូវតែបន្ថែមពណ៌តំណាងសូន្យទៅលើស្វ៊ីស៊ីសទាំងអស់នៅក្នុងបន្ទប់តូច។ បើទោះបីជាវាកើតមានការចំណាយមេម៉ូរីខ្លះ ក៏ដោយ ជាមួយ RNN វាអ្វីដែលសំខាន់ជាងគឺ កោសិកាទ្រឡប់ទួរយយនន៍បន្ថែមត្រូវបានបង្កើតសម្រាប់ធាតុខ្លក់ដែលបានបន្ថែម, ដែលចូលរួមក្នុងការបណ្តុះបណ្តាល ប៉ុន្ដែមិនមានព័ត៌មានចូលសំខាន់ឡើយ។ វាជាជម្រើសល្អជាងក្នុងការបណ្តុះបណ្តាល RNN ផ្តោតត្រឹមទំហំស្វ៊ីស៊ីសពិតប្រាកដ។\n",
"\n",
"ដើម្បីធ្វើដូចនេះ ដើមទោលសម្រាប់ស្វ៊ីស៊ីសដែលបានបន្ថែមត្រូវបានបង្ហាញជាផ្លូវការនៅក្នុង PyTorch ។ សន្មតថាយើងមានបន្ទប់តូចដែលបានបន្ថែមបែបនេះ៖\n",
"```\n",
"[[1,2,3,4,5],\n",
" [6,7,8,0,0],\n",
" [9,0,0,0,0]]\n",
"```\n",
"ទីនេះ 0 តំណាងឲ្យតម្លៃដែលបានបន្ថែម និងវ៉ិកទ័រវាស់ប្រវែងពិតរបស់ស្វ៊ីស៊ីសបញ្ចូលគឺ `[5,3,1]`។\n",
"\n",
"ដើម្បីបណ្តុះបណ្តាល RNN ជាប្រសិទ្ធភាពជាមួយស្វ៊ីស៊ីសដែលបានបន្ថែមនេះ យើងចង់ចាប់ផ្តើមបណ្តុះកោសិកានៃក្រុម RNN ដំបូងជាមួយបន្ទប់តូចធំហ្នឹង (`[1,6,9]`), បន្ទាប់មកបញ្ចប់ដំណើរការស្វ៊ីសីសទីបី ហើយបន្តបណ្តុះជាមួយបន្ទប់តូចសង្ខេប (`[2,7]`, `[3,8]`), តម្លៃបន្ថែមនិងបន្ត។ ដូច្នេះ ស្វ៊ីស៊ីសដាក់ជាបញ្ចុះត្រូវបានតំណាងជា វ៉ិកទ័រតែមួយ - ក្នុងករណីនេះ `[1,6,9,2,7,3,8,4,5]`, និងវ៉ិកទ័រវាស់ប្រវែង (`[5,3,1]`), ដែលយើងអាចបញ្ចប់ឡើងវិញស្វ៊ីស៊ីសដែលបានបន្ថែមដើម។\n",
"\n",
"ដើម្បីផលិតស្វ៊ីស៊ីសដែលបានបញ្ចុះ អ្នកអាចប្រើមុខងារ `torch.nn.utils.rnn.pack_padded_sequence` ។ ស្រទាប់ដែលមានដំណើរការជារឿយៗទាំងអស់ រួមមាន RNN, LSTM និង GRU គាំទ្រស្វ៊ីស៊ីសដែលបានបញ្ចុះជាការបញ្ចូល ហើយបង្កើតស្វ៊ីស៊ីសដែលបានបញ្ចុះជាបញ្ចេញ ដែលអាចបកប្រែបានដោយប្រើ `torch.nn.utils.rnn.pad_packed_sequence`។\n",
"\n",
"ដើម្បីអាចផលិតស្វ៊ីស៊ីសដែលបានបញ្ចុះ យើងត្រូវផ្តល់វ៉ិកទ័រវាស់ប្រវែងទៅកាន់បណ្តាញ ហើយដូច្នេះយើងត្រូវការមុខងារផ្សេងទៀតក្នុងការរៀបចំបន្ទប់តូច៖\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"def pad_length(b):\n",
" # build vectorized sequence\n",
" v = [encode(x[1]) for x in b]\n",
" # compute max length of a sequence in this minibatch and length sequence itself\n",
" len_seq = list(map(len,v))\n",
" l = max(len_seq)\n",
" return ( # tuple of three tensors - labels, padded features, length sequence\n",
" torch.LongTensor([t[0]-1 for t in b]),\n",
" torch.stack([torch.nn.functional.pad(torch.tensor(t),(0,l-len(t)),mode='constant',value=0) for t in v]),\n",
" torch.tensor(len_seq)\n",
" )\n",
"\n",
"train_loader_len = torch.utils.data.DataLoader(train_dataset, batch_size=16, collate_fn=pad_length, shuffle=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"បណ្តាញពិតប្រាកដនឹងមានលក្ខណៈស្រដៀងគ្នាជាមួយ `LSTMClassifier` ដែលបានរៀបរាប់ខាងលើ ប៉ុន្តែ `forward` pass នឹងទទួលបានទាំង minibatch ដែលបានបំពង់ និងវ៉ិចទ័រជាមួយប្រវែងរបស់រលកត(sequence lengths)។ បន្ទាប់ពីគណនាការបញ្ចូល (embedding) យើងគណនារលកជាកញ្ចប់ (packed sequence) បញ្ជូនវាទៅឲ្យស្រទាប់ LSTM ហើយបន្ទាប់មកដោះបញ្ចប់លទ្ធផលវិញ។\n",
"\n",
"> **បញ្ជាក់**: ជាក់ស្ដែងយើងមិនប្រើលទ្ធផលដែលបានដោះបញ្ចប់ `x` ទេ ពីព្រោះយើងប្រើលទ្ធផលពីស្រទាប់លាក់ក្នុងការគណនាតាមក្រោយ។ ដូច្នេះ យើងអាចលុបការដោះបញ្ចប់ចេញពីកូដនេះបានមិនបញ្ចេញទេ។ មូលហេតុដែលយើងដាក់វា​នៅទីនេះ គឺដើម្បីឲ្យអ្នកអាចកែប្រែកូដនេះបានយ៉ាងងាយស្រួល ប្រសិនបើអ្នកត្រូវការប្រើលទ្ធផលបណ្តាញនៅក្នុងការគណនាផ្សេងទៀត។\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"class LSTMPackClassifier(torch.nn.Module):\n",
" def __init__(self, vocab_size, embed_dim, hidden_dim, num_class):\n",
" super().__init__()\n",
" self.hidden_dim = hidden_dim\n",
" self.embedding = torch.nn.Embedding(vocab_size, embed_dim)\n",
" self.embedding.weight.data = torch.randn_like(self.embedding.weight.data)-0.5\n",
" self.rnn = torch.nn.LSTM(embed_dim,hidden_dim,batch_first=True)\n",
" self.fc = torch.nn.Linear(hidden_dim, num_class)\n",
"\n",
" def forward(self, x, lengths):\n",
" batch_size = x.size(0)\n",
" x = self.embedding(x)\n",
" pad_x = torch.nn.utils.rnn.pack_padded_sequence(x,lengths,batch_first=True,enforce_sorted=False)\n",
" pad_x,(h,c) = self.rnn(pad_x)\n",
" x, _ = torch.nn.utils.rnn.pad_packed_sequence(pad_x,batch_first=True)\n",
" return self.fc(h[-1])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ឥឡូវនេះចើងធ្វើការបណ្តុះបណ្តាល:\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"3200: acc=0.285625\n",
"6400: acc=0.33359375\n",
"9600: acc=0.3876041666666667\n",
"12800: acc=0.44078125\n",
"16000: acc=0.4825\n",
"19200: acc=0.5235416666666667\n",
"22400: acc=0.5559821428571429\n",
"25600: acc=0.58609375\n",
"28800: acc=0.6116666666666667\n",
"32000: acc=0.63340625\n",
"35200: acc=0.6525284090909091\n",
"38400: acc=0.668515625\n",
"41600: acc=0.6822596153846154\n",
"44800: acc=0.6948214285714286\n",
"48000: acc=0.7052708333333333\n",
"51200: acc=0.71521484375\n",
"54400: acc=0.7239889705882353\n",
"57600: acc=0.7315277777777778\n",
"60800: acc=0.7388486842105263\n",
"64000: acc=0.74571875\n",
"67200: acc=0.7518303571428572\n",
"70400: acc=0.7576988636363636\n",
"73600: acc=0.7628940217391305\n",
"76800: acc=0.7681510416666667\n",
"80000: acc=0.7728125\n",
"83200: acc=0.7772235576923077\n",
"86400: acc=0.7815393518518519\n",
"89600: acc=0.7857700892857142\n",
"92800: acc=0.7895043103448276\n",
"96000: acc=0.7930520833333333\n",
"99200: acc=0.7959072580645161\n",
"102400: acc=0.798994140625\n",
"105600: acc=0.802064393939394\n",
"108800: acc=0.8051378676470589\n",
"112000: acc=0.8077857142857143\n",
"115200: acc=0.8104600694444445\n",
"118400: acc=0.8128293918918919\n"
]
},
{
"data": {
"text/plain": [
"(0.029785829671223958, 0.8138166666666666)"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"net = LSTMPackClassifier(vocab_size,64,32,len(classes)).to(device)\n",
"train_epoch_emb(net,train_loader_len, lr=0.001,use_pack_sequence=True)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **ចំណាំ៖** អ្នកប្រហែលជាបានសម្គាល់ពីប៉ារ៉ាម៉ែត្រ `use_pack_sequence` ដែលយើងបញ្ចូនទៅឲ្យហ្វังก์សិនហ្វឹកហាត់។ សព្វថ្ងៃ, ហ្វังก์សិន `pack_padded_sequence` ត្រូវការថង់អង្កត់វែងលំដាប់លំដោយស្ថិតនៅលើឧបករណ៍ CPU ហើយដូច្នេះហ្វังก์សិនហ្វឹកហាត់ត្រូវជៀសវាងការផ្លាស់ទីទិន្នន័យអង្កត់វែងលំដាប់ទៅ GPU ពេលហ្វឹកហាត់។ អ្នកអាចមើលការអនុវត្តន៍នៃហ្វังก์សិន `train_emb` នៅក្នុងឯកសារ [`torchnlp.py`](../../../../../lessons/5-NLP/16-RNN/torchnlp.py) ។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## បណ្ដើរពីរចំណុច និង RNN ដែលមានបណ្ដាប់ជាច្រើនស្រទាប់\n",
"\n",
"ក្នុងឧទាហរណ៍របស់យើង បណ្តា របួសវិលជុំគឺ បើកដំណើរការនៅតែមួយទិសពីដើមទៅចុងសមាគម។ វាហាក់ដូចជា​ធម្មតា ពីព្រោះវាស្រដៀងនឹងវិធីដែលយើងអាន និងស្តាប់សុន្ទរកថា។ ក្រៅពីនេះ ព្រោះក្នុងករណីជាច្រើន ដំណើរការប្រតិបត្តិការចូលចិត្ដមានការចូលដំណើរការលំដាប់ពីរ ឬមួយ ហើយវាអាចមានប្រសិទ្ធិភាពក្នុងការរត់ការគណនាវិលជុំទាំងពីរទិស។ បណ្តាញបែបនេះហៅថា **RNN បណ្ដោយទិសពីរទិស** ហើយអាចបង្កើតបានដោយផ្ញើប៉ារ៉ាម៉ែត្រ `bidirectional=True` ទៅកាន់កម្មវិធីបង្កើត RNN/LSTM/GRU។\n",
"\n",
"ពេលនៅជាមួយបណ្តាញបណ្ដោយទិសពីរទិស យើងត្រូវការវិចទ័រជាប់ស្ព័រចំរាំងពីរជាន់ សម្រាប់បណ្តោយទិសនីមួយៗ។ PyTorch កំណត់កូដវិចទ័រទាំងនេះជាវិចទ័រមួយដែលមានទំហំធំពីរដង ដែលជារឿងងាយស្រួល ព្រោះអ្នកធម្មតានឹងផ្ញើស្ព័រចំរាំងនេះទៅជាស្រទាប់រាប់បញ្ចូលការគណនា ដែលអ្នកគ្រាន់តែត្រូវគិតទំហំដែលបានបន្ថែមនេះពេលបង្កើតស្រទាប់។\n",
"\n",
"បណ្តាញវិលជុំ មិនថាធ្វើការជាតិស្រទាប់ទ្វេគឺ ឬបណ្ដោយទិសពីរទិស ពួកវាចាប់យកលំនាំករណីនៅក្នុងសមាគមមួយ ហើយអាចរក្សាទុកជាវិចទ័រស្ថានភាព ឬបញ្ជូនទៅលទ្ធផល។ ដូចជាបណ្ដាញបន្លាស់អាំងគោណវេស៊ីយ៉ុង យើងអាចបង្កើតស្រទាប់វិលជុំថ្មីលើស្រទាប់ដំបូង ដើម្បីចាប់យកលំនាំកម្រិតខ្ពស់ ជារូបមន្តពីលំនាំកម្រិតទាបដែលត្រូវបានដកស្រង់ជាស្រទាប់ដំបូង។ នេះនាំឱ្យយើងយល់ដឹងពីយោបល់នៃ **RNN មួយចំណុចជាច្រើនស្រទាប់** ដែលមានបណ្តារបណ្តាញវិលជុំពីរឬច្រើនជាន់ ដែលលទ្ធផលរបស់ស្រទាប់មុនត្រូវបានផ្ញើឱ្យស្រទាប់បន្ទាប់ជាកាណ្តាល។\n",
"\n",
"![រូបភាពបង្ហាញ RNN មួយចំណុចជាច្រើនស្រទាប់ខ្សែជីវិតក្រោម-ខ្លី](../../../../../translated_images/km/multi-layer-lstm.dd975e29bb2a59fe.webp)\n",
"\n",
"*រូបថតពី [អត្ថបទអស្ចារ្យនេះ](https://towardsdatascience.com/from-a-lstm-cell-to-a-multilayer-lstm-network-with-pytorch-2899eb5696f3) ដោយ Fernando López*\n",
"\n",
"PyTorch ធ្វើឱ្យការបង្កើតបណ្តាញបែបនេះកាន់តែងាយស្រួល ព្រោះអ្នកគ្រាន់តែផ្ញើប៉ារ៉ាម៉ែត្រ `num_layers` ទៅកម្មវិធីបង្កើត RNN/LSTM/GRU ដើម្បីសង់ស្រទាប់វិលជុំជាច្រើនដោយស្វ័យប្រវត្តិ។ នេះមានន័យថាទំហំវិចទ័រស្ថានភាពនឹងកើនឡើងឡើងទៅផងដែរ ហើយអ្នកត្រូវគិតពីបន្តកើននេះពេលគ្រប់គ្រងលទ្ធផលនៃស្រទាប់វិលជុំ។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## RNNs សម្រាប់កិច្ចការផ្សេងទៀត\n",
"\n",
"នៅក្នុងឯកតានេះ យើងបានឃើញថា RNNs អាចត្រូវបានប្រើសម្រាប់ចាត់ថ្នាក់លំហាត់ តែក្រៅពីនេះ ពួកវាអាចដោះស្រាយកិច្ចការច្រើនទៀត អោយដូចជាការបង្កើតអត្ថបទ ការបកប្រែម៉ាស៊ីន និងផ្សេងទៀត។ យើងនឹងពិចារណាកិច្ចការទាំងនោះនៅក្នុងឯកតាខាងមុខ។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**ការបដិសេធ**៖ \nឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ទោះបីយើងខិតខំបំផុតសម្រាប់ភាពត្រឹមត្រូវ ក៏សូមសម្គាល់ថាការបកប្រែដោយស្វ័យប្រវត្តិក្នុងករណីខ្លះអាចមានកំហុស ឬមិនត្រឹមត្រូវ។ ឯកសារដើមជាភាសាដើមគួរត្រូវបានពិចារណាថាជាដើមទុក្ខត្រឹមត្រូវ។ សម្រាប់ព័ត៌មានសំខាន់ៗ សូមណែនាំឱ្យប្រើការបកប្រែដោយអ្នកមានជំនាញផ្នែកមនុស្ស។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកប្រែខុសពីការប្រើប្រាស់ការបកប្រែនេះឡើយ។\n<!-- CO-OP TRANSLATOR DISCLAIMER END -->\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "16af2a8bbb083ea23e5e41c7f5787656b2ce26968575d8763f2c4b17f9cd711f"
},
"kernelspec": {
"display_name": "Python 3.8.12 ('py38')",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.12"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@ -0,0 +1,456 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# បណ្តាញសរសៃទន្និនយន្តវិញ្ញាបនបត្រ\n",
"\n",
"នៅក្នុងម៉ូឌុលមុន យើងបានគ្របដណ្តប់លើការតំណាងន័យសម្បូរបែបនៃអត្ថបទ។ រចនាសម្ព័ន្ធដែលយើងបានប្រើប្រាស់ចាប់យកន័យសរុបនៃពាក្យនៅក្នុងប្រយោគមួយ ប៉ុន្តែមិនបានគិតទុកនូវ **លំដាប់** នៃពាក្យទេ ព្រោះប្រតិបត្តិការប្រមូលបញ្ចូលដែលត្រូវបានអនុវត្តបន្ទាប់ពីការបញ្ចូលព័ត៌មានលម្អិតបានយកព័ត៌មាននេះចេញពីអត្ថបទដើម។ ដោយសារថាតំណាងទាំងនេះមិនអាចបង្ហាញលំដាប់ពាក្យបាន ពួកវាដូចជាមិនអាចដោះស្រាយបញ្ហាស្មុគស្មាញ ឬបញ្ហាដែលមានភាពច្របូកច្របល់ដូចជា ការបង្កើតអត្ថបទ ឬការឆ្លើយសំណួរ។\n",
"\n",
"ដើម្បីចាប់យកន័យនៃខ្សែអក្សរមួយ យើងនឹងប្រើរចនាសម្ព័ន្ធបណ្តាញសរសៃទន្និនដែលហៅថា **បណ្តាញសរសៃទន្និនយន្តវិញ្ញាណបត្រ**, ឬ RNN។ ការប្រើប្រាស់ RNN គឺ យើងផ្ញើប្រយោគរបស់យើងឲ្យបណ្តាញមួយដោយយកតែទ្រង់ទ្រាយមួយភាគតូចក្នុងពេលណាមួយ ហើយបណ្តាញនោះបញ្ចេញ **ស្ថានភាព** មួយ ដែលយើងបន្ទាប់មកផ្ញើត្រឡប់ទៅបណ្តាញវិញជាមួយភាគតូចបន្ទាប់។\n",
"\n",
"![រូបភាពបង្ហាញឧទាហរណ៍នៃការបង្កើតបណ្តាញសរសៃទន្និនយន្តវិញ្ញាណបត្រ។](../../../../../translated_images/km/rnn.27f5c29c53d727b5.webp)\n",
"\n",
"ដោយអនុវត្តលំដាប់នៃទ្រង់ទ្រាយ $X_0,\\dots,X_n$, RNN បង្កើតជាលំដាប់នៃប្លុកបណ្តាញសរសៃទន្និនយន្តវិញ្ញាណបត្រ ហើយបង្រៀនលំដាប់នេះពីដើមដល់ចប់ដោយប្រើការបត់បញ្ច្រាសតាមវិលក្រោយ។ ប្លុកបណ្តាញនីមួយៗទទួលគូ $(X_i,S_i)$ ជាកាន់ការបញ្ចូល ហើយបង្ហាញ $S_{i+1}$ ជាលទ្ធផល។ ស្ថានភាពចុងក្រោយ $S_n$ ឬលទ្ធផល $Y_n$ ត្រូវបានដាក់ចូលទៅក្នុងម៉ាស៊ីនចាត់ថ្នាក់បែបអញ្ញើញរកលទ្ធផល។ ប្លុកបណ្តាញទាំងអស់ចែករំលែកទម្ងន់ដូចគ្នា ហើយបានបង្រៀនពីដើមដល់ចប់ដោយបង្វិលតែមួយ។\n",
"\n",
"> រូបភាពខាងលើបង្ហាញបណ្តាញសរសៃទន្និនយន្តវិញ្ញាណបត្រ នៅក្នុងទម្រង់បម៉ោងប្រែរបិទ (នៅខាងឆ្វេង) និងទម្រង់តំណាងបណ្តាញសរសៃទន្និនប្រមូល (នៅខាងស្ដាំ)។ វាសំខាន់ក្នុងការយល់ថា កោសិកា RNN ទាំងអស់មាន **ទម្ងន់ដែលអាចចែករំលែក** ដូចគ្នា។\n",
"\n",
"ដោយសារvectorស្ថានភាព $S_0,\\dots,S_n$ ត្រូវបានបញ្ជូនតាមបណ្តាញ RNN អាចរៀនពាក់ព័ន្ធតាមលំដាប់រវាងពាក្យបាន។ ឧទាហរណ៍ កាលណាពាក្យ *not* បង្ហាញនៅខាងមួយក្នុងលំដាប់ វាអាចរៀនច្រានចោលធាតុខ្លះនៅលើវ៉ិចទ័រស្ថានភាព។\n",
"\n",
"ខាងក្នុង អ្នកលេងកោសិកា RNN ម្នាក់នីមួយៗមានម៉ាទ្រីសទម្ងន់ពីរ ដូចជា $W_H$ និង $W_I$ និងផ្ទុក bias $b$។ នៅជំហាន RNN នីមួយៗ យើងមានបញ្ចូល $X_i$ និងស្ថានភាពបញ្ចូល $S_i$ ស្ថានភាពចេញលោកគិតដោយ $S_{i+1} = f(W_H\\times S_i + W_I\\times X_i+b)$ ដែល $f$ ជាអនុគមន៍បំលែង (ជាទូទៅជារាង $\\tanh$)។\n",
"\n",
"> សម្រាប់បញ្ហាដូចជា ការបង្កើតអត្ថបទ (ដែលយើងនឹងគ្របដណ្តប់ក្នុងឯកត្តបន្ទាប់) ឬបកប្រែម៉ាស៊ីន យើងក៏ចង់បានតម្លៃលទ្ធផលនៅរៀងរាល់ជំហាន RNN ផងដែរ។ ក្នុងករណីនេះ មានម៉ាទ្រីសមួយទៀតគឺ $W_O$ ហើយលទ្ធផលគិតថា $Y_i=f(W_O\\times S_i+b_O)$។\n",
"\n",
"ចង់ឲ្យមើលថាបណ្តាញសរសៃទន្និនយន្តវិញ្ញាណបត្រ អាចជួយយើងចាត់ថ្នាក់ពីកម្រិតទិន្នន័យព័ត៌មានថ្មីបានយ៉ាងដូចម្តេច។\n",
"\n",
"> សម្រាប់បរិវេណ sandbox យើងត្រូវរត់កូដខាងក្រោម ដើម្បីធានាថាចែកចាយបណ្ណាល័យត្រូវបានដំឡើង និងទិន្នន័យត្រូវបានទាញយកមុន។ បើអ្នករត់នៅលើកុំព្យូទ័រផ្ទាល់ខ្លួន អ្នកអាចរំលងកូដខាងក្រោម។\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import sys\n",
"!{sys.executable} -m pip install --quiet tensorflow_datasets==4.4.0\n",
"!cd ~ && wget -q -O - https://mslearntensorflowlp.blob.core.windows.net/data/tfds-ag-news.tgz | tar xz"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import tensorflow as tf\n",
"from tensorflow import keras\n",
"import tensorflow_datasets as tfds\n",
"import numpy as np\n",
"\n",
"# We are going to be training pretty large models. In order not to face errors, we need\n",
"# to set tensorflow option to grow GPU memory allocation when required\n",
"physical_devices = tf.config.list_physical_devices('GPU') \n",
"if len(physical_devices)>0:\n",
" tf.config.experimental.set_memory_growth(physical_devices[0], True)\n",
"\n",
"ds_train, ds_test = tfds.load('ag_news_subset').values()"
]
},
{
"cell_type": "markdown",
"metadata": {
"nteract": {
"transient": {
"deleting": false
}
}
},
"source": [
"នៅពេលបណ្តុះបណ្តាលម៉ូដែលទំហំធំ ការចំណាយចងចាំ GPU អាចក្លាយទៅជាបញ្ហា។ យើងអាចត្រូវតែសាកល្បងជាមួយទំហំមីនីបាទខុសៗគ្នា ដើម្បីឲ្យទិន្នន័យសម្របសម្រួលក្នុងចងចាំរបស់ GPU របស់យើង ប៉ុន្តែការបណ្តុះបណ្តាលត្រូវបានរហ័សគ្រប់គ្រាន់។ ប្រសិនបើអ្នកកំពុងរត់កូដនេះលើម៉ាស៊ីន GPU ផ្ទាល់របស់អ្នក អ្នកអាចសាកល្បងកែប្រែទំហំមីនីបាទដើម្បីលឿនការបណ្តុះបណ្តាល។\n",
"\n",
"> **Note**: វើស្យុងខ្លះៗនៃអ្នកបើកបរ NVidia ត្រូវបានគេដឹងថាមិនបញ្ចេញចងចាំបន្ទាប់ពីបណ្តុះបណ្តាលម៉ូដែលឡើយ។ យើងកំពុងរត់ឧទាហរណ៍ជាច្រើនក្នុងសៀវភៅកំណត់ត្រានេះ ហើយវាអាចបណ្តាលឲ្យចងចាំលែងមាននៅក្នុងការរៀបចំខ្លះៗ ជាពិសេសប្រសិនបើអ្នកកំពុងធ្វើចំណាំផ្ទាល់របស់អ្នកជាផ្នែកនៃសៀវភៅកំណត់ត្រាដូចគ្នា។ ប្រសិនបើអ្នកប្រទះឃើញកំហុសចំណាស់ៗពេលចាប់ផ្តើមបណ្តុះបណ្តាលម៉ូដែល អ្នកអាចចង់ចាប់ផ្តើម kernel សៀវភៅកំណត់ត្រាថ្មីម្តងទៀត។\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": true,
"jupyter": {
"outputs_hidden": false,
"source_hidden": false
},
"nteract": {
"transient": {
"deleting": false
}
}
},
"outputs": [],
"source": [
"batch_size = 16\n",
"embed_size = 64"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ម៉ាស៊ីនចំណាត់ថ្នាក់ RNN សាមញ្ញ\n",
"\n",
"ក្នុងករណី RNN សាមញ្ញ, មួយឯកតាការវិលត្រីមាត្រគឺជាបណ្តាញបន្ទាត់សាមញ្ញមួយ ដែលទទួលវ៉ិចទ័រសំណូល និងវ៉ិចទ័របំណែង ហើយផលិតវ៉ិចទ័របំណែងថ្មី។ ក្នុង Keras, នេះអាចត្រូវបានបង្ហាញដោយស្រទាប់ `SimpleRNN` ។\n",
"\n",
"បើទោះបីពួកយើងអាចផ្ញើតូកែនដែលបានកូដជា one-hot ទៅស្រទាប់ RNN ត្រង់ៗក៏ដោយ នោះមិនមែនជាគំនិតល្អទេ ព្រោះមានវិមាត្រខ្ពស់បំផុត។ ដូច្នេះ យើងនឹងប្រើស្រទាប់ embedding ដើម្បីចុះវិមាត្ររបស់វ៉ិចទ័រពាក្យ បន្ទាប់មកស្រទាប់ RNN ហើយចុងក្រោយជាម៉ាស៊ីនចំណាត់ថ្នាក់ `Dense` ។\n",
"\n",
"> **កំណត់សម្គាល់**: ក្នុងករណីដែលវិមាត្រមិនខ្ពស់ទេ ជាឧទាហរណ៍ពេលប្រើ tokenization កម្រិតអក្សរ វាអាចមានហេតុផលក្នុងការផ្ញើតូកែនដែលបានកូដជា one-hot ចូលទៅក្នុងកោសិកា RNN ផ្ទាល់។\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"sequential\"\n",
"_________________________________________________________________\n",
"Layer (type) Output Shape Param # \n",
"=================================================================\n",
"text_vectorization (TextVect (None, None) 0 \n",
"_________________________________________________________________\n",
"embedding (Embedding) (None, None, 64) 1280000 \n",
"_________________________________________________________________\n",
"simple_rnn (SimpleRNN) (None, 16) 1296 \n",
"_________________________________________________________________\n",
"dense (Dense) (None, 4) 68 \n",
"=================================================================\n",
"Total params: 1,281,364\n",
"Trainable params: 1,281,364\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n"
]
}
],
"source": [
"vocab_size = 20000\n",
"\n",
"vectorizer = keras.layers.experimental.preprocessing.TextVectorization(\n",
" max_tokens=vocab_size,\n",
" input_shape=(1,))\n",
"\n",
"model = keras.models.Sequential([\n",
" vectorizer,\n",
" keras.layers.Embedding(vocab_size, embed_size),\n",
" keras.layers.SimpleRNN(16),\n",
" keras.layers.Dense(4,activation='softmax')\n",
"])\n",
"\n",
"model.summary()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **កំណត់ចំណាំ៖** យើងប្រើស្រទាប់ embedding មិនបានហ្វឹកហាត់នៅទីនេះសម្រាប់ភាពសាមញ្ញ ប៉ុន្ត่าสำหรับលទ្ធផលល្អជាងនេះ យើងអាចប្រើស្រទាប់ embedding ដែលបានហ្វឹកហាត់រួចជាមួយ Word2Vec ដូចបានពិពណ៌នានៅឯកត្តជំពូកមុន។ វាជាការហាត់ដំណើរល្អសម្រាប់អ្នកក្នុងការតម្រូវកូដនេះឱ្យដំណើរការជាមួយ embeddings ដែលបានហ្វឹកហាត់រួច។ \n",
"\n",
"ឥឡូវនេះមកហ្វឹកហាត់ RNN របស់យើង។ RNN ទូទៅមានភាពលំបាកក្នុងការហ្វឹកហាត់ ព្រោះពេលដែលកោសិការបស់ RNN ត្រូវបានបម្លែង (unrolled) ទៅតាមប្រវែងរដ្ឋសភាព (sequence length) ចំនួនស្រទាប់ដែលចូលរួមក្នុងការត្រួតពិនិត្យត្រឡប់ក្រោយ (backpropagation) គឺនឹងធំជាច្រើន។ ដូចនេះយើងត្រូវជ្រើសរើសអត្រាការសិក្សា (learning rate) តូចជាងមុន ហើយហ្វឹកហាត់បណ្តាញលើឌាតាសិក្សាធំជាង ដើម្បីបានលទ្ធផលល្អ។ វាអាចចាលខ្សែពេលយូរណាស់ ដូច្នេះការប្រើ GPU គឺផ្តល់អាទិភាព។ \n",
"\n",
"ដើម្បីល្បឿនឡើង យើងនឹងហ្វឹកហាត់ម៉ូឌែល RNN លើចំណងជើងដំណឹងតែប៉ុណ្ណោះ ខ្វះពាក្យពិពណ៌នា។ អ្នកអាចសាកល្បងហ្វឹកហាត់ជាមួយពាក្យពិពណ៌នារួម និងមើលថាតើអាចធ្វើឲ្យម៉ូឌែលហ្វឹកហាត់បានឬទេ។\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Training vectorizer\n"
]
}
],
"source": [
"def extract_title(x):\n",
" return x['title']\n",
"\n",
"def tupelize_title(x):\n",
" return (extract_title(x),x['label'])\n",
"\n",
"print('Training vectorizer')\n",
"vectorizer.adapt(ds_train.take(2000).map(extract_title))"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"7500/7500 [==============================] - 82s 11ms/step - loss: 0.6629 - acc: 0.7623 - val_loss: 0.5559 - val_acc: 0.7995\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7f3e0030d350>"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')\n",
"model.fit(ds_train.map(tupelize_title).batch(batch_size),validation_data=ds_test.map(tupelize_title).batch(batch_size))"
]
},
{
"cell_type": "markdown",
"metadata": {
"nteract": {
"transient": {
"deleting": false
}
}
},
"source": [
"> **កំណត់ចំណាំ** ថា ភាពត្រឹមត្រូវប្រហែលជានឹងទាបជាងនេះ ដោយសារតែយើងកំពុងបណ្តុះបណ្តាលតែលើចំណងជើងដំណឹងប៉ុណ្ណោះ។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ការត្រលប់មកវិញលំហាត់តួអក្សរផ្សេងប្លែក \n",
"\n",
"ចងចាំថាស្រទាប់ `TextVectorization` នឹងបន្ថែមសញ្ញា pad ដើម្បីបំពេញខ្សែតួអក្សរផ្សេងប្រវែងក្នុងមីនីបាច់ដោយស្វ័យប្រវត្តិ។ វាជាក់ថាសញ្ញាទាំងនោះក៏ចូលរួមក្នុងការបណ្តុះបណ្តាលផងដែរ ហើយវាប្រហែលជាសំប៉ាយកានតម្រូវនៃម៉ូដែល។\n",
"\n",
"មានវិធីច្រើនដែលយើងអាចប្រើដើម្បីល៉ូតបំផុតបរិមាណការបំពេញ។ ក្នុងនោះមានជំហានមួយគឺធ្វើរៀបចំទិន្នន័យជាសៀគ្វីតាមប្រវែងនៃខ្សែទិន្នន័យ ហើយក្រុមគ្រប់ខ្សែតួអក្សរតាមទំហំ។ វាអាចធ្វើបានដោយប្រើមុខងារ `tf.data.experimental.bucket_by_sequence_length` (មើល [ឯកសារ](https://www.tensorflow.org/api_docs/python/tf/data/experimental/bucket_by_sequence_length))។ \n",
"\n",
"វិធីមួយទៀតគឺប្រើ **masking**។ នៅក្នុង Keras មានស្រទាប់ខ្លះដែលគាំទ្រជំរុញបញ្ចូលបន្ថែមដែលបង្ហាញថាតួអក្សរណាដែលត្រូវគិតប្រាក់ទៅពេលបណ្តុះបណ្តាល។ ដើម្បីបញ្ចូលការម៉ាស្កីងក្នុងម៉ូដែលរបស់យើង យើងអាចបញ្ចូលស្រទាប់ `Masking` ផ្សេងទៀត ([ឯកសារ](https://keras.io/api/layers/core_layers/masking/)) ឬប្រើប៉ារ៉ាម៉ែត្រ `mask_zero=True` នៃស្រទាប់ `Embedding` របស់យើង។\n",
"\n",
"> **កំណត់សម្គាល់**៖ ការបណ្តុះបណ្តាលនេះនឹងចំណាយពេលប្រហែល ៥ នាទីដើម្បីបញ្ចប់មួយ Epoch នៅទាំងមូលឯកសារទិន្នន័យ។ អ្នកអាចសម្រាកបន្ទាន់ការបណ្តុះបណ្តាលនៅពេលណាក៏បាន ប្រសិនបើអ្នកអស់ចំណោម។ អ្នកក៏អាចកំណត់ចំនួនទិន្នន័យ​ដែលប្រើសម្រាប់បណ្តុះបណ្តាល ជាមួយការ​បន្ថែម `.take(...)` បន្ទាប់ពីឌីស្ទឺត `ds_train` និង `ds_test`។\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"7500/7500 [==============================] - 371s 49ms/step - loss: 0.5401 - acc: 0.8079 - val_loss: 0.3780 - val_acc: 0.8822\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7f3dec118850>"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def extract_text(x):\n",
" return x['title']+' '+x['description']\n",
"\n",
"def tupelize(x):\n",
" return (extract_text(x),x['label'])\n",
"\n",
"model = keras.models.Sequential([\n",
" vectorizer,\n",
" keras.layers.Embedding(vocab_size,embed_size,mask_zero=True),\n",
" keras.layers.SimpleRNN(16),\n",
" keras.layers.Dense(4,activation='softmax')\n",
"])\n",
"\n",
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')\n",
"model.fit(ds_train.map(tupelize).batch(batch_size),validation_data=ds_test.map(tupelize).batch(batch_size))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ឥឡូវនេះយើងកំពុងប្រើការបំលែងមុខមាត់ (masking) ហើយយើងអាចបង្រៀនម៉ូឌែលលើទិន្នន័យបូកបញ្ចូលទាំងស្រុងនៃចំណងជើង និងការពិពណ៌នា។\n",
"\n",
"> **សម្គាល់**: តើអ្នកបាន​ដឹងទេថាយើងបានប្រើ vectorizer ដែលបានបង្រៀនលើចំណងជើងព័ត៌មាន ទេ មិនមែនលើរាងកាយទាំងមូលនៃអត្ថបទ? ប្រហែលជា វាអាចបណ្តាលឲ្យខ្លះនៃតូខេន ត្រូវបានមើលរំលង ដូច្នេះគួរតែបង្រៀនឡើងវិញ vectorizer។ ប៉ុន្តែ វាអាចមានផលប៉ះពាល់តិចតួចតែប៉ុណ្ណោះ ដូច្នេះយើងនឹងនៅតែប្រើ vectorizer ដែលបានបង្រៀនមុននេះសម្រាប់ភាពងាយស្រួល។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## LSTM: អង្គចងចាំរយៈពេលខ្លីនិងយូរ\n",
"\n",
"មួយក្នុងចំណោមបញ្ហាសំខាន់ៗ​នៃ RNN គឺ **កំណើន gradients ដែលបាត់បង់**។ RNN អាចមានប្រវែងយូរ ហើយអាចមានការលំបាកក្នុងការបញ្ជូន gradients ត្រឡប់ទៅបន្ទាត់ទីមួយនៃបណ្តាញនៅពេល backpropagation។ នៅពេលនេះកើតឡើង នេះបណ្តាញមិនអាចរៀនទំនាក់ទំនងរវាង token ដែលស្ថិតឆ្ងាយគ្នាបានទេ។ មូលហេតុ​មួយដើម្បីជៀសវាងបញ្ហានេះគឺ ដាក់បន្ថែម **ការគ្រប់គ្រងស្ថានភាពយ៉ាងច្បាស់លាស់** ដោយប្រើ **ទ្វារជ្រាប**។ ស្ថាបត្យកម្មទាំងពីរដែលជាទូទៅបង្ហាញទ្វារជ្រាបគឺ **អង្គចងចាំរយៈពេលខ្លីនិងយូរ** (LSTM) និង **ឯកតាជ្រាបប្រព័ន្ធផ្សព្វផ្សាយ** (GRU)។ យើងនឹងបញ្ជាក់អំពី LSTM នៅទីនេះ។\n",
"\n",
"![រូបភាពបង្ហាញគំរូអង្គចងចាំរយៈពេលខ្លីនិងយូរ](../../../../../lessons/5-NLP/16-RNN/images/long-short-term-memory-cell.svg)\n",
"\n",
"បណ្តាញ LSTM ត្រូវបានរៀបចំជាប្រភេទដូច RNN ប៉ុន្តែមានស្ថានភាពពីរដែលត្រូវបញ្ជូនពីជាន់មួយទៅជាន់មួយ គឺស្ថានភាពពិត $c$ និង វិទ័រលាក់ $h$។ នៅក្នុងឯកតាទីមួយ វិទ័រលាក់ $h_{t-1}$ ត្រូវបានបញ្ចូលជាមួយនឹងវ៉ិចទ័រ input $x_t$ ហើយពួកវាគ្រប់គ្រងអ្វីដែលកើតឡើងចំពោះស្ថានភាព $c_t$ និងចេញ $h_{t}$ តាមរយៈ **ទ្វារជ្រាប**។ ទ្វារ​រៀងរាល់ទ្វារមានគម្លាត sigmoid (ចេញក្នុងជួរនៃ $[0,1]$) ដែលអាចគិតជាផ្នែក bitwise mask នៅពេលគុណជាមួយវិទ័រស្ថានភាព។ LSTM មានទ្វារដូចខាងក្រោម (ពីឆ្វេងទៅស្តាំនៅលើរូបភាពខាងលើ):\n",
"* **ទ្វារភ្លេចបាត់** ដែលកំណត់ថា ធាតុណាដែលនៅក្នុងវិទ័រ $c_{t-1}$ គួរត្រូវភ្លេចបាត់ ហើយធាតុណាដែលគួរត្រូវបញ្ជូនតទៅ។\n",
"* **ទ្វារបញ្ចូល** ដែលកំណត់ថាព័ត៌មានប៉ុន្មានពីវិទ័របញ្ចូលនិងវិទ័រលាក់មុនគួរត្រូវបញ្ចូលទៅក្នុងវិទ័រស្ថានភាព។\n",
"* **ទ្វារចេញ** ដែលយកវិទ័រស្ថានភាពថ្មី ហើយសម្រេចថាធាតុណាដែល នឹងត្រូវបានប្រើសម្រាប់បង្កើតវិទ័រលាក់ថ្មី $h_t$។\n",
"\n",
"ធាតុនៃស្ថានភាព $c$ អាចគិតជាទង់ដែលអាចបិទ និងបើកបាន។ ឧទាហរណ៍ នៅពេលយើងជួបឈ្មោះ *Alice* ក្នុងលំដាប់ពាក្យ យើងគិតថាឈ្មោះនេះហៅដល់ស្ត្រី ហើយបើកទង់នៅក្នុងស្ថានភាពដែលបង្ហាញថាយើងមាននាមស្រីក្នុងប្រយោគ។ នៅពេលយើងបន្តជួបពាក្យ *and Tom* យើងនឹងបើកទង់ដែលបង្ហាញថាយើងមាននាមពហុបុគ្គល។ ដូច្នេះ ដោយការគ្រប់គ្រងស្ថានភាព យើងអាចតាមដានលក្ខណៈវេយ្យាករណ៍នៃប្រយោគ។\n",
"\n",
"> **កត់សម្គាល់**: នេះជាភស្តុតាងល្អសម្រាប់យល់ពីរចនាសម្ព័ន្ធខាងក្នុងនៃ LSTM: [Understanding LSTM Networks](https://colah.github.io/posts/2015-08-Understanding-LSTMs/) ដោយ Christopher Olah។\n",
"\n",
"នៅពេលបន្ទះខាងក្នុងនៃកោសិកា LSTM អាចមើលទៅស្មុគស្មាញ ការប្រែប្រួលនេះត្រូវបានលាក់ខាងក្នុងជាន់ `LSTM` របស់ Keras ដូច្នេះអ្វីដែលយើងត្រូវធ្វើនៅក្នុងឧទាហរណ៍ខាងលើគឺប្ដូរជាន់ recurrent ។\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"15000/15000 [==============================] - 188s 13ms/step - loss: 0.5692 - acc: 0.7916 - val_loss: 0.3441 - val_acc: 0.8870\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7f3d6af5c350>"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = keras.models.Sequential([\n",
" vectorizer,\n",
" keras.layers.Embedding(vocab_size, embed_size),\n",
" keras.layers.LSTM(8),\n",
" keras.layers.Dense(4,activation='softmax')\n",
"])\n",
"\n",
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')\n",
"model.fit(ds_train.map(tupelize).batch(8),validation_data=ds_test.map(tupelize).batch(8))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **កំណត់សម្គាល់** ការបណ្តុះបណ្តាល LSTM ផងដែរ មានល្បឿនយឺត ដូច្នេះ អ្នកអាចមិនឃើញការកើនឡើងខ្លះៗនៃភាពត្រឹមត្រូវ នៅដើមនៃការបណ្តុះបណ្តាលនោះទេ។ អ្នកអាចត្រូវបន្តបណ្តុះបណ្តាលរយៈពេលមួយ ដើម្បីទទួលបានភាពត្រឹមត្រូវល្អ។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## RNN ទិស​បូក និង RNN បច្របាំង​ច្រើន​ស្រទាប់\n",
"\n",
"ក្នុងឧទាហរណ៍របស់យើងទៅរួចនេះ បណ្ដាញ recurrent ប្រតិបត្តិការពីដើមជួរ​ដល់ចុងជួរ។ វាហាក់ដូចជា​ធម្មតាសម្រាប់យើង ពីព្រោះវាស្របទៅតាមទិសដៅដដែលនៃការអានឬការស្តាប់សំឡេង។ ទោះជាយ៉ាងណា សម្រាប់ករណីដែលត្រូវការចូលប្រើជួរដាក់ទិន្នន័យដោយចៃដន្យ វាមានហេតុផលថា គួរឱ្យដំណើរការជាន់បណ្ដួតិងទិសពីរទិស។ RNN ដែលអនុញ្ញាតឱ្យគណនាណ៍ពីទិសពីរ ត្រូវបានហៅថា **bidirectional** RNN ហើយអ្នកអាចបង្កើតវាបានដោយបញ្ឈរជាន់ recurrent ជាមួយជាន់ពិសេស `Bidirectonal`។\n",
"\n",
"> **កំណត់សម្គាល់**៖ ជាន់ `Bidirectional` បង្កើតចម្លងពីរនៃជាន់នៅក្នុងវា ហើយកំណត់លក្ខណៈ `go_backwards` សម្រាប់ចម្លងមួយក្នុងចំណោមទាំងពីរទៅជា `True` ធ្វើឲ្យវាទៅក្នុងទិសវិញនៅមុខជួរដាក់។ \n",
"\n",
"បណ្ដាញ recurrent ទាំងជាន់តែមួយ (unidirectional) ឬទ្វិទិស (bidirectional) ពន្លឿនតម្រងក្នុងមួយជួរ ហើយរក្សាទុកវាទៅក្នុងវ៉ិកទ័ររដ្ឋ ឬត្រឡប់វាជាផលចេញ។ ដូចជា បណ្ដាញមានការស្ងោ (convolutional networks) ផងដែរ អ្នកអាចបង្កើតជាន់ recurrent ថ្មីមួយបន្ទាប់ពីជាន់ដំបូង ដើម្បីចាប់យកផ្ទាំងកម្រិតខ្ពស់ ដែលបង្កើតឡើងពីផ្ទាំងកម្រិតទាបដែលចាប់យកដោយជាន់ដំបូង។ វាដឹកនាំយើងដល់គំនិតនៃ **multi-layer RNN** ដែលមានបណ្ដាភាពច្រើនជាន់ recurrent ច្រើនជាងពីរកន្លែងដែលផលចេញពីជាន់មុនត្រូវបានផ្ញើទៅជាជួរដាក់បញ្ចូលរបស់ជាន់បន្ទាប់។\n",
"\n",
"![រូបថតបង្ហាញពី Multilayer long-short-term-memory- RNN](../../../../../translated_images/km/multi-layer-lstm.dd975e29bb2a59fe.webp)\n",
"\n",
"*រូបភាពពី [អត្ថបទដ៏អស្ចារ្យនេះ](https://towardsdatascience.com/from-a-lstm-cell-to-a-multilayer-lstm-network-with-pytorch-2899eb5696f3) ដោយ Fernando López។*\n",
"\n",
"Keras ធ្វើឱ្យការបង្កើតបណ្ដាញទាំងនេះក្លាយជាការងារងាយស្រួល ពីព្រោះអ្នកត្រឹមតែបន្ថែមជាន់ recurrent ច្រើនជាងនៅក្នុងម៉ូដែលប៉ុណ្ណោះ។ សម្រាប់ជាន់ទាំងអស់ក្រៅតែជាន់ចុងក្រោយ អ្នកត្រូវបញ្ជាក់ប៉ារ៉ាម៉ែត្រ `return_sequences=True` ដូច្នេះជាន់នោះនឹងត្រលប់អោយរដ្ឋរង់ចាំពីរ្វ่ายขายទាំងមូល មិនមែនតែរដ្ឋចុងក្រោយនៃការគណនា recurrent។\n",
"\n",
"ចំណាំជូន យើងនឹងសង់ LSTM ទ្វិទិសពីរស្រទាប់សម្រាប់បញ្ហាការបែងចែកចំណាត់ថ្នាក់របស់យើង។\n",
"\n",
"> **កំណត់សម្គាល់** ៖ កូដនេះម្តងទៀតចំណាយពេលវេលាខ្លះ តែវាផ្តល់នូវភាពត្រឺមត្រូវខ្ពស់បំផុត ដែលយើងបានឃើញរហូតមកដល់ពេលនេះ។ ដូច្នេះប្រហែលជាគួរលើកទឹកចិត្តរង់ចាំ និងមើលលទ្ធផល។\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"5044/7500 [===================>..........] - ETA: 2:33 - loss: 0.3709 - acc: 0.8706\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r5045/7500 [===================>..........] - ETA: 2:33 - loss: 0.3709 - acc: 0.8706"
]
}
],
"source": [
"model = keras.models.Sequential([\n",
" vectorizer,\n",
" keras.layers.Embedding(vocab_size, 128, mask_zero=True),\n",
" keras.layers.Bidirectional(keras.layers.LSTM(64,return_sequences=True)),\n",
" keras.layers.Bidirectional(keras.layers.LSTM(64)), \n",
" keras.layers.Dense(4,activation='softmax')\n",
"])\n",
"\n",
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')\n",
"model.fit(ds_train.map(tupelize).batch(batch_size),\n",
" validation_data=ds_test.map(tupelize).batch(batch_size))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## RNN សម្រាប់ការងារផ្សេងទៀត\n",
"\n",
"រហូតមកដល់ឥឡូវនេះ យើងបានផ្តោតលើការប្រើប្រាស់ RNN ដើម្បីចាត់ថ្នាក់លំដាប់អក្សរប្រយោគ។ ប៉ុន្តែវាអាចដោះស្រាយការងារផ្សេងទៀតបានច្រើន ដូចជាការបង្កើតអត្ថបទ និងការប្រែភាសាគណនា &mdash; យើងនឹងពិចារណាការងារទាំងនេះនៅឯកិតបន្ទាប់។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**ការបដិសេធ**៖ \nឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ទោះបីយើងខិតខំសម្រាប់ភាពត្រឹមត្រូវ ក៏សូមដឹងថាការបកប្រែដោយស្វ័យប្រវត្តិក្នុងខ្លះអាចមានកំហុស ឬភាពមិនត្រឹមត្រូវ។ ឯកសារដើមនៅភាសាដើមគួរត្រូវបានគេពិចារណាថាជាអ្នកផ្គត់ផ្គង់ព័ត៌មានដែលមានសមត្ថកិច្ច។ សម្រាប់ព័ត៌មានសំខាន់ៗ សូមពិចារណាផ្នែកបកប្រែដោយមនុស្សជំនាញ។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកប្រែខុសពីការប្រើប្រាស់ការបកប្រែនេះឡើយ។\n<!-- CO-OP TRANSLATOR DISCLAIMER END -->\n"
]
}
],
"metadata": {
"kernel_info": {
"name": "conda-env-py37_tensorflow-py"
},
"kernelspec": {
"display_name": "py37_tensorflow",
"language": "python",
"name": "conda-env-py37_tensorflow-py"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.9"
},
"nteract": {
"version": "nteract-front-end@1.0.0"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,10 @@
# កិច្ចការទៅលើសៀវភោធន៍
ប្រើសៀវភោធន៍ ដែលភ្ជាប់មកជាមួយមេរៀននេះ (មួយណាមួយក្នុងចំណោម PyTorch ឬ TensorFlow) ធ្វើការរត់ឡើងវិញដោយប្រើដាតាសំណុំផ្ទាល់របស់អ្នក ប្រហែលជា មួយដែលបានយកពី Kaggle ជាមួយនឹងការបញ្ជាក់ប្រភព។ សរសេរសៀវភោធន៍ឡើងវិញដើម្បីបង្ហាញលទ្ធផលរបស់អ្នកផ្ទាល់។ សាកល្បងប្រភេទដាតាសំណុំផ្សេងទៀត ហើយចងក្រងលទ្ធផលរបស់អ្នក ដោយប្រើអត្ថបទដូចជា [ឈុតដាតាសំណុំការប្រកួត Kaggle នេះស្តីអំពីសារពត៌មានអាកាសធាតុ Twitter](https://www.kaggle.com/competitions/crowdflower-weather-twitter/data?select=train.csv)។
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការព្រមាន**៖
ឯកសារនេះបានបកប្រែដោយប្រើសេវាបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេលដែលយើងខំប្រឹងប្រែងសម្រាប់ភាពត្រឹមត្រូវ សូមកត់សម្គាល់ថាការបកប្រែដោយស្វ័យប្រវត្តិអាចមានកំហុស ឬភាពមិនត្រឹមត្រូវ។ ឯកសារដើមជាភាសារបស់វាគួរត្រូវបានចាត់ទុកជាប្រភពដែលមានអាជ្ញាបណ្ណ។ សម្រាប់ព័ត៌មានសំខាន់ៗ ការ បកប្រែដោយមនុស្សជំនាញគឺត្រូវបានផ្តល់អនុសាសន៍។ យើងខ្លួនមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកផ្សំខុសឡើងពីការប្រើប្រាស់ការបកប្រែនេះឡើយ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,405 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# បណ្តាញបង្កើត\n",
"\n",
"បណ្តាញទន់រេគ័រ (RNNs) និងវ៉ារីយ៉ង់ឈុតក្រវ៉ាត់របស់វា ដូចជា អង្គផ្សាំអង្គចងក្រងអង្គយូ​ស៊ូរ (LSTMs) និងអង្គទរព័យរេគ័រ​ក្រវ៉ាត់ (GRUs) បានផ្តល់យន្តការសម្រាប់ការម៉ូដែលភាសា គឺវាអាចរៀនលំដាប់ពាក្យ និងផ្តល់ការព្យាករណ៍សម្រាប់ពាក្យបន្ទាប់ក្នុងលំដាប់។ វាអាចអនុញ្ញាតឲ្យយើងប្រើ RNNs សម្រាប់ **ភារកិច្ចបង្កើត** ដូចជាការបង្កើតអត្ថបទធម្មតា ការបកប្រែកម្មវិធី និងដល់ស្ទើរតែការពណ៌នារូបភាពផងដែរ។\n",
"\n",
"ក្នុងសំណង់ RNN ដែលយើងបានពិភាក្សាក្នុងផ្នែកមុន យុីតអង្គ RNN នីមួយៗបានបង្កើតស្ថានភាពលាក់បន្ទាប់ជាកៅអឿន។ ទោះយ៉ាងណា យើងអាចបន្ថែមការបញ្ចេញផ្សេងមួយទៀតចំពោះ​យុីតរេគ័រនីមួយៗ ដែលនឹងអនុញ្ញាតឲ្យយើងបញ្ចេញ **លំដាប់** (ដែលមានប្រវែងស្មើនឹងលំដាប់ដើម)។ លើសពីនេះ យើងអាចប្រើយុីត RNN ដែលមិនទទួលបញ្ចូលនៅក каждомជំហាន ហើយគ្រាន់តែទទួលកំណត់ស្ថានភាពដើមមួយ បន្ទាប់មកបញ្ចេញលំដាប់នៃការចេញ។\n",
"\n",
"ក្នុងកំណត់ហេតុនេះ យើងនឹងផ្តោតលើម៉ូដែលបង្កើតសាមញ្ញ ដែលជួយយើងបង្កើតអត្ថបទ។ សម្រាប់ភាពសាមញ្ញ អ្នកអាចកសាង **បណ្តាញកម្រិតអក្សរ** ដែលបង្កើតអត្ថបទទៅតាមអក្សរ។ ខណៈពេលបណ្តុះបណ្តាល យើងត្រូវយកអត្ថបទមួយ ហើយបំបែកវាជាលំដាប់អក្សរ។\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Loading dataset...\n",
"Building vocab...\n"
]
}
],
"source": [
"import torch\n",
"import torchtext\n",
"import numpy as np\n",
"from torchnlp import *\n",
"train_dataset,test_dataset,classes,vocab = load_dataset()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ការសង់វាក្យាសព្ទតួអក្សរ\n",
"\n",
"ដើម្បីសង់បណ្តាញបង្កើតដែលកម្រិតតួអក្សរ យើងត្រូវការបំបែកអត្ថបទជាតួអក្សរច្រើនផ្ទាល់ជំនួសពាក្យ។ វាអាចធ្វើបានដោយកំណត់ tokenizer ផ្ទាល់ខ្លួនមួយ:\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Vocabulary size = 82\n",
"Encoding of 'a' is 1\n",
"Character with code 13 is c\n"
]
}
],
"source": [
"def char_tokenizer(words):\n",
" return list(words) #[word for word in words]\n",
"\n",
"counter = collections.Counter()\n",
"for (label, line) in train_dataset:\n",
" counter.update(char_tokenizer(line))\n",
"vocab = torchtext.vocab.vocab(counter)\n",
"\n",
"vocab_size = len(vocab)\n",
"print(f\"Vocabulary size = {vocab_size}\")\n",
"print(f\"Encoding of 'a' is {vocab.get_stoi()['a']}\")\n",
"print(f\"Character with code 13 is {vocab.get_itos()[13]}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"មកមើលឧទាហរណ៍នៃរបៀបដែលយើងអាចតំណEncodeអត្ថបទពីឃ្លាដែលយើងមាន៖\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"tensor([ 0, 1, 2, 2, 3, 4, 5, 6, 3, 7, 8, 1, 9, 10, 3, 11, 2, 1,\n",
" 12, 3, 7, 1, 13, 14, 3, 15, 16, 5, 17, 3, 5, 18, 8, 3, 7, 2,\n",
" 1, 13, 14, 3, 19, 20, 8, 21, 5, 8, 9, 10, 22, 3, 20, 8, 21, 5,\n",
" 8, 9, 10, 3, 23, 3, 4, 18, 17, 9, 5, 23, 10, 8, 2, 2, 8, 9,\n",
" 10, 24, 3, 0, 1, 2, 2, 3, 4, 5, 9, 8, 8, 5, 25, 10, 3, 26,\n",
" 12, 27, 16, 26, 2, 27, 16, 28, 29, 30, 1, 16, 26, 3, 17, 31, 3, 21,\n",
" 2, 5, 9, 1, 23, 13, 32, 16, 27, 13, 10, 24, 3, 1, 9, 8, 3, 10,\n",
" 8, 8, 27, 16, 28, 3, 28, 9, 8, 8, 16, 3, 1, 28, 1, 27, 16, 6])"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def enc(x):\n",
" return torch.LongTensor(encode(x,voc=vocab,tokenizer=char_tokenizer))\n",
"\n",
"enc(train_dataset[0][1])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## បណ្តុះបណ្តាល RNN ជំរុញការបង្កើត\n",
"\n",
"វិធីសាស្រ្តដែលយើងនឹងបណ្តុះបណ្តាល RNN ដើម្បីបង្កើតអក្សរគឺដូចតទៅ។ នៅក្នុងជំហានមួយៗ យើងនឹងយកលំដាប់អក្សរមួយដែលមានប្រវែង `nchars`, ហើយសុំឲ្យបណ្តាញបង្កើតអក្សរបន្ទាប់សម្រាប់អក្សរបញ្ចូលនីមួយៗ៖\n",
"\n",
"![Image showing an example RNN generation of the word 'HELLO'.](../../../../../translated_images/km/rnn-generate.56c54afb52f9781d.webp)\n",
"\n",
"អាស្រ័យលើសេណារីយ៉ូពិតប្រាកដ យើងអាចចង់បញ្ចូលអក្សរពិសេសមួយចំនួនដូចជា *end-of-sequence* `<eos>`។ ក្នុងករណីរបស់យើង គ្រាន់តែចង់បណ្តុះបណ្តាលបណ្តាញសម្រាប់ការបង្កើតអក្សរឥតដាក់ទីបញ្ចប់ ដូច្នេះយើងនឹងកំណត់ទំហំរបស់លំដាប់នីមួយៗឱ្យស្មើនឹង `nchars` tokens។ ដូច្នេះ ឧទាហរណ៍បណ្តុះបណ្តាលនីមួយៗ នឹងមាន `nchars` input និង `nchars` output (ដែលជាលំដាប់បញ្ចូលផ្តិតឆ្វេងមួយសញ្ញា)។ Minibatch នីមួយៗ នឹងបង្កើតពីលំដាប់បែបនេះជាច្រើន។\n",
"\n",
"វិធីសាស្រ្តដែលយើងនឹងបង្កើត minibatches គឺយកអត្ថបទព័ត៌មាននីមួយៗដែលមានប្រវែង `l`, ហើយបង្កើតច្រកចូល-ចេញទាំងអស់ដែលអាចពេញលេញពីវា (នឹងមានចំនួន `l-nchars` ច្រកនេះ)។ វានឹងបង្កើតជាមួយ minibatch មួយ ហើយទំហំ minibatches នឹងខុសគ្នាទៅតាមជំហានបណ្តុះបណ្តាលនៅពេលនីមួយៗ។\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(tensor([[ 0, 1, 2, ..., 28, 29, 30],\n",
" [ 1, 2, 2, ..., 29, 30, 1],\n",
" [ 2, 2, 3, ..., 30, 1, 16],\n",
" ...,\n",
" [20, 8, 21, ..., 1, 28, 1],\n",
" [ 8, 21, 5, ..., 28, 1, 27],\n",
" [21, 5, 8, ..., 1, 27, 16]]),\n",
" tensor([[ 1, 2, 2, ..., 29, 30, 1],\n",
" [ 2, 2, 3, ..., 30, 1, 16],\n",
" [ 2, 3, 4, ..., 1, 16, 26],\n",
" ...,\n",
" [ 8, 21, 5, ..., 28, 1, 27],\n",
" [21, 5, 8, ..., 1, 27, 16],\n",
" [ 5, 8, 9, ..., 27, 16, 6]]))"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"nchars = 100\n",
"\n",
"def get_batch(s,nchars=nchars):\n",
" ins = torch.zeros(len(s)-nchars,nchars,dtype=torch.long,device=device)\n",
" outs = torch.zeros(len(s)-nchars,nchars,dtype=torch.long,device=device)\n",
" for i in range(len(s)-nchars):\n",
" ins[i] = enc(s[i:i+nchars])\n",
" outs[i] = enc(s[i+1:i+nchars+1])\n",
" return ins,outs\n",
"\n",
"get_batch(train_dataset[0][1])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ឥឡូវនេះយើងចាំបាច់កំណត់បណ្តាញអ្នកបង្កើត។ វាអាចផ្អែកលើកោសិកា recurrent មួយណាក៏បានដែលយើងបានពិភាក្សាក្នុងឯកតាមុន (សាមញ្ញ LSTM ឬ GRU)។ ក្នុងឧទាហរណ៍របស់យើង យើងនឹងប្រើ LSTM។\n",
"\n",
"ដោយសារ​បណ្តាញ​ទទួល​បាន​តួអក្សរ​ជា​អិន​ប៊ុត ហើយ​ទំហំវចនានុក្រមតូច សមរម្យ អ្នកមិនចាំបាច់មានស្រទាប់បញ្ចូល embedding ទេ អ្នកអាចប្រើអ៊ីនប៊ុតកូដ​បែប one-hot ដោយផ្ទាល់ទៅកាន់កោសិកា LSTM។ ទោះយ៉ាងណា ដោយសារ​យើងផ្ញើលេខតួអក្សរជាអិនប៊ុត យើងចាំបាច់ត្រូវបំលែងវាជា one-hot encoding មុនពេលផ្ញើទៅ LSTM។ វាត្រូវបានអនុវត្ត ដោយហៅមុខងារ `one_hot` នៅពេលបញ្ជូន `forward`។ អ្នកអ៊ិនកូដធ្វើការបញ្ចេញនឹងជាស្រទាប់ linear មួយ ដែលបំលែងស្ថានភាពលាក់ឱ្យទៅជាបញ្ចេញ one-hot-encoded។\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"class LSTMGenerator(torch.nn.Module):\n",
" def __init__(self, vocab_size, hidden_dim):\n",
" super().__init__()\n",
" self.rnn = torch.nn.LSTM(vocab_size,hidden_dim,batch_first=True)\n",
" self.fc = torch.nn.Linear(hidden_dim, vocab_size)\n",
"\n",
" def forward(self, x, s=None):\n",
" x = torch.nn.functional.one_hot(x,vocab_size).to(torch.float32)\n",
" x,s = self.rnn(x,s)\n",
" return self.fc(x),s"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"នៅពេលបណ្តុះបណ្តាល យើងចង់អាចរំលឹកអត្ថបទដែលបានបង្កើត។ ដើម្បីធ្វើដូចនេះ យើងនឹងកំណត់អនុគមន៍ `generate` ដែលនឹងផលិតខ្សែអក្សរជាលទ្ធផល ដែលមានប្រវែង `size` ចាប់ពីខ្សែអក្សរដើម `start`។ \n",
"\n",
"របៀបធ្វើការគឺដូចខាងក្រោម។ ជាលើកដំបូង យើងនឹងផ្ញើខ្សែអក្សរដើមទាំងមូលតាមរយៈបណ្តាញ ហើយយកស្ថានភាពលទ្ធផល `s` និងតួអក្សរព្យាករណ៍បន្ទាប់ `out`។ ពីព្រោះ `out` ត្រូវបានកូដជាមួយបែប one-hot encoded, យើងប្រើ `argmax` ដើម្បីយកលេខសម្គាល់របស់តួអក្សរ `nc` ក្នុងវាកាណូរី ហើយប្រើ `itos` ដើម្បីស្វែងរកតួអក្សរពិតប្រាកដ ហើយបញ្ចូលវាល vào របស់បញ្ជីតួអក្សរ `chars`។ ដំណើរការនេះសម្រាប់បង្កើតតួអក្សរតែមួយ ត្រូវបានម្ដងម្ដងសម្រាប់ `size` ដង ដើម្បីបង្កើតតួអក្សរចំនួនដែលត្រូវការជា។\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"def generate(net,size=100,start='today '):\n",
" chars = list(start)\n",
" out, s = net(enc(chars).view(1,-1).to(device))\n",
" for i in range(size):\n",
" nc = torch.argmax(out[0][-1])\n",
" chars.append(vocab.get_itos()[nc])\n",
" out, s = net(nc.view(1,-1),s)\n",
" return ''.join(chars)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ឥឡូវនេះយើងចាប់ផ្តើមហ្វឹកហាត់! លំនាំហ្វឹកហាត់ស្ទ Loop training នៅជិតស្រដៀងគ្នា ដូចក្នុងឧទាហរណ៍ចាស់ៗទាំងអស់របស់យើង ប៉ុន្តែបម្លែងជំនាញត្រង់គឺយើងបោះពុម្ពអត្ថបទដែលបានបង្កើតឡើងជាគំរូរៀងរាល់ ១០០០ epoch។\n",
"\n",
"ត្រូវផ្ដល់ការយកចិត្តទុកដាក់ពិសេសចំពោះវិធីដែលយើងគណនា​ការ​បាត់បង់ (loss)។ យើងត្រូវគណនាបាត់បង់ដោយផ្តោតលើឆ្លើយតបដែលបាន encode ជាមួយ one-hot នៅ `out` ហើយអត្ថបទដែលបានរំពឹងទុកគឺ `text_out` ដែលជារបាយការណ៍ក្រុមលេខតួអក្សរ។ ហើយសំណាងល្អគឺមុខងារ `cross_entropy` រងចាំលទ្ធផលអន្តរកម្មមិនបានបញ្ច.Normalize (unnormalized) ជាអាគុយម៉ង់ទីមួយ ហើយលេខថ្នាក់ជាអាគុយម៉ង់ទីពីរ ដែលជាអ្វីដែលយើងមាន។ វាក៏ធ្វើការ averaging ដោយស្វ័យប្រវត្តិបន្ទាប់ពីទំហំ minibatch ផងដែរ។\n",
"\n",
"យើងក៏ដាក់ដែនកំណត់ការហ្វឹកហាត់ដោយ `samples_to_train` ខ្ទង់ ដើម្បីមិនអោយរង់ចាំយូរពេក។ យើងលើកទឹកចិត្តឲ្យអ្នកសាកល្បង និងព្យាយាមធ្វើហ្វឹកហាត់រយៈពេលវែងជាងនេះ ប្រហែល ជាច្រើន epoch (ក្នុងករណីនោះ អ្នកនឹងត្រូវបង្កើតខ្សែហ្វឹកហាត់បន្ថែមនៅជុំវិញកូដនេះ)។\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Current loss = 4.398899078369141\n",
"today sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr sr s\n",
"Current loss = 2.161320447921753\n",
"today and to the tor to to the tor to to the tor to to the tor to to the tor to to the tor to to the tor t\n",
"Current loss = 1.6722588539123535\n",
"today and the court to the could to the could to the could to the could to the could to the could to the c\n",
"Current loss = 2.423795223236084\n",
"today and a second to the conternation of the conternation of the conternation of the conternation of the \n",
"Current loss = 1.702607274055481\n",
"today and the company to the company to the company to the company to the company to the company to the co\n",
"Current loss = 1.692358136177063\n",
"today and the company to the company to the company to the company to the company to the company to the co\n",
"Current loss = 1.9722288846969604\n",
"today and the control the control the control the control the control the control the control the control \n",
"Current loss = 1.8705692291259766\n",
"today and the second to the second to the second to the second to the second to the second to the second t\n",
"Current loss = 1.7626899480819702\n",
"today and a security and a security and a security and a security and a security and a security and a secu\n",
"Current loss = 1.5574463605880737\n",
"today and the company and the company and the company and the company and the company and the company and \n",
"Current loss = 1.5620026588439941\n",
"today and the be that the be the be that the be the be that the be the be that the be the be that the be t\n"
]
}
],
"source": [
"net = LSTMGenerator(vocab_size,64).to(device)\n",
"\n",
"samples_to_train = 10000\n",
"optimizer = torch.optim.Adam(net.parameters(),0.01)\n",
"loss_fn = torch.nn.CrossEntropyLoss()\n",
"net.train()\n",
"for i,x in enumerate(train_dataset):\n",
" # x[0] is class label, x[1] is text\n",
" if len(x[1])-nchars<10:\n",
" continue\n",
" samples_to_train-=1\n",
" if not samples_to_train: break\n",
" text_in, text_out = get_batch(x[1])\n",
" optimizer.zero_grad()\n",
" out,s = net(text_in)\n",
" loss = torch.nn.functional.cross_entropy(out.view(-1,vocab_size),text_out.flatten()) #cross_entropy(out,labels)\n",
" loss.backward()\n",
" optimizer.step()\n",
" if i%1000==0:\n",
" print(f\"Current loss = {loss.item()}\")\n",
" print(generate(net))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ឧទាហរណ៍នេះបានបង្កើតអត្ថបទល្អជាមួយស្រាប់ហើយ ប៉ុន្តែវាអាចត្រូវបានបង្កើតកាន់តែប្រសើរឡើងបានបន្ថែមទៀតក្នុងបែបផែនជាច្រើនៈ\n",
"* **ការបង្កើត minibatch ល្អជាងមុន**។ វិធីដែលយើងបានរៀបចំទិន្នន័យសម្រាប់ការបណ្តុះបណ្តាលគឺបង្កើត minibatch មួយពីគំរូមួយ។ នេះមិនមែនជារឿងល្អទេ ព្រោះ minibatch ទាំងអស់មានទំហំខុសគ្នា ហើយអ្វីមួយខ្លះមិនអាចបង្កើតបានទេ ព្រោះអត្ថបទតូចជាង `nchars`។ ផងដែរ minibatch តូចៗ មិនបានផ្ទុក GPU យ៉ាងគ្រប់គ្រាន់ទេ។ វានឹងមានការយល់ឃើញល្អប្រសើរជាងមុនក្នុងការទទួលយកខ្នាតអត្ថបទធំមួយពីគំរូទាំងអស់ បន្ទាប់មកបង្កើតគូបញ្ចូល-ចេញទាំងអស់ ដម្រៀបតាមចៃដន្យ ហើយបង្កើត minibatch ទំហំស្មើគ្នា។\n",
"* **LSTM ពហុស្រទាប់**។ វាមានហេតុផលក្នុងការព្យាយាមស្រទាប់ LSTM 2 ឬ 3។ ដូចដែលយើងបានរាយការណ៍នៅមេរៀនមុន ស្រទាប់ LSTM រៀងរាល់ស្រទាប់យកតំណំខ្ពស់ពីអត្ថបទ ហើយក្នុងករណីទូរស័ព្ទកម្រិតតួអក្សរ យើងអាចរំពឹងថា LSTM កម្រិតទាបមានទំនួលខុសត្រូវក្នុងការដកស្រង់ព្យញ្ជនៈ ហើយកម្រិតខ្ពស់ជាងគេគឺសម្រាប់ពាក្យ និងសមាសភាពពាក្យ។ វាអាចអនុវត្តបានយ៉ាងសាមញ្ញដោយផ្តល់ប៉ារ៉ាម៉ែត្រចំនួនស្រទាប់ទៅឱ្យអ្នកបង្កើត LSTM។\n",
"* អ្នកក៏អាចចង់សាកល្បងជាមួយ **ឯកតា GRU** ហើយមើលថាណាមួយសមនឹងប្រសើរជាងទៀត ឬជាមួយ **ទំហំស្រទាប់បានលាក់ខុសគ្នា**។ ទំហំស្រទាប់បានលាក់ធំនឹងបណ្តាលឱ្យមានភាពច្រើនពេក (ឧ. បណ្តាញនឹងរៀនអត្ថបទយ៉ាងតឹងរឹង) ហើយទំហំតូចជាងមិនអាចផ្តល់លទ្ធផលល្អ។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ការបង្កើតអត្ថបទទន់ និងសីតុណ្ហភាព\n",
"\n",
"នៅក្នុងនិយមន័យមុននៃ `generate`, យើងតែងតែយកតួអក្សរដែលមានប្រូបាប៊ីលิตี้ខ្ពស់បំផុតជាតួអក្សរបន្ទាប់ក្នុងអត្ថបទដែលបានបង្កើត។ នេះបណ្តាលឲ្យអត្ថបទជាញឹកញាប់ \"បង្វិលឡើងវិញ\" រវាងលំដាប់តួអក្សរដូចគ្នារដូវៗ ដូចក្នុងឧទាហរណ៍នេះ៖\n",
"```\n",
"today of the second the company and a second the company ...\n",
"```\n",
"\n",
"ទោះជាយ៉ាងណា ប្រសិនបើយើងមើលសមាសភាពប្រូបាប៊ីលิตี้សម្រាប់តួអក្សរបន្ទាប់ វាអាចជាករណីដែលភាពខុសគ្នារវាងប្រូបាប៊ីលิตี้ខ្ពស់បំផុតមួយពីរមិនបានធំដល់កម្រិតខ្លាំងទេ ឧទាហរណ៍ តួអក្សរមួយអាចមានប្រូបាប៊ីលิตี้ 0.2 ខណៈដែលម្ចាស់ឈ្នះមួយទៀតមាន 0.19។ ឧទាហរណ៍ នៅពេលស្វែងរកតួអក្សរបន្ទាប់នៅក្នុងលំដាប់ '*play*', តួអក្សរបន្ទាប់អាចជារួមស្នូលជាតម្លៃស្មើគ្នានូវទាំងចន្លោះ ឬ **e** (ដូចជាក្នុងពាក្យ *player*)។\n",
"\n",
"នេះនាំឲ្យយើងបានសម្រេចថា ពេលខ្លះមិនត្រឹមត្រូវដែលនឹងជ្រើសតួអក្សរដែលមានប្រូបាប៊ីលิตี้ខ្ពស់ជាងទេ ពីព្រោះការជ្រើសរើសតួអក្សរខ្ពស់ទីពីរយ៉ាងហោចណាស់ក៏អាចនាំឲ្យយើងបានអត្ថបទដែលមានន័យ។ វាជាជម្រើសល្អក្នុងការប្រើ **ការស៊ែន** តួអក្សរពីការបែងចែកប្រូបាប៊ីលิตี้ដែលបានផ្តល់ដោយលទ្ធផលបណ្តោយបណ្តាញ។\n",
"\n",
"ការស៊ែននេះអាចធ្វើបានដោយប្រើមុខងារ `multinomial` ដែលអនុវត្តន៍នូវអ្វីដែលហៅថា **បែងចែកពហុឈុត**។ មុខងារមួយដែលអនុវត្តន៍ការបង្កើតអត្ថបទ **ទន់** នេះត្រូវបានកំណត់ខាងក្រោម៖\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"--- Temperature = 0.3\n",
"Today and a company and complete an all the land the restrational the as a security and has provers the pay to and a report and the computer in the stand has filities and working the law the stations for a company and with the company and the final the first company and refight of the state and and workin\n",
"\n",
"--- Temperature = 0.8\n",
"Today he oniis its first to Aus bomblaties the marmation a to manan boogot that pirate assaid a relaid their that goverfin the the Cappets Ecrotional Assonia Cition targets it annight the w scyments Blamity #39;s TVeer Diercheg Reserals fran envyuil that of ster said access what succers of Dour-provelith\n",
"\n",
"--- Temperature = 1.0\n",
"Today holy they a 11 will meda a toket subsuaties, engins for Chanos, they's has stainger past to opening orital his thempting new Nattona was al innerforder advan-than #36;s night year his religuled talitatian what the but with Wednesday to Justment will wemen of Mark CCC Camp as Timed Nae wome a leaders\n",
"\n",
"--- Temperature = 1.3\n",
"Today gpone 2.5 fech atcusion poor cocles toparsdorM.cht Line Pamage put 43 his calt lowed to the book, that has authh-the silia rruch ailing to'ory andhes beutirsimi- Aefffive heading offil an auf eacklets is charged evis, Gunymy oy) Mony has it after-sloythyor loveId out filme, the Natabl -Najuntaxiggs \n",
"\n",
"--- Temperature = 1.8\n",
"Today plary, P.slan chly\\401 mardregationly #39;t 8.1Mide) closes ,filtcon alfly playin roven!\\grea.-QFBEP: Iss onfarchQ/itilia CCf Zivesigntwasta orce.-Peul-aw.uicrin of fuglinfsut aftaningwo, MIEX awayew Aice Woiduar Corvagiugge oppo esig ThusBratourid canthly-RyI.co lagitems\\eexciaishes.conBabntusmor I\n",
"\n"
]
}
],
"source": [
"def generate_soft(net,size=100,start='today ',temperature=1.0):\n",
" chars = list(start)\n",
" out, s = net(enc(chars).view(1,-1).to(device))\n",
" for i in range(size):\n",
" #nc = torch.argmax(out[0][-1])\n",
" out_dist = out[0][-1].div(temperature).exp()\n",
" nc = torch.multinomial(out_dist,1)[0]\n",
" chars.append(vocab.get_itos()[nc])\n",
" out, s = net(nc.view(1,-1),s)\n",
" return ''.join(chars)\n",
" \n",
"for i in [0.3,0.8,1.0,1.3,1.8]:\n",
" print(f\"--- Temperature = {i}\\n{generate_soft(net,size=300,start='Today ',temperature=i)}\\n\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"យើងបានណែនាំប៉ារ៉ាម៉ែត្រថ្មីមួយដែលអំពាវនាវថា **សីតុណ្ហភាព** ដែលប្រើសម្រាប់បង្ហាញថាតើយើងគួរតែគាប់តែតែលើប្រមាណភាពខ្ពស់ប៉ុណ្ណាដូចម្តេច។ ប្រសិនបើសីតុណ្ហភាពគឺ 1.0 យើងធ្វើការជ្រើសរើស multinomial យ៉ាងសមរម្យ ហើយពេលសីតុណ្ហភាពឡើងទៅអនន្តភាព - ប្រprobabilityទាំងអស់ក្លាយជាស្មើគ្នា ហើយយើងជ្រើសរើសតួអក្សរបន្ទាប់ដោយចៃដន្យ។ នៅក្នុងឧទាហរណ៍ខាងក្រោម យើងអាចចាប់អារម្មណ៍បានថាអត្ថបទក្លាយទៅជាឥតមានន័យពេលយើងបង្កើនសីតុណ្ហភាពច្រើនពេក ហើយវាបង្ហាញដូចជា អត្ថបទដែលផលិតឡើងយ៉ាងពិបាកដែលមានលំនាំពិចារណា \"cycled\" ពេលវាឈានកាន់ក្បាលទៅ 0។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**ការបដិសេធ**៖ \nឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈដែលយើងខិតខំរកភាពត្រឹមត្រូវ សូមជ្រាបថាការបកប្រែដោយស្វ័យប្រវត្តិអាចមានកំហុស ឬការខុសឆ្គង។ ឯកសារដើមនៅក្នុងភាសារដើមគួរត្រូវបានគេយកជា ប្រភពដែលមានសុពលភាព។ សម្រាប់ព័ត៌មានសំខាន់ សូមណែនាំឲ្យប្រើការបកប្រែដោយមនុស្សដែលជាអ្នកជំនាញ។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកប្រែខុសៗណាមួយដែលកើតមានពីការប្រើប្រាស់ការបកប្រែនេះដែរ។\n<!-- CO-OP TRANSLATOR DISCLAIMER END -->\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "16af2a8bbb083ea23e5e41c7f5787656b2ce26968575d8763f2c4b17f9cd711f"
},
"kernelspec": {
"display_name": "Python 3.8.12 ('py38')",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.12"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,488 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# បណ្តាញបង្កើត\n",
"\n",
"បណ្តាញប្រស่า (Recurrent Neural Networks - RNNs) និងបែបបទកោសិកាដែលមានទ្វារដូចជា ឧក្រិដ្ឋជាតិសម័យបណ្តោះអាសន្នបែបវែង (Long Short Term Memory Cells - LSTMs) និងឧក្រិដ្ឋជាតិសម័យជាតិត្រកូល (Gated Recurrent Units - GRUs) ផ្តល់មកនូវយន្តការសម្រាប់ការម៉ូដែលភាសា ដែលមានន័យថា ពួកគេអាចរៀនលំដាប់ពាក្យ និងផ្តល់ការព្យាករណ៍សម្រាប់ពាក្យបន្ទាប់ក្នុងលំដាប់។ នេះអនុញ្ញាតឲ្យយើងប្រើ RNN សម្រាប់ **ភារកិច្ចបង្កើត** ដូចជា ការបង្កើតអត្ថបទទូទៅ ការបកប្រែម៉ាស៊ីន និងឯងការបណ្តឹងរូបភាព។\n",
"\n",
"នៅក្នុងគ្រឹះសម្រាប់ការរចនាបណ្តាញ RNN ដែលយើងបានពិភាក្សានៅឯកត្តាមុន រាល់អង្គភាព RNN ក៏បានបង្កើតស្ថានភាពលាក់បន្ទាប់ជាលទ្ធផល។ ទោះជាយ៉ាងណា យើងក៏អាចបន្ថែមលទ្ធផលមួយទៀតទៅរាល់អង្គភាពប្រសាទដែលអាចអោយយើងបញ្ចេញជាលំដាប់ (ដែលមានប្រវែងស្មើនឹងលំដាប់ដើម)។ លើសពីនេះ យើងអាចប្រើអង្គភាព RNN ដែលមិនទទួលអ្នកបញ្ចូលនៅរាល់ជំហានទេ ហើយគ្រាន់តែទទួលវ៉ិចទ័រស្ថានភាពដំបូង ហើយបន្ទាប់មកបង្កើតលំដាប់លទ្ធផល។\n",
"\n",
"នៅក្នុងសៀវភៅកំណត់ត្រានេះ យើងនឹងផ្តោតទៅលើម៉ូដែលបង្កើតបណ្តាក់សាមញ្ញ ដែលជួយយើងបង្កើតអត្ថបទ។ ដើម្បីសម្រួល អាចសង់បណ្តាញ **កម្រិតតួអក្សរ** ដែលបង្កើតអត្ថបទតួអក្សរតាមតួអក្សរ។ នៅពេលហ្វឹកហាត់ យើងត្រូវយកអត្ថបទមួយ ហើយបំបែកវាទៅជា លំដាប់តួអក្សរ។\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import tensorflow as tf\n",
"from tensorflow import keras\n",
"import tensorflow_datasets as tfds\n",
"import numpy as np\n",
"\n",
"ds_train, ds_test = tfds.load('ag_news_subset').values()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ការបង្កើតវាក្យសព្ទតួអក្សរ\n",
"\n",
"ដើម្បីបង្កើតបណ្តាញបង្កើតនៅតួអក្សររង្វែង, យើងត្រូវបំបែកអត្ថបទទៅជាតួអក្សរដូចខ្លួនតូចមួយមិនមែនជាពាក្យទេ។ ស្រទាប់ `TextVectorization` ដែលយើងបានប្រើមុនមិនអាចធ្វើបែបនេះបានទេ, ដូចនេះយើងមានជម្រើសពីរម៉េ៖\n",
"\n",
"* ដាក់អត្ថបទដោយដៃហើយធ្វើការកំណត់និយមន័យពាក្យ 'ដោយដៃ', ដូចដែលមាននៅក្នុង [គំរូផ្លូវការនៃ Keras](https://keras.io/examples/generative/lstm_character_level_text_generation/)\n",
"* ប្រើថ្នាក់ `Tokenizer` សម្រាប់កំណត់និយមន័យតួអក្សររង្វែង។\n",
"\n",
"យើងនឹងជ្រើសរើសជម្រើសទីពីរ។ អាចប្រើ `Tokenizer` សម្រាប់កំណត់និយមន័យទៅជាពាក្យបានផងដែរ, ដូច្នេះអ្នកអាចប្ដូរពីការកំណត់និយមន័យតួអក្សរទៅកាន់ការកំណត់និយមន័យពាក្យបានយ៉ាងងាយស្រួល។\n",
"\n",
"ដើម្បីធ្វើការកំណត់និយមន័យតួអក្សររង្វែង, យើងត្រូវផ្តល់ប៉ារ៉ាម៉ែត្រ `char_level=True`៖\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"def extract_text(x):\n",
" return x['title']+' '+x['description']\n",
"\n",
"def tupelize(x):\n",
" return (extract_text(x),x['label'])\n",
"\n",
"tokenizer = keras.preprocessing.text.Tokenizer(char_level=True,lower=False)\n",
"tokenizer.fit_on_texts([x['title'].numpy().decode('utf-8') for x in ds_train])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"យើងក៏ចង់ប្រើតួអក្សរពិសេសមួយដើម្បីបង្ហាញ **ចប់សន្ទស្សន៍** ដែលយើងនឹងហៅវា \\<eos>។ មកដាក់វាដោយដៃទៅក្នុងវាក្យសព្ទ៖\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"eos_token = len(tokenizer.word_index)+1\n",
"tokenizer.word_index['<eos>'] = eos_token\n",
"\n",
"vocab_size = eos_token + 1"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ឥឡូវនេះ ដើម្បីកូដអត្ថបទទៅជាអក្សរលេខ ជួរដេក យើងអាចប្រើបាន៖\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[[48, 2, 10, 10, 5, 44, 1, 25, 5, 8, 10, 13, 78]]"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tokenizer.texts_to_sequences(['Hello, world!'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ការបណ្តុះបណ្តាល RNN បង្កើតស្លោកឲ្យបាន\n",
"\n",
"វិធីដែលយើងនឹងបណ្តុះបណ្តាល RNN ដើម្បីបង្កើតស្លោកព័ត៌មាន គឺដូចខាងក្រោម។ នៅក្នុងជំហានមួយៗ យើងនឹងយកស្លោកមួយ ដែលនឹងត្រូវបញ្ចូលចូលទៅក្នុង RNN ហើយសម្រាប់តួអក្សរបញ្ចូលមួយៗ យើងនឹងស្នើឲ្យបណ្តាញបង្កើតតួអក្សរចេញបន្ទាប់៖\n",
"\n",
"![Image showing an example RNN generation of the word 'HELLO'.](../../../../../translated_images/km/rnn-generate.56c54afb52f9781d.webp)\n",
"\n",
"សម្រាប់តួអក្សរចុងក្រោយនៃខ្សែស្រឡាយយើង នឹងស្នើឲ្យបណ្តាញបង្កើត `<eos>` token។\n",
"\n",
"ភាពខុសគ្នាចម្បងរវាង RNN បង្កើតដែលយើងកំពុងប្រើនៅទីនេះ គឺយើងនឹងយកលទ្ធផលចេញពីជំហាននីមួយៗរបស់ RNN មិនមែនពីកោសិការចុងក្រោយតែប៉ុណ្ណោះទេ។ នេះអាចធ្វើទៅបានដោយកំណត់ប៉ារ៉ាម៉ែត្រ `return_sequences` ទៅកាន់កោសិការនៃ RNN។\n",
"\n",
"ដូច្នេះ ក្នុងការបណ្តុះបណ្តាលផ្នែកបញ្ចូលទៅបណ្តាញនឹងជាខ្សែស្រឡាយតួអក្សរដែលបានកូដមួយចំនួននៃប្រវែងមួយ ហើយលទ្ធផលនឹងជាខ្សែស្រឡាយដែលមានប្រវែងដូចគ្នា ប៉ុន្តែប្រែប្រួលដោយផ្លាស់ទីមួយធាតុ ហើយបញ្ចប់ដោយ `<eos>`។ Minibatch នឹងមានខ្សែស្រឡាយប៉ុន្មានដង ដូច្នេះយើងត្រូវប្រើ **padding** ដើម្បីតម្រឹមខ្សែស្រឡាយទាំងអស់។\n",
"\n",
"ឲ្យយើងបង្កើតអនុគមន៍ដែលនឹងផ្លាស់ប្តូរព័ត៌មានសម្រាប់យើង។ ពីព្រោះយើងចង់បញ្ចូល padding នៅលើកម្រិត minibatch ជាមុនសិន យើងនឹងដំបូងធ្វើការ batch ដataset ដោយហៅ `.batch()` រួចបន្ទាប់មក `map` វាដើម្បីធ្វើការបម្លែង។ ដូច្នេះ អនុគមន៍បម្លែងនឹងទទួលបាន minibatch មួយពេញជា argument៖\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"def title_batch(x):\n",
" x = [t.numpy().decode('utf-8') for t in x]\n",
" z = tokenizer.texts_to_sequences(x)\n",
" z = tf.keras.preprocessing.sequence.pad_sequences(z)\n",
" return tf.one_hot(z,vocab_size), tf.one_hot(tf.concat([z[:,1:],tf.constant(eos_token,shape=(len(z),1))],axis=1),vocab_size)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"មានអ្វីៗ​សំខាន់​ច្រើន​ដែល​យើងធ្វើនៅទីនេះ៖\n",
"* យើងចាប់ដកអត្ថបទពិតពី string tensor ដំបូង\n",
"* `text_to_sequences` ដំណើរការប្រែបញ្ជី string ទៅជា​បញ្ជី tensor ពីរៃងខុសៗគ្នា\n",
"* `pad_sequences` បន្ថែម padding ទៅលើ tensor ទាំងនោះ ដល់កម្ពស់តែមួយ\n",
"* ចុងក្រោយ យើងបំលែងតួអក្សរទាំងអស់ទៅជា one-hot និងធ្វើការ shifting និងបន្ថែម `<eos>` ផងដែរ។ យើងនឹងឃើញភ្លាមៗហេតុផលហេតុអ្វីយើងត្រូវការតួអក្សរត្រូវបានបំលែងជា one-hot encoded\n",
"\n",
"ទោះជាយ៉ាងណា មុខងារនេះគឺជាមុខងារ **Pythonic** មានន័យថា វាមិនអាចបម្លែងដោយស្វ័យប្រវត្តិទៅជា Tensorflow computational graph បានទេ។ យើងនឹងទទួលបានកំហុស ប្រសិនបើយើងខំប្រើមុខងារនេះដោយផ្ទាល់ក្នុង `Dataset.map` function។ យើងត្រូវបង្រួមការហៅ Pythonic នេះដោយប្រើ `py_function` wrapper:\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"def title_batch_fn(x):\n",
" x = x['title']\n",
" a,b = tf.py_function(title_batch,inp=[x],Tout=(tf.float32,tf.float32))\n",
" return a,b"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"> **កំណត់ចំណាំ**: ការបែងចែករវាងមុខងារបម្លែង Pythonic និង Tensorflow អាចហាក់ដូចជាស្មុគស្មាញចំពោះមួយភាគតិច ហើយអ្នកអាចកំពុងសួរថាហេតុអ្វីយើងមិនបម្លែងឈុតទិន្នន័យដោយប្រើមុខងារពី Python តាមទម្លាប់មុនពេលផ្ទុកទៅកាន់ `fit` ទេ។ ខណៈដែលវាអាចធ្វើបានប្រាកដ មុខងារ `Dataset.map` មានអត្ថប្រយោជន៍យ៉ាងខ្លាំង ពីព្រោះបំពង់បម្លែងទិន្នន័យត្រូវបានអនុវត្តដោយប្រើតង់ស័រហ្វ្លូក្រិហ្វកំណត់គណនា ដែលអាចប្រើអត្ថប្រយោជន៍នៃកំណត់គណនាការជាGPU ហើយកាត់បន្ថយការចាំបាច់ផ្ទុកទិន្នន័យរវាងCPU/GPU។\n",
"\n",
"ឥឡូវនេះយើងអាចបង្កើតបណ្ដាញកំណើតរបស់យើង និងចាប់ផ្តើមបណ្តុះបណ្តាល។ វាអាចផ្អែកលើកោសិកា recurrent មួយណាមួយដែលយើងបានពិភាក្សានៅឯកត្តាមុន (សាមញ្ញ, LSTM ឬ GRU)។ ក្នុងឧទាហរណ៍របស់យើង យើងនឹងប្រើ LSTM។\n",
"\n",
"ដោយសារតែបណ្ដាញទទួលតួអក្សរជា input ហើយទំហំវាកាបូប៉ុន្មានតូច យើងមិនត្រូវការជាន់ embedding ទេ ការបញ្ចូលតួតែតែមួយ-hot-encoded អាចចូលទៅកោសិកា LSTM ដោយផ្ទាល់។ ជាន់ output នឹងជា `Dense` ប្រភេទចម្រាញ់ ដែលនឹងបម្លែងចេញពី LSTM ទៅជាលេខកូដតួតែតែមួយ-hot។\n",
"\n",
"បន្ថែមពីនេះ ពេលដែលយើងកំពុងដំណើរការជាមួយសេរីពហុបំណែង មួយ អាចប្រើជាន់ `Masking` ដើម្បីបង្កើតម៉ាស ដែលនឹងមិនគិតផ្នែកដែលពុម្ភបន្ថែមនៅចុងជួរខ្សែអក្សរ។ នេះមិនចាំបាច់តឹងត្រាប់ទេ ពីព្រោះយើងមិនសម្លឹងទៅលើអ្វីៗទាំងអស់ដែលនៅក្រៅតួ `<eos>` ទេ ប៉ុន្តែក្នុងករណីនេះយើងនឹងប្រើវាសម្រាប់ទទួលបានបទពិសោធន៍ជាមួយប្រភេទជាន់នេះ។ `input_shape` នឹងមាន `(None, vocab_size)` ដែល `None` មានន័យថាជាសំណុំជួរចំណងជើងបញ្ចេញផ្សេងៗ ហើយទំហំនៃប្រអប់គឺ `(None,vocab_size)` ផងដែរ ដូចដែលអ្នកអាចមើលឃើញពី `summary`:\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"sequential\"\n",
"_________________________________________________________________\n",
"Layer (type) Output Shape Param # \n",
"=================================================================\n",
"masking (Masking) (None, None, 84) 0 \n",
"_________________________________________________________________\n",
"lstm (LSTM) (None, None, 128) 109056 \n",
"_________________________________________________________________\n",
"dense (Dense) (None, None, 84) 10836 \n",
"=================================================================\n",
"Total params: 119,892\n",
"Trainable params: 119,892\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n",
"15000/15000 [==============================] - 229s 15ms/step - loss: 1.5385\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7fa40c1245e0>"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model = keras.models.Sequential([\n",
" keras.layers.Masking(input_shape=(None,vocab_size)),\n",
" keras.layers.LSTM(128,return_sequences=True),\n",
" keras.layers.Dense(vocab_size,activation='softmax')\n",
"])\n",
"\n",
"model.summary()\n",
"model.compile(loss='categorical_crossentropy')\n",
"\n",
"model.fit(ds_train.batch(8).map(title_batch_fn))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ការបង្កើតលទ្ធផល\n",
"\n",
"ឥឡូវនេះដែលយើងបានបណ្តុះម៉ូដែលហើយ យើងចង់ប្រើវាដើម្បីបង្កើតលទ្ធផលមួយចំនួន។ ជាការដំបូង យើងត្រូវការរបៀបមួយក្នុងការបកប្រែអក្សរដែលតំណាងដោយលំដាប់លេខសញ្ញាសម្គាល់។ ដើម្បីធ្វើការនេះ យើងអាចប្រើមុខងារ `tokenizer.sequences_to_texts` ប៉ុន្តែវាមិនដំណើរការល្អជាមួយការបំបែកសញ្ញាលេខនៅកម្រិតតួអក្សរទេ។ ដូច្នេះ យើងនឹងយកវចនានុក្រមនៃសញ្ញាសម្គាល់ពី tokenizer (ហៅថា `word_index`), សង់ផែនទីត្រឡប់ក្រោយមួយ, ហើយសរសេរមុខងារបកប្រែរបស់យើងផ្ទាល់៖\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"reverse_map = {val:key for key, val in tokenizer.word_index.items()}\n",
"\n",
"def decode(x):\n",
" return ''.join([reverse_map[t] for t in x])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ឥឡូវនេះ យើងនឹងធ្វើការបង្កើត។ យើងនឹងចាប់ផ្តើមដោយខ្សែអក្សរ `start` មួយ ប្រើបំលែងវាទៅជាមួក `inp` ហើយបន្ទាប់មកនៅគ្រប់ជំហានយើងនឹងហៅបណ្ដាញរបស់យើងដើម្បីប៉ាន់ស្មានតួអក្សរបន្ទាប់។ \n",
"\n",
"ចេញពីបណ្ដាញ `out` គឺជាវ៉ែថ័រមានធាតុ `vocab_size` ដែលតំណាងឱ្យប្រសិទ្ធភាពនៃតួអក្សរនីមួយៗ ហើយយើងអាចស្វែងរកលេខតួអក្សរដែលមានប្រសិទ្ធភាពខ្ពស់បំផុតដោយប្រើ `argmax`។ បន្ទាប់មក យើងបន្ថែមតួអក្សរនោះទៅក្នុងបញ្ជីតួអក្សរដែលបានបង្កើត ហើយបន្តការបង្កើត។ ដំណើរការនៃការបង្កើតតួអក្សរមួយនេះត្រូវបានធ្វើឡើងជាប្រសិទ្ធិភាព `size` ដងដើម្បីបង្កើតចំនួនតួអក្សរត្រូវការ ហើយយើងបញ្ចប់មុនពេលរបស់វានៅពេលជួប `eos_token`។\n"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'Today #39;s lead to strike for the strike for the strike for the strike (AFP)'"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def generate(model,size=100,start='Today '):\n",
" inp = tokenizer.texts_to_sequences([start])[0]\n",
" chars = inp\n",
" for i in range(size):\n",
" out = model(tf.expand_dims(tf.one_hot(inp,vocab_size),0))[0][-1]\n",
" nc = tf.argmax(out)\n",
" if nc==eos_token:\n",
" break\n",
" chars.append(nc.numpy())\n",
" inp = inp+[nc]\n",
" return decode(chars)\n",
" \n",
"generate(model)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## លទ្ធផលសម្រាប់ការយកមាតិកាត្រង់ពេលបណ្តុះបណ្តាល\n",
"\n",
"ដោយសារតែយើងមិនមានមាត្រដ្ឋានណាមួយដែលមានប្រយោជន៍ដូចជា *ភាពត្រឹមត្រូវ* ទេ វិធីតែមួយដែលយើងអាចមើលឃើញថាគំរូរបស់យើងកាន់តែប្រសើរឡើងគឺដោយ **យកមាតិកា** ខ្សែអក្សរ​ដែលបង្កើតឡើងក្នុងពេលបណ្តុះបណ្តាល។ ដើម្បីបំពេញការនេះ យើងនឹងប្រើ **callbacks** ឧ. អនុគមន៍ដែលយើងអាចផ្តល់ទៅអនុគមន៍ `fit` ហើយវានឹងត្រូវបានហៅជាបន្តបន្ទាប់ក្នុងកំឡុងពេលបណ្តុះបណ្តាល។\n"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Epoch 1/3\n",
"15000/15000 [==============================] - 226s 15ms/step - loss: 1.2703\n",
"Today #39;s a lead in the company for the strike\n",
"Epoch 2/3\n",
"15000/15000 [==============================] - 227s 15ms/step - loss: 1.2057\n",
"Today #39;s the Market Service on Security Start (AP)\n",
"Epoch 3/3\n",
"15000/15000 [==============================] - 226s 15ms/step - loss: 1.1752\n",
"Today #39;s a line on the strike to start for the start\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7fa40c74e3d0>"
]
},
"execution_count": 13,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sampling_callback = keras.callbacks.LambdaCallback(\n",
" on_epoch_end = lambda batch, logs: print(generate(model))\n",
")\n",
"\n",
"model.fit(ds_train.batch(8).map(title_batch_fn),callbacks=[sampling_callback],epochs=3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ឧទាហរណ៍នេះបានបង្កើតអត្ថបទល្អមួយចំនួនរួចហើយ ប៉ុន្តែវាអាចត្រូវបានបង្កើនកាន់តែប្រសើរឡើងនៅក្នុងវិធីជាច្រើន៖\n",
"* **អត្ថបទច្រើនជាងនេះ**។ យើងបានប្រើតែចំណងជើងសម្រាប់ភារកិច្ចរបស់យើងប៉ុណ្ណោះ ប៉ុន្តែអ្នកអាចចង់សាកល្បងជាមួយអត្ថបទពេញលេញ។ ចូរចាំថា RNNs មិនខ្លាំងណាស់ក្នុងការដោះស្រាយបន្ទាត់វែងៗពីរណោះ ដូច្នេះវាជាសមរម្យក្នុងការបំបែកពួកវាចូលទៅជាឃ្លាសង្ខេបឬជាប្រចាំហ្វឹកហាត់នៅលើរយៈពេលជាកំណត់ដែលបានកំណត់ជាមុន `num_chars` (ឧ. ២៥៦)។ អ្នកអាចសាកល្បងបម្លែងឧទាហរណ៍ខាងលើទៅជារចនាសម្ព័ន្ធបែបនេះដោយប្រើ [មេរៀនផ្លូវការ Keras](https://keras.io/examples/generative/lstm_character_level_text_generation/) ជាការបំផុសគំនិត។\n",
"* **LSTM ជាច្រើនស្រទាប់**។ វាផ្តល់ន័យក្នុងការសាកល្បង ២ ឬ ៣ ស្រទាប់នៃកោសិកា LSTM។ ដូចដែលយើងបានរៀបរាប់នៅក្នុងមុខវិជ្ជាពេលមុន ស្រទាប់នីមួយៗនៃ LSTM នឹងដកស្រង់គំរូខ្លះៗពីអត្ថបទ ហើយសម្រាប់អ្នកបង្កើតអត្ថបទតាមកម្រិតតួអក្សរ យើងអាចរំពឹងថា ស្រទាប់ LSTM កម្រិតទាបនឹងទទួលខុសត្រូវក្នុងការដកស្រង់ពាក្យបញ្ជប់ខ្លះៗ ហើយស្រទាប់ខ្ពស់ជាងនេះ - សម្រាប់ពាក្យ និងការរួមបញ្ចូលនៃពាក្យ។ វាអាចអនុវត្តបានយ៉ាងសាមញ្ញដោយផ្តល់ប៉ារ៉ាម៉ែត្រពីចំនួនស្រទាប់ទៅកាន់ការសង់ LSTM។\n",
"* អ្នកក៏អាចចង់សាកល្បងជាមួយ **ឯកតា GRU** ហើយមើលថាតើឯកតាណាអនុវត្តល្អជាង និងជាមួយ **ទំហំស្រទាប់លាក់ផ្សេងៗ**។ ទំហំស្រទាប់លាក់ធំពេកអាចនាំឲ្យមានការបំផ្លាញ (ឧ. បណ្ដាញនឹងរៀនអត្ថបទជាក់លាក់) ហើយទំហំតូចជាងអាចមិនបង្កើតលទ្ធផលល្អបាន។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ការបង្កើតអត្ថបទទន់និងសីតុណ្ហភាព\n",
"\n",
"នៅក្នុងការបញ្ជាក់ទ្រឹស្តី `generate` មុននេះ មនុស្សយើងបានយកតួអក្សរដែលមានប្រតិបត្តិភាពខ្ពស់បំផុតជាតួអក្សរបន្ទាប់ក្នុងអត្ថបទដែលបានបង្កើត។ នេះបណ្តាលឲ្យអត្ថបទមួយចំនួន \"វិលជាថ្មី\" រវាងលំដាប់តួអក្សរដូចគ្នាឡើងវិញ ជាញឹកញាប់ ដូចក្នុងឧទាហរណ៍នេះ៖\n",
"```\n",
"today of the second the company and a second the company ...\n",
"```\n",
"\n",
"ដូច្នេះ ប្រសិនបើយើងមើលការបែងចែកប្រតិបត្តិភាពសម្រាប់តួអក្សរបន្ទាប់ វាអាចជា ភាពខុសគ្នារវាងប្រតិបត្តិភាពខ្ពស់បំផុតតិចណាស់ ឧទាហរណ៍ តួអក្សរមួយអាចមានប្រតិបត្តិភាព ០.២ ខណៈតួអក្សរមួយផ្សេងទៀត - ០.១៩ លី។ ឧទាហរណ៍ពេលស្វែងរកតួអក្សរបន្ទាប់ក្នុងលំដាប់ '*play*', តួអក្សរបន្ទាប់អាចជាស្ពាន (space) ឬ **e** (ដូចក្នុងពាក្យ *player*) បានស្មើ។\n",
"\n",
"នេះនាំឲ្យយើងសន្និដ្ឋានថា មិនមែនជារឿង \"ត្រឹមត្រូវ\" ទៅតែងតួអក្សរដែលមានប្រតិបត្តិភាពខ្ពស់ជានិច្ចទេ ពីព្រោះការជ្រើសរើសលេខពីរខ្ពស់បំផុតអាចនាំឲ្យយើងទទួលបានអត្ថបទមានអត្ថន័យទៀត។ វាជាការយល់ឃើញល្អក្នុងការធ្វើការគំរូបតួអក្សរពីការបែងចែកប្រតិបត្តិភាពដែលបានផ្ដល់ដោយលទ្ធផលបណ្តាញ។\n",
"\n",
"ការគំរូបនេះអាចធ្វើបានដោយប្រើមុខងារ `np.multinomial` ដែលអនុវត្តការបែងចែកប្រតិបត្តិភាពហៅថា **multinomial distribution**។ មុខងារដែលអនុវត្តការបង្កើតអត្ថបទប្រភេទ**ទន់**នេះត្រូវបានកំណត់ខាងក្រោម៖\n"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"--- Temperature = 0.3\n",
"Today #39;s strike #39; to start at the store return\n",
"On Sunday PO to Be Data Profit Up (Reuters)\n",
"Moscow, SP wins straight to the Microsoft #39;s control of the space start\n",
"President olding of the blast start for the strike to pay &lt;b&gt;...&lt;/b&gt;\n",
"Little red riding hood ficed to the spam countered in European &lt;b&gt;...&lt;/b&gt;\n",
"\n",
"--- Temperature = 0.8\n",
"Today countie strikes ryder missile faces food market blut\n",
"On Sunday collores lose-toppy of sale of Bullment in &lt;b&gt;...&lt;/b&gt;\n",
"Moscow, IBM Diffeiting in Afghan Software Hotels (Reuters)\n",
"President Ol Luster for Profit Peaced Raised (AP)\n",
"Little red riding hood dace on depart talks #39; bank up\n",
"\n",
"--- Temperature = 1.0\n",
"Today wits House buiting debate fixes #39; supervice stake again\n",
"On Sunday arling digital poaching In for level\n",
"Moscow, DS Up 7, Top Proble Protest Caprey Mamarian Strike\n",
"President teps help of roubler stepted lessabul-Dhalitics (AFP)\n",
"Little red riding hood signs on cash in Carter-youb\n",
"\n",
"--- Temperature = 1.3\n",
"Today wits flawer ro, pSIA figat's co DroftwavesIs Talo up\n",
"On Sunday hround elitwing wint EU Powerburlinetien\n",
"Moscow, Bazz #39;s sentries olymen winnelds' next for Olympite Huc?\n",
"President lost securitys from power Elections in Smiltrials\n",
"Little red riding hood vides profit, exponituity, profitmainalist-at said listers\n",
"\n",
"--- Temperature = 1.8\n",
"Today #39;It: He deat: N.KA Asside\n",
"On Sunday i arry Par aldeup patient Wo stele1\n"
]
},
{
"ename": "KeyError",
"evalue": "0",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-33-db32367a0feb>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 18\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34mf\"\\n--- Temperature = {i}\"\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mj\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m5\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 20\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mgenerate_soft\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmodel\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0msize\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;36m300\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mstart\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mwords\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mj\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0mtemperature\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m<ipython-input-33-db32367a0feb>\u001b[0m in \u001b[0;36mgenerate_soft\u001b[0;34m(model, size, start, temperature)\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[0mchars\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnc\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 12\u001b[0m \u001b[0minp\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0minp\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mnc\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 13\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0mdecode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mchars\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 14\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 15\u001b[0m \u001b[0mwords\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0;34m'Today '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'On Sunday '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'Moscow, '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'President '\u001b[0m\u001b[0;34m,\u001b[0m\u001b[0;34m'Little red riding hood '\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;32m<ipython-input-10-3f5fa6130b1d>\u001b[0m in \u001b[0;36mdecode\u001b[0;34m(x)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mdecode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0;34m''\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mreverse_map\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mt\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mt\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;32m<ipython-input-10-3f5fa6130b1d>\u001b[0m in \u001b[0;36m<listcomp>\u001b[0;34m(.0)\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mdecode\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mx\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0;32mreturn\u001b[0m \u001b[0;34m''\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mreverse_map\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mt\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mt\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mx\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
"\u001b[0;31mKeyError\u001b[0m: 0"
]
}
],
"source": [
"def generate_soft(model,size=100,start='Today ',temperature=1.0):\n",
" inp = tokenizer.texts_to_sequences([start])[0]\n",
" chars = inp\n",
" for i in range(size):\n",
" out = model(tf.expand_dims(tf.one_hot(inp,vocab_size),0))[0][-1]\n",
" probs = tf.exp(tf.math.log(out)/temperature).numpy().astype(np.float64)\n",
" probs = probs/np.sum(probs)\n",
" nc = np.argmax(np.random.multinomial(1,probs,1))\n",
" if nc==eos_token:\n",
" break\n",
" chars.append(nc)\n",
" inp = inp+[nc]\n",
" return decode(chars)\n",
"\n",
"words = ['Today ','On Sunday ','Moscow, ','President ','Little red riding hood ']\n",
" \n",
"for i in [0.3,0.8,1.0,1.3,1.8]:\n",
" print(f\"\\n--- Temperature = {i}\")\n",
" for j in range(5):\n",
" print(generate_soft(model,size=300,start=words[j],temperature=i))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"យើងបានណែនាំអង្កត់ផ្ចិតមួយទៀតដែលហៅថា **សីតុខ** ដែលប្រើសម្រាប់បង្ហាញពីរបៀបយើងគួរតែខិតខំយ៉ាងម៉េចក្នុងការបន្តតាមប្រាក់ប្រហែលខ្ពស់បំផុត។ ប្រសិនបើសីតុណ្ហភាពគឺ 1.0 យើងធ្វើការប៉ាន់ប្រមាណតាមម៉ុលទីណូម្យលាដោយសមរម្យ ហើយនៅពេលដែលសីតុណ្ហភាពទៅរកអនាម័យ - ប្រាក់ប្រហែលទាំងអស់នឹងមានតុល្យភាព ហើយយើងជ្រើសរើសតួអក្សរបន្ទាប់ដោយចៃដន្យ។ ក្នុងឧទាហរណ៍ខាងក្រោម យើងអាចសង្កេតឃើញថាអត្ថន័យអក្សរត្រូវបានបាត់បង់ពេលយើងបង្កើនសីតុណ្ហភាពច្រើនពេក ហើយវាបង្ហាញភាពស្រដៀងនឹងអត្ថបទដែលបានបង្កើតឡើងយ៉ាងម៉ត់ចត់ដែលមានលក្ខណៈ \"ចំណោត\" នៅពេលវាហាក់ដូចជាយឺនទៅកាន់ 0។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**ការបដិសេធ**៖ \nឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេលយើងខំប្រឹងរកភាពត្រឹមត្រូវ សូមយល់ដឹងថា ការបកប្រែជា​អូតូម៉ាទិច​អាចមានកំហុសឬភាពមិនត្រឹមត្រូវ។ ឯកសារដើម​នៅក្នុងភាសាម្ចាស់ផ្លូវគួរត្រូវបានចាត់ទុកជាមូលដ្ឋានដ៏មានអំណាច។ សម្រាប់ព័ត៌មានសំខាន់ វិជ្ជាជីវៈ​ដូចជាការបកប្រែ​ដោយមនុស្សមានជំនាញ​ត្រូវបានណែនាំ។ យើង​មិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកស្រាយខុស ពីការប្រើប្រាស់ការបកប្រែនេះទេ។\n<!-- CO-OP TRANSLATOR DISCLAIMER END -->\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "16af2a8bbb083ea23e5e41c7f5787656b2ce26968575d8763f2c4b17f9cd711f"
},
"kernelspec": {
"display_name": "Python 3.8.12 ('py38')",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.12"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,83 @@
# បណ្តាហ្ស៊ីនហ្សិន
## [ការប្រលងមុនមេរៀន](https://ff-quizzes.netlify.app/en/ai/quiz/33)
បណ្តាញប្រព័ន្ធសរសេរការត្រឡប់ (RNNs) និងបែបផែនកោសិកាគ្រប់គ្រងរបស់វា ដូចជាកោសិកាចងចាំរយៈពេលវែង (LSTMs) និងឯកតាចងចាំត្រឡប់ជ្រុល (GRUs) ផ្តល់នូវយន្តការសម្រាប់ការម៉ូដែលភាសា ដែលពួកវាអាចរៀនពីការរៀបចំពាក្យ ហើយផ្តល់ការព្យាករណ៍សម្រាប់ពាក្យបន្ទាប់ក្នុងខ្សែ។ នេះអនុញ្ញាតឲ្យយើងប្រើប្រាស់ RNNs សម្រាប់ **ភារកិច្ចបង្កើត** ដូចជា ការបង្កើតអត្ថបទធម្មតា ការបកប្រែម៉ាស៊ីន ហើយត្រូវម្ដងលើការបង្កើតរូបភាពនៃការពិពណ៌នា។
> ✅ គិតអំពីពេលវេលាដែលអ្នកទទួលបានអត្ថប្រយោជន៍ពីភារកិច្ចបង្កើតដូចជាការបញ្ចប់អត្ថបទនៅពេលអ្នកវាយ។ ស្វែងយល់បន្ថែមអំពីកម្មវិធីដែលអ្នកចូលចិត្ត ដើម្បីមើលថាពួកវាប្រើប្រាស់ RNNs ឬទេ។
នៅក្នុងស្ថាបត្យកម្ម RNN ដែលយើងបានពិភាក្សាកន្លងមកក្នុងឯកត្តិមួយ មួយឯកតា RNN រៀងរាល់មួយបានបង្កើតស្ថានភាពលាក់បន្ទាប់ជាផលិតផល។ ទោះយ៉ាងណា យើងក៏អាចបន្ថែមការបញ្ចេញផ្សេងទៀតទៅឯកតាត្រឡប់មួយៗ ដែលអាចអនុញ្ញាតឱ្យយើងបញ្ចេញ **ខ្សែបន្ទាត់** (ដែលមានប្រវែងស្មើនឹងខ្សែដើម)។ លើសពីនេះ យើងអាចប្រើឯកតា RNN ដែលមិនទទួលបញ្ចូលក្នុងរៀងរាល់ជំហាន ហើយគ្រាន់តែទទួលវ៉ិចទ័រស្ថានភាពដំបូង ហើយបន្ទាប់មកបង្កើតខ្សែបញ្ចេញ។
នេះអនុញ្ញាតស្ថាបត្យកម្មប្រព័ន្ធសរសេរបុរាណផ្សេងៗដែលបង្ហាញនៅក្នុងរូបខាងក្រោម៖
![Image showing common recurrent neural network patterns.](../../../../../translated_images/km/unreasonable-effectiveness-of-rnn.541ead816778f42d.webp)
> រូបភាពពីអត្ថបទប្លុក [Unreasonable Effectiveness of Recurrent Neural Networks](http://karpathy.github.io/2015/05/21/rnn-effectiveness/) ដោយ [Andrej Karpaty](http://karpathy.github.io/)
* **មួយទៅមួយ** គឺជាបណ្តាញប្រព័ន្ធប្រពៃណីមួយដែលមានបញ្ចូលមួយ និងបញ្ចេញមួយ
* **មួយទៅច្រើន** គឺជាស្ថាបត្យកម្មបង្កើត ដែលទទួលតម្លៃបញ្ចូលមួយ ហើយបង្កើតខ្សែតម្លៃបញ្ចេញច្រើន។ ឧទាហរណ៍ ប្រសិនបើយើងចង់បណ្តុះបណ្តាលបណ្តាញ **ពិពណ៌នារូបភាព** ដែលនឹងបង្កើតការពិពណ៌នាអក្សរអំពីរូបភាពមួយ យើងអាចយករូបភាពម្តងមួយជាការបញ្ចូល កាត់ចាយវាដោយ CNN ដើម្បីទទួលបានស្ថានភាពលាក់របស់វា ហើយបន្ទាប់មកឲ្យខ្សែត្រឡប់បង្កើតពាក្យពិពណ៌នាតិចតួចៗ
* **ច្រើនទៅមួយ** តំណាងឲ្យស្ថាបត្យកម្ម RNN ដែលយើងពិភាក្សាកន្លងមក ដូចជា ការកំណត់ចំណាត់ថ្នាក់អត្ថបទ
* **ច្រើនទៅច្រើន****ខ្សែទៅខ្សែ** និយាយទៅដល់ភារកិច្ចដូចជា **ការបកប្រែម៉ាស៊ីន** ដែលនៅទីនេះការ RNN ដំបូងប្រមូលព័ត៌មានគ្រប់គ្រាន់ពីខ្សែបញ្ចូល ទៅក្នុងស្ថានភាពលាក់ ហើយខ្សែ RNN ទៀតម្ដងនឹងបំបែកស្ថានភាពនេះទៅជាខ្សែក្រុមផលិត។
នៅក្នុងឯកត្តិនេះ យើងនឹងផ្តោតលើម៉ូដែលបង្កើតសាមញ្ញ ដែលជួយយើងបង្កើតអត្ថបទ។ ដើម្បីសាមញ្ញ យើងនឹងប្រើវិធីបំបែកតួអក្សរសម្រាប់ tokenize។
យើងនឹងបណ្តុះបណ្តាល RNN នេះដើម្បីបង្កើតអត្ថបទជាជំហានៗ។ នៅរៀងរាល់ជំហាន យើងនឹងយកខ្សែអក្សរសំរាប់ប្រវែង `nchars` ហើយស្នើបណ្តាញឲ្យបង្កើតតួអក្សរបន្ទាប់សម្រាប់រាល់តួអក្សរបញ្ចូល៖
![Image showing an example RNN generation of the word 'HELLO'.](../../../../../translated_images/km/rnn-generate.56c54afb52f9781d.webp)
នៅពេលបង្កើតអត្ថបទ (ក្នុងនៅការព្យាករណ៍) យើងចាប់ផ្តើមជាមួយ **បញ្ហារូបមន្ដ** មួយ ដែលត្រូវបានផ្តល់ទៅតាមកោសិកា RNN ដើម្បីបង្កើតស្ថានភាពចំណុចកណ្ដាលរបស់វា ហើយបន្ទាប់មកពីស្ថានភាពនេះ ការបង្កើតនឹងចាប់ផ្តើម។ យើងបង្កើតតួអក្សរពីមួយទៅមួយ ហើយផ្ទុកស្ថានភាព និងតួអក្សរបង្កើតទៅកាន់កោសិកា RNN មួយទៀត សម្រាប់បង្កើតតួបន្ទាប់រហូតដល់បានច្រើនតួអក្សរគ្រប់គ្រាន់។
<img src="../../../../../translated_images/km/rnn-generate-inf.5168dc65e0370eea.webp" width="60%"/>
> រូបភាពដោយអ្នកនិពន្ធ
## ✍️ អនុវត្ត: បណ្តាហ្ស៊ីនហ្សិន
បន្តការសិក្សារបស់អ្នកនៅក្នុងសៀវភៅកំណត់ត្រាខាងក្រោម៖
* [បណ្តាហ្ស៊ីនហ្សិនជាមួយ PyTorch](GenerativePyTorch.ipynb)
* [បណ្តាហ្ស៊ីនហ្សិនជាមួយ TensorFlow](GenerativeTF.ipynb)
## ការបង្កើតអត្ថបទទន់ និងសីតុណ្ហភាព
លទ្ធផលមួយចំនួននៃកោសិកា RNN គឺចែកចាយប្រូបាប(probability distribution) នៃតួអក្សរ។ ប្រសិនបើយើងគ្រប់ពេលរើសតួអក្សរដែលមានប្រូបាបខ្ពស់ជាងគេជាតួបន្ទាប់ក្នុងអត្ថបទដែលបង្កើត វាអាចធ្វើឲ្យអត្ថបទកើតមានការចងក្រងតួអក្សរដូចគ្នាដងទៀតដងទៀត ប៉ុន្តែក្នុងឧទាហរណ៍នេះ៖
```
today of the second the company and a second the company ...
```
ទោះយ៉ាងណា បើយើងមើលការចែកចាយប្រូបាបសម្រាប់តួបន្ទាប់ វាអាចមានភាពខុសគ្នាគ្នាតិច ប៉ុន្តែមិនមែនធំពេញលេញដែរ តើយ៉ាងណា ឧទាហរណ៍មួយតួអក្សរអាចមានប្រូបាប 0.2 ហើយតួអក្សរមួយទៀត 0.19 ជាដើម។ ដូចគ្នានៅពេលយើងស្វែងរកតួបន្ទាប់សម្រាប់ខ្សែ '*play*' តួបន្ទាប់អាចជាសឹងតែជាផ្ទាំងទំនេរ ឬ **e** (ដូចជា *player*) ។
នេះនាំឲ្យយើងសន្និដ្ឋានថា វាមិនតម្រូវអោយយកតួអក្សរដែលមានប្រូបាបខ្ពស់ជាងគេលើកទីមួយ ព្រោះការជ្រើសរើសតួបន្ទាប់ដែលមានប្រូបាបទីពីរ អាចនៅតែបណ្តាលឯណាក្នុងអត្ថបទមានន័យ។ វាជាជម្រើសដែលប្រសើរជាងហើយគឺ **រាយកម្ម** តួអក្សរពីចែកចាយប្រូបាបដែលបណ្តាញផ្តល់។ យើងអាចប្រើប៉ារ៉ាម៉ែត្រ **សីតុណ្ហភាព** ដែលនឹងធ្វើឲ្យចែកចាយប្រូបាបត្រង់ណាស់ បើយើងចង់បន្ថែមភាពចៃដន្យ ឬធ្វើឲ្យចែកចាយនេះវែងខ្លាំង ប្រសិនបើយើងចង់ជាប់ខ្លាំងជាមួយតួអក្សរដែលមានប្រូបាបខ្ពស់បំផុត។
ធ្វើការស្រាវជ្រាវពីរបៀបបង្កើតអត្ថបទទន់នេះនៅក្នុងសៀវភៅកំណត់ត្រាដែលបានភ្ជាប់ខាងលើ។
## សេចក្តីសន្និដ្ឋាន
ខណៈពេលដែលការបង្កើតអត្ថបទអាចមានប្រយោជន៍ដោយខ្លួនឯង ការប្រយោជន៍សំខាន់គឺការអាចបង្កើតអត្ថបទប្រើប្រាស់ RNNs ពីវ៉ិចទ័រជាលក្ខណៈដំបូងមួយ។ ឧទាហរណ៍ ការបង្កើតអត្ថបទត្រូវបានប្រើក្នុងការបកប្រែម៉ាស៊ីន (sequence-to-sequence នៅទីនេះវ៉ិចទ័រស្ថានភាពពី *encoder* ត្រូវបានប្រើសម្រាប់បង្កើត ឬ *decode* សារ ប្រែប្រាស់) ឬបង្កើតការពិពណ៌នាអក្សរសម្រាប់រូបភាព (នៅទីនេះវ៉ិចទ័រត្រួតត្រានឹងមកពីឧបករណ៍ CNN)។
## 🚀 ប្រយុទ្ធ
ចូលរួមមេរៀន Microsoft Learn លើប្រធានបទនេះ
* ការបង្កើតអត្ថបទជាមួយ [PyTorch](https://docs.microsoft.com/learn/modules/intro-natural-language-processing-pytorch/6-generative-networks/?WT.mc_id=academic-77998-cacaste)/[TensorFlow](https://docs.microsoft.com/learn/modules/intro-natural-language-processing-tensorflow/5-generative-networks/?WT.mc_id=academic-77998-cacaste)
## [ការប្រលងបន្ទាប់ម៉េរៀន](https://ff-quizzes.netlify.app/en/ai/quiz/34)
## ពិនិត្យឡើងវិញ និង អប់រំខ្លួនឯង
នេះជាអត្ថបទមួយចំនួនសម្រាប់ពង្រីកចំណេះដឹងរបស់អ្នក
* វិធីសាស្រ្តផ្សេងៗសម្រាប់បង្កើតអត្ថបទជាមួយ Markov Chain, LSTM និង GPT-2: [អត្ថបទប្លុក](https://towardsdatascience.com/text-generation-gpt-2-lstm-markov-chain-9ea371820e1e)
* គំរូការបង្កើតអត្ថបទនៅក្នុង [ឯកសារ Keras](https://keras.io/examples/generative/lstm_character_level_text_generation/)
## [ការប្រឡង](lab/README.md)
យើងបានឃើញរបៀបបង្កើតអត្ថបទតាមតួអក្សរតួតាមតួ។ នៅក្នុងមន្ទីរពិសោធន៍ អ្នកនឹងស្វែងយល់ពីការបង្កើតអត្ថបទកម្រិតពាក្យ។
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការព្រមាន**៖
ឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេលដែលយើងព្យាយាមរកភាពត្រឹមត្រូវ សូមជ្រាបថាការបកប្រែដោយស្វ័យប្រវត្តិអាចមានកំហុស ឬមិនត្រឹមត្រូវ។ ឯកសារដើមនៅភាសាមាតុភាសាគួរត្រូវបានឲ្យខ្ទង់ជាធាតុមានសក្ដានុពលចម្បង។ សម្រាប់ព័ត៌មានសំខាន់ ការបកប្រែដោយមនុស្សជំនាញត្រូវបានណែនាំ។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកអ្រាយខុសឆ្គងដែលកើតមានពីការប្រើប្រាស់ការបកប្រែនេះឡើយ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,18 @@
# ការបង្កើតអត្ថបទផ្ទាល់កម្រិតពាក្យដោយប្រើ RNNs
ការប្រលងបន្ទប់មួយពី [មេរៀន AI សម្រាប់អ្នកចាប់ផ្តើម](https://github.com/microsoft/ai-for-beginners)។
## បេសកកម្ម
ក្នុងបន្ទប់មួយនេះ អ្នអ្នកត្រូវយកសៀវភៅណាមួយ មួយ ហើយប្រើវាជាគំរូទិន្នន័យដើម្បីបណ្តុះបណ្តាលកម្មវិធីបង្កើតអត្ថបទផ្ទាល់កម្រិតពាក្យ។
## គំរូទិន្នន័យ
អ្នកអាចប្រើសៀវភៅណាមួយបានសូមស្វាគមន៍។ អ្នកអាចរកឃើញអត្ថបទឥតគិតថ្លៃច្រើននៅ [Project Gutenberg](https://www.gutenberg.org/), ជាឧទាហរណ៍ នេះគឺជាលីងផ្ទាល់ដល់ [Alice's Adventures in Wonderland](https://www.gutenberg.org/files/11/11-0.txt)) ដែលសរសេរដោយ Lewis Carroll។
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការព្រមាន**:
ឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ក្នុងកំឡុងពេលយើងខំប្រឹងប្រែងស្តីពីភាពត្រឹមត្រូវ សូមយល់ថាការបកប្រែដោយស្វ័យប្រវត្តិអាចមានកំហុស ឬភាពមិនត្រឹមត្រូវមួយចំនួន។ ឯកសារដើមក្នុងភាសាមាតុភូមិនឹងត្រូវបានគិតថាជាអ្នកផ្តល់ព័ត៌មានដែលមានសុពលភាព។ សម្រាប់ព័ត៌មានសំខាន់ៗ សូមប្រើការបកប្រែដោយមនុស្សដែលមានជំនាញ។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកអត្ថន័យខុស ណាមួយដែលកើតមានពីការប្រើប្រាស់ការបកប្រែនេះទេ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,116 @@
# យន្តការយកចិត្តទុកដាក់ និងម៉ាស៊ីនបំលែង
## [តេស្តមុនវគ្គសិក្សា](https://ff-quizzes.netlify.app/en/ai/quiz/35)
មួយក្នុងចំណោមបញ្ហាទំាងអស់សំខាន់បំផុតនៅក្នុងដែនកំណត់ភាសា NLP គឺ **ការបំលែងភាសាម៉ាស៊ីន** ជាបេសកកម្មសំខាន់ដែលគ្របដណ្តប់ឧបករណ៍ដូចជា Google Translate។ នៅក្នុងផ្នែកនេះ យើងនឹងផ្ដោតលើការបំលែងភាសាម៉ាស៊ីន ឬផ្ទុយទៅវិញ ទាំងមូលលើបេសកកម្ម *sequence-to-sequence* តែម្តង (ដែលត្រូវបានហៅថា **sentence transduction** ហើយ)។
ជាមួយ RNNs បេសកកម្ម sequence-to-sequence ត្រូវបានអនុវត្តដោយបណ្តាញរំលងពីរដង ដែលបណ្តាញមួយ គឺ **encoder** បូកសំណុំនៃវាលបញ្ចូលទៅជារូបភាពស្មុគស្មាញមួយ ខណៈបណ្តាញមួយទៀត គឺ **decoder** ពន្លត់ស្ថានភាពស្មុគស្មាញនេះឲ្យក្លាយជាលទ្ធផលបកប្រែ។ មានបញ្ហាមួយចំនួនជាមួយវិធីសាស្រ្តនេះ៖
* ស្ថានភាពចុងក្រោយនៃបណ្តាញ encoder ពិបាកចងចាំចំណុចចាប់ផ្តើមនៃប្រយោគ ដូច្នេះបណ្តាលឲ្យគុណភាពម៉ូឌែលសម្រាប់ប្រយោគវែងមានភាពខ្សោយ
* ពាក្យទាំងអស់ក្នុងលំដាប់មួយមានឥទ្ធិពលដូចគ្នាទៅលទ្ធផល។ តែតាមពិត ការពិតក្រៅពីនេះ ពាក្យជាក់លាក់មួយចំនួនក្នុងលំដាប់បញ្ចូល ឥទ្ធិពលច្រើនជាងទៅលទ្ធផលរៀងៗខ្លួន។
**យាន្ដការយកចិត្តទុកដាក់** ផ្តល់វិធីសាស្រ្តនៃការផ្តល់ទំងន់ជាន់ខ្ពស់នៃឥទ្ធិពលបរិបទនៃវ៉ិចទ័របញ្ចូលមួយៗលើការព្យាករណ៍លទ្ធផលនៃ RNN។ វា​អនុវត្តដោយបង្កើតផ្លូវប្រាំបញ្ចីរវាងស្ថានភាពចុងចន្លោះនៃ RNN បញ្ចូល និង RNN ផលិត។ ដូច្នេះ នៅពេលបង្កើតនិមិត្ត y<sub>t</sub> យើងនឹងពិចារណាទាំងស្ថានភាពស្មុគស្មាញទាំងអស់ h<sub>i</sub> ដែលមានទំងន់ផ្សេងៗ &alpha;<sub>t,i</sub>
![រូបភាពបង្ហាញម៉ូឌែល encoder/decoder ជាមួយស្រទាប់យកចិត្តទុកដាក់បន្ថែម](../../../../../translated_images/km/encoder-decoder-attention.7a726296894fb567.webp)
> ម៉ូឌែល encoder-decoder ជាមួយយន្តការយកចិត្តទុកដាក់បន្ថែមនៅក្នុង [Bahdanau et al., 2015](https://arxiv.org/pdf/1409.0473.pdf), យោងតាម [បទប្លុកនេះ](https://lilianweng.github.io/lil-log/2018/06/24/attention-attention.html)
លំហាត់ចំណុច {&alpha;<sub>i,j</sub>} នឹងតំណាងឲ្យកម្រិតដែលពាក្យចូលខ្លះៗលេងតួនាទីក្នុងការបង្កើតពាក្យមួយឲ្យបាននៅក្នុងលំដាប់លទ្ធផល។ ខាងក្រោមគឺជាគំរូលំហាត់ចំណុចដូចនេះ៖
![រូបភាពបង្ហាញការតម្រឹមគំរូដែលរកឃើញដោយ RNNsearch-50, យកពី Bahdanau - arviz.org](../../../../../translated_images/km/bahdanau-fig3.09ba2d37f202a6af.webp)
> រូបភាពពី [Bahdanau et al., 2015](https://arxiv.org/pdf/1409.0473.pdf) (រូប.3)
យន្តការយកចិត្តទុកដាក់មានការទទួលខុសត្រូវច្រើនក្នុងសម័យបច្ចុប្បន្នឬជិតសម័យនៃការបង្កើតម៉ូឌែល NLP ដែលមានគុណភាពខ្ពស់។ ការបន្ថែមយកចិត្តទុកដាក់យ៉ាងខ្លាំងបង្កើតចំនួនប៉ារ៉ាម៉ែត្ររបស់ម៉ូឌែលច្រើនច្បាស់ ដែលនាំឲ្យមានបញ្ហាការពង្រីកជាមួយ RNNs។ ការកំណត់មួយសំខាន់នៃការពង្រីក RNN គឺថាបន្ទុកចម្រាស់របស់ម៉ូឌែលធ្វើឲ្យពិបាកក្នុងការបង្រួមកញ្ចប់ និងជំរុញការបង្រៀននៅជាក្រុម។ នៅក្នុង RNN ធាតុក្នុងលំដាប់ត្រូវតែប៉ាប់បញ្ចូលតាមជំហាន​តែមួយ ដែលមានន័យថាវាទាមទារប្រតិបត្តិការតាមលំដាប់មិនអាចជាជាងករណីលើកទៅប្រព័ន្ធបាន។
![ម៉ូឌែល Encoder Decoder ជាមួយ Attention](../../../../../lessons/5-NLP/18-Transformers/images/EncDecAttention.gif)
> រូបភាពពី [Blog របស់ Google](https://research.googleblog.com/2016/09/a-neural-network-for-machine.html)
ការទទួលយកយន្តការយកចិត្តទុកដាក់រួមជាមួយកំណត់ហេតុនេះនាំឲ្យបង្កើតម៉ូឌែលកម្មវិធីបំលែង (Transformer) ដែលជាគោលការណ៍ខាងមុខដែលពេលនេះយើងធ្លាប់ប្រើដូចជា BERT និង Open-GPT3។
## ម៉ូឌែល Transformer
មួយក្នុងចំណោមគំនិតសំខាន់ពីក្រោយម៉ូឌែល transformer គឺដើម្បីលើកលែងលក្ខណៈជាប់លំដាប់តាមដំណាក់កាលរបស់ RNN ហើយបង្កើតម៉ូឌែលដែលអាចដំណើរការជាជួរប្រតិបត្តិការ ក្នុងអំឡុងពេលបង្រៀន។ វាត្រូវបានសម្រេចដោយអនុវត្តពីគំនិតពីរដូចខាងក្រោម៖
* ការបំលែងតំណាងទីតាំង
* ការប្រើម៉ាស៊ីនយកចិត្តទុកដាក់ខ្លួនឯង (self-attention) ដើម្បីចាប់យកលំនាំជំនួស RNNs (ឬ CNNs) (ហើយហើយហេតុអ្វីបានជា អត្ថបទដែលផ្ដល់បទបង្ហាញម៉ូឌែល transformer មានឈ្មោះថា *[Attention is all you need](https://arxiv.org/abs/1706.03762)*)
### ការបំលែង/បញ្ចូលតំណាងទីតាំង
គំនិតនៃការបំលែងតំណាងទីតាំងគឺដូចតទៅ៖
1. នៅពេលប្រើ RNNs ទីតាំងសម្គាល់ឬលំដាប់សមាសធាតុត្រូវតែត្រួតពិនិត្យដោយចំនួនជំហាន, ដូច្នេះមិនចាំបាច់ត្រូវបង្ហាញយ៉ាងច្បាស់។
2. ប៉ុន្តែរ ពេលយើងប្ដូរទៅយកចិត្តទុកដាក់ (attention), យើងត្រូវការបង្ហាញទីតាំងសមាតិកាផ្ទាល់ក្នុងលំដាប់។
3. ដើម្បីទទួលបានការបំលែងតំណាងទីតាំង យើងបន្ថែមលំដាប់តំណាងទីតាំងចូលទៅក្នុងលំដាប់សញ្ញាជាបញ្ចប់ (គឺលំដាប់លេខ 0,1, ...)។
4. បន្ទាប់មកយើងលាយទីតាំងនោះជាមួយវ៉ិចទ័របញ្ចូលមួយ។ ដើម្បីបំលែងទីតាំង (គត់)ទៅជាវ៉ិចទ័រ វាអាចប្រើវិធីខុសៗគ្នាៈ
* ការបញ្ចូលដែលអាចបង្រៀនបាន (trainable embedding) ដូចជាការបញ្ចូលពាក្យ។ វា​គឺជា​វិធីសាស្រ្តដែលយើងពិចារណាទីនេះ។ យើងអនុវត្តស្រទាប់បញ្ចូលលើទាំងពាក្យនិងទីតាំងរបស់វា បង្កើតវ៉ិចទ័របញ្ចូលមានទំហំដូចគ្នា ហើយបូកវាចូលគ្នា។
* មុខងារបំលែងទីតាំងដែលកំណត់ជាលក្ខណៈថេរ ដូចបានបង្ហាញនៅក្នុងអត្ថបទដើម។
<img src="../../../../../translated_images/km/pos-embedding.e41ce9b6cf6078af.webp" width="50%"/>
> រូបភាពដោយអ្នកនិពន្ធ
លទ្ធផលដែលយើងទទួលបានជាមួយការបញ្ចូលតំណាងទីតាំងនោះ គឺបញ្ចូលទាំងពាក្យដើម និងទីតាំងរបស់វានៅក្នុងលំដាប់។
### ការយកចិត្តទុកដាក់ខ្លួនឯងច្រើនក្បាល (Multi-Head Self-Attention)
បន្ទាប់មក យើងត្រូវចាប់យកលំនាំខ្លះៗនៅក្នុងលំដាប់។ ដើម្បីធ្វើឲ្យបាននោះ ម៉ូឌែល transformer ប្រើម៉ាស៊ីន **self-attention** ដែលជាយន្តការយកចិត្តទុកដាក់ដែលអនុវត្តលើលំដាប់ដដែលជាទិន្នន័យបញ្ចូល និងលទ្ធផល។ ការអនុវត្ត self-attention អនុញ្ញាតឲ្យយើងយកបរិបទ **context** នៅក្នុងប្រយោគសំរាប់មើលថាពាក្យណាខ្លះគឺពាក់ព័ន្ធគ្នា។ ឧទាហរណ៍ វាអាចបង្ហាញបានថា ពាក្យណាខ្លះត្រូវបានយោងដោយកំណត់ coreferences ដូចជា *it* និងនឹងយកបរិបទទៅតាងៈ
![](../../../../../translated_images/km/CoreferenceResolution.861924d6d384a7d6.webp)
> រូបភាពពី [Blog របស់ Google](https://research.googleblog.com/2017/08/transformer-novel-neural-network.html)
នៅក្នុងម៉ូឌែល transformers យើងប្រើ **Multi-Head Attention** ដើម្បីផ្តល់អំណាចឲ្យបណ្តាញចាប់យកទំនាក់ទំនងផ្សេងៗពីគ្នាច្រើនប្រភេទ, ឧ.ទំនាក់ទំនងពាក្យរយៈពេលវែង ប្រៀបនឹងរយៈពេលខ្លី, co-reference ប្រៀបនឹងរឿងផ្សេងៗ។
[TensorFlow Notebook](TransformersTF.ipynb) មានព័ត៌មានលម្អិតបន្ថែមអំពីការអនុវត្តស្រទាប់ transformer។
### ការយកចិត្តទុកដាក់រវាង Encoder និង Decoder
នៅក្នុងម៉ូឌែល transformers, ដំណើរការយកចិត្តទុកដាក់ត្រូវបានប្រើនៅទីតាំងពីរប្រភេទ៖
* ចាប់យកលំនាំនៅក្នុងអត្ថបទបញ្ចូលដោយ self-attention
* ព្យាករណ៍បំលែងលំដាប់ - វាជាស្រទាប់យកចិត្តទុកដាក់រវាង encoder និង decoder។
ការយកចិត្តទុកដាក់រវាង encoder និង decoder ទាក់ទងយ៉ាងខ្លាំងនឹងយន្តការយកចិត្តទុកដាក់ដែលបានប្រើនៅក្នុង RNNs ដូចបានពិពណ៌នាពីដើមផ្នែកនេះ។ រូបភាពផ្ដោតអារម្មណ៍ជារូបចល័តនេះពន្យល់ពីតួនាទីរបស់ការយកចិត្តទុកដាក់ encoder-decoder។
![GIF ជារូបចល័តបង្ហាញពីវិធីធ្វើការវាយតម្លៃនៅម៉ូឌែល transformer។](../../../../../lessons/5-NLP/18-Transformers/images/transformer-animated-explanation.gif)
ដោយសារតែទីតាំងបញ្ចូលនិមួយៗត្រូវបានផ្គូរផ្គងដោយឡែកទៅទីតាំងលទ្ធផលនិមួយៗ ម៉ូឌែល transformers អាចបង្រួមនិងផ្សព្វផ្សាយបានល្អជាង RNN ដែលអនុញ្ញាតឲ្យមានម៉ូឌែលភាសាធំធេង និងសកម្មភាពខ្ពស់។ ក្បាលយកចិត្តទុកដាក់នីមួយៗអាចរៀនទំនាក់ទំនងខុសៗគ្នារវាងពាក្យដែលជួយបង្កើនការងារប្រែសម្រួលភាសា NLP នៅក្រោយ។
## BERT
**BERT** (Bidirectional Encoder Representations from Transformers) គឺជា​បណ្តាញ transformer ជាច្រើនស្រទាប់ធំទូលាយ រួមមាន 12 ស្រទាប់សម្រាប់ *BERT-base* និង 24 ស្រទាប់សម្រាប់ *BERT-large*។ ម៉ូឌែលត្រូវបានបណ្ដុះបណ្ដាលដំបូងលើមណ្ឌលអត្ថបទធំមួយ (WikiPedia + សៀវភៅ) ដោយប្រើបច្ចេកទេសបណ្តុះបណ្តាលអស្រ័យថាស (unsupervised training) ដែលព្យាករណ៍ពាក្យដែលបានលាក់នៅក្នុងប្រយោគ។ ក្នុងអំឡុងពេលបណ្ដុះបណ្ដាល, ម៉ូឌែលស្រូបយកជំនាញភាសាច្រើនដែលបាច់ប្រើវាជាមួយទិន្នន័យផ្សេងទៀតដោយប្រើការតំរូវតំរូវល្អ (fine tuning)។ ដំណើរការនេះហៅថា **transfer learning**
![រូបភាពពី http://jalammar.github.io/illustrated-bert/](../../../../../translated_images/km/jalammarBERT-language-modeling-masked-lm.34f113ea5fec4362.webp)
> រូបភាព [ប្រភព](http://jalammar.github.io/illustrated-bert/)
## ✍️ លំហាត់៖ Transformers
បន្តការសិក្សារបស់អ្នកនៅក្នុងកំណត់ត្រាព័ត៌មានដូចខាងក្រោម៖
* [Transformers in PyTorch](TransformersPyTorch.ipynb)
* [Transformers in TensorFlow](TransformersTF.ipynb)
## សេចក្ដីសន្និដ្ឋាន
នៅក្នុងមេរៀននេះ អ្នកបានរៀនអំពី ម៉ូឌែល Transformers និង យន្តការយកចិត្តទុកដាក់ ដែលជាឧបករណ៍សំខាន់ទាំងអស់នៅក្នុងប្រអប់ឧបករណ៍ NLP។ មានការប្រែប្រួលជាច្រើននៃស្ថាបត្យកម្ម Transformer រួមមាន BERT, DistilBERT, BigBird, OpenGPT3 និងផ្សេងទៀតដែលអាចតំរូវតំរូវបាន។ [កញ្ចប់ HuggingFace](https://github.com/huggingface/) ផ្ដល់ឃ្លាំងសម្រាប់បណ្តុះបណ្តាលម៉ូឌែលស្ថាបត្យកម្មទាំងនេះដោយប្រើ PyTorch និង TensorFlow។
## 🚀 បញ្ហាជម្រើស
## [តេស្តបន្ទាប់វគ្គសិក្សា](https://ff-quizzes.netlify.app/en/ai/quiz/36)
## ការត្រួតពិនិត្យ និងសិក្សាឯករាជ្យ
* [អត្ថបទប្លុក](https://mchromiak.github.io/articles/2017/Sep/12/Transformer-Attention-is-all-you-need/), ពន្យល់អំពីអត្ថបទបុរាណ [Attention is all you need](https://arxiv.org/abs/1706.03762) លើ transformers។
* [ជួរអត្ថបទប្លុកមួយ](https://towardsdatascience.com/transformers-explained-visually-part-1-overview-of-functionality-95a6dd460452) ស្តីពី transformers ពន្យល់លំអិតពីស្ថាបត្យកម្ម។
## [ភារកិច្ច](assignment.md)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ចោលបំណុល**៖
ឯកសារនេះត្រូវបានបំលែងភាសារដោយប្រើសេវាកម្មបំលែងភាសា AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេលដែលយើងខំប្រឹងប្រែងចំពោះភាពត្រឹមត្រូវ សូមជ្រាបថាការបំលែងភាសាដោយស្វ័យប្រវត្តិអាចមានកំហុស ឬអក្សរសម្រួលមិនត្រឹមត្រូវបានបង្ហាញ។ ឯកសារដើមដែលមាននៅក្នុងភាសាពិតប្រាកដគួរត្រូវបានពិចារណាថាជាត្រួតត្រាទិន្នន័យគោល។ សម្រាប់ព័ត៌មានសំខាន់ៗ សូមផ្ដល់អនុសាសន៍ឲ្យប្រើការបកប្រែដោយមនុស្សជំនាញ។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកប្រែខុសបញ្ចេញពីការប្រើប្រាស់ការបំលែងភាសានេះទេ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,347 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# ម៉ាស៊ីនផ្តោតអារម្មណ៍ និងត្រាស់ហ្វូម៉ើរ\n",
"\n",
"គន្លុះខ្សោយធំបំផុតនៃបណ្តាញបង្វិលគឺ ពាក្យទាំងអស់ក្នុងលំដាប់មានឥទ្ធិពលដូចគ្នានៅលើលទ្ធផល។ នេះបណ្តាលឱ្យការសម្តែងមិនល្អលើម៉ូដែល LSTM encoder-decoder ស្តង់ដារសម្រាប់ភារកិច្ចលំដាប់ទៅលំដាប់ដូចជា ការទទួលស្គាល់ឈ្មោះអង្គភាព និងការប្រែសម្រួលម៉ាស៊ីន។ ជារពីតមែនពាក្យជាក់លាក់ក្នុងលំដាប់បញ្ចូលជាញឹកញាប់មានឥទ្ធិពលលើលទ្ធផលលំដាប់ខ្លះច្រើនជាងពាក្យផ្សេងទៀត។\n",
"\n",
"ចាប់យកម៉ូដែលលំដាប់ទៅលំដាប់ដូចជា ការប្រែសម្រួលម៉ាស៊ីន។ វាត្រូវបានអនុវត្តដោយបណ្តាញបង្វិលពីរមួយ ដែលបណ្តាញមួយ (**encoder**) នឹងបង្រួមលំដាប់បញ្ចូលជាស្ថានភាពសម្ងាត់ ហើយម្ដងទៀត **decoder** នឹងដោះស្រាយស្ថានភាពសម្ងាត់នេះទៅជាលទ្ធផលប្រែសម្រួល។ បញ្ហានៃវិធីនេះគឺ​ស្ថានភាពចុងក្រោយនៃបណ្តាញមានការលំបាកក្នុងការចងចាំចុះដំបូងនៃប្រយោគ ដូច្នេះបណ្តាលឱ្យគុណភាពម៉ូដែលនៅលើប្រយោគវែងមានភាពខ្សោយ។\n",
"\n",
"**ម៉ាស៊ីនផ្តោតអារម្មណ៍** ផ្ដល់នូវមធ្យោបាយបញ្ជាក់ទំងន់នៃឥទ្ធិពលបរិបទនៃវ៉ិចទ័របញ្ចូលនិទ្ទេសលើការព្យាករណ៍លទ្ធផលនិទ្ទេសនីមួយៗនៃ RNN។ វិធីដែលវាត្រូវបានអនុវត្តគឺដោយបង្កើតផ្លូវឆ្លងកាត់រវាងស្ថានភាពចន្លោះនៃ RNN បញ្ចូល និង RNN លទ្ធផល។ ដូច្នេះ នៅពេលបង្កើតនិទ្ទេសលទ្ធផល $y_t$ យើងនឹងគិតគូរជាមួយស្ថានភាពសម្ងាត់បញ្ចូលទាំងអស់ $h_i$ ជាមួយទំងន់ខុសៗគ្នា $\\alpha_{t,i}$។\n",
"\n",
"![រូបភាពបង្ហាញម៉ូដែល encoder/decoder ជាមួយបន្ទះផ្តោតអារម្មណ៍បន្ថែម](../../../../../translated_images/km/encoder-decoder-attention.7a726296894fb567.webp) \n",
"*ម៉ូដែល encoder-decoder ជាមួយម៉ាស៊ីនផ្តោតអារម្មណ៍បន្ថែមនៅក្នុង [Bahdanau et al., 2015](https://arxiv.org/pdf/1409.0473.pdf), យកចេញពី [អត្ថបទប្លុកនេះ](https://lilianweng.github.io/lil-log/2018/06/24/attention-attention.html)*\n",
"\n",
"ម៉ាទ្រីសផ្តោតអារម្មណ៍ $\\{\\alpha_{i,j}\\}$ នឹងបង្ហាញកម្រិតដែលពាក្យបញ្ចូលកំណត់មួយចូលរួមក្នុងការបង្កើតពាក្យដែលបានផ្ដល់ក្នុងលំដាប់លទ្ធផល។ ខាងក្រោមគឺជាគំរូម៉ាទ្រីសបែបនេះ៖\n",
"\n",
"![រូបភាពបង្ហាញការឆ្លើយតបគំរូដែលរកឃើញដោយ RNNsearch-50, យកចេញពី Bahdanau - arviz.org](../../../../../translated_images/km/bahdanau-fig3.09ba2d37f202a6af.webp) \n",
"\n",
"*រូបភាពយកពី [Bahdanau et al., 2015](https://arxiv.org/pdf/1409.0473.pdf) (រូប.3)*\n",
"\n",
"ម៉ាស៊ីនផ្តោតអារម្មណ៍ទទួលខុសត្រូវចំពោះសភាពបច្ចុប្បន្នឬជិតសភាពបច្ចុប្បន្ននៃស្ថានភាពសិល្បៈភាសាទិន្នន័យធម្មជាតិ។ ការបន្ថែមផ្តោតអារម្មណ៍ហើយបង្កើនចំនួនវ៉ារីយប៊ីលម៉ូដែលយ៉ាងខ្លាំង ដែលបណ្តាលឱ្យមានបញ្ហាក្នុងការបណ្ដុះបណ្ដាល RNNs។ ការពន្យល់ចម្បងនៃការពង្រីក RNN គឺដោយសារតែរូបមន្តរេកុរ៉ង់របស់ម៉ូដែលដែលធ្វើឱ្យការបំពេញបរិមាណ និងការបញ្ជូនបណ្ដាញពង្រីកក្នុងការបណ្ដុះបណ្ដាលក្លាយជារឿងលំបាក។ នៅក្នុង RNN ធាតុក្នុងលំដាប់មួយចាំបាច់ត្រូវបានដំណើរការក្នុងលំដាប់ត្រឹមត្រូវ ដែលមានន័យថាវាមិនងាយស្រួលបញ្ជូនបណ្ដាញឡើយ។\n",
"\n",
"ការទទួលយកម៉ាស៊ីនផ្តោតអារម្មណ៍រួមជាមួយនឹងកំណត់នេះបាននាំឱ្យមានការបង្កើតម៉ូដែលកម្មវិធីប្រែប្រួលស្ថានភាពបច្ចុប្បន្នដែលយើងស្គាល់ និងប្រើប្រាស់នៅថ្ងៃនេះចាប់ផ្ដើមពី BERT រហូតដល់ OpenGPT3។\n",
"\n",
"## ម៉ូដែលត្រាស់ហ្វូម៉ើរ\n",
"\n",
"ជំនួសការបញ្ជូនបរិបទនៃការព្យាករណ៍មុនៗទៅជាជំហានវាយតម្លៃបន្ទាប់, **ម៉ូដែលត្រាស់ហ្វូម៉ើរ** ប្រើ **កូដផ្លូវទីតាំង** និង ផ្តោតអារម្មណ៍ដើម្បីចាប់យកបរិបទនៃការបញ្ចូលដែលបានផ្ដល់នៅក្នុងបង្អួចអត្ថបទមួយ។ រូបភាពខាងក្រោមបង្ហាញពីរបៀបដែលកូដផ្លូវទីតាំងជាមួយផ្តោតអារម្មណ៍អាចចាប់យកបរិបទនៅក្នុងបង្អួចបាន។\n",
"\n",
"![រូបភាព GIF វិចិត្រសាស្រ្តបង្ហាញរបៀបធ្វើវាយតម្លៃក្នុងម៉ូដែលត្រាស់ហ្វូម៉ើរ។](../../../../../lessons/5-NLP/18-Transformers/images/transformer-animated-explanation.gif) \n",
"\n",
"ដោយសារ​ទីតាំងបញ្ចូលនីមួយៗត្រូវបានផ្គូផ្គងដោយឯករាជ្យទៅទីតាំងលទ្ធផលនីមួយៗ ត្រាស់ហ្វូម៉ើរអាចបណ្ដុះបណ្ដាលបានលឿនជាង RNN ដែលអនុញ្ញាតឱ្យមានម៉ូដែលភាសាធំ និងប៉ះពាល់ខាងនិមិត្តសញ្ញាខ្លួនបានច្រើនជាង។ ក្បាលផ្តោតអារម្មណ៍នីមួយៗអាចប្រើសម្រាប់រៀនទំនាក់ទំនងខុសគ្នារវាងពាក្យ ដែលបង្កើតការកែលម្អកិច្ចការផ្សេងៗក្រោមទម្រង់ភាសាធម្មជាតិ។\n",
"\n",
"**BERT** (Bidirectional Encoder Representations from Transformers) គឺជាបណ្តាញត្រាស់ហ្វូម៉ើរជាន់ច្រើនធំនិងមានស្រទាប់ 12 សម្រាប់ *BERT-base* និង 24 សម្រាប់ *BERT-large*។ ម៉ូដែលនេះចាប់ផ្តើមបណ្តុះបណ្តាលលើអង្គភាសាធំ (WikiPedia + ព្រះគម្ពីរ) ដោយប្រើការបណ្តុះបណ្តាលមិនត្រូវបានគ្រប់គ្រង (កំណត់ពាក្យបិទក្នុងប្រយោគ)។ ក្នុងអំឡុងពេលបណ្តុះបណ្តាល ម៉ូដែលផ្ទុកជាតំណាងយល់ដឹងភាសាដ៏ខ្លាំងរួច ហើយអាចប្រើប្រាស់ជាមួយឯកសារផ្សេងទៀតដោយប្រើការតំឡើងស្តើងក្រោម។ ការប្រតិបត្តិការនេះហៅថា **ការបញ្ជូនការសិក្សា**។\n",
"\n",
"![រូបភាពពី http://jalammar.github.io/illustrated-bert/](../../../../../translated_images/km/jalammarBERT-language-modeling-masked-lm.34f113ea5fec4362.webp)\n",
"\n",
"មានការបំលែងជាច្រើននៃសង់រាងត្រាស់ហ្វូម៉ើរជាមួយ BERT, DistilBERT, BigBird, OpenGPT3 និងផ្សេងទៀតដែលអាចតំឡើងស្តើងបាន។ [កញ្ចប់ HuggingFace](https://github.com/huggingface/) ផ្ដល់ឃ្លាំងកូដសម្រាប់បណ្តុះបណ្តាលវិស្វកម្មទាំងនេះជាច្រើនជាមួយ PyTorch។\n",
"\n",
"## ការប្រើប្រាស់ BERT សម្រាប់ចាត់ថ្នាក់អត្ថបទ\n",
"\n",
"មកមើលពីរបៀបយើងអាចប្រើម៉ូដែល BERT ដែលបានបណ្តុះបណ្តាលរួចសម្រាប់ដោះស្រាយភារកិច្ចបែបធម្មតារបស់យើង៖ ចាត់ថ្នាក់លំដាប់។ យើងនឹងចាត់ថ្នាក់ឯកសារ AG News ដើមរបស់យើង។\n",
"\n",
"ដំបូង ចូរទាញយកបណ្ណាល័យ HuggingFace និងឯកសារព័ត៌មានរបស់យើង៖\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Loading dataset...\n",
"Building vocab...\n"
]
}
],
"source": [
"import torch\n",
"import torchtext\n",
"from torchnlp import *\n",
"import transformers\n",
"train_dataset, test_dataset, classes, vocab = load_dataset()\n",
"vocab_len = len(vocab)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ព្រោះយើងនឹងប្រើម៉ាស៊ីនម៉ូដែល BERT ដែលបានប្រៀបធៀបមុនរួចហើយ យើងនឹងត្រូវការប្រើ tokenizer ជាក់លាក់មួយ។ ជាដំបូង យើងនឹងបង្ហាញ tokenizer ដែលទាក់ទងនឹងម៉ូដែល BERT ដែលបានប្រៀបធៀបមុន។\n",
"\n",
"បណ្ណាល័យ HuggingFace មានឃ្លាំងសំរាប់ម៉ូដែលដែលបានប្រៀបធៀបមុន ដែលអ្នកអាចប្រើបានត្រឹមតែបញ្ជាក់ឈ្មោះរបស់ពួកវាជាអាគុយម៉ង់ទៅកាន់មុខងារ `from_pretrained`។ ឯកសារប៊ីណារីទាំងអស់ដែលទាមទារសម្រាប់ម៉ូដែលនឹងត្រូវទាញយកដោយស្វ័យប្រវត្តិ។\n",
"\n",
"តែម្តងខ្លះ អ្នកអាចត្រូវការបង្ហាញម៉ូដែលផ្ទាល់ខ្លួនរបស់អ្នក ដែលក្នុងករណីនេះ អ្នកអាចបញ្ជាក់ថតដែលមានឯកសារទាំងអស់ពាក់ព័ន្ធ រួមទាំងប៉ារ៉ាម៉ែត្រ tokenizer, ឯកសារ `config.json` ជាមួយប៉ារ៉ាម៉ែត្រ ម៉ូដែល, ទម្ងន់ប៊ីណារី, ល។\n"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [],
"source": [
"# To load the model from Internet repository using model name. \n",
"# Use this if you are running from your own copy of the notebooks\n",
"bert_model = 'bert-base-uncased' \n",
"\n",
"# To load the model from the directory on disk. Use this for Microsoft Learn module, because we have\n",
"# prepared all required files for you.\n",
"bert_model = './bert'\n",
"\n",
"tokenizer = transformers.BertTokenizer.from_pretrained(bert_model)\n",
"\n",
"MAX_SEQ_LEN = 128\n",
"PAD_INDEX = tokenizer.convert_tokens_to_ids(tokenizer.pad_token)\n",
"UNK_INDEX = tokenizer.convert_tokens_to_ids(tokenizer.unk_token)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"វត្ថុ `tokenizer` មានមុខងារ `encode` ដែលអាចប្រើប្រាស់បានដោយផ្ទាល់សម្រាប់កូដអក្សរ៖\n"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[101, 1052, 22123, 2953, 2818, 2003, 1037, 2307, 7705, 2005, 17953, 2361, 102]"
]
},
"execution_count": 15,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tokenizer.encode('PyTorch is a great framework for NLP')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"បន្ទាប់មក យើងចូលចិត្តបង្កើត iterators ដែលយើងនឹងប្រើក្នុងពេលហ្វឹកហ្វឺន ដើម្បីចូលដំណើរការទិន្នន័យ។ ពីព្រោះ BERT ប្រើមុខងារវិភាគកូដរបស់ខ្លួន យើងត្រូវការកំណត់មុខងារផ្ទុកពេញដែលដូចទៅនឹង `padify` ដែលយើងបានកំណត់មុននេះៈ\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"def pad_bert(b):\n",
" # b is the list of tuples of length batch_size\n",
" # - first element of a tuple = label, \n",
" # - second = feature (text sequence)\n",
" # build vectorized sequence\n",
" v = [tokenizer.encode(x[1]) for x in b]\n",
" # compute max length of a sequence in this minibatch\n",
" l = max(map(len,v))\n",
" return ( # tuple of two tensors - labels and features\n",
" torch.LongTensor([t[0] for t in b]),\n",
" torch.stack([torch.nn.functional.pad(torch.tensor(t),(0,l-len(t)),mode='constant',value=0) for t in v])\n",
" )\n",
"\n",
"train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=8, collate_fn=pad_bert, shuffle=True)\n",
"test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=8, collate_fn=pad_bert)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ក្នុងករណីរបស់យើង យើងនឹងប្រើម៉ូដែល BERT ដែលបានបណ្ដុះបណ្ដាលរួចហើយដែលមានឈ្មោះថា `bert-base-uncased` ។ យើងត្រូវផ្ទុកម៉ូដែលដោយប្រើកញ្ចប់ `BertForSequenceClassfication` ។ វាប្រាកដថាម៉ូដែលរបស់យើងមានស្ថាបត្យកម្មដែលត្រូវការសម្រាប់ការបែងចែកចំណាត់ថ្នាក់រួចហើយ រួមមានអ្នកចាត់ថ្នាក់ចុងក្រោយផងដែរ។ អ្នកនឹងឃើញសារ​ព្រមាន​ថា​ទម្ងន់​របស់​អ្នកចាត់ថ្នាក់​ចុងក្រោយ​មិន​ត្រូវ​បាន​ចាប់ផ្តើម និងម៉ូដែលត្រូវការបណ្ដុះបណ្ដាលជាមុន - នេះគឺល្អឥតខ្ចោះ ព្រោះវាជាការដែលយើងកំពុងតែធ្វើ!\n"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"Some weights of the model checkpoint at ./bert were not used when initializing BertForSequenceClassification: ['cls.predictions.bias', 'cls.predictions.transform.dense.weight', 'cls.predictions.transform.dense.bias', 'cls.predictions.decoder.weight', 'cls.seq_relationship.weight', 'cls.seq_relationship.bias', 'cls.predictions.transform.LayerNorm.weight', 'cls.predictions.transform.LayerNorm.bias']\n",
"- This IS expected if you are initializing BertForSequenceClassification from the checkpoint of a model trained on another task or with another architecture (e.g. initializing a BertForSequenceClassification model from a BertForPreTraining model).\n",
"- This IS NOT expected if you are initializing BertForSequenceClassification from the checkpoint of a model that you expect to be exactly identical (initializing a BertForSequenceClassification model from a BertForSequenceClassification model).\n",
"Some weights of BertForSequenceClassification were not initialized from the model checkpoint at ./bert and are newly initialized: ['classifier.weight', 'classifier.bias']\n",
"You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.\n"
]
}
],
"source": [
"model = transformers.BertForSequenceClassification.from_pretrained(bert_model,num_labels=4).to(device)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ឥឡូវនេះយើងរៀបចំរួចហើយសម្រាប់ការបណ្តុះបណ្តាល! ព្រោះ BERT ត្រូវបានបណ្តុះបណ្តាលរួចមកហើយ យើងចង់ចាប់ផ្តើមជាមួយអត្រាការសិក្សាតូចៗ ដើម្បីមិនបំផ្លាញទម្ងន់ដើមទេ។\n",
"\n",
"ការងារលំបាកទាំងអស់ត្រូវបានធ្វើ bởiម៉ូដែល `BertForSequenceClassification`។ នៅពេលយើងហៅម៉ូដែលលើទិន្នន័យបណ្តុះបណ្តាល វាបង្វិលតាំងពីចំណាយនិងលទ្ធផលបណ្តាញសម្រាប់មេប្តាច់ជាដុំបញ្ចូល។ យើងប្រើចំណាយសម្រាប់បង្កើតប៉ារ៉ាម៉ែត្រ (`loss.backward()` ធ្វើការដំណើរការផ្ទៃក្រោយ), និង `out` សម្រាប់គណនាលទ្ធផលនៃការបណ្តុះបណ្តាល ដោយប្រៀបធៀបទម្រៀបដែលបានទទួល `labs` (គណនាដោយប្រើ `argmax`) ជាមួយ `labels` ដែលរំពឹងទុក។\n",
"\n",
"ដើម្បីត្រួតពិនិត្យដំណើរការ យើងសរុបចំណាយនិងភាពត្រឹមត្រូវលើជំនួញច្រើន ហើយបោះពុម្ពពួកវាក្នុងគ្រប់វដ្តបណ្តុះបណ្តាល `report_freq`។\n",
"\n",
"ការបណ្តុះបណ្តាលនេះប្រហែលជានឹងយូរជាងមុន ដូច្នេះយើងកំណត់ចំនួនវដ្តបណ្តុះបណ្តាល។\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Loss = 1.1254194641113282, Accuracy = 0.585\n",
"Loss = 0.6194715118408203, Accuracy = 0.83\n",
"Loss = 0.46665248870849607, Accuracy = 0.8475\n",
"Loss = 0.4309701919555664, Accuracy = 0.8575\n",
"Loss = 0.35427074432373046, Accuracy = 0.8825\n",
"Loss = 0.3306886291503906, Accuracy = 0.8975\n",
"Loss = 0.30340143203735354, Accuracy = 0.8975\n",
"Loss = 0.26139299392700194, Accuracy = 0.915\n",
"Loss = 0.26708646774291994, Accuracy = 0.9225\n",
"Loss = 0.3667240524291992, Accuracy = 0.8675\n"
]
}
],
"source": [
"optimizer = torch.optim.Adam(model.parameters(), lr=2e-5)\n",
"\n",
"report_freq = 50\n",
"iterations = 500 # make this larger to train for longer time!\n",
"\n",
"model.train()\n",
"\n",
"i,c = 0,0\n",
"acc_loss = 0\n",
"acc_acc = 0\n",
"\n",
"for labels,texts in train_loader:\n",
" labels = labels.to(device)-1 # get labels in the range 0-3 \n",
" texts = texts.to(device)\n",
" loss, out = model(texts, labels=labels)[:2]\n",
" labs = out.argmax(dim=1)\n",
" acc = torch.mean((labs==labels).type(torch.float32))\n",
" optimizer.zero_grad()\n",
" loss.backward()\n",
" optimizer.step()\n",
" acc_loss += loss\n",
" acc_acc += acc\n",
" i+=1\n",
" c+=1\n",
" if i%report_freq==0:\n",
" print(f\"Loss = {acc_loss.item()/c}, Accuracy = {acc_acc.item()/c}\")\n",
" c = 0\n",
" acc_loss = 0\n",
" acc_acc = 0\n",
" iterations-=1\n",
" if not iterations:\n",
" break"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"អ្នកអាចមើលឃើញ (ជាពិសេស ប្រសិនបើអ្នកបន្ថែមចំនួនវដ្ត និងរង់ចាំយូរពេក) ថា ការបែងចែកប្រភេទ BERT ផ្តល់ជូននូវការប្រកាន់ត្រឹមត្រូវល្អណាស់! នេះដោយសារតែ BERT បានយល់រចនាសម្ព័ន្ធភាសារួចហើយយ៉ាងល្អ ហើយយើងតែត្រូវតែបញ្ចូលការបង្ហាត់វេរកម្មចុងក្រោយប៉ុណ្ណោះ។ ទោះយ៉ាងណា ពីព្រោះ BERT ជាម៉ូដែលធំ មូលដ្ឋានការបង្ហាត់ទាំងមូលចំណាយពេលយូរណាស់ និងតម្រូវឱ្យមានថាមពលគណនាពិតប្រាកដ! (GPU ហើយប្រសិនបើអាចមានច្រើនជាងមួយកាន់តែប្រសើរ)។\n",
"\n",
"> **ចំណាំ៖** នៅក្នុងឧទាហរណ៍របស់យើង យើងបានប្រើប្រាស់ម៉ូដែល BERT មួយនៃម៉ូដែលដែលតូចបំផុត ដែលបានបង្ហាត់ជាមុន។ មានម៉ូដែលធំនានាដែលមានហានិភ័យផ្តល់លទ្ធផលកាន់តែប្រសើរជាងនេះ។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ការវាយតម្លៃចំណុះគ្រាប់ម៉ូដែល\n",
"\n",
"ឥឡូវនេះយើងអាចវាយតម្លៃចំណុះគ្រាប់ម៉ូដែលរបស់យើងលើឯកសារតេស្តបាន។ ប្រតិបត្តិការeval loop មានសភាពដូចប្រតិបត្តិការ training loop ប៉ុន្តែយើងមិនគួរបំភ្លេចប្ដូរម៉ូដែលទៅជារបៀបវាយតម្លៃដោយហៅ `model.eval()`។\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Final accuracy: 0.9047029702970297\n"
]
}
],
"source": [
"model.eval()\n",
"iterations = 100\n",
"acc = 0\n",
"i = 0\n",
"for labels,texts in test_loader:\n",
" labels = labels.to(device)-1 \n",
" texts = texts.to(device)\n",
" _, out = model(texts, labels=labels)[:2]\n",
" labs = out.argmax(dim=1)\n",
" acc += torch.mean((labs==labels).type(torch.float32))\n",
" i+=1\n",
" if i>iterations: break\n",
" \n",
"print(f\"Final accuracy: {acc.item()/i}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Takeaway\n",
"\n",
"ក្នុងផ្នែកនេះ យើងបានឃើញថាវាងាយស្រួលយ៉ាងដូចម្ដេចក្នុងការយកម៉ូដែលភាសាប្រកបដោយការបណ្តុះបណ្តាលរួចពីបណ្ណាល័យ **transformers** ហើយអាចប្ដូរជាប្រតិបត្ដិការ​ភាសាដើម្បីចាត់ថ្នាក់អត្ថបទរបស់យើង។ ដូចគ្នានេះ ម៉ូដែល BERT អាចប្រើសម្រាប់ការដកស្រង់អង្គភាព (entity extraction), ការឆ្លើយសំណួរ, និងភារកិច្ច NLP ផ្សេងទៀត។\n",
"\n",
"ម៉ូដែល Transformer តំណាងឱ្យភាពទំនើបបំផុត​បច្ចុប្បន្នក្នុងវិស័យ NLP ហើយនៅសំខាន់ក្នុងភាគច្រើនវាគួរតែជាដំណោះស្រាយដំបូងដែលអ្នកត្រូវចាប់ផ្តើមសាកល្បងពេលអនុវត្តដំណោះស្រាយ NLP បញ្ជាក់ផ្ទាល់ខ្លួន។ ទោះយ៉ាងណា ការយល់ដឹងអំពីគោលការណ៍មូលដ្ឋាននៃបណ្តាញប្រព័ន្ធប្រតិបត្ដិដោយជាប់ទន្តឹង (recurrent neural networks) ដែលបានពិភាក្សាក្នុងផ្នែកនេះគឺសំខាន់ខ្លាំង ប្រសិនបើអ្នកចង់សាងសង់ម៉ូដែលណែរ៉ូនថ្មីៗ។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**ការ​ព្រមាន**៖ \nឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេល​យើង​រំពឹង​ថា​បាន​រៀបចំ​ឲ្យ​មាន​ភាព​ត្រឹមត្រូវ សូម​ចំណាំ​ថា​ការ​បកប្រែ​ស្វ័យ​ប្រវត្តិ​អាច​មាន​កំហុស ឬ​ការមិន​ត្រឹមត្រូវ​ខ្លះៗ។ ឯកសារ​ដើម​នៅ​ក្នុង​ភាសារដើមគួរត្រូវ​បាន​គិត​ថាជា​ប្រភព​ដែលមាន​សក្ដាភាព។ សម្រាប់​ព័ត៌មាន​សំខាន់ៗ ការបកប្រែ​ដោយមនុស្សជំនាញ​ត្រូវ​បាន​ផ្ដល់អនុសាសន៍។ យើង​មិនទទួល​ខុស​ត្រូវ​សម្រាប់​ការ​យល់ខុស ឬ​ការបកប្រែ​ខុស​ពី​ការ​ប្រើប្រាស់​ការ​បកប្រែ​នេះឡើយ។\n<!-- CO-OP TRANSLATOR DISCLAIMER END -->\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "py37_pytorch",
"language": "python",
"name": "conda-env-py37_pytorch-py"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.7"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,823 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# មេកានិចការយកចិត្តទុកដាក់ និង ម៉ាស៊ីនបម្លែង\n",
"\n",
"ខ្សែបណ្តោទមួយចំណុចសំខាន់នៃបណ្តាញប្រើប្រាស់ស្តើងគឺថាពាក្យទាំងអស់ក្នុងតួអក្សរមានឥទ្ធិពលដូចគ្នានៅលើលទ្ធផល។ វាបង្កឲ្យមានការទទួលបានកម្មវិធីមិនល្អជាមួយម៉ូដែលកម្មវិធីស្តើង LSTM គំរូលើបំណងពីតួអក្សរទៅតួអក្សរ ដូចជា ការទទួលស្គាល់អត្តសញ្ញាណឈ្មោះ និង ការបកប្រែម៉ាស៊ីន។ នៅក្នុងការពិត ពាក្យជាក់លាក់ក្នុងជួរមូលដ្ឋានបញ្ចូលជាញឹកញាប់មានឥទ្ធិពលលើលទ្ធផលរំដោះជាមុនជាងពាក្យផ្សេងទៀត។\n",
"\n",
"សូមគិតពីម៉ូដែលជួរមូលដ្ឋានពីតួអក្សរទៅតួអក្សរ ដូចជាការបកប្រែម៉ាស៊ីន។ វាត្រូវបានអនុវត្តដោយបណ្តាញប្រើប្រាស់ស្តើងពីរមួួយដែលបណ្តាញមួយ (**encoder**) នឹងបង្រួមជួរមូលដ្ឋានបញ្ចូលទៅជាអថេរភាពលាក់ ហើយមួយទៀត **decoder** នឹងបំបែកចេញពីអថេរភាពលាក់នេះទៅជាលទ្ធផលបកប្រែ។ បញ្ហានៃវិធីសាស្រ្តនេះគឺអថេរភាពចុងក្រោយនៃបណ្តាញនឹងមានការលំបាកក្នុងការចងចាំការចាប់ផ្តើមនៃប្រយោគ ដូច្នេះបង្កឲ្យគុណភាពអ្នកម៉ូដែលនៅលើប្រយោគវែងក្រាប។\n",
"\n",
"**មេកានិចការយកចិត្តទុកដាក់** ផ្ដល់នូវវិធីសាស្រ្តក្នុងការផ្ដល់ទម្ងន់ទៅលើឥទ្ធិពលបរិបទនៃវ៉ិចទ័របញ្ចូលនីមួយៗលើការព្យាករណ៍លទ្ធផលនីមួយៗនៃ RNN។ វិធីសាស្រ្តកំណត់នេះគឺដោយបង្កើតផ្លូវរហ័សរវាងស្ថានភាពចន្លោះនៃ RNN បញ្ចូល និង RNN លទ្ធផល។ ដោយរបៀបនេះ នៅពេលបង្កើតសញ្ញាលទ្ធផល $y_t$ យើងនឹងគិតថាជាមួយនឹងស្ថានភាពលាក់បញ្ចូលទាំង អាច $h_i$ ដែលមានទម្ងន់ខុសគ្នា $\\alpha_{t,i}$ ។\n",
"\n",
"![រូបភាពបង្ហាញម៉ូដែល encoder/decoder ជាមួយស្រទាប់ការយកចិត្តទុកដាក់បន្ថែម](../../../../../translated_images/km/encoder-decoder-attention.7a726296894fb567.webp)\n",
"*ម៉ូដែល encoder-decoder ជាមួយមេកានិចការយកចិត្តទុកដាក់បន្ថែម ក្នុង [Bahdanau et al., 2015](https://arxiv.org/pdf/1409.0473.pdf), បានយោងពី [អត្ថបទប្លុកនេះ](https://lilianweng.github.io/lil-log/2018/06/24/attention-attention.html)*\n",
"\n",
"ម៉ាទិកខ្យល់ការយកចិត្តទុកដាក់ $\\{\\alpha_{i,j}\\}$ នឹងតំណាងឱ្យកម្រិតដែលពាក្យបញ្ចូលជាក់លាក់មានតួនាទីក្នុងការបង្កើតពាក្យចេញមួយនៅក្នុងជួរលទ្ធផល។ ខាងក្រោមនេះគឺជាឧទាហរណ៍នៃម៉ាទិកខ្យល់បែបនេះ៖\n",
"\n",
"![រូបភាពបង្ហាញការចំរូងគំរូដែលបានរកឃើញដោយ RNNsearch-50 យកមកពី Bahdanau - arviz.org](../../../../../translated_images/km/bahdanau-fig3.09ba2d37f202a6af.webp)\n",
"\n",
"*រូបថតយកពី [Bahdanau et al., 2015](https://arxiv.org/pdf/1409.0473.pdf) (រូប3)*\n",
"\n",
"មេកានិចការយកចិត្តទុកដាក់មានការទទួលខុសត្រូវចម្បងចំពោះស្ថានភាពបច្ចុប្បន្ន ឬ ហៀបឆាប់នៃការបំពេញភាសាធម្មជាតិ។ ការបន្ថែមការយកចិត្តទុកដាក់ប៉ុន្មានតំឡើងចំនួនប្រ៉ាម៉ែត្រ ម៉ូដែលទៅលើបញ្ហាប្រឈមក្នុងការតម្រាស់ជាមួយ RNNs។ ការរឹតបន្តឹងសំខាន់នៃការតម្រាស់ RNN គឺថារូបភាពបណ្តាញលំដាប់ហាក់ដូចជាការលំបាកក្នុងការធ្វើបាត់ជាស្វ័យប្រវត្តិ និង ធ្វើបាត់ពេញលេញ។ ក្នុង RNN, ធាតុនីមួយនៃជួរត្រូវបានដំណើរការប្រមូលក្នុងលំដាប់ក្រោមលំដាប់ ដែលមានន័យថាវាមិនអាចធ្វើបានពេញលេញលើបណ្តាត។\n",
"\n",
"ការទទួលយកមេកានិចការយកចិត្តទុកដាក់រួមជាមួយនឹងការរឹតបន្តឹងនេះបង្កើតឡើងវិធីម៉ូដែលម៉ាស៊ីនបម្លែងដែលពេញនិយមឥឡូវនេះដែលយើងស្គាល់និងប្រើប្រាស់ពី BERT ដល់ OpenGPT3។\n",
"\n",
"## ម៉ូដែលម៉ាស៊ីនបម្លែង\n",
"\n",
"ជំនួសការដាក់បញ្ជូនបរិបទនៃការព្យាករណ៍មុនទៅជាដំណាក់កាលវាយតម្លៃបន្ទាប់, **ម៉ូដែលម៉ាស៊ីនបម្លែង** ប្រើប្រាស់ **កូដទីតាំង** និង **ការយកចិត្តទុកដាក់** ដើម្បីទទួលយកបរិបទនៃបញ្ចូលមួយនៅក្នុងផ្ទៃវិនទស្សន៍អត្ថបទដែលបានផ្ដល់។ រូបភាពខាងក្រោមបង្ហាញពីរបៀបដែលកូដទីតាំងជាមួយការយកចិត្តទុកដាក់អាចទទួលយកបរិបទនៅក្នុងផ្ទៃវិនទស្សន៍មួយបាន។\n",
"\n",
"![រូបភាព GIF រូបចលនា បង្ហាញពីរបៀបចាត់ធ្វើវាយតម្លៃនៅក្នុងម៉ូដែលម៉ាស៊ីនបម្លែង។](../../../../../lessons/5-NLP/18-Transformers/images/transformer-animated-explanation.gif) \n",
"\n",
"ដោយសារតែទីតាំងបញ្ចូលនីមួយៗត្រូវបានផ្គូផ្គងដោយខ្លួនឯងទៅទីតាំងលទ្ធផលនីមួយៗ ម៉ូដែលម៉ាស៊ីនបម្លែងអាចធ្វើបាត់បានល្អជាង RNNs ដែលអនុញ្ញាតឲ្យមានម៉ូដែលភាសាធាតុធំជាងនិងបង្ហាញវឌ្ឍនភាពល្អជាង។ ក្បាលការយកចិត្តទុកដាក់នីមួយៗអាចប្រើក្នុងការរៀនទំនាក់ទំនងផ្សេងៗរវាងពាក្យដែលបង្កើនការងារជាបន្ទាប់នៃការបំលាស់ភាសាធម្មជាតិ។\n",
"\n",
"## ការបង្កើតម៉ូដែលម៉ាស៊ីនបម្លែងសាមញ្ញ\n",
"\n",
"Keras មិនមានស្រទាប់ម៉ាស៊ីនបម្លែងបញ្ចូលទេ ប៉ុន្តែយើងអាចបង្កើតរបស់យើងផ្ទាល់បាន។ ដូចមុន យើងនឹងផ្ដោតលើការចាត់ថ្នាក់អត្ថបទនៃទិន្នន័យព័ត៌មាន AG News ប៉ុន្តែគួររំលឹកថា ម៉ូដែលម៉ាស៊ីនបម្លែងបង្ហាញលទ្ធផលល្អបំផុតនៅលើបញ្ហា NLP ដែលពិបាកជាង។\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import tensorflow as tf\n",
"from tensorflow import keras\n",
"import tensorflow_datasets as tfds\n",
"import numpy as np\n",
"\n",
"ds_train, ds_test = tfds.load('ag_news_subset').values()\n",
"\n",
"def extract_text(x):\n",
" return x['title']+' '+x['description']\n",
"\n",
"def tupelize(x):\n",
" return (extract_text(x),x['label'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ស្រទាប់ថ្មីៗនៅក្នុង Keras គួរត្រូវបានបង្កើតជាកូនថ្នាក់ subclass របស់ថ្នាក់ `Layer` ហើយអនុវត្តវិធីសាស្រ្ត `call`។ យើងចាប់ផ្តើមជាមួយស្រទាប់ **Positional Embedding** ។ យើងនឹងប្រើ [កូដមួយចំនួនពីឯកសារផ្លូវការរបស់ Keras](https://keras.io/examples/nlp/text_classification_with_transformer/)។ យើងនឹងនិយមថាយើងដាក់សម្អាតចំនួនទាំងអស់នៃលំដាប់បញ្ចូលអោយមានប្រវែង `maxlen`។\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"class TokenAndPositionEmbedding(keras.layers.Layer):\n",
" def __init__(self, maxlen, vocab_size, embed_dim):\n",
" super(TokenAndPositionEmbedding, self).__init__()\n",
" self.token_emb = keras.layers.Embedding(input_dim=vocab_size, output_dim=embed_dim)\n",
" self.pos_emb = keras.layers.Embedding(input_dim=maxlen, output_dim=embed_dim)\n",
" self.maxlen = maxlen\n",
"\n",
" def call(self, x):\n",
" maxlen = self.maxlen\n",
" positions = tf.range(start=0, limit=maxlen, delta=1)\n",
" positions = self.pos_emb(positions)\n",
" x = self.token_emb(x)\n",
" return x+positions"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ស្រទាប់នេះមានស្រទាប់ `Embedding` ពីរ៖ សម្រាប់ជំរៅសញ្ញាណ (ទៅតាមវិធីដែលយើងបានពិភាក្សាកាន់មុន) និងមុខតំណែងសញ្ញាណ។ មុខតំណែងសញ្ញាណត្រូវបានបង្កើតជាខ្សែដដែលនៃលេខធម្មជាតិចាប់ពី 0 រហូតដល់ `maxlen` ដោយប្រើ `tf.range` ហើយបន្ទាប់មកផ្ញើតាមស្រទាប់ embedding។ វិចទ័រជួរ embedding ពីរដែលទទួលបានបន្ថែមគ្នា ដើរការផលិតតំណាងមុខតំណែងដែលជាស្អាតបញ្ចូលដែលមានទ្រង់ទ្រាយជា `maxlen`$\\times$`embed_dim`។\n",
"\n",
"<img src=\"../../../../../translated_images/km/pos-embedding.e41ce9b6cf6078af.webp\" width=\"40%\"/>\n",
"\n",
"ឥឡូវនេះ, សូមអនុវត្តប្លុក transformer។ វានឹងទទួលផលបញ្ចេញពីស្រទាប់ embedding ដែលបានកំណត់ពីមុន៖\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"class TransformerBlock(keras.layers.Layer):\n",
" def __init__(self, embed_dim, num_heads, ff_dim, rate=0.1):\n",
" super(TransformerBlock, self).__init__()\n",
" self.att = keras.layers.MultiHeadAttention(num_heads=num_heads, key_dim=embed_dim, name='attn')\n",
" self.ffn = keras.Sequential(\n",
" [keras.layers.Dense(ff_dim, activation=\"relu\"), keras.layers.Dense(embed_dim),]\n",
" )\n",
" self.layernorm1 = keras.layers.LayerNormalization(epsilon=1e-6)\n",
" self.layernorm2 = keras.layers.LayerNormalization(epsilon=1e-6)\n",
" self.dropout1 = keras.layers.Dropout(rate)\n",
" self.dropout2 = keras.layers.Dropout(rate)\n",
"\n",
" def call(self, inputs, training):\n",
" attn_output = self.att(inputs, inputs)\n",
" attn_output = self.dropout1(attn_output, training=training)\n",
" out1 = self.layernorm1(inputs + attn_output)\n",
" ffn_output = self.ffn(out1)\n",
" ffn_output = self.dropout2(ffn_output, training=training)\n",
" return self.layernorm2(out1 + ffn_output)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Transformer ប្រើ `MultiHeadAttention` លើអិនប៊ុតដែលត្រូវបានកូដតាមទីតាំង ដើម្បីបង្កើតវ៉ិចទ័រយល់ដឹងមានវិមាត្រ `maxlen`$\\times$`embed_dim`, ដែលបន្ទាប់មកត្រូវបានច្របាច់ជាមួយអិនប៊ុត ហើយធ្វើការប្រកួតប្រជែងដោយប្រើ `LayerNormalizaton`។\n",
"\n",
"> **សំគាល់**: `LayerNormalization` ស្រដៀងទៅនឹង `BatchNormalization` ដែលបានពិភាក្សា​នៅក្នុងផ្នែក *Computer Vision* នៃផ្លូវការសិក្សានេះ ប៉ុន្តែវាធ្វើការប្រកួតប្រជែងលទ្ធផលនៃស្រទាប់មុន សម្រាប់គំរូសិក្សាទាំងមូលដោយឯករាជ្យ ដើម្បីនាំឲ្យវាផ្លាស់ទៅក្នុងជួរទីតាំង [-1..1]។\n",
"\n",
"លទ្ធផលនៃស្រទាប់នេះបន្ទាប់មកត្រូវបានផ្ញើតាមរយៈបណ្ដាញ `Dense` (សម្រាប់ករណីរបស់យើង - ប៉ឺរប្រើតូនពីរស្រទាប់), ហើយលទ្ធផលត្រូវបានបន្ថែមទៅលើលទ្ធផលចុងក្រោយ (ដែលត្រូវបានធ្វើប្រកួតប្រជែងម្តងទៀត)។\n",
"\n",
"<img src=\"../../../../../translated_images/km/transformer-layer.905e14747ca4e7d5.webp\" width=\"30%\" />\n",
"\n",
"ឥឡូវនេះ, យើងត្រៀមខ្លួនសម្រាប់កំណត់ម៉ូដែល transformer ពេញលេញ៖\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"sequential_1\"\n",
"_________________________________________________________________\n",
"Layer (type) Output Shape Param # \n",
"=================================================================\n",
"text_vectorization (TextVect (None, 256) 0 \n",
"_________________________________________________________________\n",
"token_and_position_embedding (None, 256, 32) 648192 \n",
"_________________________________________________________________\n",
"transformer_block (Transform (None, 256, 32) 10656 \n",
"_________________________________________________________________\n",
"global_average_pooling1d (Gl (None, 32) 0 \n",
"_________________________________________________________________\n",
"dropout_2 (Dropout) (None, 32) 0 \n",
"_________________________________________________________________\n",
"dense_2 (Dense) (None, 20) 660 \n",
"_________________________________________________________________\n",
"dropout_3 (Dropout) (None, 20) 0 \n",
"_________________________________________________________________\n",
"dense_3 (Dense) (None, 4) 84 \n",
"=================================================================\n",
"Total params: 659,592\n",
"Trainable params: 659,592\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n"
]
}
],
"source": [
"embed_dim = 32 # Embedding size for each token\n",
"num_heads = 2 # Number of attention heads\n",
"ff_dim = 32 # Hidden layer size in feed forward network inside transformer\n",
"maxlen = 256\n",
"vocab_size = 20000\n",
"\n",
"model = keras.models.Sequential([\n",
" keras.layers.experimental.preprocessing.TextVectorization(max_tokens=vocab_size,output_sequence_length=maxlen, input_shape=(1,)),\n",
" TokenAndPositionEmbedding(maxlen, vocab_size, embed_dim),\n",
" TransformerBlock(embed_dim, num_heads, ff_dim),\n",
" keras.layers.GlobalAveragePooling1D(),\n",
" keras.layers.Dropout(0.1),\n",
" keras.layers.Dense(20, activation=\"relu\"),\n",
" keras.layers.Dropout(0.1),\n",
" keras.layers.Dense(4, activation=\"softmax\")\n",
"])\n",
"\n",
"model.summary()"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Training tokenizer\n",
"938/938 [==============================] - 45s 39ms/step - loss: 0.4978 - acc: 0.8068 - val_loss: 0.2808 - val_acc: 0.9124\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7f9c2427a0d0>"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"print('Training tokenizer')\n",
"model.layers[0].adapt(ds_train.map(extract_text))\n",
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')\n",
"model.fit(ds_train.map(tupelize).batch(128),validation_data=ds_test.map(tupelize).batch(128))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## គំរូប្រព័ន្ធបំលែង BERT\n",
"\n",
"**BERT** (Bidirectional Encoder Representations from Transformers) គឺជាបណ្តុំបំលែងស្រទាប់ច្រើនអព្ភូតមាន ១២ ស្រទាប់សម្រាប់ *BERT-base* និង ២៤ ស្រទាប់សម្រាប់ *BERT-large*។ គំរូនេះត្រូវបានបណ្តុះជាមុនលើសំណុំអត្ថបទធំនៅ (WikiPedia + សៀវភៅ) ដោយប្រើការបណ្តុះដោយគ្មានមគ្គុទេសក៍ (ប៉ាន់ណាចាត់ពាក្យដែលបានលាក់នៅក្នុងប្រយោគ)។ ក្នុងអំឡុងពេលបណ្តុះជាមុន គំរូនេះចំណូលទៅក្នុងការយល់ដឹងភាសាដោយមានកម្រិតខ្ពស់ ដែលបន្ទាប់មកអាចប្រើប្រាស់ជាមួយសំណុំទិន្នន័យផ្សេងទៀតដោយប្រើការតំរូវតែម្ដង។ ដំណើរការនេះហៅថា **transfer learning**។ \n",
"\n",
"![រូបភាពពី http://jalammar.github.io/illustrated-bert/](../../../../../translated_images/km/jalammarBERT-language-modeling-masked-lm.34f113ea5fec4362.webp)\n",
"\n",
"មានរចនាសម្ព័ន្ធបំលែងជាច្រើន រួមមាន BERT, DistilBERT, BigBird, OpenGPT3 និងផ្សេងទៀតដែលអាចត្រូវបានតំរូវតែម្ដងបាន។ \n",
"\n",
"យើងទៅប្រើគំរូ BERT ដែលបានបណ្តុះជាមុនសម្រាប់ដោះស្រាយបញ្ហាការបែងចែកលំដាប់ធម្មតារបស់យើង។ យើងនឹងខ្ចីគំនិត និងកូដខ្លះពី [ឯកសារផ្លូវការជាផ្លូវការ](https://www.tensorflow.org/text/tutorials/classify_text_with_bert)។\n",
"\n",
"ដើម្បីបញ្ចូលគំរូដែលបានបណ្តុះជាមុន យើងនឹងប្រើ **Tensorflow hub**។ ជំហានដំបូង សូមបញ្ចូលវ៉ិចទ័រពិសេសសម្រាប់ BERT៖\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"ename": "ModuleNotFoundError",
"evalue": "No module named 'tensorflow_text'",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m~\\AppData\\Local\\Temp/ipykernel_41180/4216669875.py\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[1;32mimport\u001b[0m \u001b[0mtensorflow_text\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 2\u001b[0m \u001b[1;32mimport\u001b[0m \u001b[0mtensorflow_hub\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0mhub\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[0mvectorizer\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mhub\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mKerasLayer\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'tensorflow_text'"
]
}
],
"source": [
"import tensorflow_text \n",
"import tensorflow_hub as hub\n",
"vectorizer = hub.KerasLayer('https://tfhub.dev/tensorflow/bert_en_uncased_preprocess/3')"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'input_type_ids': <tf.Tensor: shape=(1, 128), dtype=int32, numpy=\n",
" array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],\n",
" dtype=int32)>,\n",
" 'input_word_ids': <tf.Tensor: shape=(1, 128), dtype=int32, numpy=\n",
" array([[ 101, 1045, 2293, 19081, 102, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0]], dtype=int32)>,\n",
" 'input_mask': <tf.Tensor: shape=(1, 128), dtype=int32, numpy=\n",
" array([[1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\n",
" 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]],\n",
" dtype=int32)>}"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"vectorizer(['I love transformers'])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"វាសំខាន់ណាស់ដែលអ្នកប្រើនូវកាតាក្រហមដូចគ្នានឹងដែលបណ្តាញដើមបានបណ្តុះបណ្តាលលើវា។ ផងដែរឧបករណ៍បម្លែង BERT ត្រឡប់មកវិញនូវធាតុបី:\n",
"* `input_word_ids` ដែលជាដំណើរការប្រភេទលេខកូដសម្រាប់វាក្យបញ្ជូល\n",
"* `input_mask` បង្ហាញថាផ្នែកណានៃលំដាប់មានបញ្ចូលពិតប្រាកដ និងផ្នែកណាគឺជាការបន្លំ។ វាស្រដៀងនឹងម៉ាសដែលបានផលិតពីស្រទាប់ `Masking`\n",
"* `input_type_ids` ត្រូវបានប្រើសម្រាប់បេសកកម្មគំរូភាសា ហើយអនុញ្ញាតឱ្យបញ្ជាក់ពីប្រយោគបញ្ចូលពីរនៅលើលំដាប់មួយ។\n",
"\n",
"បន្ទាប់មក យើងអាចបង្កើតប្រភពយកលក្ខណៈពិសេស BERT បាន៖\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"bert = hub.KerasLayer('https://tfhub.dev/tensorflow/small_bert/bert_en_uncased_L-4_H-128_A-2/1')"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"pooled_output -> (1, 128)\n",
"encoder_outputs -> 4\n",
"sequence_output -> (1, 128, 128)\n",
"default -> (1, 128)\n"
]
}
],
"source": [
"z = bert(vectorizer(['I love transformers']))\n",
"for i,x in z.items():\n",
" print(f\"{i} -> { len(x) if isinstance(x, list) else x.shape }\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ដូច្នេះស្រទាប់ BERT នាំមកនូវលទ្ធផលប្រយោជន៍ជាច្រើន៖\n",
"* `pooled_output` គឺជាលទ្ធផលនៃការពន្លឿនច<Token>ងទាំងអស់ក្នុងលំដាប់។ អ្នកអាច xem វាជាបទបញ្ញាសម្ខេបស្មារតីនៃបណ្តាញទាំងមូល។ វាស្មើនឹងលទ្ធផលនៃស្រទាប់ `GlobalAveragePooling1D` ក្នុងគំរូមុនរបស់យើង។\n",
"* `sequence_output` គឺជាលទ្ធផលនៃស្រទាប់បម្លែងចុងក្រោយ (សមស្របនឹងលទ្ធផលនៃ `TransformerBlock` នៅក្នុងគំរូរបស់យើងខាងលើ)\n",
"* `encoder_outputs` គឺជាលទ្ធផលនៃស្រទាប់បម្លែងទាំងអស់។ ដោយសារយើងបានផ្ទុកគំរូ BERT ៤ ស្រទាប់ (ដូចដែលអ្នកអាចសន្មត់ពីឈ្មោះដែលមាន `4_H` នៅក្នុង), វាមានតង់ស័រចំនួន ៤។ តង់ស័រចុងក្រោយមានដូចគ្នានឹង `sequence_output`។\n",
"\n",
"ឥឡូវនេះយើងនឹងកំណត់គំរូចំណាត់ថ្នាក់ពីដើមដល់បញ្ចប់។ យើងនឹងប្រើ *ការ​កំណត់​គំរូ​តាម​អនុគមន៍* កាលណាយើងកំណត់អ៊ីពុ­tជុំវិញគំរូ ហើយបន្ទាប់មកផ្ដល់សរសេរ​អត្ថបទជាសំណុំពីរៀបរាប់របៀបគណនា​លទ្ធផល​របស់វា។ យើងនឹងក៏ធ្វើឲ្យទម្ងន់គំរូ BERT មិនអាចបណ្តុះបណ្តាលបាន សិងបណ្តុះបណ្តាលគ្រាន់តែ​អ្នកចំណាត់ថ្នាក់ចុងបញ្ចប់តែប៉ុណ្ណោះៈ\n"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"model\"\n",
"__________________________________________________________________________________________________\n",
"Layer (type) Output Shape Param # Connected to \n",
"==================================================================================================\n",
"input_1 (InputLayer) [(None,)] 0 \n",
"__________________________________________________________________________________________________\n",
"keras_layer (KerasLayer) {'input_type_ids': ( 0 input_1[0][0] \n",
"__________________________________________________________________________________________________\n",
"keras_layer_1 (KerasLayer) {'pooled_output': (N 4782465 keras_layer[0][0] \n",
" keras_layer[0][1] \n",
" keras_layer[0][2] \n",
"__________________________________________________________________________________________________\n",
"dropout_4 (Dropout) (None, 128) 0 keras_layer_1[0][5] \n",
"__________________________________________________________________________________________________\n",
"dense_4 (Dense) (None, 4) 516 dropout_4[0][0] \n",
"==================================================================================================\n",
"Total params: 4,782,981\n",
"Trainable params: 516\n",
"Non-trainable params: 4,782,465\n",
"__________________________________________________________________________________________________\n"
]
}
],
"source": [
"inp = keras.Input(shape=(),dtype=tf.string)\n",
"x = vectorizer(inp)\n",
"x = bert(x)\n",
"x = keras.layers.Dropout(0.1)(x['pooled_output'])\n",
"out = keras.layers.Dense(4,activation='softmax')(x)\n",
"model = keras.models.Model(inp,out)\n",
"bert.trainable = False\n",
"model.summary()"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"938/938 [==============================] - 528s 559ms/step - loss: 0.8056 - acc: 0.6983 - val_loss: 0.5953 - val_acc: 0.7888\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7f9bb1e36d00>"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer='adam')\n",
"model.fit(ds_train.map(tupelize).batch(128),validation_data=ds_test.map(tupelize).batch(128))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ទោះបីជាម៉ោងប៉ារ៉ាម៉ែត្រដែលអាចបណ្តុះបណ្តាលបានមានតិចក៏ដោយ ប៉ុន្តែដំណើរការនេះយឺតណាស់ ដោយសារតែអ្នកដកស្រង់លក្ខណៈ BERT មានគណនាពិបាក។ វាដូចជាយើងមិនអាចទទួលបានភាពត្រឹមត្រូវសមរម្យទេ ម្ដងទេដោយសារ ការខ្វះការបណ្តុះបណ្តាល ឬការខ្វះម៉ូដែលប៉ារ៉ាម៉ែត្រ។\n",
"\n",
"ឲ្យព្យាយាមបញ្ចេញទម្ងន់ BERT ហើយបណ្តុះបណ្តាលវាផងដែរ។ នេះទាមទារពីអត្រាការសិក្សាខ្លាំងតិច និងយុទ្ធសាស្ត្របណ្តុះបណ្តាលប្រុងប្រយ័ត្នជាមួយ **warmup** ដោយប្រើ **AdamW** អុបទីម៉ាអ៊ីសឃិន។ យើងនឹងប្រើផ្ទាំង `tf-models-official` ដើម្បីបង្កើតអុបទីម៉ាអ៊ីសឃិន៖\n"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"model\"\n",
"__________________________________________________________________________________________________\n",
"Layer (type) Output Shape Param # Connected to \n",
"==================================================================================================\n",
"input_1 (InputLayer) [(None,)] 0 \n",
"__________________________________________________________________________________________________\n",
"keras_layer (KerasLayer) {'input_type_ids': ( 0 input_1[0][0] \n",
"__________________________________________________________________________________________________\n",
"keras_layer_1 (KerasLayer) {'pooled_output': (N 4782465 keras_layer[0][0] \n",
" keras_layer[0][1] \n",
" keras_layer[0][2] \n",
"__________________________________________________________________________________________________\n",
"dropout_4 (Dropout) (None, 128) 0 keras_layer_1[0][5] \n",
"__________________________________________________________________________________________________\n",
"dense_4 (Dense) (None, 4) 516 dropout_4[0][0] \n",
"==================================================================================================\n",
"Total params: 4,782,981\n",
"Trainable params: 4,782,980\n",
"Non-trainable params: 1\n",
"__________________________________________________________________________________________________\n",
"938/938 [==============================] - 629s 664ms/step - loss: 0.6344 - acc: 0.7658 - val_loss: 0.4876 - val_acc: 0.8247\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7f9bb0bd0070>"
]
},
"execution_count": 12,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from official.nlp import optimization \n",
"bert.trainable=True\n",
"model.summary()\n",
"epochs = 3\n",
"opt = optimization.create_optimizer(\n",
" init_lr=3e-5,\n",
" num_train_steps=epochs*len(ds_train),\n",
" num_warmup_steps=0.1*epochs*len(ds_train),\n",
" optimizer_type='adamw')\n",
"\n",
"model.compile(loss='sparse_categorical_crossentropy',metrics=['acc'], optimizer=opt)\n",
"model.fit(ds_train.map(tupelize).batch(128),validation_data=ds_test.map(tupelize).batch(128))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ដូចដែលអ្នកអាចឃើញ ការបណ្តុះបណ្តាលដំណើរការយ៉ាងយឺត - ប៉ុន្តែអ្នកអាចចង់សាកល្បង និងបណ្តុះបណ្តាលម៉ូដែលសម្រាប់រយៈពេលបណ្ដោះអាសន្នមួយចំនួន (5-10) ហើយមើលថាតើអ្នកអាចទទួលបានលទ្ធផលល្អបំផុតបើប្រៀបធៀបនឹងវិធីសាស្រ្តដែលយើងបានប្រើមុន។\n",
"\n",
"## បណ្ណាល័យ Huggingface Transformers\n",
"\n",
"វិធីសាស្រ្តមួយដែលពេញនិយមខ្លាំង (និងសាមញ្ញបន្តិច) ក្នុងការប្រើម៉ូដែល Transformer គឺ [HuggingFace package](https://github.com/huggingface/), ដែលផ្តល់ជាប្លុកសាងសម្រាប់ភារកិច្ច NLP ផ្សេងៗ។ វាមានសម្រាប់ទាំង Tensorflow និង PyTorch, មានគ្រាប់ខ្សែប្រព័ន្ធសរសៃប្រសាទមួយទៀតដែលពេញនិយម។\n",
"\n",
"> **ចំណាំ**៖ ប្រសិនបើអ្នកមិនចាប់អារម្មណ៍ក្នុងការស្គាល់ថា បណ្ណាល័យ Transformers ធ្វើការយ៉ាងដូចម្តេចទេ - អ្នកអាចរំលងទៅចុងបញ្ចប់នៃសៀវភៅកំណត់ត្រានេះបាន ដោយសារ អ្នកនឹងមិនឃើញអ្វីខុសប្លែកយ៉ាងសំខាន់ពីអ្វីដែលយើងបានធ្វើខាងលើីទេស។ យើងនឹងធ្វើម្តងទៀតជំហានដូចគ្នានៃការបណ្តុះបណ្តាលម៉ូដែល BERT ដោយប្រើបណ្ណាល័យផ្សេង និងម៉ូដែលធំពេញមួយ។ ដូច្នេះ ដំណើរការនេះរួមបញ្ចូលការបណ្តុះបណ្តាលយូរមួយខ្លះ ដូច្នេះ អ្នកអាចចង់មើលតែមាតិកាកូដប៉ុណ្ណោះ។\n",
"\n",
"មកមើលថា បញ្ហារបស់យើងអាចដោះស្រាយដោយប្រើ [Huggingface Transformers](http://huggingface.co) ដូចម្តេច។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"រឿងដំបូងដែលយើងត្រូវធ្វើគឺជ្រើសរើសម៉ូដែលដែលយើងនឹងប្រើ។ បន្ថែមពីម៉ូដែលដែលបានកសាងមកដូចមានស្រាប់ហើយ Huggingface មាន [ឃ្លាំងម៉ូដែលអនឡាញ](https://huggingface.co/models) ដែលអ្នកអាចស្វែងរកម៉ូដែលបានបណ្តុះបណ្តាលជាច្រើនទៀតដោយសហគមន៍។ ម៉ូដែលទាំងអស់នោះអាចត្រូវបានបញ្ជូនចូល និងប្រើប្រាស់បានត្រឹមតែផ្ដល់ឈ្មោះម៉ូដែលប៉ុណ្ណោះ។ គ្រប់កំណត់ត្រាស៊ីស្ដមប៊ីណារបស់ម៉ូដែលនឹងត្រូវបានទាញយកដោយស្វ័យប្រវត្តិ។\n",
"\n",
"ពេលខ្លះអ្នកនឹងត្រូវបញ្ជូនចូលម៉ូដែលរបស់អ្នកផ្ទាល់ ដោយក្នុងករណីនោះ អ្នកអាចបញ្ជាក់ថតដែលមានឯកសារសម្របសម្រួលទាំងអស់ រួមមានប៉ារ៉ាមែត្រ tokenizer, ឯកសារ `config.json` រួមបញ្ចូលប៉ារ៉ាមែត្រម៉ូដែល, ត្រូងទម្ងន់ប៊ីណាររួចដែរ។\n",
"\n",
"ពីឈ្មោះម៉ូដែល អ្នកអាចបង្កើតម៉ូដែល និង tokenizer ទាំងពីរជាប្រភេទថ្នាក់មួយ។ យើងចាប់ផ្តើមជាមួយ tokenizer៖\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"import transformers\n",
"\n",
"# To load the model from Internet repository using model name. \n",
"# Use this if you are running from your own copy of the notebooks\n",
"bert_model = 'bert-base-uncased' \n",
"\n",
"# To load the model from the directory on disk. Use this for Microsoft Learn module, because we have\n",
"# prepared all required files for you.\n",
"#bert_model = './bert'\n",
"\n",
"tokenizer = transformers.BertTokenizer.from_pretrained(bert_model)\n",
"\n",
"MAX_SEQ_LEN = 128\n",
"PAD_INDEX = tokenizer.convert_tokens_to_ids(tokenizer.pad_token)\n",
"UNK_INDEX = tokenizer.convert_tokens_to_ids(tokenizer.unk_token)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"អ объект `tokenizer` មានមុខងារ `encode` ដែលអាចប្រើប្រាស់ផ្ទាល់ក្នុងការត្រួតពិនិត្យអក្សរ ៖\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[101, 23435, 12314, 2003, 1037, 2307, 7705, 2005, 17953, 2361, 102]"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tokenizer.encode('Tensorflow is a great framework for NLP')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"យើងក៏អាចប្រើ tokenizer ដើម្បីបញ្ចូលលេខសម្គាល់មួយជាលំដាប់ ដែលសមរម្យសម្រាប់ផ្ញើទៅម៉ូដែល។​ ឧទាហរណ៍ រួមមាន `token_ids`, វាល `input_mask` និងអ៊ីដូច្នេះទៀត។ យើងក៏អាចបញ្ជាក់ថាយើងចង់បាន Tensorflow tensors ដោយផ្តល់អាគុយម៉ង់ `return_tensors='tf'`:\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'input_ids': <tf.Tensor: shape=(1, 5), dtype=int32, numpy=array([[ 101, 7592, 1010, 2045, 102]], dtype=int32)>, 'token_type_ids': <tf.Tensor: shape=(1, 5), dtype=int32, numpy=array([[0, 0, 0, 0, 0]], dtype=int32)>, 'attention_mask': <tf.Tensor: shape=(1, 5), dtype=int32, numpy=array([[1, 1, 1, 1, 1]], dtype=int32)>}"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tokenizer(['Hello, there'],return_tensors='tf')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ក្នុងករណីរបស់យើង យើងនឹងប្រើម៉ូឌែល BERT ដែលបានបណ្តុះបណ្តាលរួចហើយដែលហៅថា `bert-base-uncased`។ *Uncased* បង្ហាញថាម៉ូឌែលនេះមិនអើពើអក្សរធំតូចឡើយ។\n",
"\n",
"ពេលបណ្តុះបណ្តាលម៉ូឌែល យើងត្រូវផ្តល់លំដាប់ tokenized ជាឧបិន្ត និងដូច្នេះយើងនឹងរចនាដំណើរការបំបែកទិន្នន័យ។ ពីព្រោះ `tokenizer.encode` ជាអនុគមន៍ Python យើងនឹងប្រើវិធីសាស្ត្រដូចក្នុងផ្នែកចុងក្រោយ ដោយហៅវា​ដោយប្រើ `py_function`:\n"
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [],
"source": [
"def process(x):\n",
" return tokenizer.encode(x.numpy().decode('utf-8'),return_tensors='tf',padding='max_length',max_length=MAX_SEQ_LEN,truncation=True)[0]\n",
"\n",
"def process_fn(x):\n",
" s = x['title']+' '+x['description']\n",
" e = tf.py_function(process,inp=[s],Tout=(tf.int32))\n",
" e.set_shape(MAX_SEQ_LEN)\n",
" return e,x['label']"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ឥឡូវនេះយើងអាចផ្ទុកគំរូពិតប្រាកដដោយប្រើកញ្ចប់ `BertForSequenceClassfication`។ នេះធានាថាគំរូរបស់យើងមានរចនាសម្ព័ន្ធដែលត្រូវការសម្រាប់ចាត់ថ្នាក់រួចហើយ រួមទាំងម៉ាស៊ីនចាត់ថ្នាក់ចុងក្រោយ។ អ្នកនឹងឃើញសារ​រាស្រ្ត​ត្រូវ​បាន​បង្ហាញ​ថា ទំងន់​របស់​ម៉ាស៊ីន​ចាត់ថ្នាក់​ចុងក្រោយ​មិន​ត្រូវ​បាន​ចាប់ផ្ដើម ដែល​គំរូ​ត្រូវការបណ្តុះបណ្តាល​កម្រិត​ខាងមុខ - នេះល្អបំផុត ពីព្រោះ វាជាការដែលយើងកំពុងតែធ្វើ!\n"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {},
"outputs": [],
"source": [
"model = transformers.TFBertForSequenceClassification.from_pretrained(bert_model,num_labels=4,output_attentions=False)"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"tf_bert_for_sequence_classification_1\"\n",
"_________________________________________________________________\n",
"Layer (type) Output Shape Param # \n",
"=================================================================\n",
"bert (TFBertMainLayer) multiple 109482240 \n",
"_________________________________________________________________\n",
"dropout_75 (Dropout) multiple 0 \n",
"_________________________________________________________________\n",
"classifier (Dense) multiple 3076 \n",
"=================================================================\n",
"Total params: 109,485,316\n",
"Trainable params: 109,485,316\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n"
]
}
],
"source": [
"model.summary()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ដូចដែល​អ្នក​អាច​ឃើញ​ពី​`summary()` គំរូ​មាន​ប៉ារ៉ាម៉ែត្រ​ប្រហែលជា ១១០លាន! ប្រហែល​ណាស់ ប្រសិនបើ​យើង​ចង់​ធ្វើ​បេសកកម្ម​ចាត់ថ្នាក់​សាមញ្ញ​លើ​កំណត់​ទិន្នន័យ​ខ្នាតតូច​ទៅមួយ យើង​មិន​ចង់​បណ្តុះ​ស្រទាប់មូលដ្ឋាន BERT ទេ៖\n"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"tf_bert_for_sequence_classification_1\"\n",
"_________________________________________________________________\n",
"Layer (type) Output Shape Param # \n",
"=================================================================\n",
"bert (TFBertMainLayer) multiple 109482240 \n",
"_________________________________________________________________\n",
"dropout_75 (Dropout) multiple 0 \n",
"_________________________________________________________________\n",
"classifier (Dense) multiple 3076 \n",
"=================================================================\n",
"Total params: 109,485,316\n",
"Trainable params: 3,076\n",
"Non-trainable params: 109,482,240\n",
"_________________________________________________________________\n"
]
}
],
"source": [
"model.layers[0].trainable = False\n",
"model.summary()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ឥឡូវនេះយើងមានការត្រៀមខ្លួនធ្វើបណ្តុះបណ្តាលហើយ!\n",
"\n",
"> **កំណត់ចំណាំ**៖ ការបណ្តុះបណ្តាលម៉ូដែល BERT ទំហំពេញអាចជាប់ពេលវេលាយូរ! ដូច្នេះយើងនឹងបណ្តុះបណ្តាលវាសម្រាប់ ៣២ បដិវេណ៍ដំបូងប៉ុណ្ណោះ។ នេះគ្រាន់តែបង្ហាញពីរបៀបដែលការបណ្តុះបណ្តាលម៉ូដែលត្រូវបានរៀបចំប៉ុណ្ណោះ។ ប្រសិនបើអ្នកចង់សាកល្បងបណ្តុះបណ្តាលទំហំពេញ - គ្រាន់តែដក parameter `steps_per_epoch` និង `validation_steps` ហើយត្រៀមខ្លួនរង់ចាំ!\n"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"32/32 [==============================] - 142s 4s/step - loss: 1.3896 - acc: 0.2500 - val_loss: 1.3863 - val_acc: 0.2480\n"
]
},
{
"data": {
"text/plain": [
"<tensorflow.python.keras.callbacks.History at 0x7f1d40a4b6a0>"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model.compile('adam','sparse_categorical_crossentropy',['acc'])\n",
"tf.get_logger().setLevel('ERROR')\n",
"model.fit(ds_train.map(process_fn).batch(32),validation_data=ds_test.map(process_fn).batch(32),steps_per_epoch=32,validation_steps=2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"បើអ្នកបង្កើនចំនួន iteration ហើយរង់ចាំយូរពេញលេញ ហើយបណ្តុះសិក្សារយៈពេលជាច្រើន epoch អ្នកអាចរំពឹងថាការបែងចែកប្រភេទ BERT នឹងផ្តល់ជូននូវភាពត្រឹមត្រូវល្អបំផុត! នេះគឺដោយសារតែ BERT បានយល់ពីរចនាសម្ព័ន្ធភាសាយ៉ាងល្អហើយ ហើយយើងគ្រាន់តែត្រូវតែមិនធ្វើតែការត្រួតពិនិត្យ classifier ចុងក្រោយប៉ុណ្ណោះ។ ទោះជាយ៉ាងណាក៏ដោយ ព្រោះ BERT គឺជាគំរូធំ ដំណើរការបណ្តុះសិក្សាទាំងមូលចំណាយពេលប៉ុនប៉ងយូរ ហើយត្រូវការថាមពលគណនាប្រកបដោយភាពដាច់ខាត! (GPU និងល្អបំផុតមានល្មមជាងមួយ)។\n",
"\n",
"> **កំណត់ចំណាំ:** ក្នុងឧទាហរណ៍របស់យើង យើងបានប្រើមួយក្នុងចំណោមគំរូ BERT ដែលតូចជាងគេដែលបានបណ្តុះបណ្តាលរួចមុន។ មានគំរូធំជាងនេះដែលមានសក្ដានុពលផ្តល់លទ្ធផលល្អជាង។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Takeaway\n",
"\n",
"នៅក្នុងឯកតានេះ យើងបានមើលឃើញរចនាសម្ព័ន្ធម៉ូដែលទំនើបៗថ្មីៗ ដែលផ្អែកលើ **transformers**។ យើងបានអនុវត្តវាសម្រាប់ការបែងចែកចំណាត់ថ្នាក់អក្សររបស់យើង ប៉ុន្តែដូចគ្នានេះ ម៉ូដែល BERT អាចប្រើសម្រាប់ការដកស្រង់អង្គភាព ការឆ្លើយសំណួរ និងភារកិច្ច NLP ផ្សេងទៀត។\n",
"\n",
"ម៉ូដែល Transformer តំណាងឱ្យស្ថានភាព-of-the-art បច្ចុប្បន្ននៅក្នុង NLP ហើយក្នុងភាគច្រើននៃករណី វាគួរត្រូវបានជាជម្រើសដំបូងដែលអ្នកចាប់ផ្តើមសាកល្បងនៅពេលអនុវត្តដំណោះស្រាយ NLP ផ្ទាល់ខ្លួន។ ទោះជាយ៉ាងណា ការយល់ដឹងពីគ្រឹះមូលដ្ឋាននៃគោលការណ៍ផ្នែកបណ្តាញបញ្ជូនហ្វេនដែលបានពិភាក្សាក្នុងម៉ូឌុលនេះ គឺមានសារៈសំខាន់ខ្លាំង ប្រសិនបើអ្នកចង់កសាងម៉ូដែលណឺរ៉ូនកម្រិតខ្ពស់។\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**ការលើកឡើងកំហិត**៖ \nឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាកម្មបកប្រែដោយ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេលដែលយើងខិតខំព្យាយាមរកភាពច្បាស់លាស់ សូមជ្រាបថាការបកប្រែដោយស្វ័យប្រវត្តិអាចមានកំហុសឬមិនត្រឹមត្រូវ។ ឯកសារដើមដែលមានភាសាតំណើរបស់វាគួរត្រូវបានគេយកទៅជាអំពើគោលការណ៍។ សម្រាប់ព័ត៌មានសំខាន់ៗ ការបកប្រែដោយមនុស្សជំនាញគឺមានការណែនាំ។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំនឹង ឬការបកប្រែខុសការពីការប្រើប្រាស់ការបកប្រែនេះឡើយ។\n<!-- CO-OP TRANSLATOR DISCLAIMER END -->\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "0cb620c6d4b9f7a635928804c26cf22403d89d98d79684e4529119355ee6d5a5"
},
"kernelspec": {
"display_name": "py38_tensorflow",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.12"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,10 @@
# Assignment: Transformers
សាកល្បងជាមួយ Transformers នៅលើ HuggingFace! សូមព្យាយាមប្រើស្គ្រីបខ្លះៗដែលពួកគេផ្តល់ជូនដើម្បីធ្វើការជាមួយម៉ូឌែលផ្សេងៗដែលមាននៅលើគេហទំព័ររបស់ពួកគេ៖ https://huggingface.co/docs/transformers/run_scripts។ សាកល្បង dataset មួយរបស់ពួកគេ បន្ទាប់មកនាំចូល dataset មួយដែលអ្នកមានផ្ទាល់ពីមេរៀននេះ ឬពី Kaggle ហើយមើលថាអ្នកអាចបង្កើតអត្ថបទដែលគួរឱ្យចាប់អារម្មណ៍បានទេ។ បង្កើតសៀវភៅកំណត់ត្រាមួយជាមួយនឹងការស្រាវជ្រាវរបស់អ្នក។
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការព្រមាន**៖
ឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេលយើងខិតខំរកភាពត្រឹមត្រូវ សូមយល់ព្រមថាការបកប្រែដោយស្វ័យប្រវត្តិបា្រត្រមានបញ្ហា ឬកំហុសបាន។ ឯកសារដើមក្នុងភាសាដើមគួរត្រូវបាន​គិតថាជាអ្នកផ្តល់ព័ត៌មានដែលមានសុពលភាព។ សម្រាប់ព័ត៌មានសំខាន់ៗ សូមណែនាំការបកប្រែដោយអ្នកជំនាញមនុស្ស។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកប្រែខុសគ្នាដែលកើតមានពីការប្រើប្រាស់ការបកប្រែនេះឡើយ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,488 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# ការទទួលស្គាល់អង្គភាពឈ្មោះ (NER)\n",
"\n",
"កំណត់ត្រានេះមកពី [កម្មវិធីសិក្សា AI សម្រាប់អ្នកចាប់ផ្តើម](http://aka.ms/ai-beginners)។\n",
"\n",
"នៅក្នុងឧទាហរណ៍នេះ យើងនឹងរៀនពីរបៀបបណ្តុះបណ្តាលម៉ូដែល NER លើ [Annotated Corpus for Named Entity Recognition](https://www.kaggle.com/datasets/abhinavwalia95/entity-annotated-corpus) Dataset ពី Kaggle។ មុនពេលបន្ត សូមទាញយកឯកសារ [ner_dataset.csv](https://www.kaggle.com/datasets/abhinavwalia95/entity-annotated-corpus?resource=download&select=ner_dataset.csv) ទៅក្នុងថតបច្ចុប្បន្ន។\n"
]
},
{
"cell_type": "code",
"execution_count": 62,
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"from tensorflow import keras\n",
"import numpy as np"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ការរៀបចំឯកទិន្នន័យ\n",
"\n",
"យើងនឹងចាប់ផ្តើមដោយការអានឯកទិន្នន័យទៅក្នុង dataframe។ ប្រសិនបើអ្នកចង់រៀនបន្ថែមអំពីការប្រើប្រាស់ Pandas សូមចូលទៅកាន់ [មេរៀនអំពីការដំណើរការទិន្នន័យ](https://github.com/microsoft/Data-Science-For-Beginners/tree/main/2-Working-With-Data/07-python) នៅក្នុង [វិទ្យាសាស្ត្រ​ទិន្នន័យ​សម្រាប់​អ្នក​ចាប់ផ្តើម](http://aka.ms/datascience-beginners) របស់យើង។\n"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>Sentence #</th>\n",
" <th>Word</th>\n",
" <th>POS</th>\n",
" <th>Tag</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>Sentence: 1</td>\n",
" <td>Thousands</td>\n",
" <td>NNS</td>\n",
" <td>O</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>NaN</td>\n",
" <td>of</td>\n",
" <td>IN</td>\n",
" <td>O</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>NaN</td>\n",
" <td>demonstrators</td>\n",
" <td>NNS</td>\n",
" <td>O</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>NaN</td>\n",
" <td>have</td>\n",
" <td>VBP</td>\n",
" <td>O</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>NaN</td>\n",
" <td>marched</td>\n",
" <td>VBN</td>\n",
" <td>O</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" Sentence # Word POS Tag\n",
"0 Sentence: 1 Thousands NNS O\n",
"1 NaN of IN O\n",
"2 NaN demonstrators NNS O\n",
"3 NaN have VBP O\n",
"4 NaN marched VBN O"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df = pd.read_csv('ner_dataset.csv',encoding='unicode-escape')\n",
"df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"មកយកស្លាកផ្ទាល់ខ្លួន ហើយបង្កើតវចនានុក្រមស្វែងរកដែលយើងអាចប្រើដើម្បីបម្លែងស្លាកទៅជាលេខថ្នាក់:\n"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array(['O', 'B-geo', 'B-gpe', 'B-per', 'I-geo', 'B-org', 'I-org', 'B-tim',\n",
" 'B-art', 'I-art', 'I-per', 'I-gpe', 'I-tim', 'B-nat', 'B-eve',\n",
" 'I-eve', 'I-nat'], dtype=object)"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"tags = df.Tag.unique()\n",
"tags"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"'O'"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"id2tag = dict(enumerate(tags))\n",
"tag2id = { v : k for k,v in id2tag.items() }\n",
"\n",
"id2tag[0]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ឥឡូវនេះយើងត្រូវធ្វើដូចគ្នានឹងវ៉ុកាបសារ។ សម្រាប់ភាពសាមញ្ញ យើងនឹងបង្កើតវ៉ុកាបសារដោយមិនគិតគូសអាករណ៍នៃពាក្យឡើយ; ក្នុងជីវិតពិត អ្នកអាចចង់ប្រើកម្មវិធីផ្សារជា vectorizer របស់ Keras ហើយកំណត់ចំនួនពាក្យ។\n"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {},
"outputs": [],
"source": [
"vocab = set(df['Word'].apply(lambda x: x.lower()))\n",
"id2word = { i+1 : v for i,v in enumerate(vocab) }\n",
"id2word[0] = '<UNK>'\n",
"vocab.add('<UNK>')\n",
"word2id = { v : k for k,v in id2word.items() }"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"យើងត្រូវការបង្កើតឌាតាសែតនៃប្រយោគសម្រាប់ការបណ្តុះបណ្តាល។ ម្តងនេះយើងចូលរួមតាមរយៈឌាតាសែតដើមហើយបំបែកប្រយោគមួយៗចេញទៅជា `X` (បញ្ជីពាក្យ) និង `Y` (បញ្ជីតុកខេន):\n"
]
},
{
"cell_type": "code",
"execution_count": 41,
"metadata": {},
"outputs": [],
"source": [
"X,Y = [],[]\n",
"s,t = [],[]\n",
"for i,row in df[['Sentence #','Word','Tag']].iterrows():\n",
" if pd.isna(row['Sentence #']):\n",
" s.append(row['Word'])\n",
" t.append(row['Tag'])\n",
" else:\n",
" if len(s)>0:\n",
" X.append(s)\n",
" Y.append(t)\n",
" s,t = [row['Word']],[row['Tag']]\n",
"X.append(s)\n",
"Y.append(t)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ឥឡូវនេះយើងនឹងបំលែងពាក្យ និងតូចតាមទាំងអស់ទៅជាវ៉ិចទ័រ៖\n"
]
},
{
"cell_type": "code",
"execution_count": 93,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"([10386,\n",
" 23515,\n",
" 4134,\n",
" 29620,\n",
" 7954,\n",
" 13583,\n",
" 21193,\n",
" 12222,\n",
" 27322,\n",
" 18258,\n",
" 5815,\n",
" 15880,\n",
" 5355,\n",
" 25242,\n",
" 31327,\n",
" 18258,\n",
" 27067,\n",
" 23515,\n",
" 26444,\n",
" 14412,\n",
" 358,\n",
" 26551,\n",
" 5011,\n",
" 30558],\n",
" [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0])"
]
},
"execution_count": 93,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def vectorize(seq):\n",
" return [word2id[x.lower()] for x in seq]\n",
"\n",
"def tagify(seq):\n",
" return [tag2id[x] for x in seq]\n",
"\n",
"Xv = list(map(vectorize,X))\n",
"Yv = list(map(tagify,Y))\n",
"\n",
"Xv[0], Yv[0]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"សម្រាប់ភាពងាយស្រួល យើងនឹងបញ្ចូលសញ្ញាសូន្យ 0 ទៅក្នុងប្រយោគទាំងអស់ដើម្បីឲ្យបានប្រវែងអតិបរមា។ ក្នុងជីវិតពិតប្រាកដ យើងអាចចង់ប្រើយុទ្ធសាស្រ្តឆ្លាតវៃជាងនេះ ហើយបញ្ចូលសញ្ញា 0 ក្នុងលំដាប់តែមួយនៅក្នុងមីនីបាច់ប៉ុណ្ណោះ។\n"
]
},
{
"cell_type": "code",
"execution_count": 51,
"metadata": {},
"outputs": [],
"source": [
"X_data = keras.preprocessing.sequence.pad_sequences(Xv,padding='post')\n",
"Y_data = keras.preprocessing.sequence.pad_sequences(Yv,padding='post')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ការបញ្ជាក់បណ្តាញចាត់ថ្នាក់ Token\n",
"\n",
"យើងនឹងប្រើបណ្ដាញ LSTM ជាន់ពីរដែរដោយទិសពីរដើម្បីចាត់ថ្នាក់ token។ ដើម្បីអាចអនុវត្តកម្មវិធីចាត់ថ្នាក់ដិតសម្រាប់លទ្ធផលនៃជាន់ចុងក្រោយរបស់ LSTM នីមួយៗ យើងនឹងប្រើ `TimeDistributed` ដែលធ្វើការចម្លងល័កស្ទរដិតដូចគ្នាទៅលើលទ្ធផលនៃ LSTM ក្នុងជំហាននីមួយៗ៖ \n"
]
},
{
"cell_type": "code",
"execution_count": 94,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model: \"sequential_3\"\n",
"_________________________________________________________________\n",
" Layer (type) Output Shape Param # \n",
"=================================================================\n",
" embedding_4 (Embedding) (None, 104, 300) 9545400 \n",
" \n",
" bidirectional_6 (Bidirectio (None, 104, 200) 320800 \n",
" nal) \n",
" \n",
" bidirectional_7 (Bidirectio (None, 104, 200) 240800 \n",
" nal) \n",
" \n",
" time_distributed_3 (TimeDis (None, 104, 17) 3417 \n",
" tributed) \n",
" \n",
"=================================================================\n",
"Total params: 10,110,417\n",
"Trainable params: 10,110,417\n",
"Non-trainable params: 0\n",
"_________________________________________________________________\n"
]
}
],
"source": [
"maxlen = X_data.shape[1]\n",
"vocab_size = len(vocab)\n",
"num_tags = len(tags)\n",
"model = keras.models.Sequential([\n",
" keras.layers.Embedding(vocab_size, 300, input_length=maxlen),\n",
" keras.layers.Bidirectional(keras.layers.LSTM(units=100, activation='tanh', return_sequences=True)),\n",
" keras.layers.Bidirectional(keras.layers.LSTM(units=100, activation='tanh', return_sequences=True)),\n",
" keras.layers.TimeDistributed(keras.layers.Dense(num_tags, activation='softmax'))\n",
"])\n",
"model.compile(loss='sparse_categorical_crossentropy',optimizer='adam',metrics=['acc'])\n",
"model.summary()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ចំណាំនៅទីនេះថា យើងកំពុងបញ្ជាក់យ៉ាងច្បាស់ `maxlen` សម្រាប់ឃ្លាំងទិន្នន័យរបស់យើង - បើសិនជាយើងចង់ឲ្យបណ្តាញអាចដោះស្រាយអំពីលំដាប់ប្រវែងខុសៗគ្នា ត្រូវការ​ឲ្យយើងមានប្រាជ្ញា​បន្តិចនៅពេលកំណត់បណ្តាញ។\n",
"\n",
"ឥឡូវនេះ យើងចាប់ផ្តើមបណ្តុះម៉ូដែល។ សម្រាប់ល្បឿន យើងនឹងបណ្តុះតែមួយវគ្គ តែក៏អ្នកអាចព្យាយាមបណ្តុះរយៈពេលយូរជាងនេះបាន។ លើសពីនេះ អ្នកអាចចែកជាមួយផ្នែកមួយនៃឃ្លាំងទិន្នន័យជាឃ្លាំងបណ្តុះ ដើម្បីមើលភាពត្រឹមត្រូវក្នុងការត្រួតពិនិត្យបានផង។\n"
]
},
{
"cell_type": "code",
"execution_count": 57,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1499/1499 [==============================] - 740s 488ms/step - loss: 0.0667 - acc: 0.9841\n"
]
},
{
"data": {
"text/plain": [
"<keras.callbacks.History at 0x16f0bb2a310>"
]
},
"execution_count": 57,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"model.fit(X_data,Y_data)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ការធ្វើតេស្តលទ្ធផល\n",
"\n",
"ឥឡូវនេះអោយយើងមើលថាតើម៉ូដែលការទទួលស្គាល់អង្គភាពរបស់យើងដំណើរការយ៉ាងដូចម្តេចលើប្រយោគគំរូមួយ:\n"
]
},
{
"cell_type": "code",
"execution_count": 91,
"metadata": {},
"outputs": [],
"source": [
"sent = 'John Smith went to Paris to attend a conference in cancer development institute'\n",
"words = sent.lower().split()\n",
"v = keras.preprocessing.sequence.pad_sequences([[word2id[x] for x in words]],padding='post',maxlen=maxlen)\n",
"res = model(v)[0]"
]
},
{
"cell_type": "code",
"execution_count": 92,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"john -> B-per\n",
"smith -> I-per\n",
"went -> O\n",
"to -> O\n",
"paris -> B-geo\n",
"to -> O\n",
"attend -> O\n",
"a -> O\n",
"conference -> O\n",
"in -> O\n",
"cancer -> B-org\n",
"development -> I-org\n",
"institute -> I-org\n"
]
}
],
"source": [
"r = np.argmax(res.numpy(),axis=1)\n",
"for i,w in zip(r,words):\n",
" print(f\"{w} -> {id2tag[i]}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Takeaway\n",
"\n",
"ម៉ូដែល LSTM សាមញ្ញមួយ បង្ហាញលទ្ធផលសមរម្យនៅក្នុង NER។ ទោះជាយ៉ាងណា ដើម្បីទទួលបានលទ្ធផលល្អជាងនេះ អ្នកប្រហែលចង់ប្រើម៉ូដែលភាសាធំដែលបានបណ្តុះបណ្តាលរួចដូចជាវិធី BERT។ ការបណ្តុះបណ្តាល BERT សម្រាប់ NER ដោយប្រើបណ្ណាល័យ Huggingface Transformers ត្រូវបានពិពណ៌នាអាស្រ័យ [នៅទីនេះ](https://huggingface.co/course/chapter7/2?fw=pt)।\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**ការបដិសេធ**៖ \nឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេលដែលយើងខិតខំរកសុពលភាព សូមយល់ថាការបកប្រែដោយស្វ័យប្រវត្តិបំពាក់ដោយកំហុសឬការខ្វះត្រឹមត្រូវខ្លះៗ។ ឯកសារដើមជាភាសាបុរាណគួរត្រូវបានគេយកទៅជាដើមហើយមានអំណាច។ សម្រាប់ព័ត៌មានសំខាន់ៗ សូមផ្តួចផ្តើមការបកប្រែដោយអ្នកជំនាញមនុស្ស។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំឬការបកស្រាយខុសពីការប្រើប្រាស់ការបកប្រែនេះទេ។\n<!-- CO-OP TRANSLATOR DISCLAIMER END -->\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "16af2a8bbb083ea23e5e41c7f5787656b2ce26968575d8763f2c4b17f9cd711f"
},
"kernelspec": {
"display_name": "Python 3.8.12 ('py38')",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.12"
},
"orig_nbformat": 4
},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@ -0,0 +1,89 @@
# ការទទួលស្គាល់អង្គភាពមានឈ្មោះ
រហូតមកដល់ឥឡូវនេះ យើងបានផ្ដោតសំខាន់ច្រើនលើភារកិច្ច NLP មួយគត់គ yaituការចាត់ថ្នាក់។ ទោះយ៉ាងណា ក៏មានភារកិច្ច NLP ផ្សេងទៀតដែលអាចត្រូវបានបំពេញដោយបណ្តាញប្រសាទ។ មួយក្នុងចំណោមភារកិច្ចទាំងនោះគឺ **[ការទទួលស្គាល់អង្គភាពមានឈ្មោះ](https://wikipedia.org/wiki/Named-entity_recognition)** (NER) ដែលពាក់ព័ន្ធនឹងការទទួលស្គាល់អង្គភាពជាក់លាក់នៅក្នុងអត្ថបទ ដូចជា ទីកន្លែង ឈ្មោះមនុស្ស រយៈពេលថ្ងៃ-ម៉ោង សមីការពុលរូបមន្តគីមី និងផ្សេងៗទៀត។
## [វីរុសសំណួរមុនមេរៀន](https://ff-quizzes.netlify.app/en/ai/quiz/37)
## ឧទាហរណ៍នៃការប្រើប្រាស់ NER
សន្និដ្ឋានថាអ្នកចង់អភិវឌ្ឍរកម្មវិធីជជែកភាសាធម្មជាតិដូចជា Alexa របស់ Amazon ឬ Google Assistant។ វិធីដែលកម្មវិធីជជែកឆ្លាតវៃដំណើរការពីរបៀបនេះគឺជា*យល់*ថាអ្នកប្រើប្រាស់ចង់បានអ្វី ដោយធ្វើការចាត់ថ្នាក់អត្ថបទលើប្រយោគដែលបញ្ចូល។ លទ្ធផលនៃការចាត់ថ្នាក់នេះមានឈ្មោះថា **គោលបំណង** ដែលកំណត់ថាកម្មវិធីជជែកត្រូវធ្វើអ្វី។
<img alt="Bot NER" src="../../../../../translated_images/km/bot-ner.4b09235dbb0ad275.webp" width="50%"/>
> រូបភាពដោយអ្នកនិពន្ធ
ទោះយ៉ាងណា អ្នកប្រើប្រាស់អាចផ្តល់ប៉ារ៉ាម៉ែត្រមួយចំនួនជា​ផ្នែកមួយនៃប្រយោគ។ ឧទាហរណ៍ ពេលសួរអំពីអាកាសធាតុ នាងអាចបញ្ជាក់ទីកន្លែង ឬកាលបរិច្ឆេទ។ បន្ទាប់មក កម្មវិធីជជែកគួរតែនឹងយល់អង្គភាពទាំងនោះ ហើយបំពេញទីកន្លែងប៉ារ៉ាម៉ែត្រឲ្យត្រឹមត្រូវ មុនពេលអនុវត្តសកម្មភាព។ នេះគឺជាកន្លែងដែល NER ពេញនិយម។
> ✅ ឧទាហរណ៍មួយទៀតនឹងជា [វិភាគអត្ថបទវេជ្ជសាស្ត្រអំពីវិទ្យាសាស្ត្រ](https://soshnikov.com/science/analyzing-medical-papers-with-azure-and-text-analytics-for-health/). អ្វីដែលយើងត្រូវតែរកមើលជាចម្បងគឺវាក្នុងពាក្យវេជ្ជសាស្ត្រជាក់លាក់ ដូចជាជម្ងឺ និងសារធាតុវេជ្ជសាស្ត្រ។ ទោះបីជាជម្ងឺតិចតួចមួយចំនួនអាចដកយកដោយការស្វែងរកស៊ួរង់ ខ្សែដែលស្មុគស្មាញជាងនេះ ដូចជា សមាសធាតុគីមី និងឈ្មោះថ្នាំ គឺត្រូវការដំណើរការសំបូរបែបជាងនេះ។
## NER ជាផ្នែកនៃការចាត់ថ្នាក់តូកិន
ម៉ូដែល NER គឺជា **ម៉ូដែលចាត់ថ្នាក់តូកិន** ដោយសារត្រូវការប្រាប់ជូនសម្រាប់តូកិននីមួយៗថា តើវាចូលក្នុងអង្គភាពមួយឬទេ ហើយបើចូល តើវា​ជាក្រុមអង្គភាពណា។
លើកយកចំណងជើងអត្ថបទជាតិដូចខាងក្រោម៖
**ការស្រែកត្រឡប់សន្ទះ៣ ត្រីវិទ្យា** និង **ថ្នាំលីទីយ៉ំខ៉ាប៉ូនាត** **ជម្ងឺពុលភាព** នៅក្នុងទារកកើតថ្មីមួយ។
អង្គភាពនៅទីនេះមានៈ
* ការស្រែកត្រឡប់សន្ទះ៣ ត្រីវិទ្យា ជាជម្ងឺ (`DIS`)
* ថ្នាំលីទីយ៉ំខ៉ាប៉ូនាត គឺជា សារធាតុខីមី (`CHEM`)
* ជម្ងឺពុលភាព គឺជាជម្ងឺផងដែរ (`DIS`)
ចំណាំថា អង្គភាពមួយអាចរំកិលបានច្រើនតូកិន។ ហើយ នៅក្នុងករណីនេះ ត្រូវការបំបែកចេញពីគ្នារវាងអង្គភាពពីរតាមលំដាប់ៗគ្នា។ ដូច្នេះ ស្គាល់ថា ត្រូវប្រើពីរប្រភេទថ្នាក់សម្រាប់អង្គភាពមួយ មួយសំរាប់តូកិនដំបូងនៃអង្គភាព (​ជាញឹកញាប់ប្រើ `B-` សម្រាប់ **b**eginning) និងមួយទៀតសំរាប់តូកិនបន្តនៃអង្គភាព (`I-`, សំរាប់ **i**nner token)។ យើងក៏ប្រើ `O` ដើម្បីសំដែងថាតូកិននោះគឺជា តូកិន **ប**ានផ្សេងទៀត។ វិធីស្វែងរកតូកិនដូចនេះហៅថា [ការតាមដាន BIO](https://en.wikipedia.org/wiki/Inside%E2%80%93outside%E2%80%93beginning_(tagging)) (ឬ IOB)។ នៅពេលតាមដាន សៀវភៅចំណងជើងនេះនឹងមើលទៅដូចខាងក្រោម៖
Token | Tag
------|-----
Tricuspid | B-DIS
valve | I-DIS
regurgitation | I-DIS
and | O
lithium | B-CHEM
carbonate | I-CHEM
toxicity | B-DIS
in | O
a | O
newborn | O
infant | O
. | O
ដោយសារត្រូវការបង្កើតទំនាក់ទំនងមួយទៅមួយរវាងតូកិននិងថ្នាក់ យើងអាចបណ្តុះបណ្តាលម៉ូដែលប្រព័ន្ធប្រសាទ **many-to-many** នៅខាងស្ដាំដូចនៅក្នុងរូបភាពនេះ៖
![រូបភាពបង្ហាញបែបបទបណ្តាញប្រសាទប្រចាំមួយទូទៅ។](../../../../../translated_images/km/unreasonable-effectiveness-of-rnn.541ead816778f42d.webp)
> *រូបភាពពី [អត្ថបទប្លកនេះ](http://karpathy.github.io/2015/05/21/rnn-effectiveness/) ដោយ [Andrej Karpathy](http://karpathy.github.io/). ម៉ូដែលចាត់ថ្នាក់តូកិនរបស់ NER ត្រូវគ្នាជាមួយរចនាសម្ព័ន្ធបណ្តាញខាងស្ដាំបង្ហាញក្នុងរូបនេះ។*
## បណ្ដុះបណ្ដាលម៉ូដែល NER
ដោយសារថាម៉ូដែល NER ជាម៉ូដែលចាត់ថ្នាក់តូកិន យើងអាចប្រើប្រាស់ RNNs ដែលយើងស្គាល់សម្រាប់ភារកិច្ចនេះ។ ក្នុងករណីនេះ ប្លុកនីមួយៗនៃបណ្តាញប្រសាទប្រចាំនឹងបញ្ចូលលេខសម្គាល់តូកិន។ សៀវភៅកំណត់ត្រាឧទាហរណ៍ក្រោមបង្ហាញពីរបៀបបណ្តុះ LSTM សម្រាប់ចាត់ថ្នាក់តូកិន។
## ✍️ សៀវភៅកំណត់ត្រាឧទាហរណ៍៖ NER
បន្តការសិក្សារបស់អ្នកនៅក្នុងសៀវភៅកំណត់ត្រាខាងក្រោម៖
* [NER ជាមួយ TensorFlow](NER-TF.ipynb)
## សេចក្ដីសន្និដ្ឋាន
ម៉ូដែល NER គឺជាម៉ូដែល **ចាត់ថ្នាក់តូកិន** ដែលមានន័យថាវាអាចប្រើដើម្បីអនុវត្តការចាត់ថ្នាក់តូកិន។ នេះជាភារកិច្ចធម្មតាមួយក្នុង NLP ជួយឲ្យទទួលស្គាល់អង្គភាពជាក់លាក់នៅក្នុងអត្ថបទ រួមមានទីកន្លែង ឈ្មោះ កាលបរិច្ឆេទ និងផ្សេងៗទៀត។
## 🚀 ការប្រកួតប្រជែង
បញ្ចប់ការងារដែលភ្ជាប់នៅខាងក្រោមដើម្បីបណ្តុះបណ្តាលម៉ូដែលទទួលស្គាល់អង្គភាពមានឈ្មោះសម្រាប់ពាក្យវេជ្ជសាស្ត្រ បន្ទាប់មកសាកល្បងវាជាមួយឯកសារទិន្នន័យផ្សេងទៀត។
## [វីរុសសំណួរបន្ទាប់ពីមេរៀន](https://ff-quizzes.netlify.app/en/ai/quiz/38)
## សេចក្ដីពិនិត្យ និងការសិក្សាផ្ទាល់ខ្លួន
អានតាមអត្ថបទប្លក [The Unreasonable Effectiveness of Recurrent Neural Networks](http://karpathy.github.io/2015/05/21/rnn-effectiveness/) ហើយតាមដានផ្នែកសិក្សបន្ថែមក្នុងអត្ថបទនោះដើម្បីពង្រីកចំណេះដឹងរបស់អ្នក។
## [ការងារ](lab/README.md)
ក្នុងការងារសម្រាប់មេរៀននេះ អ្នកត្រូវតែបណ្តុះបណ្តាលម៉ូដែលទទួលស្គាល់អង្គភាពវេជ្ជសាស្ត្រ។ អ្នកអាចចាប់ផ្តើមពីការបណ្តុះម៉ូដែល LSTM ដដែលណែនាំក្នុងមេរៀននេះ ហើយបន្តធ្វើការប្រើម៉ូដែលបំលែង BERT ។ អាន [ការណែនាំ](lab/README.md) ដើម្បីទទួលបានព័ត៌មានលម្អិតទាំងអស់។
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការបដិសេធ**៖
ឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator) ។ ខណៈពេលដែលយើងខំប្រឹងបំផុតសម្រាប់ភាពត្រឹមត្រូវ សូមយកចិត្តទុកដាក់ថាការបកប្រែដោយស្វ័យប្រវត្តិអាចមានកំហុសឬភាពមិនត្រឹមត្រូវ។ ឯកសារដើមដោយភាសាមូលដ្ឋានគួរត្រូវបានគេចាត់ទុកជាដើមដៃគូនៅស្រទាប់បរិយាយ។ សម្រាប់ព័ត៌មានសំខាន់ៗ យើងផ្តល់អនុសាសន៍ឱ្យមានការបកប្រែក្នុងភាសាដោយអ្នកជំនាញមនុស្ស។ យើងុំទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកប្រែខុសពីការប្រើប្រាស់ការបកប្រែនេះ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,54 @@
# NER
ការប្រឡងមួយពី [កម្មវិធីសិក្សា AI សម្រាប់អ្នកចាប់ផ្តើម](https://github.com/microsoft/ai-for-beginners)។
## បេសកកម្ម
ក្នុងការប្រឡងនេះ អ្នកត្រូវតែបណ្តុះបណ្តាលម៉ូដែលសម្គាល់អង្គភាពដែលមានឈ្មោះសម្រាប់ពាក្យវេជ្ជសាស្រ្ត។
## ឈុតទិន្នន័យ
ដើម្បីបណ្តុះម៉ូដែល NER អ្នកត្រូវការឈុតទិន្នន័យដែលបានស្លាកសញ្ញាត្រឹមត្រូវជាមួយអង្គភាពវេជ្ជសាស្រ្ត។ [ឈុតទិន្នន័យ BC5CDR](https://biocreative.bioinformatics.udel.edu/tasks/biocreative-v/track-3-cdr/) មានអង្គភាពជំងឺ និងគីមីទិន្នន័យដែលបានស្លាកពីស្នាដៃច្រើនជាង ១៥០០។ អ្នកអាចទាញយកឈុតទិន្នន័យបន្ទាប់ពីចុះឈ្មោះនៅគេហទំព័ររបស់ពួកគេ។
ឈុតទិន្នន័យ BC5CDR មើលទៅដូចនេះ៖
```
6794356|t|Tricuspid valve regurgitation and lithium carbonate toxicity in a newborn infant.
6794356|a|A newborn with massive tricuspid regurgitation, atrial flutter, congestive heart failure, and a high serum lithium level is described. This is the first patient to initially manifest tricuspid regurgitation and atrial flutter, and the 11th described patient with cardiac disease among infants exposed to lithium compounds in the first trimester of pregnancy. Sixty-three percent of these infants had tricuspid valve involvement. Lithium carbonate may be a factor in the increasing incidence of congenital heart disease when taken during early pregnancy. It also causes neurologic depression, cyanosis, and cardiac arrhythmia when consumed prior to delivery.
6794356 0 29 Tricuspid valve regurgitation Disease D014262
6794356 34 51 lithium carbonate Chemical D016651
6794356 52 60 toxicity Disease D064420
...
```
ក្នុងឈុតទិន្នន័យនេះ មានចំណងជើង និងសេចក្ដីសង្ខេបកាស្នាដៃក្នុងបន្ទាត់ពីរដំបូង ហើយបន្ទាប់មក មានអង្គភាពឯករាជ្យៗ ជាមួយនិងទីតាំងចាប់ផ្ដើម និងធ្វើបញ្ចប់នៅក្នុងប្លុកចំណងជើង+សេចក្ដីសង្ខេប។ បន្ថែមពីនេះ លើសពីប្រភេទអង្គភាព អ្នកនឹងទទួលបានអត្តសញ្ញាណនិមិត្តរបស់អង្គភាពនេះក្នុងរាងវេជ្ជសាស្រ្តមួយ។
អ្នកត្រូវតែសរសេរកូដ Python ខ្លះ ដើម្បីបម្លែងអត្ថបទនេះទៅជា encoding BIO។
## បណ្តាញ
ការព្យាយាមដំបូងសម្រាប់ NER អាចធ្វើបានដោយប្រើបណ្តាញ LSTM ដូចដែលអ្នកបានឃើញក្នុងឧទាហរណ៍នៅក្នុងមេរៀន។ ទោះជាយ៉ាងណាក៏ដោយ នៅក្នុងភារកិច្ច NLP [រចនាសម្ព័ន្ធ transformer](https://en.wikipedia.org/wiki/Transformer_(machine_learning_model)) និងជាទូទៅ [ម៉ូដែលភាសា BERT](https://en.wikipedia.org/wiki/BERT_(language_model)) បង្ហាញលទ្ធផលល្អជាងគេ។ ម៉ូដែល BERT ដែលបានបណ្តុះមកហើយយូរប្រែប្រួលយល់ដឹងពីរចនាសម្ព័ន្ធទូទៅនៃភាសា ហើយអាចធ្វើការកែប្រែត្រៀមសម្រាប់ភារកិច្ចជាក់លាក់ជាមួយឈុតទិន្នន័យតូច និងការចំណាយគណនាប្រសើរ។
ដោយសារយើងកំពុងផែនការដើម្បីអនុវត្ត NER ទៅលើស្ថានการณ์វេជ្ជសាស្រ្ត វាមានហេតុផលផ្តល់អត្ថប្រយោជន៍ក្នុងការប្រើម៉ូដែល BERT ដែលបានបណ្តុះលើអត្ថបទវេជ្ជសាស្រ្ត។ ការស្រាវជ្រាវ Microsoft បានចេញផ្សាយម៉ូដែលដែលបានបណ្តុះមួយឈ្មោះ [PubMedBERT][PubMedBERT] ([ការចេញផ្សាយ][PubMedBERT-Pub]) ដែលបានកែប្រែបន្ថែមដោយប្រើអត្ថបទពីឃ្លាំង [PubMed](https://pubmed.ncbi.nlm.nih.gov/)។
ស្តង់ដារដែលពេញនិយមសម្រាប់បណ្ដុះម៉ូដែល transformer គឺបណ្ណាល័យ [Hugging Face Transformers](https://huggingface.co/)។ វានៅក្នុងនោះមានឃ្លាំងនៃម៉ូដែលដែលបានបណ្តុះដោយសហគមន៍រួមទាំង PubMedBERT។ ដើម្បីបង្ហោះ និងប្រើម៉ូដែលនេះ អ្នកគ្រាន់តែត្រូវតែមានបន្ទាត់កូដពីរបីប៉ុណ្ណោះ៖
```python
model_name = "microsoft/BiomedNLP-PubMedBERT-base-uncased-abstract"
classes = ... # ចំនួនថ្នាក់៖ 2*អង្គភាព+1
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = BertForTokenClassification.from_pretrained(model_name, classes)
```
នេះផ្តល់ឲ្យយើង `model` មួយ ដែលបង្កើតសម្រាប់ភារកិច្ចកំណត់ប្រភេទ token ជាមួយ និងចំនួន `classes` និងវត្ថុ `tokenizer` ដែលអាចបំបែកអត្ថបទបញ្ចូលទៅជាកំណត់ត្រា។ អ្នកត្រូវបម្លែងឈុតទិន្នន័យទៅជា BIO ទ្រង់ទ្រាយដោយគិតគូរពី tokenization របស់ PubMedBERT។ អ្នកអាចប្រើ [កូដ Python នេះ](https://gist.github.com/shwars/580b55684be3328eb39ecf01b9cbbd88) ជាការប្រមូលចំណេះដឹង។
## ជំហានក្រោយ
ភារកិច្ចនេះជិតស្និទ្ធជាមួយភារកិច្ចពិតប្រាកដដែលអ្នកអាចមាន ប្រសិនបើអ្នកចង់ទទួលបានការយល់ដឹងបន្ថែមពីអត្ថបទភាសាធម្មជាតិនៅចំណុះធំ។ នៅករណីរបស់យើង អ្នកអាចអនុវត្តម៉ូដែលដែលបានបណ្តុះទៅលើ [ឈុតទិន្នន័យស្នាដៃ COVID-19](https://www.kaggle.com/allen-institute-for-ai/CORD-19-research-challenge) ហើយមើលថាតើយើងអាចទទួលបានការយល់ដឹងអ្វីខ្លះ។ [អត្ថបទប្លុកនេះ](https://soshnikov.com/science/analyzing-medical-papers-with-azure-and-text-analytics-for-health/) និង [សៀវភៅនេះ](https://www.mdpi.com/2504-2289/6/1/4) ពិពណ៌នាអំពីការស្រាវជ្រាវដែលអាចធ្វើបានលើឯកសារស្នាដៃនេះដោយប្រើ NER។
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការបដិសេធ**៖
ឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ នៅពេលដែលយើងខិតខំប្រឹងប្រែងដើម្បីឱ្យបានភាពត្រឹមត្រូវ សូមដឹងថាការបកប្រែដោយស្វ័យប្រវត្តិអាចមានកំហុសឬភាពមិនត្រឹមត្រូវទៅវិញ។ ឯកសារដើមក្នុងភាសាដើមគួរត្រូវបានពិចារណាថាជាអ្នកផ្គត់ផ្គង់ព័ត៌មានផ្លូវការជាចម្បង។ សម្រាប់ព័ត៌មានសំខាន់ៗ ការបកប្រែដោយអ្នកជំនាញមនុស្សគឺត្រូវបានណែនាំ។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកស្រាយមិនត្រឹមត្រូវណាមួយដែលកើតឡើងដោយសារការប្រើប្រាស់ការបកប្រែនេះឡើយ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,319 @@
{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## ពិសោធន៍ជាមួយ OpenAI GPT\n",
"\n",
"កំណត់ត្រានេះគឺជាផ្នែកមួយនៃ [មុខងារ AI សម្រាប់អ្នកចាប់ផ្តើម](http://aka.ms/ai-beginners)។\n",
"\n",
"ក្នុងកំណត់ត្រានេះ យើងនឹងស្វែងយល់ពីរបៀបដែលយើងអាចលេងជាមួយម៉ូដែល OpenAI-GPT ដោយប្រើបណ្ណាល័យ Hugging Face `transformers`។\n",
"\n",
"គ្មានការពន្យារពេលខ្លីទៀតទេ ចូរបង្កើតច្រកចេញអត្ថបទហើយចាប់ផ្តើមបង្កើត!\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"c:\\Users\\bethanycheum\\Desktop\\AI-For-Beginners\\.venv\\lib\\site-packages\\tqdm\\auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
" from .autonotebook import tqdm as notebook_tqdm\n",
"Downloading model.safetensors: 100%|██████████| 479M/479M [04:28<00:00, 1.78MB/s] \n",
"c:\\Users\\bethanycheum\\Desktop\\AI-For-Beginners\\.venv\\lib\\site-packages\\huggingface_hub\\file_download.py:133: UserWarning: `huggingface_hub` cache-system uses symlinks by default to efficiently store duplicated files but your machine does not support them in C:\\Users\\bethanycheum\\.cache\\huggingface\\hub. Caching files will still work but in a degraded version that might require more space on your disk. This warning can be disabled by setting the `HF_HUB_DISABLE_SYMLINKS_WARNING` environment variable. For more details, see https://huggingface.co/docs/huggingface_hub/how-to-cache#limitations.\n",
"To support symlinks on Windows, you either need to activate Developer Mode or to run Python as an administrator. In order to see activate developer mode, see this article: https://docs.microsoft.com/en-us/windows/apps/get-started/enable-your-device-for-development\n",
" warnings.warn(message)\n",
"Some weights of OpenAIGPTLMHeadModel were not initialized from the model checkpoint at openai-gpt and are newly initialized: ['position_ids']\n",
"You should probably TRAIN this model on a down-stream task to be able to use it for predictions and inference.\n",
"Downloading (…)neration_config.json: 100%|██████████| 74.0/74.0 [00:00<00:00, 48.8kB/s]\n",
"Downloading (…)olve/main/vocab.json: 100%|██████████| 816k/816k [00:00<00:00, 1.76MB/s]\n",
"Downloading (…)olve/main/merges.txt: 100%|██████████| 458k/458k [00:00<00:00, 1.11MB/s]\n",
"Downloading (…)/main/tokenizer.json: 100%|██████████| 1.27M/1.27M [00:00<00:00, 2.12MB/s]\n",
"Xformers is not installed correctly. If you want to use memory_efficient_attention to accelerate training use the following command to install Xformers\n",
"pip install xformers.\n"
]
},
{
"data": {
"text/plain": [
"[{'generated_text': \"Hello! I am a neural network, and I want to say that i apologize for not coming to you yourself, for not helping you, and that i was too busy getting dressed and studying for a midterm. you know, the kind where the teachers are like that and they come in pairs with their boyfriends, but not with theirs. it's true, that i have had a girlfriend, and i'm only going on wednesdays and thursdays because i was too busy with college, but maybe\"},\n",
" {'generated_text': 'Hello! I am a neural network, and I want to say that we have been blessed with a wonderful gift ; no one of us has died at all. and our spirits are strong, very strong. in one very lucky moment of luck for you, all has been given direction and destiny, and for us there are no more mysteries. the earth has been chosen for you, and that earth is now ours, and you must be forever in our hearts. \" \\n the words, as one,'},\n",
" {'generated_text': 'Hello! I am a neural network, and I want to say that if you would just turn and face the general, you would have a nice day. \" \\n \" sure thing, \" said one of the soldiers, and started to run. the rest of the soldiers followed, shouting. the general turned to general zulu, raising his arm. the general said something in his native language, and the general immediately started to run. zulu started to move toward the wall, with the'},\n",
" {'generated_text': 'Hello! I am a neural network, and I want to say that i am not a doctor but an anthropologist to you, a specialist, a specialist in the field of astrobiological biology, and that i am very much involved in this investigation. i am not sure, i am not certain, but i can confirm your conclusions and therefore i will go to the top. i have a colleague who has just returned from this expedition and his findings confirm that you are a specialist. that is, he'},\n",
" {'generated_text': \"Hello! I am a neural network, and I want to say that everyone here is in agreement that no matter how many times i say to myself,'he was never a man of action on the battlefield,'or'he 'll never take a chance at killing any civilians,'or'he 'll never let his men go undefended against enemy forces of this caliber,'or'that's just what i need in a day like today. \\n you see, there are only three groups that\"}]"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from transformers import pipeline\n",
"\n",
"model_name = 'openai-gpt' \n",
"\n",
"generator = pipeline('text-generation', model=model_name)\n",
"\n",
"generator(\"Hello! I am a neural network, and I want to say that\", max_length=100, num_return_sequences=5)\n"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## ការធ្វើឲ្យកំណត់បញ្ហា (Prompt Engineering)\n",
"\n",
"ក្នុងបញ្ហាខ្លះៗ អ្នកអាចប្រើការបង្កើត openai-gpt តាមបំណងភ្លាមៗដោយរចនាកំណត់បញ្ហាឲ្យត្រឹមត្រូវ។ សូមមើលឧទាហរណ៍ខាងក្រោម៖\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[{'generated_text': 'Synonyms of a word cat: the same cat i used to stare at, and you in'},\n",
" {'generated_text': 'Synonyms of a word cat: cat of the woods, cat of the hills, cat of'},\n",
" {'generated_text': 'Synonyms of a word cat: you! \\n \" it\\'s a girl. \" i said'},\n",
" {'generated_text': \"Synonyms of a word cat: big cat. but how come, we didn't hear it\"},\n",
" {'generated_text': 'Synonyms of a word cat: \" mea - o - c \" which makes them sound'}]"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"generator(\"Synonyms of a word cat:\", max_length=20, num_return_sequences=5)"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[{'generated_text': 'I love when you say this -> Positive\\nI have myself -> Negative\\nThis is awful for you to say this -> positive this is so horrible - > positive that your brother is gay - >'},\n",
" {'generated_text': 'I love when you say this -> Positive\\nI have myself -> Negative\\nThis is awful for you to say this -> negative i will bring this on you -, < positive am i, i'},\n",
" {'generated_text': 'I love when you say this -> Positive\\nI have myself -> Negative\\nThis is awful for you to say this -> negative i have self - esteem i must take it - : \\n - -'},\n",
" {'generated_text': 'I love when you say this -> Positive\\nI have myself -> Negative\\nThis is awful for you to say this -> negative this is - : \\n if it were true that the devil would have'},\n",
" {'generated_text': \"I love when you say this -> Positive\\nI have myself -> Negative\\nThis is awful for you to say this -> positive i have you - > positive it's a bad thing, > positive\"}]"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"generator(\"I love when you say this -> Positive\\nI have myself -> Negative\\nThis is awful for you to say this ->\", max_length=40, num_return_sequences=5)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[{'generated_text': 'Translate English to French: cat => chat, dog => chien, student => new and unusual. there were no more words to be'},\n",
" {'generated_text': 'Translate English to French: cat => chat, dog => chien, student => student \\n his eyes were huge in his lean face as'},\n",
" {'generated_text': \"Translate English to French: cat => chat, dog => chien, student => the teacher's words, their words, their words.\"}]"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"generator(\"Translate English to French: cat => chat, dog => chien, student => \", top_k=50, max_length=30, num_return_sequences=3)"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[{'generated_text': 'People who liked the movie The Matrix also liked it, and there was the movie of the first man after us. \\n i wanted to laugh at how stupid these stupid actors were. no, they were'},\n",
" {'generated_text': \"People who liked the movie The Matrix also liked the movie, and the film was the result. and that's when the man in the story was brought into reality, after a few decades. \\n a\"},\n",
" {'generated_text': 'People who liked the movie The Matrix also liked the movie the matrix, because there was a very old movie movie called the matrix, where there was a great super hero, and the super hero came out'},\n",
" {'generated_text': \"People who liked the movie The Matrix also liked the movie that didn't have a chance to pay cash, if they could afford it. most often they got a good deal and a lot of money,\"},\n",
" {'generated_text': \"People who liked the movie The Matrix also liked the movie, and i didn't seem to have the same problem. \\n i 'd met the other half of my family. i spent most of my time\"}]"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"generator(\"People who liked the movie The Matrix also liked \", max_length=40, num_return_sequences=5)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## estratégiés validasi téks\n",
"\n",
"Sak punaneh sampun nganggé strategi sampling **tamak** sing sederhana, nalika milih tembung sabanjuré adhedhasar kamungkinan paling dhuwur. Iki carane bisa digunakake:\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[{'generated_text': 'It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw my friend, a young man, sprawled across the bed in his bed. \\n \" hi, i\\'m mike eptirard. \" \\n there was silence on the other side of the door. i listened for any trace of life but there was nothing. my heart began to pound, i was starting to sweat, i took out my wallet'},\n",
" {'generated_text': 'It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw my mother on the bed, hugging her legs to her chest and sobbing. i saw my dad and mother from the corner of my eye. \\n elfin face was covered in tears as i entered the room. my dad and mother also wept ; just as they did every other time i came to work. but this time, they had different faces'},\n",
" {'generated_text': 'It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw the room had changed because it was dark. it still smelled like a hospital. a new light shined through from a vent in the ceiling. i found myself in a bathroom and a small room with a sink and a wall of glass. the bathroom billion years ago. not so different from all of the rest of the apartment. \\n now...'},\n",
" {'generated_text': 'It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw a large woman with dark hair and pale skin. she was asleep, but i noticed a faint movement of her face. i could sense she was awake. i got up and walked over to her. \\n \" hello miss. i am inspector michael o\\'dell ; we are investigating the case against you. i wanted to ask if you were the'},\n",
" {'generated_text': 'It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw i had an empty table and three empty chairs. that was all i needed. i had left a note on a table in the center of the room and had a pen in hand. \" \\n \" i think what you were doing was something he was doing to her. \" \\n \" yeah, \" i nodded with a grin. \" i'}]"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"prompt = \"It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw\"\n",
"generator(prompt,max_length=100,num_return_sequences=5)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**ការស្វែងរកជ្រីវជ្រៅ** អនុញ្ញាតឱ្យម៉ាស៊ីនបង្កើតអាចស្វែងរកមុខងារជាច្រើន (*ជ្រីវជ្រៅ*) នៃការបង្កើតអត្ថបទ ហើយជ្រើសរើសនូវមុខងារដែលមានពិន្ទុសរុបខ្ពស់ជាងគេ។ អ្នកអាចធ្វើការស្វែងរកជ្រីវជ្រៅបានដោយផ្តល់ប៉ារ៉ាម៉ែត្រ `num_beams`។ អ្នកក៏អាចបញ្ជាក់ `no_repeat_ngram_size` ដើម្បីទប់ស្កាត់ម៉ូដែលមិនឲ្យមានការកោរសម្ដីនៃ n-grams ដែលមានទំហំជាក់លាក់។\n"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[{'generated_text': 'It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw a man sitting in a chair with his head in his hands. he didn\\'t look up as i approached. \\n \" excuse me, sir, \" i said. \" can i help you? \" \\n the man looked up at me. his eyes were red - rimmed and his face was pale, as if he hadn\\'t slept in days'},\n",
" {'generated_text': 'It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw a man sitting at a desk in the middle of the room. he had his back to me, so i couldn\\'t see what he was doing. \" \\n \" what did he look like? \" i asked as i sat down on the bed next to her. \\n she took a deep breath and looked at me with tears in her eyes'},\n",
" {'generated_text': 'It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw a woman sitting on the bed, reading a book. she looked up at me and smiled. \\n \" hi, \" she said. \" can i help you? \" \\n i sat down next to her and looked around the room. the walls were white, and there was a large window in the middle of the wall that looked out on'},\n",
" {'generated_text': 'It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw a man sitting at a table in the middle of the room. he looked up as i walked in, and when he saw me, he got up and walked over to me. \\n \" can i help you? \" he asked as he put his hand on the small of my back and led me to a chair at the other end of'},\n",
" {'generated_text': 'It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw a woman sitting on the edge of her bed, reading a book. she looked up at me and smiled. \\n \" hello, \" she said. \" can i help you? \" \\n i didn\\'t know what to say, so i just sat down in the chair next to the bed and looked at her. her hair was dark brown'}]"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"prompt = \"It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw\"\n",
"generator(prompt,max_length=100,num_return_sequences=5,num_beams=10,no_repeat_ngram_size=2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**ស្តាប់រ نمونه** ជ្រើសពាក្យបន្ទាប់ដោយមិនកំណត់ជាក់លាក់ ដោយប្រើចែកចាយប្រព័ន្ធប្រយោលដែលបានបញ្ជូនត្រឡប់មកដោយម៉ូឌែល។ អ្នកបើកស្តាប់រ نمونه ដោយប្រើប៉ារ៉ាម៉ែត្រ `do_sample=True`។ អ្នកក៏អាចកំណត់ `temperature` ដើម្បីធ្វើឱ្យម៉ូឌែលកាន់តែមានកម្រិតកំណត់កម្រិតច្រើន ឬតិច។\n"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[{'generated_text': 'It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw her. she was on the bed, but she looked very different. \\n \" honey, what\\'s the matter? \" i asked. \\n she sat up. \" i can\\'t believe it\\'s real. i\\'ve been dreaming about you for the last two days. \" \\n \" i can\\'t believe it either. i guess that\\'s how'}]"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"prompt = \"It was early evening when I can back from work. I usually work late, but this time it was an exception. When I entered a room, I saw\"\n",
"generator(prompt,max_length=100,do_sample=True,temperature=0.8)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"យើងក៏អាចផ្តល់ប៉ារ៉ាម៉ែត្របន្ថែមទៀតសម្រាប់ការគំរូបានផងដែរ៖\n",
"* `top_k` បញ្ជាក់ចំនួនជម្រើសពាក្យដែលត្រូវពិចារណា ពេលប្រើការគំរូ។ វាជួយបន្ថយឱកាសក្នុងការទទួលបានពាក្យអស្ចារ្យ (ដែលមានប្រជាប្រិយភាពទាប) នៅក្នុងអត្ថបទរបស់យើង។\n",
"* `top_p` គឺស្រដៀងគ្នា ប៉ុន្តែយើងជ្រើសរើសឱ្យតូចជាងគេនៅក្នុងសំណុំបំបែកពាក្យដែលមានប្រជាប្រិយភាពខ្ពស់បំផុត ដោយសរុបប្រហែលមានប្រជាប្រិយភាពធំជាង p។\n",
"\n",
"សូមស្វាគមន៍ការសាកល្បងជាមួយការបញ្ជូលប៉ារ៉ាម៉ែត្រទាំងនោះ។\n"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## ការតំរូវបន្ថែមម៉ូឌែលរបស់អ្នក\n",
"\n",
"អ្នកអាច [តំរូវបន្ថែមម៉ូឌែលរបស់អ្នក](https://learn.microsoft.com/en-us/azure/cognitive-services/openai/how-to/fine-tuning?pivots=programming-language-studio?WT.mc_id=academic-77998-bethanycheum) លើសំណុំនៃទិន្នន័យផ្ទាល់ខ្លួនរបស់អ្នក។ នេះនឹងអនុញ្ញាតឱ្យអ្នកកំណត់រចនាប័ទ្មអក្សរបាន ខណៈដែលរក្សាផ្នែកសំខាន់នៃម៉ូឌែលភាសា។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**ការព្រមាន**៖ \nឯកសារនេះត្រូវបានបម្លែងជាភាសាផ្សេងដោយប្រើសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេលដែលយើងខិតខំប្រឹងប្រែងដើម្បីភាពត្រឹមត្រូវ សូមយល់ថាការបកប្រែដោយស្វ័យប្រវត្តិអាចមានកំហុស ឬភាពមិនច្បាស់លាស់ផងបាន។ ឯកសារដើមនៅជាភាសាមាតុភូមិគួរត្រូវបានទិត្តធ្វើជាមូលដ្ឋានចម្បង។ សម្រាប់ព័ត៌មានសំខាន់ គេណែនាំឲ្យប្រើប្រាស់ការបកប្រែដោយមនុស្សជំនាញ។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកប្រែដែលមិនត្រឹមត្រូវណាមួយដែលកើតមានពីការប្រើប្រាស់ការបកប្រែនេះឡើយ។\n<!-- CO-OP TRANSLATOR DISCLAIMER END -->\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "16af2a8bbb083ea23e5e41c7f5787656b2ce26968575d8763f2c4b17f9cd711f"
},
"kernelspec": {
"display_name": "Python 3.8.12 ('py38')",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.11"
},
"orig_nbformat": 4
},
"nbformat": 4,
"nbformat_minor": 2
}

View File

@ -0,0 +1,59 @@
# ម៉ូដែលភាសាច្រើនទំហំធំដែលបានបណ្ដុះស្រាប់
ក្នុងកិច្ចការមុនៗទាំងអស់របស់យើង យើងបានបណ្ដុះបណ្ដាលបណ្តាញសរសៃប្រព័ន្ធប្រព័ន្ធប្រព័ន្ធកណ្តាលដើម្បីអនុវត្តន៍កិច្ចការមួយជាមួយគ្រឿងទិន្នន័យដែលបានស្លាក។ ជាមួយម៉ូដែលបំលែងធំៗ ដូចជា BERT យើងប្រើការមូដែលភាសាក្នុងរបៀបផ្ទាល់ខ្លួនដោយខ្លួនឯងដើម្បីបង្កើតម៉ូដែលភាសា ដែលបន្ទាប់មកត្រូវបានជំនាញសម្រាប់កិច្ចការចុះក្រោមជាក់លាក់ដោយបណ្ដុះបណ្ដាលសម្រាប់វាលជាក់លាក់បន្ថែមទៀត។ ទោះបីយ៉ាងណា មានការបង្ហាញថា ម៉ូដែលភាសាធំៗអាចដោះស្រាយកិច្ចការច្រើនប្រភេទដោយគ្មានការបណ្ដុះបណ្ដាលសម្រាប់វាលជាក់លាក់ណាមួយ។ គ្រួសារម៉ូដែលដែលមានសមត្ថភាពធ្វើបានបែបនេះគឺហៅថា **GPT**: Generative Pre-Trained Transformer។
## [កម្រងសំណួរមុនបង្រៀន](https://ff-quizzes.netlify.app/en/ai/quiz/39)
## ការបង្កើតអត្ថបទ និង Perplexity
គំនិតនៃបណ្តាញសរសៃប្រព័ន្ធអាចអនុវត្តកិច្ចការទូទៅដោយគ្មានការបណ្ដុះបណ្ដាលក្រោយត្រូវបានបង្ហាញក្នុងឯកសារ [Language Models are Unsupervised Multitask Learners](https://cdn.openai.com/better-language-models/language_models_are_unsupervised_multitask_learners.pdf)។ គំនិតចម្បងគឺកិច្ចការច្រើនផ្សេងទៀតអាចត្រូវបានម៉ូដែលដោយប្រើ **ការបង្កើតអត្ថបទ** ពីព្រោះការយល់ដឹងអត្ថបទមានន័យថាអាចផលិតវាបាន។ ពីព្រោះម៉ូដែលត្រូវបានបណ្ដុះបណ្ដាលលើអត្ថបទជាច្រើនដ៏ធំ ដែលរួមបញ្ចូលចំណេះដឹងរបស់មនុស្ស វាក៏ក្លាយជាមានចំណេះដឹងពីប្រធានបទជាច្រើនផងដែរ។
> ការយល់ដឹង និងអាចផលិតអត្ថបទក៏មានន័យថាត្រូវដឹងអ្វីៗកុំផ្លែកពីពិភពដែលនៅជុំវិញយើងផងដែរ។ មនុស្សក៏រៀនតាមរយៈការអានដល់កម្រិតធំជាថ្មីៗ ហើយបណ្តាញ GPT គឺដូចជានោះផងដែរ។
បណ្តាញបង្កើតអត្ថបទដំណើរការតាមរយៈការទស្សនាព្រោងនៃពាក្យបន្ទាប់ $$P(w_N)$$ ប៉ុន្តែ ចំណុចកំណត់អន្យាក្នុងការទស្សនាព្រោងនៃពាក្យបន្ទាប់ដូចជាប្រសាររបស់ពាក្យនេះក្នុងអត្ថបទ។ GPT អាចផ្ដល់ឱ្យយើង **ចំណុចកំណត់ក្នុងការទស្សនាព្រោង** នៃពាក្យបន្ទាប់ ដែលមានលក្ខខណ្ឌដោយពាក្យមុនៗ: $$P(w_N | w_{n-1}, ..., w_0)$$
> អ្នកអាចអានបន្ថែមអំពីចំណុចកំណត់ក្នុងការទស្សនាព្រោងក្នុង [កម្មវិធីសិក្សាពត៌មានវិទ្យាសម្រាប់អ្នកចាប់ផ្តើម](https://github.com/microsoft/Data-Science-For-Beginners/tree/main/1-Introduction/04-stats-and-probability)
គុណភាពនៃម៉ូដែលបង្កើតភាសាអាចកំណត់ដោយប្រើ **perplexity**។ វាជាមេត្រដែលមានលក្ខណៈផ្ទាល់ខ្លួនដែលអនុញ្ញាតឲ្យយើងវាស់បានគុណភាពម៉ូដែលដោយគ្មានគ្រឿងទិន្នន័យសម្រាប់កិច្ចការជាក់លាក់ណាមួយ។ វាត្រូវបានគេពិចារណារក់នៅលើគំនិត *ចំណុចកំណត់នៃវាក្យបថ* - ម៉ូដែលផ្ដល់ចំណុចកំណត់ខ្ពស់ទៅវាក្យបថដែលមានសក្តានុពលដើម្បីជាការពិត (គឺម៉ូដែលមិន **ភ្ញាក់ផ្អើល** ពីវា), ហើយចំណុចកំណត់ទាបទៅវាក្យបថដែលមិនសមរម្យ (ឧ. *Can it does what?*)។ ពេលដែលយើងផ្ដល់ម៉ូដែលនូវវាក្យបថពីអត្ថបទពិត អ្នកនឹងរំពឹងថាវាត្រូវមានចំណុចកំណត់ខ្ពស់ និង **perplexity** ទាប។ ភាសាដោយគណិតវិទ្យា វាត្រូវបានកំណត់ជាចំនួនបំបែកក្រោមនៃចំណុចកំណត់ឧបករណ៍តេស្ត៖
$$
\mathrm{Perplexity}(W) = \sqrt[N]{1\over P(W_1,...,W_N)}
$$
**អ្នកអាចសាកល្បងបង្កើតអត្ថបទដោយប្រើ [កម្មវិធីកែសម្រួលអត្ថបទដែលដំណើរការជាមួយ GPT ពី Hugging Face](https://transformer.huggingface.co/doc/gpt2-large)**។ នៅក្នុងកម្មវិធីកែសម្រួលនេះ អ្នកចាប់ផ្តើមសរសេរអត្ថបទរបស់អ្នក ហើយចុច **[TAB]** នឹងផ្ដល់ជម្រើសបញ្ចប់ជាច្រើន។ ប្រសិនបើវាខ្លីពេក ឬអ្នកមិនពេញចិត្ត អ្នកអាចចុច [TAB] ម្តងទៀត ហើយអ្នកនឹងទទួលបានជម្រើសបន្ថែម រួមមានអត្ថបទវែងជាង។
## GPT គឺជាគ្រួសារ
GPT មិនមែនជាម៉ូដែលតែមួយទេ ប៉ុន្តែជាការប្រមូលផ្តុំម៉ូដែល ដែលបានអភិវឌ្ឍន៍ និងបណ្ដុះបណ្ដាលដោយ [OpenAI](https://openai.com)។
ក្រោមម៉ូដែល GPT យើងមាន៖
| [GPT-2](https://huggingface.co/docs/transformers/model_doc/gpt2#openai-gpt2) | [GPT 3](https://openai.com/research/language-models-are-few-shot-learners) | [GPT-4](https://openai.com/gpt-4) |
| -- | -- | -- |
| ម៉ូដែលភាសាមួយដែលមានរហូតដល់ 1.5 ពាន់លានពារ៉ាម៉ែត្រ។ | ម៉ូដែលភាសាមួយដែលមានរហូតដល់ 175 ពាន់លានពារ៉ាមែត្រ | 100T ពារ៉ាមែត្រ និងទទួលទ both រូបភាព និងអត្ថបទចូល និងបញ្ចេញអត្ថបទ។ |
ម៉ូដែល GPT-3 និង GPT-4 មានគ្រប់លក្ខណៈជាសេវាជំនាញខាងចំណេះដឹកដល់ផ្នែកចរិតពី Microsoft Azure ([source](https://azure.microsoft.com/en-us/services/cognitive-services/openai-service/#overview?WT.mc_id=academic-77998-cacaste)) និង [OpenAI API](https://openai.com/api/)។
## វិស្វកម្មបញ្ចូលសុវត្ថិភាព
ដោយសារតែ GPT ត្រូវបានបណ្ដុះបណ្ដាលលើទិន្នន័យជាច្រើនដើម្បីយល់ភាសា និងកូដ វាផ្ដល់លទ្ធផលឆ្លើយតបនឹងការបញ្ចូល (prompts)។ Prompts គឺជាការបញ្ចូល ឬ សំណួរដែលស្នើដល់ម៉ូដែលដើម្បីអនុវត្តកិច្ចការដែលអ្នកត្រូវការបន្ទាប់។ ដើម្បីទទួលបានលទ្ធផលដែលចង់បាន អ្នកត្រូវការបញ្ចូលជាដ៏មានប្រសិទ្ធភាពសម្រាប់ការជ្រើសរើសពាក្យទ្រឹងទ្រាយ ប្រយោគ ឬ សញ្ញា។ វិធីសាស្រ្តនេះហៅថា [វិស្វកម្មបញ្ចូល](https://learn.microsoft.com/en-us/shows/ai-show/the-basics-of-prompt-engineering-with-azure-openai-service?WT.mc_id=academic-77998-bethanycheum)។
[ឯកសារនេះ](https://learn.microsoft.com/en-us/semantic-kernel/prompt-engineering/?WT.mc_id=academic-77998-bethanycheum) ផ្ដល់ព័ត៌មានបន្ថែមអំពីវិស្វកម្មបញ្ចូល។
## ✍️ ឧទាហរណ៍កំណត់ត្រា៖ [លេងជាមួយ OpenAI-GPT](GPT-PyTorch.ipynb)
បន្តការសិក្សារបស់អ្នកក្នុងកំណត់ត្រាដូចខាងក្រោម៖
* [បង្កើតអត្ថបទជាមួយ OpenAI-GPT និង Hugging Face Transformers](GPT-PyTorch.ipynb)
## សេចក្ដីសន្និដ្ឋាន
ម៉ូដែលភាសាថ្មីទូទៅដែលបានបណ្ដុះស្រាប់ មិនត្រឹមតែម៉ូដែលរចនាសម្ព័ន្ធភាសាប៉ុណ្ណោះទេ តែថែមទាំងផ្ទុកចំណុចច្រើននៃភាសាប្រពៃណី។ ដូច្នេះវាអាចប្រើបានយ៉ាងមានប្រសិទ្ធភាពក្នុងការដោះស្រាយកិច្ចការផ្នែក NLP មួយចំនួនដោយគ្មានការបណ្ដុះបណ្ដាល ឬ តិចតួច។
## [កម្រងសំណួរផ្ដើមក្រោយបង្រៀន](https://ff-quizzes.netlify.app/en/ai/quiz/40)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការបព្ចាញ់**៖
ឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេលដែលយើងខិតខំប្រឹងប្រែងក្នុងការធានាគុណភាពភាពត្រូវតែម្តង កុំភ្លេចថាការបកប្រែដោយស្វ័យប្រវត្តិអាចមានកំហុស ឬការខុសគ្នាផ្សេងៗ។ ឯកសារដើមនៅក្នុងភាសាដើមគួរត្រូវបានទទួលស្គាល់ជាឯកសារមូលដ្ឋានដ៏ត្រឹមត្រូវ។ សម្រាប់ព័ត៌មានដែលមានសារៈសំខាន់ យើងណែនាំឱ្យប្រើប្រាស់ការបកប្រែដោយមនុស្សវិជ្ជាជីវៈ។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកប្រែខុសព្រោះពីការប្រើប្រាស់ការបកប្រែនេះឡើយ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,73 @@
# ការគ្រប់គ្រងភាសាប្រពៃណី
![សង្ខេបពីភារកិច្ច NLP នៅក្នុងរូបភាពសំលៀកបំពាក់](../../../../translated_images/km/ai-nlp.b22dcb8ca4707cea.webp)
នៅក្នុងផ្នែកនេះ យើងនឹងផ្តោតលើការប្រើប្រាស់បណ្តាញប្រព័ន្ធប្រសាទដើម្បីដោះស្រាយភារកិច្ចដែលទាក់ទងនឹង **ការគ្រប់គ្រងភាសាប្រពៃណី (NLP)**។ មានបញ្ហា NLP ជាច្រើនដែលយើងចង់ឲ្យកុំព្យូទ័រអាចដោះស្រាយបាន៖
* **ចាត់ថ្នាក់អត្ថបទ** គឺជាបញ្ហាចាត់ថ្នាក់ទូទៅដែលសាក់សន្ធិស្នាអត្ថបទ។ ឧទាហរណ៍រួមមានការចាត់ថ្នាក់សារអ៊ីម៉ែលថាជាអ៊ីមែលជាតសំរាម ឬមិនជាតសំរាម ឬចាត់ថ្នាក់អត្ថបទជាប្រភេទកីឡា អាជីវកម្ម នយោបាយ ល។ ក៏ដូចជាករណីបង្កើតជាមួយបច្ចេកវិទ្យាច្រើនរបស់ប៊ូតជាការយល់ដឹងអំពីអ្វីដែលអ្នកប្រើប្រាស់ចង់និយាយ -- ក្នុងករណីនេះ យើងកំពុងដោះស្រាយបញ្ហា **ចាត់ថ្នាក់ចេតនា**។ ជាញឹកញាប់ ក្នុងចំណាត់ថ្នាក់ចេតនា យើងត្រូវដោះស្រាយជាមួយកថាខណ្ឌជាច្រើន។
* **វាយតម្លៃអារម្មណ៍** គឺជាបញ្ហាកំណត់តម្លៃលើតម្លៃតំបន់ដែលយើងត្រូវផ្តល់លេខមួយ (អារម្មណ៍) ដែលបញ្ជាក់ពីភាពវិជ្ជមាន/អវិជ្ជមានន័យនៃឃ្លា។​ ជំនាន់ដែលមានកម្រិតខ្ពស់ជាងនៃវាយតម្លៃអារម្មណ៍គឺ **វាយតម្លៃអារម្មណ៍ផ្អែកលើកត្តា** (ABSA) ដែលយើងផ្តល់អារម្មណ៍នៅចំពោះមុខមិនមែនជាទ្វារសំណួរទាំងមូលទេ តែក្នុងផ្នែកផ្សេងៗរបស់វា (កត្តា) ឧ. *នៅភោជនីយដ្ឋាននេះ ខ្ញុំចូលចិត្តម្ហូបបាយ ប៉ុន្តែការតុបតែងបរិយាកាសគឺអាក្រក់*
* **ការទទួលស្គាល់អត្តសញ្ញាណឈ្មោះ** (NER) មានន័យពីបញ្ហាការដករកសូមកន្សោមណាមួយចេញពីអត្ថបទ។ ឧទាហរណ៍ ជាថ្មី យើងអាចត្រូវយល់ថាក្នុងឃ្លា *ខ្ញុំត្រូវការហោះហើរទៅទីក្រុងប៉ារីសថ្ងៃស្អែក* ពាក្យ *ថ្ងៃស្អែក* មានន័យថាជា DATE ហើយ *ប៉ារីស* គឺ LOCATION។
* **ការដកស្រង់ពាក្យគន្លឹះ** ស្រដៀងទៅនឹង NER ប៉ុន្តែយើងត្រូវដកពាក្យដែលមានសារៈសំខាន់ទៅន័យនៃឃ្លាដោយស្វ័យប្រវត្តិ ដោយមិនមានការបណ្តុះបណ្តាលជាមុនសម្រាប់ប្រភេទអត្តសញ្ញាណជាក់លាក់។
* **ការបែងចែកអត្ថបទជាក្រុម** អាចមានប្រយោជន៍នៅពេលដែលយើងចង់ក្រុមឃ្លាស្រដៀងគ្នាក្នុងការស្នើសុំជាក់លាក់នៅក្នុងការពិភាក្សាជំនួយបច្ចេកទេស។
* **ការឆ្លើយសំណួរ** មានន័យថាគំរូអាចឆ្លើយសំណួរជាក់លាក់មួយបាន។ គំរូទទួលបានអត្ថបទមួយនិងសំណួរជាអ៊ីនភ៊ុត ហើយវាត្រូវផ្តល់កន្លែងក្នុងអត្ថបទដែលមានចម្លើយសំណួរនោះ (ឬក្នុងករណីខ្លះ បង្កើតអត្ថបទចម្លើយ)។
* **ការបង្កើតអត្ថបទ** គឺជាការអនុញ្ញាតឲ្យគំរូបង្កើតអត្ថបទថ្មី។ វាអាចត្រូវបានពិចារណាជាការចាត់ថ្នាក់ដែលទាយលទ្ធផលអក្ខរក្រម/ពាក្យបន្ទាប់ដោយផ្អែកលើ *សំណួរអត្ថបទ*។ គំរូបង្កើតអត្ថបទកម្រិតខ្ពស់ ដូចជា GPT-3 អាចដោះស្រាយភារកិច្ច NLP ផ្សេងទៀតដូចជាចាត់ថ្នាក់ទៅលើបច្ចេកទេសដែលហៅថា [ការសរសេរបញ្ជា](https://towardsdatascience.com/software-3-0-how-prompting-will-change-the-rules-of-the-game-a982fbfe1e0) ឬ [វិស្វកម្មសរសេរបញ្ចូល](https://medium.com/swlh/openai-gpt-3-and-prompt-engineering-dcdc2c5fcd29)។
* **ការសង្ខេបអត្ថបទ** គឺជាបច្ចេកទេសនៅពេលដែលយើងចង់ឲ្យកុំព្យូទ័រប្រាប់ "អាន" អត្ថបទវែង និងសង្ខេបវា​ក្នុងឃ្លា​ចំនួនតិច។
* **ការបកប្រែម៉ាស៊ីន** អាចមើលថាជាការរួមបញ្ចូលរវាងការយល់ដឹងអត្ថបទក្នុងភាសាមួយ និងការបង្កើតអត្ថបទក្នុងភាសាមួយផ្សេងទៀត។
ដើមគេភារកិច្ច NLP ច្រើនត្រូវបានដោះស្រាយប្រើវិធីប្រពៃណីដូចជា វិញ្ញាសាកាត់តាមវេយ្យាករណ៍។ ឧទាហរណ៍ ក្នុងការបកប្រែមួយ គេបានប្រើវេយ្យាករណ៍ដើម្បីបម្លែងឃ្លាដើមទៅជារឹមសៀវភៅវេយ្យាករណ៍ បន្ទាប់មកទាញយករចនាសម្ព័ន្ធសំណួរល្អជាង ដើម្បីបង្ហាញន័យនៃឃ្លា ហើយតាមបណ្តាដើម្បីន័យនិងវេយ្យាករណ៍ភាសាគោលលទ្ធផលត្រូវបានបង្កើត។ ឥឡូវនេះ ភារកិច្ច NLP ជាច្រើនត្រូវបានដោះស្រាយមានប្រសិទ្ធភាពច្រើនជាមួយបណ្តាញប្រព័ន្ធប្រសាទ។
> វិធី NLP ចាស់ៗជាច្រើនត្រូវបានអនុវត្តក្នុងបណ្ណាល័យ Python [Natural Language Processing Toolkit (NLTK)](https://www.nltk.org)។ មានសៀវភៅ [NLTK Book](https://www.nltk.org/book/) ដែលមាននៅលើគេហទំព័រអនឡាញផងដែរ ដែលធ្វើអោយយើងយល់ពីភារកិច្ច NLP ផ្សេងៗដដែលអាចដោះស្រាយបានដោយប្រើ NLTK។
ក្នុងវគ្គនេះ យើងនឹងផ្តោតចំណុចចម្បងទៅលើការប្រើបណ្តាញប្រព័ន្ធប្រសាទសម្រាប់ NLP ហើយយើងនឹងប្រើ NLTK នៅពេលដែលត្រូវការ។
យើងបានរៀនពីការប្រើបណ្តាញប្រព័ន្ធប្រសាទសម្រាប់ទិន្នន័យតារាង និងរូបភាពរួចហើយ។ ផ្សេងគ្នាចម្បងរវាងទិន្នន័យទាំងនេះនឹងអត្ថបទគឺអត្ថបទគឺជាខ្សែវែងប្រែប្រួល ខណៈពេលដែលកម្រាតបញ្ចូលក្នុងរូបភាពត្រូវបានដឹងជាមុន។ ទោះបីបណ្តាញបរាជ័យអាចយករៀបចំប្លង់ពីទិន្នន័យបញ្ចូល ប្លង់ក្នុងអត្ថបទមានភាពស្មុគស្មាញជាង។ ឧ. យើងអាចមានការបដិសេធចេញពីប្រធានបទជាច្រើនពាក្យបាន​ដោយគ្រាន់តែជាការបដិសេធសម្រាប់ពាក្យជាច្រើន (ឧ. *ខ្ញុំមិនចូលចិត្តផ្លែទាំងអង់* ទៅវិញទៅមក *ខ្ញុំមិនចូលចិត្តផ្លែទាំងអាំងធំនិងពណ៌ស្រស់* ) ហើយនោះគួរតែត្រូវបានបកស្រាយថាជាប្លង់តែមួយ។ ដូច្នេះ ដើម្បីសម្របសម្រួលភាសាយើងត្រូវបញ្ចូលប្រភេទបណ្តាញប្រព័ន្ធប្រសាទថ្មីៗដូចជា *បណ្តាញត្រឡប់* និង *transfomers*
## ដំឡើងបណ្ណាល័យ
បើអ្នកកំពុងប្រើការដំឡើង Python នៅលើកុំព្យូទ័រផ្ទាល់ខ្លួន ដើម្បីបើកអនុវត្តវគ្គនេះ អ្នកប្រហែលត្រូវតែដំឡើងបណ្ណាល័យទាំងអស់ដែលត្រូវការនៃ NLP ដោយប្រើពាក្យបញ្ជានិយមដូចខាងក្រោម៖
**សម្រាប់ PyTorch**
```bash
pip install -r requirements-torch.txt
```
**សម្រាប់ TensorFlow**
```bash
pip install -r requirements-tf.txt
```
> អ្នកអាចសាកល្បង NLP ជាមួយ TensorFlow នៅលើ [Microsoft Learn](https://docs.microsoft.com/learn/modules/intro-natural-language-processing-tensorflow/?WT.mc_id=academic-77998-cacaste)
## សេចក្ដីវិភាគ GPU
នៅក្នុងផ្នែកនេះ នៅខ្លះខ្លះនៃឧទាហរណ៍យើងនឹងហាត់គំរូដែលមានទំហំធំជាងមុន។
* **ប្រើកុំព្យូទ័រដែលមាន GPU**៖ ជាការណែនាំឲ្យបើកកំណត់ត្រារបស់អ្នកលើកុំព្យូទ័រដែលមាន GPU ដើម្បីកាត់បន្ថយពេលរង់ចាំពេលធ្វើការជាមួយគំរូទំហំធំ។
* **កំណត់ជំហរចងចំណង GPU**៖ ការប្រើ GPU អាចនាំឲ្យមានស្ថានភាពដែលអង្គចងចំណង GPU គាត់ប្រេងដាច់ពេលហាត់គំរូធំៗ។
* **ការប្រើប្រាស់អង្គចងចំណង GPU**៖ បរិមាណអង្គចងចំណង GPU ប្រើពេលហាត់គំរូអាស្រ័យលើប៉ារ៉ាម៉ែត្រ ផ្សេងៗ រួមមានទំហំជំពូកតូច (minibatch)។
* **កាត់បន្ថយទំហំជំពូកតូច**៖ ប្រសិនបើអ្នកប្រឈមមុខបញ្ហាអង្គចងចំណង GPU អ្នកអាចពិចារណាកាត់បន្ថយទំហំជំពូកតូចនៅក្នុងកូដរបស់អ្នកជាជម្រើសមួយ។
* **ការដោះស្រាយបញ្ហាអង្គចងចំណង GPU ក្នុង TensorFlow**៖ កំណែចាស់ៗនៃ TensorFlow អាចមិនបញ្ឈប់ការប្រើប្រាស់អង្គចងចំណង GPU យ៉ាងត្រឹមត្រូវ នៅពេលហាត់គំរូច្រើនក្នុងកឺណែល Python មួយ។ ដើម្បីគ្រប់គ្រងការប្រើប្រាស់អង្គចងចំណង GPU ជាដំណោះស្រាយ អ្នកអាចកំណត់ TensorFlow ឲ្យបន្ថែមអង្គចងចំណង GPU ពេញតែត្រូវការតែប៉ុណ្ណោះ។
* **ការបញ្ចូលកូដ**៖ ដើម្បីកំណត់ឲ្យ TensorFlow កំណត់បន្ថែមអង្គចងចំណង GPU លើកដំបូងតែពេលគាំទ្រ អ្នកអាចបញ្ចូលកូដខាងក្រោមក្នុងកំណត់ត្រារបស់អ្នក៖
```python
physical_devices = tf.config.list_physical_devices('GPU')
if len(physical_devices)>0:
tf.config.experimental.set_memory_growth(physical_devices[0], True)
```
បើអ្នកចាប់អារម្មណ៍ក្នុងការសិក្សា NLP ពីទស្សនវិជ្ជា ML ចាស់ៗ សូមចូលទៅរក [ជួរមេរៀននេះ](https://github.com/microsoft/ML-For-Beginners/tree/main/6-NLP)
## នៅក្នុងផ្នែកនេះ
នៅក្នុងផ្នែកនេះ យើងនឹងរៀនអំពី៖
* [តំណាងអត្ថបទជាទិន្នន័យ tensor](13-TextRep/README.md)
* [ការដាក់ពាក្យជាតំណ](14-Emdeddings/README.md)
* [ម៉ូដែលភាសា](15-LanguageModeling/README.md)
* [បណ្តាញប្រព័ន្ធប្រសាទត្រឡប់](16-RNN/README.md)
* [បណ្តាញបង្កើត](17-GenerativeNetworks/README.md)
* [Transformers](18-Transformers/README.md)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការបដិសេធ**៖
ឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ រួមទាំងយើងខិតខំប្រឹងប្រែងដើម្បីភាពត្រឹមត្រូវ ក៏សូមយល់ដឹងថាការបកប្រែដោយស្វ័យប្រវត្តិអាចមានកំហុសឬភាពមិនត្រឹមត្រូវ។ ឯកសារដើមជាភាសាដើមគួរត្រូវបានយកជាធនាគារដែលមានសិទ្ធិ។ សម្រាប់ព័ត៌មានសំខាន់ ការបកប្រែដោយអ្នកជំនាញជាថ្នាក់មនុស្សត្រូវបានណែនាំ។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំឬការបកប្រែខុសពីការប្រើប្រាស់ការបកប្រែនេះឡើយ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,43 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## កិច្ចការ: សមីការឌីយូហ្វង់ទីន\n",
"\n",
"> កិច្ចការនេះជាផ្នែកមួយនៃ [មេរៀន AI សម្រាប់អ្នកចាប់ផ្តើម](http://github.com/microsoft/ai-for-beginners) ហើយបានទទួលចbouរប្រភពពី [អត្ថបទនេះ](https://habr.com/post/128704/).\n",
"\n",
"គោលបំណងរបស់អ្នកគឺដោះស្រាយដែលហៅថា **សមីការឌីយូហ្វង់ទីន** - សមីការមួយដែលមានដំណោះស្រាយជាចំនួនគត់ និងសមាសធាតុជាចំនួនគត់។ ឧទាហរណ៍ សូមពិចារណាសមីការដូចខាងក្រោម៖\n",
"\n",
"$$a+2b+3c+4d=30$$\n",
"\n",
"អ្នកត្រូវស្វែងរកដំណោះស្រាយជាចំនួនគត់ $a$,$b$,$c$,$d\\in\\mathbb{N}$ ដែលបំពេញសមីការនេះ។\n",
"\n",
"Hints:\n",
"1. អ្នកអាចចាត់ទុកដំណោះស្រាយនៅក្នុងចន្លោះ [0;30]\n",
"1. ជាជីន សូមពិចារណាការប្រើបញ្ជីនៃតម្លៃដំណោះស្រាយ\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**ការមិនទទួលខុសត្រូវ**:\nឯកសារនេះបានបកប្រែដោយប្រើសេវាកម្មបកប្រែដោយ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេលដែលយើងខិតខំរកភាពត្រឹមត្រូវ សូមយកចិត្តទុកដាក់ថាការបកប្រែដោយស្វ័យប្រវត្តិអាចមានកំហុស ឬមិនពិតប្រាកដ។ ឯកសារដើមក្នុងភាសាដើមគួរត្រូវបានចាត់ទុកជាប្រភពត្រឹមត្រូវ។ សម្រាប់ព័ត៌មានសំខាន់ៗ យើងផ្តល់អនុសាសន៍ឱ្យធ្វើការបកប្រែដោយអ្នកជំនាញ (មនុស្ស)។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកស្រាយខុសណាមួយដែលកើតឡើងពីការប្រើប្រាស់ការបកប្រែនេះ។\n<!-- CO-OP TRANSLATOR DISCLAIMER END -->\n"
]
}
],
"metadata": {
"language_info": {
"name": "python"
},
"orig_nbformat": 4
},
"nbformat": 4,
"nbformat_minor": 2
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,84 @@
# អាល់ហ្គារីធម៍ចំលែក
## [ការប្រលងមុនមេរៀន](https://ff-quizzes.netlify.app/en/ai/quiz/41)
**អាល់ហ្គារីធម៍ចំលែក** (GA) ត្រូវបានផ្អែកលើវិធីសាស្រ្ត **វិបត្តិជីវៈ** ទៅកាន់ AI ដែលរបៀបនៃការវះកាត់ប្រជាជនត្រូវបានប្រើ ដើម្បីទទួលបានដំណោះស្រាយល្អបំផុតសម្រាប់បញ្ហាដែលបានផ្តល់។ វាត្រូវបានផ្ដល់អធិប្បាយនៅឆ្នាំ 1975 ដោយ [John Henry Holland](https://wikipedia.org/wiki/John_Henry_Holland)។
អាល់ហ្គារីធម៍ចំលែកផ្អែកលើគំនិតដូចខាងក្រោម៖
* ដំណោះស្រាយត្រឹមត្រូវសម្រាប់បញ្ហាអាចត្រូវតំណាងជា **កោសិការី**
* **ការបន្តិចបន្តួច** អនុញ្ញាតឱ្យយើងបញ្ចូលរួមពីរដំណោះស្រាយមួយគ្នាដើម្បីទទួលបានដំណោះស្រាយថ្មីត្រឹមត្រូវ
* **ការជ្រើសរើស** ត្រូវបានប្រើដើម្បីជ្រើសយកដំណោះស្រាយល្អជាងដោយប្រើ **មុខងារសមត្ថភាព**
* **ការបម្លែង** ត្រូវបានបញ្ចូល ដើម្បីធ្វើឲ្យការបង្កើតបញ្ហាមិនមានសុវត្ថិភាព និងធ្វើឲ្យយើងចេញពីតម្លៃតំបន់តិចបំផុតក្នុងមូលដ្ឋាន
បើអ្នកចង់អនុវត្តអាល់ហ្គារីធម៍ចំលែក អ្នកត្រូវការដូចខាងក្រោម៖
* រកវិធីសាស្រ្តកូដដំណោះស្រាយបញ្ហារបស់យើងដោយប្រើ **កោសិការី** g&in;&Gamma;
* លើសំណុំកោសិការី &Gamma; ត្រូវកំណត់ **មុខងារសមត្ថភាព** fit: &Gamma;&rightarrow;**R**។ តម្លៃមុខងារតិចជាងបង្ហាញដំណោះស្រាយល្អជាង។
* កំណត់យន្តការជំនួស (crossover) ដើម្បីបញ្ចូលរួមពីរកោសិការីរួមគ្នា ដើម្បីទទួលបានដំណោះស្រាយថ្មីត្រឹមត្រូវ crossover: &Gamma;<sup>2</sub>&rightarrow;&Gamma;
* កំណត់យន្តការបម្លែង mutate: &Gamma;&rightarrow;&Gamma;
ជាច្រើនករណី ការជំនួស និងការបម្លែង គឺជាអាល់ហ្គារីធម៍សាមញ្ញក្នុងការគ្រប់គ្រងកោសិការីជា់ជួរលេខ ឬជាគ្រាប់ប៊ីត។
ការអនុវត្តជាក់លាក់នៃអាល់ហ្គារីធម៍ចំលែកអាចខុសគ្នាចាប់ពីករណីមួយទៅករណីមួយ ប៉ុន្តែរចនាសម្ព័ន្ធសរុបគឺដូចខាងក្រោម៖
1. ជ្រើសរើសប្រជាជនដើម G&subset;&Gamma;
2. ជ្រើសរើសដោយចៃដន្យពីលើប្រតិបត្តិការណ៍មួយដែលនឹងត្រូវអនុវត្តនៅជំហាននេះ៖ ជំនួស ឬ បម្លែង
3. **ជំនួស**
* ជ្រើសរើសដោយចៃដន្យពីរកោសិការី g<sub>1</sub>, g<sub>2</sub> &in; G
* គណនាជំនួស g=crossover(g<sub>1</sub>,g<sub>2</sub>)
* បើ fit(g)<fit(g<sub>1</sub>) ឬ fit(g)<fit(g<sub>2</sub>) នោះដូរកោសិការីដែលសមស្របក្នុងប្រជាជនជាមួយ g។
4. **បម្លែង** - ជ្រើសរើសកោសិការីចៃដន្យ g&in;G ហើយដូរវាជា mutate(g)
5. ត្រលប់មកជំហានទី 2 រហូតដល់យើងទទួលបានតម្លៃ fit តិចគ្រប់គ្រាន់ ឬដល់ដល់កំណត់ចំនួនជំហាន។
## បុព្វហេតុទូទៅ
បុព្វហេតុដែលជាធម្មតាត្រូវបានដោះស្រាយដោយអាល់ហ្គារីធម៍ចំលែករួមមាន៖
1. ការប្រសិទ្ធភាពពេលវេលាកំណត់តារាចរ
1. ការវេចខ្ចប់ប្រសើរបំផុត
1. ការកាត់កៅអីប្រសើរបំផុត
1. ការបង្វិលស្វែងរកឲ្យលឿនឡើង
## ✍️ មេរៀនអនុវត្ត៖ អាល់ហ្គារីធម៍ចំលែក
បន្តការរៀនរបស់អ្នកនៅក្នុងសៀវភៅដូចខាងក្រោម៖
ទៅកាន់ [សៀវភៅនេះ](Genetic.ipynb) ដើម្បីមើលឧទាហរណ៍ពីរជាមួយអាល់ហ្គារីធម៍ចំលែក៖
1. ការបែងចែកមូលដ្ឋានយ៉ាងត្រឹមត្រូវ
1. បញ្ហា Queens 8
## សេចក្តីសន្និដ្ឋាន
អាល់ហ្គារីធម៍ចំលែកត្រូវបានប្រើដោះស្រាយបញ្ហាច្រើន មានរួមទាំងបញ្ហាឡូហ្សីស្ទីក និងការស្វែងរក។ វាលនេះទទួលបំផុតបញ្ញាបណ្ដា ដែលផ្ទុយពីការស្រាវជ្រាវដែលបញ្ចូលប្រធានបទក្នុងចំណោមវិជ្ជា ចិត្តវិទ្យា និងវិទ្យាសាស្រ្តកុំព្យូទ័រ។
## 🚀 ឧបសគ្គ
"អាល់ហ្គារីធម៍ចំលែកគឺសាមញ្ញក្នុងការអនុវត្ត ប៉ុន្តែឥរិយាបថរបស់វារឹងប៉ឹងក្នុងការយល់។" [ប្រភព](https://wikipedia.org/wiki/Genetic_algorithm) សូមធ្វើការស្រាវជ្រាវដើម្បីរកការអនុវត្តអាល់ហ្គារីធម៍ចំលែកមួយ ដូចជា ដោះស្រាយសោគូម៉ូ រួចពន្យល់របៀបវាដំណើរការជាគំនូសបរិយាយ ឬផែនទីប្រែកម្មវិធី។
## [ការប្រលងបន្ទាប់គេរៀន](https://ff-quizzes.netlify.app/en/ai/quiz/42)
## ការត្រួតពិនិត្យ និង រៀនផ្ទាល់ខ្លួន
មើល [វីដេអូដ៏អស្ចារ្យនេះ](https://www.youtube.com/watch?v=qv6UVOQ0F44) បង្ហាញអំពីរបៀបកុំព្យូទ័រអាចរៀនលេងហ្គេម Super Mario ដោយប្រើបណ្តាញសរសៃប្រសាទ ដែលបានហ្វឹកហាត់ដោយអាល់ហ្គារីធម៍ចំលែក។ យើងនឹងរៀនបន្ថែមអំពីការរៀនកុំព្យូទ័រលេងហ្គេមដូចនេះ [នៅក្នុងផ្នែកបន្ទាប់](../22-DeepRL/README.md)។
## [ការងារ៖ សមីការដាយូហ្វង់ទីន](Diophantine.ipynb)
គោលបំណងរបស់អ្នកគឺដោះស្រាយសមីការដែលហៅថា **សមីការ​ដាយូហ្វង់ទីន** - សមីការដែលមានឫសគោលគតិជាចំនួនគត់។ ឧទាហរណ៍ ពិនិត្យសមីការ a+2b+3c+4d=30។ អ្នកត្រូវស្វែងរកឫសគោលគត់ដែលបំពេញសមីការនេះ។
*ការប្រឹក្សានេះបានចាប់ផ្អើលពី [ការប្រកាសនេះ](https://habr.com/post/128704/)។*
កំណត់សម្គាល់៖
1. អ្នកអាចពិចារណាឫសគោលគតិជាតំបន់ [0;30]
1. ជាកោសិការី សូមពិចារណាប្រើបញ្ជីតម្លៃឫសគោលគតិ
ប្រើ [Diophantine.ipynb](Diophantine.ipynb) ដើម្បីជាចំណុចចាប់ផ្តើម។
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការបដិសេធ**៖
ឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ទោះបីជាយើងខិតខំរកភាពត្រឹមត្រូវ ក៏ត្រូវស្គាល់ថាការបកប្រែដោយស្វ័យប្រវត្តិអាចមានកំហុស ឬភាពមិនច្បាស់លាស់។ ឯកសារដើមជាភាសាមูลដ្ឋានគឺជាទីតាំងផ្លូវការជាភាគី។ សម្រាប់ព័ត៌មានសំខាន់ៗ សូមណែនាំឱ្យធ្វើការបកប្រែដោយជំនាញមនុស្សវិជ្ជាជីវៈ។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ខុស ឬការបកស្រាយខុសណាមួយដែលកើតឡើងពីការប្រើប្រាស់ការបកប្រែនេះទេ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,498 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# បណ្តុះបណ្តាល RL សម្រាប់ធ្វើតុល្យភាព Cartpole\n",
"\n",
"កំណត់ត្រានេះជាផ្នែកមួយនៃ [AI for Beginners Curriculum](http://aka.ms/ai-beginners). វាបានចាប់ផ្តើមពី [official PyTorch tutorial](https://pytorch.org/tutorials/intermediate/reinforcement_q_learning.html) និង [this Cartpole PyTorch implementation](https://github.com/yc930401/Actor-Critic-pytorch).\n",
"\n",
"ក្នុងឧទាហរណ៍នេះ យើងនឹងប្រើ RL ដើម្បីបណ្តុះម៉ូដែលឲ្យតុល្យភាពកន្ទេលមួយលើរទេះ (cart) ដែលអាចចល័តទៅឆ្វេង និងស្តាំលើផ្ទាប់ទ្រង់ទ្រាយផ្ដេក។ យើងនឹងប្រើបរិយាកាស [OpenAI Gym](https://www.gymlibrary.ml/) ដើម្បីសមនិយមកន្ទេល។\n",
"\n",
"> **ចំណាំ**: អ្នកអាចរត់កូដវគ្គរៀននេះនៅលើកុំព្យូទ័រទីតាំង (ឧ. ពី Visual Studio Code) ដែលក្នុងករណីនោះ ការសមនិយមនឹងបើកក្នុងបង្អួចថ្មី។ ពេលរត់កូដតាមអនឡាញ អ្នកប្រហែលជាត្រូវការធ្វើកែប្រៃខ្លះលើកូដ ដូចបានពិពណ៌នានៅ [នៅទីនេះ](https://towardsdatascience.com/rendering-openai-gym-envs-on-binder-and-google-colab-536f99391cc7).\n",
"\n",
"យើងនឹងចាប់ផ្តើមដោយធ្វើឲ្យប្រាកដថា Gym បានតំឡើង:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import sys\n",
"!{sys.executable} -m pip install gym"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ឥឡូវនេះយើងបង្កើតបរិយាកាស CartPole ហើយមើលពីរបៀបប្រតិបត្តិលើវា។ បរិយាកាសមួយមានលក្ខណៈដូចខាងក្រោម៖\n",
"\n",
"* **Action space** គឺជាសំណុំសកម្មភាពដែលយើងអាចអនុវត្តបាននៅក្នុងរាល់ជំហាននៃការសម្រួល\n",
"* **Observation space** គឺជាដែននៃការសង្កេតដែលយើងអាចធ្វើបាន\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import gym\n",
"\n",
"env = gym.make(\"CartPole-v1\")\n",
"\n",
"print(f\"Action space: {env.action_space}\")\n",
"print(f\"Observation space: {env.observation_space}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"មកមើលថា​សមូឡាសិន​ដំណើរការ​យ៉ាងដូចម្តេច។ លូខាងក្រោមនេះរត់សមូឡាសិន រហូតដល់ `env.step` ត្រឡប់បញ្ជាក់សញ្ញាបញ្ចប់ `done`។ យើង​នឹងជ្រើសសកម្មភាព​ដោយចៃដន្យ ដោយប្រើ `env.action_space.sample()`, ដែលមានន័យថាការសាកល្បងនេះភាគច្រើននឹងបរាជ័យយ៉ាងឆាប់ (បរិយាកាស CartPole នឹងបញ្ចប់នៅពេលល្បឿន ទីតាំង ឬមុំរបស់ CartPole ចេញពីដែនកំណត់)។\n",
"\n",
"> ការសមូឡាសិន​នឹងបើក​នៅក្នុង​ជញ្ជាំងវីនដូ​ថ្មី។ អ្នកអាចរត់កូដនេះ​ច្រើនដង និងមើលថាវាធ្វើការ​យ៉ាងដូចម្តេច។\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"env.reset()\n",
"\n",
"done = False\n",
"total_reward = 0\n",
"while not done:\n",
" env.render()\n",
" obs, rew, done, info = env.step(env.action_space.sample())\n",
" total_reward += rew\n",
" print(f\"{obs} -> {rew}\")\n",
"print(f\"Total reward: {total_reward}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"អ្នកអាចសង្កេតឃើញថាការសង្កេតមានចំនួន 4 លេខ។ វាដូចជា៖\n",
"- ទីតាំងនៃរទេះ\n",
"- ល្បឿននៃរទេះ\n",
"- មុំនៃ pole\n",
"- អត្រាបង្វិលនៃ pole\n",
"\n",
"`rew` គឺជารางวัลដែលយើងទទួលបាននៅរាល់ជំហាន។ អ្នកអាចឃើញថា ក្នុងបរិយាកាស CartPole យើងត្រូវបានផ្តល់រង្វាន់ 1 ពិន្ទុសម្រាប់រាល់ជំហានសមីការ ហើយគោលបំណងគឺបង្កើនចំនួនរង្វាន់សរុប ឬ ន័យថា ពេលវេលា​ដែល CartPole អាចរក្សាសមតុល្យបានដោយមិនធ្លាក់។\n",
"\n",
"ក្នុងអំឡុងការ reinforcement learning គោលបំណងរបស់យើងគឺបណ្តុះបណ្តាល **គោលនយោបាយ** $\\pi$ ដែលសម្រាប់រាល់ស្ថានភាព $s$ នឹងប្រាប់យើងថាត្រូវអនុវត្តសកម្មភាព $a$ ណា ដូច្នេះសារសង្ខេបគឺ $a = \\pi(s)$។\n",
"\n",
"បើអ្នកចង់ដំណោះស្រាយដោយប្រើវិធីសាស្ត្រប្រហែលភាព អ្នកអាចគិតថា គោលនយោបាយបញ្ចូនចំនួនប្រហែលភាពសម្រាប់នីមួយៗសកម្មភាព, ឧទាហរណ៍ $\\pi(a|s)$ មានន័យថាជាពីរប្រហែលភាពដែលយើងគួរជ្រើសសកម្មភាព $a$ នៅស្ថានភាព $s$។\n",
"\n",
"## វិធីសាស្ត្រ Policy Gradient\n",
"\n",
"នៅក្នុងអាល់ហ្គរីធម์ RL ដែលសាមញ្ញបំផុត ហៅថា **Policy Gradient** យើងនឹងបណ្តុះបណ្តាលបណ្តាញប្រសាទ ដើម្បីទទាញទាយសកម្មភាពបន្ទាប់។\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import torch\n",
"\n",
"num_inputs = 4\n",
"num_actions = 2\n",
"\n",
"model = torch.nn.Sequential(\n",
" torch.nn.Linear(num_inputs, 128, bias=False, dtype=torch.float32),\n",
" torch.nn.ReLU(),\n",
" torch.nn.Linear(128, num_actions, bias = False, dtype=torch.float32),\n",
" torch.nn.Softmax(dim=1)\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"យើងនឹងបណ្តុះបណ្តាលបណ្ដាញដោយប្រតិបត្តិការពិសោធន៍ជាច្រើន ហើយធ្វើបច្ចុប្បន្នភាពបណ្ដាញរបស់យើងបន្ទាប់ពីរាល់ដំណើរ។ ចូរយើងកំណត់មុខងារមួយដែលនឹងរត់ពិសោធន៍ ហើយត្រឡប់លទ្ធផលវិញ (ហៅថា **trace**) - ស្ថានភាពទាំងអស់ សកម្មភាព (និងប្រហែលភាពដែលបានណែនាំ) និងរង្វាន់៖\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def run_episode(max_steps_per_episode = 10000,render=False): \n",
" states, actions, probs, rewards = [],[],[],[]\n",
" state = env.reset()\n",
" for _ in range(max_steps_per_episode):\n",
" if render:\n",
" env.render()\n",
" action_probs = model(torch.from_numpy(np.expand_dims(state,0)))[0]\n",
" action = np.random.choice(num_actions, p=np.squeeze(action_probs.detach().numpy()))\n",
" nstate, reward, done, info = env.step(action)\n",
" if done:\n",
" break\n",
" states.append(state)\n",
" actions.append(action)\n",
" probs.append(action_probs.detach().numpy())\n",
" rewards.append(reward)\n",
" state = nstate\n",
" return np.vstack(states), np.vstack(actions), np.vstack(probs), np.vstack(rewards)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"អ្នកអាចរត់វគ្គមួយជាមួយបណ្តាញមិនទាន់បានបណ្តុះ ហើយសង្កេតឃើញថារង្វាន់សរុប (ឬប្រវែងនៃវគ្គ) ទាបណាស់៖\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"s, a, p, r = run_episode()\n",
"print(f\"Total reward: {np.sum(r)}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"មួយក្នុងចំណោមចំណុចលំបាកនៃអាល់ហ្គរីធម៍ gradient នៃគោលនយោបាយ គឺការប្រើ **រង្វាន់ដែលបានបញ្ចុះតម្លៃ**. គំនិតគឺយើងគណនា វ៉ិចទ័រ នៃរង្វាន់សរុប នៅក្នុងគ្រប់ជំហាននៃហ្គេម ហើយក្នុងដំណើរការនេះ យើងបញ្ចុះតម្លៃរង្វាន់ដើមៗ ដោយប្រើសមាសធាតុមួយ $gamma$. យើងក៏ធ្វើឲ្យវ៉ិចទ័រដែលបានទទួលមានការប្រកាស់បទ (normalize) ព្រោះយើងនឹងប្រើវាជាទម្ងន់ ដើម្បីប៉ះពាល់ដល់ការបណ្តុះបណ្តាលរបស់យើង:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"eps = 0.0001\n",
"\n",
"def discounted_rewards(rewards,gamma=0.99,normalize=True):\n",
" ret = []\n",
" s = 0\n",
" for r in rewards[::-1]:\n",
" s = r + gamma * s\n",
" ret.insert(0, s)\n",
" if normalize:\n",
" ret = (ret-np.mean(ret))/(np.std(ret)+eps)\n",
" return ret"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now let's do the actual training! We will run 300 episodes, and at each episode we will do the following:\n",
"\n",
"1. រៀបចំការសាកល្បង និងប្រមូល trace\n",
"1. គណនាចម្ងាយ (`gradients`) រវាងសកម្មភាពដែលបានអនុវត្ត និង ភាគរយដែលបានទាយ។ បើចម្ងាយតិច នោះយើងនឹងមានភាពប្រាកដជាងថាបានជ្រើសសកម្មភាពត្រឹមត្រូវ។\n",
"1. គណនារង្វាន់ដែលបានបញ្ចុះតម្លៃ (discounted rewards) ហើយគុណ gradients ជាមួយ discounted rewards - នេះនឹងធានាថាជំហានដែលមានរង្វាន់ខ្ពស់នឹងមានឥទ្ធិពលច្រើនលើលទ្ធផលចុងក្រោយជាងជំហានដែលមានរង្វាន់ទាប។\n",
"1. សកម្មភាពគោលដៅសម្រាប់បណ្តាញប្រសាទរបស់យើងនឹងផ្តល់ផ្នែកមួយពីភាគរយដែលបានទាយក្នុងកំឡុងការរត់ និងផ្នែកមួយពី gradients ដែលបានគណនា។ យើងនឹងប្រើប៉ារ៉ាម៉ែត្រ `alpha` ដើម្បីកំណត់ដល់កម្រិតណា gradients និង rewards ត្រូវបានគិតគូរ - នេះហៅថា *អត្រាសិក្សា* នៃអាល់គ័រីធម៍ពង្រឹង។\n",
"1. ចុងក្រោយ យើងបណ្តុះបណ្តាលបណ្តាញលើ states និង សកម្មភាពគោលដៅដែលរំពឹងទុក ហើយធ្វើដំណើរការម្ដងទៀត\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"optimizer = torch.optim.Adam(model.parameters(), lr=0.01)\n",
"\n",
"def train_on_batch(x, y):\n",
" x = torch.from_numpy(x)\n",
" y = torch.from_numpy(y)\n",
" optimizer.zero_grad()\n",
" predictions = model(x)\n",
" loss = -torch.mean(torch.log(predictions) * y)\n",
" loss.backward()\n",
" optimizer.step()\n",
" return loss"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"alpha = 1e-4\n",
"\n",
"history = []\n",
"for epoch in range(300):\n",
" states, actions, probs, rewards = run_episode()\n",
" one_hot_actions = np.eye(2)[actions.T][0]\n",
" gradients = one_hot_actions-probs\n",
" dr = discounted_rewards(rewards)\n",
" gradients *= dr\n",
" target = alpha*np.vstack([gradients])+probs\n",
" train_on_batch(states,target)\n",
" history.append(np.sum(rewards))\n",
" if epoch%100==0:\n",
" print(f\"{epoch} -> {np.sum(rewards)}\")\n",
"\n",
"plt.plot(history)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ឥឡូវនេះ យើងនឹងរត់វគ្គនេះដោយមានការបង្ហាញ ដើម្បីមើលលទ្ធផល:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"_ = run_episode(render=True)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"សង្ឃឹមថា អ្នកអាចមើលឃើញបានថា ដង្កូវឥឡូវនេះអាចសមតុល្យបានល្អ!\n",
"\n",
"## ម៉ូដែល Actor-Critic\n",
"\n",
"ម៉ូដែល Actor-Critic គឺជាការវិវត្តបន្ថែមរបស់ policy gradients ដែលក្នុងនោះយើងបង្កើតបណ្ដាញណឺរ៉ាល់មួយ ដើម្បីរៀនទាំងគោលនយោបាយ និងរង្វាន់ដែលបានប៉ាន់ស្មាន។ បណ្ដាញនឹងមានលទ្ធផលពីរផ្លៅ (ឬអ្នកអាចមើលវាជាបណ្ដាញពីរក៏បាន):\n",
"\n",
"* **Actor** នឹងណែនាំសកម្មភាពដែលត្រូវធ្វើ ដោយផ្តល់ឲ្យយើងចែកចាយប្រហាមានភាពរបស់ស្ថានភាព ដូចក្នុងម៉ូដែល policy gradient\n",
"* **Critic** នឹងប៉ាន់ស្មានថារង្វាន់នឹងមានអ្វីពីសកម្មភាពទាំងនោះ។ វាត្រឡប់មកនូវរង្វាន់សរុបដែលបានប៉ាន់ស្មានសម្រាប់អនាគតនៅស្ថានភាពដែលបានផ្ដល់។\n",
"\n",
"មកកំណត់ម៉ូដែលបែបនេះ៖\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from itertools import count\n",
"import torch.nn.functional as F"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n",
"env = gym.make(\"CartPole-v1\")\n",
"\n",
"state_size = env.observation_space.shape[0]\n",
"action_size = env.action_space.n\n",
"lr = 0.0001\n",
"\n",
"class Actor(torch.nn.Module):\n",
" def __init__(self, state_size, action_size):\n",
" super(Actor, self).__init__()\n",
" self.state_size = state_size\n",
" self.action_size = action_size\n",
" self.linear1 = torch.nn.Linear(self.state_size, 128)\n",
" self.linear2 = torch.nn.Linear(128, 256)\n",
" self.linear3 = torch.nn.Linear(256, self.action_size)\n",
"\n",
" def forward(self, state):\n",
" output = F.relu(self.linear1(state))\n",
" output = F.relu(self.linear2(output))\n",
" output = self.linear3(output)\n",
" distribution = torch.distributions.Categorical(F.softmax(output, dim=-1))\n",
" return distribution\n",
"\n",
"\n",
"class Critic(torch.nn.Module):\n",
" def __init__(self, state_size, action_size):\n",
" super(Critic, self).__init__()\n",
" self.state_size = state_size\n",
" self.action_size = action_size\n",
" self.linear1 = torch.nn.Linear(self.state_size, 128)\n",
" self.linear2 = torch.nn.Linear(128, 256)\n",
" self.linear3 = torch.nn.Linear(256, 1)\n",
"\n",
" def forward(self, state):\n",
" output = F.relu(self.linear1(state))\n",
" output = F.relu(self.linear2(output))\n",
" value = self.linear3(output)\n",
" return value"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"យើងនឹងត្រូវតែធ្វើការកែប្រែតិចតួចលើមុខងារ `discounted_rewards` និង `run_episode` របស់យើង:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def discounted_rewards(next_value, rewards, masks, gamma=0.99):\n",
" R = next_value\n",
" returns = []\n",
" for step in reversed(range(len(rewards))):\n",
" R = rewards[step] + gamma * R * masks[step]\n",
" returns.insert(0, R)\n",
" return returns\n",
"\n",
"def run_episode(actor, critic, n_iters):\n",
" optimizerA = torch.optim.Adam(actor.parameters())\n",
" optimizerC = torch.optim.Adam(critic.parameters())\n",
" for iter in range(n_iters):\n",
" state = env.reset()\n",
" log_probs = []\n",
" values = []\n",
" rewards = []\n",
" masks = []\n",
" entropy = 0\n",
" env.reset()\n",
"\n",
" for i in count():\n",
" env.render()\n",
" state = torch.FloatTensor(state).to(device)\n",
" dist, value = actor(state), critic(state)\n",
"\n",
" action = dist.sample()\n",
" next_state, reward, done, _ = env.step(action.cpu().numpy())\n",
"\n",
" log_prob = dist.log_prob(action).unsqueeze(0)\n",
" entropy += dist.entropy().mean()\n",
"\n",
" log_probs.append(log_prob)\n",
" values.append(value)\n",
" rewards.append(torch.tensor([reward], dtype=torch.float, device=device))\n",
" masks.append(torch.tensor([1-done], dtype=torch.float, device=device))\n",
"\n",
" state = next_state\n",
"\n",
" if done:\n",
" print('Iteration: {}, Score: {}'.format(iter, i))\n",
" break\n",
"\n",
"\n",
" next_state = torch.FloatTensor(next_state).to(device)\n",
" next_value = critic(next_state)\n",
" returns = discounted_rewards(next_value, rewards, masks)\n",
"\n",
" log_probs = torch.cat(log_probs)\n",
" returns = torch.cat(returns).detach()\n",
" values = torch.cat(values)\n",
"\n",
" advantage = returns - values\n",
"\n",
" actor_loss = -(log_probs * advantage.detach()).mean()\n",
" critic_loss = advantage.pow(2).mean()\n",
"\n",
" optimizerA.zero_grad()\n",
" optimizerC.zero_grad()\n",
" actor_loss.backward()\n",
" critic_loss.backward()\n",
" optimizerA.step()\n",
" optimizerC.step()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ឥឡូវនេះយើងនឹងរត់លូបបណ្តុះបណ្តាលចម្បង។ យើងនឹងប្រើដំណើរការ​បណ្តុះបណ្តាលបណ្ដាញដោយដៃ ដើម្បីគណនា​អនុគមន៍ខាតដែលសមរម្យ និងធ្វើការអាប់ដេតព៉ារ៉ាមែត្រនៃបណ្ដាញ៖\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"\n",
"actor = Actor(state_size, action_size).to(device)\n",
"critic = Critic(state_size, action_size).to(device)\n",
"run_episode(actor, critic, n_iters=100)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ចុងក្រោយ យើងបិទបរិស្ថាន។\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"env.close()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## ចំណុចសំខាន់\n",
"\n",
"យើងបានឃើញអាល់ហ្គរីធម៍ RL ពីរនៅក្នុងការបង្ហាញនេះ៖ simple policy gradient, និង actor-critic ដែលស្មុគស្មាញជាង។ អ្នកអាចឃើញថា​អាល់ហ្គរីធម៍ទាំងនេះធ្វើការជាមួយគំនិតទូទៅស្តីពី state, action និង reward - ដូច្នេះវាអាចអនុវត្តទៅលើបរិយាកាសដែលខុសគ្នាយ៉ាងច្រើន។\n",
"\n",
"ការរៀនដោយពង្រឹងអនុញ្ញាតឱ្យយើងរៀនយុទ្ធសាស្ត្រល្អបំផុតដើម្បីដោះស្រាយបញ្ហា ដោយមើលតែរង្វាន់ចុងក្រោយ។ ការមិនចាំបាច់ប្រើ labelled datasets អនុញ្ញាតឱ្យយើងធ្វើការស្វែងយល់ដោយស្ទង់ឡើងវិញជាច្រើនដងដើម្បីតម្រៀបម៉ូឌែលរបស់យើង។ ទោះជាយ៉ាងណា នៅតែមានបញ្ហាជាច្រើនក្នុង RL ដែលអ្នកអាចរៀនបន្ថែម ប្រសិនបើអ្នកសម្រេចចិត្តផ្ដោតចំណាប់អារម្មណ៍លើវិស័យទាក់ទាញនេះនៃ AI។\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**Disclaimer**:\nឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេលយើងខិតខំរកភាពត្រឹមត្រូវ សូមយកចិត្តទុកដាក់ថាការបកប្រែដោយស្វ័យប្រវត្តិអាចមានកំហុស ឬភាពមិនត្រឹមត្រូវ។ ឯកសារដើមនៅក្នុងភាសាមូលដ្ឋានគួរត្រូវបានគេចាត់ទុកជាប្រភពដែលអាចទុកចិត្តបាន។ សម្រាប់ព័ត៌មានសំខាន់ៗ យើងស្នើឱ្យប្រើការបកប្រែដោយមនុស្សជំនាញ។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកស្រាយខុសណាមួយដែលកើតមានពីការប្រើប្រាស់ការបកប្រែនេះទេ។\n<!-- CO-OP TRANSLATOR DISCLAIMER END -->\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3.10.4 64-bit",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.4"
},
"orig_nbformat": 4,
"vscode": {
"interpreter": {
"hash": "916dbcbb3f70747c44a77c7bcd40155683ae19c65e1c03b4aa3499c5328201f1"
}
}
},
"nbformat": 4,
"nbformat_minor": 2
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,121 @@
# ការសិក្សាដែលជ្រៅលើការសំរបសំរួលដោយជំនឿជាក់
ការសំរបសំរួលដោយជំនឿជាក់ (RL) ត្រូវបានគេឃើញថា ជាមួយនឹងមូលដ្ឋានមួយនៃទ្រឹស្តីការសិក្សាម៉ាស៊ីន ជាប់ជាមួយការសិក្សាដោយមានការបញ្ជាក់ និងការសិក្សាដោយមិនមានការបញ្ជាក់។ ខណៈពេលដែលនៅក្នុងការសិក្សាដោយមានការបញ្ជាក់ យើងអាស្រ័យលើសំណុំទិន្នន័យដែលមានលទ្ធផលដែលបានស្គាល់ហើយ RL មានមូលដ្ឋានលើ **ការសិក្សាតាមរយៈការធ្វើ**។ ឧទាហរណ៍ នៅពេលដែលយើងឃើញហ្គេមកុំព្យូទ័រជាលើកដំបូង យើងចាប់ផ្តើមលេង ដោយមិនចាំបាច់ស្គាល់ច្បាប់ ហើយភ្លាមៗយើងអាចធ្វើឲ្យជំនាញរបស់យើងកាន់តែប្រសើរឡើងត្រឹមតែដំណើរការលេងហើយកែលម្អអាកប្បកិរិយារបស់យើង។
## [សំណួរពីមុនវគ្គបង្រៀន](https://ff-quizzes.netlify.app/en/ai/quiz/43)
ដើម្បីអនុវត្ត RL យើងត្រូវការជាភាគី៖
* **បរិយាកាស****កម្មវិធីសមកម្ម** ដែលកំណត់ច្បាប់នៃហ្គេម។ យើងគួរតែអាចដំណើរការជាធម្មតានៅក្នុងកម្មវិធីសមកម្មហើយមើលលទ្ធផលបាន។
* មុខងារប្រាក់រង្វាន់មួយ ដែលបង្ហាញពីកំរិតជោគជ័យនៃសាកល្បងរបស់យើង។ ក្នុងករណីនៃការសិក្សាលេងហ្គេមកុំព្យូទ័រ ប្រាក់រង្វាន់គឺជาคะแนนចុងក្រោយរបស់យើង។
ដោយផ្អែកលើមុខងារប្រាក់រង្វាន់ យើងគួរអាចកែប្រែអាកប្បកិរិយារបស់យើង និងបង្កើនជំនាញ ដើម្បីលេងបានកាន់តែល្អនៅលើជំហានក្រោយ។ ភាពខុសគ្នាចម្បងរវាងការសិក្សាម៉ាស៊ីនប្រភេទផ្សេងៗ និង RL គឺនៅក្នុង RL យើងមិនស្គាល់ថាយើងឈ្នះ ឬបរាជ័យរហូតដល់ចប់ហ្គេមទេ។ ដូច្នេះមិនអាចនិយាយបានថា ចលនាអេទែលមួយគឺល្អ ឬមិនល្អទេ — យើងទទួលបានប្រាក់រង្វាន់តែចុងក្រោយប៉ុណ្ណោះ។
នៅពេលធ្វើ RL យើងធ្វើជាច្រើនករណីសាកល្បង។ នៅក្នុងរាល់ការសាកល្បង យើងត្រូវលំអៀងចំណុចរវាងការតាមដានយុទ្ធសាស្ត្រដែលបានសិក្សារួចហើយ (**ការប្រើប្រាស់**) និងការស្វែងរកស្ថានភាពថ្មីៗ (**ការស្រាវជ្រាវ**)។
## OpenAI Gym
ឧបករណ៍ដ៏អស្ចារ្យសម្រាប់ RL គឺ [OpenAI Gym](https://gym.openai.com/) - បរិយាកាសសមកម្មមួយ ដែលអាចសមកម្មបានបរិយាកាសនានារាប់ពីហ្គេម Atari ដល់រូបវិទ្យាជំនួសហត្ថបន្ទាត់។ វា គឺជាបរិយាកាសសមកម្មដែលពេញនិយមមួយសម្រាប់បណ្ដុះបណ្ដាលអាល់ហ្គរីធម៍សំរបសំរួលដោយជំនឿជាក់ ហើយត្រូវបានគ្រប់គ្រងដោយ [OpenAI](https://openai.com/)។
> **ចំណាំ**៖ អ្នកអាចមើលបរិយាកាសទាំងអស់ដែលមាននៅក្នុង OpenAI Gym [នៅទីនេះ](https://gym.openai.com/envs/#classic_control)។
## ការសមតុល្យ CartPole
អ្នកប្រហែលជាបានឃើញឧបករណ៍សមតុល្យទំនើបដូចជា *Segway**Gyroscooters*។ ពួកវាអាចសមតុល្យដោយស្វ័យប្រវត្តិ ដោយកែប្រែជាមួយកង់របស់ពួកវា ដើម្បីឆ្លើយតបនឹងសញ្ញាពីកម្មវិធីវាស់ល្បឿន ឬឧបករណ៍វាស់មុំ (gyroscope)។ ក្នុងផ្នែកនេះ យើងនឹងរៀនពីរបៀបដោះស្រាយបញ្ហាស្រដៀងគ្នាទៀត - គឺការសមតុល្យដល់កំពង់ស្ព័រ។ វាស្រដៀងនឹងស្ថានភាពពេលព្យួរកម្មបង្ហាញល្បែងមួយត្រូវតែសមតុល្យកំពង់ស្ព័រនៅលើដៃរបស់គេ - ប៉ុន្តែការសមតុល្យកំពង់ស្ព័រនេះមានតែម្នាក់ទីតែមួយគត់។
រូបមន្តសមតុល្យបានធ្វើឲ្យសាមញ្ញត្រូវបានគេស្គាល់ថាជាបញ្ហា **CartPole**។ នៅក្នុងពិភព cartpole យើងមានស្លាយបញ្ឈរមួយដែលអាចធ្វើចលនា ឆ្វេងឬស្តាំ ហើយគោលបំណងគឺសមតុល្យកំពង់ស្ព័រនៅផ្នែកលើស្លាយនៅពេលវាចលនា។
<img alt="a cartpole" src="../../../../../translated_images/km/cartpole.f52a67f27e058170.webp" width="200"/>
ដើម្បីបង្កើត និងប្រើប្រាស់បរិយាកាសនេះ យើងត្រូវការបន្ទាត់ Python ប៉ុន្មានខ្ទង់៖
```python
import gym
env = gym.make("CartPole-v1")
env.reset()
done = False
total_reward = 0
while not done:
env.render()
action = env.action_space.sample()
observaton, reward, done, info = env.step(action)
total_reward += reward
print(f"Total reward: {total_reward}")
```
បរិយាកាសមួយៗអាចចូលដំណើរការ​បាន​ដោយ​របៀបដូចគ្នា៖
* `env.reset` ចាប់ផ្តើមការសាកល្បងថ្មី
* `env.step` អនុវត្តជំហានសមកម្មមួយ។ វាទទួល **សកម្មភាព** មកពី **លំហសកម្មភាព** ហើយតបតាមការសង្កេតមួយ (ពីលំហសង្កេត), រួមមានប្រាក់រង្វាន់ និងស្លាកបញ្ចប់។
នៅក្នុងឧទាហរណ៍ខាងលើ យើងអនុវត្តសកម្មភាពចៃដន្យក្នុងរាល់ជំហាន ដូច្នេះជីវិតនៃការសាកល្បងមានរយៈពេលខ្លីណាស់៖
![non-balancing cartpole](../../../../../lessons/6-Other/22-DeepRL/images/cartpole-nobalance.gif)
គោលបំណងនៃអាល់ហ្គរីធម៍ RL គឺបណ្តុះបណ្តាលគំរូមួយ ដដែលហៅថា **នីតិកម្ម** &pi; — ដែលនឹងតបសកម្មភាពមួយមកវិញនៅក្នុងស្ថានភាព។ យើងក៏អាចយកនីតិកម្មឲ្យមានលក្ខណៈប្រូបាប៊ីលីស្ទិច បាន ផងដែរ។ ឧ. សម្រាប់ស្ថានភាព *s* និងសកម្មភាព *a* វានឹងតបតាមប្រូបាប៊ីលីស្ទិច &pi;(*a*|*s*) ដែលយើងគួរតែអនុវត្ត *a* នៅស្ថានភាព *s*
## អាល់ហ្គរីធម៍តុល្យភាពនីតិកម្ម (Policy Gradients)
វិធីតែមួយច្បាស់លាស់ក្នុងការគំរូនីតិការសិក្សាគឺបង្កើតបណ្ដាញប្រសាទច្នៃម៉ាស៊ីនដែលទទួលស្ថានភាពជាបញ្ចូល ហើយបញ្ចេញសកម្មភាពដែលសមរម្យ (ឬប្រូបាប៊ីលីតាំងនៃសកម្មភាពទាំងមូល)។ នៅក្នុងអារម្មណ៍មួយ វាស្រដៀងនឹងការដាក់ចំណាត់ថ្នាក់ធម្មតាមួយ ប៉ុន្តែភាពខុសគ្នាចម្បងគឺ យើងមិនស្គាល់ជាមុនថា តើនៅក្នុងជំហានណាមួយ យើងគួរតែចាប់ផ្តើមអ្វី។
គំនិតនៅទីនេះគឺប៉ាន់ប្រមានប្រូបាប៊ីលីតាំងនោះ។ យើងកសាងវ៉ិចទ័រនៃ **ប្រាក់រង្វាន់សរុប** ដែលបង្ហាញប្រាក់រង្វាន់សរុបរបស់យើងនៅរាល់ជំហាននៃសាកល្បង។ យើងក៏អនុវត្ត **ការបញ្ចុះតម្លៃប្រាក់រង្វាន់** ដោយគុណប្រាក់រង្វាន់មុនដោយមួយកូអឹស្យង់ &gamma;=0.99 ដើម្បីបន្ថយតួនាទីនៃប្រាក់រង្វាន់កាលពីមុន។ បន្ទាប់មក យើងបញ្ជាក់ទ្រទ្រង់ទៅលើជំហាននៅក្នុងផ្លូវសាកល្បងដែលផ្តល់ប្រាក់រង្វាន់ធំជាង។
> រៀនបន្ថែមអំពីអាល់ហ្គរីធម៍ Policy Gradient ហើយមើលវាពិតប្រាកដក្នុង [សៀវភៅជាក់លាក់](CartPole-RL-TF.ipynb)។
## អាល់ហ្គរីធម៍ Actor-Critic
ជំនាន់កែលម្អនៃវីធី Policy Gradients មានឈ្មោះថា **Actor-Critic**។ គំនិតសំខាន់នៅពីក្រោយវាគឺថាបណ្ដាញប្រសាទនឹងត្រូវបណ្តុះបណ្តាលឲ្យបញ្ចេញពីរព័ត៌មាន៖
* នីតិកម្ម ដែលកំណត់ថាតើត្រូវធ្វើសកម្មភាពអ្វី។ ផ្នែកនេះហៅថា **actor**
* ការប៉ាន់ប្រមាណប្រាក់រង្វាន់សរុបដែលយើងអាចរំពឹងទុកបាននៅស្ថានភាពនេះ — ផ្នែកនេះហៅថា **critic**
ក្នុងអារម្មណ៍មួយ សំណង់នេះស្រដៀងនឹង [GAN](../../4-ComputerVision/10-GANs/README.md) ដែលយើងមានបណ្ដាញពីរដែលបណ្ដុះបណ្ដាលប្រឆាំងគ្នា។ ក្នុងគំរូ actor-critic, actor ផ្តល់សកម្មភាពដែលយើងត្រូវធ្វើ ហើយ critic ព្យាយាមធ្វើតម្លៃវិជ្ជមាន និងប៉ាន់ប្រមាណលទ្ធផល។ ទោះបីជាយើងមានគោលដៅបណ្តុះបណ្ដាលបណ្ដាញទាំងពីរបញ្ចូលគ្នា។
ដោយសារយើងស្គាល់ទាំងប្រាក់រង្វាន់សរុបពិតប្រាកដ និងលទ្ធផលដែលវិភាគដោយ critic ក្នុងពេលនៃសាកល្បង វាជារឿងងាយស្រួលក្នុងការបង្កើតមុខងារបាត់បង់ ដែលនឹងបន្ថយភាពខុសគ្នារវាងពួកវា។ នេះហៅថា **critic loss**។ យើងអាចគណនាបាត់បង់ **actor loss** ដោយប្រើផ្លូវដដែលដូចជាក្នុងអាល់ហ្គរីធម៍ policy gradient។
បន្ទាប់ពីរត់អាល់ហ្គរីធម៍មួយក្នុងនោះ យើងអាចរំពឹងថា CartPole នឹងមានការប្រព្រឹត្តទៅដូចនេះ៖
![a balancing cartpole](../../../../../lessons/6-Other/22-DeepRL/images/cartpole-balance.gif)
## ✍️ ផ្តល់ការហ្វឹកហាត់៖ Policy Gradients និង Actor-Critic RL
បន្តការសិក្សារបស់អ្នកនៅក្នុងសៀវភៅបណ្តុះបណ្តាលខាងក្រោម៖
* [RL ក្នុង TensorFlow](CartPole-RL-TF.ipynb)
* [RL ក្នុង PyTorch](CartPole-RL-PyTorch.ipynb)
## បេសកកម្ម RL ផ្សេងទៀត
ការសំរបសំរួលដោយជំនឿជាក់ (Reinforcement Learning) កំពុងរីកចម្រើនយ៉ាងឆាប់រហ័សនៅថ្ងៃនេះ។ ឧទាហរណ៍គួរឱ្យចាប់អារម្មណ៍ខ្លះៗរបស់ RL មានដូចជា៖
* បង្រៀនកុំព្យូទ័រឱ្យលេង **ហ្គេម Atari**។ ចំណុចតំបន់ពិបាកនៅក្នុងបញ្ហានេះគឺយើងមិនមានស្ថានភាពសាមញ្ញជាវ៉ិចទ័រ ប៉ុន្តែជារូបភាពផ្ទេស្រប ដែលយើងត្រូវប្រើ CNN ដើម្បីបម្លែងរូបភាពនេះទៅជាវ៉ិចទ័រពហុលក្ខណៈ ឬដកស្រង់ពត៌មានប្រាក់រង្វាន់។ ហ្គេម Atari មានឲ្យប្រើនៅក្នុង Gym។
* បង្រៀនកុំព្យូទ័រឱ្យលេងហ្គេមក្តារ ដូចជា កាសុី និង Go។ កម្មវិធីដល់កំពូល​ដូចជា **Alpha Zero** ត្រូវបានបណ្តុះបណ្តាលពីគ្មានអ្វី ដោយភាគីពីរលេងប្រកួតគ្នាខ្ទង់ជា​ស្ទើរ និងកែលម្អជាប់ជានិច្ច។
* នៅក្នុងឧស្សាហកម្ម RL ត្រូវបានប្រើដើម្បីបង្កើតប្រព័ន្ធត្រួតពិនិត្យចេញពីកម្មវិធីសមកម្ម។ សេវាកម្មមួយហៅថា [Bonsai](https://azure.microsoft.com/services/project-bonsai/?WT.mc_id=academic-77998-cacaste) ត្រូវបានរចនាពិសេសសម្រាប់កម្មវិធីនេះ។
## សេចក្ដីសន្និដ្ឋាន
ឥឡូវនេះ យើងបានរៀនពីរបៀបបណ្ដុះបណ្ដាលរត់យន្តឲ្យទទួលបានលទ្ធផលល្អ ត្រឹមតែផ្តល់ពួកគេនូវមុខងារប្រាក់រង្វាន់ដែលកំណត់ស្ថានភាពចង់បាននៃហ្គេម ហើយផ្តល់ឱកាសឲ្យពួកគេចូលចិត្តស្វែងរកចន្លោះស្វែងរកយ៉ាងមានឆ្លាត។ យើងបានប្រើសមាភាគទាំងពីរដោយជោគជ័យ ហើយទទួលបានលទ្ធផលល្អក្នុងរយៈពេលខ្លីមួយ។ ទោះជាយ៉ាងណា នេះគឺជាចាប់ផ្តើមនៃដំណើររបស់អ្នកក្នុង RL ហើយអ្នកគួរតែចូលចិត្តចូលរួមថ្នាក់បណ្តុះបណ្តាលផ្សេងទៀត ប្រសិនបើចង់ស្វែងយល់ជ្រៅទៀត។
## 🚀 thách thức
ស្វែងយល់ពីកម្មវិធីដែលបានរាយការណ៍ក្នុងផ្នែក 'បេសកកម្ម RL ផ្សេងទៀត' ហើយព្យាយាមអនុវត្តមួយ!
## [សំណួរពេលបញ្ចប់វគ្គបង្រៀន](https://ff-quizzes.netlify.app/en/ai/quiz/44)
## ពិនិត្យឡើងវិញ និងសិក្សាផ្ទាល់ខ្លួន
សូមរៀនបន្ថែមអំពីការសំរបសំរួលដោយជំនឿជាក់ classical នៅក្នុង [កម្មវិធីបណ្តុះបណ្តាល Machine Learning សម្រាប់អ្នកចាប់ផ្តើម](https://github.com/microsoft/ML-For-Beginners/blob/main/8-Reinforcement/README.md) ។
មើល [វីដេអូដ៏អស្ចារ្យនេះ](https://www.youtube.com/watch?v=qv6UVOQ0F44) ដែលពិភាក្សាអំពីរបៀបដែលកុំព្យូទ័រអាចរៀនលេង Super Mario។
## កិច្ចការផ្សាយ៖ [បណ្ដុះបណ្ដាលឡានភ្នំ](lab/README.md)
គោលបំណងរបស់អ្នកក្នុងកិច្ចការនេះគឺបណ្ដុះបណ្ដាលបរិយាកាស Gym ផ្សេងទៀត — [Mountain Car](https://www.gymlibrary.ml/environments/classic_control/mountain_car/)।
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការយោង**:
ឯកសារនេះត្រូវបានបកប្រែដោយសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេលយើងខិតខំរកភាពត្រឹមត្រូវ សូមដឹងថា ការបកប្រែដោយស្វ័យប្រវត្តិអាចមានកំហុសឬភាពមិនត្រឹមត្រូវ។ ឯកសារដើមដែលមានភាសាតំបន់មូលដ្ឋានគួរត្រូវបានគេពិចារណា ជា ប្រភពដែលមានអំណាច។ សម្រាប់ព័ត៌មានសំខាន់ ប្រសិនបើមាន សូមកុំភ្លេចប្រើការបកប្រែដោយអ្នកជំនាញមនុស្ស។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកស្រាយខុសព្រោះពីការប្រើប្រាស់ការបកប្រែនេះឡើយ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,105 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# # បណ្តុះបណ្តាល Mountain Car ឲ្យគេចចេញ\n",
"\n",
"កិច្ចការពិសោធន៍ពី [កម្មវិធីសិក្សា AI សម្រាប់អ្នកចាប់ផ្តើម](https://github.com/microsoft/ai-for-beginners).\n",
"\n",
"គោលបំណងរបស់អ្នកគឺបណ្តុះភ្នាក់ងារ RL ដើម្បីគ្រប់គ្រង [Mountain Car](https://www.gymlibrary.ml/environments/classic_control/mountain_car/) ក្នុងបរិស្ថាន OpenAI។\n",
"\n",
"ចាប់ផ្តើមដោយបង្កើតបរិស្ថាន:\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import gym\n",
"env = gym.make('MountainCar-v0')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"មកមើលថា ពិសោធន៍ចៃដន្យនេះមើលដូចម្តេច៖\n"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"state = env.reset()\n",
"while True:\n",
" env.render()\n",
" action = env.action_space.sample()\n",
" state, reward, done, info = env.step(action)\n",
" if done:\n",
" break"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"ឥឡូវនេះសៀវភៅកំណត់ត្រានេះជារបស់អ្នកទាំងអស់ - អ្នកអាចយកអាល់ហ្គរីធម៍ Policy Gradients និង Actor-Critic ពីមេរៀនមកអនុវត្តលើបញ្ហានេះបានដោយសេរី!\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"## Lost of code here"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"env.close()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n\n<!-- CO-OP TRANSLATOR DISCLAIMER START -->\n**ការមិនទទួលខុសត្រូវ**:\nឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាកម្មបកប្រែដោយស្វ័យប្រវត្តិ (AI) [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈដែលយើងខិតខំសម្រាប់ភាពត្រឹមត្រូវ សូមចំណាំថាការបកប្រែដោយស្វ័យប្រវត្តិអាចមានកំហុស ឬមិនត្រឹមត្រូវបានខ្លះ។ ឯកសារដើមក្នុងភាសាទីមួយគួរត្រូវបានចាត់ទុកជាប្រភពដែលអាចទុកចិត្តបាន។ សម្រាប់ព័ត៌មានសំខាន់ៗ យើងណែនាំឱ្យប្រើការបកប្រែដោយអ្នកបកប្រែជាមនុស្សដែលមានវិជ្ជាជីវៈ។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកយល់ខុសណាមួយដែលបណដាលមកពីការប្រើប្រាស់ការបកប្រែនេះ។\n<!-- CO-OP TRANSLATOR DISCLAIMER END -->\n"
]
}
],
"metadata": {
"interpreter": {
"hash": "16af2a8bbb083ea23e5e41c7f5787656b2ce26968575d8763f2c4b17f9cd711f"
},
"kernelspec": {
"display_name": "Python 3.8.12 ('py38')",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.12"
}
},
"nbformat": 4,
"nbformat_minor": 4
}

View File

@ -0,0 +1,28 @@
# រៀនបង្រៀនឡានភ្នំឲ្យគេចបានចេញ
ភារកិច្ចមន្ទីរ​សិក្សា​ពី [AI សម្រាប់អ្នកចាប់ផ្តើម Curriculum](https://github.com/microsoft/ai-for-beginners)។
## បំណងការ
គោលបំណងរបស់អ្នកគឺបង្រៀនភ្នាក់ងាររបៀបរៀន (RL) ដើម្បីគ្រប់គ្រង [ឡានភ្នំ](https://www.gymlibrary.ml/environments/classic_control/mountain_car/) ក្នុងបរិយាកាស OpenAI។
<img alt="Mountain Car" src="../../../../../../translated_images/km/mountaincar.f7b7a7f6d4f9933b.webp" width="300"/>
## បរិយាកាស
បរិយាកាសឡានភ្នំមានឡានត្រូវចងខ្សែក្នុងវាលភ្នំ។ គោលបំណងរបស់អ្នកគឺត្រូវលោតចេញពីវាលភ្នំនិងឈានដល់ទង់ជាតិក្នុងភ្នំ។ សកម្មភាពដែលអ្នកអាចធ្វើបានរួមមាន កំចាត់ឡានទៅខាងឆ្វេង ខាងស្តាំ ឬមិនធ្វើអ្វីទេ។ អ្នកអាចមើលឃើញទីតាំងឡានតាមអ័ក្ស x និងល្បឿន។
## សៀវភៅកំណត់ត្រាដំបូង
ចាប់ផ្តើមលំហាត់ដោយបើក [MountainCar.ipynb](MountainCar.ipynb)
## អ្វីដែលរៀនបាន
អ្នកគួរតែរៀននៅពេលបង្រៀននេះថា ការព្យាយាមប្រើអាល់ហ្គរីធម៌ RL ទៅបរិយាកាសថ្មី ជាការ៉ឺត្បិតងាយស្រួល ជាពិសេសដោយសារបរិយាកាស OpenAI Gym មានរបៀបធ្វើការដូចគ្នាសម្រាប់បរិយាកាសទាំងអស់ ហើយអាល់ហ្គរីធម៍ទាំងនោះមិនពឹងផ្អែកយ៉ាងខ្លាំងលើធម្មជាតិនៃបរិយាកាសទេ។ អ្នកអាចរៀបចំកូដ Python ជារបៀបដែលអាចផ្ទេរបរិយាកាសណាមួយទៅអាល់ហ្គរីធម៍ RL ជាប៉ារ៉ាម៉ែត្រ។
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការលើកចិត្តផ្សា**៖
ឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេលដែលយើងខិតខំផ្តល់នូវភាពត្រឹមត្រូវ សូមចំណាំថាការបកប្រែដោយស្វ័យប្រវត្តិអាចមានកំហុសឬភាពមិនត្រឹមត្រូវ។ ឯកសារដើមក្នុងភាសាមាតុភូមិរបស់វាគួរត្រូវបានគេទទួលស្គាល់ថាជាប្រភពដែលមានសិទ្ធិលើព័ត៍មាន។ សម្រាប់ព័ត៍មានមានសារៈសំខាន់ ការបកប្រែដោយមនុស្សអ្នកជំនាញត្រូវបានណែនាំ។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកស្រាយខុសពីការប្រើប្រាស់ការបកប្រែនេះឡើយ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,159 @@
# ប្រព័ន្ធអ្នកប្រតិបត្តិការច្រើន
វិធីមួយក្នុងការសម្រេចបានលទ្ធភាពប្រសើរគឺ​វិធីសាស្រ្ត​ដែលហៅថា **emergent** (ឬ **synergetic**) ដែលផ្អែកលើភាពជាការពិតថា​ សកម្មភាពរួមគ្នារបស់អ្នកប្រតិបត្តិការច្រើនដែលមានភាពសាមញ្ញ អាចបណ្តាលឱ្យមានសកម្មភាពស្មុគស្មាញ (ឬ​មានប្រាជ្ញា) ទាំងមូលរបស់ប្រព័ន្ធ។ ជាទស្សនវិជ្ជា វាផ្អែកលើគោលការណ៍នៃ [ការបញ្ញាសមាស](https://en.wikipedia.org/wiki/Collective_intelligence), [ការកើតទំព័រ](https://en.wikipedia.org/wiki/Global_brain) និង [Evolutionary Cybernetics](https://en.wikipedia.org/wiki/Global_brain) ដែលវាសន្និដ្ឋានថាប្រព័ន្ធកម្រិតខ្ពស់ទទួលបានតម្លៃបន្ថែមមួយពីការរួមបញ្ចូលគ្នាសមរម្យពីប្រព័ន្ធកម្រិតទាប (ដែលហៅថា *គោលការណ៍ផ្លូវចិត្តរបស់ metasystem transition*)។
## [តេស្តមុនមេរៀន](https://ff-quizzes.netlify.app/en/ai/quiz/45)
ទិសដៅនៃ **ប្រព័ន្ធអ្នកប្រតិបត្តិការច្រើន** បានកើតឡើងក្នុង AI នៅឆ្នាំ 1990s ជាចម្លើយដល់ការរីកចម្រើនរបស់អ៊ីនធឺណិត និងប្រព័ន្ធចែកចាយ។ សៀវភៅសិក្សា AI ផ្លូវចាស់មួយ អត្ថបទ [Artificial Intelligence: A Modern Approach](https://en.wikipedia.org/wiki/Artificial_Intelligence:_A_Modern_Approach) ផ្តោតលើទស្សនៈនៃ AI ផ្លូវចាស់ពីមุมមองប្រព័ន្ធអ្នកប្រតិបត្តិការច្រើន។
ចំណុចដែលសំខាន់ក្នុងវិធីរបស់អ្នកប្រតិបត្តិការច្រើនគឺ​ **Agent** - អង្គភាពមួយដែលរស់នៅក្នុង **បរិយាកាស** មួយ ដែលវាអាចទទួលបានការយល់ដឹង និងអនុវត្តសកម្មភាពលើវា។ នេះជាការពិពណ៌នាធំទូលាយ ហើយអាចមានប្រភេទ និងចំណាត់ថ្នាក់នៃអាជីពជាច្រើន៖
* ដោយសមត្ថភាពក្នុងការតុល្យ:
- អ្នកប្រតិបត្តិការ **Reactive** ជាទូទៅមានទ្រឹស្តីសំណើ-ឆ្លើយចម្លងសាមញ្ញ
- អ្នកប្រតិបត្តិការ **Deliberative** ប្រើប្រាស់តុល្យាការ និង/ឬសមត្ថភាពផែនការ
* ដោយកន្លែងដែលអ្នកប្រតិបត្តិការ​ដំណើរការកូដរបស់ខ្លួន:
- អ្នកប្រតិបត្តិការ **Static** ចំណីកូដនៅ Node បណ្តាញដាច់ខាតមួយ
- អ្នកប្រតិបត្តិការ **Mobile** អាចផ្លាស់ទីកូដរបស់ខ្លួននៅក្នុង Node បណ្តាញផ្សេងៗ
* ដោយសេចក្ដីឥរិយាបថរបស់ពួកគេ:
- អ្នកប្រតិបត្តិការ **Passive** មិនមានគោលបំណងជាក់លាក់ទេ។ អ្នកប្រតិបត្តិការ់បែបនេះអាចឆ្លើយតបទៅនឹងរំញោចខាងក្រៅ ប៉ុន្តាមិនចាប់ផ្តើមសកម្មភាពផ្ទាល់ខ្លួនឡើយ
- អ្នកប្រតិបត្តិការ **Active** មានគោលបំណងមួយចំនួនដែលពួកគេចុះបញ្ជូល
- អ្នកប្រតិបត្តិការ **Cognitive** បញ្ចូលផែនការ និងតុល្យស្មារតីស្មុគស្មាញ
ប្រព័ន្ធអ្នកប្រតិបត្តិការច្រើនទៅហើយត្រូវបានប្រើប្រាស់នៅក្នុងកម្មវិធីជាច្រើន៖
* ក្នុងហ្គេម ឥរិយាបថនៃតួអង្គមិនមែនជាកីឡាករម្នាក់ៗប្រើប្រាស់លទ្ធភាព AI មួយចំនួន និងអាចត្រូវបានគេឆ្លងកាត់ជាអ្នកប្រតិបត្តិការប្រកបដោយប្រាជ្ញា
* ក្នុងការផលិតវីដេអូ ការបង្ហាញសេណារី 3D ស្មុគស្មាញដែលពាក់ព័ន្ធទៅនឹងជាក្រុមធម្មតាត្រូវបានធ្វើជាទូទៅដោយប្រើការសាំញ៉ាញ់អ្នកប្រតិបត្តិការច្រើន
* ក្នុងម៉ូដែលប្រព័ន្ធវេចខ្ចប់ វិធីអ្នកប្រតិបត្តិការច្រើនត្រូវបានប្រើដើម្បីសាំញ៉ាញ់ឥរិយាបថនៃម៉ូដែលស្មុគស្មាញមួយ។ ឧទាហរណ៍ វិធីនេះត្រូវបានប្រើជោគជ័យក្នុងការព្យាករណ៍ការរីករាលដាលជម្ងឺ COVID-19 នៅជុំវិញពពកលោក។ វិធីសាស្រ្តដូចគ្នាក៏អាចត្រូវបានប្រើដើម្បីម៉ូដែលចរាចរណ៍ក្នុងទីក្រុង និងមើលថាតើវាប្ដូរយ៉ាងដូចម្តេចចំពោះការផ្លាស់ប្តូរក្បួនចរាចរណ៍។
* ក្នុងប្រព័ន្ធស្វ័យប្រវត្តស្មុគស្មាញ ឧបករណ៍នីមួយៗអាចដំណើរការជាអ្នកប្រតិបត្តិការឯករាជ្យ ដែលធ្វើឱ្យប្រព័ន្ធទាំងមូលមានភាពមិនមួយខ្លួន និងរឹងមាំជាងមុន។
យើងនឹងមិនចំណាយពេលយូរចូលជ្រៅក្នុងប្រព័ន្ធអ្នកប្រតិបត្តិការច្រើនទេ ប៉ុន្តែសូមពិចារណាឧទាហរណ៍មួយនៃ **ម៉ូដែលអ្នកប្រតិបត្តិការច្រើន**
## NetLogo
[NetLogo](https://ccl.northwestern.edu/netlogo/) គឺជាបរិយាកាសម៉ូដែលអ្នកប្រតិបត្តិការច្រើនមួយដែលផ្អែកលើកំណែបំលែងនៃភាសាកម្មវិធី [Logo](https://en.wikipedia.org/wiki/Logo_(programming_language))។ ភាសានេះត្រូវបានអភិវឌ្ឍសម្រាប់បង្រៀនគំនិតកម្មវិធីទៅកុមារ ហើយវាអនុញ្ញាតឱ្យអ្នកគ្រប់គ្រងភ្នាក់ងារដែលហៅថា **turtle** ដែលអាចផ្លាស់ទីបាន ដាក់សតិកំណត់ពីក្រោយ។ វាអនុញ្ញាតឱ្យបង្កើតរូបរាងវិទ្យាសាស្រ្តស្មុគស្មាញ ដែលជាវិធីមើលឃើញយ៉ាងច្បាស់ក្នុងការយល់អំពីអនុវត្តិរបស់ភ្នាក់ងារ។
នៅក្នុង NetLogo យើងអាចបង្កើតពពួក turtles ជាច្រើនដោយប្រើពាក្យបញ្ជា `create-turtles`។ បន្ទាប់មក យើងអាចបញ្ជាទាំង turtles ទាំងអស់ឱ្យអនុវត្តសកម្មភាពមួយ (ក្នុងឧទាហរណ៍ខាងក្រោម - ធ្វើចំនុច 10 ខាងមុខ)៖
```
create-turtles 10
ask turtles [
forward 10
]
```
ប្រាកដណាស់ វាមិនគួរឱ្យចាប់អារម្មណ៍ពេលដែល turtles ទាំងអស់ធ្វើអ្វីបានដូចគ្នាទេ ដូច្នេះយើងអាច `ask` ក្រុមតurtles មួយ ជាឧទាហរណ៍ អ្នកដែលនៅជិតចំណុចជាក់លាក់មួយ។ យើងអាចបង្កើត turtles មួយចំនួននៃ *ពូជ* ផ្សេងគ្នាតាមពាក្យបញ្ជា `breed [cats cat]`។ នៅទីនេះ `cat` ជាឈ្មោះពូជមួយ ហើយយើងត្រូវបញ្ជាក់ពាក្យទាំងឯកេតិយនិងពហុតួ ដោយសារតែបញ្ចា់បញ្ជាពិធីផ្សេងៗប្រើបែបផែនខុសគ្នា ដើម្បីទូលាយច្បាស់។
> ✅ យើងមិនចូលរួមសិក្សាភាសា NetLogo ដោយផ្ទាល់ទេ - អ្នកអាចទស្សនាទៅកាន់ធនធាន [វចនានុក្រមអន្តរកម្មសម្រាប់អ្នកចាប់ផ្តើម NetLogo](https://ccl.northwestern.edu/netlogo/bind/) ប្រសិនបើអ្នកចាប់អារម្មណ៍ស្វែងយល់បន្ថែម។
អ្នកអាច [ទាញយក](https://ccl.northwestern.edu/netlogo/download.shtml) និងដំឡើង NetLogo ដើម្បីសាកល្បង។
### បណ្ណាល័យម៉ូដែល
អ្វីដែលល្អនៅពីក្រោយ NetLogo គឺវាមានបណ្ណាល័យអ្នកម៉ូដែលដែលអាចសាកល្បងបាន។ ទៅកាន់ **File &rightarrow; Models Library** ហើយអ្នកមានប្រភេទម៉ូដែលជាច្រើនជ្រើសរើស។
<img alt="NetLogo Models Library" src="../../../../../translated_images/km/NetLogo-ModelLib.efe023afb4763c05.webp" width="60%"/>
> រូបថតផ្ទាំងបណ្ណាល័យម៉ូដែលដោយ Dmitry Soshnikov
អ្នកអាចបើកម៉ូដែលមួយ ឧទាហរណ៍ **Biology &rightarrow; Flocking**
### គោលការណ៍សំខាន់ៗ
ក្រោយបើកម៉ូដែល អ្នកត្រូវបានយកទៅកាន់ផ្ទាំង NetLogo ប្រើប្រាស់ចម្បង។ នេះគឺជា ម៉ូដែលតំណាងថ្មីសង្ខេប ដែលពិពណ៌នាពីប្រជាជនប្រេះនិងចៀម​ ដែលមានធនធានកំណត់ (ស្មៅ)។
![NetLogo Main Screen](../../../../../translated_images/km/NetLogo-Main.32653711ec1a01b3.webp)
> រូបថតដោយ Dmitry Soshnikov
នៅលើផ្ទាំងនេះ អ្នកអាចមើលឃើញ៖
* ផ្នែក **Interface** ដែលមាន៖
- វាលចម្បង ដែលអ្នកប្រតិបត្តិការទាំងអស់រស់នៅ
- ការគ្រប់គ្រងផ្សេងៗ៖ ប៊ូតុង ស្លាយឌើរ ល។ អោយ
- ក្រាហ្វដែលអាចប្រើសម្រាប់បង្ហាញប៉ារ៉ាម៉ែត្រ នៃការសាំញ៉ាញ់
* តាប **Code** ដែលមានកម្មវិធីកែសម្រួល សម្រាប់វាយបញ្ចូលកម្មវិធី NetLogo
ភាគច្រើន ផ្ទាំងនឹងមានប៊ូតុង **Setup** ដែលដំណើរការស្ថានភាពសាំញ៉ាញ់ និងប៊ូតុង **Go** ដើម្បីចាប់ផ្តើមការអនុវត្ត។ នេះត្រូវបានគ្រប់គ្រងដោយកូដដែលមានដូចខាងក្រោម៖
```
to go [
...
]
```
ពិព័រណ៍ NetLogo ប្រហែលមានវត្ថុដូចខាងក្រោម៖
* **Agents** (turtles) ដែលអាចផ្លាស់ទីនៅលើវាល ហើយអាចអនុវត្តអ្វីមួយ។ អ្នកបញ្ជាអ្នកប្រតិបត្តិការដោយប្រើ `ask turtles [...]` និងកូដក្នុងគន្លងនោះអនុវត្តដោយអ្នកប្រតិបត្តិការទាំងអស់ក្នុង *របៀប turtle mode*
* **Patches** ជាតំបន់ជាមួយចំហៀងសម្រាប់វាល ដែលអ្នកប្រតិបត្តិការស្នាក់នៅលើវា។ អ្នកអាចយោងទាំងអស់អ្នកប្រតិបត្តិការនៅលើ patch តែមួយ ឬ អ្នកអាចផ្លាស់ប្តូរពណ៌ patch និងលក្ខណៈផ្សេងៗ។ អ្នកក៏អាច `ask patches` ឲ្យអនុវត្តអ្វីមួយ។
* **Observer** គឺជាអ្នកប្រតិបត្តិចម្រុះម្នាក់ដែលគ្រប់គ្រងពិភពលោក។ អ្នកចុចប៊ូតុងទាំងអស់អនុវត្តនៅក្នុង *ម៉ូដ observer*
> ✅ សោភ័ណភាពនៃបរិយាកាសអ្នកប្រតិបត្តិការច្រើនគឺ​ កូដដែលដំណើរការនៅលើ turtle mode ឬ patch mode នឹងត្រូវដំណើរការប្រកបដោយសមកម្មដោយអ្នកទាំងអស់នៅពេលនាព្រហ្មទាំងស្រុង។ ដូច្នេះ ដោយសរសេរកូដតិចតួច ហើយកម្មវិធីអំពីឥរិយាបថអ្នកប្រតិបត្តិការផ្ទាល់ម្នាក់ អ្នកអាចបង្កើតឥរិយាបថស្មុគស្មាញរបស់ប្រព័ន្ធសាំញ៉ាញ់គ្រួសារទាំងមូល។
### Flocking
ជាឧទាហរណ៍នៃឥរិយាបថអ្នកប្រតិបត្តិការច្រើន នាំមក xem xét **[Flocking](https://en.wikipedia.org/wiki/Flocking_(behavior))**។ Flocking គឺជាគំរូស្មុគស្មាញដែលស្រដៀងនឹងរបៀបក្រុមមាន់បក្សជាតិក្រោម មើលពួកវាហោះហើរ អ្នកអាចគិតថាពួកវាអនុវត្តកាលកំណត់ស្គាល់មួយចំនួន រឺថាពួកវាមានប្រយោជន៍ខាងប្រាជ្ញា។ ទោះជាយ៉ាងណា អ្នកប្រតិបត្តិការផ្ទាល់ម្នាក់ (នៅទីនេះគឺ *មាន់*) ធ្វើការសង្កេតអ្នកប្រតិបត្តិការផ្សេងនៅចម្ងាយខ្លីៗ ហើយអនុវត្តតាមច្បាប់សាមញ្ញបី៖
* **Alignment** - វាផ្លាស់ទីទៅភាគរយដឹកនាំជាសាមញ្ញរបស់អ្នកជិតខាង
* **Cohesion** - វាខំប្រឹងផ្លាស់ទីទៅកាន់ទីតាំងភាគរយមធ្យមនៃអ្នកជិតខាង (*ទាក់ទាញចម្ងាយយូរ*)
* **Separation** - បើវាប្រហែលជា​ជិតខ្លាំងទៅដល់មាន់ផ្សេង វាខំប្រឹងផ្លាស់ទីឲ្យឆ្ងាយ (*ទម្លាក់ចម្ងាយខ្លី*)
អ្នកអាចដំណើរការ Flocking និងមើលឥរិយាបថ។ អ្នកក៏អាចកំណត់ប៉ារ៉ាម៉ែត្រ ដូចជា *កម្រិតបំបែក**ជួរមើល* ដែលកំណត់ទម្ងន់ការមើលនៃមាន់ម្នាក់មួយ។ សំគាល់ថាបើអ្នកបន្ថយជួរមើលទៅសូន្យ មិនមានមាន់មួយណាអាចមើលឃើញ ទោះបីជា flocking រអស់។ បើបន្ថយការបំបែកទៅសូន្យ ផ្លូវមាន់ទាំងអស់នឹងមកជួរត្រង់។
> ✅ ផ្លាស់ទៅតាប **Code** ហើយមើលកន្លែងដែលច្បាប់បីនៃ flocking (alignment, cohesion និង separation) ត្រូវបានអនុវត្តនៅក្នុងកូដ។ សូមចំណាំថាយើងយោងតែអ្នកដែលនៅក្នុងទស្សនៈតែប៉ុណ្ណោះ។
### ម៉ូដែលផ្សេងទៀតសម្រាប់មើល
មានម៉ូដែលគួរឲ្យចាប់អារម្មណ៍ផ្សេងទៀតដែលអ្នកអាចសាកល្បងបាន៖
* **Art &rightarrow; Fireworks** បង្ហាញពីរបៀបដែល ភ្លើងលើឈើអាចត្រូវបានគេចាត់ទុកជាឥរិយាបថរួមរបស់ចរន្តភ្លើងផ្ទាល់ខ្លួន
* **Social Science &rightarrow; Traffic Basic** និង **Social Science &rightarrow; Traffic Grid** បង្ហាញម៉ូដែលចរាចរណ៍ទីក្រុងក្នុងមាត្រា 1D និង 2D Grid មានឬគ្មានសញ្ញាស្ទិប។ ឡានរាល់គ្រឿងនៅក្នុងសាំញ៉ាញ់ទាំងអស់អនុវត្តតាមច្បាប់ខាងក្រោម៖
- ប្រសិនបើគេហៅទំហំពីមុខទំនេរ - ល្បឿនឡើង (រហូតដល់ល្បឿនអប្បបរមាមួយ)
- ប្រសិនបើគេឃើញឧបសគ្គពីមុខ - បោះបង់ (និងអ្នកអាចកំណត់យ៉ាងហោចណាស់ថាអ្នកបើកបរ​អាចមើលឃើញឆ្ងាយប៉ុណ្ណា)
* **Social Science &rightarrow; Party** បង្ហាញរបៀបដែលមនុស្សក្រុមគ្នាជាមួយគ្នាផ្នែកពេលរាត្រីខារ៉ាអូខេមួយ។ អ្នកអាចស្វែងរករបៀបភ្ជាប់ចាប់គ្នានៃប៉ារ៉ាម៉ែត្រ ដែលនាំឲ្យមានការកើនឡើងលឿននៃក្ដីសប្បាយរីករាយនៃក្រុម។
ដូចដែលអ្នកបានឃើញពីឧទាហរណ៍ទាំងនេះ ការសាំញ៉ាញ់អ្នកប្រតិបត្តិការច្រើនអាចជាវិធីមានប្រយោជន៍សម្រាប់យល់ពីឥរិយាបថនៃប្រព័ន្ធស្មុគស្មាញដែលមានបុគ្គលជាច្រើនដែលអនុវត្តតាមគោលការណ៍ដូចគ្នា ឬស្រដៀងគ្នា។ វាក៏អាចត្រូវបានប្រើដើម្បីគ្រប់គ្រងភ្នាក់ងារឌីជីថល ដូចជា [NPCs](https://en.wikipedia.org/wiki/NPC) ក្នុងហ្គេមកុំព្យូទ័រ ឬភ្នាក់ងារនៅក្នុងពិភព 3D រូបភាព
## អ្នកប្រតិបត្តិការដែលមានការតុល្យ
អ្នកប្រតិបត្តិការដែលបានពិពណ៌នាខាងលើ គឺសាមញ្ញណាស់ អ្នកប្រតិបត្តិការเหล่านี้គឺជាអ្នកប្រតិបត្តិការ **វិភាគប្រតិកម្ម**។ ប៉ុន្តែពេលខ្លះ អ្នកប្រតិបត្តិការអាចមានសមត្ថភាពតុល្យ និងផែនការសកម្មភាព ដូច្នេះវាត្រូវបានគេហៅថា **អ្នកប្រតិបត្តិការដែលមានការតុល្យ**
ឧទាហរណ៍ធម្មតា គឺជាភ្នាក់ងារផ្ទាល់ខ្លួនមួយ ដែលទទួលបានកំណត់ពីមនុស្សម្នាក់ ដើម្បីកក់ការធ្វើដំណើរថ្មីៗ។ សន្និដ្ឋានថា មានអ្នកប្រតិបត្តិការច្រើនក្នុងអ៊ីនធឺណិត អ្នកណាមួយអាចជួយវា។ វាគួរតែនឹងទាក់ទងអ្នកជំនួយផ្សេងៗ ដើម្បីស្ទាបើកាបានតម្លៃសំបុត្រយន្តហោះនេះសុទ្ធតែមាន អ្វីជាតម្លៃសណ្ឋាគារនៅតាមកាលបរិច្ឆេទផ្សេងៗ ហើយព្យាយាមចរចាតម្លៃល្អបំផុត។ ពេលផែនការធ្វើដំណើរនេះរួចរាល់ និងបានបញ្ជាក់ដោយម្ចាស់កម្មសិទ្ធិ វាអាចបន្តការកក់បាន។
ដើម្បីធ្វើការនេះ អ្នកប្រតិបត្តិការត្រូវការ **ទំនាក់ទំនង**
សម្រាប់ការទំនាក់ទំនងជោគជ័យ ពួកគេត្រូវការ៖
* ភាសាទូទៅមួយចំនួនសម្រាប់ប្តូរស្រោចស្រង់ចំណេះដឹងមួយចំនួន ដូចជា [Knowledge Interchange Format](https://en.wikipedia.org/wiki/Knowledge_Interchange_Format) (KIF) និង [Knowledge Query and Manipulation Language](https://en.wikipedia.org/wiki/Knowledge_Query_and_Manipulation_Language) (KQML)។ ភាសាទាំងនេះត្រូវបានរចនាឡើងដោយផ្អែកលើ [Speech Act theory](https://en.wikipedia.org/wiki/Speech_act)។
* ភាសាទាំងនោះគួរត្រូវរួមបញ្ចូល **ប្រព័ន្ធនៃការចរចា** ដែលផ្អែកលើ ប្រភេទរបៀបលក់វិធីផ្សេងៗ។
* អត្រា **ontology ទូទៅ** ដែលប្រើសម្រាប់យោងទៅតាមគំនិតដូចគ្នា ដែលគេដឹងតែអត្ថន័យរបស់ពួកវា។
* វិធីសាស្រ្តក្នុងការស្វែងរកតើអ្នកប្រតិបត្តិការផ្សេងៗអាចធ្វើអ្វីបាន ខណៈពេលផ្អែកលើ ontology របស់ពួកវា។
អ្នកប្រតិបត្តិការដែលមានការតុល្យស្មុគស្មាញជាង reactive ពីព្រោះពួកគេមិនត្រឹមតែឆ្លើយតបដល់ការផ្លាស់ប្តូរនៅក្នុងបរិយាកាសទេ អ្នកណាគួរតែអាច *ចាប់ផ្តើម* សកម្មភាពបានផងដែរ។ ការរចនាតែមួយសម្រាប់អ្នកប្រតិបត្តិការដែលមានការតុល្យ​ហៅថា Belief-Desire-Intention (BDI) agent៖
* **Beliefs** ជាសំណុំចំណេះដឹងអំពីបរិយាកាស​របស់អ្នកប្រតិបត្តិការ។ វាអាចមានរចនាសម្ព័ន្ធជា អាគារចំណេះដឹង ឬច្បាប់មួយដែលអ្នកប្រតិបត្តិការ​អាចអនុវត្តឲ្យតស៊ូមតិបំពេញស្ថានភាពជាក់លាក់នៅក្នុងបរិយាកាស។
* **Desires** កំណត់អ្វីដែលអ្នកប្រតិបត្តិការ​ចង់ធ្វើ គឺគោលបំណងរបស់ខ្លួន។ ឧទាហរណ៍ គោលបំណងរបស់ភ្នាក់ងារជំនួយផ្ទាល់ខ្លួន ខាងលើ គឺកក់ដំណើរការ ហើយគោលបំណងរបស់ភ្នាក់ងារសណ្ឋាគារគឺបំផុតប្រាក់ចំណេញ។
* **Intentions** ជាសកម្មភាពជាក់លាក់ដែលអ្នកប្រតិបត្តិបញ្ជាំងធ្វើដើម្បីសម្រេចបានគោលបំណងរបស់ខ្លួន។ សកម្មភាពទូទៅផ្លាស់ប្ដូរបរិយាកាស និងបង្កើតការទំនាក់ទំនងជាមួយអ្នកប្រតិបត្តិការផ្សេងទៀត។
មានវេទិកាមួយចំនួនសម្រាប់កសាងប្រព័ន្ធអ្នកប្រតិបត្តិការច្រើន ដូចជា [JADE](https://jade.tilab.com/). [ក្រដាសនេះ](https://arxiv.org/ftp/arxiv/papers/2007/2007.08961.pdf) មានការពិភាក្សាអំពីវេទិកាអ្នកប្រតិបត្តិការច្រើន ជាមួយនឹងប្រវត្តិសង្ខេបនៃប្រព័ន្ធ និងរូបលក្ខណៈការប្រើប្រាស់ផ្សេងៗ។
## សេចក្តីសន្និដ្ឋាន
ប្រព័ន្ធអ្នកប្រតិបត្តិការច្រើនអាចមានទម្រង់ខុសគ្នាហើយត្រូវបានប្រើប្រាស់ក្នុងកម្មវិធីជាច្រើន។ ពួកវាទាំងអស់បុគ្គលិកលើឥរិយាបថសាមញ្ញរបស់អ្នកប្រតិបត្តិការផ្ទាល់ និងទទួលបានឥរិយាបថស្មុគស្មាញជាងមុនរបស់ប្រព័ន្ធទាំងមូល ដោយសារបទពិសោធន៍ **synergetic effect**
## 🚀 챌린지
យកមេរៀននេះកក់ក្តៅទៅកាន់ពិភពពិត និងពិចារណាថាពីសំណុំនៃប្រព័ន្ធអ្នកប្រតិបត្តិការច្រើនមួយ ដែលអាចដោះស្រាយបញ្ហាមួយ។ ឧទាហរណ៍ ប្រព័ន្ធអ្នកប្រតិបត្តិការច្រើនត្រូវតែធ្វើអ្វី ដើម្បីបង្កើតផ្លូវរថយន្តរបស់សាលាបឋម? វាអាចដំណើរការ​យ៉ាងដូចម្តេចនៅក្នុងហាងនំ?
## [តេស្តក្រោយមេរៀន](https://ff-quizzes.netlify.app/en/ai/quiz/46)
## ការត្រួតពិនិត្យ និងការសិក្សាផ្ទាល់ខ្លួន
ពិនិត្យការប្រើប្រាស់ប្រព័ន្ធប្រភេទនេះនៅក្នុងឧស្សាហកម្ម។ ជ្រើសរើសវិស័យមួយដូចជាអាជីវកម្មផលិតកម្ម ឬវិស័យហ្គេមវិដេអូ ហើយស្វែងរកថា ប្រព័ន្ធអ្នកប្រតិបត្តិការច្រើនអាចប្រើសម្រាប់ដោះស្រាយបញ្ហាដ៏ប្លែកៗបានយ៉ាងដូចម្តេច។
## [NetLogo Assignment](assignment.md)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការបង្ហាញការទទួលខុសត្រូវ**៖
ឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ នៅពេលដែលយើងខិតខំដើម្បីឲ្យបានភាពត្រឹមត្រូវ សូមយល់ថាការបកប្រែដោយស្វ័យប្រវត្តិសមាជិកអាចមានកំហុស ឬការខុសឆ្គងបាន។ ឯកសារដើមនៅភាសាមេគួរត្រូវបានគិតថាជា ប្រភពចម្បងដែលត្រឹមត្រូវ។ សម្រាប់ព័ត៌មានសំខាន់ ជំរុញឲ្យប្រើការបកប្រែដោយអ្នកជំនាញមនុស្ស។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបញ្ចេញន័យខុសដែលកើតឡើងពីការប្រើប្រាស់ការបកប្រែនេះទេ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,12 @@
# ការងារ NetLogo
យកម៉ូដែលមួយក្នុងបណ្ណាល័យ NetLogo ហើយប្រើវា ដើម្បីស្ទុះស្ទើរបញ្ហាជាក់ស្តែងជាប្រព័ន្ធជា៉ច្បាស់ជាងគេ។ ឧទាហរណ៍មួយល្អគឺកែប្រែម៉ូដែល Virus នៅក្នុងថត Alternative Visualizations ដើម្បីបង្ហាញពីរបៀបដែលវាអាចត្រូវបានប្រើសម្រាប់ម៉ូឌែលការរីកព្រំដែននៃ COVID-19។ តើអ្នកអាចបង្កើតម៉ូដែលមួយដែលបម្លែងការរីករាលដាលមេរោគក្នុងជីវិតពិតបានទេ?
បង្ហាញស្នាដៃរបស់អ្នកដោយរក្សាសំណុំនិងសង់វីដេអូបង្ហាញពន្យល់ពីរបៀបដែលម៉ូដែលភ្ជាប់ទៅនឹងស្ថានភាពជាក់ស្តែងក្នុងពិភពលោក។
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការមិនទទួលខុសត្រូវ**៖
ឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ទោះបីយើងខិតខំផ្តល់ភាពត្រឹមត្រូវក៏ដោយ សូមយល់ថា ការបកប្រែដោយស្វ័យប្រវត្តិក្នុងមួយចំនួនអាចមានកំហុស ឬមិនត្រឹមត្រូវ។ ឯកសារដើមក្នុងភាសាបុរណារបស់វាគួរត្រូវបានយកជាលក្ខណៈជាការយោងដ៏មានសុពលភាព។ ចំពោះព័ត៌មានសំខាន់ៗ សូមណែនាំឲ្យបកប្រែដោយមនុស្សជំនាញវិជ្ជាជីវៈ។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកគេត្រឹមត្រូវដែលកើតមានពីការប្រើប្រាស់ការបកប្រែនេះឡើយ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,47 @@
# បច្ចេកវិទ្យាបញ្ញាសិប្បនិម្មិតដែលមានសីលធម៌ និងមានទំនួលខុសត្រូវ
អ្នកបានជិតបញ្ចប់វគ្គសិក្សានេះហើយ ហើយខ្ញុំសង្ឃឹមថាឥឡូវនេះអ្នកបានឃើញយ៉ាងច្បាស់ថា AI មានមូលដ្ឋានលើវិធីសាស្រ្តគណិតវិទ្យាទម្រង់ផ្លូវការជាច្រើន ដែលអនុញ្ញាតឲ្យយើងរកឃើញទំនាក់ទំនងនៅក្នុងទិន្នន័យ ហើយបណ្តុះបណ្តាលម៉ូដែលដើម្បីធ្វើស្ទុះលក្ខណៈមួយចំនួននៃឥរិយាបថមនុស្ស។ នៅពេលនេះក្នុងប្រវត្តិសាស្ត្រ យើងពិចារណាថា AI គឺជាឧបករណ៍មានសមត្ថភាពខ្លាំងមួយសម្រាប់ដកយកលំនាំពីទិន្នន័យ និងអនុវត្តលំនាំនោះដើម្បីដោះស្រាយបញ្ហាថ្មីៗ។
## [វិចារណកម្រិតមុនការសន្ទនា](https://white-water-09ec41f0f.azurestaticapps.net/quiz/5/)
ប៉ុន្តែក្នុងវិទ្យាសាស្ត្រសម្ភោធ យើងជាញឹកញាប់ឃើញរឿងដែល AI បង្ហាញពីគ្រោះថ្នាក់ចំពោះមនុស្សជាតិ។ ជារឿយៗរឿងទាំងនោះមានមូលដ្ឋានមកពីការប្រឆាំងរបស់ AI មួយប្រភេទ ដែល AI សម្រេចចិត្តប្រឈមមុខនឹងមនុស្ស។ នេះមានន័យថា AI មានអារម្មណ៍មួយណាមួយឬអាចធ្វើការសម្រេចចិត្តដែលកសាងដោយអ្នកអភិវឌ្ឍរមិនបានរំពឹងទុក។
ប្រភេទ AI ដែលយើងបានរៀនឡើងក្នុងវគ្គសិក្សានេះ គឺមិនមែនជាប្រភេទប៉ុន្មានទេ គ្រាន់តែជាការ គណនាគម្ពីរធំៗ។ វាជាឧបករណ៍មានអំណាចខ្លាំងដែលជួយឲ្យយើងដោះស្រាយបញ្ហារបស់យើងបាន ហើយដូចជា ឧបករណ៍មានអំណាចផ្សេងទៀត វាអាចត្រូវបានប្រើប្រាស់សម្រាប់ផលប្រយោជន៍ល្អ ឬសម្រាប់គោលបំណងអាក្រក់។ ហើយសំខាន់បំផុត វាអាចត្រូវបាន *ប្រើប្រាស់មិនត្រឹមត្រូវ*
## គោលការណ៍នៃ AI ដែលមានទំនួលខុសត្រូវ
ដើម្បីជៀសវាងការប្រើប្រាស់AI ដែលជាប្រតិបត្តិមិនប្រក្រតី ឬមានគោលបំណងមិនល្អ Microsoft បានបញ្ជាក់ [គោលការណ៍នៃ AI ដែលមានទំនួលខុសត្រូវ](https://www.microsoft.com/ai/responsible-ai?WT.mc_id=academic-77998-cacaste) ដែលមានមូលដ្ឋានលើគំនិតដូចខាងក្រោម៖
* **ភាពត្រឹមត្រូវ** មានសេចក្តីទាក់ទងជាមួយបញ្ហាសំខាន់នៃ *អនុភាពប៉ុនប៉ង* នៅក្នុងម៉ូដែល ដែលអាចកើតមានដោយការប្រើទិន្នន័យមានភាគល្អិតក្នុងការបណ្តុះបណ្តាល។ ឧទាហរណ៍ បើព្យាយាមទស្សនាប្រាក់ចំណូលនៃការរកការងារជា អ្នកអភិវឌ្ឍន៍កម្មវិធី ក្រុមម៉ូដែលសំរាប់បុរសមួយត្រូវបានផ្តល់អាទិភាពខ្ពស់ជាងបុគ្គលស្រី ព្រោះពេលបណ្តុះបណ្តាលទិន្នន័យត្រូវបានផ្តោតទៅលើបុរសជាច្រើនជាង។ យើងត្រូវតែសមមរិតទិន្នន័យបណ្តុះបណ្តាលដោយយកចិត្តទុកដាក់ ហើយពិនិត្យម៉ូដែល ដើម្បីជៀសវាងការប៉ុនប៉ង ដើម្បីធានាថាម៉ូដែលយកចិត្តទុកដាក់លក្ខណៈដែលពាក់ព័ន្ធជាង។
* **ភាពទុកចិត្តបាន និងសុវត្ថិភាព**។ ដោយធម្មជាតិ ម៉ូដែល AI អាចកើតមានកំហុស។ បណ្ដាញសរសៃប្រព័ន្ធនឹងត្រលប់មកជាប្រាក់ប្រហែល ហើយយើង​ត្រូវយកទៅគិតគូរនៅពេលធ្វើការសម្រេចចិត្ត។ ម៉ូដែលគ្រប់ប្រភេទមានអត្រាកែតម្រូវ និងអត្រាថតត្រឡប់វិញ ហើយយើងត្រូវយល់ដឹងដើម្បីការពារពីការខូចខាតដែលអាចកើតមាន ពីការណែនាំដែលមិនត្រឹមត្រូវ។
* **ភាពឯកជន និងសុវត្ថិភាព** មានភាពខុសគ្នាគ្នា នៃ AI។ ឧទាហរណ៍ នៅពេលយើងប្រើទិន្នន័យមួយសម្រាប់បណ្តុះបណ្តាលម៉ូដែល ទិន្នន័យនោះក្លាយទៅជាគ្រឿងផ្សំរួមក្នុងម៉ូដែល។ មួយដៃនេះ នាំឲ្យមានសុវត្ថិភាព និងភាពឯកជនបន្ថែម ហត្ថបីយើងត្រូវចងចាំថាម៉ូដែលមានការបណ្តុះបណ្តាលលើទិន្នន័យអ្វីខ្លះ។
* **ភាពរួមចំណែក** មានន័យថាយើងមិនកំពុងបង្កើត AI ដើម្បីជំនួសមនុស្សទេ ប៉ុន្តែដើម្បីជួយបំប៉ុសមនុស្ស និងធ្វើឲ្យម្ចាស់ការងាររបស់យើងមានភាពច្នៃប្រឌិតបន្ថែម។ វាក៏ទាក់ទងទៅដល់ភាពត្រឹមត្រូវ ដោយពេលជួបប្រទៈនឹងសហគមន៍ដែលមានតំណាងតិច យើងសំរេចថាធ្វើការប្រមូលទិន្នន័យភាគច្រើនបង្ហាញពីប៉ុនប៉ង ហើយយើងត្រូវធានាថាសហគមន៍ទាំងនោះត្រូវបានរួមបញ្ចូល និងគ្រប់គ្រងត្រឹមត្រូវដោយ AI។
* **ភាពច្បាស់លាស់**។ មានន័យថា យើងត្រូវធ្វើឲ្យប្រាកដថា យើងច្បាស់លាស់អំពីការប្រើប្រាស់ AI ទៅគ្រប់ពេលវេលា។ ផងដែរយើងចង់ប្រើប្រព័ន្ធ AI ដែលអាច *បកស្រាយ* បាន នៅកន្លែងដែលអាចធ្វើទៅបាន។
* **ការទទួលខុសត្រូវ**។ នៅពេលម៉ូដែល AI ធ្វើការសម្រេចចិត្ត មិនមែនគ្រប់ពេលវេលាជាក់លាក់ថា តើអ្នកណាទទួលខុសត្រូវចំពោះការសម្រេចចិត្តនោះ។ យើងត្រូវធានាថាយើងយល់ពីកន្លែងដែលទទួលខុសត្រូវនៅក្នុងការសម្រេចចិត្ត AI។ ក្នុងក្ដីសង្ឃឹមភាគច្រើន យើងចង់រួមបញ្ចូលមនុស្សទៅក្នុងដំណើរការសម្រេចចិត្តសំខាន់ៗ ដើម្បីធ្វើឲ្យអ្នកមនុស្សពិតប្រាកដមានទំនួលខុសត្រូវ។
## ឧបករណ៍សម្រាប់ AI ដែលមានទំនួលខុសត្រូវ
Microsoft បានអភិវឌ្ឍ [ប្រអប់ឧបករណ៍ AI មានទំនួលខុសត្រូវ](https://github.com/microsoft/responsible-ai-toolbox) ដែលមានឧបករណ៍ច្រើនដូចជា៖
* ទំព័រត្រួតពិនិត្យការបកស្រាយ (InterpretML)
* ទំព័រត្រួតពិនិត្យភាពត្រឹមត្រូវ (FairLearn)
* ទំព័រត្រួតពិនិត្យការវិភាគកំហុស
* ទំព័រត្រួតពិនិត្យ AI មានទំនួលខុសត្រូវ ដែលរួមមាន
- EconML - ឧបករណ៍សម្រាប់វិភាគហេតុផល ដែលផ្តោតលើសំណួរថា តើបើជាអ្វី
- DiCE - ឧបករណ៍វិភាគប្រឆាំងប្រសើរ ដែលអនុញ្ញាតឲ្យអ្នកមើលថាតើលក្ខណៈណាខ្លះត្រូវបានផ្លាស់ប្តូរដើម្បីផ្លាស់ប្តូរថ្លៃថ្នាលសម្រេចចិត្តរបស់ម៉ូដែល
សម្រាប់ព័ត៌មានបន្ថែមអំពីសីលធម៌ AI សូមទស្សនាវគ្គសិក្សានេះ [មេរៀននេះ](https://github.com/microsoft/ML-For-Beginners/tree/main/1-Introduction/3-fairness?WT.mc_id=academic-77998-cacaste) នៅក្នុងកម្មវិធីសិក្សា ឥណ្ឌុក្រិតលើម៉ាស៊ីនហ្វឹកហាត់ ដែលរួមបញ្ចូលភារកិច្ច។
## ការត្រួតពិនិត្យ និងការសិក្សាផ្ទាល់ខ្លួន
ចូលរួមចំណែក [ផ្លូវការសិក្សា](https://docs.microsoft.com/learn/modules/responsible-ai-principles/?WT.mc_id=academic-77998-cacaste) ដើម្បីរៀនបន្ថែមអំពី AI ដែលមានទំនួលខុសត្រូវ។
## [វិចារណកម្រិតក្រោយសន្ទនា](https://white-water-09ec41f0f.azurestaticapps.net/quiz/6/)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការព្រមាន**៖
ឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ បើទោះបីយើងខិតខំប្រឹងប្រែងឱ្យបានត្រឹមត្រូវ ក៏សូមជ្រាបថាការបកប្រែដោយស្វ័យប្រវត្តិក៏អាចមានកំហុស ឬការមិនត្រឹមត្រូវបាន។ ឯកសារដើមក្នុងភាសាដើមគួរត្រូវបានទទួលស្គាល់ជាទីតាំងប្រភពមានអំណាច។ សម្រាប់ព័ត៌មានសំខាន់ៗ គួរត្រូវបានបកប្រែដោយអ្នកជំនាញមនុស្សផ្នែកវិជ្ជាជីវៈ។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកប្រែខុសឆ្គងណាមួយដែលកើតមានពីការប្រើប្រាស់ការបកប្រែនេះនោះទេ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,12 @@
# ទិដ្ឋភាពទូទៅ
![Overview in a doodle](../../../translated_images/km/ai-overview.0857791951d19500.webp)
> Sketchnote ដោយ [Tomomi Imura](https://twitter.com/girlie_mac)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការបដិសេធ**៖
ឯកសារនេះត្រូវបានបំលែងជាភាសាខ្មែរ ដោយប្រើសេវាកម្មបំលែងភាសា AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេលដែលយើងខិតខមក្នុងការធ្វើឱ្យមានភាពត្រឹមត្រូវ សូមយល់ថាការបំលែងភាសា ជា​ធម្មតា​អាចមានកំហុស ឬការមិនត្រឹមត្រូវ។ ឯកសារដើមក្នុងភាសាម្ចាស់វាត្រូវបានគេចាត់ទុកជាមូលដ្ឋានដែលមានសិទ្ធិលើព័ត៌មាន។ សម្រាប់ព័ត៌មានសំខាន់ៗ សូមណែនាំឱ្យប្រើការបំលែងភាសាដោយអ្នកជំនាញមនុស្ស។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការប្រែប្រែលម្អិតណាមួយដែលមានមកពីការប្រើប្រាស់ការបំលែងនេះឡើយ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,83 @@
# បណ្ដាញពហុ​ម៉ូដេល
បន្ទាប់ពីការជោគជ័យនៃម៉ូដែល transformer សម្រាប់ដោះស្រាយបញ្ហា NLP កសាងរចនាសម្ព័ន្ធដូចគ្នា ឬស្រដៀងគ្នាត្រូវបានអនុវត្តលើបញ្ហាផ្សេងៗក្នុងការមើលឃើញកុំព្យូទ័រ។ មានចំណាប់អារម្មណ៍កើនឡើងក្នុងការសាងសង់ម៉ូដែលដែលនឹង *បញ្ចូល* សមត្ថភាពមើលឃើញ និងភាសាធម្មជាតិ។ មួយក្នុងចំណោមកិច្ចខិតខំប្រឹងប្រែងដូចបានធ្វើដោយ OpenAI ហើយវាត្រូវបានហៅថា CLIP និង DALL.E។
## ការបណ្តុះបណ្តាលរូបភាពប្រឆាំង (CLIP)
គំនិតសំខាន់នៃ CLIP គឺដើម្បីអាចប្រៀបធៀបការតម្រូវអត្ថបទជាមួយរូបភាព និងកំណត់ថាតើរូបភាពបានផ្គូផ្គងប៉ុណ្ណា រម្យជាមួយការតម្រូវ។
![CLIP Architecture](../../../../../translated_images/km/clip-arch.b3dbf20b4e8ed8be.webp)
> *រូបភាពពី [អត្ថបទប្លុកនេះ](https://openai.com/blog/clip/)*
ម៉ូដែលត្រូវបានបណ្តុះបណ្តាលលើរូបភាពដែលទទួលបានពីអ៊ីនធឺណិត និងអត្ថបទពណ៌នារបស់ពួកវា។ សម្រាប់ប្រអប់នីមួយៗ យើងយកគូ N នៃ (រូបភាព, អត្ថបទ) ហើយបម្លែងពួកវាទៅជារូបភាពវ៉ិចទ័រ I<sub>1</sub>,..., I<sub>N</sub> / T<sub>1</sub>, ..., T<sub>N</sub>។ តំណាងទាំងនេះ ត្រូវបានផ្គូផ្គងគ្នា។ មុខងារបាត់បង់ត្រូវបានកំណត់ឡើងដើម្បីបង្កើនការស្រដៀង cosine រវាងវ៉ិចទ័រដែលផ្គូផ្គងគ្នា (ឧ. I<sub>i</sub> និង T<sub>i</sub>) ហើយកាត់បន្ថយការស្រដៀង cosine រវាងគូផ្សេងទៀតទាំងអស់។ នេះហើយជាហេតុផលដែលវិធីសាស្ត្រនេះត្រូវបានគេហៅថា **ប្រឆាំងគ្នា**
ម៉ូដែល/បណ្ណាល័យ CLIP មានស្រាប់នៅ [OpenAI GitHub](https://github.com/openai/CLIP)។ វិធីសាស្ត្រទាំងនេះបានពិពណ៌នានៅ [អត្ថបទប្លុកនេះ](https://openai.com/blog/clip/), និងលម្អិតបន្ថែមនៅ [ឯកសារ​នេះ](https://arxiv.org/pdf/2103.00020.pdf)។
ពេលម៉ូដែលនេះត្រូវបានបណ្តុះបណ្តាលរួច អ្នកអាចផ្តល់ឲ្យវាប្រអប់រូបភាព និងប្រអប់អត្ថបទតម្រូវ ហើយវានឹងត្រឡប់មកជាតង់ស័រដែលមានប្រតិបត្តិការភាព។ CLIP អាចប្រើសម្រាប់បញ្ហាច្រើន៖
**ចាត់ថ្នាក់រូបភាព**
យើងយកគំរូយល់ថាត្រូវចាត់ថ្នាក់រូបភាពក្នុងចំណោម ឧ. ក្រុមឆ្មា, សត្វ​ឆ្កែ និងមនុស្ស។ នៅក្នុងករណីនេះ យើងអាចផ្តល់រូបភាពមួយ ដោយមានអត្ថបទតម្រូវ ច្រើនលំដាប់៖ "*រូបភាពនៃឆ្មាមួយ*", "*រូបភាពនៃឆ្កែមួយ*", "*រូបភាពនៃមនុស្សម្នាក់*។ នៅក្នុងវ៉ិចទ័រប្រតិបត្តិការភាព 3 យើងគ្រាន់តែជ្រើសរើសពណ៌សាន់​ដែលមានតម្លៃខ្ពស់បំផុត។
![CLIP for Image Classification](../../../../../translated_images/km/clip-class.3af42ef0b2b19369.webp)
> *រូបភាពពី [អត្ថបទប្លុកនេះ](https://openai.com/blog/clip/)*
**ស្វែងរករូបភាពដោយផ្អែកលើអត្ថបទ**
យើងក៏អាចធ្វើ័រភាគវិញបាន។ ប្រសិនបើយើងមានកម្រងរូបភាព ក៏អាចផ្តល់កម្រងនេះទៅម៉ូដែល និងអត្ថបទតម្រូវ - វានឹងផ្តល់រូបភាពដែលស្រដៀងគ្នាម៉េចបំផុតនឹងអត្ថបទនោះ។
## ✍️ ឧទាហរណ៍: [ប្រើ CLIP សម្រាប់ចាត់ថ្នាក់រូបភាព និងស្វែងរករូបភាព](Clip.ipynb)
បើកកំណត់ត្រា [Clip.ipynb](Clip.ipynb) ដើម្បីមើល CLIP ដំណើរការ។
## ការបង្កើតរូបភាពជាមួយ VQGAN+ CLIP
CLIP ក៏អាចប្រើក្នុងការបង្កើតរូបភាពពីអត្ថបទតម្រូវបាន។ ដើម្បីធ្វើការនេះ ត្រូវការម៉ូដែល **ជាស្រ្តីមួយ** ដែលអាចបង្កើតរូបភាពទៅលើវ៉ិចទ័រប្រភេទចូលបsome។ ម៉ូដែលមួយដែលមានគឺហៅថា [VQGAN](https://compvis.github.io/taming-transformers/) (Vector-Quantized GAN)។
គំនិតសំខាន់ៗរបស់ VQGAN ដែលមានភាពខុសគ្នាពី [GAN](../../4-ComputerVision/10-GANs/README.md) ទូទៅមាន៖
* ប្រើរចនាសម្ព័ន្ធ transformer autoregressive ដើម្បីបង្កើតលំដាប់ផ្នែកវិចិត្រសរស្ត្រ context-rich ដែលបង្កើតរូបភាព។ ផ្នែកវិចិត្រសរស្ត្រខាងលើត្រូវបានរៀនជាមួយ [CNN](../../4-ComputerVision/07-ConvNets/README.md)
* ប្រើជាអ្នកគ្រប់គ្រងរូបភាពតូច (sub-image discriminator) ដែលរកឃើញថាផ្នែកនៃរូបភាពមាន "ពិត" ឬ "មិនពិត" (ខុសពីវិធីការ "ទាំងអស់ឬមិន" ក្នុង GAN ប្រពៃណី)។
សូមស្វែងយល់បន្ថែមអំពី VQGAN នៅតំបន់វេប [Taming Transformers](https://compvis.github.io/taming-transformers/)។
ភាពខុសគ្នាសំខាន់រវាង VQGAN និង GAN ប្រពៃណីគឺថា GANប្រពៃណីអាចបង្កើតរូបភាពល្អពីវ៉ិចទ័រប្រភេទចូលណាឡើយ ខណៈដែល VQGAN អាចបង្កើតរូបភាពមិនស្របតាមចំនួន ។ ដូច្នេះ យើងត្រូវដឹកនាំដំណើរការបង្កើតរូបភាពបន្ថែម ដែលអាចធ្វើបានជាមួយ CLIP។
![VQGAN+CLIP Architecture](../../../../../translated_images/km/vqgan.5027fe05051dfa31.webp)
ដើម្បីបង្កើតរូបភាពដែលត្រូវតែផ្គូផ្គងនឹងអត្ថបទចេញពីការតម្រូវ យើងចាប់ផ្តើមពីវ៉ិចទ័រទៅបណ្តុះបណ្តាល ដែលត្រូវបានបញ្ចូនតាម VQGAN ដើម្បីបង្កើតរូបភាព។ បន្ទាប់មក CLIP ត្រូវបានប្រើដើម្បីបង្កើតមុខងារបាត់បង់ដែលបង្ហាញថារូបភាពផ្គូផ្គងប៉ុណ្ណា ទៅតាមអត្ថបទតម្រូវ។ គោលបំណងត្រូវកាត់បន្ថយមុខងារបាត់បង់នេះ ដោយប្រើ back propagation ដើម្បីកែប្រែអថេរinputs vector។
បណ្ណាល័យដ៏ល្អសម្រាប់ដំណើរការ VQGAN+CLIP គឺ [Pixray](http://github.com/pixray/pixray)
![Picture produced by Pixray](../../../../../translated_images/km/a_closeup_watercolor_portrait_of_young_male_teacher_of_literature_with_a_book.2384968e9db8a0d0.webp) | ![Picture produced by pixray](../../../../../translated_images/km/a_closeup_oil_portrait_of_young_female_teacher_of_computer_science_with_a_computer.e0b6495f210a4390.webp) | ![Picture produced by Pixray](../../../../../translated_images/km/a_closeup_oil_portrait_of_old_male_teacher_of_math.5362e67aa7fc2683.webp)
----|----|----
រូបភាពបានបង្កើតពីអត្ថបទតម្រូវ *a closeup watercolor portrait of young male teacher of literature with a book* | រូបភាពបានបង្កើតពីអត្ថបទតម្រូវ *a closeup oil portrait of young female teacher of computer science with a computer* | រូបភាពបានបង្កើតពីអត្ថបទតម្រូវ *a closeup oil portrait of old male teacher of mathematics in front of blackboard*
> រូបភាពពីការប្រមូលផ្តុំ **Artificial Teachers** ដោយ [Dmitry Soshnikov](http://soshnikov.com)
## DALL-E
### [DALL-E 1](https://openai.com/research/dall-e)
DALL-E ជារូបមន្តនៃ GPT-3 ដែលត្រូវបានបណ្តុះបណ្តាលសម្រាប់បង្កើតរូបភាពពីអត្ថបទតម្រូវ។ វាត្រូវបានបណ្តុះបណ្តាលជាមួយប៉ារ៉ាម៉ែត្រ 12 ពាន់លាន។
ខុសពី CLIP, DALL-E ទទួលបានទាំងអត្ថបទ និងរូបភាពក្នុងចរន្តតែមួយសម្រាប់រូបភាព និងអត្ថបទទាំងអស់។ ដូច្នេះ ពីអត្ថបទតម្រូវជាច្រើន អ្នកអាចបង្កើតរូបភាពពីអត្ថបទ។
### [DALL-E 2](https://openai.com/dall-e-2)
ភាពខុសគ្នាសំខាន់រវាង DALL.E 1 និង 2 គឺថាវាបង្កើតរូបភាព និងសិល្បៈដែលមានភាពរឹងបញ្ចេញជាច្រើនជាងមុន។
ឧទាហរណ៍ការបង្កើតរូបភាពជាមួយ DALL-E:
![Picture produced by Pixray](../../../../../translated_images/km/DALL·E%202023-06-20%2015.56.56%20-%20a%20closeup%20watercolor%20portrait%20of%20young%20male%20teacher%20of%20literature%20with%20a%20book.6c235e8271d9ed10.webp) | ![Picture produced by pixray](../../../../../translated_images/km/DALL·E%202023-06-20%2015.57.43%20-%20a%20closeup%20oil%20portrait%20of%20young%20female%20teacher%20of%20computer%20science%20with%20a%20computer.f21dc4166340b6c8.webp) | ![Picture produced by Pixray](../../../../../translated_images/km/DALL·E%202023-06-20%2015.58.42%20-%20%20a%20closeup%20oil%20portrait%20of%20old%20male%20teacher%20of%20mathematics%20in%20front%20of%20blackboard.d331c2dfbdc3f7c4.webp)
----|----|----
រូបភាពបានបង្កើតពីអត្ថបទតម្រូវ *a closeup watercolor portrait of young male teacher of literature with a book* | រូបភាពបានបង្កើតពីអត្ថបទតម្រូវ *a closeup oil portrait of young female teacher of computer science with a computer* | រូបភាពបានបង្កើតពីអត្ថបទតម្រូវ *a closeup oil portrait of old male teacher of mathematics in front of blackboard*
## ឯកសារយោង
* ឯកសារ VQGAN: [Taming Transformers for High-Resolution Image Synthesis](https://compvis.github.io/taming-transformers/paper/paper.pdf)
* ឯកសារ CLIP: [Learning Transferable Visual Models From Natural Language Supervision](https://arxiv.org/pdf/2103.00020.pdf)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការដោះលែងពីការទទួលខុសត្រូវ**:
ឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេលដែលយើងខិតខំប្រឹងប្រែងរកភាពត្រឹមត្រូវ សូមយល់ដឹងថាការបកប្រែដោយស្វ័យប្រវត្តិអាចមានកំហុស ឬមិនត្រឹមត្រូវខ្លះ។ ឯកសារដើមដែលមានភាសាដើមគួរត្រូវបានពិចារណាទៅជាមូលដ្ឋាននៃការទទួលស្គាល់។ សម្រាប់ព័ត៌មានសំខាន់ៗ ការបកប្រែដោយមនុស្សមើលឯកទេសគឺត្រូវបានណែនាំ។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកស្រាយខុស ដោយសារការប្រើប្រាស់ការបកប្រែនេះឡើយ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,200 @@
Attribution-ShareAlike 4.0 អន្ដរជាតិ
=======================================================================
ក្រុមហ៊ុន Creative Commons ("Creative Commons") មិនមែនជាក្រសួងច្បាប់ឡើយ ហើយមិនផ្តល់សេវាកម្មច្បាប់ ឬ​ផ្តល់​សំណូមពរ​ផ្នែកច្បាប់។ ការចែកចាយប្រាក់ប័ណ្ណសាធារណៈ Creative Commons មិនបង្កើតទំនាក់ទំនងថ្នាក់ អតិថិជន-មេធាវី ឬទំនាក់ទំនងផ្សេងទៀតឡើយ។ Creative Commons ផ្ដល់ប្រាក់ប័ណ្ណ និងព័ត៌មានដែលពាក់ព័ន្ធដោយមានលក្ខខណ្ឌ "ដូចដែលមាន"។ Creative Commons មិនផ្តល់ការធានាអំពីប្រាក់ប័ណ្ណរបស់ខ្លួន ឬសម្ភារៈណាមួយដែលបានអនុញ្ញាតក្រោមលក្ខខណ្ឌរបស់វា ឬព័ត៌មានពាក់ព័ន្ធណាមួយឡើយ។ Creative Commons បដិសេធភារកិច្ចទាំងអស់ចំពោះការខូចខាតដែលកើតឡើងពីការប្រើប្រាស់ឲ្យបានកំណត់ត្រឹមខ្ទង់អតិបរមា។
ការប្រើប្រាស់ប្រាក់ប័ណ្ណសាធារណៈ Creative Commons
ប្រាក់ប័ណ្ណសាធារណៈ Creative Commons ផ្ដល់នូវលក្ខខណ្ឌ និងលក្ខខណ្ឌស្តង់ដារដែលអ្នកបង្កើត និងម្ចាស់សិទ្ធិផ្សេងអាចប្រើដើម្បីចែករំលែកស្នាដៃដើមនៃការចងក្រង និងសម្ភារៈផ្សេងទៀតដែលគ្របដណ្តប់ដោយសិទ្ធិបោះពុម្ព និងសិទ្ធិផ្សេងទៀតដែលបានបញ្ជាក់នៅក្នុងប្រាក់ប័ណ្ណសាធារណៈខាងក្រោម។ ការពិចារណាខាងក្រោមគឺសម្រាប់គោលបំណងព័ត៌មានតែប៉ុណ្ណោះ មិនទាំងស្រុង និងមិនមែនជាផ្នែកមួយនៃប្រាក់ប័ណ្ណរបស់យើង។
ការពិចារណាសម្រាប់អ្នកឲ្យប្រាក់ប័ណ្ណ៖ ប្រាក់ប័ណ្ណសាធារណៈរបស់យើងមានគោលបំណងសម្រាប់អ្នកដែលមានសិទ្ធិផ្ដល់អនុញ្ញាតជាសាធារណៈក្នុងការប្រើប្រាស់សម្ភារៈនានាជាដូចដែលត្រូវបានដាក់ជាកំណត់ដោយសិទ្ធិបោះពុម្ព និងសិទ្ធិផ្សេងទៀត។ ប្រាក់ប័ណ្ណរបស់យើងមិនអាចបដិសេធបាន។ អ្នកឲ្យប្រាក់ប័ណ្ណគួរតែអាន និងយល់អំពីលក្ខខណ្ឌនៃប្រាក់ប័ណ្ណដែលពួកគេជ្រើសមុនពេលអនុវត្ត។ អ្នកឲ្យប្រាក់ប័ណ្ណគួរតែរក្សាសិទ្ធិទាំងអស់ដែលចាំបាច់មុនពេលអនុវត្តប្រាក់ប័ណ្ណខ្លួន ដូច្នេះសាធារណៈអាចប្រើការសម្ភារៈបានតាមរយៈរបៀបដែលរំពឹងទុក។ អ្នកឲ្យប្រាក់ប័ណ្ណគួរតែជម្រាបច្បាស់អំពីសម្ភារៈណាមួយដែលមិនគ្របដណ្តប់ដោយប្រាក់ប័ណ្ណនេះ។ រួមទាំងសម្ភារៈផ្សេងទៀតដែលមានប្រាក់ប័ណ្ណ CC ឬសម្ភារៈប្រើប្រាស់ក្រោមលក្ខខណ្ឌលើកលែង ឬកំណត់សិទ្ធិបោះពុម្ពផ្សេងទៀត។ ការពិចារណាថែមទៀតសម្រាប់អ្នកឲ្យប្រាក់ប័ណ្ណ:
wiki.creativecommons.org/Considerations_for_licensors
ការពិចារណាសម្រាប់សាធារណៈ៖ ដោយប្រើប្រាស់ប្រាក់ប័ណ្ណសាធារណៈរបស់យើង, អ្នកឲ្យប្រាក់ប័ណ្ណផ្ដល់អនុញ្ញាតឲ្យសាធារណៈប្រើប្រាស់សម្ភារៈដែលបានអនុញ្ញាតក្រោមលក្ខខណ្ឌដែលបានកំណត់។ ប្រសិនបើការអនុញ្ញាតរបស់អ្នកឲ្យប្រាក់ប័ណ្ណមិនចាំបាច់សម្រាប់មូលហេតុណាមួយ — ដូចជាលើកលែង ឬកំណត់សិទ្ធិបោះពុម្ពដែលអាចអនុវត្ត — នោះការប្រើប្រាស់នោះមិនត្រូវបានគ្រប់គ្រងដោយប្រាក់ប័ណ្ណទេ។ ប្រាក់ប័ណ្ណរបស់យើងផ្ដល់សិទ្ធិគ្រាន់តែប៉ុណ្ណោះក្រោមសិទ្ធិបោះពុម្ព និងសិទ្ធិផ្សេងទៀតដែលអ្នកឲ្យប្រាក់ប័ណ្ណមានសិទ្ធិផ្ដល់។ ការប្រើប្រាស់សម្ភារៈដែលបានអនុញ្ញាតអាចត្រូវបានដាក់កំណត់សម្រាប់មូលហេតុផ្សេងទៀត, រួមទាំងព្រោះអ្នកផ្សេងមានសិទ្ធិបោះពុម្ព ឬសិទ្ធិផ្សេងទៀតលើសម្ភារៈនោះ។ អ្នកឲ្យប្រាក់ប័ណ្ណអាចធ្វើសំណូមពរពិសេស ដូចជាស្នើឲ្យបញ្ចាក់ ឬពណ៌នាអំពីការផ្លាស់ប្តូរ។ ទោះបីជាមិនត្រូវបានទាមទារដោយប្រាក់ប័ណ្ណរបស់យើងក៏ដោយ អ្នកត្រូវបានលើកទឹកចិត្តឲ្យគោរពសំណូមពរទាំងនោះនៅពេលវាជាការអាចធ្វើបាន។ ការពិចារណាថែមទៀតសម្រាប់សាធារណៈ:
wiki.creativecommons.org/Considerations_for_licensees
=======================================================================
ប្រាក់ប័ណ្ណសាធារណៈ Creative Commons Attribution-ShareAlike 4.0 អន្ដរជាតិ
ដោយអនុវត្តសិទ្ធិដែលបានអនុញ្ញាត (បានកំណត់ខាងក្រោម), អ្នកយល់ព្រម និងទទួលភារកិច្ចគោរពលក្ខខណ្ឌនៃប្រាក់ប័ណ្ណសាធារណៈ Creative Commons Attribution-ShareAlike 4.0 អន្ដរជាតិ ("ប្រាក់ប័ណ្ណសាធារណៈ")។ ប្រសិនបើប្រាក់ប័ណ្ណសាធារណៈនេះអាចត្រូវបានព្រាងជាសន្ធិបតី, អ្នកត្រូវបានផ្ដល់សិទ្ធិបោះពុម្ពដោយយោងលើការទទួលយកលក្ខខណ្ឌទាំងនេះ, ហើយអ្នកឲ្យប្រាក់ប័ណ្ណផ្ដល់សិទ្ធិដូច្នេះ ដោយទំនាក់ទំនងនៃអត្ថប្រយោជន៍ដែលអ្នកឲ្យប្រាក់ប័ណ្ណទទួលបានពីការផ្ដល់សម្ភារៈដែលបានអនុញ្ញាតក្រោមលក្ខខណ្ឌទាំងនេះ។
ផ្នែក 1 -- និយមន័យ។
ក. សម្ភារៈបានផ្លាស់ប្តូរ មានន័យថាសម្ភារៈដែលគឺជាសិទ្ធិបោះពុម្ព និងសិទ្ធិដូចគ្នា ដែលបានបង្កើតឡើងឬផ្អែកលើសម្ភារៈដែលបានអនុញ្ញាត ហើយនៅទីនេះ សម្ភារៈដែលបានអនុញ្ញាតត្រូវបានបកប្រែ ប្ដូរ រៀបចំ បំលែង ឬកែប្រែជារបៀបណាមួយដែលទាមទារអនុញ្ញាតក្រោមសិទ្ធិបោះពុម្ព និងសិទ្ធិដូចគ្នារបស់អ្នកឲ្យប្រាក់ប័ណ្ណ។ សម្រាប់គោលបំណងនៃប្រាក់ប័ណ្ណនេះ ប្រសិនបើសម្ភារៈដែលបានអនុញ្ញាតគឺជា​ស្នាដៃតន្ត្រី, ការសម្តែង, ឬការថតសម្លេង, សម្ភារៈបានផ្លាស់ប្តូរមានន័យថាត្រូវបានផលិតឡើងនៅពេលសម្ភារៈដែលបានអនុញ្ញាតត្រូវបានសម្របក្នុងកម្រិតពេលវេលារួមជាមួយរូបភាពចល័ត។
ខ. ប្រាក់ប័ណ្ណរបស់អ្នកផ្លាស់ប្តូរ หมายถึงប្រាក់ប័ណ្ណដែលអ្នកអនុវត្តលើសិទ្ធិបោះពុម្ព និងសិទ្ធិដូចគ្នា ក្នុងការរួមចំណែករបស់អ្នកលើសម្ភារៈបានផ្លាស់ប្តូរតាមលក្ខខណ្ឌនៃប្រាក់ប័ណ្ណសាធារណៈនេះ។
គ. ប្រាក់ប័ណ្ណដែលផ្គូរផ្គង BY-SA មានន័យថាប្រាក់ប័ណ្ណដែលរាយនៅ creativecommons.org/compatiblelicenses ដែលបានអនុម័តដោយ Creative Commons ថា ភាគច្រើនស្រដៀងនឹងប្រាក់ប័ណ្ណសាធារណៈនេះ។
ឃ. សិទ្ធិបោះពុម្ព និងសិទ្ធិដូចគ្នាមានន័យថាសិទ្ធិបោះពុម្ព និង/ឬសិទ្ធិដូចគ្នា ដែលពាក់ព័ន្ធដោយជិតស្និទ្ធទៅនឹងសិទ្ធិបោះពុម្ព រួមមាន ប៉ុន្តែមិនកំណត់តែប៉ុណ្ណោះ ការសម្តែង, ភាបផ្សាយ, ការថតសម្លេង, និងសិទ្ធិទិន្នន័យ Sui Generis Database Rights ដោយមិនគិតបែបណាការកំណត់ឈ្មោះឬចាត់ថ្នាក់សិទ្ធិ។ សម្រាប់គោលដៅនៃប្រាក់ប័ណ្ណសាធារណៈនេះ, សិទ្ធិដែលបានកំណត់លើផ្នែក 2(ខ)(1)-(2) មិនមែនជាសិទ្ធិបោះពុម្ព និងសិទ្ធិដូចគ្នាទេ។
ង. វិធានការបច្ចេកទេសមានប្រសិទ្ធភាព មានន័យថាវិធានការណ៍ដែលនៅពេលគ្មានសិទ្ធិត្រឹមត្រូវ អាចមិនត្រូវបានលុបចោលតាមច្បាប់ដែលអនុវត្តតាមអត្តបទ 11 នៃពិធិប័ត្រសិទ្ធិបោះពុម្ពអន្តរជាតិ WIPO ប្រកាសនៅថ្ងៃទី ២០ ខែធ្នូ ឆ្នាំ ១៩៩៦ និង/ឬអនុសញ្ញាអន្ដរជាតិស្រដៀងគ្នា។
ច. លើកលែង និងកំណត់មានន័យថាការប្រើប្រាស់សមរម្យ, សកម្មភាពសមរម្យ និង/ឬលើកលែង ឬកំណត់ផ្សេងទៀតទៅលើសិទ្ធិបោះពុម្ព និងសិទ្ធិដូចគ្នា ដែលអនុវត្តចំពោះការប្រើប្រាស់សម្ភារៈដែលបានអនុញ្ញាតរបស់អ្នក។
ឆ. ធាតុប្រាក់ប័ណ្ណ មានន័យថាគុណលក្ខណ៍ប្រាក់ប័ណ្ណដែលរាយនៅក្នុងឈ្មោះប្រាក់ប័ណ្ណសាធារណៈ Creative Commons។ ធាតុប្រាក់ប័ណ្ណក្នុងប្រាក់ប័ណ្ណសាធារណៈនេះរួមមាន Attribution និង ShareAlike។
ត. សម្ភារៈដែលបានអនុញ្ញាត មានន័យថាស្នាដៃសិល្បៈ ឬអក្សរសាស្ត្រ, ឌីតាបេស, ឬសម្ភារៈផ្សេងទៀតដែលអ្នកឲ្យប្រាក់ប័ណ្ណបានអនុវត្តប្រាក់ប័ណ្ណសាធារណៈនេះ។
ថ. សិទ្ធិដែលបានអនុញ្ញាត មានន័យថាសិទ្ធិដែលផ្ដល់ឲ្យអ្នកដោយមានលក្ខខណ្ឌនៃប្រាក់ប័ណ្ណសាធារណៈនេះ ដែលមានដែនកំណត់លើសិទ្ធិបោះពុម្ព និងសិទ្ធិដូចគ្នារួមទាំងសិទ្ធិទាំងអស់ដែលអនុវត្តចំពោះការប្រើប្រាស់សម្ភារៈដែលបានអនុញ្ញាត និងដែលអ្នកឲ្យប្រាក់ប័ណ្ណមានសិទ្ធិផ្ដល់។
ជ. អ្នកឲ្យប្រាក់ប័ណ្ណ មានន័យថាពុំដែលជ വ്യക്തិ ឬអង្គការដែលផ្ដល់សិទ្ធិក្រោមប្រាក់ប័ណ្ណសាធារណៈនេះ។
ឈ. ចែករំលែក មានន័យថាបង្ហាញឲ្យសាធារណៈឲ្យបានដឹងដោយវិធីនានា ឬដំណើរការណា ដែលទាមទារអនុញ្ញាតក្រោមសិទ្ធិដែលបានអនុញ្ញាត ដូចជាការចម្លងបញ្ជូនការបង្ហាញសាធារណៈ ការសម្តែងសាធារណៈ ការចែកចាយ ការចម្លង ការប្រាស្រ័យ ឬការនាំចូល និងធ្វើឲ្យសម្ភារៈអាចប្រើបានសម្រាប់សាធារណៈ រួមទាំងវិធីដែលសមាជិកសាធារណៈអាចចូលប្រើសម្ភារៈពីកន្លែងនិងពេលវេលាដែលបានជ្រើសរើសដោយខ្លួនឯង។
ឌ. សិទ្ធិទិន្នន័យ Sui Generis មានន័យថាសិទ្ធិផ្សេងទៀតក្រៅសិទ្ធិបោះពុម្ពដែលកើតឡើងតាមផ្លូវច្បាប់Directive 96/9/EC នៃសភា និងក្រុមប្រឹក្សាយូរ៉ុប ថ្ងៃទី ១១ មីនា ១៩៩៦ អំពីការការពារច្បាប់ទិន្នន័យ និងបានកែប្រែ ឬបានបន្ត ក៏ដូចជាសិទ្ធិដូចគ្នាដែលស្មើគ្នានៅគ្រប់ទីកន្លែងលើពិភពលោក។
ធ. អ្នក មានន័យថានរណាឬអង្គការដែលអនុវត្តសិទ្ធិសាស្ត្រ តាមប្រាក់ប័ណ្ណសាធារណៈនេះ។ អ្នកមានន័យបន្ទាប់។
ផ្នែក 2 -- ដែនកំណត់។
ក. ច授ប័ណ្ណ។
1. ដោយសមរម្យតាមលក្ខខណ្ឌនៃប្រាក់ប័ណ្ណសាធារណៈនេះ, អ្នកឲ្យប្រាក់ប័ណ្ណផ្ដល់សិទ្ធិដល់អ្នកជាការសាកល, មិនប្រគល់ប្រាក់កម្រៃ, មិនអាចផ្ដល់បណ្ដោះអាសន្នបាន, មិនផ្តល់អនុញ្ញាតពិសេស និងមិនអាចបដិសេធបាន សម្រាប់អនុវត្តសិទ្ធិដែលបានអនុញ្ញាតរបស់អ្នកលើសម្ភារៈដែលបានអនុញ្ញាត ដូចជា៖
ក. ចម្លង និងចែករំលែក សម្ភារៈដែលបានអនុញ្ញាត ជាពេញលេញ ឬជាផ្នែកខ្លះ; និង
ខ. ផលិត, ចម្លង, និងចែករំលែក សម្ភារៈបានផ្លាស់ប្តូរ។
2. លើកលែង និងកំណត់។ ដើម្បីជៀសវាងការអះអាងខុស ករណីដែលលើកលែង និងកំណត់អំពើដែលអនុវត្តចំពោះការប្រើប្រាស់របស់អ្នក, ប្រាក់ប័ណ្ណសាធារណៈនេះមិនអាចអនុវត្ត ហើយអ្នកមិនចាំបាច់គោរពតាមលក្ខខណ្ឌរបស់វា។
3. រយៈពេល។ រយៈពេលនៃប្រាក់ប័ណ្ណសាធារណៈនេះត្រូវបានកំណត់នៅផ្នែក 6(ក)។
4. មានឧបករណ៍ និងទ្រង់ទ្រាយ; អនុញ្ញាតឲ្យកែប្រែបច្ចេកទេស។ អ្នកឲ្យប្រាក់ប័ណ្ណអនុញ្ញាតឲ្យអ្នកអនុវត្តសិទ្ធិដែលបានអនុញ្ញាតក្នុងគ្រប់ប្រភេទមេឌៀ និងទ្រង់ទ្រាយ មិនថាបច្ចុប្បន្នមានឬក៏បង្កើតឡើងក្រោយប៉ុន្មានក៏ដោយ និងអាចធ្វើការកែប្រែបច្ចេកទេសដែលចាំបាច់ដើម្បីអនុវត្តសិទ្ធិ។ អ្នកឲ្យប្រាក់ប័ណ្ណបោះបង់ និង/ឬយល់ព្រមមិនប្រើសិទ្ធិ ឬអំណាចណាមួយដើម្បីហាមឃាត់អ្នកអោយធ្វើការកែប្រែបច្ចេកទេសដែលចាំបាច់ដើម្បីអនុវត្តសិទ្ធិដែលបានអនុញ្ញាត រួមទាំងការកែប្រែបច្ចេកទេសដែលចាំបាច់ដើម្បីរំកិលវិធានការបច្ចេកទេសមានប្រសិទ្ធភាព។ សម្រាប់គោលបំណងនៃប្រាក់ប័ណ្ណសាធារណៈនេះ ការធ្វើបម្លែងបច្ចេកទេសដោយសេរីដែលបានអនុញ្ញាតឲ្យប្រាក់ប័ណ្ណផ្នែក 2(ក)(4) មិនដែលបង្កើតសម្ភារៈបានផ្លាស់ប្តូរ។
5. អ្នកទទួលក្រោមផ្នែកក្រោម។
ក. ការផ្តល់ជូនពីអ្នកឲ្យប្រាក់ប័ណ្ណ -- សម្ភារៈបានអនុញ្ញាត។ អ្នកទទួលសម្ភារៈបានអនុញ្ញាតគ្រប់រូបទទួលបានការផ្តល់ជូនពីអ្នកឲ្យប្រាក់ប័ណ្ណដោយស្វ័យប្រវត្តិសម្រាប់អនុវត្តសិទ្ធិដែលបានអនុញ្ញាតដោយមានលក្ខខណ្ឌនៃប្រាក់ប័ណ្ណសាធារណៈនេះ។
ខ. ការផ្តល់ជូនបន្ថែមពីអ្នកឲ្យប្រាក់ប័ណ្ណ -- សម្ភារៈបានផ្លាស់ប្តូរ។ អ្នកទទួលសម្ភារៈបានផ្លាស់ប្តូរពីអ្នកទទួលបានស្វ័យប្រវត្តិការផ្តល់ជូនពីអ្នកឲ្យប្រាក់ប័ណ្ណអនុវត្តសិទ្ធិដែលបានអនុញ្ញាតលើសម្ភារៈបានផ្លាស់ប្តូរជាកំណត់ដោយប្រាក់ប័ណ្ណអ្នកផ្លាស់ប្តូរដែលអ្នកអនុវត្ត។
គ. មិនមានការហាមឃាត់ក្រោម។ អ្នកមិនអាចផ្ដល់ឬដាក់លក្ខខណ្ឌបន្ថែម ឬខុសផ្សេងលើសម្ភារៈដែលបានអនុញ្ញាត ឬអនុវត្តវិធានសេ្តក្រិតបច្ចេកទេសណាមួយលើសម្ភារៈដែលបានអនុញ្ញាតបើការធ្វើដូច្នោះហាមឃាត់ភាពសម្របសម្រួលនៃសិទ្ធិដែលបានអនុញ្ញាតដោយអ្នកទទួលសម្ភារៈ។
6. មិនយល់ព្រមពីការគាំទ្រ។ គ្មានអ្វីនៅក្នុងប្រាក់ប័ណ្ណសាធារណៈនេះដែលមានន័យថាការអនុញ្ញាតឬបញ្ជាក់ថាអ្នក ក៏ដូចជាការប្រើប្រាស់សម្ភារៈរបស់អ្នក មានការភ្ជាប់ ឬសង្គ្រោះ ជាភាគីផ្តល់ឬគាំទ្រ ឬអនុញ្ញាតស្ថានភាពផ្លូវការដោយអ្នកឲ្យប្រាក់ប័ណ្ណ ឬអ្នកផ្សេងដែលត្រូវបានកំណត់ឲ្យទទួលបានការទទួលស្គាល់តាមផ្នែក 3(ក)(1)(ក)(i)។
ខ. សិទ្ធិផ្សេងទៀត។
1. សិទ្ធិផ្លូវចិត្ត ឧ.សិទ្ធិនៃភាពស្មោះត្រង់, មិនត្រូវបានបណ្ដេញនៅក្រោមប្រាក់ប័ណ្ណសាធារណៈនេះ ទាំងនេះរួមមានការផ្សព្វផ្សាយផ្ទាល់ខ្លួន, សិទ្ធិនៃឯកជនភាព និង/ឬសិទ្ធិទាក់ទងបុគ្គលភាពផ្សេងៗ; ទោះយ៉ាងណាក៏ដោយ, នៅក្នុងវិមាត្រដែលអាចធ្វើទៅបាន, អ្នកឲ្យប្រាក់ប័ណ្ណបោះបង់ និង/ឬយល់ព្រមមិនប្រើសិទ្ធិទាំងនេះដែលអ្នកឲ្យប្រាក់ប័ណ្ណមាននៅក្នុងកម្រិតដើម្បីអនុញ្ញាតឲ្យអ្នកអនុវត្តសិទ្ធិដែលបានអនុញ្ញាត, តែគ្មានបណ្តោះអាសន្នផ្សេងទៀតទេ។
2. សិទ្ធិប៉ាតង់ និងសិទ្ធិម៉ាកពាណិជ្ជកម្ម មិនត្រូវបានបណ្ដេញនៅក្រោមប្រាក់ប័ណ្ណសាធារណៈនេះ។
3. នៅក្នុងវិមាត្រដែលអាចធ្វើទៅបាន អ្នកឲ្យប្រាក់ប័ណ្ណបោះបង់សិទិ្ធក្នុងការប្រមូលទុកប្រាក់កម្រៃពីអ្នកសម្រាប់ការអនុវត្តសិទ្ធិដែលបានអនុញ្ញាត មិនថាតាមផ្លូវបណ្តាញ ឬតាមវិធានការ លើកលែងខុសពីករណីផ្សេងទៀតដែលអ្នកឲ្យប្រាក់ប័ណ្ណរក្សាសិទ្ធិពិសេសក្នុងការប្រមូលប្រាក់កម្រៃទាំងនេះ។
ផ្នែក 3 -- លក្ខខណ្ឌប្រាក់ប័ណ្ណ។
ការអនុវត្តសិទ្ធិដែលបានអនុញ្ញាតរបស់អ្នក ត្រូវបានបញ្ជាក់នៅក្នុងលក្ខខណ្ឌដូចខាងក្រោម។
ក. ការទទួលស្គាល់។
1. បើអ្នកចែករំលែកសម្ភារៈដែលបានអនុញ្ញាត (រួមទាំងលំនាំដែលបានកែប្រែ), អ្នកត្រូវ៖
ក. រក្សាទុកអ្វីដែលបានផ្ដល់ដោយអ្នកឲ្យប្រាក់ប័ណ្ណជាមួយសម្ភារៈដែលបានអនុញ្ញាត៖
i. ការបញ្ជាក់អំពីអ្នកបង្កើតសម្ភារៈបានអនុញ្ញាត និងអ្នកដទៃដែលត្រូវបានតែងតាំងឲ្យទទួលការទទួលស្គាល់ ជាវិធីណាមួយដែលអ្នកឲ្យប្រាក់ប័ណ្ណស្នើសុំ (រួមទាំងប្រើឈ្មោះប្រូនាំបើបានបញ្ជាក់);
ii. សេចក្តីជូនដំណឹងសិទ្ធិបោះពុម្ព;
iii. សេចក្តីជូនដំណឹងដែលយោងទៅកាន់ប្រាក់ប័ណ្ណសាធារណៈនេះ;
iv. សេចក្តីជូនដំណឹងដែលយោងទៅកាន់ការបដិសេធការធានា;
v. URI ឬតំណភ្ជាប់សម្រាប់សម្ភារៈបានអនុញ្ញាតទៅតាមកម្រិតដែលអាចអនុវត្តបានយ៉ាងសមរម្យ;
ខ. បង្ហាញថាអ្នកបានកែប្រែសម្ភារៈដែលបានអនុញ្ញាត ហើយរក្សាទុកព័ត៌មានអំពីការផ្លាស់ប្តូរមុនៗ;
គ. បង្ហាញថាសម្ភារៈដែលបានអនុញ្ញាតគឺបានអនុញ្ញាតក្រោមប្រាក់ប័ណ្ណសាធារណៈនេះ ហើយរួមបញ្ចូលអត្ថបទ ប្រភព URI ឬតំណភ្ជាប់ទៅកាន់ប្រាក់ប័ណ្ណនេះ។
2. អ្នកអាចបំពេញលក្ខខណ្ឌនៅផ្នែក 3(ក)(1) ដោយវិធីណាមួយដែលសមរម្យលើគ្រប់ប្រភេទមេឌៀ វិធីសាស្ត្រ និងបរិបទដែលអ្នកចែករំលែកសម្ភារៈបានអនុញ្ញាត។ ឧទាហរណ៍ វាអាចជាការសមរម្យក្នុងការផ្តល់ URI ឬតំណភ្ជាប់ទៅកាន់ធនធានដែលរួមបញ្ចូលព័ត៌មានដែលត្រូវការ។
3. ប្រសិនបើមានការស្នើសុំពីអ្នកឲ្យប្រាក់ប័ណ្ណ អ្នកត្រូវយកព័ត៌មានណាមួយដែលត្រូវការដោយផ្នែក 3(ក)(1)(ក) ចេញចោល ដោយផ្អែកលើកម្រិតដែលអាចអនុវត្តបានយ៉ាងសមរម្យ។
ខ. ShareAlike.
បន្ថែមលើលក្ខខណ្ឌនៅផ្នែក 3(ក), ប្រសិនបើអ្នកចែករំលែកសម្ភារៈបានផ្លាស់ប្តូរដែលអ្នកផលិត, លក្ខខណ្ឌខាងក្រោមក៏អនុវត្តដែរ។
1. ប្រាក់ប័ណ្ណអ្នកផ្លាស់ប្តូរដែលអ្នកអនុវត្តត្រូវតែជាប្រាក់ប័ណ្ណ Creative Commons ដែលមានធាតុប្រាក់ប័ណ្ណដូចគ្នា នូវកំណែបច្ចុប្បន្ន ឬក្រោយគ្នា ឬជាប្រាក់ប័ណ្ណ BY-SA ដែលផ្គូរផ្គង។
2. អ្នកត្រូវបញ្ចូលអត្ថបទ ប្រភព URI ឬតំណភ្ជាប់ទៅកាន់ប្រាក់ប័ណ្ណអ្នកផ្លាស់ប្តូរដែលអ្នកអនុវត្ត។ អ្នកអាចបំពេញលក្ខខណ្ឌនេះក្នុងវិធីណាមួយដែលសមរម្យ ដោយផ្អែកលើប្រភេទមេឌៀ វិធីសាស្ត្រ និងបរិបទដែលអ្នកចែករំលែកសម្ភារៈបានផ្លាស់ប្តូរ។
3. អ្នកមិនអាចផ្ដល់ឬដាក់លក្ខខណ្ឌបន្ថែម ឬខុសផ្សេងលើ សម្ភារៈបានផ្លាស់ប្តូរ ឬអនុវត្តវិធានការបច្ចេកទេសមានប្រសិទ្ធភាពឲ្យសម្ភារៈបានផ្លាស់ប្តូរដែលហាមឃាត់ការអនុវត្តសិទ្ធិដែលផ្ដល់ដោយប្រាក់ប័ណ្ណអ្នកផ្លាស់ប្តូរដែលអ្នកអនុវត្ត។
ផ្នែក 4 -- សិទ្ធិទិន្នន័យ Sui Generis។
នៅពេលសិទ្ធិដែលបានអនុញ្ញាតរួមមានសិទ្ធិទិន្នន័យ Sui Generis ដែលអាចអនុវត្តចំពោះការប្រើប្រាស់របស់អ្នកលើសម្ភារៈដែលបានអនុញ្ញាត៖
ក. ដើម្បីជៀសវាងការអះអាង ខ្លឹមសារផ្នែក 2(ក)(1) ផ្ដល់សិទ្ធិឲ្យអ្នកក្នុងការដកយក ធ្វើម្តងទៀត ចម្លង និងចែករំលែកទាំងអស់ ឬផ្នែកត្រឹមត្រូវនៃមាតិកាទិន្នន័យ;
ខ. ប្រសិនបើអ្នករួមបញ្ចូលទិន្នន័យទាំងអស់ ឬផ្នែកត្រឹមត្រូវ នៃមាតិកាទិន្នន័យក្នុងទិន្នន័យដែលអ្នកមានសិទ្ធිទិន្នន័យ Sui Generis...
សិទ្ធិ បន្ទាប់មកមូលដ្ឋានទិន្នន័យដែលអ្នកមានសិទ្ធិមូលដ្ឋានទិន្នន័យ Sui Generis (ប៉ុន្តែមិនមែនមាតិកាផ្ទាល់ខ្លួនរបស់វា) គឺជាសម្ភារះដែលបានដាក់សម្រួល,
រួមទាំងសម្រាប់គោលបំណងនៃមាតិកា 3(b); និង
c. អ្នកត្រូវតែគោរពតាមលក្ខខណ្ឌនៅក្នុងមាតិកា 3(a) ប្រសិនបើអ្នកចែករំលែក
មាតិកាទាំងមូលឬផ្នែកសំខាន់នៃមាតិកា។
សម្រាប់ការបញ្ចាក់ច្បាស់ផុតកង្វះ ចំណុចនេះមាតិកា 4 បន្ថែម និងមិនបាន
ជំនួសការទទួលខុសត្រូវរបស់អ្នកក្រោម បណ្ណៈសាធារណៈនេះដែលមានសិទ្ធិដែលបានអនុញ្ញាតជាមួយសិទ្ធិភាគហ៊ុន និងសិទ្ធិដទៃទៀត។
មាតិកា 5 -- ការមិនធានា និងការកំណត់ច្បាប់នៃការទទួលខុសត្រូវ។
a. បើមិនមានការជូនដំណឹងផ្សេងទៀតពីផ្នែកអ្នកផ្តល់ការអនុញ្ញាត សម្រាប់
ដល់កំរិតដែលអាចធ្វើទៅបាន អ្នកផ្តល់ការអនុញ្ញាតផ្តល់សម្ភារះដែលដាក់បញ្ចូលដោយមិនមានការទទួលខុសត្រូវ ឬធានាណាមួយ
សម្រាប់មាតិកាដែលអនុញ្ញាតនេះ ទោះបីជាត្រូវបានបញ្ជាក់ដោយឬជាលើកទីមួយ ផ្លូវច្បាប់ ឬផ្សេងទៀត។ រួមមាន ប៉ុន្តែមិនកំណត់លើ ការធានាស្ដីពីម្ចាស់កម្មសិទ្ធិ សេវាកម្ម សមស្របសម្រាប់គោលបំណងពិសេស មិនប្រើបាប បញ្ហាមិនទាន់បង្ហាញ ឬផ្សេងៗ ការត្រឹមត្រូវ ឬការបង្ហាញកំហុស ទោះបីជាមិនគាំទ្រឬអាចរកឃើញក៏ដោយ។ បើមិនអនុញ្ញាតឱ្យមានការមិនធានា ពេញលេញឬផ្នែកមួយ ការមិនធានានេះមិនអាចអនុវត្តទៅអ្នកទេ។
b. ដល់កម្រិតដែលអាចធ្វើទៅបាន អ្នកផ្តល់ការអនុញ្ញាតមិនធ្វើការទទួលខុសត្រូវណាមួយ
ទៅលើអ្នកដោយទ្រឹស្តីច្បាប់ណាមួយ (រួមទាំង មិនប្រកាន់ខ្ជង់) ឬផ្សេងទៀត សម្រាប់ការបាត់បង់ផ្ទាល់ ប្លែក ដើម្បីចេញពីការកើតដោយចៃដន្យ ការខូចខាតសម្រាប់រឿង Punitive ឬធ្វើឧទាហរណ៍ ឬបាត់បង់ផ្សេងៗ សំរាប់ថ្លៃដើម ចំណាយ ឬការខូចខាតដែលកើតឡើងពីបណ្ណៈសាធារណៈនេះ ឬការប្រើប្រាស់មាតិកាដែលបានអនុញ្ញាត ទោះបីជាអ្នកផ្តល់ការអនុញ្ញាតបានជូនដំណឹងអំពីករណីបាត់បង់ ផ្លូវច្បាប់ ឬចំណាយទាំងនេះ។ ប្រសិនបើការកំណត់ច្បាប់នេះមិនអាចអនុញ្ញាតបានទាំងមូល ឬមួយផ្នែក ការកំណត់នេះមិនអាចអនុវត្តទៅអ្នកទេ។
c. ការមិនធានា និងការកំណត់ច្បាប់នៃការទទួលខុសត្រូវដែលបានផ្ដល់ខាងលើ
ត្រូវបានបកស្រាយក្នុងរបៀបដែល ដល់កម្រិតដែលអាចធ្វើទៅបាន ស្រដៀងនឹងការធ្វើការមិនទទួលខុសត្រូវ និងលះបង់លើការទទួលខុសត្រូវទាំងអស់។
មាតិកា 6 -- រយៈពេល និងការដាច់ការ។
a. បណ្ណៈសាធារណៈនេះអនុវត្តបានសម្រាប់រយៈពេលនៃសិទ្ធិចម្លង
និងសិទ្ធិដូចគ្នាដែលបានអនុញ្ញាតនៅទីនេះ។ ទោះបីជាយ៉ាងណា ប្រសិនបើអ្នកមិនគោរពបណ្ណៈសាធារណៈនេះ ទិញសិទ្ធិរបស់អ្នកក្រោមបណ្ណៈនេះនឹងផ្តាច់ដោយស្វ័យប្រវត្តិ។
b. នៅពេលដែលសិទ្ធិរបស់អ្នកក្នុងការប្រើមាតិកាដែលបានអនុញ្ញាតផ្តាច់ដោយ
មាតិកា 6(a) វាកត់ត្រាទៅវិញ:
1. ដោយស្វ័យប្រវត្តិចាប់ពីកាលបរិច្ឆេទដែលការរំលែកបានជួសជុល ប្រសិនបើវាត្រូវបានជួសជុលក្នុងរយៈពេល 30 ថ្ងៃពីពេលដែលអ្នកបានរកឃើញកំហុស;
2. នៅពេលមានការដាក់ទៅវិញដោយអ្នកផ្តល់ការអនុញ្ញាតយ៉ាងច្បាស់។
សម្រាប់ការបញ្ចាក់ច្បាស់ មាតិកា 6(b) មិនប៉ះពាល់ដល់សិទ្ធិណាមួយដែលអ្នកផ្តល់ការអនុញ្ញាតប្រហែលជាអាចស្វែងរកសកម្មភាពច្បាប់សម្រាប់ករណីរំលាស់បញ្ហារបស់អ្នក។
c. សម្រាប់ការបញ្ចាក់ច្បាស់ អ្នកផ្តល់ការអនុញ្ញាតអាចផ្តល់សម្ភារះក្រោមលក្ខខណ្ឌឬលក្ខខណ្ឌផ្សេងៗ ឬបញ្ឈប់ការចែកចាយសម្ភារះនៅពេលណាមួយ ប៉ុន្តែការធ្វើបែបនេះមិនមានជាហេតុផលដើម្បីផ្តាច់បណ្ណៈនេះទេ។
d. មាតិកា 1, 5, 6, 7, និង 8 នឹងនៅទីនេះបន្តក្រោយការផ្អាកបណ្ណៈនេះ។
មាតិកា 7 -- លក្ខខណ្ឌ និងលក្ខណៈផ្សេងៗ។
a. អ្នកផ្តល់ការអនុញ្ញាតមិនត្រូវចាប់ខ្សែដោយលក្ខខណ្ឌផ្សេងទៀត ឬលក្ខណៈផ្សេងទៀតដែលអ្នកបានផ្ដល់សេចក្តីជូនដំណឹង ទៅទាល់តែមានការយល់ព្រមយ៉ាងច្បាស់។
b. ការរៀបចំ ការយល់ព្រម ឬការសន្យាណាមួយដែលពាក់ព័ន្ធនឹងមាតិកាដែលបានអនុញ្ញាត មិនត្រូវបានរាប់បញ្ចូលក្នុងនេះ និងជាឯករាជ្យពីលក្ខខណ្ឌនិងលក្ខណៈនៃបណ្ណៈសាធារណៈនេះ។
មាតិកា 8 -- ការបកស្រាយ។
a. សម្រាប់ការបញ្ចាក់ទំនងច្បាស់ បណ្ណៈសាធារណៈនេះ មិនមានន័យ និងមិនត្រូវបានបង្ហាញឱ្យជា ការកាត់បន្ថយ ការរឹតបន្ថយ ការហាមឃាត់ ឬការដាក់លក្ខខណ្ឌលើការប្រើប្រាស់មាតិកាដែលអាចប្រើបានតាមផ្លូវច្បាប់ដោយគ្មានការអនុញ្ញាតក្រោមបណ្ណៈនេះ។
b. ដល់កម្រិតដែលអាចធ្វើទៅបាន ប្រសិនបើថ្នាក់ណាមួយនៃបណ្ណៈសាធារណៈនេះត្រូវបានគេចាត់ទុកថាមិនអាចអនុវត្តបាន វាគួរត្រូវបានកែលម្អដោយស្វ័យប្រវត្តិដោយកម្រិតតិចបំផុតដើម្បីអោយអាចអនុវត្តបាន។ ប្រសិនបើថ្នាក់មិនអាចកែលម្អបាន វាគួរត្រូវបានដកចេញពីបណ្ណៈសាធារណៈនេះដោយគ្មានការប៉ះពាល់ដល់សមត្ថភាពអនុវត្តន៍លក្ខខណ្ឌទាំងនៅសល់។
c. គ្មានលក្ខខណ្ឌ ឬលទ្ធផលណាមួយនៃបណ្ណៈសាធារណៈនេះត្រូវបានលះបង់ និងគ្មានការខកខានណាមួយត្រូវតែផលិតដោយអនុញ្ញាតឱ្យតែមានការយល់ព្រមយ៉ាងច្បាស់ពីអ្នកផ្តល់ការអនុញ្ញាត។
d. គ្មានអ្វីមួយក្នុងបណ្ណៈសាធារណៈនេះបង្កើត ឬអាចត្រូវបានបកស្រាយថាជាការកំណត់ ឬលះបង់លើភាពឯកោ និងសិទ្ធិដែលអាចអនុវត្តរយៈអ្នកផ្តល់ការអនុញ្ញាត ឬអ្នក ប្រសិនបើពាក់ព័ន្ធនឹងដំណើរការរដ្ឋបាលច្បាប់នៅក្នុងតំបន់ណាមួយ។
=======================================================================
Creative Commons មិនមែនជាភាគីនៃបណ្ណៈសាធារណៈទេ។ ទោះយ៉ាងណា Creative Commons អាចជ្រើសរើសធ្វើបណ្ណៈសាធារណៈមួយចំពោះសម្ភារះដែលវាបោះពុម្ពផ្សាយ ហើយក្នុងករណីទាំងនេះ នឹងត្រូវបានចាត់ទុកថា "អ្នកផ្តល់ការអនុញ្ញាត" ។ អត្ថបទនៃបណ្ណៈសាធារណៈ Creative Commons ត្រូវបានចែកចាយក្នុងដែនសាធារណៈក្រោមការផ្ដល់សិទ្ធិ CC0 Public Domain Dedication។ លើកលែងតែជាមួយគោលបំណងកំណត់ថា សម្ភារះត្រូវបានចែករំលែកក្រោមបណ្ណៈសាធារណៈ Creative Commons ឬដូចដែលបានអនុញ្ញាតដោយគោលការណ៍ Creative Commons ដែលបានបោះពុម្ពនៅ creativecommons.org/policies, Creative Commons មិនផ្តល់សិទ្ធិប្រើប្រាស់ម៉ាក "Creative Commons" ឬម៉ាកផ្សេងទៀត ឬរូបសញ្ញារបស់ Creative Commons ដោយគ្មានការយល់ព្រមជាលាយលក្ខណៈសរសេរមុនរបស់វា រួមទាំង ប៉ុន្តែមិនកំណត់ តាមរយៈការផ្លាស់ប្ដូរដោយគ្មានអនុញ្ញាតលើបណ្ណៈណាមួយ រឺការរៀបចំ ការយល់ព្រម ឬកិច្ចសន្យាណាមួយដែលពាក់ព័ន្ធនឹងការប្រើប្រាស់មាតិកាដែលបានអនុញ្ញាត។ សម្រាប់ការបញ្ចាក់ទំនងច្បាស់វា បំបែកនេះមិនជាផ្នែកមួយនៃបណ្ណៈសាធារណៈទេ។
អាចទាក់ទង Creative Commons តាម creativecommons.org។
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការបដិសេធ**៖
ឯកសារនេះត្រូវបានបរាជ័យដោយប្រើសេវាកម្មបកប្រែដោយ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ទោះបីយើងខិតខំប្រឹងប្រែងក្នុងការព្យាយាមឱ្យបានត្រឹមត្រូវ ក៏សូមយល់ព្រមថាការបកប្រែដោយស្វ័យប្រវត្តិអាចមានកំហុសឬភាពមិនត្រឹមត្រូវផ្សេងៗ។ ឯកសារដើមនៅក្នុងភាសាតិជំពាក់គួរត្រូវបានគេចាត់ទុកជាមូលដ្ឋានដែលមានសុពលភាព។ សម្រាប់ពត៌មានសំខាន់ៗ ការបកប្រែដោយអ្នកជំនាញមនុស្សត្រូវបានណែនាំ។ យើងគ្មានការទទួលខុសត្រូវចំពោះការយល់ច្រឡំនៃអ្វីដែលបានបកប្រែនេះទេ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,12 @@
អាចទាញយកសេចក្តីសរុបគំនូររបស់មេរៀនទាំងអស់បាននៅទីនេះ។
🎨 បង្កើតដោយ៖ Tomomi Imura (Twitter: [@girlie_mac](https://twitter.com/girlie_mac), GitHub: [girliemac](https://github.com/girliemac))
[![CC BY-SA 4.0](https://img.shields.io/badge/License-CC%20BY--SA%204.0-lightgrey.svg)](https://creativecommons.org/licenses/by-sa/4.0/)
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការរំដោះទោស**៖
ឯកសារនេះត្រូវបានបកប្រែដោយប្រើសេវាបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេលដែលយើងខិតខំប្រឹងប្រែងដើម្បីភាពត្រឹមត្រូវ សូមកំណត់ចិត្តថា ការបកប្រែដោយស្វ័យប្រវត្តិអាចមានកំហុស ឬភាពមិនត្រឹមត្រូវខ្លះ។ ឯកសារដើមជាភាសាដើមគួរត្រូវបានចាត់ទុកជាភស្តុតាងដែលមានអំណាច។ សម្រាប់ព័ត៌មានដ៏សំខាន់ សូមប្រើការបកប្រែដោយមនុស្សដែលមានជំនាញ។ យើងមិនទទួលខុសត្រូវចំពោះការយល់ច្រឡំ ឬការបកប្រែមិនត្រឹមត្រូវណាមួយ ដោយសារការប្រើប្រាស់ការបកប្រែនេះឡើយ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->

View File

@ -0,0 +1,280 @@
# មគ្គុទេសក៍ដោះស្រាយបញ្ហា AI-សម្រាប់អ្នកដំណើរកាត់ចាប់ផ្តើម
មគ្គុទេសក៍នេះជួយអ្នកដោះស្រាយបញ្ហាទូទៅដែលជួបប្រទៈពេលប្រើប្រាស់ ឬចូលរួមចំណែកក្នុងឃ្លាំង [AI-For-Beginners](https://github.com/microsoft/AI-For-Beginners)។ បញ្ហា និងអ្វីដែលទៅជាមួយនឹងវារួមមាន ប្រែវត្ថុ, រលក្ខណៈ, សេចក្ដីពន្យល់ និងដំណោះស្រាយជាជំហ៊ាន។
---
## តារាងមាតិកា
- [បញ្ហាទូទៅ](#បញ្ហាទូទៅ)
- [បញ្ហាក្នុងការដំឡើង](#បញ្ហាក្នុងការដំឡើង)
- [បញ្ហាកំណត់រចនា](#បញ្ហាកំណត់រចនា)
- [ការប្រតិបត្តិលើកំណត់ត្រា](#ការប្រតិបត្ដិលើកំណត់ត្រា)
- [បញ្ហាផ្នែកប្រសិទ្ធភាព](#បញ្ហាផ្នែកប្រសិទ្ធភាព)
- [បញ្ហាគេហទំព័រពុម្ពភាគ](#បញ្ហាគេហទំព័រពុម្ពភាគ)
- [បញ្ហា​ចូលរួមធ្វើការ](#បញ្ហាចូលរួមធ្វើការ)
- [សំណួរញឹកញាប់](#សំណួរញឹកញាប់)
- [ការទទួលជំនួយ](#ការទទួលជំនួយ)
---
## បញ្ហាទូទៅ
### 1. ឃ្លាំងមិនអាចកើនឡើងបានត្រឹមត្រូវ
**ជំពូក៖** ការក្លូនអនុញ្ញាតឲ្យអ្នកចម្លងឃ្លាំងទៅកាន់ម៉ាស៊ីនរបស់អ្នក។
**រោគសញ្ញា៖**
- ព័តមានកំហុស៖ `fatal: repository not found`
- ព័តមានកំហុស៖ `Permission denied (publickey)`
**មូលហេតុដែលអាចមាន៖**
- អាសយដ្ឋាន URL របស់ឃ្លាំងមិនត្រឹមត្រូវ
- សិទ្ធិការអនុញ្ញាតមិនគ្រប់គ្រាន់
- កូនសោ SSH មិនបានកំណត់រចនា
**ដំណោះស្រាយ៖**
1. **ពិនិត្យអាសយដ្ឋាន URL របស់ឃ្លាំង។**
ប្រើអាសយដ្ឋាន HTTPS៖
```
git clone https://github.com/microsoft/AI-For-Beginners.git
```
2. **ប្តូរទៅ HTTPS ប្រសិនបើ SSH បរាជ័យ។**
ប្រសិនបើអ្នកឃើញ `Permission denied (publickey)` សូមប្រើតំណ HTTPS ខាងលើជំនួស SSH ។
3. **កំណត់រចនាកូនសោ SSH (មិនបាច់ធ្វើក៏បាន)។**
ប្រសិនបើអ្នកចង់ប្រើ SSH សូមអនុវត្តតាម [មគ្គុទេសក៏នៃ SSH របស់ GitHub](https://docs.github.com/en/authentication/connecting-to-github-with-ssh)។
---
## បញ្ហាក្នុងការដំឡើង
### 2. បញ្ហាបរិបទ Python
**ជំពូក៖** ឃ្លាំងអាស្រ័យលើ Python និងបណ្ណាល័យគ្រប់យ៉ាង។
**រោគសញ្ញា៖**
- កំហុស៖ `ModuleNotFoundError: No module named '<package>'`
- កំហុសនាំចូលពេលរត់ script ឬ notebook
**មូលហេតុដែលអាចមាន៖**
- មិនបានដំឡើងទំនាក់ទំនង
- ជំរើស Python មិនត្រឹមត្រូវ
**ដំណោះស្រាយ៖**
1. **បង្កើតបរិបទវីរុស។**
```bash
python -m venv venv
source venv/bin/activate # នៅលើ Windows: venv\Scripts\activate
```
2. **ដំឡើងទំនាក់ទំនង។**
```bash
pip install -r requirements.txt
```
3. **ពិនិត្យជំរើស Python។**
ប្រើ Python 3.7 ឬថ្មីជាង។
```bash
python --version
```
### 3. Jupyter មិនបានដំឡើង
**ជំពូក៖** កំណត់ត្រាគឺជាធនធានសិក្សាអគ្គិសនីសំខាន់មួយ។
**រោគសញ្ញា៖**
- កំហុស៖ `jupyter: command not found`
- កំណត់ត្រាបរាជ័យក្នុងការចាប់ផ្តើម
**មូលហេតុដែលអាចមាន៖**
- មិនបានដំឡើង Jupyter
**ដំណោះស្រាយ៖**
1. **ដំឡើង Jupyter Notebook។**
```bash
pip install notebook
```
ឬ ប្រសិនបើប្រើ Anaconda៖
```bash
conda install notebook
```
2. **ចាប់ផ្តើម Jupyter Notebook។**
```bash
jupyter notebook
```
### 4. ទំនាក់ទំនងជំនាន់បញ្ហា
**ជំពូក៖** គម្រោងអាចខូចប៉ះពាល់ ប្រសិនបើជំនាន់កញ្ចប់មិនស្របគ្នា។
**រោគសញ្ញា៖**
- កំហុស ឬ ការព្រមានអំពីជំនាន់ដែលមិនបា្រក់គ្នា
**មូលហេតុដែលអាចមាន៖**
- កញ្ចប់ Python ចាស់ ឬ ប៉ះពាល់គ្នា
**ដំណោះស្រាយ៖**
1. **ដំឡើងនៅក្នុងបរិបទស្អាត។**
លុបបរិបទ venv/conda ចាស់ ហើយបង្កើតថ្មី។
2. **ប្រើជំនាន់ត្រឹមត្រូវ។**
ជានិច្ចបញ្ចូល:
```bash
pip install -r requirements.txt
```
ប្រសិនបើបរាជ័យនេះ សូមដំឡើងកញ្ចប់ខ្វះដូចបានពណ៌នា​នៅ README ។
---
## បញ្ហាកំណត់រចនា
### 5. ព្រំដែនបរិបទមិនបានកំណត់
**ជំពូក៖** ម៉ូឌុលមួយចំនួនប្រហែលត្រូវការកូនសោ ស្លាក ឬការកំណត់រចនា។
**រោគសញ្ញា៖**
- កំហុស៖ `KeyError` ឬ ការព្រមានអំពីការខ្វះ config
**មូលហេតុដែលអាចមាន៖**
- មិនបានកំណត់ព្រំដែនបរិបទដែលត្រូវការ
**ដំណោះស្រាយ៖**
1. **ពិនិត្យឯកសារ `.env.example` ឬឯកសារលាយៗ។**
2. **បង្កើតឯកសារ `.env` ហើយបំពេញតម្លៃដែលត្រូវការ។**
3. **ផ្ទុកឡើង Terminal ឬ IDE របស់អ្នកបន្ទាប់ពីកំណត់ environment variables។**
---
## ការប្រតិបត្ដិលើកំណត់ត្រា
### 6. កំណត់ត្រាមិនផ្ទុកឬមិនដំណើរការ
**ជំពូក៖** កំណត់ត្រា Jupyter ត្រូវការការកំណត់រចនាឲ្យត្រឹមត្រូវ។
**រោគសញ្ញា៖**
- កំណត់ត្រាបរាជ័យក្នុងការចាប់ផ្តើម
- អន្ដរជាតិសម្រង់មិនបើកឡើងស្វ័យប្រវត្តិ
**មូលហេតុដែលអាចមាន៖**
- មិនបានដំឡើង Jupyter
- បញ្ហាការកំណត់រចនាក្នុងកម្មវិធីរុករក
**ដំណោះស្រាយ៖**
1. **ដំឡើង Jupyter (មើលបញ្ហាក្នុងការដំឡើងខាងលើ)។**
2. **បើកកំណត់ត្រាដោយដៃ​។**
- ចម្លង URL ពី Terminal (ឧ. `http://localhost:8888/?token=...`) ហើយបិទវាទៅកម្មវិធីរុករក។
### 7. Kernel បែកបាក់ ឬ ហើយត្រូវបិទរយះពេលយូរ
**ជំពូក៖** Kernel កំណត់ត្រាអាចបែកដោយសារកំណត់ធនធានឬកូដមានកំហុស។
**រោគសញ្ញា៖**
- Kernel ស្លាប់ ឬ ចាប់ផ្តើមឡើងវិញជាបន្តបន្ទាប់
- កំហុសចុះពីអង្គចងចាំ (out-of-memory)
**មូលហេតុដែលអាចមាន៖**
- ទិន្នន័យធំ
- កូដ ឬ កញ្ចប់មិនស្របគ្នា
**ដំណោះស្រាយ៖**
1. **ចាប់ផ្តើម Kernel ថ្មី។**
ប្រើប៊ូតុង "Restart Kernel" នៅក្នុង Jupyter។
2. **ពិនិត្យការប្រើប្រាស់អង្គចងចាំ។**
បិទកម្មវិធីដែលមិនបានប្រើ។
3. **រត់កំណត់ត្រានៅលើវេទិកាបណ្តាញ។**
ប្រើ [Google Colab](https://colab.research.google.com/) ឬ [Azure Notebooks](https://notebooks.azure.com/)។
---
## បញ្ហាផ្នែកប្រសិទ្ធភាព
### 8. កំណត់ត្រារត់យឺត
**ជំពូក៖** ភារកិច្ច AI មួយចំនួនតម្រូវឲ្យមានអង្គចងចាំ និង CPU ច្រើន។
**រោគសញ្ញា៖**
- រត់យឺត
- សំឡេងកង្ហារលេបក្តៅម៉ាស៊ីនកុំភ្លេច
**មូលហេតុដែលអាចមាន៖**
- ទិន្នន័យ ឬ ម៉ូឌែលធំ
- អង្គចងចាំក្នុងប្រព័ន្ធមានកំណត់
**ដំណោះស្រាយ៖**
1. **ប្រើវេទិកាបណ្តាញ។**
- បញ្ចូលកំណត់ត្រាទៅ Colab ឬ Azure Notebooks។
2. **កាត់បន្ថយទំហំទិន្នន័យ។**
- ប្រើទិន្នន័យគំរូសម្រាប់ហាត់ប្រាណ។
3. **បិទកម្មវិធីមិនចាំបាច់។**
- ទទួលបាន RAM ល្អបំផុតសម្រាប់ប្រព័ន្ធ។
---
## បញ្ហាគេហទំព័រពុម្ពភាគ
### 9. មាតិកាផ្សាប់មិនបានផ្ទុក
**ជំពូក៖** សៀវភៅអេឡិចត្រូនិចបង្ហាញមេរៀន និងជំពូក។
**រោគសញ្ញា៖**
- មាតិកាយ៉ាងណាមួយ (ឧ. Transformers/BERT) ខ្វះ ឬ មិនបើកឡើង
**បញ្ហាល្បី៖**
- [បញ្ហា #303](https://github.com/microsoft/AI-For-Beginners/issues/303): “18 Transformers. BERT. មិនអាចបើកបាននៅលើគេហទំព័រពុម្ពភាគ។” មានហេតុពីកំហុសឈ្មោះឯកសារ (`READMEtransformers.md` ជំនួសឲ្យ `README.md`)។
**ដំណោះស្រាយ៖**
1. **ពិនិត្យកំហុសប្តូរឈ្មោះឯកសារ។**
ប្រសិនបើអ្នកជាអ្នកចូលរួម សូមធានាថាឯកសារជំពូកមានឈ្មោះជា `README.md`
2. **រាយការណ៍ឯកសារខ្វះ។**
បើកបញ្ហារបស់ GitHub ជាមួយឈ្មោះជំពូក និងព័ត៌មានកំហុស។
---
## បញ្ហាចូលរួមធ្វើការ
### 10. PR មិនទទួល ឬ ការសាងសង់បរាជ័យ
**ជំពូក៖** ការចូលរួមត្រូវតែឆ្លងកាត់ការធ្វើតេស្ដ និងអនុវត្តផែនការទាញយក។
**រោគសញ្ញា៖**
- ការស្នើប្រាក់ចូលRejected
- កំហុសក្នុង CI/CD pipeline
**មូលហេតុដែលអាចមាន៖**
- ទេស្ដបរាជ័យ
- មិនអនុវត្តតាមស្តង់ដារកូដ
**ដំណោះស្រាយ៖**
1. **អានក្រុមប្រឹក្សាចូលរួម។**
- អនុវត្តតាម [CONTRIBUTING.md](https://github.com/microsoft/AI-For-Beginners/blob/main/CONTRIBUTING.md) របស់ឃ្លាំង។
2. **ធ្វើតេស្ដក្នុងម៉ាស៊ីនមូលដ្ឋានមុនចុចបញ្ជូន។**
3. **ពិនិត្យច្បាប់ linting ឬតម្រូវការរចនា។**
---
## សំណួរញឹកញាប់
### តើខ្ញុំអាចស្វែងរកជំនួយសម្រាប់ម៉ូឌុលជាក់លាក់នៅណា?
- ម៉ូឌុលនីមួយៗភាគច្រើនមាន README របស់វា។ ចាប់ផ្តើមនៅទីនោះសម្រាប់ការដំឡើង និងកំណត់ប្រើប្រាស់។
### តើធ្វើដូចម្តេចដើម្បីរាយការណ៍កំហុស ឬស្នើសុំមុខងារថ្មី?
- [បើកបញ្ហា GitHub](https://github.com/microsoft/AI-For-Beginners/issues/new) ជាមួយការពិពណ៌នាស្រួលយល់ និងជំហ៊ានសម្រាប់បង្កើតតាម។
### តើខ្ញុំអាចស្នើសុំជំនួយប្រសិនបើបញ្ហារបស់ខ្ញុំមិនមានក្នុងបញ្ជីទេ?
- បាន! ស្វែងរកបញ្ហាដែលមានជាមុនសិន ហើយប្រសិនបើមិនមានបញ្ហារបស់អ្នក សូមបង្កើតបញ្ហាថ្មី។
---
## ការទទួលជំនួយ
- **ពិនិត្យបញ្ហា៖** [GitHub Issues](https://github.com/microsoft/AI-For-Beginners/issues)
- **សួរសំណួរ៖** ប្រើការពិភាក្សា GitHub ឬបើកបញ្ហា។
- **សហគមន៍៖** មើលតំណភ្ជាប់ឃ្លាំងសម្រាប់ជម្រើសជជែក/វេទិកា។
---
_បានបន្តបន្ទាប់ចុងក្រោយ៖ 2025-09-20_
---
<!-- CO-OP TRANSLATOR DISCLAIMER START -->
**ការផ្សងព្រេង**:
ឯកសារនេះបានបកប្រែដោយប្រើសេវាកម្មបកប្រែ AI [Co-op Translator](https://github.com/Azure/co-op-translator)។ ខណៈពេលយើងខិតខំប្រឹងប្រែងដើម្បីភាពត្រឹមត្រូវ សូមពាក់ព័ន្ធថាបកប្រែដោយកម្មវិធីអាចមានខុសត្រូវ ឬកំហុសបាន។ ឯកសារដើមដែលនៅក្នុងភាសាគោលត្រូវបានទទួលស្គាល់ថាជាដើមឯកសារដែលមានសុពលភាព។ សម្រាប់ព័ត៌មានសំខាន់ ការបកប្រែដោយមនុស្សជំនាញគឺគួរឱ្យយកចិត្តទុកដាក់។ យើងមិនទទួលខុសត្រូវចំពោះការយល់មិនអាចកើតមាន ឬក៏ការបកប្រត្យាសខុសផ្សេងៗពីការប្រើប្រាស់បកប្រែនេះឡើយ។
<!-- CO-OP TRANSLATOR DISCLAIMER END -->