diff --git a/.github/workflows/build_documentation.yml b/.github/workflows/build_documentation.yml index a3e462fbe..339d7a254 100644 --- a/.github/workflows/build_documentation.yml +++ b/.github/workflows/build_documentation.yml @@ -14,6 +14,6 @@ jobs: package: course path_to_docs: course/chapters/ additional_args: --not_python_module - languages: ar bn de en es fa fr gj he hi id it ja ko my ne pl pt ru ro te th tr vi zh-CN zh-TW + languages: ar bn de en es fa fr gj he hi id it ja ko ml my ne pl pt ru ro te th tr vi zh-CN zh-TW secrets: hf_token: ${{ secrets.HF_DOC_BUILD_PUSH }} diff --git a/.github/workflows/build_pr_documentation.yml b/.github/workflows/build_pr_documentation.yml index 7bceda10f..dde410abc 100644 --- a/.github/workflows/build_pr_documentation.yml +++ b/.github/workflows/build_pr_documentation.yml @@ -16,4 +16,4 @@ jobs: package: course path_to_docs: course/chapters/ additional_args: --not_python_module - languages: ar bn de en es fa fr gj he hi id it ja ko my ne pl pt ru ro te th tr vi zh-CN zh-TW + languages: ar bn de en es fa fr gj he hi id it ja ko ml my ne pl pt ru ro te th tr vi zh-CN zh-TW diff --git a/README.md b/README.md index d26b326b1..d1ba443ad 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ This repo contains the content that's used to create the **[Hugging Face course] | [Chinese (simplified)](https://huggingface.co/course/zh-CN/chapter1/1) | [`chapters/zh-CN`](https://github.com/huggingface/course/tree/main/chapters/zh-CN) | [@zhlhyx](https://github.com/zhlhyx), [petrichor1122](https://github.com/petrichor1122), [@1375626371](https://github.com/1375626371) | | [Chinese (traditional)](https://huggingface.co/course/zh-TW/chapter1/1) (WIP) | [`chapters/zh-TW`](https://github.com/huggingface/course/tree/main/chapters/zh-TW) | [@davidpeng86](https://github.com/davidpeng86), [@thliang01](https://github.com/thliang01) | | [Romanian](https://huggingface.co/course/ro/chapter1/1) (WIP) | [`chapters/ro`](https://github.com/huggingface/course/tree/main/chapters/ro) | [@Sigmoid](https://github.com/SigmoidAI), [@eduard-balamatiuc](https://github.com/eduard-balamatiuc), [@FriptuLudmila](https://github.com/FriptuLudmila), [@tokyo-s](https://github.com/tokyo-s), [@hbkdesign](https://github.com/hbkdesign), [@grumpycatyo-collab](https://github.com/grumpycatyo-collab), [@Angroys](https://github.com/Angroys) | +| [Malayalam](https://huggingface.co/course/ml/chapter1/1) (WIP) | [`chapters/ml`](https://github.com/huggingface/course/tree/main/chapters/ml) | [@nikhilkilivayil](https://github.com/nikhilkilivayil) | ### Translating the course into your language diff --git a/chapters/en/chapter1/1.mdx b/chapters/en/chapter1/1.mdx index 9294f9af1..e36ac521f 100644 --- a/chapters/en/chapter1/1.mdx +++ b/chapters/en/chapter1/1.mdx @@ -141,6 +141,7 @@ Thanks to our wonderful community, the course is available in many languages bey | [Thai](https://huggingface.co/course/th/chapter1/1) (WIP) | [@peeraponw](https://github.com/peeraponw), [@a-krirk](https://github.com/a-krirk), [@jomariya23156](https://github.com/jomariya23156), [@ckingkan](https://github.com/ckingkan) | | [Turkish](https://huggingface.co/course/tr/chapter1/1) (WIP) | [@tanersekmen](https://github.com/tanersekmen), [@mertbozkir](https://github.com/mertbozkir), [@ftarlaci](https://github.com/ftarlaci), [@akkasayaz](https://github.com/akkasayaz) | | [Chinese (traditional)](https://huggingface.co/course/zh-TW/chapter1/1) (WIP) | [@davidpeng86](https://github.com/davidpeng86) | +| [Malayalam](https://huggingface.co/course/ml/chapter1/1) (WIP) | [@nikhilkilivayil](https://github.com/nikhilkilivayil) | For some languages, the [course YouTube videos](https://youtube.com/playlist?list=PLo2EIpI_JMQvWfQndUesu0nPBAtZ9gP1o) have subtitles in the language. You can enable them by first clicking the _CC_ button in the bottom right corner of the video. Then, under the settings icon ⚙️, you can select the language you want by selecting the _Subtitles/CC_ option. diff --git a/chapters/ml/TRANSLATING.txt b/chapters/ml/TRANSLATING.txt new file mode 100644 index 000000000..2775fdea6 --- /dev/null +++ b/chapters/ml/TRANSLATING.txt @@ -0,0 +1,34 @@ +1. ഈ വിവർത്തനത്തിന്റെ ലക്ഷ്യം മലയാളം സംസാരിക്കുന്ന പഠിതാക്കൾക്ക് സ്വാഭാവികമായി വായിക്കാവുന്ന, വ്യക്തമായ ഒരു കോഴ്‌സ് നൽകുകയാണ് — വാക്കിനുവാക്ക് പരിഭാഷയല്ല, അർത്ഥം കൃത്യമായി കൈമാറുന്ന പരിഭാഷയാണ് വേണ്ടത്. + +2. സാങ്കേതിക പദങ്ങൾ (technical terms): മെഷീൻ ലേണിംഗ് / NLP മേഖലയിലെ സ്ഥാപിതമായ ഇംഗ്ലീഷ് പദങ്ങൾ ഇംഗ്ലീഷിൽ തന്നെ നിലനിർത്തുക, അല്ലെങ്കിൽ മലയാള ലിപിയിൽ എഴുതുക (transliteration). ഉദാഹരണം: + - Transformer → Transformer / ട്രാൻസ്‌ഫോർമർ + - model → മോഡൽ + - token / tokenizer / tokenization → ടോക്കൺ / ടോക്കണൈസർ / ടോക്കണൈസേഷൻ + - fine-tuning → ഫൈൻ-ട്യൂണിംഗ് + - pretraining → പ്രീട്രെയിനിംഗ് + - encoder / decoder → എൻകോഡർ / ഡീകോഡർ + - attention → അറ്റൻഷൻ + - embedding → എംബെഡ്ഡിംഗ് + - dataset → ഡേറ്റാസെറ്റ് + - pipeline → പൈപ്പ്‌ലൈൻ + - inference → ഇൻഫറൻസ് + - prompt → പ്രോംപ്‌റ്റ് + - checkpoint → ചെക്ക്‌പോയിന്റ് + - library → ലൈബ്രറി + - notebook → നോട്ട്‌ബുക്ക് + - GPU / CPU / API / LLM / NLP → അതേപടി (ഇംഗ്ലീഷിൽ) + ആദ്യമായി ഒരു പദം വരുമ്പോൾ ആവശ്യമെങ്കിൽ ബ്രാക്കറ്റിൽ ഇംഗ്ലീഷ് പദം ചേർക്കാം: ഉദാ. "അറ്റൻഷൻ (attention)". + +3. ഇവ വിവർത്തനം ചെയ്യരുത്: + - കോഡ് ബ്ലോക്കുകൾ, ഇൻലൈൻ കോഡ് (`...`), ഫയൽ/ഫോൾഡർ പേരുകൾ, കമാൻഡുകൾ + - URL-കൾ, ചിത്രങ്ങളുടെ പാതകൾ (image paths) + - MDX ഘടകങ്ങൾ (, , , ,
...) — ഇവയുടെ ആട്രിബ്യൂട്ടുകൾ അതേപടി വയ്ക്കുക; വായിക്കാവുന്ന ടെക്‌സ്‌റ്റ് മാത്രം (text, explain, alt) വിവർത്തനം ചെയ്യുക + - തലക്കെട്ടുകളിലെ anchor ID-കൾ: `## തലക്കെട്ട്[[anchor-id]]` — anchor ഇംഗ്ലീഷിൽ അതേപടി നിലനിർത്തുക + - മോഡലുകളുടെയും ലൈബ്രറികളുടെയും കമ്പനികളുടെയും പേരുകൾ (BERT, GPT, Llama, 🤗 Transformers, Hugging Face Hub, Google Colab, PyTorch ...) + - വ്യക്തികളുടെ പേരുകൾ (ഇംഗ്ലീഷിൽ നിലനിർത്തുക) + +4. ശൈലി: വായനക്കാരനെ ബഹുമാനപൂർവ്വം "നിങ്ങൾ" എന്ന് അഭിസംബോധന ചെയ്യുക. ലളിതവും സംഭാഷണാത്മകവുമായ, എന്നാൽ കൃത്യമായ മലയാളം ഉപയോഗിക്കുക. വളരെ സംസ്‌കൃതവത്കൃതമായ പദങ്ങളെക്കാൾ സാധാരണ ഉപയോഗത്തിലുള്ള പദങ്ങൾക്ക് മുൻഗണന നൽകുക. + +5. അക്ഷരവിന്യാസം: ഏകീകൃതമായ യൂണികോഡ് മലയാളം (ചില്ലക്ഷരങ്ങൾക്ക് atomic chillu: ൻ ർ ൽ ൾ ൺ) ഉപയോഗിക്കുക. ആവശ്യമുള്ളിടത്ത് ZWJ/ZWNJ ഉപയോഗിക്കാം. + +6. Markdown ഘടന (തലക്കെട്ടുകളുടെ ലെവൽ, ലിസ്റ്റുകൾ, ബോൾഡ്/ഇറ്റാലിക്, ടേബിളുകൾ, ഒഴിഞ്ഞ വരികൾ) ഇംഗ്ലീഷ് മൂലത്തിന് സമാനമായി നിലനിർത്തുക. diff --git a/chapters/ml/_toctree.yml b/chapters/ml/_toctree.yml new file mode 100644 index 000000000..9f88957b7 --- /dev/null +++ b/chapters/ml/_toctree.yml @@ -0,0 +1,154 @@ +- title: 0. സജ്ജീകരണം + sections: + - local: chapter0/1 + title: ആമുഖം + +- title: 1. Transformer മോഡലുകൾ + sections: + - local: chapter1/1 + title: ആമുഖം + - local: chapter1/2 + title: നാച്ചുറൽ ലാംഗ്വേജ് പ്രോസസ്സിംഗും ലാർജ് ലാംഗ്വേജ് മോഡലുകളും + - local: chapter1/3 + title: Transformer-കൾക്ക് എന്തെല്ലാം ചെയ്യാൻ കഴിയും? + - local: chapter1/4 + title: Transformer-കൾ എങ്ങനെ പ്രവർത്തിക്കുന്നു? + - local: chapter1/5 + title: 🤗 Transformers എങ്ങനെ ടാസ്‌ക്കുകൾ പരിഹരിക്കുന്നു + - local: chapter1/6 + title: Transformer ആർക്കിടെക്ചറുകൾ + - local: chapter1/7 + title: ചെറു ക്വിസ് + - local: chapter1/8 + title: LLM-കൾ ഉപയോഗിച്ചുള്ള ഇൻഫറൻസ് + - local: chapter1/9 + title: പക്ഷപാതവും പരിമിതികളും + - local: chapter1/10 + title: സംഗ്രഹം + - local: chapter1/11 + title: സർട്ടിഫിക്കേഷൻ പരീക്ഷ + quiz: 1 + +- title: 2. 🤗 Transformers ഉപയോഗിക്കുന്നത് + sections: + - local: chapter2/1 + title: ആമുഖം + - local: chapter2/2 + title: പൈപ്പ്‌ലൈനിന്റെ പിന്നിൽ + - local: chapter2/3 + title: മോഡലുകൾ + - local: chapter2/4 + title: ടോക്കണൈസറുകൾ + - local: chapter2/5 + title: ഒന്നിലധികം സീക്വൻസുകൾ കൈകാര്യം ചെയ്യുന്നത് + - local: chapter2/6 + title: എല്ലാം ഒരുമിച്ച് ചേർക്കുന്നത് + - local: chapter2/7 + title: അടിസ്ഥാന ഉപയോഗം പൂർത്തിയായി! + - local: chapter2/8 + title: ഒപ്‌റ്റിമൈസ് ചെയ്ത ഇൻഫറൻസ് ഡിപ്ലോയ്‌മെന്റ് + - local: chapter2/9 + title: അധ്യായാന്ത്യ ക്വിസ് + quiz: 2 + +- title: 3. ഒരു പ്രീട്രെയിൻഡ് മോഡൽ ഫൈൻ-ട്യൂൺ ചെയ്യുന്നത് + sections: + - local: chapter3/1 + title: ആമുഖം + - local: chapter3/2 + title: ഡേറ്റ പ്രോസസ്സ് ചെയ്യുന്നത് + - local: chapter3/3 + title: Trainer API ഉപയോഗിച്ച് ഒരു മോഡൽ ഫൈൻ-ട്യൂൺ ചെയ്യുന്നത് + - local: chapter3/4 + title: ഒരു പൂർണ്ണ ട്രെയിനിംഗ് ലൂപ്പ് + - local: chapter3/5 + title: ലേണിംഗ് കർവുകൾ മനസ്സിലാക്കുന്നത് + - local: chapter3/6 + title: ഫൈൻ-ട്യൂണിംഗ്, പൂർത്തിയായി! + - local: chapter3/7 + title: അധ്യായാന്ത്യ ക്വിസ് + quiz: 3 + +- title: 4. മോഡലുകളും ടോക്കണൈസറുകളും പങ്കുവയ്ക്കുന്നത് + sections: + - local: chapter4/1 + title: Hugging Face Hub + - local: chapter4/2 + title: പ്രീട്രെയിൻഡ് മോഡലുകൾ ഉപയോഗിക്കുന്നത് + - local: chapter4/3 + title: പ്രീട്രെയിൻഡ് മോഡലുകൾ പങ്കുവയ്ക്കുന്നത് + - local: chapter4/4 + title: ഒരു മോഡൽ കാർഡ് നിർമ്മിക്കുന്നത് + - local: chapter4/5 + title: ഭാഗം 1 പൂർത്തിയായി! + - local: chapter4/6 + title: അധ്യായാന്ത്യ ക്വിസ് + quiz: 4 + +- title: 5. 🤗 Datasets ലൈബ്രറി + sections: + - local: chapter5/1 + title: ആമുഖം + - local: chapter5/2 + title: എന്റെ ഡേറ്റാസെറ്റ് Hub-ൽ ഇല്ലെങ്കിലോ? + - local: chapter5/3 + title: ഡേറ്റ അരിഞ്ഞു മുറിക്കാൻ സമയമായി + - local: chapter5/4 + title: ബിഗ് ഡേറ്റയോ? 🤗 Datasets രക്ഷയ്‌ക്കെത്തുന്നു! + - local: chapter5/5 + title: നിങ്ങളുടെ സ്വന്തം ഡേറ്റാസെറ്റ് ഉണ്ടാക്കുന്നത് + - local: chapter5/6 + title: FAISS ഉപയോഗിച്ചുള്ള സെമാന്റിക് സെർച്ച് + - local: chapter5/7 + title: 🤗 Datasets, പൂർത്തിയായി! + - local: chapter5/8 + title: അധ്യായാന്ത്യ ക്വിസ് + quiz: 5 + +- title: 6. 🤗 Tokenizers ലൈബ്രറി + sections: + - local: chapter6/1 + title: ആമുഖം + - local: chapter6/2 + title: ഒരു പഴയ ടോക്കണൈസറിൽ നിന്ന് ഒരു പുതിയ ടോക്കണൈസർ ട്രെയിൻ ചെയ്യുന്നത് + - local: chapter6/3 + title: ഫാസ്‌റ്റ് ടോക്കണൈസറുകളുടെ പ്രത്യേക ശക്തികൾ + - local: chapter6/3b + title: QA പൈപ്പ്‌ലൈനിലെ ഫാസ്‌റ്റ് ടോക്കണൈസറുകൾ + - local: chapter6/4 + title: നോർമലൈസേഷനും പ്രീ-ടോക്കണൈസേഷനും + - local: chapter6/5 + title: Byte-Pair Encoding ടോക്കണൈസേഷൻ + - local: chapter6/6 + title: WordPiece ടോക്കണൈസേഷൻ + - local: chapter6/7 + title: Unigram ടോക്കണൈസേഷൻ + - local: chapter6/8 + title: ഒരു ടോക്കണൈസർ ബ്ലോക്ക് ബ്ലോക്കായി നിർമ്മിക്കുന്നത് + - local: chapter6/9 + title: Tokenizers, പൂർത്തിയായി! + - local: chapter6/10 + title: അധ്യായാന്ത്യ ക്വിസ് + quiz: 6 + +- title: 7. ക്ലാസിക്കൽ NLP ടാസ്‌ക്കുകൾ + sections: + - local: chapter7/1 + title: ആമുഖം + - local: chapter7/2 + title: ടോക്കൺ ക്ലാസിഫിക്കേഷൻ + - local: chapter7/3 + title: ഒരു മാസ്‌ക്‌ഡ് ലാംഗ്വേജ് മോഡൽ ഫൈൻ-ട്യൂൺ ചെയ്യുന്നത് + - local: chapter7/4 + title: വിവർത്തനം + - local: chapter7/5 + title: സമ്മറൈസേഷൻ + - local: chapter7/6 + title: ഒരു കോസൽ ലാംഗ്വേജ് മോഡൽ പൂജ്യത്തിൽ നിന്ന് ട്രെയിൻ ചെയ്യുന്നത് + - local: chapter7/7 + title: ചോദ്യോത്തരം + - local: chapter7/8 + title: LLM-കളിൽ പ്രാവീണ്യം നേടുന്നത് + - local: chapter7/9 + title: അധ്യായാന്ത്യ ക്വിസ് + quiz: 7 diff --git a/chapters/ml/chapter0/1.mdx b/chapters/ml/chapter0/1.mdx new file mode 100644 index 000000000..8d992746f --- /dev/null +++ b/chapters/ml/chapter0/1.mdx @@ -0,0 +1,110 @@ +# ആമുഖം[[introduction]] + +Hugging Face കോഴ്‌സിലേക്ക് സ്വാഗതം! ഈ ആമുഖം നിങ്ങളെ ഒരു വർക്കിംഗ് എൻവയോൺമെന്റ് (working environment) സജ്ജമാക്കാൻ സഹായിക്കും. നിങ്ങൾ കോഴ്‌സ് ഇപ്പോൾ തുടങ്ങുകയാണെങ്കിൽ, ആദ്യം [അധ്യായം 1](/course/chapter1) ഒന്ന് നോക്കുകയും, പിന്നീട് തിരിച്ചുവന്ന് എൻവയോൺമെന്റ് സജ്ജമാക്കുകയും ചെയ്യാൻ ഞങ്ങൾ ശുപാർശ ചെയ്യുന്നു — അങ്ങനെ കോഡ് നിങ്ങൾക്ക് സ്വയം പരീക്ഷിച്ചുനോക്കാം. + +ഈ കോഴ്‌സിൽ നാം ഉപയോഗിക്കുന്ന എല്ലാ ലൈബ്രറികളും Python പാക്കേജുകളായി ലഭ്യമാണ്. അതിനാൽ ഒരു Python എൻവയോൺമെന്റ് എങ്ങനെ സജ്ജമാക്കാമെന്നും നിങ്ങൾക്ക് ആവശ്യമായ ലൈബ്രറികൾ എങ്ങനെ ഇൻസ്‌റ്റാൾ ചെയ്യാമെന്നും ഇവിടെ കാണിച്ചുതരാം. + +വർക്കിംഗ് എൻവയോൺമെന്റ് സജ്ജമാക്കാനുള്ള രണ്ട് വഴികളാണ് നാം ഇവിടെ പരിചയപ്പെടുന്നത്: ഒരു Colab നോട്ട്‌ബുക്ക് ഉപയോഗിക്കുക, അല്ലെങ്കിൽ ഒരു Python വിർച്വൽ എൻവയോൺമെന്റ് (virtual environment) ഉപയോഗിക്കുക. നിങ്ങൾക്ക് ഏറ്റവും ഇണങ്ങുന്നത് ഏതാണോ അത് തിരഞ്ഞെടുക്കാം. തുടക്കക്കാർക്ക് Colab നോട്ട്‌ബുക്ക് ഉപയോഗിച്ച് ആരംഭിക്കാനാണ് ഞങ്ങൾ ശക്തമായി ശുപാർശ ചെയ്യുന്നത്. + +Windows സിസ്‌റ്റം ഇവിടെ പ്രതിപാദിക്കുന്നില്ല എന്നത് ശ്രദ്ധിക്കുക. നിങ്ങൾ Windows-ലാണെങ്കിൽ, ഒരു Colab നോട്ട്‌ബുക്ക് ഉപയോഗിച്ച് പിന്തുടരാൻ ഞങ്ങൾ ശുപാർശ ചെയ്യുന്നു. Linux ഡിസ്ട്രിബ്യൂഷനോ macOS-ഓ ആണ് ഉപയോഗിക്കുന്നതെങ്കിൽ, ഇവിടെ വിവരിക്കുന്ന രണ്ട് രീതികളിൽ ഏതും ഉപയോഗിക്കാം. + +കോഴ്‌സിന്റെ ഭൂരിഭാഗവും നിങ്ങൾക്ക് ഒരു Hugging Face അക്കൗണ്ട് ഉണ്ടെന്ന അനുമാനത്തിലാണ്. ഇപ്പോൾ തന്നെ ഒന്ന് ഉണ്ടാക്കാൻ ഞങ്ങൾ ശുപാർശ ചെയ്യുന്നു: [ഒരു അക്കൗണ്ട് ഉണ്ടാക്കുക](https://huggingface.co/join). + +## ഒരു Google Colab നോട്ട്‌ബുക്ക് ഉപയോഗിക്കുന്നത്[[using-a-google-colab-notebook]] + +Colab നോട്ട്‌ബുക്ക് ഉപയോഗിക്കുന്നതാണ് സാധ്യമായതിൽ ഏറ്റവും ലളിതമായ സെറ്റപ്പ്; ബ്രൗസറിൽ ഒരു നോട്ട്‌ബുക്ക് തുറന്ന് നേരെ കോഡിംഗിലേക്ക് കടക്കാം! + +Colab നിങ്ങൾക്ക് പരിചിതമല്ലെങ്കിൽ, [ആമുഖം](https://colab.research.google.com/notebooks/intro.ipynb) പിന്തുടർന്ന് തുടങ്ങാൻ ഞങ്ങൾ ശുപാർശ ചെയ്യുന്നു. GPU-കൾ, TPU-കൾ പോലുള്ള ആക്സിലറേറ്റിംഗ് ഹാർഡ്‌വെയർ ഉപയോഗിക്കാൻ Colab അനുവദിക്കുന്നു, ചെറിയ വർക്ക്‌ലോഡുകൾക്ക് ഇത് സൗജന്യവുമാണ്. + +Colab-ൽ സഞ്ചരിക്കാൻ നിങ്ങൾക്ക് സൌകര്യമായിക്കഴിഞ്ഞാൽ, ഒരു പുതിയ നോട്ട്‌ബുക്ക് ഉണ്ടാക്കി സെറ്റപ്പ് ആരംഭിക്കുക: + +
+ഒരു ഒഴിഞ്ഞ colab നോട്ട്‌ബുക്ക് +
+ +അടുത്ത പടി ഈ കോഴ്‌സിൽ നാം ഉപയോഗിക്കുന്ന ലൈബ്രറികൾ ഇൻസ്‌റ്റാൾ ചെയ്യുകയാണ്. ഇൻസ്‌റ്റാളേഷനായി നാം Python-ന്റെ പാക്കേജ് മാനേജറായ `pip` ഉപയോഗിക്കും. നോട്ട്‌ബുക്കുകളിൽ, കമാൻഡിന് മുന്നിൽ `!` എന്ന ചിഹ്നം ചേർത്ത് സിസ്‌റ്റം കമാൻഡുകൾ റൺ ചെയ്യാം. അതിനാൽ 🤗 Transformers ലൈബ്രറി ഇങ്ങനെ ഇൻസ്‌റ്റാൾ ചെയ്യാം: + +``` +!pip install transformers +``` + +Python റൺടൈമിനുള്ളിൽ ഇംപോർട്ട് ചെയ്തുനോക്കി പാക്കേജ് ശരിയായി ഇൻസ്‌റ്റാൾ ആയെന്ന് ഉറപ്പാക്കാം: + +``` +import transformers +``` + +
+മുകളിലെ രണ്ട് കമാൻഡുകളുടെ ഫലം കാണിക്കുന്ന ഒരു gif: ഇൻസ്‌റ്റാളേഷനും ഇംപോർട്ടും +
+ +ഇത് 🤗 Transformers-ന്റെ വളരെ ലഘുവായ ഒരു പതിപ്പാണ് ഇൻസ്‌റ്റാൾ ചെയ്യുന്നത്. പ്രത്യേകിച്ച്, ഒരു മെഷീൻ ലേണിംഗ് ഫ്രെയിംവർക്കും (PyTorch അല്ലെങ്കിൽ TensorFlow പോലുള്ളവ) ഇതിൽ ഇൻസ്‌റ്റാൾ ആകുന്നില്ല. ലൈബ്രറിയുടെ പലതരം ഫീച്ചറുകൾ നാം ഉപയോഗിക്കാൻ പോകുന്നതിനാൽ, ഡെവലപ്‌മെന്റ് പതിപ്പ് ഇൻസ്‌റ്റാൾ ചെയ്യാൻ ഞങ്ങൾ ശുപാർശ ചെയ്യുന്നു — ഊഹിക്കാവുന്ന ഏതാണ്ട് എല്ലാ ഉപയോഗങ്ങൾക്കും ആവശ്യമായ ഡിപ്പൻഡൻസികൾ (dependencies) ഇതിനൊപ്പം വരും: + +``` +!pip install transformers[sentencepiece] +``` + +ഇതിന് അൽപ്പം സമയമെടുക്കും, പക്ഷേ അതു കഴിഞ്ഞാൽ കോഴ്‌സിന്റെ ബാക്കി ഭാഗത്തിന് നിങ്ങൾ തയ്യാറായി! + +## ഒരു Python വിർച്വൽ എൻവയോൺമെന്റ് ഉപയോഗിക്കുന്നത്[[using-a-python-virtual-environment]] + +ഒരു Python വിർച്വൽ എൻവയോൺമെന്റ് ഉപയോഗിക്കാനാണ് നിങ്ങൾക്ക് താൽപ്പര്യമെങ്കിൽ, ആദ്യ പടി നിങ്ങളുടെ സിസ്‌റ്റത്തിൽ Python ഇൻസ്‌റ്റാൾ ചെയ്യുകയാണ്. തുടങ്ങാൻ [ഈ ഗൈഡ്](https://realpython.com/installing-python/) പിന്തുടരാൻ ഞങ്ങൾ ശുപാർശ ചെയ്യുന്നു. + +Python ഇൻസ്‌റ്റാൾ ചെയ്തുകഴിഞ്ഞാൽ, നിങ്ങളുടെ ടെർമിനലിൽ Python കമാൻഡുകൾ റൺ ചെയ്യാൻ കഴിയണം. അടുത്ത ഘട്ടങ്ങളിലേക്ക് പോകുന്നതിന് മുമ്പ്, അത് ശരിയായി ഇൻസ്‌റ്റാൾ ആയെന്ന് ഉറപ്പാക്കാൻ ഈ കമാൻഡ് റൺ ചെയ്തുനോക്കാം: `python --version`. നിങ്ങളുടെ സിസ്‌റ്റത്തിൽ ഇപ്പോൾ ലഭ്യമായ Python പതിപ്പ് ഇത് പ്രിന്റ് ചെയ്യണം. + +ടെർമിനലിൽ `python --version` പോലുള്ള ഒരു Python കമാൻഡ് റൺ ചെയ്യുമ്പോൾ, നിങ്ങളുടെ കമാൻഡ് റൺ ചെയ്യുന്ന പ്രോഗ്രാമിനെ സിസ്‌റ്റത്തിലെ "പ്രധാന" (main) Python ആയി കണക്കാക്കണം. ഈ പ്രധാന ഇൻസ്‌റ്റാളേഷനിൽ ഒരു പാക്കേജും ഇൻസ്‌റ്റാൾ ചെയ്യാതെ സൂക്ഷിക്കാനും, നിങ്ങൾ പ്രവർത്തിക്കുന്ന ഓരോ ആപ്ലിക്കേഷനും വെവ്വേറെ എൻവയോൺമെന്റുകൾ ഉണ്ടാക്കാൻ അത് ഉപയോഗിക്കാനുമാണ് ഞങ്ങൾ ശുപാർശ ചെയ്യുന്നത് — ഇങ്ങനെ ചെയ്താൽ ഓരോ ആപ്ലിക്കേഷനും അതിന്റേതായ ഡിപ്പൻഡൻസികളും പാക്കേജുകളും ഉണ്ടാകും, മറ്റ് ആപ്ലിക്കേഷനുകളുമായി ഉണ്ടാകാവുന്ന കോംപാറ്റിബിലിറ്റി പ്രശ്‌നങ്ങളെക്കുറിച്ച് നിങ്ങൾ ആശങ്കപ്പെടേണ്ടതുമില്ല. + +Python-ൽ ഇത് ചെയ്യുന്നത് [*വിർച്വൽ എൻവയോൺമെന്റുകൾ*](https://docs.python.org/3/tutorial/venv.html) ഉപയോഗിച്ചാണ്. ഇവ സ്വയംപൂർണ്ണമായ ഡയറക്ടറി ട്രീകളാണ് — ഓരോന്നിലും ഒരു നിശ്ചിത Python പതിപ്പുള്ള Python ഇൻസ്‌റ്റാളേഷനും ആപ്ലിക്കേഷന് ആവശ്യമായ എല്ലാ പാക്കേജുകളും അടങ്ങിയിരിക്കും. ഇത്തരമൊരു വിർച്വൽ എൻവയോൺമെന്റ് ഉണ്ടാക്കാൻ പല ടൂളുകളും ഉണ്ട്, എന്നാൽ നാം അതിനായി [`venv`](https://docs.python.org/3/library/venv.html#module-venv) എന്ന ഔദ്യോഗിക Python പാക്കേജ് ഉപയോഗിക്കും. + +ആദ്യം, നിങ്ങളുടെ ആപ്ലിക്കേഷൻ സൂക്ഷിക്കാനുദ്ദേശിക്കുന്ന ഡയറക്ടറി ഉണ്ടാക്കുക — ഉദാഹരണത്തിന്, ഹോം ഡയറക്ടറിയുടെ റൂട്ടിൽ *transformers-course* എന്ന പേരിൽ ഒരു പുതിയ ഡയറക്ടറി ഉണ്ടാക്കാം: + +``` +mkdir ~/transformers-course +cd ~/transformers-course +``` + +ഈ ഡയറക്ടറിക്കുള്ളിൽ നിന്ന്, Python-ന്റെ `venv` മൊഡ്യൂൾ ഉപയോഗിച്ച് ഒരു വിർച്വൽ എൻവയോൺമെന്റ് ഉണ്ടാക്കുക: + +``` +python -m venv .env +``` + +അല്ലാതെ ഒഴിഞ്ഞുകിടക്കുന്ന നിങ്ങളുടെ ഫോൾഡറിൽ ഇപ്പോൾ *.env* എന്ന ഒരു ഡയറക്ടറി ഉണ്ടായിരിക്കണം: + +``` +ls -a +``` + +```out +. .. .env +``` + +`activate`, `deactivate` എന്നീ സ്‌ക്രിപ്‌റ്റുകൾ ഉപയോഗിച്ച് നിങ്ങൾക്ക് വിർച്വൽ എൻവയോൺമെന്റിലേക്ക് കടക്കാനും അതിൽ നിന്ന് പുറത്തുവരാനും കഴിയും: + +``` +# Activate the virtual environment +source .env/bin/activate + +# Deactivate the virtual environment +deactivate +``` + +`which python` എന്ന കമാൻഡ് റൺ ചെയ്ത് എൻവയോൺമെന്റ് ആക്ടിവേറ്റ് ആയെന്ന് ഉറപ്പാക്കാം: അത് വിർച്വൽ എൻവയോൺമെന്റിലേക്കാണ് ചൂണ്ടുന്നതെങ്കിൽ, നിങ്ങൾ അത് വിജയകരമായി ആക്ടിവേറ്റ് ചെയ്തിരിക്കുന്നു! + +``` +which python +``` + +```out +/home//transformers-course/.env/bin/python +``` + +### ഡിപ്പൻഡൻസികൾ ഇൻസ്‌റ്റാൾ ചെയ്യുന്നത്[[installing-dependencies]] + +Google Colab ഇൻസ്‌റ്റൻസുകൾ ഉപയോഗിക്കുന്നതിനെക്കുറിച്ചുള്ള മുൻ വിഭാഗത്തിലെപ്പോലെ, തുടരാൻ ആവശ്യമായ പാക്കേജുകൾ ഇപ്പോൾ നിങ്ങൾ ഇൻസ്‌റ്റാൾ ചെയ്യേണ്ടതുണ്ട്. `pip` പാക്കേജ് മാനേജർ ഉപയോഗിച്ച് 🤗 Transformers-ന്റെ ഡെവലപ്‌മെന്റ് പതിപ്പ് വീണ്ടും ഇങ്ങനെ ഇൻസ്‌റ്റാൾ ചെയ്യാം: + +``` +pip install "transformers[sentencepiece]" +``` + +ഇപ്പോൾ എല്ലാം സജ്ജമായി, നിങ്ങൾ മുന്നോട്ടുപോകാൻ തയ്യാറാണ്! diff --git a/chapters/ml/chapter1/1.mdx b/chapters/ml/chapter1/1.mdx new file mode 100644 index 000000000..16164f74f --- /dev/null +++ b/chapters/ml/chapter1/1.mdx @@ -0,0 +1,160 @@ +# ആമുഖം[[introduction]] + + + +## 🤗 കോഴ്‌സിലേക്ക് സ്വാഗതം![[welcome-to-the-course]] + + + +[Hugging Face](https://huggingface.co/) ഇക്കോസിസ്‌റ്റത്തിലെ ലൈബ്രറികൾ — [🤗 Transformers](https://github.com/huggingface/transformers), [🤗 Datasets](https://github.com/huggingface/datasets), [🤗 Tokenizers](https://github.com/huggingface/tokenizers), [🤗 Accelerate](https://github.com/huggingface/accelerate) — എന്നിവയും [Hugging Face Hub](https://huggingface.co/models)-ഉം ഉപയോഗിച്ച് ലാർജ് ലാംഗ്വേജ് മോഡലുകളെ (LLM) കുറിച്ചും നാച്ചുറൽ ലാംഗ്വേജ് പ്രോസസ്സിംഗിനെ (NLP) കുറിച്ചും ഈ കോഴ്‌സ് നിങ്ങളെ പഠിപ്പിക്കും. + +Hugging Face ഇക്കോസിസ്‌റ്റത്തിന് പുറത്തുള്ള ലൈബ്രറികളും നാം പരിചയപ്പെടും. AI സമൂഹത്തിനുള്ള മികച്ച സംഭാവനകളും അത്യധികം ഉപകാരപ്രദമായ ടൂളുകളുമാണ് അവ. + +ഇത് പൂർണ്ണമായും സൗജന്യമാണ്, പരസ്യങ്ങളൊന്നുമില്ല. + +## NLP-യും LLM-കളും മനസ്സിലാക്കുന്നത്[[understanding-nlp-and-llms]] + +ഈ കോഴ്‌സ് തുടക്കത്തിൽ NLP-യിൽ (Natural Language Processing) ആയിരുന്നു ശ്രദ്ധ കേന്ദ്രീകരിച്ചിരുന്നതെങ്കിലും, ഈ മേഖലയിലെ ഏറ്റവും പുതിയ മുന്നേറ്റമായ ലാർജ് ലാംഗ്വേജ് മോഡലുകൾക്ക് (LLM) ഊന്നൽ നൽകുന്ന രീതിയിലേക്ക് ഇത് വികസിച്ചിരിക്കുന്നു. + +**എന്താണ് വ്യത്യാസം?** +- **NLP (Natural Language Processing)** എന്നത് കമ്പ്യൂട്ടറുകൾക്ക് മനുഷ്യഭാഷ മനസ്സിലാക്കാനും വ്യാഖ്യാനിക്കാനും സൃഷ്‌ടിക്കാനും കഴിവ് നൽകുന്നതിൽ ശ്രദ്ധ കേന്ദ്രീകരിക്കുന്ന വിശാലമായ മേഖലയാണ്. സെന്റിമെന്റ് അനാലിസിസ് (sentiment analysis), നെയിംഡ് എന്റിറ്റി റെക്കഗ്നിഷൻ (named entity recognition), മെഷീൻ ട്രാൻസ്‌ലേഷൻ (machine translation) തുടങ്ങി നിരവധി സങ്കേതങ്ങളും ടാസ്‌ക്കുകളും NLP-യിൽ ഉൾപ്പെടുന്നു. +- **LLM-കൾ (Large Language Models)** NLP മോഡലുകളുടെ ശക്തമായ ഒരു ഉപവിഭാഗമാണ് — ഭീമമായ വലിപ്പം, വിപുലമായ ട്രെയിനിംഗ് ഡേറ്റ, ടാസ്‌ക്-നിർദ്ദിഷ്‌ട ട്രെയിനിംഗ് വളരെ കുറച്ചുമാത്രം നൽകിയാലും വൈവിധ്യമാർന്ന ഭാഷാ ടാസ്‌ക്കുകൾ ചെയ്യാനുള്ള കഴിവ് എന്നിവയാണ് ഇവയുടെ സവിശേഷതകൾ. Llama, GPT, Claude സീരീസ് പോലുള്ള മോഡലുകൾ NLP-യിൽ സാധ്യമായതിനെ അടിമുടി മാറ്റിമറിച്ച LLM-കൾക്കുള്ള ഉദാഹരണങ്ങളാണ്. + +ഈ കോഴ്‌സിലുടനീളം, പരമ്പരാഗത NLP ആശയങ്ങളും അത്യാധുനിക LLM സങ്കേതങ്ങളും നിങ്ങൾ പഠിക്കും — കാരണം LLM-കളുമായി ഫലപ്രദമായി പ്രവർത്തിക്കാൻ NLP-യുടെ അടിസ്ഥാനങ്ങൾ മനസ്സിലാക്കുന്നത് അത്യാവശ്യമാണ്. + +## എന്താണ് പ്രതീക്ഷിക്കേണ്ടത്?[[what-to-expect]] + +കോഴ്‌സിന്റെ ഒരു ഹ്രസ്വ അവലോകനം ഇതാ: + +
+കോഴ്‌സിലെ അധ്യായങ്ങളുടെ ഹ്രസ്വ അവലോകനം. + +
+ +- അധ്യായങ്ങൾ 1 മുതൽ 4 വരെ 🤗 Transformers ലൈബ്രറിയുടെ പ്രധാന ആശയങ്ങളിലേക്ക് ഒരു ആമുഖം നൽകുന്നു. കോഴ്‌സിന്റെ ഈ ഭാഗം പൂർത്തിയാകുമ്പോൾ, Transformer മോഡലുകൾ എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്നത് നിങ്ങൾക്ക് പരിചിതമാകും; [Hugging Face Hub](https://huggingface.co/models)-ൽ നിന്ന് ഒരു മോഡൽ ഉപയോഗിക്കാനും, ഒരു ഡേറ്റാസെറ്റിൽ അത് ഫൈൻ-ട്യൂൺ ചെയ്യാനും, നിങ്ങളുടെ ഫലങ്ങൾ Hub-ൽ പങ്കുവയ്ക്കാനും നിങ്ങൾക്ക് അറിയാമായിരിക്കും! +- അധ്യായങ്ങൾ 5 മുതൽ 8 വരെ 🤗 Datasets-ന്റെയും 🤗 Tokenizers-ന്റെയും അടിസ്ഥാനങ്ങൾ പഠിപ്പിച്ചശേഷം ക്ലാസിക് NLP ടാസ്‌ക്കുകളിലേക്കും LLM സങ്കേതങ്ങളിലേക്കും കടക്കുന്നു. ഈ ഭാഗം പൂർത്തിയാകുമ്പോൾ, ഏറ്റവും സാധാരണമായ ഭാഷാ പ്രോസസ്സിംഗ് വെല്ലുവിളികളെ സ്വയം നേരിടാൻ നിങ്ങൾക്ക് കഴിയും. +- അധ്യായം 9 NLP-ക്ക് അപ്പുറം കടന്ന്, നിങ്ങളുടെ മോഡലുകളുടെ ഡെമോകൾ 🤗 Hub-ൽ എങ്ങനെ നിർമ്മിക്കാമെന്നും പങ്കുവയ്ക്കാമെന്നും വിവരിക്കുന്നു. ഈ ഭാഗം പൂർത്തിയാകുമ്പോൾ, നിങ്ങളുടെ 🤗 Transformers ആപ്ലിക്കേഷൻ ലോകത്തിന് മുന്നിൽ അവതരിപ്പിക്കാൻ നിങ്ങൾ തയ്യാറായിരിക്കും! +- അധ്യായങ്ങൾ 10 മുതൽ 12 വരെ ഫൈൻ-ട്യൂണിംഗ്, ഉയർന്ന ഗുണനിലവാരമുള്ള ഡേറ്റാസെറ്റുകൾ തയ്യാറാക്കൽ, റീസണിംഗ് മോഡലുകൾ (reasoning models) നിർമ്മിക്കൽ തുടങ്ങിയ അഡ്വാൻസ്‌ഡ് LLM വിഷയങ്ങളിലേക്ക് ആഴത്തിൽ കടക്കുന്നു. + +ഈ കോഴ്‌സ്: + +* Python-ൽ നല്ല അറിവ് ആവശ്യപ്പെടുന്നു +* [fast.ai-യുടെ](https://www.fast.ai/) [Practical Deep Learning for Coders](https://course.fast.ai/) അല്ലെങ്കിൽ [DeepLearning.AI](https://www.deeplearning.ai/) വികസിപ്പിച്ച പ്രോഗ്രാമുകളിലൊന്ന് പോലുള്ള ഒരു ആമുഖ ഡീപ് ലേണിംഗ് കോഴ്‌സിന് ശേഷം പഠിക്കുന്നതാണ് കൂടുതൽ നല്ലത് +* [PyTorch](https://pytorch.org/) അല്ലെങ്കിൽ [TensorFlow](https://www.tensorflow.org/) മുൻപരിചയം പ്രതീക്ഷിക്കുന്നില്ല, എങ്കിലും ഇവയിലേതെങ്കിലുമൊന്നിലുള്ള അൽപ്പം പരിചയം സഹായകമാകും + +ഈ കോഴ്‌സ് പൂർത്തിയാക്കിയശേഷം, DeepLearning.AI-യുടെ [Natural Language Processing Specialization](https://www.coursera.org/specializations/natural-language-processing?utm_source=deeplearning-ai&utm_medium=institutions&utm_campaign=20211011-nlp-2-hugging_face-page-nlp-refresh) ഒന്ന് പരിശോധിക്കാൻ ഞങ്ങൾ ശുപാർശ ചെയ്യുന്നു — naive Bayes, LSTM-കൾ പോലുള്ള, അറിഞ്ഞിരിക്കേണ്ടതായ നിരവധി പരമ്പരാഗത NLP മോഡലുകൾ ഇത് ഉൾക്കൊള്ളുന്നു! + +## ഞങ്ങൾ ആരാണ്?[[who-are-we]] + +രചയിതാക്കളെക്കുറിച്ച്: + +[**Abubakar Abid**](https://huggingface.co/abidlabs) Stanford-ൽ അപ്ലൈഡ് മെഷീൻ ലേണിംഗിൽ PhD പൂർത്തിയാക്കി. PhD കാലത്ത് അദ്ദേഹം [Gradio](https://github.com/gradio-app/gradio) എന്ന ഓപ്പൺ സോഴ്‌സ് Python ലൈബ്രറി സ്ഥാപിച്ചു — 600,000-ത്തിലധികം മെഷീൻ ലേണിംഗ് ഡെമോകൾ നിർമ്മിക്കാൻ ഇത് ഉപയോഗിച്ചിട്ടുണ്ട്. Gradio-യെ Hugging Face ഏറ്റെടുത്തു, അവിടെ Abubakar ഇപ്പോൾ മെഷീൻ ലേണിംഗ് ടീം ലീഡായി പ്രവർത്തിക്കുന്നു. + +[**Ben Burtenshaw**](https://huggingface.co/burtenshaw) Hugging Face-ൽ മെഷീൻ ലേണിംഗ് എഞ്ചിനീയറാണ്. University of Antwerp-ൽ നിന്ന് Natural Language Processing-ൽ PhD പൂർത്തിയാക്കിയ അദ്ദേഹം, അവിടെ സാക്ഷരതാ കഴിവുകൾ മെച്ചപ്പെടുത്തുക എന്ന ലക്ഷ്യത്തോടെ കുട്ടികൾക്കുള്ള കഥകൾ സൃഷ്‌ടിക്കാൻ Transformer മോഡലുകൾ പ്രയോഗിച്ചു. അതിനുശേഷം, വിശാലമായ സമൂഹത്തിനുള്ള വിദ്യാഭ്യാസ സാമഗ്രികളിലും ടൂളുകളിലുമാണ് അദ്ദേഹം ശ്രദ്ധ കേന്ദ്രീകരിച്ചിരിക്കുന്നത്. + +[**Matthew Carrigan**](https://huggingface.co/Rocketknight1) Hugging Face-ൽ മെഷീൻ ലേണിംഗ് എഞ്ചിനീയറാണ്. അയർലൻഡിലെ ഡബ്ലിനിൽ താമസിക്കുന്ന അദ്ദേഹം മുമ്പ് Parse.ly-യിൽ ML എഞ്ചിനീയറായും അതിനു മുമ്പ് Trinity College Dublin-ൽ പോസ്‌റ്റ്-ഡോക്ടറൽ ഗവേഷകനായും പ്രവർത്തിച്ചിരുന്നു. നിലവിലുള്ള ആർക്കിടെക്‌ചറുകൾ വലുതാക്കി AGI-യിലേക്ക് എത്താനാകുമെന്ന് അദ്ദേഹം വിശ്വസിക്കുന്നില്ല, എങ്കിലും റോബോട്ട് അമരത്വത്തിൽ അദ്ദേഹത്തിന് വലിയ പ്രതീക്ഷയുണ്ട്. + +[**Lysandre Debut**](https://huggingface.co/lysandre) Hugging Face-ൽ മെഷീൻ ലേണിംഗ് എഞ്ചിനീയറാണ്; വികസനത്തിന്റെ വളരെ ആദ്യഘട്ടങ്ങൾ മുതൽ 🤗 Transformers ലൈബ്രറിയിൽ പ്രവർത്തിച്ചുവരുന്നു. വളരെ ലളിതമായ API-യുള്ള ടൂളുകൾ വികസിപ്പിച്ച് NLP എല്ലാവർക്കും പ്രാപ്യമാക്കുകയാണ് അദ്ദേഹത്തിന്റെ ലക്ഷ്യം. + +[**Sylvain Gugger**](https://huggingface.co/sgugger) Hugging Face-ൽ റിസർച്ച് എഞ്ചിനീയറും 🤗 Transformers ലൈബ്രറിയുടെ പ്രധാന മെയിന്റെയ്‌നർമാരിൽ ഒരാളുമാണ്. മുമ്പ് fast.ai-യിൽ റിസർച്ച് സയന്റിസ്‌റ്റായിരുന്ന അദ്ദേഹം Jeremy Howard-നൊപ്പം _[Deep Learning for Coders with fastai and PyTorch](https://learning.oreilly.com/library/view/deep-learning-for/9781492045519/)_ എന്ന പുസ്‌തകം സഹരചിച്ചു. പരിമിതമായ വിഭവങ്ങളിൽ മോഡലുകളെ വേഗത്തിൽ ട്രെയിൻ ചെയ്യാൻ സഹായിക്കുന്ന സങ്കേതങ്ങൾ രൂപകൽപ്പന ചെയ്യുകയും മെച്ചപ്പെടുത്തുകയും ചെയ്തുകൊണ്ട് ഡീപ് ലേണിംഗ് കൂടുതൽ പ്രാപ്യമാക്കുകയാണ് അദ്ദേഹത്തിന്റെ ഗവേഷണത്തിന്റെ പ്രധാന ലക്ഷ്യം. + +[**Dawood Khan**](https://huggingface.co/dawoodkhan82) Hugging Face-ൽ മെഷീൻ ലേണിംഗ് എഞ്ചിനീയറാണ്. NYC-യിൽ നിന്നുള്ള അദ്ദേഹം New York University-യിൽ നിന്ന് കമ്പ്യൂട്ടർ സയൻസിൽ ബിരുദം നേടി. കുറച്ചു വർഷം iOS എഞ്ചിനീയറായി ജോലി ചെയ്തശേഷം, സഹസ്ഥാപകർക്കൊപ്പം Gradio ആരംഭിക്കാനായി Dawood ആ ജോലി ഉപേക്ഷിച്ചു. പിന്നീട് Gradio-യെ Hugging Face ഏറ്റെടുത്തു. + +[**Merve Noyan**](https://huggingface.co/merve) Hugging Face-ൽ ഡെവലപ്പർ അഡ്വക്കേറ്റാണ്; മെഷീൻ ലേണിംഗ് എല്ലാവർക്കും പ്രാപ്യമാക്കാൻ ടൂളുകൾ വികസിപ്പിക്കുകയും അവയെക്കുറിച്ചുള്ള ഉള്ളടക്കം നിർമ്മിക്കുകയും ചെയ്യുന്നു. + +[**Lucile Saulnier**](https://huggingface.co/SaulLu) Hugging Face-ൽ മെഷീൻ ലേണിംഗ് എഞ്ചിനീയറാണ്; ഓപ്പൺ സോഴ്‌സ് ടൂളുകൾ വികസിപ്പിക്കുകയും അവയുടെ ഉപയോഗത്തിന് പിന്തുണ നൽകുകയും ചെയ്യുന്നു. കൊളാബറേറ്റീവ് ട്രെയിനിംഗ്, BigScience തുടങ്ങിയ Natural Language Processing മേഖലയിലെ നിരവധി ഗവേഷണ പദ്ധതികളിലും അവർ സജീവമായി പങ്കാളിയാണ്. + +[**Lewis Tunstall**](https://huggingface.co/lewtun) Hugging Face-ൽ മെഷീൻ ലേണിംഗ് എഞ്ചിനീയറാണ്; ഓപ്പൺ സോഴ്‌സ് ടൂളുകൾ വികസിപ്പിക്കുന്നതിലും അവ വിശാലമായ സമൂഹത്തിന് പ്രാപ്യമാക്കുന്നതിലുമാണ് ശ്രദ്ധ. O'Reilly-യുടെ [Natural Language Processing with Transformers](https://www.oreilly.com/library/view/natural-language-processing/9781098136789/) എന്ന പുസ്‌തകത്തിന്റെ സഹരചയിതാവ് കൂടിയാണ് അദ്ദേഹം. + +[**Leandro von Werra**](https://huggingface.co/lvwerra) Hugging Face-ലെ ഓപ്പൺ സോഴ്‌സ് ടീമിൽ മെഷീൻ ലേണിംഗ് എഞ്ചിനീയറാണ്; O'Reilly-യുടെ [Natural Language Processing with Transformers](https://www.oreilly.com/library/view/natural-language-processing/9781098136789/) എന്ന പുസ്‌തകത്തിന്റെ സഹരചയിതാവ് കൂടിയാണ്. മെഷീൻ ലേണിംഗ് സ്‌റ്റാക്കിന്റെ എല്ലാ തലങ്ങളിലും പ്രവർത്തിച്ച് NLP പ്രോജക്‌ടുകൾ പ്രൊഡക്ഷനിൽ എത്തിച്ച നിരവധി വർഷത്തെ വ്യവസായ പരിചയം അദ്ദേഹത്തിനുണ്ട്. + +## പതിവുചോദ്യങ്ങൾ (FAQ)[[faq]] + +പതിവായി ചോദിക്കുന്ന ചില ചോദ്യങ്ങൾക്കുള്ള ഉത്തരങ്ങൾ ഇതാ: + +- **ഈ കോഴ്‌സ് ചെയ്താൽ സർട്ടിഫിക്കേഷൻ ലഭിക്കുമോ?** +നിലവിൽ ഈ കോഴ്‌സിന് സർട്ടിഫിക്കേഷനൊന്നുമില്ല. എന്നാൽ Hugging Face ഇക്കോസിസ്‌റ്റത്തിനായി ഒരു സർട്ടിഫിക്കേഷൻ പ്രോഗ്രാം ഞങ്ങൾ തയ്യാറാക്കിക്കൊണ്ടിരിക്കുന്നു — കാത്തിരിക്കൂ! + +- **ഈ കോഴ്‌സിനായി എത്ര സമയം ചെലവഴിക്കണം?** +ഈ കോഴ്‌സിലെ ഓരോ അധ്യായവും 1 ആഴ്‌ചയിൽ, ആഴ്‌ചയിൽ ഏകദേശം 6-8 മണിക്കൂർ ജോലിയോടെ, പൂർത്തിയാക്കാവുന്ന രീതിയിലാണ് രൂപകൽപ്പന ചെയ്തിരിക്കുന്നത്. എന്നാൽ കോഴ്‌സ് പൂർത്തിയാക്കാൻ നിങ്ങൾക്ക് ആവശ്യമുള്ളത്ര സമയം എടുക്കാം. + +- **ഒരു ചോദ്യമുണ്ടെങ്കിൽ എവിടെ ചോദിക്കാം?** +കോഴ്‌സിന്റെ ഏതെങ്കിലും വിഭാഗത്തെക്കുറിച്ച് ചോദ്യമുണ്ടെങ്കിൽ, പേജിന്റെ മുകളിലുള്ള "*Ask a question*" ബാനറിൽ ക്ലിക്ക് ചെയ്യുക — [Hugging Face ഫോറങ്ങളിലെ](https://discuss.huggingface.co/) ശരിയായ വിഭാഗത്തിലേക്ക് നിങ്ങൾ സ്വയമേവ എത്തിക്കപ്പെടും: + +Hugging Face ഫോറങ്ങളിലേക്കുള്ള ലിങ്ക് + +കോഴ്‌സ് പൂർത്തിയാക്കിയശേഷം കൂടുതൽ പരിശീലിക്കാൻ താൽപ്പര്യമുണ്ടെങ്കിൽ, [പ്രോജക്‌ട് ആശയങ്ങളുടെ](https://discuss.huggingface.co/c/course/course-event/25) ഒരു പട്ടികയും ഫോറങ്ങളിൽ ലഭ്യമാണെന്ന് ശ്രദ്ധിക്കുക. + +- **കോഴ്‌സിന്റെ കോഡ് എവിടെ കിട്ടും?** +ഓരോ വിഭാഗത്തിനും, പേജിന്റെ മുകളിലുള്ള ബാനറിൽ ക്ലിക്ക് ചെയ്ത് Google Colab-ലോ Amazon SageMaker Studio Lab-ലോ കോഡ് റൺ ചെയ്യാം: + +Hugging Face കോഴ്‌സ് നോട്ട്‌ബുക്കുകളിലേക്കുള്ള ലിങ്ക് + +കോഴ്‌സിലെ എല്ലാ കോഡും അടങ്ങിയ Jupyter നോട്ട്‌ബുക്കുകൾ [`huggingface/notebooks`](https://github.com/huggingface/notebooks) റിപ്പോയിൽ ഹോസ്‌റ്റ് ചെയ്തിരിക്കുന്നു. അവ ലോക്കലായി ജനറേറ്റ് ചെയ്യാൻ താൽപ്പര്യമുണ്ടെങ്കിൽ, GitHub-ലെ [`course`](https://github.com/huggingface/course#-jupyter-notebooks) റിപ്പോയിലെ നിർദ്ദേശങ്ങൾ നോക്കുക. + + +- **കോഴ്‌സിലേക്ക് എനിക്ക് എങ്ങനെ സംഭാവന ചെയ്യാം?** +കോഴ്‌സിലേക്ക് സംഭാവന ചെയ്യാൻ പല വഴികളുണ്ട്! ഒരു അക്ഷരത്തെറ്റോ ബഗ്ഗോ കണ്ടെത്തിയാൽ, [`course`](https://github.com/huggingface/course) റിപ്പോയിൽ ഒരു ഇഷ്യൂ തുറക്കുക. കോഴ്‌സ് നിങ്ങളുടെ മാതൃഭാഷയിലേക്ക് വിവർത്തനം ചെയ്യാൻ സഹായിക്കാൻ താൽപ്പര്യമുണ്ടെങ്കിൽ, [ഇവിടെയുള്ള](https://github.com/huggingface/course#translating-the-course-into-your-language) നിർദ്ദേശങ്ങൾ നോക്കുക. + +- ** ഓരോ വിവർത്തനത്തിലും എന്തെല്ലാം തിരഞ്ഞെടുപ്പുകളാണ് നടത്തിയത്?** +ഓരോ വിവർത്തനത്തിനും ഒരു ഗ്ലോസറിയും, മെഷീൻ ലേണിംഗ് പദാവലി തുടങ്ങിയവയ്ക്കായി എടുത്ത തീരുമാനങ്ങൾ വിശദീകരിക്കുന്ന `TRANSLATING.txt` ഫയലും ഉണ്ട്. ജർമ്മൻ ഭാഷയ്ക്കുള്ള ഒരു ഉദാഹരണം [ഇവിടെ](https://github.com/huggingface/course/blob/main/chapters/de/TRANSLATING.txt) കാണാം. + + +- **ഈ കോഴ്‌സ് എനിക്ക് പുനരുപയോഗിക്കാമോ?** +തീർച്ചയായും! ഈ കോഴ്‌സ് ഉദാരമായ [Apache 2 ലൈസൻസിന്](https://www.apache.org/licenses/LICENSE-2.0.html) കീഴിലാണ് പുറത്തിറക്കിയിരിക്കുന്നത്. അതായത്, നിങ്ങൾ ഉചിതമായ ക്രെഡിറ്റ് നൽകണം, ലൈസൻസിലേക്ക് ഒരു ലിങ്ക് നൽകണം, മാറ്റങ്ങൾ വരുത്തിയിട്ടുണ്ടെങ്കിൽ അത് സൂചിപ്പിക്കണം. ന്യായമായ ഏത് രീതിയിലും ഇത് ചെയ്യാം, എന്നാൽ ലൈസൻസ് നൽകുന്നവർ നിങ്ങളെയോ നിങ്ങളുടെ ഉപയോഗത്തെയോ അംഗീകരിക്കുന്നു എന്ന് തോന്നിക്കുന്ന രീതിയിൽ ആകരുത്. കോഴ്‌സ് ഉദ്ധരിക്കാൻ (cite) താൽപ്പര്യമുണ്ടെങ്കിൽ, ഈ BibTeX ഉപയോഗിക്കുക: + +``` +@misc{huggingfacecourse, + author = {Hugging Face}, + title = {The Hugging Face Course, 2022}, + howpublished = "\url{https://huggingface.co/course}", + year = {2022}, + note = "[Online; accessed ]" +} +``` + +## ഭാഷകളും വിവർത്തനങ്ങളും[[languages-and-translations]] + +ഞങ്ങളുടെ അതുല്യമായ സമൂഹത്തിന് നന്ദി, ഇംഗ്ലീഷിന് പുറമേ നിരവധി ഭാഷകളിൽ ഈ കോഴ്‌സ് ലഭ്യമാണ് 🔥! ഏതെല്ലാം ഭാഷകൾ ലഭ്യമാണെന്നും വിവർത്തനങ്ങളിലേക്ക് ആരെല്ലാം സംഭാവന ചെയ്‌തുവെന്നും അറിയാൻ താഴെയുള്ള പട്ടിക നോക്കുക: + +| Language | Authors | +|:------------------------------------------------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| [French](https://huggingface.co/course/fr/chapter1/1) | [@lbourdois](https://github.com/lbourdois), [@ChainYo](https://github.com/ChainYo), [@melaniedrevet](https://github.com/melaniedrevet), [@abdouaziz](https://github.com/abdouaziz) | +| [Vietnamese](https://huggingface.co/course/vi/chapter1/1) | [@honghanhh](https://github.com/honghanhh) | +| [Chinese (simplified)](https://huggingface.co/course/zh-CN/chapter1/1) | [@zhlhyx](https://github.com/zhlhyx), [petrichor1122](https://github.com/petrichor1122), [@yaoqih](https://github.com/yaoqih) | +| [Bengali](https://huggingface.co/course/bn/chapter1/1) (WIP) | [@avishek-018](https://github.com/avishek-018), [@eNipu](https://github.com/eNipu) | +| [German](https://huggingface.co/course/de/chapter1/1) (WIP) | [@JesperDramsch](https://github.com/JesperDramsch), [@MarcusFra](https://github.com/MarcusFra), [@fabridamicelli](https://github.com/fabridamicelli) | +| [Spanish](https://huggingface.co/course/es/chapter1/1) (WIP) | [@camartinezbu](https://github.com/camartinezbu), [@munozariasjm](https://github.com/munozariasjm), [@fordaz](https://github.com/fordaz) | +| [Persian](https://huggingface.co/course/fa/chapter1/1) (WIP) | [@jowharshamshiri](https://github.com/jowharshamshiri), [@schoobani](https://github.com/schoobani) | +| [Gujarati](https://huggingface.co/course/gu/chapter1/1) (WIP) | [@pandyaved98](https://github.com/pandyaved98) | +| [Hebrew](https://huggingface.co/course/he/chapter1/1) (WIP) | [@omer-dor](https://github.com/omer-dor) | +| [Hindi](https://huggingface.co/course/hi/chapter1/1) (WIP) | [@pandyaved98](https://github.com/pandyaved98) | +| [Bahasa Indonesia](https://huggingface.co/course/id/chapter1/1) (WIP) | [@gstdl](https://github.com/gstdl) | +| [Italian](https://huggingface.co/course/it/chapter1/1) (WIP) | [@CaterinaBi](https://github.com/CaterinaBi), [@ClonedOne](https://github.com/ClonedOne), [@Nolanogenn](https://github.com/Nolanogenn), [@EdAbati](https://github.com/EdAbati), [@gdacciaro](https://github.com/gdacciaro) | +| [Japanese](https://huggingface.co/course/ja/chapter1/1) (WIP) | [@hiromu166](https://github.com/@hiromu166), [@younesbelkada](https://github.com/@younesbelkada), [@HiromuHota](https://github.com/@HiromuHota) | +| [Korean](https://huggingface.co/course/ko/chapter1/1) (WIP) | [@Doohae](https://github.com/Doohae), [@wonhyeongseo](https://github.com/wonhyeongseo), [@dlfrnaos19](https://github.com/dlfrnaos19) | +| [Portuguese](https://huggingface.co/course/pt/chapter1/1) (WIP) | [@johnnv1](https://github.com/johnnv1), [@victorescosta](https://github.com/victorescosta), [@LincolnVS](https://github.com/LincolnVS) | +| [Russian](https://huggingface.co/course/ru/chapter1/1) (WIP) | [@pdumin](https://github.com/pdumin), [@svv73](https://github.com/svv73) | +| [Thai](https://huggingface.co/course/th/chapter1/1) (WIP) | [@peeraponw](https://github.com/peeraponw), [@a-krirk](https://github.com/a-krirk), [@jomariya23156](https://github.com/jomariya23156), [@ckingkan](https://github.com/ckingkan) | +| [Turkish](https://huggingface.co/course/tr/chapter1/1) (WIP) | [@tanersekmen](https://github.com/tanersekmen), [@mertbozkir](https://github.com/mertbozkir), [@ftarlaci](https://github.com/ftarlaci), [@akkasayaz](https://github.com/akkasayaz) | +| [Chinese (traditional)](https://huggingface.co/course/zh-TW/chapter1/1) (WIP) | [@davidpeng86](https://github.com/davidpeng86) | +| [Malayalam](https://huggingface.co/course/ml/chapter1/1) (WIP) | [@nikhilkilivayil](https://github.com/nikhilkilivayil) | + +ചില ഭാഷകൾക്ക്, [കോഴ്‌സിന്റെ YouTube വീഡിയോകൾക്ക്](https://youtube.com/playlist?list=PLo2EIpI_JMQvWfQndUesu0nPBAtZ9gP1o) ആ ഭാഷയിൽ സബ്‌ടൈറ്റിലുകൾ ഉണ്ട്. വീഡിയോയുടെ താഴെ വലത് മൂലയിലുള്ള _CC_ ബട്ടണിൽ ആദ്യം ക്ലിക്ക് ചെയ്ത് അവ പ്രവർത്തനക്ഷമമാക്കാം. തുടർന്ന്, സെറ്റിംഗ്‌സ് ഐക്കണിന് ⚙️ കീഴിൽ, _Subtitles/CC_ ഓപ്‌ഷൻ തിരഞ്ഞെടുത്ത് നിങ്ങൾക്ക് വേണ്ട ഭാഷ തിരഞ്ഞെടുക്കാം. + +Hugging Face കോഴ്‌സ് YouTube വീഡിയോകൾക്ക് സബ്‌ടൈറ്റിലുകൾ പ്രവർത്തനക്ഷമമാക്കുന്നത് + +> [!TIP] +> മുകളിലെ പട്ടികയിൽ നിങ്ങളുടെ ഭാഷ കാണുന്നില്ലേ, അല്ലെങ്കിൽ നിലവിലുള്ള ഒരു വിവർത്തനത്തിലേക്ക് സംഭാവന ചെയ്യാൻ താൽപ്പര്യമുണ്ടോ? ഇവിടെയുള്ള നിർദ്ദേശങ്ങൾ പിന്തുടർന്ന് കോഴ്‌സ് വിവർത്തനം ചെയ്യാൻ നിങ്ങൾക്ക് ഞങ്ങളെ സഹായിക്കാം. + +## നമുക്ക് തുടങ്ങാം 🚀 + +തയ്യാറാണോ? ഈ അധ്യായത്തിൽ നിങ്ങൾ പഠിക്കുന്നത്: + +* ടെക്‌സ്‌റ്റ് ജനറേഷൻ, ക്ലാസിഫിക്കേഷൻ പോലുള്ള NLP ടാസ്‌ക്കുകൾ പരിഹരിക്കാൻ `pipeline()` ഫംഗ്‌ഷൻ എങ്ങനെ ഉപയോഗിക്കാം +* Transformer ആർക്കിടെക്‌ചറിനെക്കുറിച്ച് +* എൻകോഡർ, ഡീകോഡർ, എൻകോഡർ-ഡീകോഡർ ആർക്കിടെക്‌ചറുകളും അവയുടെ ഉപയോഗങ്ങളും എങ്ങനെ വേർതിരിച്ചറിയാം + diff --git a/chapters/ml/chapter1/10.mdx b/chapters/ml/chapter1/10.mdx new file mode 100644 index 000000000..539b425bc --- /dev/null +++ b/chapters/ml/chapter1/10.mdx @@ -0,0 +1,66 @@ +# സംഗ്രഹം[[summary]] + + + +ഈ അധ്യായത്തിൽ, Transformer മോഡലുകളുടെയും വലിയ ഭാഷാ മോഡലുകളുടെയും (Large Language Models, LLM-കൾ) അടിസ്ഥാനങ്ങളും, അവ AI-യിലും അതിനപ്പുറവും എങ്ങനെ വിപ്ലവം സൃഷ്ടിക്കുന്നു എന്നതും നിങ്ങൾക്ക് പരിചയപ്പെടുത്തി. + +## പ്രതിപാദിച്ച പ്രധാന ആശയങ്ങൾ + +### Natural Language Processing-ഉം LLM-കളും + +NLP എന്താണെന്നും വലിയ ഭാഷാ മോഡലുകൾ ഈ മേഖലയെ എങ്ങനെ മാറ്റിമറിച്ചു എന്നും നാം പരിശോധിച്ചു. നിങ്ങൾ പഠിച്ചത്: +- വർഗ്ഗീകരണം (classification) മുതൽ ജനറേഷൻ വരെ വിപുലമായ ടാസ്‌ക്കുകൾ NLP ഉൾക്കൊള്ളുന്നു +- LLM-കൾ വൻതോതിലുള്ള ടെക്‌സ്‌റ്റ് ഡേറ്റയിൽ പരിശീലിപ്പിച്ച ശക്തമായ മോഡലുകളാണ് +- ഈ മോഡലുകൾക്ക് ഒരൊറ്റ ആർക്കിടെക്ചറിനുള്ളിൽ ഒന്നിലധികം ടാസ്‌ക്കുകൾ നിർവഹിക്കാൻ കഴിയും +- കഴിവുകൾ ഉണ്ടെങ്കിലും, hallucination-ഉം പക്ഷപാതവും (bias) ഉൾപ്പെടെയുള്ള പരിമിതികൾ LLM-കൾക്കുണ്ട് + +### Transformer-ന്റെ കഴിവുകൾ + +🤗 Transformers-ലെ `pipeline()` ഫംഗ്‌ഷൻ വിവിധ ടാസ്‌ക്കുകൾക്കായി പ്രീട്രെയിൻ ചെയ്ത മോഡലുകൾ ഉപയോഗിക്കുന്നത് എങ്ങനെ എളുപ്പമാക്കുന്നു എന്ന് നിങ്ങൾ കണ്ടു: +- ടെക്‌സ്‌റ്റ് ക്ലാസിഫിക്കേഷൻ, ടോക്കൺ ക്ലാസിഫിക്കേഷൻ, ചോദ്യോത്തരം (question answering) +- ടെക്‌സ്‌റ്റ് ജനറേഷനും സംഗ്രഹവും (summarization) +- വിവർത്തനവും മറ്റ് sequence-to-sequence ടാസ്‌ക്കുകളും +- സംഭാഷണം തിരിച്ചറിയലും (speech recognition) ഇമേജ് ക്ലാസിഫിക്കേഷനും + +### Transformer ആർക്കിടെക്ചർ + +Transformer മോഡലുകൾ ഉയർന്ന തലത്തിൽ എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് നാം ചർച്ച ചെയ്തു, ഇവ ഉൾപ്പെടെ: +- അറ്റൻഷൻ മെക്കാനിസത്തിന്റെ പ്രാധാന്യം +- നിർദ്ദിഷ്ട ടാസ്‌ക്കുകളിലേക്ക് പൊരുത്തപ്പെടാൻ transfer learning മോഡലുകളെ എങ്ങനെ പ്രാപ്തമാക്കുന്നു +- മൂന്ന് പ്രധാന ആർക്കിടെക്ചർ വകഭേദങ്ങൾ: എൻകോഡർ-മാത്രം, ഡീകോഡർ-മാത്രം, എൻകോഡർ-ഡീകോഡർ + +### മോഡൽ ആർക്കിടെക്ചറുകളും അവയുടെ പ്രയോഗങ്ങളും +വ്യത്യസ്ത ടാസ്‌ക്കുകൾക്ക് ഏത് ആർക്കിടെക്ചർ ഉപയോഗിക്കണം എന്ന് മനസ്സിലാക്കുന്നത് ഈ അധ്യായത്തിന്റെ ഒരു പ്രധാന ഭാഗമായിരുന്നു: + +| മോഡൽ | ഉദാഹരണങ്ങൾ | ടാസ്‌ക്കുകൾ | +|-----------------|--------------------------------------------|----------------------------------------------------------------------------------| +| എൻകോഡർ-മാത്രം | BERT, DistilBERT, ModernBERT | വാക്യ വർഗ്ഗീകരണം, named entity recognition, extractive question answering | +| ഡീകോഡർ-മാത്രം | GPT, LLaMA, Gemma, SmolLM | ടെക്‌സ്‌റ്റ് ജനറേഷൻ, സംഭാഷണാത്മക AI, സർഗ്ഗാത്മക രചന | +| എൻകോഡർ-ഡീകോഡർ | BART, T5, Marian, mBART | സംഗ്രഹം, വിവർത്തനം, generative question answering | + +### ആധുനിക LLM സംഭവവികാസങ്ങൾ +ഈ മേഖലയിലെ സമീപകാല സംഭവവികാസങ്ങളെക്കുറിച്ചും നിങ്ങൾ പഠിച്ചു: +- കാലക്രമേണ LLM-കൾ വലിപ്പത്തിലും കഴിവിലും എങ്ങനെ വളർന്നു +- സ്‌കെയിലിംഗ് നിയമങ്ങൾ (scaling laws) എന്ന ആശയവും അവ മോഡൽ വികസനത്തെ എങ്ങനെ നയിക്കുന്നു എന്നതും +- ദൈർഘ്യമേറിയ സീക്വൻസുകൾ പ്രോസസ്സ് ചെയ്യാൻ മോഡലുകളെ സഹായിക്കുന്ന പ്രത്യേക അറ്റൻഷൻ മെക്കാനിസങ്ങൾ +- പ്രീട്രെയിനിംഗും instruction tuning-ഉം എന്ന രണ്ട് ഘട്ടങ്ങളുള്ള പരിശീലന സമീപനം + +### പ്രായോഗിക പ്രയോഗങ്ങൾ +അധ്യായത്തിലുടനീളം, ഈ മോഡലുകൾ യഥാർത്ഥ ലോക പ്രശ്നങ്ങളിൽ എങ്ങനെ പ്രയോഗിക്കാം എന്ന് നിങ്ങൾ കണ്ടു: +- പ്രീട്രെയിൻ ചെയ്ത മോഡലുകൾ കണ്ടെത്താനും ഉപയോഗിക്കാനും Hugging Face Hub ഉപയോഗിക്കുന്നത് +- നിങ്ങളുടെ ബ്രൗസറിൽ നേരിട്ട് മോഡലുകൾ പരീക്ഷിക്കാൻ Inference API പ്രയോജനപ്പെടുത്തുന്നത് +- നിർദ്ദിഷ്ട ടാസ്‌ക്കുകൾക്ക് ഏറ്റവും അനുയോജ്യമായ മോഡലുകൾ ഏതെന്ന് മനസ്സിലാക്കുന്നത് + +## മുന്നോട്ടുള്ള വഴി + +Transformer മോഡലുകൾ എന്താണെന്നും ഉയർന്ന തലത്തിൽ അവ എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്നതിനെക്കുറിച്ചും ഉറച്ച ധാരണ ലഭിച്ചതിനാൽ, അവ ഫലപ്രദമായി എങ്ങനെ ഉപയോഗിക്കാം എന്നതിലേക്ക് കൂടുതൽ ആഴത്തിൽ ഇറങ്ങാൻ നിങ്ങൾ തയ്യാറാണ്. അടുത്ത അധ്യായങ്ങളിൽ, നിങ്ങൾ പഠിക്കുന്നത്: + +- മോഡലുകൾ ലോഡ് ചെയ്യാനും ഫൈൻ-ട്യൂൻ ചെയ്യാനും Transformers ലൈബ്രറി ഉപയോഗിക്കുന്നത് +- മോഡൽ ഇൻപുട്ടിനായി വിവിധ തരം ഡേറ്റ പ്രോസസ്സ് ചെയ്യുന്നത് +- പ്രീട്രെയിൻ ചെയ്ത മോഡലുകളെ നിങ്ങളുടെ നിർദ്ദിഷ്ട ടാസ്‌ക്കുകളിലേക്ക് പൊരുത്തപ്പെടുത്തുന്നത് +- പ്രായോഗിക പ്രയോഗങ്ങൾക്കായി മോഡലുകൾ ഡിപ്ലോയ് ചെയ്യുന്നത് + +വരാനിരിക്കുന്ന ഭാഗങ്ങളിൽ കൂടുതൽ വിപുലമായ വിഷയങ്ങളും സാങ്കേതിക വിദ്യകളും പരിശോധിക്കുമ്പോൾ, ഈ അധ്യായത്തിൽ നിങ്ങൾ കെട്ടിപ്പടുത്ത അടിത്തറ നിങ്ങൾക്ക് ഏറെ പ്രയോജനപ്പെടും. diff --git a/chapters/ml/chapter1/11.mdx b/chapters/ml/chapter1/11.mdx new file mode 100644 index 000000000..60af7b209 --- /dev/null +++ b/chapters/ml/chapter1/11.mdx @@ -0,0 +1,21 @@ +# പരീക്ഷാ സമയം! + +നിങ്ങളുടെ അറിവ് പരീക്ഷിക്കാനുള്ള സമയമായി! ഈ അധ്യായത്തിൽ പ്രതിപാദിച്ച ആശയങ്ങളെക്കുറിച്ചുള്ള നിങ്ങളുടെ ധാരണ പരിശോധിക്കാൻ ഒരു ചെറിയ ക്വിസ് നാം തയ്യാറാക്കിയിട്ടുണ്ട്. + +ക്വിസിൽ പങ്കെടുക്കാൻ, നിങ്ങൾ ഈ ഘട്ടങ്ങൾ പിന്തുടരേണ്ടതുണ്ട്: + +1. നിങ്ങളുടെ Hugging Face അക്കൗണ്ടിലേക്ക് സൈൻ ഇൻ ചെയ്യുക. +2. ക്വിസിലെ ചോദ്യങ്ങൾക്ക് ഉത്തരം നൽകുക. +3. നിങ്ങളുടെ ഉത്തരങ്ങൾ സമർപ്പിക്കുക. + + +## മൾട്ടിപ്പിൾ ചോയ്‌സ് ക്വിസ് + +ഈ ക്വിസിൽ, ഓപ്‌ഷനുകളുടെ ഒരു പട്ടികയിൽ നിന്ന് ശരിയായ ഉത്തരം തിരഞ്ഞെടുക്കാൻ നിങ്ങളോട് ആവശ്യപ്പെടും. supervised ഫൈൻ-ട്യൂണിംഗിന്റെ അടിസ്ഥാനങ്ങളിലാണ് നാം നിങ്ങളെ പരീക്ഷിക്കുന്നത്. + + diff --git a/chapters/ml/chapter1/2.mdx b/chapters/ml/chapter1/2.mdx new file mode 100644 index 000000000..5aa12ea29 --- /dev/null +++ b/chapters/ml/chapter1/2.mdx @@ -0,0 +1,52 @@ +# നാച്ചുറൽ ലാംഗ്വേജ് പ്രോസസ്സിംഗും ലാർജ് ലാംഗ്വേജ് മോഡലുകളും[[natural-language-processing-and-large-language-models]] + + + +Transformer മോഡലുകളിലേക്ക് കടക്കുന്നതിന് മുമ്പ്, നാച്ചുറൽ ലാംഗ്വേജ് പ്രോസസ്സിംഗ് (natural language processing) എന്താണ്, ലാർജ് ലാംഗ്വേജ് മോഡലുകൾ ഈ മേഖലയെ എങ്ങനെ മാറ്റിമറിച്ചു, നമ്മൾ എന്തുകൊണ്ട് ഇതിൽ ശ്രദ്ധ ചെലുത്തുന്നു എന്നിവയെക്കുറിച്ച് ഒരു ചെറിയ അവലോകനം നടത്താം. + +## NLP എന്താണ്?[[what-is-nlp]] + + + +മനുഷ്യഭാഷയുമായി ബന്ധപ്പെട്ട എല്ലാ കാര്യങ്ങളും മനസ്സിലാക്കുന്നതിൽ ശ്രദ്ധ കേന്ദ്രീകരിക്കുന്ന, ഭാഷാശാസ്ത്രവും മെഷീൻ ലേണിംഗും ചേരുന്ന ഒരു മേഖലയാണ് NLP. ഓരോ വാക്കും വെവ്വേറെ മനസ്സിലാക്കുക മാത്രമല്ല, ആ വാക്കുകളുടെ സന്ദർഭം (context) മനസ്സിലാക്കാൻ കഴിയുക എന്നതാണ് NLP ടാസ്‌ക്കുകളുടെ ലക്ഷ്യം. + +സാധാരണ NLP ടാസ്‌ക്കുകളുടെ ഒരു പട്ടികയും ഓരോന്നിന്റെയും ചില ഉദാഹരണങ്ങളും താഴെ കൊടുക്കുന്നു: + +- **വാക്യങ്ങളെ മൊത്തത്തിൽ വർഗ്ഗീകരിക്കുക**: ഒരു റിവ്യൂവിന്റെ വികാരം (sentiment) കണ്ടെത്തുക, ഒരു ഇമെയിൽ സ്പാം ആണോ എന്ന് തിരിച്ചറിയുക, ഒരു വാക്യം വ്യാകരണപരമായി ശരിയാണോ എന്നോ രണ്ട് വാക്യങ്ങൾ യുക്തിപരമായി ബന്ധപ്പെട്ടിരിക്കുന്നുണ്ടോ എന്നോ നിർണ്ണയിക്കുക +- **ഒരു വാക്യത്തിലെ ഓരോ വാക്കും വർഗ്ഗീകരിക്കുക**: ഒരു വാക്യത്തിന്റെ വ്യാകരണഘടകങ്ങൾ (നാമം, ക്രിയ, വിശേഷണം) അല്ലെങ്കിൽ നാമ-സത്തകൾ (named entities — വ്യക്തി, സ്ഥലം, സ്ഥാപനം) തിരിച്ചറിയുക +- **ടെക്‌സ്‌റ്റ് ഉള്ളടക്കം സൃഷ്ടിക്കുക**: ഒരു പ്രോംപ്‌റ്റിനെ സ്വയമേവ സൃഷ്ടിച്ച ടെക്‌സ്‌റ്റ് കൊണ്ട് പൂർത്തിയാക്കുക, മാസ്‌ക് ചെയ്ത വാക്കുകളുള്ള ഒരു ടെക്‌സ്‌റ്റിലെ വിട്ടഭാഗങ്ങൾ പൂരിപ്പിക്കുക +- **ഒരു ടെക്‌സ്‌റ്റിൽ നിന്ന് ഉത്തരം കണ്ടെത്തുക**: ഒരു ചോദ്യവും ഒരു സന്ദർഭവും (context) നൽകിയാൽ, സന്ദർഭത്തിൽ നൽകിയിരിക്കുന്ന വിവരങ്ങളുടെ അടിസ്ഥാനത്തിൽ ചോദ്യത്തിന്റെ ഉത്തരം കണ്ടെത്തുക +- **ഇൻപുട്ട് ടെക്‌സ്‌റ്റിൽ നിന്ന് ഒരു പുതിയ വാക്യം സൃഷ്ടിക്കുക**: ഒരു ടെക്‌സ്‌റ്റ് മറ്റൊരു ഭാഷയിലേക്ക് വിവർത്തനം ചെയ്യുക, ഒരു ടെക്‌സ്‌റ്റ് സംഗ്രഹിക്കുക + +എന്നാൽ NLP എഴുതപ്പെട്ട ടെക്‌സ്‌റ്റിൽ മാത്രം ഒതുങ്ങുന്നില്ല. ഒരു ഓഡിയോ സാമ്പിളിന്റെ ട്രാൻസ്‌ക്രിപ്‌റ്റ് തയ്യാറാക്കുക, ഒരു ചിത്രത്തിന്റെ വിവരണം സൃഷ്ടിക്കുക എന്നിങ്ങനെ സ്പീച്ച് റെക്കഗ്നിഷനിലെയും കമ്പ്യൂട്ടർ വിഷനിലെയും സങ്കീർണ്ണമായ വെല്ലുവിളികളും ഇത് കൈകാര്യം ചെയ്യുന്നു. + +## ലാർജ് ലാംഗ്വേജ് മോഡലുകളുടെ (LLM) ഉയർച്ച[[rise-of-llms]] + +സമീപ വർഷങ്ങളിൽ, ലാർജ് ലാംഗ്വേജ് മോഡലുകൾ (LLM) NLP മേഖലയിൽ ഒരു വിപ്ലവം തന്നെ സൃഷ്ടിച്ചിട്ടുണ്ട്. GPT (Generative Pre-trained Transformer), [Llama](https://huggingface.co/meta-llama) തുടങ്ങിയ ആർക്കിടെക്‌ചറുകൾ ഉൾപ്പെടുന്ന ഈ മോഡലുകൾ ഭാഷാ പ്രോസസ്സിംഗിൽ സാധ്യമായതിന്റെ അതിരുകൾ തന്നെ മാറ്റിയെഴുതി. + +> [!TIP] +> ഒരു ലാർജ് ലാംഗ്വേജ് മോഡൽ (LLM) എന്നത് വളരെ വലിയ അളവിലുള്ള ടെക്‌സ്‌റ്റ് ഡേറ്റയിൽ പരിശീലിപ്പിച്ച ഒരു AI മോഡലാണ്. ഇതിന് മനുഷ്യരെപ്പോലെ ടെക്‌സ്‌റ്റ് മനസ്സിലാക്കാനും സൃഷ്ടിക്കാനും, ഭാഷയിലെ പാറ്റേണുകൾ തിരിച്ചറിയാനും, ഓരോ ടാസ്‌ക്കിനും വേണ്ടി പ്രത്യേകം പരിശീലനം നൽകാതെ തന്നെ വിവിധതരം ഭാഷാ ടാസ്‌ക്കുകൾ ചെയ്യാനും കഴിയും. നാച്ചുറൽ ലാംഗ്വേജ് പ്രോസസ്സിംഗ് (NLP) മേഖലയിലെ ഒരു സുപ്രധാന മുന്നേറ്റമാണ് ഇവ. + +LLM-കളുടെ പ്രധാന സവിശേഷതകൾ ഇവയാണ്: +- **വലിപ്പം (Scale)**: ഇവയിൽ ദശലക്ഷക്കണക്കിനോ, ശതകോടിക്കണക്കിനോ, അല്ലെങ്കിൽ നൂറുകണക്കിന് ശതകോടി പാരാമീറ്ററുകളോ ഉണ്ടാകും +- **പൊതുവായ കഴിവുകൾ**: ഓരോ ടാസ്‌ക്കിനും വേണ്ടി പ്രത്യേകം പരിശീലനം നൽകാതെ തന്നെ ഇവയ്ക്ക് പല ടാസ്‌ക്കുകളും ചെയ്യാൻ കഴിയും +- **ഇൻ-കോൺടെക്‌സ്‌റ്റ് ലേണിംഗ് (In-context learning)**: പ്രോംപ്‌റ്റിൽ നൽകുന്ന ഉദാഹരണങ്ങളിൽ നിന്ന് ഇവയ്ക്ക് പഠിക്കാൻ കഴിയും +- **ഉയർന്നുവരുന്ന കഴിവുകൾ (Emergent abilities)**: ഈ മോഡലുകളുടെ വലിപ്പം കൂടുന്നതിനനുസരിച്ച്, വ്യക്തമായി പ്രോഗ്രാം ചെയ്യാത്തതോ പ്രതീക്ഷിക്കാത്തതോ ആയ കഴിവുകൾ ഇവ പ്രകടിപ്പിക്കുന്നു + +LLM-കളുടെ വരവോടെ, ഓരോ NLP ടാസ്‌ക്കിനും വേണ്ടി പ്രത്യേക മോഡലുകൾ നിർമ്മിക്കുന്ന രീതിയിൽ നിന്ന്, വൈവിധ്യമാർന്ന ഭാഷാ ടാസ്‌ക്കുകൾ കൈകാര്യം ചെയ്യാൻ പ്രോംപ്‌റ്റ് നൽകാനോ ഫൈൻ-ട്യൂൺ ചെയ്യാനോ കഴിയുന്ന ഒരൊറ്റ വലിയ മോഡൽ ഉപയോഗിക്കുന്ന രീതിയിലേക്ക് ചിന്താഗതി മാറി. ഇത് നൂതനമായ ഭാഷാ പ്രോസസ്സിംഗ് കൂടുതൽ ആളുകൾക്ക് പ്രാപ്യമാക്കി; അതേസമയം കാര്യക്ഷമത, നൈതികത, ഡിപ്ലോയ്‌മെന്റ് തുടങ്ങിയ മേഖലകളിൽ പുതിയ വെല്ലുവിളികളും കൊണ്ടുവന്നു. + +എന്നിരുന്നാലും, LLM-കൾക്ക് ചില പ്രധാന പരിമിതികളുമുണ്ട്: +- **ഹാലൂസിനേഷനുകൾ (Hallucinations)**: തെറ്റായ വിവരങ്ങൾ ഇവ ആത്മവിശ്വാസത്തോടെ സൃഷ്ടിച്ചേക്കാം +- **യഥാർത്ഥ ധാരണയുടെ അഭാവം**: ലോകത്തെക്കുറിച്ച് ഇവയ്ക്ക് യഥാർത്ഥ ധാരണയില്ല; സ്ഥിതിവിവര പാറ്റേണുകളുടെ (statistical patterns) അടിസ്ഥാനത്തിൽ മാത്രമാണ് ഇവ പ്രവർത്തിക്കുന്നത് +- **പക്ഷപാതം (Bias)**: പരിശീലന ഡേറ്റയിലോ ഇൻപുട്ടുകളിലോ ഉള്ള പക്ഷപാതങ്ങൾ ഇവ ആവർത്തിച്ചേക്കാം. +- **കോൺടെക്‌സ്‌റ്റ് വിൻഡോകൾ**: ഇവയുടെ കോൺടെക്‌സ്‌റ്റ് വിൻഡോ പരിമിതമാണ് (ഇത് മെച്ചപ്പെട്ടുവരുന്നുണ്ടെങ്കിലും) +- **കമ്പ്യൂട്ടേഷണൽ വിഭവങ്ങൾ**: ഇവയ്ക്ക് വലിയ അളവിൽ കമ്പ്യൂട്ടേഷണൽ വിഭവങ്ങൾ ആവശ്യമാണ് + +## ഭാഷാ പ്രോസസ്സിംഗ് എന്തുകൊണ്ട് വെല്ലുവിളി നിറഞ്ഞതാണ്?[[why-is-it-challenging]] + +കമ്പ്യൂട്ടറുകൾ മനുഷ്യരെപ്പോലെയല്ല വിവരങ്ങൾ പ്രോസസ്സ് ചെയ്യുന്നത്. ഉദാഹരണത്തിന്, "I am hungry" എന്ന വാക്യം വായിക്കുമ്പോൾ നമുക്ക് അതിന്റെ അർത്ഥം എളുപ്പത്തിൽ മനസ്സിലാകും. അതുപോലെ, "I am hungry", "I am sad" എന്നീ രണ്ട് വാക്യങ്ങൾ നൽകിയാൽ, അവ എത്രത്തോളം സമാനമാണെന്ന് നമുക്ക് എളുപ്പത്തിൽ പറയാൻ കഴിയും. എന്നാൽ മെഷീൻ ലേണിംഗ് (ML) മോഡലുകൾക്ക് ഇത്തരം ടാസ്‌ക്കുകൾ കൂടുതൽ ബുദ്ധിമുട്ടുള്ളതാണ്. മോഡലിന് അതിൽ നിന്ന് പഠിക്കാൻ കഴിയുന്ന വിധത്തിൽ ടെക്‌സ്‌റ്റ് പ്രോസസ്സ് ചെയ്യേണ്ടതുണ്ട്. ഭാഷ സങ്കീർണ്ണമായതിനാൽ, ഈ പ്രോസസ്സിംഗ് എങ്ങനെ ചെയ്യണം എന്നതിനെക്കുറിച്ച് നമ്മൾ ശ്രദ്ധാപൂർവ്വം ചിന്തിക്കേണ്ടതുണ്ട്. ടെക്‌സ്‌റ്റിനെ എങ്ങനെ പ്രതിനിധീകരിക്കാം എന്നതിനെക്കുറിച്ച് ധാരാളം ഗവേഷണങ്ങൾ നടന്നിട്ടുണ്ട്; അടുത്ത അധ്യായത്തിൽ അതിലെ ചില രീതികൾ നമ്മൾ പരിശോധിക്കും. + +LLM-കളിലെ പുരോഗതി ഉണ്ടായിട്ടും, അടിസ്ഥാനപരമായ പല വെല്ലുവിളികളും ഇപ്പോഴും നിലനിൽക്കുന്നു. അവ്യക്തത (ambiguity), സാംസ്‌കാരിക സന്ദർഭം, പരിഹാസം (sarcasm), നർമ്മം എന്നിവ മനസ്സിലാക്കുന്നത് ഇതിൽ ഉൾപ്പെടുന്നു. വൈവിധ്യമാർന്ന ഡേറ്റാസെറ്റുകളിൽ വൻതോതിൽ പരിശീലനം നൽകിയാണ് LLM-കൾ ഈ വെല്ലുവിളികളെ നേരിടുന്നത്; എന്നിട്ടും സങ്കീർണ്ണമായ പല സാഹചര്യങ്ങളിലും മനുഷ്യതലത്തിലുള്ള ധാരണയിലേക്ക് എത്താൻ അവയ്ക്ക് പലപ്പോഴും കഴിയാറില്ല. diff --git a/chapters/ml/chapter1/3.mdx b/chapters/ml/chapter1/3.mdx new file mode 100644 index 000000000..124c63ea8 --- /dev/null +++ b/chapters/ml/chapter1/3.mdx @@ -0,0 +1,390 @@ +# Transformer-കൾ, അവയ്ക്ക് എന്തൊക്കെ ചെയ്യാൻ കഴിയും?[[transformers-what-can-they-do]] + + + +ഈ ഭാഗത്തിൽ, Transformer മോഡലുകൾക്ക് എന്തൊക്കെ ചെയ്യാൻ കഴിയുമെന്ന് നമ്മൾ നോക്കും, കൂടാതെ 🤗 Transformers ലൈബ്രറിയിലെ നമ്മുടെ ആദ്യത്തെ ടൂൾ ഉപയോഗിക്കും: `pipeline()` ഫംഗ്‌ഷൻ. + +> [!TIP] +> 👀 മുകളിൽ വലതുവശത്തുള്ള Open in Colab ബട്ടൺ കണ്ടോ? ഈ ഭാഗത്തിലെ എല്ലാ കോഡ് ഉദാഹരണങ്ങളും അടങ്ങിയ ഒരു Google Colab നോട്ട്‌ബുക്ക് തുറക്കാൻ അതിൽ ക്ലിക്ക് ചെയ്യുക. കോഡ് ഉദാഹരണങ്ങൾ ഉള്ള ഏത് ഭാഗത്തിലും ഈ ബട്ടൺ ഉണ്ടായിരിക്കും. +> +> ഉദാഹരണങ്ങൾ നിങ്ങളുടെ കമ്പ്യൂട്ടറിൽ തന്നെ (locally) റൺ ചെയ്യാൻ ആഗ്രഹിക്കുന്നെങ്കിൽ, സെറ്റപ്പ് ഒന്ന് നോക്കാൻ ഞങ്ങൾ ശുപാർശ ചെയ്യുന്നു. + +## Transformer-കൾ എല്ലായിടത്തുമുണ്ട്![[transformers-are-everywhere]] + +നാച്ചുറൽ ലാംഗ്വേജ് പ്രോസസ്സിംഗ് (NLP), കമ്പ്യൂട്ടർ വിഷൻ, ഓഡിയോ പ്രോസസ്സിംഗ് തുടങ്ങി വിവിധ മോഡാലിറ്റികളിലുള്ള എല്ലാത്തരം ടാസ്‌ക്കുകളും പരിഹരിക്കാൻ Transformer മോഡലുകൾ ഉപയോഗിക്കുന്നു. Hugging Face-ഉം Transformer മോഡലുകളും ഉപയോഗിക്കുന്ന, തങ്ങളുടെ മോഡലുകൾ പങ്കുവെച്ചുകൊണ്ട് കമ്മ്യൂണിറ്റിക്ക് തിരികെ സംഭാവന ചെയ്യുന്ന ചില കമ്പനികളും സ്ഥാപനങ്ങളും ഇവയാണ്: + +Hugging Face ഉപയോഗിക്കുന്ന കമ്പനികൾ + +പങ്കുവെച്ചിട്ടുള്ള ഈ മോഡലുകൾ സൃഷ്ടിക്കാനും ഉപയോഗിക്കാനുമുള്ള സൗകര്യം [🤗 Transformers ലൈബ്രറി](https://github.com/huggingface/transformers) നൽകുന്നു. ആർക്കും ഡൗൺലോഡ് ചെയ്ത് ഉപയോഗിക്കാവുന്ന ദശലക്ഷക്കണക്കിന് പ്രീട്രെയിൻഡ് മോഡലുകൾ [Model Hub](https://huggingface.co/models)-ൽ ഉണ്ട്. നിങ്ങളുടെ സ്വന്തം മോഡലുകളും Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യാം! + +> [!TIP] +> ⚠️ Hugging Face Hub Transformer മോഡലുകളിൽ മാത്രം ഒതുങ്ങുന്നില്ല. ആർക്കും ഏതുതരം മോഡലുകളും ഡേറ്റാസെറ്റുകളും പങ്കുവെക്കാം! ലഭ്യമായ എല്ലാ സവിശേഷതകളും പ്രയോജനപ്പെടുത്താൻ ഒരു huggingface.co അക്കൗണ്ട് ഉണ്ടാക്കുക! + +Transformer മോഡലുകൾ അകമേ എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്നതിലേക്ക് കടക്കുന്നതിന് മുമ്പ്, രസകരമായ ചില NLP പ്രശ്നങ്ങൾ പരിഹരിക്കാൻ അവ എങ്ങനെ ഉപയോഗിക്കാം എന്നതിന്റെ ചില ഉദാഹരണങ്ങൾ നോക്കാം. + +## പൈപ്പ്‌ലൈനുകൾ ഉപയോഗിച്ച് പ്രവർത്തിക്കുന്നു[[working-with-pipelines]] + + + +🤗 Transformers ലൈബ്രറിയിലെ ഏറ്റവും അടിസ്ഥാനപരമായ ഒബ്‌ജക്റ്റ് `pipeline()` ഫംഗ്‌ഷനാണ്. ഇത് ഒരു മോഡലിനെ അതിന് ആവശ്യമായ പ്രീപ്രോസസ്സിംഗ്, പോസ്‌റ്റ്‌പ്രോസസ്സിംഗ് ഘട്ടങ്ങളുമായി ബന്ധിപ്പിക്കുന്നു; അതുവഴി ഏത് ടെക്‌സ്‌റ്റും നേരിട്ട് ഇൻപുട്ടായി നൽകി മനസ്സിലാക്കാവുന്ന ഒരു ഉത്തരം നേടാൻ നമുക്ക് കഴിയും: + +```python +from transformers import pipeline + +classifier = pipeline("sentiment-analysis") +classifier("I've been waiting for a HuggingFace course my whole life.") +``` + +```python out +[{'label': 'POSITIVE', 'score': 0.9598047137260437}] +``` + +ഒന്നിലധികം വാക്യങ്ങൾ പോലും നമുക്ക് നൽകാം! + +```python +classifier( + ["I've been waiting for a HuggingFace course my whole life.", "I hate this so much!"] +) +``` + +```python out +[{'label': 'POSITIVE', 'score': 0.9598047137260437}, + {'label': 'NEGATIVE', 'score': 0.9994558095932007}] +``` + +ഡിഫോൾട്ടായി, ഇംഗ്ലീഷിലുള്ള സെന്റിമെന്റ് അനാലിസിസിനായി ഫൈൻ-ട്യൂൺ ചെയ്ത ഒരു പ്രത്യേക പ്രീട്രെയിൻഡ് മോഡലാണ് ഈ പൈപ്പ്‌ലൈൻ തിരഞ്ഞെടുക്കുന്നത്. നിങ്ങൾ `classifier` ഒബ്‌ജക്റ്റ് ഉണ്ടാക്കുമ്പോൾ മോഡൽ ഡൗൺലോഡ് ചെയ്ത് കാഷ് (cache) ചെയ്യപ്പെടുന്നു. കമാൻഡ് വീണ്ടും റൺ ചെയ്താൽ, കാഷ് ചെയ്ത മോഡൽ ഉപയോഗിക്കും; മോഡൽ വീണ്ടും ഡൗൺലോഡ് ചെയ്യേണ്ട ആവശ്യമില്ല. + +ഒരു പൈപ്പ്‌ലൈനിലേക്ക് ടെക്‌സ്‌റ്റ് നൽകുമ്പോൾ മൂന്ന് പ്രധാന ഘട്ടങ്ങൾ നടക്കുന്നു: + +1. ടെക്‌സ്‌റ്റ് മോഡലിന് മനസ്സിലാകുന്ന ഒരു ഫോർമാറ്റിലേക്ക് പ്രീപ്രോസസ്സ് ചെയ്യപ്പെടുന്നു. +2. പ്രീപ്രോസസ്സ് ചെയ്ത ഇൻപുട്ടുകൾ മോഡലിലേക്ക് നൽകുന്നു. +3. മോഡലിന്റെ പ്രവചനങ്ങൾ (predictions) പോസ്‌റ്റ്-പ്രോസസ്സ് ചെയ്യുന്നു, അതുവഴി നിങ്ങൾക്ക് അവ മനസ്സിലാക്കാൻ കഴിയും. + +## വിവിധ മോഡാലിറ്റികൾക്കായി ലഭ്യമായ പൈപ്പ്‌ലൈനുകൾ + +`pipeline()` ഫംഗ്‌ഷൻ ഒന്നിലധികം മോഡാലിറ്റികളെ പിന്തുണയ്ക്കുന്നു; ടെക്‌സ്‌റ്റ്, ചിത്രങ്ങൾ, ഓഡിയോ, മൾട്ടിമോഡൽ ടാസ്‌ക്കുകൾ എന്നിവയുമായി പോലും പ്രവർത്തിക്കാൻ ഇത് നിങ്ങളെ അനുവദിക്കുന്നു. ഈ കോഴ്‌സിൽ നമ്മൾ ടെക്‌സ്‌റ്റ് ടാസ്‌ക്കുകളിലാണ് ശ്രദ്ധ കേന്ദ്രീകരിക്കുന്നത്, എന്നാൽ Transformer ആർക്കിടെക്‌ചറിന്റെ സാധ്യതകൾ മനസ്സിലാക്കുന്നത് പ്രയോജനകരമായതിനാൽ അതിനെക്കുറിച്ച് ഒരു ചെറിയ രൂപരേഖ നൽകാം. + +ലഭ്യമായവയുടെ ഒരു അവലോകനം ഇതാ: + +> [!TIP] +> പൈപ്പ്‌ലൈനുകളുടെ പൂർണ്ണവും കാലികവുമായ പട്ടികയ്ക്ക്, [🤗 Transformers ഡോക്യുമെന്റേഷൻ](https://huggingface.co/docs/hub/en/models-tasks) കാണുക. + +### ടെക്‌സ്‌റ്റ് പൈപ്പ്‌ലൈനുകൾ + +- `text-generation`: ഒരു പ്രോംപ്‌റ്റിൽ നിന്ന് ടെക്‌സ്‌റ്റ് സൃഷ്ടിക്കുക +- `text-classification`: ടെക്‌സ്‌റ്റിനെ മുൻകൂട്ടി നിശ്ചയിച്ച വിഭാഗങ്ങളിലേക്ക് വർഗ്ഗീകരിക്കുക +- `summarization`: പ്രധാന വിവരങ്ങൾ നിലനിർത്തിക്കൊണ്ട് ഒരു ടെക്‌സ്‌റ്റിന്റെ ചെറിയ പതിപ്പ് ഉണ്ടാക്കുക +- `translation`: ടെക്‌സ്‌റ്റ് ഒരു ഭാഷയിൽ നിന്ന് മറ്റൊന്നിലേക്ക് വിവർത്തനം ചെയ്യുക +- `zero-shot-classification`: നിശ്ചിത ലേബലുകളിൽ മുൻകൂർ പരിശീലനം ഇല്ലാതെ ടെക്‌സ്‌റ്റ് വർഗ്ഗീകരിക്കുക +- `feature-extraction`: ടെക്‌സ്‌റ്റിന്റെ വെക്‌റ്റർ പ്രതിനിധാനങ്ങൾ (vector representations) വേർതിരിച്ചെടുക്കുക + +### ഇമേജ് പൈപ്പ്‌ലൈനുകൾ + +- `image-to-text`: ചിത്രങ്ങളുടെ ടെക്‌സ്‌റ്റ് വിവരണങ്ങൾ സൃഷ്ടിക്കുക +- `image-classification`: ഒരു ചിത്രത്തിലെ വസ്തുക്കൾ തിരിച്ചറിയുക +- `object-detection`: ചിത്രങ്ങളിലെ വസ്തുക്കളുടെ സ്ഥാനം കണ്ടെത്തി അവയെ തിരിച്ചറിയുക + +### ഓഡിയോ പൈപ്പ്‌ലൈനുകൾ + +- `automatic-speech-recognition`: സംസാരം ടെക്‌സ്‌റ്റിലേക്ക് മാറ്റുക +- `audio-classification`: ഓഡിയോയെ വിഭാഗങ്ങളായി വർഗ്ഗീകരിക്കുക +- `text-to-speech`: ടെക്‌സ്‌റ്റിനെ സംസാര ഓഡിയോയിലേക്ക് മാറ്റുക + +### മൾട്ടിമോഡൽ പൈപ്പ്‌ലൈനുകൾ + +- `image-text-to-text`: ഒരു ടെക്‌സ്‌റ്റ് പ്രോംപ്‌റ്റിന്റെ അടിസ്ഥാനത്തിൽ ഒരു ചിത്രത്തോട് പ്രതികരിക്കുക + +ഈ പൈപ്പ്‌ലൈനുകളിൽ ചിലത് കൂടുതൽ വിശദമായി പരിശോധിക്കാം! + +## Zero-shot ക്ലാസിഫിക്കേഷൻ[[zero-shot-classification]] + +ലേബൽ ചെയ്യപ്പെടാത്ത ടെക്‌സ്‌റ്റുകൾ വർഗ്ഗീകരിക്കേണ്ടിവരുന്ന, കുറച്ചുകൂടി വെല്ലുവിളി നിറഞ്ഞ ഒരു ടാസ്‌ക്കിൽ നിന്ന് നമുക്ക് തുടങ്ങാം. ടെക്‌സ്‌റ്റ് അനോട്ടേറ്റ് ചെയ്യുന്നത് സാധാരണയായി സമയമെടുക്കുന്നതും വിഷയത്തിൽ വൈദഗ്ധ്യം ആവശ്യമുള്ളതുമായതിനാൽ, യഥാർത്ഥ പ്രോജക്റ്റുകളിൽ ഇത് സാധാരണമായി കാണുന്ന ഒരു സാഹചര്യമാണ്. ഈ ഉപയോഗത്തിന് `zero-shot-classification` പൈപ്പ്‌ലൈൻ വളരെ ശക്തമാണ്: വർഗ്ഗീകരണത്തിന് ഏതൊക്കെ ലേബലുകൾ ഉപയോഗിക്കണം എന്ന് നിങ്ങൾക്ക് തന്നെ വ്യക്തമാക്കാൻ ഇത് അനുവദിക്കുന്നു, അതിനാൽ പ്രീട്രെയിൻഡ് മോഡലിന്റെ ലേബലുകളെ ആശ്രയിക്കേണ്ടതില്ല. positive, negative എന്ന രണ്ട് ലേബലുകൾ ഉപയോഗിച്ച് മോഡൽ ഒരു വാക്യത്തെ എങ്ങനെ വർഗ്ഗീകരിക്കുന്നു എന്ന് നിങ്ങൾ ഇതിനകം കണ്ടു — എന്നാൽ നിങ്ങൾക്ക് ഇഷ്ടമുള്ള മറ്റേതൊരു ലേബൽ കൂട്ടം ഉപയോഗിച്ചും ഇതിന് ടെക്‌സ്‌റ്റ് വർഗ്ഗീകരിക്കാൻ കഴിയും. + +```python +from transformers import pipeline + +classifier = pipeline("zero-shot-classification") +classifier( + "This is a course about the Transformers library", + candidate_labels=["education", "politics", "business"], +) +``` + +```python out +{'sequence': 'This is a course about the Transformers library', + 'labels': ['education', 'business', 'politics'], + 'scores': [0.8445963859558105, 0.111976258456707, 0.043427448719739914]} +``` + +ഈ പൈപ്പ്‌ലൈൻ ഉപയോഗിക്കാൻ നിങ്ങളുടെ ഡേറ്റയിൽ മോഡൽ ഫൈൻ-ട്യൂൺ ചെയ്യേണ്ട ആവശ്യമില്ലാത്തതിനാലാണ് ഇതിനെ _zero-shot_ എന്ന് വിളിക്കുന്നത്. നിങ്ങൾക്ക് വേണ്ട ഏത് ലേബൽ പട്ടികയ്ക്കും ഇത് നേരിട്ട് പ്രോബബിലിറ്റി സ്‌കോറുകൾ നൽകും! + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** നിങ്ങളുടെ സ്വന്തം വാക്യങ്ങളും ലേബലുകളും ഉപയോഗിച്ച് പരീക്ഷിച്ചുനോക്കി മോഡൽ എങ്ങനെ പെരുമാറുന്നു എന്ന് കാണുക. + + +## ടെക്‌സ്‌റ്റ് ജനറേഷൻ[[text-generation]] + +ഇനി ടെക്‌സ്‌റ്റ് സൃഷ്ടിക്കാൻ ഒരു പൈപ്പ്‌ലൈൻ എങ്ങനെ ഉപയോഗിക്കാം എന്ന് നോക്കാം. നിങ്ങൾ ഒരു പ്രോംപ്‌റ്റ് നൽകുന്നു, ബാക്കി ടെക്‌സ്‌റ്റ് സൃഷ്ടിച്ച് മോഡൽ അത് സ്വയം പൂർത്തിയാക്കുന്നു — ഇതാണ് ഇവിടത്തെ പ്രധാന ആശയം. പല ഫോണുകളിലും കാണുന്ന പ്രെഡിക്‌റ്റീവ് ടെക്‌സ്‌റ്റ് സവിശേഷതയോട് ഇത് സാമ്യമുള്ളതാണ്. ടെക്‌സ്‌റ്റ് ജനറേഷനിൽ റാൻഡംനെസ് ഉള്ളതിനാൽ, താഴെ കാണിച്ചിരിക്കുന്ന അതേ ഫലങ്ങൾ നിങ്ങൾക്ക് ലഭിച്ചില്ലെങ്കിൽ അത് സ്വാഭാവികമാണ്. + +```python +from transformers import pipeline + +generator = pipeline("text-generation") +generator("In this course, we will teach you how to") +``` + +```python out +[{'generated_text': 'In this course, we will teach you how to understand and use ' + 'data flow and data interchange when handling user data. We ' + 'will be working with one or more of the most commonly used ' + 'data flows — data flows of various types, as seen by the ' + 'HTTP'}] +``` + +`num_return_sequences` എന്ന ആർഗ്യുമെന്റ് ഉപയോഗിച്ച് എത്ര വ്യത്യസ്ത സീക്വൻസുകൾ സൃഷ്ടിക്കണം എന്നും, `max_length` എന്ന ആർഗ്യുമെന്റ് ഉപയോഗിച്ച് ഔട്ട്‌പുട്ട് ടെക്‌സ്‌റ്റിന്റെ മൊത്തം നീളവും നിങ്ങൾക്ക് നിയന്ത്രിക്കാം. + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** `num_return_sequences`, `max_length` എന്നീ ആർഗ്യുമെന്റുകൾ ഉപയോഗിച്ച് 15 വാക്കുകൾ വീതമുള്ള രണ്ട് വാക്യങ്ങൾ സൃഷ്ടിക്കുക. + +## Hub-ലെ ഏത് മോഡലും ഒരു പൈപ്പ്‌ലൈനിൽ ഉപയോഗിക്കുന്നു[[using-any-model-from-the-hub-in-a-pipeline]] + +മുൻ ഉദാഹരണങ്ങളിൽ അതത് ടാസ്‌ക്കിനുള്ള ഡിഫോൾട്ട് മോഡലാണ് ഉപയോഗിച്ചത്, എന്നാൽ ഒരു നിശ്ചിത ടാസ്‌ക്കിനായി — ഉദാഹരണത്തിന്, ടെക്‌സ്‌റ്റ് ജനറേഷൻ — പൈപ്പ്‌ലൈനിൽ ഉപയോഗിക്കാൻ Hub-ൽ നിന്ന് ഒരു പ്രത്യേക മോഡൽ തിരഞ്ഞെടുക്കാനും നിങ്ങൾക്ക് കഴിയും. [Model Hub](https://huggingface.co/models)-ലേക്ക് പോയി, ആ ടാസ്‌ക്കിനെ പിന്തുണയ്ക്കുന്ന മോഡലുകൾ മാത്രം കാണാൻ ഇടതുവശത്തുള്ള അനുബന്ധ ടാഗിൽ ക്ലിക്ക് ചെയ്യുക. [ഇതുപോലൊരു](https://huggingface.co/models?pipeline_tag=text-generation) പേജിലേക്ക് നിങ്ങൾ എത്തണം. + +[`HuggingFaceTB/SmolLM2-360M`](https://huggingface.co/HuggingFaceTB/SmolLM2-360M) മോഡൽ ഒന്ന് പരീക്ഷിക്കാം! മുമ്പത്തെ അതേ പൈപ്പ്‌ലൈനിൽ ഇത് എങ്ങനെ ലോഡ് ചെയ്യാം എന്ന് നോക്കുക: + +```python +from transformers import pipeline + +generator = pipeline("text-generation", model="HuggingFaceTB/SmolLM2-360M") +generator( + "In this course, we will teach you how to", + max_length=30, + num_return_sequences=2, +) +``` + +```python out +[{'generated_text': 'In this course, we will teach you how to manipulate the world and ' + 'move your mental and physical capabilities to your advantage.'}, + {'generated_text': 'In this course, we will teach you how to become an expert and ' + 'practice realtime, and with a hands on experience on both real ' + 'time and real'}] +``` + +ഭാഷാ ടാഗുകളിൽ ക്ലിക്ക് ചെയ്ത് നിങ്ങളുടെ മോഡൽ തിരയൽ കൂടുതൽ കൃത്യമാക്കാനും, മറ്റൊരു ഭാഷയിൽ ടെക്‌സ്‌റ്റ് സൃഷ്ടിക്കുന്ന ഒരു മോഡൽ തിരഞ്ഞെടുക്കാനും കഴിയും. ഒന്നിലധികം ഭാഷകളെ പിന്തുണയ്ക്കുന്ന ബഹുഭാഷാ (multilingual) മോഡലുകളുടെ ചെക്ക്‌പോയിന്റുകൾ പോലും Model Hub-ൽ ഉണ്ട്. + +ഒരു മോഡലിൽ ക്ലിക്ക് ചെയ്ത് അത് തിരഞ്ഞെടുത്താൽ, അത് നേരിട്ട് ഓൺലൈനായി പരീക്ഷിക്കാൻ കഴിയുന്ന ഒരു വിജറ്റ് നിങ്ങൾക്ക് കാണാം. ഇങ്ങനെ, മോഡൽ ഡൗൺലോഡ് ചെയ്യുന്നതിന് മുമ്പ് അതിന്റെ കഴിവുകൾ വേഗത്തിൽ പരിശോധിക്കാൻ കഴിയും. + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** ഫിൽട്ടറുകൾ ഉപയോഗിച്ച് മറ്റൊരു ഭാഷയ്ക്കുള്ള ഒരു ടെക്‌സ്‌റ്റ് ജനറേഷൻ മോഡൽ കണ്ടെത്തുക. വിജറ്റ് ഉപയോഗിച്ച് പരീക്ഷിച്ചുനോക്കാനും ഒരു പൈപ്പ്‌ലൈനിൽ അത് ഉപയോഗിക്കാനും മടിക്കേണ്ട! + +### Inference Providers[[inference-providers]] + +Hugging Face [വെബ്‌സൈറ്റിൽ](https://huggingface.co/docs/inference-providers/en/index) ലഭ്യമായ Inference Providers ഉപയോഗിച്ച് എല്ലാ മോഡലുകളും നിങ്ങളുടെ ബ്രൗസറിലൂടെ നേരിട്ട് പരീക്ഷിക്കാം. ഈ പേജിൽ സ്വന്തം ടെക്‌സ്‌റ്റ് ഇൻപുട്ടായി നൽകി, മോഡൽ ആ ഇൻപുട്ട് ഡേറ്റ പ്രോസസ്സ് ചെയ്യുന്നത് കണ്ടുകൊണ്ട് നിങ്ങൾക്ക് മോഡലുമായി നേരിട്ട് പരീക്ഷണം നടത്താം. + +വിജറ്റിന് പിന്നിൽ പ്രവർത്തിക്കുന്ന Inference Providers ഒരു പെയ്ഡ് ഉൽപ്പന്നമായും ലഭ്യമാണ്; നിങ്ങളുടെ വർക്ക്‌ഫ്ലോകളിൽ ഇത് ആവശ്യമായി വന്നാൽ അത് ഉപകാരപ്രദമാകും. കൂടുതൽ വിവരങ്ങൾക്ക് [പ്രൈസിംഗ് പേജ്](https://huggingface.co/docs/inference-providers/en/pricing) കാണുക. + +## മാസ്‌ക് പൂരിപ്പിക്കൽ (Mask filling)[[mask-filling]] + +നിങ്ങൾ അടുത്തതായി പരീക്ഷിക്കുന്ന പൈപ്പ്‌ലൈൻ `fill-mask` ആണ്. നൽകിയ ഒരു ടെക്‌സ്‌റ്റിലെ വിട്ടഭാഗങ്ങൾ പൂരിപ്പിക്കുക എന്നതാണ് ഈ ടാസ്‌ക്കിന്റെ ആശയം: + +```python +from transformers import pipeline + +unmasker = pipeline("fill-mask") +unmasker("This course will teach you all about models.", top_k=2) +``` + +```python out +[{'sequence': 'This course will teach you all about mathematical models.', + 'score': 0.19619831442832947, + 'token': 30412, + 'token_str': ' mathematical'}, + {'sequence': 'This course will teach you all about computational models.', + 'score': 0.04052725434303284, + 'token': 38163, + 'token_str': ' computational'}] +``` + +എത്ര സാധ്യതകൾ പ്രദർശിപ്പിക്കണം എന്ന് `top_k` ആർഗ്യുമെന്റ് നിയന്ത്രിക്കുന്നു. ഇവിടെ മോഡൽ പൂരിപ്പിക്കുന്നത് `` എന്ന പ്രത്യേക വാക്കാണ് എന്നത് ശ്രദ്ധിക്കുക; ഇതിനെ പലപ്പോഴും *മാസ്‌ക് ടോക്കൺ* (mask token) എന്ന് വിളിക്കുന്നു. മറ്റ് മാസ്‌ക്-ഫില്ലിംഗ് മോഡലുകൾക്ക് വ്യത്യസ്ത മാസ്‌ക് ടോക്കണുകൾ ഉണ്ടാകാം, അതിനാൽ മറ്റ് മോഡലുകൾ പരിശോധിക്കുമ്പോൾ ശരിയായ മാസ്‌ക് വാക്ക് ഉറപ്പുവരുത്തുന്നത് എപ്പോഴും നല്ലതാണ്. വിജറ്റിൽ ഉപയോഗിച്ചിരിക്കുന്ന മാസ്‌ക് വാക്ക് നോക്കുന്നതാണ് ഇത് പരിശോധിക്കാനുള്ള ഒരു വഴി. + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** Hub-ൽ `bert-base-cased` മോഡൽ തിരഞ്ഞ്, Inference API വിജറ്റിൽ അതിന്റെ മാസ്‌ക് വാക്ക് കണ്ടെത്തുക. മുകളിലെ നമ്മുടെ `pipeline` ഉദാഹരണത്തിലെ വാക്യത്തിന് ഈ മോഡൽ എന്ത് പ്രവചിക്കുന്നു? + +## നാമ-സത്ത തിരിച്ചറിയൽ (Named entity recognition)[[named-entity-recognition]] + +നാമ-സത്ത തിരിച്ചറിയൽ (NER) എന്നത്, ഇൻപുട്ട് ടെക്‌സ്‌റ്റിന്റെ ഏതൊക്കെ ഭാഗങ്ങൾ വ്യക്തികൾ, സ്ഥലങ്ങൾ, സ്ഥാപനങ്ങൾ തുടങ്ങിയ എന്റിറ്റികളെ സൂചിപ്പിക്കുന്നു എന്ന് മോഡൽ കണ്ടെത്തേണ്ട ഒരു ടാസ്‌ക്കാണ്. ഒരു ഉദാഹരണം നോക്കാം: + +```python +from transformers import pipeline + +ner = pipeline("ner", aggregation_strategy="simple") +ner("My name is Sylvain and I work at Hugging Face in Brooklyn.") +``` + +```python out +[{'entity_group': 'PER', 'score': 0.99816, 'word': 'Sylvain', 'start': 11, 'end': 18}, + {'entity_group': 'ORG', 'score': 0.97960, 'word': 'Hugging Face', 'start': 33, 'end': 45}, + {'entity_group': 'LOC', 'score': 0.99321, 'word': 'Brooklyn', 'start': 49, 'end': 57} +] +``` + +ഇവിടെ Sylvain ഒരു വ്യക്തിയാണെന്നും (PER), Hugging Face ഒരു സ്ഥാപനമാണെന്നും (ORG), Brooklyn ഒരു സ്ഥലമാണെന്നും (LOC) മോഡൽ കൃത്യമായി തിരിച്ചറിഞ്ഞു. + +ഒരേ എന്റിറ്റിയെ സൂചിപ്പിക്കുന്ന വാക്യഭാഗങ്ങളെ ഒരുമിച്ച് കൂട്ടിച്ചേർക്കാൻ പൈപ്പ്‌ലൈനിനോട് പറയാനാണ് പൈപ്പ്‌ലൈൻ ഉണ്ടാക്കുന്ന ഫംഗ്‌ഷനിൽ `aggregation_strategy="simple"` എന്ന ഓപ്‌ഷൻ നമ്മൾ നൽകുന്നത്: ഇവിടെ, പേരിൽ ഒന്നിലധികം വാക്കുകൾ ഉണ്ടെങ്കിലും, "Hugging", "Face" എന്നിവയെ ഒരൊറ്റ സ്ഥാപനമായി മോഡൽ കൃത്യമായി കൂട്ടിച്ചേർത്തു. വാസ്തവത്തിൽ, അടുത്ത അധ്യായത്തിൽ നമ്മൾ കാണുന്നതുപോലെ, പ്രീപ്രോസസ്സിംഗ് ചില വാക്കുകളെ കൂടുതൽ ചെറിയ ഭാഗങ്ങളായി പോലും വിഭജിക്കുന്നു. ഉദാഹരണത്തിന്, `Sylvain` എന്നത് നാല് ഭാഗങ്ങളായി വിഭജിക്കപ്പെടുന്നു: `S`, `##yl`, `##va`, `##in`. പോസ്‌റ്റ്-പ്രോസസ്സിംഗ് ഘട്ടത്തിൽ, പൈപ്പ്‌ലൈൻ ആ ഭാഗങ്ങളെ വിജയകരമായി വീണ്ടും കൂട്ടിച്ചേർത്തു. + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** ഇംഗ്ലീഷിൽ part-of-speech ടാഗിംഗ് (സാധാരണയായി POS എന്ന് ചുരുക്കി വിളിക്കുന്നു) ചെയ്യാൻ കഴിയുന്ന ഒരു മോഡൽ Model Hub-ൽ തിരയുക. മുകളിലെ ഉദാഹരണത്തിലെ വാക്യത്തിന് ഈ മോഡൽ എന്ത് പ്രവചിക്കുന്നു? + +## ചോദ്യോത്തരം (Question answering)[[question-answering]] + +`question-answering` പൈപ്പ്‌ലൈൻ, നൽകിയ ഒരു സന്ദർഭത്തിലെ (context) വിവരങ്ങൾ ഉപയോഗിച്ച് ചോദ്യങ്ങൾക്ക് ഉത്തരം നൽകുന്നു: + +```python +from transformers import pipeline + +question_answerer = pipeline("question-answering") +question_answerer( + question="Where do I work?", + context="My name is Sylvain and I work at Hugging Face in Brooklyn", +) +``` + +```python out +{'score': 0.6385916471481323, 'start': 33, 'end': 45, 'answer': 'Hugging Face'} +``` + +നൽകിയ സന്ദർഭത്തിൽ നിന്ന് വിവരങ്ങൾ വേർതിരിച്ചെടുത്താണ് ഈ പൈപ്പ്‌ലൈൻ പ്രവർത്തിക്കുന്നത് എന്നത് ശ്രദ്ധിക്കുക; ഇത് ഉത്തരം സൃഷ്ടിക്കുന്നില്ല. + +## സംഗ്രഹം (Summarization)[[summarization]] + +ഒരു ടെക്‌സ്‌റ്റിൽ പരാമർശിക്കുന്ന പ്രധാന കാര്യങ്ങൾ എല്ലാം (അല്ലെങ്കിൽ മിക്കതും) നിലനിർത്തിക്കൊണ്ട് അതിനെ ഒരു ചെറിയ ടെക്‌സ്‌റ്റായി ചുരുക്കുന്ന ടാസ്‌ക്കാണ് സംഗ്രഹം. ഒരു ഉദാഹരണം ഇതാ: + +```python +from transformers import pipeline + +summarizer = pipeline("summarization") +summarizer( + """ + America has changed dramatically during recent years. Not only has the number of + graduates in traditional engineering disciplines such as mechanical, civil, + electrical, chemical, and aeronautical engineering declined, but in most of + the premier American universities engineering curricula now concentrate on + and encourage largely the study of engineering science. As a result, there + are declining offerings in engineering subjects dealing with infrastructure, + the environment, and related issues, and greater concentration on high + technology subjects, largely supporting increasingly complex scientific + developments. While the latter is important, it should not be at the expense + of more traditional engineering. + + Rapidly developing economies such as China and India, as well as other + industrial countries in Europe and Asia, continue to encourage and advance + the teaching of engineering. Both China and India, respectively, graduate + six and eight times as many traditional engineers as does the United States. + Other industrial countries at minimum maintain their output, while America + suffers an increasingly serious decline in the number of engineering graduates + and a lack of well-educated engineers. +""" +) +``` + +```python out +[{'summary_text': ' America has changed dramatically during recent years . The ' + 'number of engineering graduates in the U.S. has declined in ' + 'traditional engineering disciplines such as mechanical, civil ' + ', electrical, chemical, and aeronautical engineering . Rapidly ' + 'developing economies such as China and India, as well as other ' + 'industrial countries in Europe and Asia, continue to encourage ' + 'and advance engineering .'}] +``` + +ടെക്‌സ്‌റ്റ് ജനറേഷനിലേതുപോലെ, ഫലത്തിന് ഒരു `max_length` അല്ലെങ്കിൽ `min_length` നിങ്ങൾക്ക് വ്യക്തമാക്കാം. + + +## വിവർത്തനം (Translation)[[translation]] + +വിവർത്തനത്തിന്, ടാസ്‌ക്കിന്റെ പേരിൽ ഒരു ഭാഷാ ജോഡി നൽകിയാൽ (ഉദാഹരണത്തിന് `"translation_en_to_fr"`) ഒരു ഡിഫോൾട്ട് മോഡൽ ഉപയോഗിക്കാം, എന്നാൽ ഏറ്റവും എളുപ്പമുള്ള വഴി [Model Hub](https://huggingface.co/models)-ൽ നിന്ന് നിങ്ങൾക്ക് ഉപയോഗിക്കേണ്ട മോഡൽ തിരഞ്ഞെടുക്കുന്നതാണ്. ഇവിടെ ഫ്രഞ്ചിൽ നിന്ന് ഇംഗ്ലീഷിലേക്ക് വിവർത്തനം ചെയ്യാൻ ശ്രമിക്കാം: + +```python +from transformers import pipeline + +translator = pipeline("translation", model="Helsinki-NLP/opus-mt-fr-en") +translator("Ce cours est produit par Hugging Face.") +``` + +```python out +[{'translation_text': 'This course is produced by Hugging Face.'}] +``` + +ടെക്‌സ്‌റ്റ് ജനറേഷനിലേയും സംഗ്രഹത്തിലേയും പോലെ, ഫലത്തിന് ഒരു `max_length` അല്ലെങ്കിൽ `min_length` നിങ്ങൾക്ക് വ്യക്തമാക്കാം. + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** മറ്റ് ഭാഷകളിലുള്ള വിവർത്തന മോഡലുകൾ തിരഞ്ഞ്, മുമ്പത്തെ വാക്യം കുറച്ച് വ്യത്യസ്ത ഭാഷകളിലേക്ക് വിവർത്തനം ചെയ്യാൻ ശ്രമിക്കുക. + +## ഇമേജ്, ഓഡിയോ പൈപ്പ്‌ലൈനുകൾ + +ടെക്‌സ്‌റ്റിനപ്പുറം, Transformer മോഡലുകൾക്ക് ചിത്രങ്ങളും ഓഡിയോയും കൈകാര്യം ചെയ്യാനും കഴിയും. ചില ഉദാഹരണങ്ങൾ ഇതാ: + +### ഇമേജ് ക്ലാസിഫിക്കേഷൻ + +```python +from transformers import pipeline + +image_classifier = pipeline( + task="image-classification", model="google/vit-base-patch16-224" +) +result = image_classifier( + "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/pipeline-cat-chonk.jpeg" +) +print(result) +``` + +```python out +[{'label': 'lynx, catamount', 'score': 0.43350091576576233}, + {'label': 'cougar, puma, catamount, mountain lion, painter, panther, Felis concolor', + 'score': 0.034796204417943954}, + {'label': 'snow leopard, ounce, Panthera uncia', + 'score': 0.03240183740854263}, + {'label': 'Egyptian cat', 'score': 0.02394474856555462}, + {'label': 'tiger cat', 'score': 0.02288915030658245}] +``` + +### ഓട്ടോമാറ്റിക് സ്പീച്ച് റെക്കഗ്നിഷൻ + +```python +from transformers import pipeline + +transcriber = pipeline( + task="automatic-speech-recognition", model="openai/whisper-large-v3" +) +result = transcriber( + "https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/mlk.flac" +) +print(result) +``` + +```python out +{'text': ' I have a dream that one day this nation will rise up and live out the true meaning of its creed.'} +``` + +## ഒന്നിലധികം സ്രോതസ്സുകളിൽ നിന്നുള്ള ഡേറ്റ സംയോജിപ്പിക്കുന്നു + +ഒന്നിലധികം സ്രോതസ്സുകളിൽ നിന്നുള്ള ഡേറ്റ സംയോജിപ്പിക്കാനും പ്രോസസ്സ് ചെയ്യാനുമുള്ള കഴിവാണ് Transformer മോഡലുകളുടെ ശക്തമായ ഒരു പ്രയോഗം. താഴെ പറയുന്ന സാഹചര്യങ്ങളിൽ ഇത് പ്രത്യേകിച്ചും ഉപകാരപ്രദമാണ്: + +1. ഒന്നിലധികം ഡേറ്റാബേസുകളിലോ റിപ്പോസിറ്ററികളിലോ തിരയേണ്ടിവരുമ്പോൾ +2. വ്യത്യസ്ത ഫോർമാറ്റുകളിലുള്ള (ടെക്‌സ്‌റ്റ്, ചിത്രങ്ങൾ, ഓഡിയോ) വിവരങ്ങൾ ഒരുമിപ്പിക്കേണ്ടിവരുമ്പോൾ +3. പരസ്പരബന്ധിതമായ വിവരങ്ങളുടെ ഒരു ഏകീകൃത കാഴ്ച ഉണ്ടാക്കേണ്ടിവരുമ്പോൾ + +ഉദാഹരണത്തിന്, താഴെ പറയുന്നവ ചെയ്യുന്ന ഒരു സിസ്റ്റം നിങ്ങൾക്ക് നിർമ്മിക്കാം: +- ടെക്‌സ്‌റ്റ്, ഇമേജ് തുടങ്ങിയ ഒന്നിലധികം മോഡാലിറ്റികളിലുള്ള ഡേറ്റാബേസുകളിൽ വിവരങ്ങൾ തിരയുന്നു. +- വ്യത്യസ്ത സ്രോതസ്സുകളിൽ നിന്നുള്ള ഫലങ്ങൾ ഒരൊറ്റ യോജിച്ച പ്രതികരണമായി സംയോജിപ്പിക്കുന്നു. ഉദാഹരണത്തിന്, ഒരു ഓഡിയോ ഫയലിൽ നിന്നും ഒരു ടെക്‌സ്‌റ്റ് വിവരണത്തിൽ നിന്നും. +- ഡോക്യുമെന്റുകളുടെയും മെറ്റാഡേറ്റയുടെയും ഒരു ഡേറ്റാബേസിൽ നിന്ന് ഏറ്റവും പ്രസക്തമായ വിവരങ്ങൾ അവതരിപ്പിക്കുന്നു. + +## ഉപസംഹാരം + +ഈ അധ്യായത്തിൽ കാണിച്ച പൈപ്പ്‌ലൈനുകൾ പ്രധാനമായും പ്രദർശന ആവശ്യങ്ങൾക്കുള്ളതാണ്. അവ നിശ്ചിത ടാസ്‌ക്കുകൾക്കായി പ്രോഗ്രാം ചെയ്തവയാണ്, അവയുടെ വ്യതിയാനങ്ങൾ ചെയ്യാൻ അവയ്ക്ക് കഴിയില്ല. അടുത്ത അധ്യായത്തിൽ, ഒരു `pipeline()` ഫംഗ്‌ഷന്റെ ഉള്ളിൽ എന്താണുള്ളതെന്നും അതിന്റെ പ്രവർത്തനം എങ്ങനെ ഇഷ്ടാനുസൃതമാക്കാമെന്നും നിങ്ങൾ പഠിക്കും. diff --git a/chapters/ml/chapter1/4.mdx b/chapters/ml/chapter1/4.mdx new file mode 100644 index 000000000..d79d68d6e --- /dev/null +++ b/chapters/ml/chapter1/4.mdx @@ -0,0 +1,189 @@ +# Transformer-കൾ എങ്ങനെ പ്രവർത്തിക്കുന്നു?[[how-do-transformers-work]] + + + +ഈ ഭാഗത്ത്, Transformer മോഡലുകളുടെ ആർക്കിടെക്ചർ നാം പരിശോധിക്കുകയും അറ്റൻഷൻ (attention), എൻകോഡർ-ഡീകോഡർ ആർക്കിടെക്ചർ തുടങ്ങിയ ആശയങ്ങളിലേക്ക് കൂടുതൽ ആഴത്തിൽ ഇറങ്ങുകയും ചെയ്യും. + +> [!WARNING] +> 🚀 ഇവിടെ നാം കാര്യങ്ങൾ ഒരു പടി മുന്നോട്ട് കൊണ്ടുപോകുന്നു. ഈ ഭാഗം വിശദവും സാങ്കേതികവുമാണ്, അതിനാൽ എല്ലാം ഉടനടി മനസ്സിലായില്ലെങ്കിൽ വിഷമിക്കേണ്ട. കോഴ്‌സിൽ പിന്നീട് ഈ ആശയങ്ങളിലേക്ക് നാം തിരിച്ചുവരും. + +## Transformer-ന്റെ ചരിത്രത്തിൽ നിന്ന് അൽപ്പം[[a-bit-of-transformer-history]] + +Transformer മോഡലുകളുടെ (ഹ്രസ്വമായ) ചരിത്രത്തിലെ ചില നാഴികക്കല്ലുകൾ ഇതാ: + +
+Transformer മോഡലുകളുടെ ഒരു ഹ്രസ്വ കാലരേഖ. + +
+ +[Transformer ആർക്കിടെക്ചർ](https://arxiv.org/abs/1706.03762) 2017 ജൂണിൽ അവതരിപ്പിക്കപ്പെട്ടു. മൂല ഗവേഷണത്തിന്റെ ശ്രദ്ധ വിവർത്തന ടാസ്‌ക്കുകളിലായിരുന്നു. ഇതിനെ തുടർന്ന് സ്വാധീനശക്തിയുള്ള നിരവധി മോഡലുകൾ അവതരിപ്പിക്കപ്പെട്ടു, അവയിൽ ചിലത്: + +- **2018 ജൂൺ**: [GPT](https://cdn.openai.com/research-covers/language-unsupervised/language_understanding_paper.pdf), ആദ്യത്തെ പ്രീട്രെയിൻ ചെയ്ത Transformer മോഡൽ; വിവിധ NLP ടാസ്‌ക്കുകളിൽ ഫൈൻ-ട്യൂണിംഗിനായി ഉപയോഗിക്കുകയും അത്യാധുനിക (state-of-the-art) ഫലങ്ങൾ നേടുകയും ചെയ്തു + +- **2018 ഒക്‌ടോബർ**: [BERT](https://arxiv.org/abs/1810.04805), മറ്റൊരു വലിയ പ്രീട്രെയിൻ ചെയ്ത മോഡൽ; വാക്യങ്ങളുടെ മികച്ച സംഗ്രഹങ്ങൾ ഉണ്ടാക്കാൻ രൂപകൽപ്പന ചെയ്തത് (ഇതേക്കുറിച്ച് കൂടുതൽ അടുത്ത അധ്യായത്തിൽ!) + +- **2019 ഫെബ്രുവരി**: [GPT-2](https://cdn.openai.com/better-language-models/language_models_are_unsupervised_multitask_learners.pdf), GPT-യുടെ മെച്ചപ്പെടുത്തിയ (കൂടുതൽ വലിയ) പതിപ്പ്; ധാർമ്മിക ആശങ്കകൾ കാരണം ഉടനടി പൊതുജനങ്ങൾക്ക് ലഭ്യമാക്കിയിരുന്നില്ല + +- **2019 ഒക്‌ടോബർ**: [T5](https://huggingface.co/papers/1910.10683), sequence-to-sequence Transformer ആർക്കിടെക്ചറിന്റെ മൾട്ടി-ടാസ്‌ക് കേന്ദ്രീകൃതമായ ഒരു ഇംപ്ലിമെന്റേഷൻ. + +- **2020 മെയ്**, [GPT-3](https://huggingface.co/papers/2005.14165), GPT-2-ന്റെ അതിലും വലിയ പതിപ്പ്; ഫൈൻ-ട്യൂണിംഗിന്റെ ആവശ്യമില്ലാതെ തന്നെ വിവിധ ടാസ്‌ക്കുകളിൽ നന്നായി പ്രവർത്തിക്കാൻ കഴിവുള്ളത് (_zero-shot learning_ എന്ന് വിളിക്കുന്നു) + +- **2022 ജനുവരി**: [InstructGPT](https://huggingface.co/papers/2203.02155), നിർദ്ദേശങ്ങൾ (instructions) കൂടുതൽ നന്നായി പിന്തുടരാൻ പരിശീലിപ്പിച്ച GPT-3-ന്റെ ഒരു പതിപ്പ്. + +- **2023 ജനുവരി**: [Llama](https://huggingface.co/papers/2302.13971), വിവിധ ഭാഷകളിൽ ടെക്‌സ്‌റ്റ് ജനറേറ്റ് ചെയ്യാൻ കഴിവുള്ള ഒരു വലിയ ഭാഷാ മോഡൽ (large language model). + +- **2023 മാർച്ച്**: [Mistral](https://huggingface.co/papers/2310.06825), 7 ബില്യൺ പാരാമീറ്ററുകളുള്ള ഒരു ഭാഷാ മോഡൽ; വിലയിരുത്തിയ എല്ലാ ബെഞ്ച്‌മാർക്കുകളിലും Llama 2 13B-യെ മറികടക്കുന്നു. വേഗത്തിലുള്ള ഇൻഫറൻസിനായി grouped-query attention-ഉം ഏത് നീളത്തിലുള്ള സീക്വൻസുകളും കൈകാര്യം ചെയ്യാൻ sliding window attention-ഉം ഇത് ഉപയോഗിക്കുന്നു. + +- **2024 മെയ്**: [Gemma 2](https://huggingface.co/papers/2408.00118), 2B മുതൽ 27B വരെ പാരാമീറ്ററുകളുള്ള, ഭാരം കുറഞ്ഞ, അത്യാധുനിക ഓപ്പൺ മോഡലുകളുടെ ഒരു കുടുംബം. ഇവ interleaved local-global attention-ഉം group-query attention-ഉം ഉൾക്കൊള്ളുന്നു; ചെറിയ മോഡലുകൾ knowledge distillation ഉപയോഗിച്ച് പരിശീലിപ്പിച്ചതിനാൽ 2-3 മടങ്ങ് വലിയ മോഡലുകളോട് കിടപിടിക്കുന്ന പ്രകടനം നൽകുന്നു. + +- **2024 നവംബർ**: [SmolLM2](https://huggingface.co/papers/2502.02737), അത്യാധുനികമായ ഒരു ചെറിയ ഭാഷാ മോഡൽ (135 ദശലക്ഷം മുതൽ 1.7 ബില്യൺ വരെ പാരാമീറ്ററുകൾ); ചെറിയ വലിപ്പമായിട്ടും ശ്രദ്ധേയമായ പ്രകടനം കാഴ്ചവയ്ക്കുകയും മൊബൈൽ, എഡ്ജ് ഉപകരണങ്ങൾക്ക് പുതിയ സാധ്യതകൾ തുറന്നുകൊടുക്കുകയും ചെയ്യുന്നു. + +ഈ പട്ടിക ഒരിക്കലും സമ്പൂർണ്ണമല്ല; വിവിധ തരം Transformer മോഡലുകളിൽ ചിലതിനെ എടുത്തുകാണിക്കാൻ മാത്രമാണ് ഇത് ഉദ്ദേശിച്ചിട്ടുള്ളത്. വിശാലമായി പറഞ്ഞാൽ, ഇവയെ മൂന്ന് വിഭാഗങ്ങളായി തിരിക്കാം: + +- GPT-സമാനമായവ (_auto-regressive_ Transformer മോഡലുകൾ എന്നും വിളിക്കുന്നു) +- BERT-സമാനമായവ (_auto-encoding_ Transformer മോഡലുകൾ എന്നും വിളിക്കുന്നു) +- T5-സമാനമായവ (_sequence-to-sequence_ Transformer മോഡലുകൾ എന്നും വിളിക്കുന്നു) + +ഈ കുടുംബങ്ങളെക്കുറിച്ച് പിന്നീട് നാം കൂടുതൽ ആഴത്തിൽ പഠിക്കും. + +## Transformer-കൾ ഭാഷാ മോഡലുകളാണ്[[transformers-are-language-models]] + +മുകളിൽ പറഞ്ഞ എല്ലാ Transformer മോഡലുകളും (GPT, BERT, T5 മുതലായവ) *ഭാഷാ മോഡലുകൾ* (language models) ആയാണ് പരിശീലിപ്പിച്ചിട്ടുള്ളത്. അതായത്, വലിയ അളവിലുള്ള അസംസ്‌കൃത ടെക്‌സ്‌റ്റിൽ self-supervised രീതിയിലാണ് ഇവയെ പരിശീലിപ്പിച്ചിട്ടുള്ളത്. + +Self-supervised learning എന്നത് മോഡലിന്റെ ഇൻപുട്ടുകളിൽ നിന്ന് തന്നെ പരിശീലന ലക്ഷ്യം (objective) സ്വയമേവ കണക്കാക്കപ്പെടുന്ന ഒരു തരം പരിശീലനമാണ്. അതിനർത്ഥം ഡേറ്റ ലേബൽ ചെയ്യാൻ മനുഷ്യരുടെ ആവശ്യമില്ല എന്നാണ്! + +ഇത്തരം മോഡലുകൾ അവയെ പരിശീലിപ്പിച്ച ഭാഷയെക്കുറിച്ച് ഒരു സ്ഥിതിവിവരപരമായ (statistical) ധാരണ വികസിപ്പിക്കുന്നു, എന്നാൽ നിർദ്ദിഷ്ട പ്രായോഗിക ടാസ്‌ക്കുകൾക്ക് ഇവ അത്ര ഉപയോഗപ്രദമല്ല. ഇക്കാരണത്താൽ, പൊതുവായ പ്രീട്രെയിൻ ചെയ്ത മോഡൽ പിന്നീട് *transfer learning* അഥവാ *ഫൈൻ-ട്യൂണിംഗ്* എന്ന ഒരു പ്രക്രിയയിലൂടെ കടന്നുപോകുന്നു. ഈ പ്രക്രിയയിൽ, ഒരു നിശ്ചിത ടാസ്‌ക്കിനായി supervised രീതിയിൽ -- അതായത്, മനുഷ്യർ നൽകിയ ലേബലുകൾ ഉപയോഗിച്ച് -- മോഡലിനെ ഫൈൻ-ട്യൂൻ ചെയ്യുന്നു. + +ഒരു ടാസ്‌ക്കിന്റെ ഉദാഹരണമാണ് മുൻപുള്ള *n* വാക്കുകൾ വായിച്ചതിനുശേഷം ഒരു വാക്യത്തിലെ അടുത്ത വാക്ക് പ്രവചിക്കുന്നത്. ഔട്ട്‌പുട്ട് ഭൂതകാല, വർത്തമാനകാല ഇൻപുട്ടുകളെ ആശ്രയിക്കുകയും ഭാവിയിലുള്ളവയെ ആശ്രയിക്കാതിരിക്കുകയും ചെയ്യുന്നതിനാൽ ഇതിനെ *causal language modeling* എന്ന് വിളിക്കുന്നു. + +
+ഒരു വാക്യത്തിലെ അടുത്ത വാക്ക് പ്രവചിക്കുന്ന causal language modeling-ന്റെ ഉദാഹരണം. + +
+ +മറ്റൊരു ഉദാഹരണം *masked language modeling* ആണ്; ഇതിൽ വാക്യത്തിലെ മാസ്‌ക് ചെയ്ത ഒരു വാക്ക് മോഡൽ പ്രവചിക്കുന്നു. + +
+ഒരു വാക്യത്തിലെ മാസ്‌ക് ചെയ്ത വാക്ക് പ്രവചിക്കുന്ന masked language modeling-ന്റെ ഉദാഹരണം. + +
+ +## Transformer-കൾ വലിയ മോഡലുകളാണ്[[transformers-are-big-models]] + +ചില അപവാദങ്ങൾ (DistilBERT പോലുള്ളവ) ഒഴിച്ചാൽ, മികച്ച പ്രകടനം നേടാനുള്ള പൊതുവായ തന്ത്രം മോഡലുകളുടെ വലിപ്പവും അവയെ പ്രീട്രെയിൻ ചെയ്യുന്ന ഡേറ്റയുടെ അളവും വർദ്ധിപ്പിക്കുക എന്നതാണ്. + +
+സമീപകാല Transformer മോഡലുകളുടെ പാരാമീറ്ററുകളുടെ എണ്ണം +
+ +നിർഭാഗ്യവശാൽ, ഒരു മോഡൽ പരിശീലിപ്പിക്കാൻ, പ്രത്യേകിച്ച് വലിയ ഒന്ന്, വലിയ അളവിൽ ഡേറ്റ ആവശ്യമാണ്. സമയത്തിന്റെയും കമ്പ്യൂട്ട് വിഭവങ്ങളുടെയും കാര്യത്തിൽ ഇത് വളരെ ചെലവേറിയതായി മാറുന്നു. താഴെയുള്ള ഗ്രാഫിൽ കാണാവുന്നതുപോലെ, ഇത് പരിസ്ഥിതിയെ ബാധിക്കുന്നതിലേക്കും നയിക്കുന്നു. + +
+ഒരു വലിയ ഭാഷാ മോഡലിന്റെ കാർബൺ കാൽപ്പാട്. + +
+ + + +പ്രീട്രെയിനിംഗിന്റെ പാരിസ്ഥിതിക ആഘാതം കുറയ്ക്കാൻ ബോധപൂർവ്വം ശ്രമിക്കുന്ന ഒരു ടീം നയിച്ച (വളരെ വലിയ) ഒരു മോഡലിന്റെ പ്രോജക്റ്റാണ് ഇവിടെ കാണിക്കുന്നത്. മികച്ച ഹൈപ്പർപാരാമീറ്ററുകൾ കണ്ടെത്താൻ നിരവധി പരീക്ഷണങ്ങൾ നടത്തുന്നതിന്റെ കാൽപ്പാട് ഇതിലും വളരെ കൂടുതലായിരിക്കും. + +ഒരു ഗവേഷക ടീമോ, വിദ്യാർത്ഥി സംഘടനയോ, കമ്പനിയോ ഒരു മോഡൽ പരിശീലിപ്പിക്കാൻ ആഗ്രഹിക്കുമ്പോഴെല്ലാം അത് പൂജ്യത്തിൽ നിന്ന് (from scratch) ചെയ്യുന്നു എന്ന് സങ്കൽപ്പിക്കുക. ഇത് ആഗോളതലത്തിൽ ഭീമവും അനാവശ്യവുമായ ചെലവുകളിലേക്ക് നയിക്കും! + +ഇതുകൊണ്ടാണ് ഭാഷാ മോഡലുകൾ പങ്കുവയ്ക്കുന്നത് അതിപ്രധാനമാകുന്നത്: പരിശീലിപ്പിച്ച വെയ്‌റ്റുകൾ (weights) പങ്കുവയ്ക്കുന്നതും ഇതിനകം പരിശീലിപ്പിച്ച വെയ്‌റ്റുകളുടെ മേൽ കെട്ടിപ്പടുക്കുന്നതും കമ്യൂണിറ്റിയുടെ മൊത്തത്തിലുള്ള കമ്പ്യൂട്ട് ചെലവും കാർബൺ കാൽപ്പാടും കുറയ്ക്കുന്നു. + +അതുകൂടാതെ, നിങ്ങളുടെ മോഡലുകളുടെ പരിശീലനത്തിന്റെ കാർബൺ കാൽപ്പാട് പല ടൂളുകൾ ഉപയോഗിച്ച് നിങ്ങൾക്ക് വിലയിരുത്താം. ഉദാഹരണത്തിന് [ML CO2 Impact](https://mlco2.github.io/impact/) അല്ലെങ്കിൽ 🤗 Transformers-ൽ സംയോജിപ്പിച്ചിട്ടുള്ള [Code Carbon]( https://codecarbon.io/). ഇതേക്കുറിച്ച് കൂടുതൽ അറിയാൻ, നിങ്ങളുടെ പരിശീലനത്തിന്റെ കാൽപ്പാടിന്റെ ഒരു കണക്കുകൂട്ടലടങ്ങിയ `emissions.csv` ഫയൽ എങ്ങനെ ഉണ്ടാക്കാമെന്ന് കാണിക്കുന്ന ഈ [ബ്ലോഗ് പോസ്റ്റ്](https://huggingface.co/blog/carbon-emissions-on-the-hub) വായിക്കാം; അതുപോലെ ഈ വിഷയം കൈകാര്യം ചെയ്യുന്ന 🤗 Transformers-ന്റെ [ഡോക്യുമെന്റേഷനും](https://huggingface.co/docs/hub/model-cards-co2) വായിക്കാം. + + +## Transfer Learning[[transfer-learning]] + + + +*പ്രീട്രെയിനിംഗ്* എന്നത് ഒരു മോഡലിനെ പൂജ്യത്തിൽ നിന്ന് പരിശീലിപ്പിക്കുന്ന പ്രവർത്തനമാണ്: വെയ്‌റ്റുകൾ ക്രമരഹിതമായി (randomly) ഇനിഷ്യലൈസ് ചെയ്യപ്പെടുന്നു, മുൻകൂർ അറിവ് ഒന്നുമില്ലാതെ പരിശീലനം ആരംഭിക്കുന്നു. + +
+ഒരു ഭാഷാ മോഡലിന്റെ പ്രീട്രെയിനിംഗ് സമയത്തിന്റെയും പണത്തിന്റെയും കാര്യത്തിൽ ചെലവേറിയതാണ്. + +
+ +ഈ പ്രീട്രെയിനിംഗ് സാധാരണയായി വളരെ വലിയ അളവിലുള്ള ഡേറ്റയിലാണ് ചെയ്യുന്നത്. അതിനാൽ, ഇതിന് വളരെ വലിയ ഒരു ഡേറ്റാ കോർപ്പസ് ആവശ്യമാണ്, പരിശീലനം പല ആഴ്ചകൾ വരെ നീണ്ടുനിൽക്കാം. + +മറുവശത്ത്, *ഫൈൻ-ട്യൂണിംഗ്* എന്നത് ഒരു മോഡൽ പ്രീട്രെയിൻ ചെയ്തതിനു **ശേഷം** നടത്തുന്ന പരിശീലനമാണ്. ഫൈൻ-ട്യൂണിംഗ് നടത്താൻ, നിങ്ങൾ ആദ്യം പ്രീട്രെയിൻ ചെയ്ത ഒരു ഭാഷാ മോഡൽ സ്വന്തമാക്കുന്നു, പിന്നീട് നിങ്ങളുടെ ടാസ്‌ക്കിന് പ്രത്യേകമായ ഒരു ഡേറ്റാസെറ്റ് ഉപയോഗിച്ച് അധിക പരിശീലനം നടത്തുന്നു. ഒരു നിമിഷം -- എന്തുകൊണ്ട് നിങ്ങളുടെ അന്തിമ ഉപയോഗത്തിനായി തുടക്കം മുതൽ (**scratch**) തന്നെ മോഡലിനെ പരിശീലിപ്പിക്കുന്നില്ല? അതിന് ചില കാരണങ്ങളുണ്ട്: + +* ഫൈൻ-ട്യൂണിംഗ് ഡേറ്റാസെറ്റുമായി ചില സാമ്യങ്ങളുള്ള ഒരു ഡേറ്റാസെറ്റിൽ പ്രീട്രെയിൻ ചെയ്ത മോഡൽ ഇതിനകം പരിശീലിപ്പിക്കപ്പെട്ടിട്ടുണ്ട്. അതിനാൽ പ്രീട്രെയിനിംഗ് സമയത്ത് ആദ്യ മോഡൽ നേടിയ അറിവ് ഫൈൻ-ട്യൂണിംഗ് പ്രക്രിയയ്ക്ക് പ്രയോജനപ്പെടുത്താൻ കഴിയും (ഉദാഹരണത്തിന്, NLP പ്രശ്നങ്ങളിൽ, നിങ്ങളുടെ ടാസ്‌ക്കിനായി നിങ്ങൾ ഉപയോഗിക്കുന്ന ഭാഷയെക്കുറിച്ച് പ്രീട്രെയിൻ ചെയ്ത മോഡലിന് ഏതെങ്കിലും തരത്തിലുള്ള സ്ഥിതിവിവരപരമായ ധാരണ ഉണ്ടായിരിക്കും). +* പ്രീട്രെയിൻ ചെയ്ത മോഡൽ ഇതിനകം ധാരാളം ഡേറ്റയിൽ പരിശീലിപ്പിക്കപ്പെട്ടതിനാൽ, തൃപ്തികരമായ ഫലങ്ങൾ ലഭിക്കാൻ ഫൈൻ-ട്യൂണിംഗിന് വളരെ കുറച്ച് ഡേറ്റ മതി. +* അതേ കാരണത്താൽ, നല്ല ഫലങ്ങൾ ലഭിക്കാൻ ആവശ്യമായ സമയവും വിഭവങ്ങളും വളരെ കുറവാണ്. + +ഉദാഹരണത്തിന്, ഇംഗ്ലീഷ് ഭാഷയിൽ പരിശീലിപ്പിച്ച ഒരു പ്രീട്രെയിൻ ചെയ്ത മോഡൽ എടുത്ത് ഒരു arXiv കോർപ്പസിൽ ഫൈൻ-ട്യൂൻ ചെയ്താൽ, ശാസ്ത്ര/ഗവേഷണ അധിഷ്ഠിതമായ ഒരു മോഡൽ ലഭിക്കും. ഫൈൻ-ട്യൂണിംഗിന് പരിമിതമായ അളവിലുള്ള ഡേറ്റ മാത്രമേ ആവശ്യമുള്ളൂ: പ്രീട്രെയിൻ ചെയ്ത മോഡൽ നേടിയ അറിവ് "കൈമാറ്റം ചെയ്യപ്പെടുന്നു" (transferred), അതുകൊണ്ടാണ് *transfer learning* എന്ന പേര്. + +
+ഒരു ഭാഷാ മോഡലിന്റെ ഫൈൻ-ട്യൂണിംഗ് സമയത്തിന്റെയും പണത്തിന്റെയും കാര്യത്തിൽ പ്രീട്രെയിനിംഗിനെക്കാൾ ചെലവ് കുറഞ്ഞതാണ്. + +
+ +അതിനാൽ ഒരു മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യുന്നതിന് സമയം, ഡേറ്റ, പണം, പരിസ്ഥിതി എന്നിവയുടെ കാര്യത്തിൽ ചെലവ് കുറവാണ്. പൂർണ്ണമായ പ്രീട്രെയിനിംഗിനെക്കാൾ പരിശീലനത്തിന് നിയന്ത്രണങ്ങൾ കുറവായതിനാൽ, വ്യത്യസ്ത ഫൈൻ-ട്യൂണിംഗ് രീതികൾ പരീക്ഷിച്ചുനോക്കുന്നതും കൂടുതൽ വേഗത്തിലും എളുപ്പത്തിലും സാധിക്കും. + +ഈ പ്രക്രിയ പൂജ്യത്തിൽ നിന്ന് പരിശീലിപ്പിക്കുന്നതിനെക്കാൾ മികച്ച ഫലങ്ങളും നൽകും (നിങ്ങൾക്ക് ധാരാളം ഡേറ്റ ഇല്ലെങ്കിൽ). അതുകൊണ്ടാണ് നിങ്ങൾ എപ്പോഴും പ്രീട്രെയിൻ ചെയ്ത ഒരു മോഡൽ -- നിങ്ങളുടെ കൈയിലുള്ള ടാസ്‌ക്കിനോട് കഴിയുന്നത്ര അടുത്തുനിൽക്കുന്ന ഒന്ന് -- പ്രയോജനപ്പെടുത്തി അതിനെ ഫൈൻ-ട്യൂൻ ചെയ്യാൻ ശ്രമിക്കേണ്ടത്. + +## Transformer-ന്റെ പൊതുവായ ആർക്കിടെക്ചർ[[general-transformer-architecture]] + +ഈ ഭാഗത്ത്, Transformer മോഡലിന്റെ പൊതുവായ ആർക്കിടെക്ചർ നാം പരിശോധിക്കും. ചില ആശയങ്ങൾ മനസ്സിലായില്ലെങ്കിൽ വിഷമിക്കേണ്ട; ഓരോ ഘടകത്തെയും വിശദമായി പ്രതിപാദിക്കുന്ന ഭാഗങ്ങൾ പിന്നീടുണ്ട്. + + + +മോഡൽ പ്രധാനമായും രണ്ട് ബ്ലോക്കുകൾ ചേർന്നതാണ്: + +* **എൻകോഡർ (ഇടത്)**: എൻകോഡർ ഒരു ഇൻപുട്ട് സ്വീകരിക്കുകയും അതിന്റെ ഒരു പ്രതിനിധാനം (representation, അതായത് അതിന്റെ ഫീച്ചറുകൾ) നിർമ്മിക്കുകയും ചെയ്യുന്നു. അതായത്, ഇൻപുട്ടിൽ നിന്ന് ധാരണ നേടാൻ മോഡൽ ഒപ്‌റ്റിമൈസ് ചെയ്യപ്പെട്ടിരിക്കുന്നു. +* **ഡീകോഡർ (വലത്)**: ഡീകോഡർ എൻകോഡറിന്റെ പ്രതിനിധാനവും (ഫീച്ചറുകൾ) മറ്റ് ഇൻപുട്ടുകളും ഉപയോഗിച്ച് ഒരു ടാർഗെറ്റ് സീക്വൻസ് ജനറേറ്റ് ചെയ്യുന്നു. അതായത്, ഔട്ട്‌പുട്ടുകൾ ജനറേറ്റ് ചെയ്യാൻ മോഡൽ ഒപ്‌റ്റിമൈസ് ചെയ്യപ്പെട്ടിരിക്കുന്നു. + +
+Transformer മോഡലുകളുടെ ആർക്കിടെക്ചർ + +
+ +ടാസ്‌ക്കിനെ ആശ്രയിച്ച്, ഈ ഭാഗങ്ങളിൽ ഓരോന്നും സ്വതന്ത്രമായി ഉപയോഗിക്കാം: + +* **എൻകോഡർ-മാത്രം (Encoder-only) മോഡലുകൾ**: വാക്യ വർഗ്ഗീകരണം (sentence classification), named entity recognition എന്നിവ പോലെ ഇൻപുട്ടിനെക്കുറിച്ചുള്ള ധാരണ ആവശ്യമായ ടാസ്‌ക്കുകൾക്ക് നല്ലത്. +* **ഡീകോഡർ-മാത്രം (Decoder-only) മോഡലുകൾ**: ടെക്‌സ്‌റ്റ് ജനറേഷൻ പോലുള്ള ജനറേറ്റീവ് ടാസ്‌ക്കുകൾക്ക് നല്ലത്. +* **എൻകോഡർ-ഡീകോഡർ മോഡലുകൾ** അഥവാ **sequence-to-sequence മോഡലുകൾ**: വിവർത്തനം, സംഗ്രഹം (summarization) എന്നിവ പോലെ ഒരു ഇൻപുട്ട് ആവശ്യമായ ജനറേറ്റീവ് ടാസ്‌ക്കുകൾക്ക് നല്ലത്. + +ഈ ആർക്കിടെക്ചറുകളെ ഓരോന്നായി പിന്നീടുള്ള ഭാഗങ്ങളിൽ നാം വിശദമായി പഠിക്കും. + +## അറ്റൻഷൻ ലെയറുകൾ[[attention-layers]] + +Transformer മോഡലുകളുടെ ഒരു പ്രധാന സവിശേഷത അവ *അറ്റൻഷൻ ലെയറുകൾ* (attention layers) എന്ന പ്രത്യേക ലെയറുകൾ ഉപയോഗിച്ചാണ് നിർമ്മിച്ചിട്ടുള്ളത് എന്നതാണ്. വാസ്തവത്തിൽ, Transformer ആർക്കിടെക്ചർ അവതരിപ്പിച്ച പ്രബന്ധത്തിന്റെ തലക്കെട്ട് തന്നെ ["Attention Is All You Need"](https://arxiv.org/abs/1706.03762) എന്നായിരുന്നു! അറ്റൻഷൻ ലെയറുകളുടെ വിശദാംശങ്ങൾ കോഴ്‌സിൽ പിന്നീട് നാം പരിശോധിക്കും; ഇപ്പോൾ നിങ്ങൾ അറിയേണ്ടത് ഇത്രമാത്രം: ഓരോ വാക്കിന്റെയും പ്രതിനിധാനം കൈകാര്യം ചെയ്യുമ്പോൾ, നിങ്ങൾ നൽകിയ വാക്യത്തിലെ ചില പ്രത്യേക വാക്കുകളിൽ ശ്രദ്ധ കേന്ദ്രീകരിക്കാനും (മറ്റുള്ളവയെ ഏറെക്കുറെ അവഗണിക്കാനും) ഈ ലെയർ മോഡലിനോട് പറയുന്നു. + +ഇത് സന്ദർഭത്തിൽ മനസ്സിലാക്കാൻ, ഇംഗ്ലീഷിൽ നിന്ന് ഫ്രഞ്ചിലേക്ക് ടെക്‌സ്‌റ്റ് വിവർത്തനം ചെയ്യുന്ന ടാസ്‌ക് പരിഗണിക്കുക. "You like this course" എന്ന ഇൻപുട്ട് നൽകിയാൽ, "like" എന്ന വാക്കിന്റെ ശരിയായ വിവർത്തനം ലഭിക്കാൻ ഒരു വിവർത്തന മോഡലിന് അതിനോട് ചേർന്നുള്ള "You" എന്ന വാക്കിലും ശ്രദ്ധിക്കേണ്ടിവരും, കാരണം ഫ്രഞ്ചിൽ "like" എന്ന ക്രിയയുടെ രൂപം കർത്താവിനെ ആശ്രയിച്ച് മാറുന്നു. എന്നാൽ വാക്യത്തിന്റെ ബാക്കി ഭാഗം ആ വാക്കിന്റെ വിവർത്തനത്തിന് ഉപകാരപ്രദമല്ല. അതുപോലെ, "this" വിവർത്തനം ചെയ്യുമ്പോൾ മോഡലിന് "course" എന്ന വാക്കിലും ശ്രദ്ധിക്കേണ്ടിവരും, കാരണം ബന്ധപ്പെട്ട നാമം പുല്ലിംഗമോ സ്ത്രീലിംഗമോ എന്നതനുസരിച്ച് "this" വ്യത്യസ്തമായി വിവർത്തനം ചെയ്യപ്പെടുന്നു. ഇവിടെയും, "course" വിവർത്തനം ചെയ്യുന്നതിന് വാക്യത്തിലെ മറ്റ് വാക്കുകൾ പ്രസക്തമല്ല. കൂടുതൽ സങ്കീർണ്ണമായ വാക്യങ്ങളിൽ (കൂടുതൽ സങ്കീർണ്ണമായ വ്യാകരണ നിയമങ്ങളിലും), ഓരോ വാക്കും ശരിയായി വിവർത്തനം ചെയ്യാൻ വാക്യത്തിൽ വളരെ അകലെ വരുന്ന വാക്കുകളിലും മോഡലിന് പ്രത്യേക ശ്രദ്ധ കൊടുക്കേണ്ടിവരും. + +സ്വാഭാവിക ഭാഷയുമായി ബന്ധപ്പെട്ട ഏത് ടാസ്‌ക്കിനും ഇതേ ആശയം ബാധകമാണ്: ഒരു വാക്കിന് അതിന്റേതായ അർത്ഥമുണ്ട്, എന്നാൽ ആ അർത്ഥത്തെ സന്ദർഭം ആഴത്തിൽ സ്വാധീനിക്കുന്നു — ആ സന്ദർഭം പഠിക്കുന്ന വാക്കിന് മുൻപോ പിൻപോ വരുന്ന ഏതെങ്കിലും വാക്കോ (വാക്കുകളോ) ആകാം. + +അറ്റൻഷൻ ലെയറുകൾ എന്തിനെക്കുറിച്ചാണെന്ന് ഇപ്പോൾ നിങ്ങൾക്കൊരു ധാരണ ലഭിച്ചതിനാൽ, Transformer ആർക്കിടെക്ചറിനെ കൂടുതൽ അടുത്ത് നോക്കാം. + +## മൂല ആർക്കിടെക്ചർ[[the-original-architecture]] + +Transformer ആർക്കിടെക്ചർ ആദ്യം വിവർത്തനത്തിനായി രൂപകൽപ്പന ചെയ്തതാണ്. പരിശീലന സമയത്ത്, എൻകോഡർ ഒരു നിശ്ചിത ഭാഷയിലുള്ള ഇൻപുട്ടുകൾ (വാക്യങ്ങൾ) സ്വീകരിക്കുന്നു, അതേസമയം ഡീകോഡർ അതേ വാക്യങ്ങൾ ആവശ്യമുള്ള ടാർഗെറ്റ് ഭാഷയിൽ സ്വീകരിക്കുന്നു. എൻകോഡറിൽ, അറ്റൻഷൻ ലെയറുകൾക്ക് ഒരു വാക്യത്തിലെ എല്ലാ വാക്കുകളും ഉപയോഗിക്കാം (കാരണം, നാം ഇപ്പോൾ കണ്ടതുപോലെ, ഒരു വാക്കിന്റെ വിവർത്തനം വാക്യത്തിൽ അതിന് മുൻപുള്ളതിനെയും പിൻപുള്ളതിനെയും ആശ്രയിച്ചിരിക്കാം). എന്നാൽ ഡീകോഡർ ക്രമാനുഗതമായി (sequentially) പ്രവർത്തിക്കുന്നു, അതിന് ഇതിനകം വിവർത്തനം ചെയ്ത വാക്കുകളിൽ മാത്രമേ ശ്രദ്ധിക്കാൻ കഴിയൂ (അതായത്, ഇപ്പോൾ ജനറേറ്റ് ചെയ്യുന്ന വാക്കിന് മുൻപുള്ള വാക്കുകളിൽ മാത്രം). ഉദാഹരണത്തിന്, വിവർത്തനം ചെയ്ത ടാർഗെറ്റിന്റെ ആദ്യ മൂന്ന് വാക്കുകൾ പ്രവചിച്ചുകഴിഞ്ഞാൽ, അവ നാം ഡീകോഡറിന് നൽകുന്നു, അത് പിന്നീട് എൻകോഡറിന്റെ എല്ലാ ഇൻപുട്ടുകളും ഉപയോഗിച്ച് നാലാമത്തെ വാക്ക് പ്രവചിക്കാൻ ശ്രമിക്കുന്നു. + +പരിശീലന സമയത്ത് (മോഡലിന് ടാർഗെറ്റ് വാക്യങ്ങളിലേക്ക് ആക്‌സസ് ഉള്ളപ്പോൾ) കാര്യങ്ങൾ വേഗത്തിലാക്കാൻ, ഡീകോഡറിന് മുഴുവൻ ടാർഗെറ്റും നൽകുന്നു, എന്നാൽ ഭാവിയിലെ വാക്കുകൾ ഉപയോഗിക്കാൻ അതിനെ അനുവദിക്കുന്നില്ല (സ്ഥാനം 2-ലെ വാക്ക് പ്രവചിക്കാൻ ശ്രമിക്കുമ്പോൾ സ്ഥാനം 2-ലെ വാക്കിലേക്ക് ആക്‌സസ് ഉണ്ടായിരുന്നെങ്കിൽ, പ്രശ്നം അത്ര ബുദ്ധിമുട്ടുള്ളതാകുമായിരുന്നില്ല!). ഉദാഹരണത്തിന്, നാലാമത്തെ വാക്ക് പ്രവചിക്കാൻ ശ്രമിക്കുമ്പോൾ, അറ്റൻഷൻ ലെയറിന് 1 മുതൽ 3 വരെയുള്ള സ്ഥാനങ്ങളിലെ വാക്കുകളിലേക്ക് മാത്രമേ ആക്‌സസ് ഉണ്ടാകൂ. + +മൂല Transformer ആർക്കിടെക്ചർ ഇങ്ങനെയായിരുന്നു — ഇടതുവശത്ത് എൻകോഡറും വലതുവശത്ത് ഡീകോഡറും: + +
+Transformer മോഡലുകളുടെ ആർക്കിടെക്ചർ + +
+ +ഒരു ഡീകോഡർ ബ്ലോക്കിലെ ആദ്യത്തെ അറ്റൻഷൻ ലെയർ ഡീകോഡറിലേക്കുള്ള എല്ലാ (മുൻകാല) ഇൻപുട്ടുകളിലും ശ്രദ്ധിക്കുന്നു, എന്നാൽ രണ്ടാമത്തെ അറ്റൻഷൻ ലെയർ എൻകോഡറിന്റെ ഔട്ട്‌പുട്ട് ഉപയോഗിക്കുന്നു എന്നത് ശ്രദ്ധിക്കുക. അതിനാൽ നിലവിലെ വാക്ക് ഏറ്റവും നന്നായി പ്രവചിക്കാൻ അതിന് മുഴുവൻ ഇൻപുട്ട് വാക്യവും ആക്‌സസ് ചെയ്യാൻ കഴിയും. വ്യത്യസ്ത ഭാഷകളിൽ വാക്കുകളെ വ്യത്യസ്ത ക്രമത്തിൽ വയ്ക്കുന്ന വ്യാകരണ നിയമങ്ങൾ ഉണ്ടാകാം, അല്ലെങ്കിൽ വാക്യത്തിൽ പിന്നീട് നൽകുന്ന ചില സന്ദർഭങ്ങൾ ഒരു വാക്കിന്റെ ഏറ്റവും മികച്ച വിവർത്തനം നിർണ്ണയിക്കാൻ സഹായകമായേക്കാം എന്നതിനാൽ ഇത് വളരെ ഉപയോഗപ്രദമാണ്. + +ചില പ്രത്യേക വാക്കുകളിൽ മോഡൽ ശ്രദ്ധിക്കുന്നത് തടയാൻ എൻകോഡറിലും ഡീകോഡറിലും *അറ്റൻഷൻ മാസ്‌ക്* (attention mask) ഉപയോഗിക്കാം -- ഉദാഹരണത്തിന്, വാക്യങ്ങൾ ഒരുമിച്ച് ബാച്ച് ചെയ്യുമ്പോൾ എല്ലാ ഇൻപുട്ടുകളും ഒരേ നീളത്തിലാക്കാൻ ഉപയോഗിക്കുന്ന പ്രത്യേക പാഡിംഗ് (padding) വാക്ക്. + +## ആർക്കിടെക്ചറുകളും ചെക്ക്‌പോയിന്റുകളും[[architecture-vs-checkpoints]] + +ഈ കോഴ്‌സിൽ Transformer മോഡലുകളിലേക്ക് നാം ആഴത്തിൽ ഇറങ്ങുമ്പോൾ, *ആർക്കിടെക്ചറുകൾ*, *ചെക്ക്‌പോയിന്റുകൾ*, *മോഡലുകൾ* എന്നിവയെക്കുറിച്ചുള്ള പരാമർശങ്ങൾ നിങ്ങൾ കാണും. ഈ പദങ്ങൾക്കെല്ലാം അൽപ്പം വ്യത്യസ്തമായ അർത്ഥങ്ങളുണ്ട്: + +* **ആർക്കിടെക്ചർ**: ഇത് മോഡലിന്റെ അസ്ഥികൂടമാണ് -- മോഡലിനുള്ളിൽ നടക്കുന്ന ഓരോ ലെയറിന്റെയും ഓരോ പ്രവർത്തനത്തിന്റെയും നിർവചനം. +* **ചെക്ക്‌പോയിന്റുകൾ**: ഒരു നിശ്ചിത ആർക്കിടെക്ചറിൽ ലോഡ് ചെയ്യപ്പെടുന്ന വെയ്‌റ്റുകളാണ് ഇവ. +* **മോഡൽ**: ഇത് "ആർക്കിടെക്ചർ" അല്ലെങ്കിൽ "ചെക്ക്‌പോയിന്റ്" പോലെ കൃത്യമല്ലാത്ത ഒരു പൊതുപദമാണ്: ഇതിന് രണ്ടും അർത്ഥമാക്കാം. അവ്യക്തത കുറയ്ക്കാൻ ആവശ്യമുള്ളിടത്ത് ഈ കോഴ്‌സ് *ആർക്കിടെക്ചർ* അല്ലെങ്കിൽ *ചെക്ക്‌പോയിന്റ്* എന്ന് വ്യക്തമാക്കും. + +ഉദാഹരണത്തിന്, BERT ഒരു ആർക്കിടെക്ചറാണ്, അതേസമയം BERT-ന്റെ ആദ്യ റിലീസിനായി Google ടീം പരിശീലിപ്പിച്ച വെയ്‌റ്റുകളുടെ ഒരു കൂട്ടമായ `bert-base-cased` ഒരു ചെക്ക്‌പോയിന്റാണ്. എന്നിരുന്നാലും, "BERT മോഡൽ" എന്നും "`bert-base-cased` മോഡൽ" എന്നും പറയാവുന്നതാണ്. diff --git a/chapters/ml/chapter1/5.mdx b/chapters/ml/chapter1/5.mdx new file mode 100644 index 000000000..dd8992503 --- /dev/null +++ b/chapters/ml/chapter1/5.mdx @@ -0,0 +1,235 @@ +# 🤗 Transformers എങ്ങനെ ടാസ്‌കുകൾ പരിഹരിക്കുന്നു + + + +[Transformers, അവയ്ക്ക് എന്തൊക്കെ ചെയ്യാൻ കഴിയും?](/course/chapter1/3) എന്ന ഭാഗത്തിൽ, നാച്ചുറൽ ലാംഗ്വേജ് പ്രോസസ്സിംഗ് (NLP), സ്പീച്ച് ആൻഡ് ഓഡിയോ, കമ്പ്യൂട്ടർ വിഷൻ ടാസ്‌കുകൾ എന്നിവയെക്കുറിച്ചും അവയുടെ ചില പ്രധാന പ്രയോഗങ്ങളെക്കുറിച്ചും നിങ്ങൾ പഠിച്ചു. മോഡലുകൾ ഈ ടാസ്‌കുകൾ എങ്ങനെ പരിഹരിക്കുന്നു എന്ന് ഈ പേജ് അടുത്തു നിന്ന് പരിശോധിക്കുകയും, ഉള്ളിൽ എന്താണ് സംഭവിക്കുന്നത് എന്ന് വിശദീകരിക്കുകയും ചെയ്യും. ഒരു ടാസ്‌ക് പരിഹരിക്കാൻ പല വഴികളുണ്ട്; ചില മോഡലുകൾ പ്രത്യേക ടെക്‌നിക്കുകൾ ഉപയോഗിക്കുകയോ പുതിയൊരു കോണിൽ നിന്ന് ടാസ്‌കിനെ സമീപിക്കുകയോ ചെയ്യാം. എന്നാൽ Transformer മോഡലുകളുടെ കാര്യത്തിൽ പൊതുവായ ആശയം ഒന്നുതന്നെയാണ്. അതിന്റെ വഴക്കമുള്ള ആർക്കിടെക്ചർ കാരണം, ഭൂരിഭാഗം മോഡലുകളും ഒരു എൻകോഡർ, ഒരു ഡീകോഡർ, അല്ലെങ്കിൽ എൻകോഡർ-ഡീകോഡർ ഘടനയുടെ ഏതെങ്കിലും ഒരു വകഭേദമാണ്. + +> [!TIP] +> പ്രത്യേക ആർക്കിടെക്ചർ വകഭേദങ്ങളിലേക്ക് കടക്കുന്നതിന് മുമ്പ്, മിക്ക ടാസ്‌കുകളും ഒരേ മാതൃക പിന്തുടരുന്നു എന്ന് മനസ്സിലാക്കുന്നത് സഹായകമാണ്: ഇൻപുട്ട് ഡേറ്റ ഒരു മോഡലിലൂടെ പ്രോസസ്സ് ചെയ്യപ്പെടുന്നു, ഔട്ട്‌പുട്ട് ഒരു പ്രത്യേക ടാസ്‌കിനായി വ്യാഖ്യാനിക്കപ്പെടുന്നു. വ്യത്യാസങ്ങൾ ഡേറ്റ എങ്ങനെ തയ്യാറാക്കുന്നു, ഏത് മോഡൽ ആർക്കിടെക്ചർ വകഭേദം ഉപയോഗിക്കുന്നു, ഔട്ട്‌പുട്ട് എങ്ങനെ പ്രോസസ്സ് ചെയ്യുന്നു എന്നിവയിലാണ്. + +ടാസ്‌കുകൾ എങ്ങനെ പരിഹരിക്കപ്പെടുന്നു എന്ന് വിശദീകരിക്കാൻ, ഉപയോഗപ്രദമായ പ്രവചനങ്ങൾ (predictions) പുറത്തുവിടാൻ മോഡലിനുള്ളിൽ എന്താണ് നടക്കുന്നത് എന്ന് നാം പരിശോധിക്കും. താഴെ പറയുന്ന മോഡലുകളും അവയുമായി ബന്ധപ്പെട്ട ടാസ്‌കുകളും നാം ചർച്ച ചെയ്യും: + +- ഓഡിയോ ക്ലാസിഫിക്കേഷനും ഓട്ടോമാറ്റിക് സ്പീച്ച് റെക്കഗ്നിഷനും (ASR) വേണ്ടി [Wav2Vec2](https://huggingface.co/docs/transformers/model_doc/wav2vec2) +- ഇമേജ് ക്ലാസിഫിക്കേഷനായി [Vision Transformer (ViT)](https://huggingface.co/docs/transformers/model_doc/vit), [ConvNeXT](https://huggingface.co/docs/transformers/model_doc/convnext) +- ഒബ്‌ജക്റ്റ് ഡിറ്റക്ഷനായി [DETR](https://huggingface.co/docs/transformers/model_doc/detr) +- ഇമേജ് സെഗ്‌മെന്റേഷനായി [Mask2Former](https://huggingface.co/docs/transformers/model_doc/mask2former) +- ഡെപ്ത് എസ്റ്റിമേഷനായി [GLPN](https://huggingface.co/docs/transformers/model_doc/glpn) +- എൻകോഡർ ഉപയോഗിക്കുന്ന ടെക്‌സ്‌റ്റ് ക്ലാസിഫിക്കേഷൻ, ടോക്കൺ ക്ലാസിഫിക്കേഷൻ, ക്വസ്‌ഷൻ ആൻസറിംഗ് പോലുള്ള NLP ടാസ്‌കുകൾക്കായി [BERT](https://huggingface.co/docs/transformers/model_doc/bert) +- ഡീകോഡർ ഉപയോഗിക്കുന്ന ടെക്‌സ്‌റ്റ് ജനറേഷൻ പോലുള്ള NLP ടാസ്‌കുകൾക്കായി [GPT2](https://huggingface.co/docs/transformers/model_doc/gpt2) +- എൻകോഡർ-ഡീകോഡർ ഉപയോഗിക്കുന്ന സമ്മറൈസേഷൻ, ട്രാൻസ്ലേഷൻ പോലുള്ള NLP ടാസ്‌കുകൾക്കായി [BART](https://huggingface.co/docs/transformers/model_doc/bart) + +> [!TIP] +> മുന്നോട്ട് പോകുന്നതിന് മുമ്പ്, യഥാർത്ഥ Transformer ആർക്കിടെക്ചറിനെക്കുറിച്ച് കുറച്ച് അടിസ്ഥാന അറിവ് ഉണ്ടായിരിക്കുന്നത് നല്ലതാണ്. എൻകോഡറുകൾ, ഡീകോഡറുകൾ, അറ്റൻഷൻ എന്നിവ എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് അറിയുന്നത്, വ്യത്യസ്ത Transformer മോഡലുകൾ എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് മനസ്സിലാക്കാൻ നിങ്ങളെ സഹായിക്കും. കൂടുതൽ വിവരങ്ങൾക്ക് ഞങ്ങളുടെ [മുൻ ഭാഗം](https://huggingface.co/course/chapter1/4?fw=pt) തീർച്ചയായും പരിശോധിക്കുക! + +## ഭാഷയ്ക്കുള്ള Transformer മോഡലുകൾ + +ആധുനിക NLP-യുടെ ഹൃദയമാണ് ലാംഗ്വേജ് മോഡലുകൾ. ടെക്‌സ്‌റ്റിലെ വാക്കുകൾക്കോ ടോക്കണുകൾക്കോ ഇടയിലുള്ള സ്ഥിതിവിവര മാതൃകകളും (statistical patterns) ബന്ധങ്ങളും പഠിച്ചെടുത്ത് മനുഷ്യഭാഷ മനസ്സിലാക്കാനും സൃഷ്ടിക്കാനുമാണ് അവ രൂപകൽപ്പന ചെയ്തിരിക്കുന്നത്. + +Transformer തുടക്കത്തിൽ മെഷീൻ ട്രാൻസ്ലേഷനായി രൂപകൽപ്പന ചെയ്തതാണ്; അതിനുശേഷം, എല്ലാ AI ടാസ്‌കുകളും പരിഹരിക്കാനുള്ള സ്ഥിരം ആർക്കിടെക്ചറായി അത് മാറി. ചില ടാസ്‌കുകൾ Transformer-ന്റെ എൻകോഡർ ഘടനയ്ക്ക് യോജിച്ചവയാണ്, മറ്റുള്ളവ ഡീകോഡറിന് കൂടുതൽ അനുയോജ്യമാണ്. ഇനിയും ചില ടാസ്‌കുകൾ Transformer-ന്റെ എൻകോഡർ-ഡീകോഡർ ഘടന മുഴുവനായി ഉപയോഗപ്പെടുത്തുന്നു. + +### ലാംഗ്വേജ് മോഡലുകൾ എങ്ങനെ പ്രവർത്തിക്കുന്നു + +ചുറ്റുമുള്ള വാക്കുകളുടെ സന്ദർഭം (context) നോക്കി ഒരു വാക്കിന്റെ സാധ്യത (probability) പ്രവചിക്കാൻ പരിശീലിപ്പിക്കപ്പെടുന്നതിലൂടെയാണ് ലാംഗ്വേജ് മോഡലുകൾ പ്രവർത്തിക്കുന്നത്. ഇത് അവയ്ക്ക് ഭാഷയെക്കുറിച്ച് ഒരു അടിസ്ഥാന ധാരണ നൽകുന്നു, അത് മറ്റ് ടാസ്‌കുകളിലേക്കും വ്യാപിപ്പിക്കാൻ (generalize) കഴിയും. + +ഒരു transformer മോഡൽ പരിശീലിപ്പിക്കാൻ രണ്ട് പ്രധാന സമീപനങ്ങളുണ്ട്: + +1. **മാസ്‌ക്ഡ് ലാംഗ്വേജ് മോഡലിംഗ് (MLM)**: BERT പോലുള്ള എൻകോഡർ മോഡലുകൾ ഉപയോഗിക്കുന്ന ഈ സമീപനം, ഇൻപുട്ടിലെ ചില ടോക്കണുകൾ ക്രമരഹിതമായി മറയ്ക്കുകയും (mask), ചുറ്റുമുള്ള സന്ദർഭത്തിന്റെ അടിസ്ഥാനത്തിൽ യഥാർത്ഥ ടോക്കണുകൾ പ്രവചിക്കാൻ മോഡലിനെ പരിശീലിപ്പിക്കുകയും ചെയ്യുന്നു. ഇത് മോഡലിന് ദ്വിദിശ സന്ദർഭം (bidirectional context) പഠിക്കാൻ അനുവദിക്കുന്നു (മറച്ച വാക്കിന് മുമ്പും പിമ്പുമുള്ള വാക്കുകൾ നോക്കുന്നു). + +2. **കോസൽ ലാംഗ്വേജ് മോഡലിംഗ് (CLM)**: GPT പോലുള്ള ഡീകോഡർ മോഡലുകൾ ഉപയോഗിക്കുന്ന ഈ സമീപനം, സീക്വൻസിലെ മുൻപുള്ള എല്ലാ ടോക്കണുകളുടെയും അടിസ്ഥാനത്തിൽ അടുത്ത ടോക്കൺ പ്രവചിക്കുന്നു. അടുത്ത ടോക്കൺ പ്രവചിക്കാൻ മോഡലിന് ഇടതുവശത്തുള്ള സന്ദർഭം (മുൻപുള്ള ടോക്കണുകൾ) മാത്രമേ ഉപയോഗിക്കാൻ കഴിയൂ. + +### ലാംഗ്വേജ് മോഡലുകളുടെ തരങ്ങൾ + +Transformers ലൈബ്രറിയിൽ, ലാംഗ്വേജ് മോഡലുകൾ പൊതുവെ മൂന്ന് ആർക്കിടെക്ചർ വിഭാഗങ്ങളിൽ പെടുന്നു: + +1. **എൻകോഡർ-ഒൺലി മോഡലുകൾ** (BERT പോലുള്ളവ): ഈ മോഡലുകൾ രണ്ട് ദിശകളിൽ നിന്നും സന്ദർഭം മനസ്സിലാക്കാൻ ഒരു ദ്വിദിശ സമീപനം ഉപയോഗിക്കുന്നു. ക്ലാസിഫിക്കേഷൻ, നെയിംഡ് എന്റിറ്റി റെക്കഗ്നിഷൻ, ക്വസ്‌ഷൻ ആൻസറിംഗ് പോലെ ടെക്‌സ്‌റ്റിനെക്കുറിച്ച് ആഴത്തിലുള്ള ധാരണ ആവശ്യമായ ടാസ്‌കുകൾക്ക് ഇവ ഏറ്റവും അനുയോജ്യമാണ്. + +2. **ഡീകോഡർ-ഒൺലി മോഡലുകൾ** (GPT, Llama പോലുള്ളവ): ഈ മോഡലുകൾ ടെക്‌സ്‌റ്റ് ഇടത്തുനിന്ന് വലത്തോട്ട് പ്രോസസ്സ് ചെയ്യുന്നു, ടെക്‌സ്‌റ്റ് ജനറേഷൻ ടാസ്‌കുകളിൽ ഇവ പ്രത്യേകിച്ച് മികച്ചതാണ്. ഒരു പ്രോംപ്‌റ്റിന്റെ അടിസ്ഥാനത്തിൽ ഇവയ്ക്ക് വാക്യങ്ങൾ പൂർത്തിയാക്കാനും ലേഖനങ്ങൾ എഴുതാനും കോഡ് വരെ സൃഷ്ടിക്കാനും കഴിയും. + +3. **എൻകോഡർ-ഡീകോഡർ മോഡലുകൾ** (T5, BART പോലുള്ളവ): ഈ മോഡലുകൾ രണ്ട് സമീപനങ്ങളും സംയോജിപ്പിക്കുന്നു — ഇൻപുട്ട് മനസ്സിലാക്കാൻ ഒരു എൻകോഡറും ഔട്ട്‌പുട്ട് സൃഷ്ടിക്കാൻ ഒരു ഡീകോഡറും ഉപയോഗിക്കുന്നു. ട്രാൻസ്ലേഷൻ, സമ്മറൈസേഷൻ, ക്വസ്‌ഷൻ ആൻസറിംഗ് പോലുള്ള സീക്വൻസ്-ടു-സീക്വൻസ് ടാസ്‌കുകളിൽ ഇവ മികവ് പുലർത്തുന്നു. + +![ഭാഷയ്ക്കുള്ള transformer മോഡലുകൾ](https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter1/transformers_architecture.png) + +മുൻ ഭാഗത്തിൽ നാം കണ്ടതുപോലെ, ലാംഗ്വേജ് മോഡലുകൾ സാധാരണയായി വലിയ അളവിലുള്ള ടെക്‌സ്‌റ്റ് ഡേറ്റയിൽ സെൽഫ്-സൂപ്പർവൈസ്ഡ് രീതിയിൽ (മനുഷ്യർ നൽകുന്ന അനോട്ടേഷനുകൾ ഇല്ലാതെ) പ്രീട്രെയിൻ ചെയ്യപ്പെടുകയും, പിന്നീട് പ്രത്യേക ടാസ്‌കുകളിൽ ഫൈൻ-ട്യൂൻ ചെയ്യപ്പെടുകയും ചെയ്യുന്നു. ട്രാൻസ്ഫർ ലേണിംഗ് (transfer learning) എന്നറിയപ്പെടുന്ന ഈ സമീപനം, താരതമ്യേന ചെറിയ അളവിലുള്ള ടാസ്‌ക്-നിർദ്ദിഷ്ട ഡേറ്റ ഉപയോഗിച്ച് പല വ്യത്യസ്ത NLP ടാസ്‌കുകളിലേക്കും പൊരുത്തപ്പെടാൻ ഈ മോഡലുകളെ അനുവദിക്കുന്നു. + +തുടർന്നുള്ള ഭാഗങ്ങളിൽ, പ്രത്യേക മോഡൽ ആർക്കിടെക്ചറുകളും അവ സ്പീച്ച്, വിഷൻ, ടെക്‌സ്‌റ്റ് മേഖലകളിലെ വിവിധ ടാസ്‌കുകളിൽ എങ്ങനെ പ്രയോഗിക്കപ്പെടുന്നു എന്നതും നാം പരിശോധിക്കും. + +> [!TIP] +> ഒരു പ്രത്യേക NLP ടാസ്‌കിന് Transformer ആർക്കിടെക്ചറിന്റെ ഏത് ഭാഗം (എൻകോഡർ, ഡീകോഡർ, അല്ലെങ്കിൽ രണ്ടും) ഏറ്റവും അനുയോജ്യമാണ് എന്ന് മനസ്സിലാക്കുന്നത് ശരിയായ മോഡൽ തിരഞ്ഞെടുക്കുന്നതിൽ നിർണായകമാണ്. പൊതുവെ, ദ്വിദിശ സന്ദർഭം ആവശ്യമായ ടാസ്‌കുകൾ എൻകോഡറുകൾ ഉപയോഗിക്കുന്നു, ടെക്‌സ്‌റ്റ് സൃഷ്ടിക്കുന്ന ടാസ്‌കുകൾ ഡീകോഡറുകൾ ഉപയോഗിക്കുന്നു, ഒരു സീക്വൻസിനെ മറ്റൊന്നിലേക്ക് മാറ്റുന്ന ടാസ്‌കുകൾ എൻകോഡർ-ഡീകോഡറുകൾ ഉപയോഗിക്കുന്നു. + +### ടെക്‌സ്‌റ്റ് ജനറേഷൻ + +ഒരു പ്രോംപ്‌റ്റിന്റെയോ ഇൻപുട്ടിന്റെയോ അടിസ്ഥാനത്തിൽ യുക്തിസഹവും സന്ദർഭത്തിന് അനുയോജ്യവുമായ ടെക്‌സ്‌റ്റ് സൃഷ്ടിക്കുന്നതാണ് ടെക്‌സ്‌റ്റ് ജനറേഷൻ. + +[GPT-2](https://huggingface.co/docs/transformers/model_doc/gpt2) വലിയ അളവിലുള്ള ടെക്‌സ്‌റ്റിൽ പ്രീട്രെയിൻ ചെയ്ത ഒരു ഡീകോഡർ-ഒൺലി മോഡലാണ്. ഒരു പ്രോംപ്‌റ്റ് നൽകിയാൽ അതിന് വിശ്വസനീയമായ (എപ്പോഴും സത്യമല്ലെങ്കിലും!) ടെക്‌സ്‌റ്റ് സൃഷ്ടിക്കാനും, പ്രത്യേകം പരിശീലിപ്പിച്ചിട്ടില്ലെങ്കിലും ക്വസ്‌ഷൻ ആൻസറിംഗ് പോലുള്ള മറ്റ് NLP ടാസ്‌കുകൾ പൂർത്തിയാക്കാനും കഴിയും. + +
+ +
+ +1. വാക്കുകൾ ടോക്കണൈസ് ചെയ്യാനും ഒരു ടോക്കൺ എംബെഡ്ഡിംഗ് സൃഷ്ടിക്കാനും GPT-2 [byte pair encoding (BPE)](https://huggingface.co/docs/transformers/tokenizer_summary#bytepair-encoding-bpe) ഉപയോഗിക്കുന്നു. സീക്വൻസിലെ ഓരോ ടോക്കണിന്റെയും സ്ഥാനം സൂചിപ്പിക്കാൻ ടോക്കൺ എംബെഡ്ഡിംഗുകളിലേക്ക് പൊസിഷണൽ എൻകോഡിംഗുകൾ (positional encodings) കൂട്ടിച്ചേർക്കുന്നു. ഇൻപുട്ട് എംബെഡ്ഡിംഗുകൾ ഒന്നിലധികം ഡീകോഡർ ബ്ലോക്കുകളിലൂടെ കടത്തിവിട്ട് ഒരു അന്തിമ ഹിഡൻ സ്റ്റേറ്റ് (final hidden state) ഔട്ട്‌പുട്ട് ചെയ്യുന്നു. ഓരോ ഡീകോഡർ ബ്ലോക്കിനുള്ളിലും GPT-2 ഒരു *മാസ്‌ക്ഡ് സെൽഫ്-അറ്റൻഷൻ* ലെയർ ഉപയോഗിക്കുന്നു, അതായത് GPT-2-ന് ഭാവിയിലെ ടോക്കണുകളിലേക്ക് ശ്രദ്ധ (attend) നൽകാൻ കഴിയില്ല. ഇടതുവശത്തുള്ള ടോക്കണുകളിലേക്ക് മാത്രമേ ശ്രദ്ധ നൽകാൻ അനുവാദമുള്ളൂ. ഇത് BERT-ന്റെ [`mask`] ടോക്കണിൽ നിന്ന് വ്യത്യസ്തമാണ്, കാരണം മാസ്‌ക്ഡ് സെൽഫ്-അറ്റൻഷനിൽ, ഭാവിയിലെ ടോക്കണുകളുടെ സ്‌കോർ `0` ആയി സെറ്റ് ചെയ്യാൻ ഒരു അറ്റൻഷൻ മാസ്‌ക് ഉപയോഗിക്കുന്നു. + +2. ഡീകോഡറിൽ നിന്നുള്ള ഔട്ട്‌പുട്ട് ഒരു ലാംഗ്വേജ് മോഡലിംഗ് ഹെഡിലേക്ക് (language modeling head) കൈമാറുന്നു, അത് ഹിഡൻ സ്റ്റേറ്റുകളെ ലോജിറ്റുകളാക്കി (logits) മാറ്റാൻ ഒരു ലീനിയർ ട്രാൻസ്ഫർമേഷൻ നടത്തുന്നു. സീക്വൻസിലെ അടുത്ത ടോക്കണാണ് ലേബൽ; ലോജിറ്റുകളെ ഒരു സ്ഥാനം വലത്തോട്ട് മാറ്റിയാണ് (shift) ഇവ സൃഷ്ടിക്കുന്നത്. അടുത്ത ഏറ്റവും സാധ്യതയുള്ള ടോക്കൺ ഔട്ട്‌പുട്ട് ചെയ്യാൻ, മാറ്റിയ ലോജിറ്റുകൾക്കും ലേബലുകൾക്കും ഇടയിൽ ക്രോസ്-എൻട്രോപ്പി ലോസ് (cross-entropy loss) കണക്കാക്കുന്നു. + +GPT-2-ന്റെ പ്രീട്രെയിനിംഗ് ലക്ഷ്യം പൂർണ്ണമായും [കോസൽ ലാംഗ്വേജ് മോഡലിംഗ്](https://huggingface.co/docs/transformers/glossary#causal-language-modeling) അടിസ്ഥാനമാക്കിയുള്ളതാണ് — ഒരു സീക്വൻസിലെ അടുത്ത വാക്ക് പ്രവചിക്കുക. ഇത് ടെക്‌സ്‌റ്റ് സൃഷ്ടിക്കുന്ന ടാസ്‌കുകളിൽ GPT-2-നെ പ്രത്യേകിച്ച് മികച്ചതാക്കുന്നു. + +ടെക്‌സ്‌റ്റ് ജനറേഷൻ സ്വയം പരീക്ഷിക്കാൻ തയ്യാറാണോ? DistilGPT-2 എങ്ങനെ ഫൈൻ-ട്യൂൻ ചെയ്യാമെന്നും ഇൻഫറൻസിനായി ഉപയോഗിക്കാമെന്നും പഠിക്കാൻ ഞങ്ങളുടെ പൂർണ്ണമായ [കോസൽ ലാംഗ്വേജ് മോഡലിംഗ് ഗൈഡ്](https://huggingface.co/docs/transformers/tasks/language_modeling#causal-language-modeling) പരിശോധിക്കുക! + +> [!TIP] +> ടെക്‌സ്‌റ്റ് ജനറേഷനെക്കുറിച്ച് കൂടുതൽ വിവരങ്ങൾക്ക്, [ടെക്‌സ്‌റ്റ് ജനറേഷൻ സ്ട്രാറ്റജികൾ](https://huggingface.co/docs/transformers/generation_strategies#generation-strategies) എന്ന ഗൈഡ് പരിശോധിക്കുക! + +### ടെക്‌സ്‌റ്റ് ക്ലാസിഫിക്കേഷൻ + +സെന്റിമെന്റ് അനാലിസിസ്, ടോപ്പിക് ക്ലാസിഫിക്കേഷൻ, സ്പാം ഡിറ്റക്ഷൻ എന്നിവ പോലെ, ടെക്‌സ്‌റ്റ് ഡോക്യുമെന്റുകൾക്ക് മുൻകൂട്ടി നിശ്ചയിച്ച വിഭാഗങ്ങൾ നൽകുന്നതാണ് ടെക്‌സ്‌റ്റ് ക്ലാസിഫിക്കേഷൻ. + +[BERT](https://huggingface.co/docs/transformers/model_doc/bert) ഒരു എൻകോഡർ-ഒൺലി മോഡലാണ്; വാക്കുകളുടെ ഇരുവശത്തുമുള്ള വാക്കുകളിലേക്ക് ശ്രദ്ധ നൽകി ടെക്‌സ്‌റ്റിന്റെ കൂടുതൽ സമ്പന്നമായ പ്രതിനിധാനങ്ങൾ (representations) പഠിക്കാൻ ആഴത്തിലുള്ള ദ്വിദിശാത്വം (deep bidirectionality) ഫലപ്രദമായി നടപ്പിലാക്കിയ ആദ്യ മോഡലാണിത്. + +1. ടെക്‌സ്‌റ്റിന്റെ ഒരു ടോക്കൺ എംബെഡ്ഡിംഗ് സൃഷ്ടിക്കാൻ BERT [WordPiece](https://huggingface.co/docs/transformers/tokenizer_summary#wordpiece) ടോക്കണൈസേഷൻ ഉപയോഗിക്കുന്നു. ഒരൊറ്റ വാക്യവും ഒരു ജോടി വാക്യങ്ങളും തമ്മിലുള്ള വ്യത്യാസം തിരിച്ചറിയാൻ, അവയെ വേർതിരിക്കുന്ന ഒരു പ്രത്യേക `[SEP]` ടോക്കൺ ചേർക്കുന്നു. ഓരോ ടെക്‌സ്‌റ്റ് സീക്വൻസിന്റെയും തുടക്കത്തിൽ ഒരു പ്രത്യേക `[CLS]` ടോക്കൺ ചേർക്കുന്നു. `[CLS]` ടോക്കണിനൊപ്പമുള്ള അന്തിമ ഔട്ട്‌പുട്ട്, ക്ലാസിഫിക്കേഷൻ ടാസ്‌കുകൾക്കായി ക്ലാസിഫിക്കേഷൻ ഹെഡിലേക്കുള്ള ഇൻപുട്ടായി ഉപയോഗിക്കുന്നു. ഒരു ജോടി വാക്യങ്ങളിൽ ഒരു ടോക്കൺ ആദ്യത്തെ വാക്യത്തിലാണോ രണ്ടാമത്തേതിലാണോ എന്ന് സൂചിപ്പിക്കാൻ BERT ഒരു സെഗ്‌മെന്റ് എംബെഡ്ഡിംഗും ചേർക്കുന്നു. + +2. BERT രണ്ട് ലക്ഷ്യങ്ങളോടെ പ്രീട്രെയിൻ ചെയ്യപ്പെടുന്നു: മാസ്‌ക്ഡ് ലാംഗ്വേജ് മോഡലിംഗും നെക്‌സ്‌റ്റ്-സെന്റൻസ് പ്രെഡിക്ഷനും. മാസ്‌ക്ഡ് ലാംഗ്വേജ് മോഡലിംഗിൽ, ഇൻപുട്ട് ടോക്കണുകളുടെ ഒരു നിശ്ചിത ശതമാനം ക്രമരഹിതമായി മറയ്ക്കുന്നു, മോഡൽ അവ പ്രവചിക്കണം. മോഡൽ എല്ലാ വാക്കുകളും കണ്ടിട്ട് അടുത്ത വാക്ക് "പ്രവചിച്ച്" കബളിപ്പിക്കാൻ കഴിയുന്ന ദ്വിദിശാത്വത്തിന്റെ പ്രശ്നം ഇത് പരിഹരിക്കുന്നു. പ്രവചിച്ച മാസ്‌ക് ടോക്കണുകളുടെ അന്തിമ ഹിഡൻ സ്റ്റേറ്റുകൾ, മറച്ച വാക്ക് പ്രവചിക്കാൻ വൊക്കാബുലറിക്ക് മേൽ ഒരു softmax ഉള്ള ഒരു ഫീഡ്‌ഫോർവേഡ് നെറ്റ്‌വർക്കിലേക്ക് കൈമാറുന്നു. + + രണ്ടാമത്തെ പ്രീട്രെയിനിംഗ് ലക്ഷ്യം നെക്‌സ്‌റ്റ്-സെന്റൻസ് പ്രെഡിക്ഷനാണ്. വാക്യം A-യെ തുടർന്ന് വാക്യം B വരുന്നുണ്ടോ എന്ന് മോഡൽ പ്രവചിക്കണം. പകുതി സമയവും വാക്യം B അടുത്ത വാക്യമായിരിക്കും, ബാക്കി പകുതി സമയം വാക്യം B ഒരു ക്രമരഹിത വാക്യമായിരിക്കും. അടുത്ത വാക്യമാണോ അല്ലയോ എന്ന പ്രവചനം, രണ്ട് ക്ലാസുകൾക്ക് (`IsNext`, `NotNext`) മേൽ ഒരു softmax ഉള്ള ഒരു ഫീഡ്‌ഫോർവേഡ് നെറ്റ്‌വർക്കിലേക്ക് കൈമാറുന്നു. + +3. ഇൻപുട്ട് എംബെഡ്ഡിംഗുകൾ ഒന്നിലധികം എൻകോഡർ ലെയറുകളിലൂടെ കടത്തിവിട്ട് അന്തിമ ഹിഡൻ സ്റ്റേറ്റുകൾ ഔട്ട്‌പുട്ട് ചെയ്യുന്നു. + +പ്രീട്രെയിൻ ചെയ്ത മോഡൽ ടെക്‌സ്‌റ്റ് ക്ലാസിഫിക്കേഷനായി ഉപയോഗിക്കാൻ, അടിസ്ഥാന BERT മോഡലിന് മുകളിൽ ഒരു സീക്വൻസ് ക്ലാസിഫിക്കേഷൻ ഹെഡ് ചേർക്കുക. സീക്വൻസ് ക്ലാസിഫിക്കേഷൻ ഹെഡ് എന്നത് അന്തിമ ഹിഡൻ സ്റ്റേറ്റുകൾ സ്വീകരിച്ച് അവയെ ലോജിറ്റുകളാക്കി മാറ്റാൻ ഒരു ലീനിയർ ട്രാൻസ്ഫർമേഷൻ നടത്തുന്ന ഒരു ലീനിയർ ലെയറാണ്. ഏറ്റവും സാധ്യതയുള്ള ലേബൽ കണ്ടെത്താൻ ലോജിറ്റുകൾക്കും ടാർഗെറ്റിനും ഇടയിൽ ക്രോസ്-എൻട്രോപ്പി ലോസ് കണക്കാക്കുന്നു. + +ടെക്‌സ്‌റ്റ് ക്ലാസിഫിക്കേഷൻ സ്വയം പരീക്ഷിക്കാൻ തയ്യാറാണോ? DistilBERT എങ്ങനെ ഫൈൻ-ട്യൂൻ ചെയ്യാമെന്നും ഇൻഫറൻസിനായി ഉപയോഗിക്കാമെന്നും പഠിക്കാൻ ഞങ്ങളുടെ പൂർണ്ണമായ [ടെക്‌സ്‌റ്റ് ക്ലാസിഫിക്കേഷൻ ഗൈഡ്](https://huggingface.co/docs/transformers/tasks/sequence_classification) പരിശോധിക്കുക! + +### ടോക്കൺ ക്ലാസിഫിക്കേഷൻ + +നെയിംഡ് എന്റിറ്റി റെക്കഗ്നിഷനിലോ പാർട്ട്-ഓഫ്-സ്പീച്ച് ടാഗിംഗിലോ ഉള്ളതുപോലെ, ഒരു സീക്വൻസിലെ ഓരോ ടോക്കണിനും ഒരു ലേബൽ നൽകുന്നതാണ് ടോക്കൺ ക്ലാസിഫിക്കേഷൻ. + +നെയിംഡ് എന്റിറ്റി റെക്കഗ്നിഷൻ (NER) പോലുള്ള ടോക്കൺ ക്ലാസിഫിക്കേഷൻ ടാസ്‌കുകൾക്ക് BERT ഉപയോഗിക്കാൻ, അടിസ്ഥാന BERT മോഡലിന് മുകളിൽ ഒരു ടോക്കൺ ക്ലാസിഫിക്കേഷൻ ഹെഡ് ചേർക്കുക. ടോക്കൺ ക്ലാസിഫിക്കേഷൻ ഹെഡ് എന്നത് അന്തിമ ഹിഡൻ സ്റ്റേറ്റുകൾ സ്വീകരിച്ച് അവയെ ലോജിറ്റുകളാക്കി മാറ്റാൻ ഒരു ലീനിയർ ട്രാൻസ്ഫർമേഷൻ നടത്തുന്ന ഒരു ലീനിയർ ലെയറാണ്. ഏറ്റവും സാധ്യതയുള്ള ലേബൽ കണ്ടെത്താൻ ലോജിറ്റുകൾക്കും ഓരോ ടോക്കണിനും ഇടയിൽ ക്രോസ്-എൻട്രോപ്പി ലോസ് കണക്കാക്കുന്നു. + +ടോക്കൺ ക്ലാസിഫിക്കേഷൻ സ്വയം പരീക്ഷിക്കാൻ തയ്യാറാണോ? DistilBERT എങ്ങനെ ഫൈൻ-ട്യൂൻ ചെയ്യാമെന്നും ഇൻഫറൻസിനായി ഉപയോഗിക്കാമെന്നും പഠിക്കാൻ ഞങ്ങളുടെ പൂർണ്ണമായ [ടോക്കൺ ക്ലാസിഫിക്കേഷൻ ഗൈഡ്](https://huggingface.co/docs/transformers/tasks/token_classification) പരിശോധിക്കുക! + +### ക്വസ്‌ഷൻ ആൻസറിംഗ് + +നൽകിയ ഒരു സന്ദർഭത്തിലോ ഖണ്ഡികയിലോ നിന്ന് ഒരു ചോദ്യത്തിന്റെ ഉത്തരം കണ്ടെത്തുന്നതാണ് ക്വസ്‌ഷൻ ആൻസറിംഗ്. + +ക്വസ്‌ഷൻ ആൻസറിംഗിനായി BERT ഉപയോഗിക്കാൻ, അടിസ്ഥാന BERT മോഡലിന് മുകളിൽ ഒരു സ്പാൻ ക്ലാസിഫിക്കേഷൻ ഹെഡ് ചേർക്കുക. ഈ ലീനിയർ ലെയർ അന്തിമ ഹിഡൻ സ്റ്റേറ്റുകൾ സ്വീകരിച്ച്, ഉത്തരത്തിന് അനുയോജ്യമായ `span`-ന്റെ തുടക്കത്തിന്റെയും അവസാനത്തിന്റെയും ലോജിറ്റുകൾ കണക്കാക്കാൻ ഒരു ലീനിയർ ട്രാൻസ്ഫർമേഷൻ നടത്തുന്നു. ഉത്തരത്തിന് അനുയോജ്യമായ, ഏറ്റവും സാധ്യതയുള്ള ടെക്‌സ്‌റ്റ് സ്പാൻ കണ്ടെത്താൻ ലോജിറ്റുകൾക്കും ലേബൽ പൊസിഷനും ഇടയിൽ ക്രോസ്-എൻട്രോപ്പി ലോസ് കണക്കാക്കുന്നു. + +ക്വസ്‌ഷൻ ആൻസറിംഗ് സ്വയം പരീക്ഷിക്കാൻ തയ്യാറാണോ? DistilBERT എങ്ങനെ ഫൈൻ-ട്യൂൻ ചെയ്യാമെന്നും ഇൻഫറൻസിനായി ഉപയോഗിക്കാമെന്നും പഠിക്കാൻ ഞങ്ങളുടെ പൂർണ്ണമായ [ക്വസ്‌ഷൻ ആൻസറിംഗ് ഗൈഡ്](https://huggingface.co/docs/transformers/tasks/question_answering) പരിശോധിക്കുക! + +> [!TIP] +> 💡 ഒരിക്കൽ പ്രീട്രെയിൻ ചെയ്തുകഴിഞ്ഞാൽ, വ്യത്യസ്ത ടാസ്‌കുകൾക്ക് BERT ഉപയോഗിക്കുന്നത് എത്ര എളുപ്പമാണെന്ന് ശ്രദ്ധിക്കുക. ഹിഡൻ സ്റ്റേറ്റുകളെ നിങ്ങൾക്ക് ആവശ്യമുള്ള ഔട്ട്‌പുട്ടിലേക്ക് മാറ്റാൻ പ്രീട്രെയിൻ ചെയ്ത മോഡലിലേക്ക് ഒരു പ്രത്യേക ഹെഡ് ചേർത്താൽ മാത്രം മതി! + +### സമ്മറൈസേഷൻ + +ഒരു നീണ്ട ടെക്‌സ്‌റ്റിന്റെ പ്രധാന വിവരങ്ങളും അർത്ഥവും നിലനിർത്തിക്കൊണ്ട് അതിനെ ചെറിയൊരു രൂപത്തിലേക്ക് ചുരുക്കുന്നതാണ് സമ്മറൈസേഷൻ. + +[BART](https://huggingface.co/docs/transformers/model_doc/bart), [T5](model_doc/t5) പോലുള്ള എൻകോഡർ-ഡീകോഡർ മോഡലുകൾ ഒരു സമ്മറൈസേഷൻ ടാസ്‌കിന്റെ സീക്വൻസ്-ടു-സീക്വൻസ് മാതൃകയ്ക്കായി രൂപകൽപ്പന ചെയ്തവയാണ്. ഈ ഭാഗത്തിൽ BART എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് നാം വിശദീകരിക്കും, തുടർന്ന് അവസാനം T5 ഫൈൻ-ട്യൂൻ ചെയ്യാൻ നിങ്ങൾക്ക് ശ്രമിക്കാം. + +
+ +
+ +1. BART-ന്റെ എൻകോഡർ ആർക്കിടെക്ചർ BERT-നോട് വളരെ സാമ്യമുള്ളതാണ്; അത് ടെക്‌സ്‌റ്റിന്റെ ഒരു ടോക്കൺ എംബെഡ്ഡിംഗും പൊസിഷണൽ എംബെഡ്ഡിംഗും സ്വീകരിക്കുന്നു. ഇൻപുട്ടിനെ വികലമാക്കി (corrupt) പിന്നീട് ഡീകോഡർ ഉപയോഗിച്ച് അത് പുനർനിർമ്മിച്ചാണ് BART പ്രീട്രെയിൻ ചെയ്യുന്നത്. പ്രത്യേക വികലമാക്കൽ തന്ത്രങ്ങളുള്ള മറ്റ് എൻകോഡറുകളിൽ നിന്ന് വ്യത്യസ്തമായി, BART-ന് ഏത് തരത്തിലുള്ള വികലമാക്കലും പ്രയോഗിക്കാൻ കഴിയും. എന്നിരുന്നാലും *ടെക്‌സ്‌റ്റ് ഇൻഫില്ലിംഗ്* (text infilling) എന്ന തന്ത്രമാണ് ഏറ്റവും നന്നായി പ്രവർത്തിക്കുന്നത്. ടെക്‌സ്‌റ്റ് ഇൻഫില്ലിംഗിൽ, നിരവധി ടെക്‌സ്‌റ്റ് സ്പാനുകൾ **ഒരൊറ്റ** [`mask`] ടോക്കൺ കൊണ്ട് മാറ്റിസ്ഥാപിക്കുന്നു. ഇത് പ്രധാനമാണ്, കാരണം മോഡലിന് മറച്ച ടോക്കണുകൾ പ്രവചിക്കേണ്ടതുണ്ട്; കൂടാതെ എത്ര ടോക്കണുകൾ നഷ്ടപ്പെട്ടിട്ടുണ്ട് എന്ന് പ്രവചിക്കാനും ഇത് മോഡലിനെ പഠിപ്പിക്കുന്നു. ഇൻപുട്ട് എംബെഡ്ഡിംഗുകളും മറച്ച സ്പാനുകളും എൻകോഡറിലൂടെ കടത്തിവിട്ട് അന്തിമ ഹിഡൻ സ്റ്റേറ്റുകൾ ഔട്ട്‌പുട്ട് ചെയ്യുന്നു; എന്നാൽ BERT-ൽ നിന്ന് വ്യത്യസ്തമായി, ഒരു വാക്ക് പ്രവചിക്കാൻ BART അവസാനം ഒരു ഫീഡ്‌ഫോർവേഡ് നെറ്റ്‌വർക്ക് ചേർക്കുന്നില്ല. + +2. എൻകോഡറിന്റെ ഔട്ട്‌പുട്ട് ഡീകോഡറിലേക്ക് കൈമാറുന്നു; എൻകോഡറിന്റെ ഔട്ട്‌പുട്ടിൽ നിന്ന് മറച്ച ടോക്കണുകളും വികലമാക്കാത്ത ഏതെങ്കിലും ടോക്കണുകളും ഡീകോഡർ പ്രവചിക്കണം. യഥാർത്ഥ ടെക്‌സ്‌റ്റ് പുനഃസ്ഥാപിക്കാൻ ഡീകോഡറിനെ സഹായിക്കുന്ന അധിക സന്ദർഭം ഇത് നൽകുന്നു. ഡീകോഡറിൽ നിന്നുള്ള ഔട്ട്‌പുട്ട് ഒരു ലാംഗ്വേജ് മോഡലിംഗ് ഹെഡിലേക്ക് കൈമാറുന്നു, അത് ഹിഡൻ സ്റ്റേറ്റുകളെ ലോജിറ്റുകളാക്കി മാറ്റാൻ ഒരു ലീനിയർ ട്രാൻസ്ഫർമേഷൻ നടത്തുന്നു. ലോജിറ്റുകൾക്കും ലേബലിനും ഇടയിൽ ക്രോസ്-എൻട്രോപ്പി ലോസ് കണക്കാക്കുന്നു; ലേബൽ എന്നത് വലത്തോട്ട് ഒരു സ്ഥാനം മാറ്റിയ ടോക്കൺ മാത്രമാണ്. + +സമ്മറൈസേഷൻ സ്വയം പരീക്ഷിക്കാൻ തയ്യാറാണോ? T5 എങ്ങനെ ഫൈൻ-ട്യൂൻ ചെയ്യാമെന്നും ഇൻഫറൻസിനായി ഉപയോഗിക്കാമെന്നും പഠിക്കാൻ ഞങ്ങളുടെ പൂർണ്ണമായ [സമ്മറൈസേഷൻ ഗൈഡ്](https://huggingface.co/docs/transformers/tasks/summarization) പരിശോധിക്കുക! + +> [!TIP] +> ടെക്‌സ്‌റ്റ് ജനറേഷനെക്കുറിച്ച് കൂടുതൽ വിവരങ്ങൾക്ക്, [ടെക്‌സ്‌റ്റ് ജനറേഷൻ സ്ട്രാറ്റജികൾ](https://huggingface.co/docs/transformers/generation_strategies) എന്ന ഗൈഡ് പരിശോധിക്കുക! + +### ട്രാൻസ്ലേഷൻ + +അർത്ഥം നിലനിർത്തിക്കൊണ്ട് ടെക്‌സ്‌റ്റ് ഒരു ഭാഷയിൽ നിന്ന് മറ്റൊന്നിലേക്ക് മാറ്റുന്നതാണ് ട്രാൻസ്ലേഷൻ. സീക്വൻസ്-ടു-സീക്വൻസ് ടാസ്‌കിന്റെ മറ്റൊരു ഉദാഹരണമാണ് ട്രാൻസ്ലേഷൻ, അതായത് ഇത് ചെയ്യാൻ [BART](https://huggingface.co/docs/transformers/model_doc/bart) അല്ലെങ്കിൽ [T5](model_doc/t5) പോലുള്ള ഒരു എൻകോഡർ-ഡീകോഡർ മോഡൽ നിങ്ങൾക്ക് ഉപയോഗിക്കാം. ഈ ഭാഗത്തിൽ BART എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് നാം വിശദീകരിക്കും, തുടർന്ന് അവസാനം T5 ഫൈൻ-ട്യൂൻ ചെയ്യാൻ നിങ്ങൾക്ക് ശ്രമിക്കാം. + +ഒരു സോഴ്‌സ് ഭാഷയെ, ടാർഗെറ്റ് ഭാഷയിലേക്ക് ഡീകോഡ് ചെയ്യാവുന്ന ഒരു ഇൻപുട്ടിലേക്ക് മാപ്പ് ചെയ്യുന്നതിനായി, ക്രമരഹിതമായി ഇനിഷ്യലൈസ് ചെയ്ത ഒരു പ്രത്യേക എൻകോഡർ കൂട്ടിച്ചേർത്താണ് BART ട്രാൻസ്ലേഷനിലേക്ക് പൊരുത്തപ്പെടുന്നത്. ഈ പുതിയ എൻകോഡറിന്റെ എംബെഡ്ഡിംഗുകൾ, യഥാർത്ഥ വേഡ് എംബെഡ്ഡിംഗുകൾക്ക് പകരം പ്രീട്രെയിൻ ചെയ്ത എൻകോഡറിലേക്ക് കൈമാറുന്നു. മോഡൽ ഔട്ട്‌പുട്ടിൽ നിന്നുള്ള ക്രോസ്-എൻട്രോപ്പി ലോസ് ഉപയോഗിച്ച് സോഴ്‌സ് എൻകോഡർ, പൊസിഷണൽ എംബെഡ്ഡിംഗുകൾ, ഇൻപുട്ട് എംബെഡ്ഡിംഗുകൾ എന്നിവ അപ്‌ഡേറ്റ് ചെയ്താണ് സോഴ്‌സ് എൻകോഡർ പരിശീലിപ്പിക്കുന്നത്. ഈ ആദ്യ ഘട്ടത്തിൽ മോഡൽ പാരാമീറ്ററുകൾ ഫ്രീസ് ചെയ്തിരിക്കും, രണ്ടാം ഘട്ടത്തിൽ എല്ലാ മോഡൽ പാരാമീറ്ററുകളും ഒരുമിച്ച് പരിശീലിപ്പിക്കുന്നു. +പിന്നീട് BART-ന് പിന്നാലെ mBART എന്ന ഒരു ബഹുഭാഷാ പതിപ്പ് വന്നു; ട്രാൻസ്ലേഷനായി ഉദ്ദേശിച്ചുള്ളതും വ്യത്യസ്തങ്ങളായ പല ഭാഷകളിൽ പ്രീട്രെയിൻ ചെയ്തതുമാണ് അത്. + +ട്രാൻസ്ലേഷൻ സ്വയം പരീക്ഷിക്കാൻ തയ്യാറാണോ? T5 എങ്ങനെ ഫൈൻ-ട്യൂൻ ചെയ്യാമെന്നും ഇൻഫറൻസിനായി ഉപയോഗിക്കാമെന്നും പഠിക്കാൻ ഞങ്ങളുടെ പൂർണ്ണമായ [ട്രാൻസ്ലേഷൻ ഗൈഡ്](https://huggingface.co/docs/transformers/tasks/translation) പരിശോധിക്കുക! + +> [!TIP] +> ഈ ഗൈഡിലുടനീളം നിങ്ങൾ കണ്ടതുപോലെ, വ്യത്യസ്ത ടാസ്‌കുകളെ അഭിസംബോധന ചെയ്യുന്നുണ്ടെങ്കിലും പല മോഡലുകളും സമാനമായ മാതൃകകൾ പിന്തുടരുന്നു. ഈ പൊതു മാതൃകകൾ മനസ്സിലാക്കുന്നത്, പുതിയ മോഡലുകൾ എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്നും നിലവിലുള്ള മോഡലുകളെ നിങ്ങളുടെ പ്രത്യേക ആവശ്യങ്ങൾക്ക് എങ്ങനെ പൊരുത്തപ്പെടുത്താം എന്നും വേഗത്തിൽ ഗ്രഹിക്കാൻ നിങ്ങളെ സഹായിക്കും. + +## ടെക്‌സ്‌റ്റിനപ്പുറമുള്ള മോഡാലിറ്റികൾ + +Transformers ടെക്‌സ്‌റ്റിൽ മാത്രം ഒതുങ്ങുന്നില്ല. സ്പീച്ച് ആൻഡ് ഓഡിയോ, ഇമേജുകൾ, വീഡിയോ പോലുള്ള മറ്റ് മോഡാലിറ്റികളിലും അവ പ്രയോഗിക്കാൻ കഴിയും. തീർച്ചയായും, ഈ കോഴ്‌സിൽ നാം ടെക്‌സ്‌റ്റിലാണ് ശ്രദ്ധ കേന്ദ്രീകരിക്കുന്നത്, എന്നാൽ മറ്റ് മോഡാലിറ്റികളെ ചുരുക്കമായി പരിചയപ്പെടുത്താം. + +### സ്പീച്ച് ആൻഡ് ഓഡിയോ + +ടെക്‌സ്‌റ്റിനെയോ ഇമേജുകളെയോ അപേക്ഷിച്ച് സവിശേഷമായ വെല്ലുവിളികൾ ഉയർത്തുന്ന സ്പീച്ച്, ഓഡിയോ ഡേറ്റ Transformer മോഡലുകൾ എങ്ങനെ കൈകാര്യം ചെയ്യുന്നു എന്ന് പരിശോധിച്ചുകൊണ്ട് തുടങ്ങാം. + +[Whisper](https://huggingface.co/docs/transformers/main/en/model_doc/whisper) 680,000 മണിക്കൂർ ലേബൽ ചെയ്ത ഓഡിയോ ഡേറ്റയിൽ പ്രീട്രെയിൻ ചെയ്ത ഒരു എൻകോഡർ-ഡീകോഡർ (സീക്വൻസ്-ടു-സീക്വൻസ്) transformer ആണ്. ഈ അളവിലുള്ള പ്രീട്രെയിനിംഗ് ഡേറ്റ, ഇംഗ്ലീഷിലും മറ്റ് പല ഭാഷകളിലുമുള്ള ഓഡിയോ ടാസ്‌കുകളിൽ സീറോ-ഷോട്ട് (zero-shot) പ്രകടനം സാധ്യമാക്കുന്നു. എൻകോഡർ പഠിച്ചെടുത്ത സ്പീച്ച് പ്രതിനിധാനങ്ങളെ, അധിക ഫൈൻ-ട്യൂണിംഗ് ഇല്ലാതെ തന്നെ ടെക്‌സ്‌റ്റ് പോലുള്ള ഉപയോഗപ്രദമായ ഔട്ട്‌പുട്ടുകളിലേക്ക് മാപ്പ് ചെയ്യാൻ ഡീകോഡർ Whisper-നെ അനുവദിക്കുന്നു. Whisper നേരിട്ട് അതേപടി പ്രവർത്തിക്കുന്നു. + +
+ +
+ +ഈ ഡയഗ്രം [Whisper പേപ്പറിൽ](https://huggingface.co/papers/2212.04356) നിന്നുള്ളതാണ്. + +ഈ മോഡലിന് രണ്ട് പ്രധാന ഘടകങ്ങളുണ്ട്: + +1. ഒരു **എൻകോഡർ** ഇൻപുട്ട് ഓഡിയോ പ്രോസസ്സ് ചെയ്യുന്നു. റോ ഓഡിയോ ആദ്യം ഒരു log-Mel സ്പെക്ട്രോഗ്രാമിലേക്ക് മാറ്റുന്നു. ഈ സ്പെക്ട്രോഗ്രാം പിന്നീട് ഒരു Transformer എൻകോഡർ നെറ്റ്‌വർക്കിലൂടെ കടത്തിവിടുന്നു. + +2. ഒരു **ഡീകോഡർ** എൻകോഡ് ചെയ്ത ഓഡിയോ പ്രതിനിധാനം സ്വീകരിച്ച്, അതിന് അനുയോജ്യമായ ടെക്‌സ്‌റ്റ് ടോക്കണുകൾ ഓട്ടോറിഗ്രസ്സീവായി (autoregressively) പ്രവചിക്കുന്നു. മുൻപുള്ള ടോക്കണുകളും എൻകോഡർ ഔട്ട്‌പുട്ടും നൽകിയാൽ അടുത്ത ടെക്‌സ്‌റ്റ് ടോക്കൺ പ്രവചിക്കാൻ പരിശീലിപ്പിച്ച ഒരു സ്റ്റാൻഡേർഡ് Transformer ഡീകോഡറാണിത്. ട്രാൻസ്ക്രിപ്ഷൻ, ട്രാൻസ്ലേഷൻ, ഭാഷ തിരിച്ചറിയൽ പോലുള്ള പ്രത്യേക ടാസ്‌കുകളിലേക്ക് മോഡലിനെ നയിക്കാൻ ഡീകോഡർ ഇൻപുട്ടിന്റെ തുടക്കത്തിൽ പ്രത്യേക ടോക്കണുകൾ ഉപയോഗിക്കുന്നു. + +വെബിൽ നിന്ന് ശേഖരിച്ച 680,000 മണിക്കൂർ ലേബൽ ചെയ്ത ഓഡിയോ ഡേറ്റ അടങ്ങിയ ഒരു ബൃഹത്തും വൈവിധ്യപൂർണ്ണവുമായ ഡേറ്റാസെറ്റിലാണ് Whisper പ്രീട്രെയിൻ ചെയ്തത്. വലിയ തോതിലുള്ള, ദുർബലമായി മേൽനോട്ടം വഹിക്കപ്പെട്ട (weakly supervised) ഈ പ്രീട്രെയിനിംഗാണ് പല ഭാഷകളിലും ടാസ്‌കുകളിലുമുള്ള അതിന്റെ ശക്തമായ സീറോ-ഷോട്ട് പ്രകടനത്തിന്റെ താക്കോൽ. + +ഇപ്പോൾ Whisper പ്രീട്രെയിൻ ചെയ്തിരിക്കുന്നതിനാൽ, സീറോ-ഷോട്ട് ഇൻഫറൻസിനായി നിങ്ങൾക്ക് അത് നേരിട്ട് ഉപയോഗിക്കാം, അല്ലെങ്കിൽ ഓട്ടോമാറ്റിക് സ്പീച്ച് റെക്കഗ്നിഷൻ അഥവാ സ്പീച്ച് ട്രാൻസ്ലേഷൻ പോലുള്ള പ്രത്യേക ടാസ്‌കുകളിൽ മെച്ചപ്പെട്ട പ്രകടനത്തിനായി നിങ്ങളുടെ ഡേറ്റയിൽ അത് ഫൈൻ-ട്യൂൻ ചെയ്യാം! + +> [!TIP] +> Whisper-ന്റെ പ്രധാന നവീകരണം, ഇന്റർനെറ്റിൽ നിന്നുള്ള വൈവിധ്യപൂർണ്ണവും ദുർബലമായി മേൽനോട്ടം വഹിക്കപ്പെട്ടതുമായ ഓഡിയോ ഡേറ്റയിൽ മുമ്പെങ്ങുമില്ലാത്ത തോതിൽ നടത്തിയ പരിശീലനമാണ്. ടാസ്‌ക്-നിർദ്ദിഷ്ട ഫൈൻ-ട്യൂണിംഗ് ഇല്ലാതെ തന്നെ വ്യത്യസ്ത ഭാഷകളിലേക്കും ഉച്ചാരണരീതികളിലേക്കും ടാസ്‌കുകളിലേക്കും ശ്രദ്ധേയമായ രീതിയിൽ വ്യാപിക്കാൻ ഇത് അതിനെ അനുവദിക്കുന്നു. + +### ഓട്ടോമാറ്റിക് സ്പീച്ച് റെക്കഗ്നിഷൻ + +പ്രീട്രെയിൻ ചെയ്ത മോഡൽ ഓട്ടോമാറ്റിക് സ്പീച്ച് റെക്കഗ്നിഷനായി ഉപയോഗിക്കാൻ, അതിന്റെ പൂർണ്ണമായ എൻകോഡർ-ഡീകോഡർ ഘടന നിങ്ങൾ പ്രയോജനപ്പെടുത്തുന്നു. എൻകോഡർ ഓഡിയോ ഇൻപുട്ട് പ്രോസസ്സ് ചെയ്യുന്നു, ഡീകോഡർ ട്രാൻസ്ക്രിപ്‌റ്റ് ടോക്കൺ ടോക്കണായി ഓട്ടോറിഗ്രസ്സീവായി സൃഷ്ടിക്കുന്നു. ഫൈൻ-ട്യൂണിംഗ് ചെയ്യുമ്പോൾ, ഓഡിയോ ഇൻപുട്ടിന്റെ അടിസ്ഥാനത്തിൽ ശരിയായ ടെക്‌സ്‌റ്റ് ടോക്കണുകൾ പ്രവചിക്കാൻ ഒരു സ്റ്റാൻഡേർഡ് സീക്വൻസ്-ടു-സീക്വൻസ് ലോസ് (ക്രോസ്-എൻട്രോപ്പി പോലുള്ളത്) ഉപയോഗിച്ചാണ് മോഡൽ സാധാരണയായി പരിശീലിപ്പിക്കുന്നത്. + +ഫൈൻ-ട്യൂൻ ചെയ്ത ഒരു മോഡൽ ഇൻഫറൻസിനായി ഉപയോഗിക്കാനുള്ള ഏറ്റവും എളുപ്പമുള്ള മാർഗം ഒരു `pipeline`-നുള്ളിലാണ്. + +```python +from transformers import pipeline + +transcriber = pipeline( + task="automatic-speech-recognition", model="openai/whisper-base.en" +) +transcriber("https://huggingface.co/datasets/Narsil/asr_dummy/resolve/main/mlk.flac") +# Output: {'text': ' I have a dream that one day this nation will rise up and live out the true meaning of its creed.'} +``` + +ഓട്ടോമാറ്റിക് സ്പീച്ച് റെക്കഗ്നിഷൻ സ്വയം പരീക്ഷിക്കാൻ തയ്യാറാണോ? Whisper എങ്ങനെ ഫൈൻ-ട്യൂൻ ചെയ്യാമെന്നും ഇൻഫറൻസിനായി ഉപയോഗിക്കാമെന്നും പഠിക്കാൻ ഞങ്ങളുടെ പൂർണ്ണമായ [ഓട്ടോമാറ്റിക് സ്പീച്ച് റെക്കഗ്നിഷൻ ഗൈഡ്](https://huggingface.co/docs/transformers/tasks/asr) പരിശോധിക്കുക! + +### കമ്പ്യൂട്ടർ വിഷൻ + +ഇനി നമുക്ക് കമ്പ്യൂട്ടർ വിഷൻ ടാസ്‌കുകളിലേക്ക് കടക്കാം; ഇമേജുകളിൽ നിന്നോ വീഡിയോകളിൽ നിന്നോ ഉള്ള ദൃശ്യവിവരങ്ങൾ മനസ്സിലാക്കുകയും വ്യാഖ്യാനിക്കുകയും ചെയ്യുന്നതാണ് ഇവ. + +കമ്പ്യൂട്ടർ വിഷൻ ടാസ്‌കുകളെ സമീപിക്കാൻ രണ്ട് വഴികളുണ്ട്: + +1. ഒരു ഇമേജിനെ പാച്ചുകളുടെ (patches) ഒരു സീക്വൻസായി വിഭജിച്ച്, അവയെ ഒരു Transformer ഉപയോഗിച്ച് സമാന്തരമായി പ്രോസസ്സ് ചെയ്യുക. +2. [ConvNeXT](https://huggingface.co/docs/transformers/model_doc/convnext) പോലുള്ള ഒരു ആധുനിക CNN ഉപയോഗിക്കുക; ഇത് കൺവൊല്യൂഷണൽ ലെയറുകളെ ആശ്രയിക്കുന്നു, എന്നാൽ ആധുനിക നെറ്റ്‌വർക്ക് ഡിസൈനുകൾ സ്വീകരിക്കുന്നു. + +> [!TIP] +> മൂന്നാമതൊരു സമീപനം Transformers-നെ കൺവൊല്യൂഷനുകളുമായി കൂട്ടിക്കലർത്തുന്നു (ഉദാഹരണത്തിന്, [Convolutional Vision Transformer](https://huggingface.co/docs/transformers/model_doc/cvt) അല്ലെങ്കിൽ [LeViT](https://huggingface.co/docs/transformers/model_doc/levit)). നാം ഇവിടെ പരിശോധിക്കുന്ന രണ്ട് സമീപനങ്ങളെ വെറുതെ സംയോജിപ്പിക്കുന്നവയായതിനാൽ അവയെക്കുറിച്ച് നാം ചർച്ച ചെയ്യുന്നില്ല. + +ViT-യും ConvNeXT-ഉം സാധാരണയായി ഇമേജ് ക്ലാസിഫിക്കേഷനായി ഉപയോഗിക്കുന്നു, എന്നാൽ ഒബ്‌ജക്റ്റ് ഡിറ്റക്ഷൻ, സെഗ്‌മെന്റേഷൻ, ഡെപ്ത് എസ്റ്റിമേഷൻ പോലുള്ള മറ്റ് വിഷൻ ടാസ്‌കുകൾക്കായി നാം യഥാക്രമം DETR, Mask2Former, GLPN എന്നിവ പരിശോധിക്കും; ഈ മോഡലുകൾ ആ ടാസ്‌കുകൾക്ക് കൂടുതൽ അനുയോജ്യമാണ്. + +### ഇമേജ് ക്ലാസിഫിക്കേഷൻ + +അടിസ്ഥാന കമ്പ്യൂട്ടർ വിഷൻ ടാസ്‌കുകളിൽ ഒന്നാണ് ഇമേജ് ക്ലാസിഫിക്കേഷൻ. വ്യത്യസ്ത മോഡൽ ആർക്കിടെക്ചറുകൾ ഈ പ്രശ്നത്തെ എങ്ങനെ സമീപിക്കുന്നു എന്ന് നോക്കാം. + +ViT-യും ConvNeXT-ഉം രണ്ടും ഇമേജ് ക്ലാസിഫിക്കേഷനായി ഉപയോഗിക്കാം; പ്രധാന വ്യത്യാസം ViT ഒരു അറ്റൻഷൻ മെക്കാനിസം ഉപയോഗിക്കുന്നു, ConvNeXT കൺവൊല്യൂഷനുകൾ ഉപയോഗിക്കുന്നു എന്നതാണ്. + +[ViT](https://huggingface.co/docs/transformers/model_doc/vit) കൺവൊല്യൂഷനുകളെ പൂർണ്ണമായും ഒരു ശുദ്ധ Transformer ആർക്കിടെക്ചർ കൊണ്ട് മാറ്റിസ്ഥാപിക്കുന്നു. യഥാർത്ഥ Transformer നിങ്ങൾക്ക് പരിചിതമാണെങ്കിൽ, ViT മനസ്സിലാക്കുന്നതിലേക്കുള്ള വഴിയുടെ ഭൂരിഭാഗവും നിങ്ങൾ ഇതിനകം പിന്നിട്ടിരിക്കുന്നു. + +
+ +
+ +ViT കൊണ്ടുവന്ന പ്രധാന മാറ്റം ഇമേജുകൾ ഒരു Transformer-ലേക്ക് എങ്ങനെ നൽകുന്നു എന്നതിലാണ്: + +1. ഒരു ഇമേജിനെ പരസ്പരം ഓവർലാപ്പ് ചെയ്യാത്ത ചതുര പാച്ചുകളായി വിഭജിക്കുന്നു; ഇവ ഓരോന്നും ഒരു വെക്റ്ററായി അഥവാ *പാച്ച് എംബെഡ്ഡിംഗ്* ആയി മാറുന്നു. ശരിയായ ഇൻപുട്ട് ഡൈമെൻഷനുകൾ സൃഷ്ടിക്കുന്ന ഒരു കൺവൊല്യൂഷണൽ 2D ലെയറിൽ നിന്നാണ് പാച്ച് എംബെഡ്ഡിംഗുകൾ സൃഷ്ടിക്കുന്നത് (ഒരു അടിസ്ഥാന Transformer-ന് ഇത് ഓരോ പാച്ച് എംബെഡ്ഡിംഗിനും 768 മൂല്യങ്ങളാണ്). നിങ്ങൾക്ക് 224x224 പിക്‌സൽ ഇമേജ് ഉണ്ടെങ്കിൽ, അതിനെ 16x16 വലുപ്പമുള്ള 196 ഇമേജ് പാച്ചുകളായി വിഭജിക്കാം. ടെക്‌സ്‌റ്റ് വാക്കുകളായി ടോക്കണൈസ് ചെയ്യുന്നതുപോലെ, ഒരു ഇമേജ് പാച്ചുകളുടെ ഒരു സീക്വൻസായി "ടോക്കണൈസ്" ചെയ്യപ്പെടുന്നു. + +2. BERT-ലേതുപോലെ, ഒരു *ലേണബിൾ എംബെഡ്ഡിംഗ്* (learnable embedding) — ഒരു പ്രത്യേക `[CLS]` ടോക്കൺ — പാച്ച് എംബെഡ്ഡിംഗുകളുടെ തുടക്കത്തിൽ ചേർക്കുന്നു. `[CLS]` ടോക്കണിന്റെ അന്തിമ ഹിഡൻ സ്റ്റേറ്റ്, ഘടിപ്പിച്ചിരിക്കുന്ന ക്ലാസിഫിക്കേഷൻ ഹെഡിലേക്കുള്ള ഇൻപുട്ടായി ഉപയോഗിക്കുന്നു; മറ്റ് ഔട്ട്‌പുട്ടുകൾ അവഗണിക്കുന്നു. ഇമേജിന്റെ ഒരു പ്രതിനിധാനം എങ്ങനെ എൻകോഡ് ചെയ്യണമെന്ന് പഠിക്കാൻ ഈ ടോക്കൺ മോഡലിനെ സഹായിക്കുന്നു. + +3. പാച്ച് എംബെഡ്ഡിംഗുകളിലേക്കും ലേണബിൾ എംബെഡ്ഡിംഗുകളിലേക്കും അവസാനമായി ചേർക്കേണ്ടത് *പൊസിഷൻ എംബെഡ്ഡിംഗുകൾ* (position embeddings) ആണ്, കാരണം ഇമേജ് പാച്ചുകൾ എങ്ങനെയാണ് ക്രമീകരിച്ചിരിക്കുന്നത് എന്ന് മോഡലിന് അറിയില്ല. പൊസിഷൻ എംബെഡ്ഡിംഗുകളും ലേണബിൾ ആണ്, അവയ്ക്ക് പാച്ച് എംബെഡ്ഡിംഗുകളുടെ അതേ വലുപ്പമുണ്ട്. അവസാനം, എല്ലാ എംബെഡ്ഡിംഗുകളും Transformer എൻകോഡറിലേക്ക് കൈമാറുന്നു. + +4. ഔട്ട്‌പുട്ട് — കൃത്യമായി പറഞ്ഞാൽ `[CLS]` ടോക്കണിനൊപ്പമുള്ള ഔട്ട്‌പുട്ട് മാത്രം — ഒരു മൾട്ടിലെയർ പെർസെപ്ട്രോൺ ഹെഡിലേക്ക് (MLP) കൈമാറുന്നു. ViT-യുടെ പ്രീട്രെയിനിംഗ് ലക്ഷ്യം ലളിതമായി ക്ലാസിഫിക്കേഷനാണ്. മറ്റ് ക്ലാസിഫിക്കേഷൻ ഹെഡുകൾ പോലെ, MLP ഹെഡ് ഔട്ട്‌പുട്ടിനെ ക്ലാസ് ലേബലുകൾക്ക് മേലുള്ള ലോജിറ്റുകളാക്കി മാറ്റുകയും, ഏറ്റവും സാധ്യതയുള്ള ക്ലാസ് കണ്ടെത്താൻ ക്രോസ്-എൻട്രോപ്പി ലോസ് കണക്കാക്കുകയും ചെയ്യുന്നു. + +ഇമേജ് ക്ലാസിഫിക്കേഷൻ സ്വയം പരീക്ഷിക്കാൻ തയ്യാറാണോ? ViT എങ്ങനെ ഫൈൻ-ട്യൂൻ ചെയ്യാമെന്നും ഇൻഫറൻസിനായി ഉപയോഗിക്കാമെന്നും പഠിക്കാൻ ഞങ്ങളുടെ പൂർണ്ണമായ [ഇമേജ് ക്ലാസിഫിക്കേഷൻ ഗൈഡ്](https://huggingface.co/docs/transformers/tasks/image_classification) പരിശോധിക്കുക! + + +> [!TIP] +> ViT-യും BERT-ഉം തമ്മിലുള്ള സമാന്തരം ശ്രദ്ധിക്കുക: രണ്ടും മൊത്തത്തിലുള്ള പ്രതിനിധാനം പിടിച്ചെടുക്കാൻ ഒരു പ്രത്യേക ടോക്കൺ ([CLS]) ഉപയോഗിക്കുന്നു, രണ്ടും അവയുടെ എംബെഡ്ഡിംഗുകളിലേക്ക് സ്ഥാന വിവരങ്ങൾ ചേർക്കുന്നു, രണ്ടും ടോക്കണുകളുടെ/പാച്ചുകളുടെ സീക്വൻസ് പ്രോസസ്സ് ചെയ്യാൻ ഒരു Transformer എൻകോഡർ ഉപയോഗിക്കുന്നു. diff --git a/chapters/ml/chapter1/6.mdx b/chapters/ml/chapter1/6.mdx new file mode 100644 index 000000000..5d94d809f --- /dev/null +++ b/chapters/ml/chapter1/6.mdx @@ -0,0 +1,203 @@ + + +# Transformer ആർക്കിടെക്ചറുകൾ[[transformer-architectures]] + +മുൻ വിഭാഗങ്ങളിൽ നാം Transformer-ന്റെ പൊതുവായ ആർക്കിടെക്ചർ പരിചയപ്പെടുത്തുകയും, ഈ മോഡലുകൾ വിവിധ ടാസ്‌കുകൾ എങ്ങനെ പരിഹരിക്കുന്നു എന്ന് പരിശോധിക്കുകയും ചെയ്തു. ഇനി, Transformer മോഡലുകളുടെ മൂന്ന് പ്രധാന ആർക്കിടെക്ചർ വകഭേദങ്ങളെ കൂടുതൽ അടുത്തു നോക്കുകയും ഓരോന്നും എപ്പോൾ ഉപയോഗിക്കണം എന്ന് മനസ്സിലാക്കുകയും ചെയ്യാം. അതിനുശേഷം, ഈ ആർക്കിടെക്ചറുകൾ വ്യത്യസ്ത ഭാഷാ ടാസ്‌കുകളിൽ എങ്ങനെ പ്രയോഗിക്കുന്നു എന്ന് നോക്കാം. + +ഈ വിഭാഗത്തിൽ, Transformer മോഡലുകളുടെ മൂന്ന് പ്രധാന ആർക്കിടെക്ചർ വകഭേദങ്ങളിലേക്ക് നാം ആഴത്തിൽ ഇറങ്ങുകയും ഓരോന്നും എപ്പോൾ ഉപയോഗിക്കണം എന്ന് മനസ്സിലാക്കുകയും ചെയ്യും. + + +> [!TIP] +> മിക്ക Transformer മോഡലുകളും മൂന്ന് ആർക്കിടെക്ചറുകളിൽ ഒന്ന് ഉപയോഗിക്കുന്നു എന്ന് ഓർക്കുക: എൻകോഡർ-മാത്രം (encoder-only), ഡീകോഡർ-മാത്രം (decoder-only), അല്ലെങ്കിൽ എൻകോഡർ-ഡീകോഡർ (sequence-to-sequence). ഈ വ്യത്യാസങ്ങൾ മനസ്സിലാക്കുന്നത് നിങ്ങളുടെ പ്രത്യേക ടാസ്‌കിന് അനുയോജ്യമായ മോഡൽ തിരഞ്ഞെടുക്കാൻ സഹായിക്കും. + +## എൻകോഡർ മോഡലുകൾ[[encoder-models]] + + + +എൻകോഡർ മോഡലുകൾ ഒരു Transformer മോഡലിന്റെ എൻകോഡർ ഭാഗം മാത്രമാണ് ഉപയോഗിക്കുന്നത്. ഓരോ ഘട്ടത്തിലും, അറ്റൻഷൻ ലെയറുകൾക്ക് ആദ്യ വാക്യത്തിലെ എല്ലാ വാക്കുകളും ആക്‌സസ് ചെയ്യാൻ കഴിയും. ഈ മോഡലുകൾക്ക് "ദ്വിദിശ" (bi-directional) അറ്റൻഷൻ ഉണ്ടെന്ന് പൊതുവെ പറയപ്പെടുന്നു, അവയെ പലപ്പോഴും *ഓട്ടോ-എൻകോഡിംഗ് മോഡലുകൾ* (auto-encoding models) എന്ന് വിളിക്കുന്നു. + +ഈ മോഡലുകളുടെ പ്രീട്രെയിനിംഗ് സാധാരണയായി ഒരു നിശ്ചിത വാക്യത്തെ ഏതെങ്കിലും വിധത്തിൽ വികലമാക്കുകയും (ഉദാഹരണത്തിന്, അതിലെ ചില വാക്കുകൾ ക്രമരഹിതമായി മറച്ചുകൊണ്ട്), ആദ്യ വാക്യം കണ്ടെത്താനോ പുനർനിർമ്മിക്കാനോ മോഡലിനെ ചുമതലപ്പെടുത്തുകയും ചെയ്യുന്നതിനെ ചുറ്റിപ്പറ്റിയാണ്. + +വാക്യം പൂർണ്ണമായി മനസ്സിലാക്കേണ്ട ടാസ്‌കുകൾക്ക് എൻകോഡർ മോഡലുകളാണ് ഏറ്റവും അനുയോജ്യം — ഉദാഹരണത്തിന്, വാക്യ വർഗ്ഗീകരണം (sentence classification), നെയിംഡ് എന്റിറ്റി റെക്കഗ്നിഷൻ (കൂടുതൽ പൊതുവായി പറഞ്ഞാൽ വാക്ക് വർഗ്ഗീകരണം), എക്‌സ്ട്രാക്റ്റീവ് ചോദ്യോത്തരം (extractive question answering) തുടങ്ങിയവ. + +> [!TIP] +> [🤗 Transformers ടാസ്‌കുകൾ എങ്ങനെ പരിഹരിക്കുന്നു](https://huggingface.co/learn/llm-course/chapter1/5) എന്ന വിഭാഗത്തിൽ കണ്ടതുപോലെ, BERT പോലുള്ള എൻകോഡർ മോഡലുകൾ ടെക്‌സ്‌റ്റ് മനസ്സിലാക്കുന്നതിൽ മികവ് പുലർത്തുന്നു, കാരണം അവയ്ക്ക് രണ്ട് ദിശകളിലുമുള്ള മുഴുവൻ സന്ദർഭവും (context) നോക്കാൻ കഴിയും. ഇൻപുട്ട് മുഴുവനായി ഗ്രഹിക്കേണ്ട ടാസ്‌കുകൾക്ക് ഇത് അവയെ ഏറ്റവും അനുയോജ്യമാക്കുന്നു. + +ഈ കുടുംബത്തിലെ പ്രതിനിധി മോഡലുകളിൽ ഉൾപ്പെടുന്നവ: + +- [BERT](https://huggingface.co/docs/transformers/model_doc/bert) +- [DistilBERT](https://huggingface.co/docs/transformers/model_doc/distilbert) +- [ModernBERT](https://huggingface.co/docs/transformers/en/model_doc/modernbert) + +## ഡീകോഡർ മോഡലുകൾ[[decoder-models]] + + + +ഡീകോഡർ മോഡലുകൾ ഒരു Transformer മോഡലിന്റെ ഡീകോഡർ ഭാഗം മാത്രമാണ് ഉപയോഗിക്കുന്നത്. ഓരോ ഘട്ടത്തിലും, ഒരു നിശ്ചിത വാക്കിന് വേണ്ടി അറ്റൻഷൻ ലെയറുകൾക്ക് വാക്യത്തിൽ അതിനു മുൻപ് വരുന്ന വാക്കുകൾ മാത്രമേ ആക്‌സസ് ചെയ്യാൻ കഴിയൂ. ഈ മോഡലുകളെ പലപ്പോഴും *ഓട്ടോ-റിഗ്രസ്സീവ് മോഡലുകൾ* (auto-regressive models) എന്ന് വിളിക്കുന്നു. + +ഡീകോഡർ മോഡലുകളുടെ പ്രീട്രെയിനിംഗ് സാധാരണയായി വാക്യത്തിലെ അടുത്ത വാക്ക് പ്രവചിക്കുന്നതിനെ ചുറ്റിപ്പറ്റിയാണ്. + +ടെക്‌സ്‌റ്റ് ജനറേഷൻ ഉൾപ്പെടുന്ന ടാസ്‌കുകൾക്ക് ഈ മോഡലുകളാണ് ഏറ്റവും അനുയോജ്യം. + +> [!TIP] +> GPT പോലുള്ള ഡീകോഡർ മോഡലുകൾ ഒരു സമയം ഒരു ടോക്കൺ വീതം പ്രവചിച്ച് ടെക്‌സ്‌റ്റ് ജനറേറ്റ് ചെയ്യാനാണ് രൂപകൽപ്പന ചെയ്തിരിക്കുന്നത്. [🤗 Transformers ടാസ്‌കുകൾ എങ്ങനെ പരിഹരിക്കുന്നു](https://huggingface.co/learn/llm-course/chapter1/5) എന്ന വിഭാഗത്തിൽ നാം കണ്ടതുപോലെ, അവയ്ക്ക് മുൻപുള്ള ടോക്കണുകൾ മാത്രമേ കാണാൻ കഴിയൂ. ഇത് അവയെ സർഗ്ഗാത്മക ടെക്‌സ്‌റ്റ് ജനറേഷനിൽ മികച്ചതാക്കുന്നു, എന്നാൽ ദ്വിദിശ ധാരണ ആവശ്യമുള്ള ടാസ്‌കുകൾക്ക് അത്ര അനുയോജ്യമല്ലാതാക്കുന്നു. + +ഈ കുടുംബത്തിലെ പ്രതിനിധി മോഡലുകളിൽ ഉൾപ്പെടുന്നവ: + +- [Hugging Face SmolLM Series](https://huggingface.co/HuggingFaceTB/SmolLM2-1.7B-Instruct) +- [Meta's Llama Series](https://huggingface.co/docs/transformers/en/model_doc/llama4) +- [Google's Gemma Series](https://huggingface.co/docs/transformers/main/en/model_doc/gemma3) +- [DeepSeek's V3](https://huggingface.co/deepseek-ai/DeepSeek-V3) + +### ആധുനിക ലാർജ് ലാംഗ്വേജ് മോഡലുകൾ (LLMs) + +മിക്ക ആധുനിക ലാർജ് ലാംഗ്വേജ് മോഡലുകളും (LLMs) ഡീകോഡർ-മാത്രം ആർക്കിടെക്ചറാണ് ഉപയോഗിക്കുന്നത്. കഴിഞ്ഞ കുറച്ച് വർഷങ്ങളിൽ ഈ മോഡലുകൾ വലിപ്പത്തിലും കഴിവുകളിലും വൻതോതിൽ വളർന്നിട്ടുണ്ട്; ഏറ്റവും വലിയ ചില മോഡലുകളിൽ നൂറുകണക്കിന് ബില്യൻ പാരാമീറ്ററുകൾ അടങ്ങിയിരിക്കുന്നു. + +ആധുനിക LLM-കൾ സാധാരണയായി രണ്ട് ഘട്ടങ്ങളിലായാണ് ട്രെയിൻ ചെയ്യപ്പെടുന്നത്: +1. **പ്രീട്രെയിനിംഗ്**: വലിയ അളവിലുള്ള ടെക്‌സ്‌റ്റ് ഡേറ്റയിൽ അടുത്ത ടോക്കൺ പ്രവചിക്കാൻ മോഡൽ പഠിക്കുന്നു +2. **ഇൻസ്ട്രക്ഷൻ ട്യൂണിംഗ്**: നിർദ്ദേശങ്ങൾ പിന്തുടരാനും സഹായകമായ പ്രതികരണങ്ങൾ ജനറേറ്റ് ചെയ്യാനും മോഡൽ ഫൈൻ-ട്യൂൺ ചെയ്യപ്പെടുന്നു + +വിശാലമായ വിഷയങ്ങളിലും ടാസ്‌കുകളിലും മനുഷ്യസമാനമായ ടെക്‌സ്‌റ്റ് മനസ്സിലാക്കാനും ജനറേറ്റ് ചെയ്യാനും കഴിയുന്ന മോഡലുകളിലേക്ക് ഈ സമീപനം നയിച്ചു. + +#### ആധുനിക LLM-കളുടെ പ്രധാന കഴിവുകൾ + +ആധുനിക ഡീകോഡർ-അധിഷ്ഠിത LLM-കൾ ശ്രദ്ധേയമായ കഴിവുകൾ പ്രകടിപ്പിച്ചിട്ടുണ്ട്: + +| കഴിവ് | വിവരണം | ഉദാഹരണം | +|------------|-------------|---------| +| ടെക്‌സ്‌റ്റ് ജനറേഷൻ | യോജിപ്പുള്ളതും സന്ദർഭോചിതവുമായ ടെക്‌സ്‌റ്റ് സൃഷ്ടിക്കുക | ഉപന്യാസങ്ങൾ, കഥകൾ, അല്ലെങ്കിൽ ഇമെയിലുകൾ എഴുതുക | +| സംഗ്രഹം (Summarization) | നീണ്ട ഡോക്യുമെന്റുകളെ ചെറിയ പതിപ്പുകളായി ചുരുക്കുക | റിപ്പോർട്ടുകളുടെ എക്‌സിക്യൂട്ടീവ് സംഗ്രഹങ്ങൾ തയ്യാറാക്കുക | +| വിവർത്തനം | ടെക്‌സ്‌റ്റ് ഒരു ഭാഷയിൽ നിന്ന് മറ്റൊന്നിലേക്ക് മാറ്റുക | ഇംഗ്ലീഷിൽ നിന്ന് സ്പാനിഷിലേക്ക് വിവർത്തനം ചെയ്യുക | +| ചോദ്യോത്തരം | വസ്തുതാപരമായ ചോദ്യങ്ങൾക്ക് ഉത്തരം നൽകുക | "ഫ്രാൻസിന്റെ തലസ്ഥാനം ഏതാണ്?" | +| കോഡ് ജനറേഷൻ | കോഡ് സ്‌നിപ്പെറ്റുകൾ എഴുതുകയോ പൂർത്തിയാക്കുകയോ ചെയ്യുക | ഒരു വിവരണത്തെ അടിസ്ഥാനമാക്കി ഒരു ഫംഗ്‌ഷൻ എഴുതുക | +| യുക്തിചിന്ത (Reasoning) | പ്രശ്നങ്ങൾ ഘട്ടം ഘട്ടമായി പരിഹരിക്കുക | ഗണിത പ്രശ്നങ്ങളോ ലോജിക്കൽ പസിലുകളോ പരിഹരിക്കുക | +| ഫ്യൂ-ഷോട്ട് ലേണിംഗ് | പ്രോംപ്‌റ്റിലെ ഏതാനും ഉദാഹരണങ്ങളിൽ നിന്ന് പഠിക്കുക | 2-3 ഉദാഹരണങ്ങൾ മാത്രം കണ്ടതിനുശേഷം ടെക്‌സ്‌റ്റ് വർഗ്ഗീകരിക്കുക | + +Hub-ലെ മോഡൽ റിപ്പോ പേജുകൾ വഴി നിങ്ങളുടെ ബ്രൗസറിൽ നേരിട്ട് ഡീകോഡർ-അധിഷ്ഠിത LLM-കൾ പരീക്ഷിച്ചു നോക്കാം. ക്ലാസിക് [GPT-2](https://huggingface.co/openai-community/gpt2) (OpenAI-യുടെ ഏറ്റവും മികച്ച ഓപ്പൺ സോഴ്‌സ് മോഡൽ!) ഉപയോഗിച്ചുള്ള ഒരു ഉദാഹരണം ഇതാ: + + + GPT-2 മോഡൽ Hugging Face-ൽ കാണുക + + +## Sequence-to-sequence മോഡലുകൾ[[sequence-to-sequence-models]] + + + +എൻകോഡർ-ഡീകോഡർ മോഡലുകൾ (*sequence-to-sequence മോഡലുകൾ* എന്നും വിളിക്കപ്പെടുന്നു) Transformer ആർക്കിടെക്ചറിന്റെ രണ്ട് ഭാഗങ്ങളും ഉപയോഗിക്കുന്നു. ഓരോ ഘട്ടത്തിലും, എൻകോഡറിന്റെ അറ്റൻഷൻ ലെയറുകൾക്ക് ആദ്യ വാക്യത്തിലെ എല്ലാ വാക്കുകളും ആക്‌സസ് ചെയ്യാൻ കഴിയും, അതേസമയം ഡീകോഡറിന്റെ അറ്റൻഷൻ ലെയറുകൾക്ക് ഇൻപുട്ടിൽ ഒരു നിശ്ചിത വാക്കിന് മുൻപ് വരുന്ന വാക്കുകൾ മാത്രമേ ആക്‌സസ് ചെയ്യാൻ കഴിയൂ. + +ഈ മോഡലുകളുടെ പ്രീട്രെയിനിംഗ് വ്യത്യസ്ത രൂപങ്ങളിൽ ആകാം, എന്നാൽ പലപ്പോഴും ഇൻപുട്ട് ഏതെങ്കിലും വിധത്തിൽ വികലമാക്കപ്പെട്ട (ഉദാഹരണത്തിന്, ക്രമരഹിതമായ വാക്കുകൾ മറച്ചുകൊണ്ട്) ഒരു വാക്യം പുനർനിർമ്മിക്കുന്നത് അതിൽ ഉൾപ്പെടുന്നു. T5 മോഡലിന്റെ പ്രീട്രെയിനിംഗിൽ, ടെക്‌സ്‌റ്റിലെ ക്രമരഹിതമായ ഭാഗങ്ങളെ (നിരവധി വാക്കുകൾ അടങ്ങിയവയാകാം) ഒരൊറ്റ മാസ്‌ക് സ്‌പെഷ്യൽ ടോക്കൺ കൊണ്ട് പകരം വയ്ക്കുന്നു; ആ മാസ്‌ക് ടോക്കൺ മറച്ച ടെക്‌സ്‌റ്റ് പ്രവചിക്കുകയാണ് പിന്നീടുള്ള ടാസ്‌ക്. + +ഒരു നിശ്ചിത ഇൻപുട്ടിനെ ആശ്രയിച്ച് പുതിയ വാക്യങ്ങൾ ജനറേറ്റ് ചെയ്യുന്ന ടാസ്‌കുകൾക്ക് sequence-to-sequence മോഡലുകളാണ് ഏറ്റവും അനുയോജ്യം — ഉദാഹരണത്തിന്, സംഗ്രഹം, വിവർത്തനം, അല്ലെങ്കിൽ ജനറേറ്റീവ് ചോദ്യോത്തരം. + +> [!TIP] +> [🤗 Transformers ടാസ്‌കുകൾ എങ്ങനെ പരിഹരിക്കുന്നു](https://huggingface.co/learn/llm-course/chapter1/5) എന്ന വിഭാഗത്തിൽ കണ്ടതുപോലെ, BART, T5 പോലുള്ള എൻകോഡർ-ഡീകോഡർ മോഡലുകൾ രണ്ട് ആർക്കിടെക്ചറുകളുടെയും ശക്തികൾ സംയോജിപ്പിക്കുന്നു. എൻകോഡർ ഇൻപുട്ടിനെക്കുറിച്ച് ആഴത്തിലുള്ള ദ്വിദിശ ധാരണ നൽകുന്നു, അതേസമയം ഡീകോഡർ അനുയോജ്യമായ ഔട്ട്‌പുട്ട് ടെക്‌സ്‌റ്റ് ജനറേറ്റ് ചെയ്യുന്നു. വിവർത്തനം അല്ലെങ്കിൽ സംഗ്രഹം പോലെ, ഒരു സീക്വൻസിനെ മറ്റൊന്നാക്കി മാറ്റുന്ന ടാസ്‌കുകൾക്ക് ഇത് അവയെ ഏറ്റവും അനുയോജ്യമാക്കുന്നു. + +### പ്രായോഗിക ഉപയോഗങ്ങൾ + +അർത്ഥം നിലനിർത്തിക്കൊണ്ട് ടെക്‌സ്‌റ്റിന്റെ ഒരു രൂപത്തെ മറ്റൊന്നാക്കി മാറ്റേണ്ട ടാസ്‌കുകളിൽ sequence-to-sequence മോഡലുകൾ മികവ് പുലർത്തുന്നു. ചില പ്രായോഗിക ഉപയോഗങ്ങൾ ഇവയാണ്: + +| ഉപയോഗം | വിവരണം | ഉദാഹരണ മോഡൽ | +|-------------|-------------|---------------| +| മെഷീൻ ട്രാൻസ്‌ലേഷൻ | ടെക്‌സ്‌റ്റ് ഒരു ഭാഷയിൽ നിന്ന് മറ്റൊന്നിലേക്ക് മാറ്റുക | Marian, T5 | +| ടെക്‌സ്‌റ്റ് സംഗ്രഹം | നീണ്ട ടെക്‌സ്‌റ്റുകളുടെ സംക്ഷിപ്ത സംഗ്രഹങ്ങൾ തയ്യാറാക്കുക | BART, T5 | +| ഡേറ്റയിൽ നിന്ന് ടെക്‌സ്‌റ്റ് ജനറേഷൻ | ഘടനാപരമായ ഡേറ്റയെ സ്വാഭാവിക ഭാഷയാക്കി മാറ്റുക | T5 | +| വ്യാകരണ തിരുത്തൽ | ടെക്‌സ്‌റ്റിലെ വ്യാകരണ പിശകുകൾ തിരുത്തുക | T5 | +| ചോദ്യോത്തരം | സന്ദർഭത്തെ അടിസ്ഥാനമാക്കി ഉത്തരങ്ങൾ ജനറേറ്റ് ചെയ്യുക | BART, T5 | + +വിവർത്തനത്തിനുള്ള ഒരു sequence-to-sequence മോഡലിന്റെ ഇന്ററാക്ടീവ് ഡെമോ ഇതാ: + + + +ഈ കുടുംബത്തിലെ പ്രതിനിധി മോഡലുകളിൽ ഉൾപ്പെടുന്നവ: + +- [BART](https://huggingface.co/docs/transformers/model_doc/bart) +- [mBART](https://huggingface.co/docs/transformers/model_doc/mbart) +- [Marian](https://huggingface.co/docs/transformers/model_doc/marian) +- [T5](https://huggingface.co/docs/transformers/model_doc/t5) + +## അനുയോജ്യമായ ആർക്കിടെക്ചർ തിരഞ്ഞെടുക്കൽ[[choosing-the-right-architecture]] + +ഒരു പ്രത്യേക NLP ടാസ്‌കിൽ പ്രവർത്തിക്കുമ്പോൾ, ഏത് ആർക്കിടെക്ചർ ഉപയോഗിക്കണം എന്ന് നിങ്ങൾ എങ്ങനെ തീരുമാനിക്കും? ഒരു ദ്രുത ഗൈഡ് ഇതാ: + +| ടാസ്‌ക് | നിർദ്ദേശിക്കുന്ന ആർക്കിടെക്ചർ | ഉദാഹരണങ്ങൾ | +|------|------------------------|----------| +| ടെക്‌സ്‌റ്റ് വർഗ്ഗീകരണം (വികാരം, വിഷയം) | എൻകോഡർ | BERT, RoBERTa | +| ടെക്‌സ്‌റ്റ് ജനറേഷൻ (സർഗ്ഗാത്മക രചന) | ഡീകോഡർ | GPT, LLaMA | +| വിവർത്തനം | എൻകോഡർ-ഡീകോഡർ | T5, BART | +| സംഗ്രഹം | എൻകോഡർ-ഡീകോഡർ | BART, T5 | +| നെയിംഡ് എന്റിറ്റി റെക്കഗ്നിഷൻ | എൻകോഡർ | BERT, RoBERTa | +| ചോദ്യോത്തരം (എക്‌സ്ട്രാക്റ്റീവ്) | എൻകോഡർ | BERT, RoBERTa | +| ചോദ്യോത്തരം (ജനറേറ്റീവ്) | എൻകോഡർ-ഡീകോഡർ അല്ലെങ്കിൽ ഡീകോഡർ | T5, GPT | +| സംഭാഷണ AI | ഡീകോഡർ | GPT, LLaMA | + +> [!TIP] +> ഏത് മോഡൽ ഉപയോഗിക്കണം എന്ന് സംശയമുണ്ടെങ്കിൽ, ഇവ പരിഗണിക്കുക: +> +> 1. നിങ്ങളുടെ ടാസ്‌കിന് ഏത് തരത്തിലുള്ള ധാരണയാണ് വേണ്ടത്? (ദ്വിദിശയോ ഏകദിശയോ) +> 2. നിങ്ങൾ പുതിയ ടെക്‌സ്‌റ്റ് ജനറേറ്റ് ചെയ്യുകയാണോ, അതോ നിലവിലുള്ള ടെക്‌സ്‌റ്റ് വിശകലനം ചെയ്യുകയാണോ? +> 3. ഒരു സീക്വൻസിനെ മറ്റൊന്നാക്കി മാറ്റേണ്ടതുണ്ടോ? +> +> ഈ ചോദ്യങ്ങളുടെ ഉത്തരങ്ങൾ നിങ്ങളെ അനുയോജ്യമായ ആർക്കിടെക്ചറിലേക്ക് നയിക്കും. + +## LLM-കളുടെ പരിണാമം + +സമീപ വർഷങ്ങളിൽ ലാർജ് ലാംഗ്വേജ് മോഡലുകൾ അതിവേഗം പരിണമിച്ചിട്ടുണ്ട്; ഓരോ തലമുറയും കഴിവുകളിൽ ഗണ്യമായ പുരോഗതി കൊണ്ടുവന്നിട്ടുണ്ട്. + +## അറ്റൻഷൻ മെക്കാനിസങ്ങൾ[[attention-mechanisms]] + +മിക്ക transformer മോഡലുകളും പൂർണ്ണ അറ്റൻഷൻ (full attention) ഉപയോഗിക്കുന്നു — അതായത്, അറ്റൻഷൻ മാട്രിക്‌സ് ചതുരാകൃതിയിലുള്ളതാണ്. നീണ്ട ടെക്‌സ്‌റ്റുകൾ ഉള്ളപ്പോൾ ഇത് ഒരു വലിയ +കമ്പ്യൂട്ടേഷണൽ തടസ്സമായി (bottleneck) മാറാം. Longformer, Reformer എന്നിവ കൂടുതൽ കാര്യക്ഷമമാകാൻ ശ്രമിക്കുന്ന മോഡലുകളാണ്; ട്രെയിനിംഗ് വേഗത്തിലാക്കാൻ അവ +അറ്റൻഷൻ മാട്രിക്‌സിന്റെ ഒരു സ്‌പാഴ്‌സ് (sparse) പതിപ്പ് ഉപയോഗിക്കുന്നു. + +> [!TIP] +> സാധാരണ അറ്റൻഷൻ മെക്കാനിസങ്ങൾക്ക് O(n²) കമ്പ്യൂട്ടേഷണൽ കോംപ്ലക്‌സിറ്റിയാണ് ഉള്ളത്, ഇവിടെ n എന്നത് സീക്വൻസിന്റെ നീളമാണ്. വളരെ നീണ്ട സീക്വൻസുകൾക്ക് ഇത് പ്രശ്നമാകുന്നു. താഴെ പറയുന്ന പ്രത്യേക അറ്റൻഷൻ മെക്കാനിസങ്ങൾ ഈ പരിമിതി പരിഹരിക്കാൻ സഹായിക്കുന്നു. + +### LSH അറ്റൻഷൻ + +[Reformer](https://huggingface.co/docs/transformers/model_doc/reformer) LSH അറ്റൻഷൻ ഉപയോഗിക്കുന്നു. softmax(QK^t)-ൽ, QK^t മാട്രിക്‌സിലെ ഏറ്റവും വലിയ ഘടകങ്ങൾ (softmax ഡൈമെൻഷനിൽ) മാത്രമേ ഉപയോഗപ്രദമായ സംഭാവനകൾ നൽകുകയുള്ളൂ. അതിനാൽ Q-യിലെ ഓരോ ക്വറി q-നും, q-നോട് അടുത്തുനിൽക്കുന്ന +K-യിലെ കീകൾ k മാത്രം പരിഗണിച്ചാൽ മതി. q-യും k-യും അടുത്താണോ എന്ന് നിർണ്ണയിക്കാൻ ഒരു ഹാഷ് ഫംഗ്‌ഷൻ ഉപയോഗിക്കുന്നു. നിലവിലെ ടോക്കണെ മറയ്ക്കാൻ (ആദ്യ സ്ഥാനത്തൊഴികെ) അറ്റൻഷൻ മാസ്‌ക് +പരിഷ്‌കരിക്കുന്നു, കാരണം അത് തുല്യമായ (അതിനാൽ പരസ്‌പരം വളരെ സാമ്യമുള്ള) ഒരു ക്വറിയും കീയും നൽകും. ഹാഷ് അൽപ്പം ക്രമരഹിതമാകാമെന്നതിനാൽ, പ്രായോഗികമായി നിരവധി ഹാഷ് ഫംഗ്‌ഷനുകൾ +(ഒരു n_rounds പാരാമീറ്റർ കൊണ്ട് നിർണ്ണയിക്കപ്പെടുന്നു) ഉപയോഗിക്കുകയും പിന്നീട് അവയുടെ ശരാശരി എടുക്കുകയും ചെയ്യുന്നു. + +### ലോക്കൽ അറ്റൻഷൻ + +[Longformer](https://huggingface.co/docs/transformers/model_doc/longformer) ലോക്കൽ അറ്റൻഷൻ ഉപയോഗിക്കുന്നു: പലപ്പോഴും, ഒരു നിശ്ചിത ടോക്കണിന് വേണ്ടി തീരുമാനമെടുക്കാൻ ലോക്കൽ സന്ദർഭം (ഉദാ., ഇടത്തും വലത്തുമുള്ള രണ്ട് ടോക്കണുകൾ ഏതൊക്കെയാണ്?) മതിയാകും. കൂടാതെ, ചെറിയ വിൻഡോയുള്ള അറ്റൻഷൻ ലെയറുകൾ +അടുക്കി വയ്ക്കുന്നതിലൂടെ, അവസാന ലെയറിന് വിൻഡോയിലെ ടോക്കണുകളെക്കാൾ വിശാലമായ ഒരു റിസപ്‌റ്റീവ് ഫീൽഡ് ലഭിക്കും, ഇത് വാക്യം മുഴുവന്റെയും ഒരു +പ്രതിനിധാനം (representation) നിർമ്മിക്കാൻ അവയെ അനുവദിക്കുന്നു. + +മുൻകൂട്ടി തിരഞ്ഞെടുത്ത ചില ഇൻപുട്ട് ടോക്കണുകൾക്ക് ഗ്ലോബൽ അറ്റൻഷനും നൽകുന്നു: ആ ചുരുക്കം ടോക്കണുകൾക്ക്, അറ്റൻഷൻ മാട്രിക്‌സിന് +എല്ലാ ടോക്കണുകളും ആക്‌സസ് ചെയ്യാൻ കഴിയും, ഈ പ്രക്രിയ സമമിതമാണ് (symmetric): മറ്റെല്ലാ ടോക്കണുകൾക്കും (അവയുടെ ലോക്കൽ വിൻഡോയിലുള്ളവയ്ക്ക് പുറമേ) ആ പ്രത്യേക ടോക്കണുകളിലേക്ക് +ആക്‌സസ് ഉണ്ട്. ഇത് പേപ്പറിലെ Figure 2d-ൽ കാണിച്ചിരിക്കുന്നു; ഒരു മാതൃകാ അറ്റൻഷൻ മാസ്‌ക് താഴെ കാണുക: + +
+ +
+ +കുറഞ്ഞ പാരാമീറ്ററുകളുള്ള ഈ അറ്റൻഷൻ മാട്രിക്‌സുകൾ ഉപയോഗിക്കുന്നത്, കൂടുതൽ നീളമുള്ള സീക്വൻസുകൾ ഇൻപുട്ടായി സ്വീകരിക്കാൻ +മോഡലിനെ പ്രാപ്‌തമാക്കുന്നു. + +### ആക്‌സിയൽ പൊസിഷണൽ എൻകോഡിംഗുകൾ + +[Reformer](https://huggingface.co/docs/transformers/model_doc/reformer) ആക്‌സിയൽ പൊസിഷണൽ എൻകോഡിംഗുകൾ (axial positional encodings) ഉപയോഗിക്കുന്നു: പരമ്പരാഗത transformer മോഡലുകളിൽ, പൊസിഷണൽ എൻകോഡിംഗ് +E എന്നത് \\(l\\) x \\(d\\) വലിപ്പമുള്ള ഒരു മാട്രിക്‌സാണ്, ഇവിടെ \\(l\\) സീക്വൻസിന്റെ നീളവും \\(d\\) ഹിഡൻ സ്‌റ്റേറ്റിന്റെ +ഡൈമെൻഷനുമാണ്. വളരെ നീണ്ട ടെക്‌സ്‌റ്റുകൾ ഉണ്ടെങ്കിൽ, ഈ മാട്രിക്‌സ് വളരെ വലുതാകുകയും GPU-വിൽ അമിതമായ സ്ഥലം എടുക്കുകയും ചെയ്യാം. ഇത് ലഘൂകരിക്കാൻ, +ആക്‌സിയൽ പൊസിഷണൽ എൻകോഡിംഗുകൾ ആ വലിയ മാട്രിക്‌സ് E-യെ E1, E2 എന്നീ രണ്ട് ചെറിയ മാട്രിക്‌സുകളായി ഫാക്ടറൈസ് ചെയ്യുന്നു; ഇവയുടെ +ഡൈമെൻഷനുകൾ \\(l_{1} \times d_{1}\\) ഉം \\(l_{2} \times d_{2}\\) ഉം ആണ്, അതായത് \\(l_{1} \times l_{2} = l\\) ഉം +\\(d_{1} + d_{2} = d\\) ഉം (നീളങ്ങളുടെ ഗുണനഫലം കാരണം, ഇത് വളരെ ചെറുതായിത്തീരുന്നു). E-യിലെ ടൈം സ്‌റ്റെപ്പ് \\(j\\)-യുടെ +എംബെഡ്ഡിംഗ്, E1-ലെ ടൈംസ്‌റ്റെപ്പ് \\(j \% l1\\)-ന്റെയും E2-ലെ \\(j // l1\\)-ന്റെയും എംബെഡ്ഡിംഗുകൾ +കൂട്ടിച്ചേർത്ത് (concatenate) ലഭിക്കുന്നു. + +## ഉപസംഹാരം[[conclusion]] + +ഈ വിഭാഗത്തിൽ, മൂന്ന് പ്രധാന Transformer ആർക്കിടെക്ചറുകളും ചില പ്രത്യേക അറ്റൻഷൻ മെക്കാനിസങ്ങളും നാം പരിശോധിച്ചു. നിങ്ങളുടെ പ്രത്യേക NLP ടാസ്‌കിന് അനുയോജ്യമായ മോഡൽ തിരഞ്ഞെടുക്കാൻ ഈ ആർക്കിടെക്ചർ വ്യത്യാസങ്ങൾ മനസ്സിലാക്കുന്നത് നിർണ്ണായകമാണ്. + +കോഴ്‌സിൽ മുന്നോട്ട് പോകുമ്പോൾ, ഈ വ്യത്യസ്ത ആർക്കിടെക്ചറുകളുമായി നിങ്ങൾക്ക് പ്രായോഗിക പരിചയം ലഭിക്കുകയും, നിങ്ങളുടെ ആവശ്യങ്ങൾക്ക് അനുസരിച്ച് അവയെ എങ്ങനെ ഫൈൻ-ട്യൂൺ ചെയ്യാമെന്ന് പഠിക്കുകയും ചെയ്യും. അടുത്ത വിഭാഗത്തിൽ, ഈ മോഡലുകൾ വിന്യസിക്കുമ്പോൾ (deploy) നിങ്ങൾ അറിഞ്ഞിരിക്കേണ്ട ചില പരിമിതികളും പക്ഷപാതങ്ങളും (biases) നാം പരിശോധിക്കും. diff --git a/chapters/ml/chapter1/7.mdx b/chapters/ml/chapter1/7.mdx new file mode 100644 index 000000000..f7201b057 --- /dev/null +++ b/chapters/ml/chapter1/7.mdx @@ -0,0 +1,257 @@ + + +# ഗ്രേഡ് ഇല്ലാത്ത ക്വിസ്[[ungraded-quiz]] + + + +ഇതുവരെ, ഈ അധ്യായം ഒട്ടേറെ കാര്യങ്ങൾ കൈകാര്യം ചെയ്തു! എല്ലാ വിശദാംശങ്ങളും പിടികിട്ടിയില്ലെങ്കിൽ വിഷമിക്കേണ്ട; ഇതുവരെ പഠിച്ചത് ഒരു ക്വിസിലൂടെ ഒന്ന് ഓർത്തുനോക്കാനുള്ള അവസരമാണിത്. + +ഈ ക്വിസിന് ഗ്രേഡ് ഇല്ല, അതിനാൽ എത്ര തവണ വേണമെങ്കിലും നിങ്ങൾക്ക് ഇത് ചെയ്യാം. ചില ചോദ്യങ്ങളിൽ ബുദ്ധിമുട്ട് തോന്നിയാൽ, നൽകിയിരിക്കുന്ന സൂചനകൾ പിന്തുടർന്ന് പാഠഭാഗം വീണ്ടും വായിക്കുക. സർട്ടിഫിക്കേഷൻ പരീക്ഷയിൽ ഈ വിഷയങ്ങളെക്കുറിച്ച് വീണ്ടും ചോദ്യങ്ങളുണ്ടാകും. + +### 1. Hub-ൽ പരതി `roberta-large-mnli` ചെക്ക്‌പോയിന്റ് കണ്ടെത്തുക. അത് ഏത് ടാസ്‌ക് ആണ് ചെയ്യുന്നത്? + + +roberta-large-mnli പേജ് ഒന്നുകൂടി നോക്കുക." + }, + { + text: "ടെക്‌സ്‌റ്റ് വർഗ്ഗീകരണം (Text classification)", + explain: "കൂടുതൽ കൃത്യമായി പറഞ്ഞാൽ, രണ്ട് വാക്യങ്ങൾ യുക്തിപരമായി ബന്ധപ്പെട്ടിരിക്കുന്നുണ്ടോ എന്ന് മൂന്ന് ലേബലുകളിലായി (contradiction, neutral, entailment) ഇത് വർഗ്ഗീകരിക്കുന്നു — ഈ ടാസ്‌കിനെ natural language inference എന്നും വിളിക്കുന്നു.", + correct: true + }, + { + text: "ടെക്‌സ്‌റ്റ് ജനറേഷൻ (Text generation)", + explain: "roberta-large-mnli പേജ് ഒന്നുകൂടി നോക്കുക." + } + ]} +/> + +### 2. താഴെ കൊടുത്ത കോഡ് എന്ത് റിട്ടേൺ ചെയ്യും? + +```py +from transformers import pipeline + +ner = pipeline("ner", aggregation_strategy="simple") +ner("My name is Sylvain and I work at Hugging Face in Brooklyn.") +``` + +sentiment-analysis പൈപ്പ്‌ലൈൻ ആയിരിക്കും." + }, + { + text: "ഈ വാക്യം പൂർത്തിയാക്കുന്ന ഒരു ജനറേറ്റ് ചെയ്ത ടെക്‌സ്‌റ്റ് റിട്ടേൺ ചെയ്യും.", + explain: "ഇത് തെറ്റാണ് — അത് ഒരു text-generation പൈപ്പ്‌ലൈൻ ആയിരിക്കും.", + }, + { + text: "വ്യക്തികളെയോ സ്ഥാപനങ്ങളെയോ സ്ഥലങ്ങളെയോ സൂചിപ്പിക്കുന്ന വാക്കുകൾ റിട്ടേൺ ചെയ്യും.", + explain: "കൂടാതെ, aggregation_strategy="simple" ഉപയോഗിക്കുന്നതിനാൽ, \"Hugging Face\" പോലെ ഒരേ എന്റിറ്റിയിൽ പെടുന്ന വാക്കുകളെ ഇത് ഒരുമിച്ച് ഗ്രൂപ്പ് ചെയ്യും.", + correct: true + } + ]} +/> + +### 3. ഈ കോഡ് സാമ്പിളിൽ ... എന്നതിന്റെ സ്ഥാനത്ത് എന്ത് വരണം? + +```py +from transformers import pipeline + +filler = pipeline("fill-mask", model="bert-base-cased") +result = filler("...") +``` + + has been waiting for you.", + explain: "ഇത് തെറ്റാണ്. bert-base-cased മോഡൽ കാർഡ് പരിശോധിച്ച് നിങ്ങളുടെ തെറ്റ് കണ്ടെത്താൻ ശ്രമിക്കുക." + }, + { + text: "This [MASK] has been waiting for you.", + explain: "ഈ മോഡലിന്റെ മാസ്‌ക് ടോക്കൺ [MASK] ആണ്.", + correct: true + }, + { + text: "This man has been waiting for you.", + explain: "ഇത് തെറ്റാണ്. ഈ പൈപ്പ്‌ലൈൻ മറച്ചുവെച്ച വാക്കുകൾ പൂരിപ്പിക്കുന്നതാണ്, അതിനാൽ എവിടെയെങ്കിലും ഒരു മാസ്‌ക് ടോക്കൺ ആവശ്യമാണ്." + } + ]} +/> + +### 4. ഈ കോഡ് എന്തുകൊണ്ട് പരാജയപ്പെടും? + +```py +from transformers import pipeline + +classifier = pipeline("zero-shot-classification") +result = classifier("This is a course about the Transformers library") +``` + +candidate_labels=[...] ഉൾപ്പെടുത്തേണ്ടതുണ്ട്.", + correct: true + }, + { + text: "ഈ പൈപ്പ്‌ലൈനിന് ഒന്നല്ല, നിരവധി വാക്യങ്ങൾ ആവശ്യമാണ്.", + explain: "ഇത് തെറ്റാണ്; എന്നാൽ ശരിയായി ഉപയോഗിക്കുമ്പോൾ, (മറ്റെല്ലാ പൈപ്പ്‌ലൈനുകളെയും പോലെ) ഈ പൈപ്പ്‌ലൈനിനും പ്രോസസ്സ് ചെയ്യാൻ വാക്യങ്ങളുടെ ഒരു ലിസ്‌റ്റ് സ്വീകരിക്കാൻ കഴിയും." + }, + { + text: "🤗 Transformers ലൈബ്രറി, പതിവുപോലെ, തകരാറിലാണ്.", + explain: "ഈ ഉത്തരത്തിന് ഒരു അഭിപ്രായം പറഞ്ഞ് ഞങ്ങൾ മാന്യത നൽകുന്നില്ല!" + }, + { + text: "ഈ പൈപ്പ്‌ലൈനിന് കൂടുതൽ നീളമുള്ള ഇൻപുട്ടുകൾ ആവശ്യമാണ്; ഇത് വളരെ ചെറുതാണ്.", + explain: "ഇത് തെറ്റാണ്. വളരെ നീണ്ട ഒരു ടെക്‌സ്‌റ്റ് ഈ പൈപ്പ്‌ലൈൻ പ്രോസസ്സ് ചെയ്യുമ്പോൾ അത് വെട്ടിച്ചുരുക്കപ്പെടും (truncate) എന്ന് ശ്രദ്ധിക്കുക." + } + ]} +/> + +### 5. "ട്രാൻസ്‌ഫർ ലേണിംഗ്" (transfer learning) എന്നാൽ എന്താണ്? + + + +### 6. ശരിയോ തെറ്റോ? ഒരു ലാംഗ്വേജ് മോഡലിന് അതിന്റെ പ്രീട്രെയിനിംഗിന് സാധാരണയായി ലേബലുകൾ ആവശ്യമില്ല. + +self-supervised ആണ്, അതായത് ലേബലുകൾ ഇൻപുട്ടുകളിൽ നിന്ന് സ്വയമേവ സൃഷ്ടിക്കപ്പെടുന്നു (ഉദാഹരണത്തിന്, അടുത്ത വാക്ക് പ്രവചിക്കുക അല്ലെങ്കിൽ മറച്ചുവെച്ച ചില വാക്കുകൾ പൂരിപ്പിക്കുക).", + correct: true + }, + { + text: "തെറ്റ്", + explain: "ഇത് ശരിയായ ഉത്തരമല്ല." + } + ]} +/> + +### 7. "മോഡൽ", "ആർക്കിടെക്ചർ", "വെയ്‌റ്റുകൾ" എന്നീ പദങ്ങളെ ഏറ്റവും നന്നായി വിവരിക്കുന്ന വാക്യം തിരഞ്ഞെടുക്കുക. + + + + +### 8. ജനറേറ്റ് ചെയ്ത ടെക്‌സ്‌റ്റ് കൊണ്ട് പ്രോംപ്‌റ്റുകൾ പൂർത്തിയാക്കാൻ ഈ മോഡൽ തരങ്ങളിൽ ഏതാണ് നിങ്ങൾ ഉപയോഗിക്കുക? + + + +### 9. ടെക്‌സ്‌റ്റുകൾ സംഗ്രഹിക്കാൻ ഈ മോഡൽ തരങ്ങളിൽ ഏതാണ് നിങ്ങൾ ഉപയോഗിക്കുക? + + + +### 10. ചില ലേബലുകൾ അനുസരിച്ച് ടെക്‌സ്‌റ്റ് ഇൻപുട്ടുകൾ വർഗ്ഗീകരിക്കാൻ ഈ മോഡൽ തരങ്ങളിൽ ഏതാണ് നിങ്ങൾ ഉപയോഗിക്കുക? + + + +### 11. ഒരു മോഡലിൽ കാണുന്ന പക്ഷപാതത്തിന് (bias) സാധ്യമായ ഉറവിടം എന്താകാം? + + diff --git a/chapters/ml/chapter1/8.mdx b/chapters/ml/chapter1/8.mdx new file mode 100644 index 000000000..1384fbb93 --- /dev/null +++ b/chapters/ml/chapter1/8.mdx @@ -0,0 +1,263 @@ +# LLM-കൾ ഉപയോഗിച്ചുള്ള ടെക്‌സ്‌റ്റ് ജനറേഷൻ ഇൻഫറൻസ് — ഒരു ആഴത്തിലുള്ള പഠനം[[inference-with-llms]] + + + + + +ഇതുവരെ നാം ട്രാൻസ്‌ഫോർമർ ആർക്കിടെക്ചറിനെ ടെക്‌സ്‌റ്റ് ക്ലാസിഫിക്കേഷൻ, സംഗ്രഹം (summarization) തുടങ്ങിയ വ്യത്യസ്ത ടാസ്‌ക്കുകളുമായി ബന്ധപ്പെടുത്തിയാണ് പരിചയപ്പെട്ടത്. എന്നാൽ, Large Language Model-കൾ (LLM-കൾ) ഏറ്റവുമധികം ഉപയോഗിക്കപ്പെടുന്നത് ടെക്‌സ്‌റ്റ് ജനറേഷനുവേണ്ടിയാണ്; ഈ അധ്യായത്തിൽ നാം അതാണ് പരിശോധിക്കുന്നത്. + +ഈ പേജിൽ, LLM ഇൻഫറൻസിന്റെ അടിസ്ഥാന ആശയങ്ങൾ നാം പരിശോധിക്കും — ഈ മോഡലുകൾ എങ്ങനെ ടെക്‌സ്‌റ്റ് ഉണ്ടാക്കുന്നു എന്നതും ഇൻഫറൻസ് പ്രക്രിയയിലെ പ്രധാന ഘടകങ്ങൾ ഏതെല്ലാമെന്നതും സമഗ്രമായി മനസ്സിലാക്കാൻ ഇത് സഹായിക്കും. + +## അടിസ്ഥാനങ്ങൾ മനസ്സിലാക്കാം + +നമുക്ക് അടിസ്ഥാന കാര്യങ്ങളിൽനിന്ന് തുടങ്ങാം. ട്രെയിൻ ചെയ്ത ഒരു LLM ഉപയോഗിച്ച്, നൽകിയ ഒരു ഇൻപുട്ട് പ്രോംപ്‌റ്റിൽനിന്ന് മനുഷ്യർ എഴുതുന്നതുപോലുള്ള ടെക്‌സ്‌റ്റ് ഉണ്ടാക്കുന്ന പ്രക്രിയയാണ് ഇൻഫറൻസ് (inference). ഭാഷാ മോഡലുകൾ ട്രെയിനിംഗിൽനിന്ന് നേടിയ അറിവ് ഉപയോഗിച്ച് ഒരു സമയം ഒരു വാക്ക് വീതം മറുപടി രൂപപ്പെടുത്തുന്നു. കോടിക്കണക്കിന് പാരാമീറ്ററുകളിൽനിന്ന് പഠിച്ചെടുത്ത പ്രോബബിലിറ്റികൾ ഉപയോഗിച്ചാണ് മോഡൽ ഒരു ശ്രേണിയിലെ അടുത്ത ടോക്കൺ പ്രവചിക്കുന്നതും ഉണ്ടാക്കുന്നതും. ഈ ക്രമാനുഗതമായ (sequential) ജനറേഷനാണ് LLM-കൾക്ക് യോജിപ്പുള്ളതും സന്ദർഭത്തിന് അനുയോജ്യവുമായ ടെക്‌സ്‌റ്റ് ഉണ്ടാക്കാൻ കഴിവ് നൽകുന്നത്. + +## അറ്റൻഷന്റെ പങ്ക് + +LLM-കൾക്ക് സന്ദർഭം മനസ്സിലാക്കാനും യോജിപ്പുള്ള മറുപടികൾ ഉണ്ടാക്കാനും കഴിവ് നൽകുന്നത് അറ്റൻഷൻ (attention) മെക്കാനിസമാണ്. അടുത്ത വാക്ക് പ്രവചിക്കുമ്പോൾ, ഒരു വാക്യത്തിലെ എല്ലാ വാക്കുകൾക്കും ഒരേ പ്രാധാന്യമല്ല ഉള്ളത് — ഉദാഹരണത്തിന്, *"The capital of France is ..."* എന്ന വാക്യത്തിൽ, അടുത്തതായി "Paris" വരണം എന്ന് നിർണ്ണയിക്കാൻ "France", "capital" എന്ന വാക്കുകളാണ് നിർണ്ണായകം. പ്രസക്തമായ വിവരങ്ങളിൽ ശ്രദ്ധ കേന്ദ്രീകരിക്കാനുള്ള ഈ കഴിവിനെയാണ് നാം അറ്റൻഷൻ എന്ന് വിളിക്കുന്നത്. + +അറ്റൻഷന്റെ ദൃശ്യാവിഷ്കാരം (Gif) + +അടുത്ത ടോക്കൺ പ്രവചിക്കാൻ ഏറ്റവും പ്രസക്തമായ വാക്കുകൾ കണ്ടെത്തുന്ന ഈ പ്രക്രിയ അസാധാരണമായി ഫലപ്രദമാണെന്ന് തെളിഞ്ഞിട്ടുണ്ട്. LLM-കളെ ട്രെയിൻ ചെയ്യുന്നതിന്റെ അടിസ്ഥാന തത്വം — അടുത്ത ടോക്കൺ പ്രവചിക്കുക — BERT, GPT-2 എന്നിവയുടെ കാലം മുതൽ ഏറെക്കുറെ മാറ്റമില്ലാതെ തുടരുന്നുണ്ടെങ്കിലും, ന്യൂറൽ നെറ്റ്‌വർക്കുകളെ വലുതാക്കുന്നതിലും (scaling), കൂടുതൽ കൂടുതൽ നീളമുള്ള ശ്രേണികളിൽ കുറഞ്ഞ ചെലവിൽ അറ്റൻഷൻ മെക്കാനിസം പ്രവർത്തിപ്പിക്കുന്നതിലും കാര്യമായ പുരോഗതി ഉണ്ടായിട്ടുണ്ട്. + +> [!TIP] +> ചുരുക്കത്തിൽ, യോജിപ്പുള്ളതും സന്ദർഭം അറിയുന്നതുമായ ടെക്‌സ്‌റ്റ് ഉണ്ടാക്കാൻ LLM-കൾക്ക് കഴിയുന്നതിന്റെ താക്കോൽ അറ്റൻഷൻ മെക്കാനിസമാണ്. ഇതാണ് ആധുനിക LLM-കളെ മുൻതലമുറ ഭാഷാ മോഡലുകളിൽനിന്ന് വേറിട്ടുനിർത്തുന്നത്. + +### കോൺടെക്‌സ്‌റ്റ് ലെങ്ത്തും അറ്റൻഷൻ സ്പാനും + +അറ്റൻഷൻ എന്താണെന്ന് മനസ്സിലായ സ്ഥിതിക്ക്, ഒരു LLM-ന് യഥാർത്ഥത്തിൽ എത്ര സന്ദർഭം (context) കൈകാര്യം ചെയ്യാൻ കഴിയും എന്ന് നോക്കാം. ഇത് നമ്മെ കോൺടെക്‌സ്‌റ്റ് ലെങ്ത് (context length), അഥവാ മോഡലിന്റെ 'അറ്റൻഷൻ സ്പാൻ' എന്ന ആശയത്തിലേക്ക് എത്തിക്കുന്നു. + +ഒരു LLM-ന് ഒരേസമയം പ്രോസസ്സ് ചെയ്യാൻ കഴിയുന്ന പരമാവധി ടോക്കണുകളുടെ (വാക്കുകൾ അല്ലെങ്കിൽ വാക്കുകളുടെ ഭാഗങ്ങൾ) എണ്ണത്തെയാണ് കോൺടെക്‌സ്‌റ്റ് ലെങ്ത് എന്ന് പറയുന്നത്. ഇതിനെ മോഡലിന്റെ വർക്കിംഗ് മെമ്മറിയുടെ വലുപ്പമായി കരുതാം. + +ഈ കഴിവുകൾക്ക് പല പ്രായോഗിക ഘടകങ്ങളും പരിമിതികൾ സൃഷ്ടിക്കുന്നു: +- മോഡലിന്റെ ആർക്കിടെക്ചറും വലുപ്പവും +- ലഭ്യമായ കമ്പ്യൂട്ടേഷണൽ വിഭവങ്ങൾ +- ഇൻപുട്ടിന്റെയും ആവശ്യമുള്ള ഔട്ട്‌പുട്ടിന്റെയും സങ്കീർണ്ണത + +ഒരു ഉത്തമലോകത്തിൽ നമുക്ക് പരിധിയില്ലാത്ത കോൺടെക്‌സ്‌റ്റ് മോഡലിന് നൽകാമായിരുന്നു; എന്നാൽ ഹാർഡ്‌വെയർ പരിമിതികളും കമ്പ്യൂട്ടേഷണൽ ചെലവുകളും ഇത് അപ്രായോഗികമാക്കുന്നു. അതുകൊണ്ടാണ് കഴിവും കാര്യക്ഷമതയും തമ്മിൽ സന്തുലനം നിലനിർത്താൻ വ്യത്യസ്ത മോഡലുകൾ വ്യത്യസ്ത കോൺടെക്‌സ്‌റ്റ് ലെങ്ത്തുകളോടെ രൂപകൽപ്പന ചെയ്യപ്പെടുന്നത്. + +> [!TIP] +> ഒരു മറുപടി ഉണ്ടാക്കുമ്പോൾ മോഡലിന് ഒരേസമയം പരിഗണിക്കാൻ കഴിയുന്ന പരമാവധി ടോക്കണുകളുടെ എണ്ണമാണ് കോൺടെക്‌സ്‌റ്റ് ലെങ്ത്. + +### പ്രോംപ്‌റ്റിംഗിന്റെ കല + +LLM-കൾക്ക് വിവരങ്ങൾ നൽകുമ്പോൾ, LLM-ന്റെ ജനറേഷനെ നമുക്ക് ആവശ്യമുള്ള ഔട്ട്‌പുട്ടിലേക്ക് നയിക്കുന്ന രീതിയിലാണ് നാം ഇൻപുട്ട് ക്രമീകരിക്കുന്നത്. ഇതിനെ _പ്രോംപ്‌റ്റിംഗ്_ (prompting) എന്ന് വിളിക്കുന്നു. + +LLM-കൾ വിവരങ്ങൾ എങ്ങനെ പ്രോസസ്സ് ചെയ്യുന്നു എന്ന് മനസ്സിലാക്കുന്നത് മികച്ച പ്രോംപ്‌റ്റുകൾ തയ്യാറാക്കാൻ നമ്മെ സഹായിക്കും. ഓരോ ഇൻപുട്ട് ടോക്കണിന്റെയും പ്രാധാന്യം വിശകലനം ചെയ്ത് അടുത്ത ടോക്കൺ പ്രവചിക്കുകയാണ് മോഡലിന്റെ പ്രധാന ജോലി എന്നതിനാൽ, നിങ്ങളുടെ ഇൻപുട്ട് ശ്രേണിയിലെ വാക്കുകളുടെ തിരഞ്ഞെടുപ്പ് നിർണ്ണായകമാകുന്നു. + +> [!TIP] +> പ്രോംപ്‌റ്റ് ശ്രദ്ധയോടെ രൂപകൽപ്പന ചെയ്യുന്നത് **LLM-ന്റെ ജനറേഷനെ ആവശ്യമുള്ള ഔട്ട്‌പുട്ടിലേക്ക് നയിക്കുന്നത്** എളുപ്പമാക്കുന്നു. + +## രണ്ട് ഘട്ടങ്ങളുള്ള ഇൻഫറൻസ് പ്രക്രിയ + +അടിസ്ഥാന ഘടകങ്ങൾ മനസ്സിലായ സ്ഥിതിക്ക്, LLM-കൾ യഥാർത്ഥത്തിൽ എങ്ങനെ ടെക്‌സ്‌റ്റ് ഉണ്ടാക്കുന്നു എന്ന് ആഴത്തിൽ നോക്കാം. ഈ പ്രക്രിയയെ പ്രധാനമായി രണ്ട് ഘട്ടങ്ങളായി തിരിക്കാം: പ്രീഫിൽ (prefill), ഡീകോഡ് (decode). ഒരു അസംബ്ലി ലൈൻ പോലെ ഈ ഘട്ടങ്ങൾ ഒരുമിച്ച് പ്രവർത്തിക്കുന്നു; യോജിപ്പുള്ള ടെക്‌സ്‌റ്റ് ഉണ്ടാക്കുന്നതിൽ ഓരോന്നിനും നിർണ്ണായക പങ്കുണ്ട്. + +### പ്രീഫിൽ ഘട്ടം + +പ്രീഫിൽ ഘട്ടം പാചകത്തിലെ ഒരുക്കത്തിന്റെ ഘട്ടം പോലെയാണ് — ആദ്യ ചേരുവകളെല്ലാം ഇവിടെയാണ് പ്രോസസ്സ് ചെയ്ത് തയ്യാറാക്കുന്നത്. ഈ ഘട്ടത്തിൽ മൂന്ന് പ്രധാന പടികളുണ്ട്: + +1. **ടോക്കണൈസേഷൻ**: ഇൻപുട്ട് ടെക്‌സ്‌റ്റിനെ ടോക്കണുകളാക്കി മാറ്റുന്നു (മോഡലിന് മനസ്സിലാകുന്ന അടിസ്ഥാന നിർമ്മാണഘടകങ്ങളായി ഇവയെ കരുതാം) +2. **എംബെഡ്ഡിംഗ് പരിവർത്തനം**: ഈ ടോക്കണുകളെ അവയുടെ അർത്ഥം ഉൾക്കൊള്ളുന്ന സംഖ്യാരൂപങ്ങളാക്കി (numerical representations) മാറ്റുന്നു +3. **പ്രാരംഭ പ്രോസസ്സിംഗ്**: സന്ദർഭത്തെക്കുറിച്ച് സമ്പന്നമായ ഒരു ധാരണ ഉണ്ടാക്കാൻ ഈ എംബെഡ്ഡിംഗുകളെ മോഡലിന്റെ ന്യൂറൽ നെറ്റ്‌വർക്കുകളിലൂടെ കടത്തിവിടുന്നു + +എല്ലാ ഇൻപുട്ട് ടോക്കണുകളും ഒരേസമയം പ്രോസസ്സ് ചെയ്യേണ്ടതുകൊണ്ട് ഈ ഘട്ടത്തിന് ധാരാളം കമ്പ്യൂട്ടേഷൻ ആവശ്യമാണ്. ഒരു മറുപടി എഴുതാൻ തുടങ്ങുന്നതിനുമുമ്പ് ഒരു ഖണ്ഡിക മുഴുവൻ വായിച്ച് മനസ്സിലാക്കുന്നതുപോലെയാണിത്. + +താഴെയുള്ള ഇന്ററാക്ടീവ് പ്ലേഗ്രൗണ്ടിൽ വ്യത്യസ്ത ടോക്കണൈസറുകൾ നിങ്ങൾക്ക് പരീക്ഷിച്ചുനോക്കാം: + + + +### ഡീകോഡ് ഘട്ടം + +പ്രീഫിൽ ഘട്ടം ഇൻപുട്ട് പ്രോസസ്സ് ചെയ്തുകഴിഞ്ഞാൽ, നാം ഡീകോഡ് ഘട്ടത്തിലേക്ക് കടക്കുന്നു — യഥാർത്ഥ ടെക്‌സ്‌റ്റ് ജനറേഷൻ നടക്കുന്നത് ഇവിടെയാണ്. ഓട്ടോറിഗ്രസ്സീവ് (autoregressive) പ്രക്രിയ എന്ന് നാം വിളിക്കുന്ന രീതിയിൽ (ഓരോ പുതിയ ടോക്കണും അതിന് മുമ്പുള്ള എല്ലാ ടോക്കണുകളെയും ആശ്രയിച്ചിരിക്കുന്നു) മോഡൽ ഒരു സമയം ഒരു ടോക്കൺ വീതം ഉണ്ടാക്കുന്നു. + +ഡീകോഡ് ഘട്ടത്തിൽ, ഓരോ പുതിയ ടോക്കണിനും വേണ്ടി നടക്കുന്ന പ്രധാന പടികൾ ഇവയാണ്: +1. **അറ്റൻഷൻ കണക്കുകൂട്ടൽ**: സന്ദർഭം മനസ്സിലാക്കാൻ മുമ്പുള്ള എല്ലാ ടോക്കണുകളിലേക്കും തിരിഞ്ഞുനോക്കുന്നു +2. **പ്രോബബിലിറ്റി കണക്കുകൂട്ടൽ**: സാധ്യമായ ഓരോ അടുത്ത ടോക്കണിന്റെയും സാധ്യത നിർണ്ണയിക്കുന്നു +3. **ടോക്കൺ തിരഞ്ഞെടുപ്പ്**: ഈ പ്രോബബിലിറ്റികളെ അടിസ്ഥാനമാക്കി അടുത്ത ടോക്കൺ തിരഞ്ഞെടുക്കുന്നു +4. **തുടരണോ എന്ന പരിശോധന**: ജനറേഷൻ തുടരണോ നിർത്തണോ എന്ന് തീരുമാനിക്കുന്നു + +മുമ്പ് ഉണ്ടാക്കിയ എല്ലാ ടോക്കണുകളും അവയ്ക്കിടയിലുള്ള ബന്ധങ്ങളും മോഡലിന് ഓർത്തുവയ്ക്കേണ്ടതുകൊണ്ട് ഈ ഘട്ടത്തിന് ധാരാളം മെമ്മറി ആവശ്യമാണ്. + +## സാംപ്ലിംഗ് സ്ട്രാറ്റജികൾ + +മോഡൽ എങ്ങനെ ടെക്‌സ്‌റ്റ് ഉണ്ടാക്കുന്നു എന്ന് മനസ്സിലായ സ്ഥിതിക്ക്, ഈ ജനറേഷൻ പ്രക്രിയയെ നിയന്ത്രിക്കാനുള്ള വിവിധ മാർഗ്ഗങ്ങൾ നോക്കാം. ഒരു എഴുത്തുകാരൻ കൂടുതൽ സർഗ്ഗാത്മകമാകണോ കൂടുതൽ കൃത്യമാകണോ എന്ന് തിരഞ്ഞെടുക്കുന്നതുപോലെ, മോഡൽ ടോക്കണുകൾ തിരഞ്ഞെടുക്കുന്ന രീതി നമുക്ക് ക്രമീകരിക്കാം. + +ഈ Space-ൽ SmolLM2 ഉപയോഗിച്ച് അടിസ്ഥാന ഡീകോഡിംഗ് പ്രക്രിയ നിങ്ങൾക്ക് സ്വയം പരീക്ഷിക്കാം (ഓർക്കുക, ഒരു **EOS** ടോക്കണിൽ എത്തുന്നതുവരെ ഇത് ഡീകോഡ് ചെയ്യും; ഈ മോഡലിന് അത് **<|im_end|>** ആണ്): + + + +### ടോക്കൺ തിരഞ്ഞെടുപ്പ് മനസ്സിലാക്കാം: പ്രോബബിലിറ്റികളിൽനിന്ന് ടോക്കൺ തിരഞ്ഞെടുപ്പുകളിലേക്ക് + +അടുത്ത ടോക്കൺ തിരഞ്ഞെടുക്കേണ്ടിവരുമ്പോൾ, മോഡൽ തന്റെ വൊക്കാബുലറിയിലെ ഓരോ വാക്കിനുമുള്ള അസംസ്കൃത പ്രോബബിലിറ്റികളിൽനിന്നാണ് (ഇവയെ ലോജിറ്റ്‌സ് — logits — എന്ന് വിളിക്കുന്നു) തുടങ്ങുന്നത്. എന്നാൽ ഈ പ്രോബബിലിറ്റികളെ യഥാർത്ഥ തിരഞ്ഞെടുപ്പുകളാക്കി മാറ്റുന്നത് എങ്ങനെയാണ്? ഈ പ്രക്രിയ പടിപടിയായി നോക്കാം: + +![image](https://huggingface.co/reasoning-course/images/resolve/main/inference/1.png) + +1. **റോ ലോജിറ്റ്‌സ് (Raw Logits)**: സാധ്യമായ ഓരോ അടുത്ത വാക്കിനെക്കുറിച്ചുമുള്ള മോഡലിന്റെ ആദ്യ ഉൾവിളി (gut feeling) ആയി ഇവയെ കരുതാം +2. **ടെമ്പറേച്ചർ നിയന്ത്രണം (Temperature Control)**: ഒരു സർഗ്ഗാത്മകതാ ഡയൽ പോലെ — ഉയർന്ന മൂല്യങ്ങൾ (>1.0) തിരഞ്ഞെടുപ്പുകളെ കൂടുതൽ ക്രമരഹിതവും സർഗ്ഗാത്മകവുമാക്കുന്നു, താഴ്ന്ന മൂല്യങ്ങൾ (<1.0) അവയെ കൂടുതൽ ഏകാഗ്രവും നിർണ്ണീതവുമാക്കുന്നു (deterministic) +3. **Top-p (Nucleus) സാംപ്ലിംഗ്**: സാധ്യമായ എല്ലാ വാക്കുകളും പരിഗണിക്കുന്നതിനുപകരം, നാം തിരഞ്ഞെടുത്ത പ്രോബബിലിറ്റി പരിധിയിലേക്ക് (ഉദാ. മുൻനിരയിലെ 90%) കൂട്ടിച്ചേരുന്ന ഏറ്റവും സാധ്യതയുള്ള വാക്കുകൾ മാത്രം നോക്കുന്നു +4. **Top-k ഫിൽറ്ററിംഗ്**: ഏറ്റവും സാധ്യതയുള്ള k അടുത്ത വാക്കുകൾ മാത്രം പരിഗണിക്കുന്ന ഒരു ബദൽ രീതി + +### ആവർത്തനം നിയന്ത്രിക്കൽ: ഔട്ട്‌പുട്ട് പുതുമയോടെ നിലനിർത്താം + +LLM-കളിലെ ഒരു സാധാരണ വെല്ലുവിളി അവ സ്വയം ആവർത്തിക്കാനുള്ള പ്രവണതയാണ് — ഒരേ കാര്യങ്ങളിലേക്ക് വീണ്ടും വീണ്ടും മടങ്ങിവരുന്ന ഒരു പ്രാസംഗികനെപ്പോലെ. ഇത് പരിഹരിക്കാൻ നാം രണ്ട് തരം പെനാൽറ്റികൾ ഉപയോഗിക്കുന്നു: + +1. **പ്രസൻസ് പെനാൽറ്റി (Presence Penalty)**: മുമ്പ് പ്രത്യക്ഷപ്പെട്ട ഏതൊരു ടോക്കണിനും, എത്ര തവണ വന്നു എന്നത് പരിഗണിക്കാതെ, ചുമത്തുന്ന ഒരു നിശ്ചിത പെനാൽറ്റി. ഒരേ വാക്കുകൾ മോഡൽ വീണ്ടും ഉപയോഗിക്കുന്നത് തടയാൻ ഇത് സഹായിക്കുന്നു. +2. **ഫ്രീക്വൻസി പെനാൽറ്റി (Frequency Penalty)**: ഒരു ടോക്കൺ എത്ര തവണ ഉപയോഗിച്ചു എന്നതിനനുസരിച്ച് വർദ്ധിക്കുന്ന ഒരു അനുപാതിക പെനാൽറ്റി. ഒരു വാക്ക് എത്ര കൂടുതൽ പ്രത്യക്ഷപ്പെടുന്നുവോ, അത്രയും കുറവായിരിക്കും അത് വീണ്ടും തിരഞ്ഞെടുക്കപ്പെടാനുള്ള സാധ്യത. + +![image](https://huggingface.co/reasoning-course/images/resolve/main/inference/2.png) + +ടോക്കൺ തിരഞ്ഞെടുപ്പ് പ്രക്രിയയുടെ തുടക്കത്തിൽത്തന്നെ ഈ പെനാൽറ്റികൾ പ്രയോഗിക്കുന്നു; മറ്റ് സാംപ്ലിംഗ് സ്ട്രാറ്റജികൾ പ്രയോഗിക്കുന്നതിനുമുമ്പ് അസംസ്കൃത പ്രോബബിലിറ്റികളെ ഇവ ക്രമീകരിക്കുന്നു. പുതിയ പദങ്ങൾ പരീക്ഷിക്കാൻ മോഡലിനെ പ്രോത്സാഹിപ്പിക്കുന്ന മൃദുവായ തള്ളലുകളായി ഇവയെ കരുതാം. + +### ജനറേഷൻ ദൈർഘ്യം നിയന്ത്രിക്കൽ: അതിരുകൾ നിശ്ചയിക്കാം + +ഒരു നല്ല കഥയ്ക്ക് ശരിയായ വേഗവും നീളവും വേണ്ടതുപോലെ, നമ്മുടെ LLM എത്ര ടെക്‌സ്‌റ്റ് ഉണ്ടാക്കണം എന്ന് നിയന്ത്രിക്കാനുള്ള മാർഗ്ഗങ്ങളും നമുക്ക് വേണം. പ്രായോഗിക ആപ്ലിക്കേഷനുകളിൽ ഇത് നിർണ്ണായകമാണ് — ഒരു ട്വീറ്റിന്റെ നീളമുള്ള മറുപടിയാണോ അതോ ഒരു പൂർണ്ണ ബ്ലോഗ് പോസ്റ്റാണോ നാം ഉണ്ടാക്കുന്നത് എന്നതിനനുസരിച്ച്. + +ജനറേഷൻ ദൈർഘ്യം നമുക്ക് പല രീതികളിൽ നിയന്ത്രിക്കാം: +1. **ടോക്കൺ പരിധികൾ**: ഏറ്റവും കുറഞ്ഞതും കൂടിയതുമായ ടോക്കൺ എണ്ണം നിശ്ചയിക്കുക +2. **സ്റ്റോപ്പ് സീക്വൻസുകൾ**: ജനറേഷന്റെ അവസാനം സൂചിപ്പിക്കുന്ന നിശ്ചിത പാറ്റേണുകൾ നിർവചിക്കുക +3. **എൻഡ്-ഓഫ്-സീക്വൻസ് കണ്ടെത്തൽ**: മോഡലിനെ സ്വാഭാവികമായി മറുപടി അവസാനിപ്പിക്കാൻ അനുവദിക്കുക + +ഉദാഹരണത്തിന്, ഒരു ഖണ്ഡിക മാത്രം ഉണ്ടാക്കണമെങ്കിൽ, പരമാവധി 100 ടോക്കണുകൾ എന്ന് നിശ്ചയിക്കുകയും "\n\n" ഒരു സ്റ്റോപ്പ് സീക്വൻസായി ഉപയോഗിക്കുകയും ചെയ്യാം. ഇത് നമ്മുടെ ഔട്ട്‌പുട്ട് ഏകാഗ്രവും ഉദ്ദേശ്യത്തിന് അനുയോജ്യമായ വലുപ്പത്തിലുള്ളതുമായി തുടരുന്നു എന്ന് ഉറപ്പാക്കുന്നു. + +![image](https://huggingface.co/reasoning-course/images/resolve/main/inference/3.png) + +### ബീം സെർച്ച്: കൂടുതൽ യോജിപ്പിനായി മുന്നോട്ട് നോക്കാം + +ഇതുവരെ നാം ചർച്ച ചെയ്ത സ്ട്രാറ്റജികൾ ഒരു സമയം ഒരു ടോക്കൺ വീതം തീരുമാനങ്ങൾ എടുക്കുമ്പോൾ, ബീം സെർച്ച് (beam search) കൂടുതൽ സമഗ്രമായ ഒരു സമീപനമാണ് സ്വീകരിക്കുന്നത്. ഓരോ പടിയിലും ഒരൊറ്റ തിരഞ്ഞെടുപ്പിൽ ഉറച്ചുനിൽക്കുന്നതിനുപകരം, ഇത് സാധ്യമായ പല പാതകളും ഒരേസമയം പരിശോധിക്കുന്നു — പല നീക്കങ്ങൾ മുന്നോട്ട് ചിന്തിക്കുന്ന ഒരു ചെസ്സ് കളിക്കാരനെപ്പോലെ. + +![image](https://huggingface.co/reasoning-course/images/resolve/main/inference/4.png) + +ഇത് പ്രവർത്തിക്കുന്നത് ഇങ്ങനെയാണ്: +1. ഓരോ പടിയിലും ഒന്നിലധികം സ്ഥാനാർത്ഥി ശ്രേണികൾ (സാധാരണയായി 5-10) നിലനിർത്തുന്നു +2. ഓരോ സ്ഥാനാർത്ഥിക്കും അടുത്ത ടോക്കണിനുള്ള പ്രോബബിലിറ്റികൾ കണക്കുകൂട്ടുന്നു +3. ശ്രേണികളുടെയും അടുത്ത ടോക്കണുകളുടെയും ഏറ്റവും സാധ്യതയുള്ള സംയോജനങ്ങൾ മാത്രം നിലനിർത്തുന്നു +4. ആവശ്യമുള്ള ദൈർഘ്യത്തിലോ സ്റ്റോപ്പ് വ്യവസ്ഥയിലോ എത്തുന്നതുവരെ ഈ പ്രക്രിയ തുടരുന്നു +5. മൊത്തത്തിൽ ഏറ്റവും ഉയർന്ന പ്രോബബിലിറ്റിയുള്ള ശ്രേണി തിരഞ്ഞെടുക്കുന്നു + +ബീം സെർച്ച് ദൃശ്യരൂപത്തിൽ ഇവിടെ നിങ്ങൾക്ക് പരിശോധിക്കാം: + + + +ഈ സമീപനം പലപ്പോഴും കൂടുതൽ യോജിപ്പുള്ളതും വ്യാകരണപരമായി ശരിയായതുമായ ടെക്‌സ്‌റ്റ് ഉണ്ടാക്കുന്നു; എന്നാൽ ലളിതമായ രീതികളെക്കാൾ കൂടുതൽ കമ്പ്യൂട്ടേഷണൽ വിഭവങ്ങൾ ഇതിന് ആവശ്യമാണ്. + +## പ്രായോഗിക വെല്ലുവിളികളും ഒപ്റ്റിമൈസേഷനും + +LLM ഇൻഫറൻസിനെക്കുറിച്ചുള്ള നമ്മുടെ പര്യവേക്ഷണം അവസാനിപ്പിക്കുന്നതിനുമുമ്പ്, ഈ മോഡലുകൾ ഡിപ്ലോയ് ചെയ്യുമ്പോൾ നിങ്ങൾ നേരിടേണ്ടിവരുന്ന പ്രായോഗിക വെല്ലുവിളികളും, അവയുടെ പ്രകടനം എങ്ങനെ അളക്കാമെന്നും ഒപ്റ്റിമൈസ് ചെയ്യാമെന്നും നോക്കാം. + +### പ്രധാന പെർഫോമൻസ് മെട്രിക്കുകൾ + +LLM-കളുമായി പ്രവർത്തിക്കുമ്പോൾ, നാല് നിർണ്ണായക മെട്രിക്കുകൾ നിങ്ങളുടെ ഇംപ്ലിമെന്റേഷൻ തീരുമാനങ്ങളെ രൂപപ്പെടുത്തും: + +1. **Time to First Token (TTFT)**: എത്ര വേഗത്തിൽ ആദ്യ മറുപടി ലഭിക്കും? ഉപയോക്തൃ അനുഭവത്തിന് ഇത് നിർണ്ണായകമാണ്; പ്രധാനമായും പ്രീഫിൽ ഘട്ടമാണ് ഇതിനെ സ്വാധീനിക്കുന്നത്. +2. **Time Per Output Token (TPOT)**: തുടർന്നുള്ള ടോക്കണുകൾ എത്ര വേഗത്തിൽ ഉണ്ടാക്കാൻ കഴിയും? ഇത് മൊത്തത്തിലുള്ള ജനറേഷൻ വേഗം നിർണ്ണയിക്കുന്നു. +3. **Throughput**: ഒരേസമയം എത്ര അഭ്യർത്ഥനകൾ (requests) കൈകാര്യം ചെയ്യാൻ കഴിയും? ഇത് സ്കെയിലിംഗിനെയും ചെലവ് കാര്യക്ഷമതയെയും ബാധിക്കുന്നു. +4. **VRAM ഉപയോഗം**: എത്ര GPU മെമ്മറി ആവശ്യമാണ്? യഥാർത്ഥ ആപ്ലിക്കേഷനുകളിൽ ഇത് പലപ്പോഴും പ്രധാന പരിമിതിയായി മാറുന്നു. + +### കോൺടെക്‌സ്‌റ്റ് ലെങ്ത് എന്ന വെല്ലുവിളി + +LLM ഇൻഫറൻസിലെ ഏറ്റവും പ്രധാനപ്പെട്ട വെല്ലുവിളികളിലൊന്ന് കോൺടെക്‌സ്‌റ്റ് ലെങ്ത് ഫലപ്രദമായി കൈകാര്യം ചെയ്യുന്നതാണ്. നീളമുള്ള കോൺടെക്‌സ്‌റ്റുകൾ കൂടുതൽ വിവരങ്ങൾ നൽകുന്നു, എന്നാൽ അവയ്ക്ക് കാര്യമായ ചെലവുകളുമുണ്ട്: + +- **മെമ്മറി ഉപയോഗം**: കോൺടെക്‌സ്‌റ്റ് ലെങ്ത്തിനനുസരിച്ച് ക്വാഡ്രാറ്റിക് ആയി (quadratically) വർദ്ധിക്കുന്നു +- **പ്രോസസ്സിംഗ് വേഗം**: നീളമുള്ള കോൺടെക്‌സ്‌റ്റുകളിൽ രേഖീയമായി (linearly) കുറയുന്നു +- **വിഭവ വിന്യാസം**: VRAM ഉപയോഗത്തിന്റെ ശ്രദ്ധാപൂർവ്വമായ സന്തുലനം ആവശ്യമാണ് + +[Qwen2.5-1M](https://huggingface.co/Qwen/Qwen2.5-14B-Instruct-1M) പോലുള്ള സമീപകാല മോഡലുകൾ 1M ടോക്കണുകളുടെ ശ്രദ്ധേയമായ കോൺടെക്‌സ്‌റ്റ് വിൻഡോ നൽകുന്നു; എന്നാൽ ഇതിന് വളരെ മന്ദഗതിയിലുള്ള ഇൻഫറൻസ് സമയം എന്ന വില കൊടുക്കേണ്ടിവരുന്നു. നിങ്ങളുടെ പ്രത്യേക ഉപയോഗത്തിന് ശരിയായ സന്തുലനം കണ്ടെത്തുന്നതാണ് ഇവിടെ പ്രധാനം. + + +
+
+
+
+ ഇൻപുട്ട് ടെക്‌സ്‌റ്റ് (അസംസ്കൃതം) +
+
→
+
+ ടോക്കണൈസ് ചെയ്ത ഇൻപുട്ട് +
+
+
+
+ കോൺടെക്‌സ്‌റ്റ് വിൻഡോ
(ഉദാ. 4K ടോക്കണുകൾ) +
+
+
+
+
+
+
+
+
+
+
+ മെമ്മറി ഉപയോഗം
∝ Length² +
+
+
+
+ പ്രോസസ്സിംഗ് സമയം
∝ Length +
+
+
+
+
+ +### KV കാഷ് ഒപ്റ്റിമൈസേഷൻ + +ഈ വെല്ലുവിളികൾ പരിഹരിക്കാനുള്ള ഏറ്റവും ശക്തമായ ഒപ്റ്റിമൈസേഷനുകളിലൊന്ന് KV (Key-Value) കാഷിംഗ് ആണ്. ഇടക്കാല കണക്കുകൂട്ടലുകൾ സംഭരിച്ച് വീണ്ടും ഉപയോഗിക്കുന്നതിലൂടെ ഈ വിദ്യ ഇൻഫറൻസ് വേഗം കാര്യമായി മെച്ചപ്പെടുത്തുന്നു. ഈ ഒപ്റ്റിമൈസേഷൻ: +- ആവർത്തിച്ചുള്ള കണക്കുകൂട്ടലുകൾ കുറയ്ക്കുന്നു +- ജനറേഷൻ വേഗം മെച്ചപ്പെടുത്തുന്നു +- നീളമുള്ള കോൺടെക്‌സ്‌റ്റുള്ള ജനറേഷനെ പ്രായോഗികമാക്കുന്നു + +ഇതിന്റെ വിലയായി അധിക മെമ്മറി ഉപയോഗം വേണ്ടിവരും; എന്നാൽ പ്രകടനത്തിലെ നേട്ടങ്ങൾ സാധാരണയായി ഈ ചെലവിനെ ബഹുദൂരം മറികടക്കുന്നു. + +## ഉപസംഹാരം + +ശക്തമായ ഈ മോഡലുകൾ ഫലപ്രദമായി ഡിപ്ലോയ് ചെയ്യാനും ഒപ്റ്റിമൈസ് ചെയ്യാനും LLM ഇൻഫറൻസ് മനസ്സിലാക്കുന്നത് നിർണ്ണായകമാണ്. നാം പരിശോധിച്ച പ്രധാന ഘടകങ്ങൾ: + +- അറ്റൻഷന്റെയും കോൺടെക്‌സ്‌റ്റിന്റെയും അടിസ്ഥാന പങ്ക് +- രണ്ട് ഘട്ടങ്ങളുള്ള ഇൻഫറൻസ് പ്രക്രിയ +- ജനറേഷൻ നിയന്ത്രിക്കാനുള്ള വിവിധ സാംപ്ലിംഗ് സ്ട്രാറ്റജികൾ +- പ്രായോഗിക വെല്ലുവിളികളും ഒപ്റ്റിമൈസേഷനുകളും + +ഈ ആശയങ്ങളിൽ പ്രാവീണ്യം നേടുന്നതിലൂടെ, LLM-കളെ ഫലപ്രദമായും കാര്യക്ഷമമായും ഉപയോഗിക്കുന്ന ആപ്ലിക്കേഷനുകൾ നിർമ്മിക്കാൻ നിങ്ങൾ കൂടുതൽ സജ്ജരാകും. + +LLM ഇൻഫറൻസ് എന്ന മേഖല അതിവേഗം വികസിച്ചുകൊണ്ടിരിക്കുന്നു എന്നും, പുതിയ വിദ്യകളും ഒപ്റ്റിമൈസേഷനുകളും നിരന്തരം ഉയർന്നുവരുന്നുണ്ട് എന്നും ഓർക്കുക. ജിജ്ഞാസ നിലനിർത്തുക; നിങ്ങളുടെ പ്രത്യേക ഉപയോഗങ്ങൾക്ക് ഏറ്റവും അനുയോജ്യമായത് കണ്ടെത്താൻ വ്യത്യസ്ത സമീപനങ്ങൾ പരീക്ഷിച്ചുകൊണ്ടിരിക്കുക. diff --git a/chapters/ml/chapter1/9.mdx b/chapters/ml/chapter1/9.mdx new file mode 100644 index 000000000..86a9d76e9 --- /dev/null +++ b/chapters/ml/chapter1/9.mdx @@ -0,0 +1,32 @@ +# പക്ഷപാതവും പരിമിതികളും[[bias-and-limitations]] + + + +പ്രീട്രെയിൻ ചെയ്ത ഒരു മോഡലോ ഫൈൻ-ട്യൂൻ ചെയ്ത ഒരു പതിപ്പോ പ്രൊഡക്ഷനിൽ ഉപയോഗിക്കാനാണ് നിങ്ങളുടെ ഉദ്ദേശ്യമെങ്കിൽ, ഈ മോഡലുകൾ ശക്തമായ ടൂളുകളാണെങ്കിലും അവയ്ക്ക് പരിമിതികളുണ്ടെന്ന് ദയവായി ഓർക്കുക. അവയിൽ ഏറ്റവും വലുത് ഇതാണ്: വലിയ അളവിലുള്ള ഡേറ്റയിൽ പ്രീട്രെയിനിംഗ് സാധ്യമാക്കാൻ, ഗവേഷകർ പലപ്പോഴും കണ്ടെത്താനാവുന്ന എല്ലാ ഉള്ളടക്കവും സ്‌ക്രേപ്പ് ചെയ്യുന്നു — ഇന്റർനെറ്റിൽ ലഭ്യമായതിൽ ഏറ്റവും നല്ലതും ഏറ്റവും മോശവുമായതെല്ലാം ഉൾപ്പെടെ. + +ഒരു ചെറിയ ഉദാഹരണം കാണിക്കാൻ, BERT മോഡൽ ഉപയോഗിക്കുന്ന `fill-mask` പൈപ്പ്‌ലൈനിന്റെ ഉദാഹരണത്തിലേക്ക് നമുക്ക് തിരിച്ചുപോകാം: + +```python +from transformers import pipeline + +unmasker = pipeline("fill-mask", model="bert-base-uncased") +result = unmasker("This man works as a [MASK].") +print([r["token_str"] for r in result]) + +result = unmasker("This woman works as a [MASK].") +print([r["token_str"] for r in result]) +``` + +```python out +['lawyer', 'carpenter', 'doctor', 'waiter', 'mechanic'] +['nurse', 'waitress', 'teacher', 'maid', 'prostitute'] +``` + +ഈ രണ്ട് വാക്യങ്ങളിലെയും വിട്ടുപോയ വാക്ക് പൂരിപ്പിക്കാൻ ആവശ്യപ്പെട്ടപ്പോൾ, ലിംഗഭേദമില്ലാത്ത ഒരേയൊരു ഉത്തരം മാത്രമേ മോഡൽ നൽകുന്നുള്ളൂ (waiter/waitress). ബാക്കിയുള്ളവ സാധാരണയായി ഒരു പ്രത്യേക ലിംഗവുമായി ബന്ധപ്പെടുത്തുന്ന തൊഴിലുകളാണ് -- അതെ, "woman" (സ്ത്രീ), "work" (ജോലി) എന്നിവയുമായി മോഡൽ ബന്ധപ്പെടുത്തുന്ന ആദ്യ 5 സാധ്യതകളിൽ prostitute എന്ന വാക്ക് വരെ വന്നു. ഇന്റർനെറ്റിലുടനീളമുള്ള ഡേറ്റ സ്‌ക്രേപ്പ് ചെയ്ത് നിർമ്മിക്കാത്ത, പകരം പ്രത്യക്ഷത്തിൽ നിഷ്‌പക്ഷമെന്ന് തോന്നുന്ന ഡേറ്റ ഉപയോഗിച്ച് നിർമ്മിച്ച അപൂർവ്വം Transformer മോഡലുകളിൽ ഒന്നാണ് BERT എന്നിരിക്കെയാണ് ഇത് സംഭവിക്കുന്നത് ([English Wikipedia](https://huggingface.co/datasets/wikipedia), [BookCorpus](https://huggingface.co/datasets/bookcorpus) എന്നീ ഡേറ്റാസെറ്റുകളിലാണ് ഇത് പരിശീലിപ്പിച്ചിട്ടുള്ളത്). + +അതിനാൽ ഈ ടൂളുകൾ ഉപയോഗിക്കുമ്പോൾ, നിങ്ങൾ ഉപയോഗിക്കുന്ന മൂല മോഡൽ ലിംഗവിവേചനപരമോ, വംശീയമോ, സ്വവർഗ്ഗാനുരാഗവിരുദ്ധമോ ആയ ഉള്ളടക്കം വളരെ എളുപ്പത്തിൽ ജനറേറ്റ് ചെയ്യാനിടയുണ്ട് എന്നത് നിങ്ങൾ മനസ്സിൽ സൂക്ഷിക്കേണ്ടതുണ്ട്. നിങ്ങളുടെ ഡേറ്റയിൽ മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്താലും ഈ അന്തർലീനമായ പക്ഷപാതം ഇല്ലാതാകില്ല. diff --git a/chapters/ml/chapter2/1.mdx b/chapters/ml/chapter2/1.mdx new file mode 100644 index 000000000..1afcfcc6e --- /dev/null +++ b/chapters/ml/chapter2/1.mdx @@ -0,0 +1,24 @@ +# ആമുഖം[[introduction]] + + + +[അധ്യായം 1](/course/chapter1)-ൽ നിങ്ങൾ കണ്ടതുപോലെ, Transformer മോഡലുകൾ സാധാരണയായി വളരെ വലുതാണ്. ദശലക്ഷക്കണക്കിന് മുതൽ പല *ബില്യൺ* വരെ പാരാമീറ്ററുകളുള്ള ഈ മോഡലുകളെ പരിശീലിപ്പിക്കുന്നതും വിന്യസിക്കുന്നതും (deploy) സങ്കീർണ്ണമായ ഒരു ജോലിയാണ്. കൂടാതെ, ഏകദേശം ദിവസേനയെന്നോണം പുതിയ മോഡലുകൾ പുറത്തിറങ്ങുന്നതും അവയ്ക്ക് ഓരോന്നിനും അതിന്റേതായ ഇംപ്ലിമെന്റേഷൻ ഉള്ളതും കാരണം, അവയെല്ലാം പരീക്ഷിച്ചുനോക്കുക എന്നത് എളുപ്പമുള്ള കാര്യമല്ല. + +ഈ പ്രശ്നം പരിഹരിക്കാനാണ് 🤗 Transformers ലൈബ്രറി സൃഷ്ടിച്ചത്. ഏത് Transformer മോഡലും ലോഡ് ചെയ്യാനും പരിശീലിപ്പിക്കാനും സേവ് ചെയ്യാനും കഴിയുന്ന ഒരൊറ്റ API നൽകുക എന്നതാണ് ഇതിന്റെ ലക്ഷ്യം. ലൈബ്രറിയുടെ പ്രധാന സവിശേഷതകൾ ഇവയാണ്: + +- **ഉപയോഗിക്കാനുള്ള എളുപ്പം**: അത്യാധുനികമായ ഒരു NLP മോഡൽ ഡൗൺലോഡ് ചെയ്യുന്നതും ലോഡ് ചെയ്യുന്നതും ഇൻഫറൻസിനായി ഉപയോഗിക്കുന്നതും വെറും രണ്ട് വരി കോഡിൽ ചെയ്യാൻ കഴിയും. +- **വഴക്കം (Flexibility)**: അടിസ്ഥാനപരമായി, എല്ലാ മോഡലുകളും ലളിതമായ PyTorch `nn.Module` ക്ലാസുകളാണ്; അതത് മെഷീൻ ലേണിംഗ് (ML) ഫ്രെയിംവർക്കുകളിലെ മറ്റേതൊരു മോഡലിനെയും പോലെ ഇവയെ കൈകാര്യം ചെയ്യാം. +- **ലാളിത്യം**: ലൈബ്രറിയിലുടനീളം അബ്‌സ്ട്രാക്‌ഷനുകൾ ഏറെക്കുറെ ഇല്ല എന്നു പറയാം. "എല്ലാം ഒരൊറ്റ ഫയലിൽ" (All in one file) എന്നത് ഒരു അടിസ്ഥാന ആശയമാണ്: ഒരു മോഡലിന്റെ ഫോർവേഡ് പാസ് (forward pass) പൂർണ്ണമായും ഒരൊറ്റ ഫയലിലാണ് നിർവചിച്ചിരിക്കുന്നത്; അതിനാൽ കോഡ് തന്നെ മനസ്സിലാക്കാവുന്നതും മാറ്റം വരുത്തി പരീക്ഷിക്കാവുന്നതും (hackable) ആണ്. + +ഈ അവസാനത്തെ സവിശേഷത 🤗 Transformers-നെ മറ്റ് ML ലൈബ്രറികളിൽ നിന്ന് തികച്ചും വ്യത്യസ്തമാക്കുന്നു. ഫയലുകൾക്കിടയിൽ പങ്കുവെക്കപ്പെടുന്ന മൊഡ്യൂളുകളുടെ മേലല്ല മോഡലുകൾ +നിർമ്മിച്ചിരിക്കുന്നത്; പകരം, ഓരോ മോഡലിനും അതിന്റേതായ ലെയറുകളുണ്ട്. മോഡലുകളെ കൂടുതൽ സമീപിക്കാവുന്നതും മനസ്സിലാക്കാവുന്നതുമാക്കുന്നതിനു പുറമേ, മറ്റ് മോഡലുകളെ ബാധിക്കാതെ ഒരു മോഡലിൽ എളുപ്പത്തിൽ പരീക്ഷണം നടത്താനും ഇത് നിങ്ങളെ അനുവദിക്കുന്നു. + +[അധ്യായം 1](/course/chapter1)-ൽ പരിചയപ്പെടുത്തിയ `pipeline()` ഫംഗ്‌ഷനെ ഒരു മോഡലും ഒരു ടോക്കണൈസറും ഒരുമിച്ച് ഉപയോഗിച്ച് പുനഃസൃഷ്ടിക്കുന്ന, തുടക്കം മുതൽ അവസാനം വരെയുള്ള (end-to-end) ഒരു ഉദാഹരണത്തോടെയാണ് ഈ അധ്യായം ആരംഭിക്കുന്നത്. അടുത്തതായി, മോഡൽ API-യെക്കുറിച്ച് നമ്മൾ ചർച്ച ചെയ്യും: മോഡൽ ക്ലാസുകളിലേക്കും കോൺഫിഗറേഷൻ ക്ലാസുകളിലേക്കും ആഴത്തിൽ കടന്ന്, ഒരു മോഡൽ എങ്ങനെ ലോഡ് ചെയ്യാമെന്നും അത് സംഖ്യാ ഇൻപുട്ടുകളെ പ്രോസസ്സ് ചെയ്ത് എങ്ങനെ പ്രവചനങ്ങൾ ഔട്ട്‌പുട്ട് ചെയ്യുന്നു എന്നും ഞങ്ങൾ കാണിച്ചുതരും. + +തുടർന്ന്, `pipeline()` ഫംഗ്‌ഷന്റെ മറ്റൊരു പ്രധാന ഘടകമായ ടോക്കണൈസർ API-യിലേക്ക് നമ്മൾ കടക്കും. പ്രോസസ്സിംഗിന്റെ ആദ്യത്തെയും അവസാനത്തെയും ഘട്ടങ്ങൾ കൈകാര്യം ചെയ്യുന്നത് ടോക്കണൈസറുകളാണ് — ടെക്‌സ്‌റ്റിനെ ന്യൂറൽ നെറ്റ്‌വർക്കിനുള്ള സംഖ്യാ ഇൻപുട്ടുകളാക്കി മാറ്റുന്നതും, ആവശ്യമുള്ളപ്പോൾ അവയെ തിരികെ ടെക്‌സ്‌റ്റാക്കി മാറ്റുന്നതും. അവസാനമായി, തയ്യാറാക്കിയ ഒരു ബാച്ചായി ഒന്നിലധികം വാക്യങ്ങൾ ഒരു മോഡലിലൂടെ എങ്ങനെ കടത്തിവിടാമെന്ന് ഞങ്ങൾ കാണിച്ചുതരും; പിന്നീട് ഉയർന്ന തലത്തിലുള്ള (high-level) `tokenizer()` ഫംഗ്‌ഷനെ കൂടുതൽ അടുത്തറിഞ്ഞുകൊണ്ട് എല്ലാം ഉപസംഹരിക്കും. + +> [!TIP] +> ⚠️ Model Hub-ഉം 🤗 Transformers-ഉം നൽകുന്ന എല്ലാ സവിശേഷതകളും പ്രയോജനപ്പെടുത്താൻ, ഒരു അക്കൗണ്ട് ഉണ്ടാക്കാൻ ഞങ്ങൾ ശുപാർശ ചെയ്യുന്നു. diff --git a/chapters/ml/chapter2/2.mdx b/chapters/ml/chapter2/2.mdx new file mode 100644 index 000000000..04f2773e3 --- /dev/null +++ b/chapters/ml/chapter2/2.mdx @@ -0,0 +1,232 @@ + + +# പൈപ്പ്‌ലൈനിന്റെ പിന്നിൽ[[behind-the-pipeline]] + + + + + +[അധ്യായം 1](/course/chapter1)-ൽ താഴെ കൊടുത്ത കോഡ് നമ്മൾ റൺ ചെയ്തപ്പോൾ തിരശ്ശീലയ്ക്ക് പിന്നിൽ എന്താണ് സംഭവിച്ചത് എന്ന് പരിശോധിച്ചുകൊണ്ട്, ഒരു പൂർണ്ണമായ ഉദാഹരണത്തിൽ നിന്ന് തുടങ്ങാം: + +```python +from transformers import pipeline + +classifier = pipeline("sentiment-analysis") +classifier( + [ + "I've been waiting for a HuggingFace course my whole life.", + "I hate this so much!", + ] +) +``` + +അപ്പോൾ നമുക്ക് ലഭിച്ചത്: + +```python out +[{'label': 'POSITIVE', 'score': 0.9598047137260437}, + {'label': 'NEGATIVE', 'score': 0.9994558095932007}] +``` + +[അധ്യായം 1](/course/chapter1)-ൽ നമ്മൾ കണ്ടതുപോലെ, ഈ പൈപ്പ്‌ലൈൻ മൂന്ന് ഘട്ടങ്ങളെ ഒരുമിച്ച് ചേർക്കുന്നു: പ്രീപ്രോസസ്സിംഗ്, ഇൻപുട്ടുകൾ മോഡലിലൂടെ കടത്തിവിടൽ, പോസ്‌റ്റ്‌പ്രോസസ്സിംഗ്: + +
+പൂർണ്ണമായ NLP പൈപ്പ്‌ലൈൻ: ടെക്‌സ്‌റ്റിന്റെ ടോക്കണൈസേഷൻ, ID-കളിലേക്കുള്ള മാറ്റം, Transformer മോഡലിലൂടെയും മോഡൽ ഹെഡിലൂടെയുമുള്ള ഇൻഫറൻസ്. + +
+ +ഇവയോരോന്നും വേഗത്തിൽ ഒന്ന് നോക്കാം. + +## ഒരു ടോക്കണൈസർ ഉപയോഗിച്ചുള്ള പ്രീപ്രോസസ്സിംഗ്[[preprocessing-with-a-tokenizer]] + +മറ്റ് ന്യൂറൽ നെറ്റ്‌വർക്കുകളെപ്പോലെ, Transformer മോഡലുകൾക്കും അസംസ്‌കൃത ടെക്‌സ്‌റ്റ് (raw text) നേരിട്ട് പ്രോസസ്സ് ചെയ്യാൻ കഴിയില്ല; അതിനാൽ നമ്മുടെ പൈപ്പ്‌ലൈനിന്റെ ആദ്യ ഘട്ടം ടെക്‌സ്‌റ്റ് ഇൻപുട്ടുകളെ മോഡലിന് മനസ്സിലാക്കാൻ കഴിയുന്ന സംഖ്യകളാക്കി മാറ്റുകയാണ്. ഇതിനായി നമ്മൾ ഒരു *ടോക്കണൈസർ* ഉപയോഗിക്കുന്നു; അതിന്റെ ചുമതലകൾ ഇവയാണ്: + +- ഇൻപുട്ടിനെ *ടോക്കണുകൾ* എന്ന് വിളിക്കുന്ന വാക്കുകളായോ ഉപവാക്കുകളായോ (subwords) ചിഹ്നങ്ങളായോ (വിരാമചിഹ്നങ്ങൾ പോലെ) വിഭജിക്കുക +- ഓരോ ടോക്കണെയും ഒരു പൂർണ്ണസംഖ്യയുമായി (integer) ബന്ധപ്പെടുത്തുക +- മോഡലിന് ഉപകാരപ്രദമാകാവുന്ന അധിക ഇൻപുട്ടുകൾ ചേർക്കുക + +ഈ പ്രീപ്രോസസ്സിംഗ് മുഴുവനും മോഡൽ പ്രീട്രെയിൻ ചെയ്തപ്പോൾ ചെയ്ത അതേ രീതിയിൽ തന്നെ ചെയ്യേണ്ടതുണ്ട്; അതിനാൽ ആ വിവരങ്ങൾ ആദ്യം [Model Hub](https://huggingface.co/models)-ൽ നിന്ന് ഡൗൺലോഡ് ചെയ്യണം. ഇതിനായി നമ്മൾ `AutoTokenizer` ക്ലാസും അതിന്റെ `from_pretrained()` മെത്തേഡും ഉപയോഗിക്കുന്നു. നമ്മുടെ മോഡലിന്റെ ചെക്ക്‌പോയിന്റ് പേര് ഉപയോഗിച്ച്, മോഡലിന്റെ ടോക്കണൈസറുമായി ബന്ധപ്പെട്ട ഡേറ്റ ഇത് സ്വയമേവ എടുത്ത് കാഷ് ചെയ്യും (അതിനാൽ താഴെയുള്ള കോഡ് നിങ്ങൾ ആദ്യമായി റൺ ചെയ്യുമ്പോൾ മാത്രമേ ഇത് ഡൗൺലോഡ് ചെയ്യപ്പെടുകയുള്ളൂ). + +`sentiment-analysis` പൈപ്പ്‌ലൈനിന്റെ ഡിഫോൾട്ട് ചെക്ക്‌പോയിന്റ് `distilbert-base-uncased-finetuned-sst-2-english` ആയതിനാൽ (അതിന്റെ മോഡൽ കാർഡ് [ഇവിടെ](https://huggingface.co/distilbert-base-uncased-finetuned-sst-2-english) കാണാം), നമ്മൾ താഴെ പറയുന്നത് റൺ ചെയ്യുന്നു: + +```python +from transformers import AutoTokenizer + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +``` + +ടോക്കണൈസർ കിട്ടിക്കഴിഞ്ഞാൽ, നമ്മുടെ വാക്യങ്ങൾ നേരിട്ട് അതിലേക്ക് നൽകാം; മോഡലിലേക്ക് നൽകാൻ തയ്യാറായ ഒരു ഡിക്‌ഷണറി നമുക്ക് തിരികെ ലഭിക്കും! ഇനി ചെയ്യാനുള്ള ഒരേയൊരു കാര്യം ഇൻപുട്ട് ID-കളുടെ ലിസ്‌റ്റിനെ ടെൻസറുകളാക്കി (tensors) മാറ്റുകയാണ്. + +ബാക്കെൻഡായി ഏത് ML ഫ്രെയിംവർക്കാണ് ഉപയോഗിക്കുന്നത് എന്നതിനെക്കുറിച്ച് വിഷമിക്കാതെ നിങ്ങൾക്ക് 🤗 Transformers ഉപയോഗിക്കാം; ചില മോഡലുകൾക്ക് അത് PyTorch ആകാം, അല്ലെങ്കിൽ Flax ആകാം. എന്നിരുന്നാലും, Transformer മോഡലുകൾ *ടെൻസറുകൾ* മാത്രമേ ഇൻപുട്ടായി സ്വീകരിക്കുകയുള്ളൂ. ടെൻസറുകളെക്കുറിച്ച് നിങ്ങൾ ആദ്യമായി കേൾക്കുന്നതാണെങ്കിൽ, അവയെ NumPy അറേകളായി കരുതാം. ഒരു NumPy അറേ ഒരു സ്‌കെയിലർ (0D) ആകാം, ഒരു വെക്‌റ്റർ (1D) ആകാം, ഒരു മാട്രിക്‌സ് (2D) ആകാം, അല്ലെങ്കിൽ കൂടുതൽ ഡൈമെൻഷനുകൾ ഉള്ളതാകാം. ഫലത്തിൽ അത് ഒരു ടെൻസറാണ്; മറ്റ് ML ഫ്രെയിംവർക്കുകളിലെ ടെൻസറുകളും ഇതുപോലെ തന്നെ പെരുമാറുന്നു, സാധാരണയായി NumPy അറേകൾ പോലെ എളുപ്പത്തിൽ അവ ഉണ്ടാക്കാനും (instantiate) കഴിയും. + +നമുക്ക് തിരികെ ലഭിക്കേണ്ട ടെൻസറുകളുടെ തരം (PyTorch അല്ലെങ്കിൽ സാധാരണ NumPy) വ്യക്തമാക്കാൻ, `return_tensors` ആർഗ്യുമെന്റ് ഉപയോഗിക്കുന്നു: + +```python +raw_inputs = [ + "I've been waiting for a HuggingFace course my whole life.", + "I hate this so much!", +] +inputs = tokenizer(raw_inputs, padding=True, truncation=True, return_tensors="pt") +print(inputs) +``` + +പാഡിംഗിനെയും ട്രങ്കേഷനെയും (truncation) കുറിച്ച് ഇപ്പോൾ വിഷമിക്കേണ്ട; അവ പിന്നീട് വിശദീകരിക്കാം. ഇവിടെ ഓർത്തിരിക്കേണ്ട പ്രധാന കാര്യങ്ങൾ ഇവയാണ്: ഒരു വാക്യമോ വാക്യങ്ങളുടെ ഒരു ലിസ്‌റ്റോ നിങ്ങൾക്ക് നൽകാം, കൂടാതെ തിരികെ ലഭിക്കേണ്ട ടെൻസറുകളുടെ തരവും വ്യക്തമാക്കാം (തരം ഒന്നും നൽകിയില്ലെങ്കിൽ, ഫലമായി ലിസ്‌റ്റുകളുടെ ഒരു ലിസ്‌റ്റ് ലഭിക്കും). + +PyTorch ടെൻസറുകളായി ഫലങ്ങൾ ഇങ്ങനെയാണ് കാണപ്പെടുന്നത്: + +```python out +{ + 'input_ids': tensor([ + [ 101, 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012, 102], + [ 101, 1045, 5223, 2023, 2061, 2172, 999, 102, 0, 0, 0, 0, 0, 0, 0, 0] + ]), + 'attention_mask': tensor([ + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0] + ]) +} +``` + +ഔട്ട്‌പുട്ട് തന്നെ `input_ids`, `attention_mask` എന്ന രണ്ട് കീകൾ അടങ്ങിയ ഒരു ഡിക്‌ഷണറിയാണ്. `input_ids`-ൽ പൂർണ്ണസംഖ്യകളുടെ രണ്ട് വരികൾ (ഓരോ വാക്യത്തിനും ഒന്ന്) അടങ്ങിയിരിക്കുന്നു; ഓരോ വാക്യത്തിലെയും ടോക്കണുകളുടെ അനന്യമായ തിരിച്ചറിയൽ സംഖ്യകളാണ് (unique identifiers) ഇവ. `attention_mask` എന്താണെന്ന് ഈ അധ്യായത്തിൽ പിന്നീട് വിശദീകരിക്കാം. + +## മോഡലിലൂടെ കടന്നുപോകുന്നു[[going-through-the-model]] + +ടോക്കണൈസർ ഡൗൺലോഡ് ചെയ്ത അതേ രീതിയിൽ നമ്മുടെ പ്രീട്രെയിൻഡ് മോഡലും ഡൗൺലോഡ് ചെയ്യാം. 🤗 Transformers ഒരു `AutoModel` ക്ലാസ് നൽകുന്നു; ഇതിനും ഒരു `from_pretrained()` മെത്തേഡ് ഉണ്ട്: + +```python +from transformers import AutoModel + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = AutoModel.from_pretrained(checkpoint) +``` + +ഈ കോഡ് ഭാഗത്തിൽ, മുമ്പ് നമ്മുടെ പൈപ്പ്‌ലൈനിൽ ഉപയോഗിച്ച അതേ ചെക്ക്‌പോയിന്റ് നമ്മൾ ഡൗൺലോഡ് ചെയ്യുകയും (വാസ്തവത്തിൽ അത് ഇതിനകം കാഷ് ചെയ്യപ്പെട്ടിരിക്കണം) അതുപയോഗിച്ച് ഒരു മോഡൽ ഉണ്ടാക്കുകയും (instantiate) ചെയ്തു. + +ഈ ആർക്കിടെക്ചറിൽ അടിസ്ഥാന Transformer മൊഡ്യൂൾ മാത്രമേ അടങ്ങിയിട്ടുള്ളൂ: ചില ഇൻപുട്ടുകൾ നൽകിയാൽ, *ഹിഡൻ സ്റ്റേറ്റുകൾ* (hidden states) എന്ന് നമ്മൾ വിളിക്കുന്ന — *ഫീച്ചറുകൾ* (features) എന്നും അറിയപ്പെടുന്ന — ഔട്ട്‌പുട്ടാണ് ഇത് നൽകുന്നത്. ഓരോ മോഡൽ ഇൻപുട്ടിനും, **Transformer മോഡൽ ആ ഇൻപുട്ടിനെ സന്ദർഭാനുസൃതമായി മനസ്സിലാക്കിയതിനെ** പ്രതിനിധീകരിക്കുന്ന ഉയർന്ന ഡൈമെൻഷനുള്ള ഒരു വെക്‌റ്റർ നമുക്ക് ലഭിക്കും. + +ഇത് മനസ്സിലായില്ലെങ്കിൽ വിഷമിക്കേണ്ട. എല്ലാം പിന്നീട് വിശദീകരിക്കാം. + +ഈ ഹിഡൻ സ്റ്റേറ്റുകൾ അവ തന്നെയായി ഉപകാരപ്രദമാകാമെങ്കിലും, സാധാരണയായി അവ മോഡലിന്റെ *ഹെഡ്* (head) എന്നറിയപ്പെടുന്ന മറ്റൊരു ഭാഗത്തിലേക്കുള്ള ഇൻപുട്ടുകളാണ്. [അധ്യായം 1](/course/chapter1)-ലെ വ്യത്യസ്ത ടാസ്‌ക്കുകൾ ഒരേ ആർക്കിടെക്ചർ ഉപയോഗിച്ച് ചെയ്യാമായിരുന്നു, എന്നാൽ ഈ ടാസ്‌ക്കുകളിൽ ഓരോന്നിനും അതുമായി ബന്ധപ്പെട്ട വ്യത്യസ്തമായ ഒരു ഹെഡ് ഉണ്ടായിരിക്കും. + +### ഉയർന്ന ഡൈമെൻഷനുള്ള ഒരു വെക്‌റ്റർ?[[a-high-dimensional-vector]] + +Transformer മൊഡ്യൂൾ ഔട്ട്‌പുട്ട് ചെയ്യുന്ന വെക്‌റ്റർ സാധാരണയായി വലുതാണ്. അതിന് പൊതുവെ മൂന്ന് ഡൈമെൻഷനുകളുണ്ട്: + +- **ബാച്ച് സൈസ്**: ഒരു സമയത്ത് പ്രോസസ്സ് ചെയ്യുന്ന സീക്വൻസുകളുടെ എണ്ണം (നമ്മുടെ ഉദാഹരണത്തിൽ 2). +- **സീക്വൻസ് ലെങ്ത്**: സീക്വൻസിന്റെ സംഖ്യാ പ്രതിനിധാനത്തിന്റെ നീളം (നമ്മുടെ ഉദാഹരണത്തിൽ 16). +- **ഹിഡൻ സൈസ്**: ഓരോ മോഡൽ ഇൻപുട്ടിന്റെയും വെക്‌റ്റർ ഡൈമെൻഷൻ. + +അവസാനത്തെ മൂല്യം കാരണമാണ് ഇതിനെ "ഉയർന്ന ഡൈമെൻഷനുള്ളത്" എന്ന് പറയുന്നത്. ഹിഡൻ സൈസ് വളരെ വലുതാകാം (ചെറിയ മോഡലുകളിൽ 768 സാധാരണമാണ്, വലിയ മോഡലുകളിൽ ഇത് 3072-ഓ അതിലധികമോ വരെ എത്താം). + +നമ്മൾ പ്രീപ്രോസസ്സ് ചെയ്ത ഇൻപുട്ടുകൾ മോഡലിലേക്ക് നൽകിയാൽ ഇത് കാണാൻ കഴിയും: + +```python +outputs = model(**inputs) +print(outputs.last_hidden_state.shape) +``` + +```python out +torch.Size([2, 16, 768]) +``` + +🤗 Transformers മോഡലുകളുടെ ഔട്ട്‌പുട്ടുകൾ `namedtuple`-കളോ ഡിക്‌ഷണറികളോ പോലെയാണ് പെരുമാറുന്നത് എന്നത് ശ്രദ്ധിക്കുക. ആട്രിബ്യൂട്ടുകൾ വഴിയോ (നമ്മൾ ചെയ്തതുപോലെ) കീ വഴിയോ (`outputs["last_hidden_state"]`) നിങ്ങൾക്ക് ഘടകങ്ങൾ ആക്‌സസ് ചെയ്യാം; നിങ്ങൾ തിരയുന്നത് കൃത്യമായി എവിടെയാണെന്ന് അറിയാമെങ്കിൽ ഇൻഡെക്‌സ് വഴിയും (`outputs[0]`) ആക്‌സസ് ചെയ്യാം. + +### മോഡൽ ഹെഡുകൾ: സംഖ്യകളിൽ നിന്ന് അർത്ഥം കണ്ടെത്തുന്നു[[model-heads-making-sense-out-of-numbers]] + +മോഡൽ ഹെഡുകൾ ഹിഡൻ സ്റ്റേറ്റുകളുടെ ഉയർന്ന ഡൈമെൻഷനുള്ള വെക്‌റ്റർ ഇൻപുട്ടായി സ്വീകരിച്ച് അവയെ മറ്റൊരു ഡൈമെൻഷനിലേക്ക് പ്രൊജക്റ്റ് ചെയ്യുന്നു. സാധാരണയായി ഒന്നോ ഏതാനുമോ ലീനിയർ ലെയറുകൾ ചേർന്നതാണ് ഇവ: + +
+ഒരു Transformer നെറ്റ്‌വർക്കും അതിന്റെ ഹെഡും. + +
+ +Transformer മോഡലിന്റെ ഔട്ട്‌പുട്ട് പ്രോസസ്സ് ചെയ്യപ്പെടാനായി നേരിട്ട് മോഡൽ ഹെഡിലേക്ക് അയയ്ക്കുന്നു. + +ഈ ചിത്രത്തിൽ, മോഡലിനെ അതിന്റെ എംബെഡ്ഡിംഗ് ലെയറും തുടർന്നുള്ള ലെയറുകളും ചേർന്നാണ് പ്രതിനിധീകരിക്കുന്നത്. ടോക്കണൈസ് ചെയ്ത ഇൻപുട്ടിലെ ഓരോ ഇൻപുട്ട് ID-യെയും അതുമായി ബന്ധപ്പെട്ട ടോക്കണെ പ്രതിനിധീകരിക്കുന്ന ഒരു വെക്‌റ്ററാക്കി എംബെഡ്ഡിംഗ് ലെയർ മാറ്റുന്നു. തുടർന്നുള്ള ലെയറുകൾ അറ്റൻഷൻ മെക്കാനിസം ഉപയോഗിച്ച് ആ വെക്‌റ്ററുകളിൽ പ്രവർത്തിച്ച് വാക്യങ്ങളുടെ അന്തിമ പ്രതിനിധാനം സൃഷ്ടിക്കുന്നു. + +🤗 Transformers-ൽ വ്യത്യസ്തങ്ങളായ നിരവധി ആർക്കിടെക്ചറുകൾ ലഭ്യമാണ്; ഓരോന്നും ഒരു നിശ്ചിത ടാസ്‌ക്ക് കൈകാര്യം ചെയ്യാൻ രൂപകൽപ്പന ചെയ്തവയാണ്. പൂർണ്ണമല്ലാത്ത ഒരു പട്ടിക ഇതാ: + +- `*Model` (ഹിഡൻ സ്റ്റേറ്റുകൾ ലഭ്യമാക്കുന്നു) +- `*ForCausalLM` +- `*ForMaskedLM` +- `*ForMultipleChoice` +- `*ForQuestionAnswering` +- `*ForSequenceClassification` +- `*ForTokenClassification` +- മറ്റുള്ളവയും 🤗 + +നമ്മുടെ ഉദാഹരണത്തിന്, ഒരു സീക്വൻസ് ക്ലാസിഫിക്കേഷൻ ഹെഡുള്ള ഒരു മോഡൽ ആവശ്യമാണ് (വാക്യങ്ങളെ positive അല്ലെങ്കിൽ negative എന്ന് വർഗ്ഗീകരിക്കാൻ കഴിയാൻ). അതിനാൽ, നമ്മൾ യഥാർത്ഥത്തിൽ `AutoModel` ക്ലാസല്ല, `AutoModelForSequenceClassification` ആണ് ഉപയോഗിക്കുന്നത്: + +```python +from transformers import AutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +model = AutoModelForSequenceClassification.from_pretrained(checkpoint) +outputs = model(**inputs) +``` + +ഇപ്പോൾ നമ്മുടെ ഔട്ട്‌പുട്ടുകളുടെ ഷേപ്പ് (shape) നോക്കിയാൽ, ഡൈമെൻഷണാലിറ്റി വളരെ കുറവായിരിക്കും: മോഡൽ ഹെഡ് നമ്മൾ മുമ്പ് കണ്ട ഉയർന്ന ഡൈമെൻഷനുള്ള വെക്‌റ്ററുകളെ ഇൻപുട്ടായി സ്വീകരിച്ച്, രണ്ട് മൂല്യങ്ങൾ (ഓരോ ലേബലിനും ഒന്ന്) അടങ്ങിയ വെക്‌റ്ററുകൾ ഔട്ട്‌പുട്ട് ചെയ്യുന്നു: + +```python +print(outputs.logits.shape) +``` + +```python out +torch.Size([2, 2]) +``` + +നമുക്ക് രണ്ട് വാക്യങ്ങളും രണ്ട് ലേബലുകളും മാത്രമുള്ളതിനാൽ, മോഡലിൽ നിന്ന് നമുക്ക് ലഭിക്കുന്ന ഫലത്തിന്റെ ഷേപ്പ് 2 x 2 ആണ്. + +## ഔട്ട്‌പുട്ടിന്റെ പോസ്‌റ്റ്‌പ്രോസസ്സിംഗ്[[postprocessing-the-output]] + +മോഡലിൽ നിന്ന് ഔട്ട്‌പുട്ടായി നമുക്ക് ലഭിക്കുന്ന മൂല്യങ്ങൾ അവ തന്നെയായി അർത്ഥവത്താകണമെന്നില്ല. ഒന്ന് നോക്കാം: + +```python +print(outputs.logits) +``` + +```python out +tensor([[-1.5607, 1.6123], + [ 4.1692, -3.3464]], grad_fn=) +``` + +നമ്മുടെ മോഡൽ ആദ്യ വാക്യത്തിന് `[-1.5607, 1.6123]` എന്നും രണ്ടാമത്തേതിന് `[ 4.1692, -3.3464]` എന്നും പ്രവചിച്ചു. ഇവ പ്രോബബിലിറ്റികളല്ല, *ലോജിറ്റുകൾ* (logits) ആണ് — മോഡലിന്റെ അവസാന ലെയർ ഔട്ട്‌പുട്ട് ചെയ്യുന്ന അസംസ്‌കൃതവും നോർമലൈസ് ചെയ്യാത്തതുമായ സ്‌കോറുകൾ. പ്രോബബിലിറ്റികളാക്കി മാറ്റാൻ, ഇവ ഒരു [SoftMax](https://en.wikipedia.org/wiki/Softmax_function) ലെയറിലൂടെ കടന്നുപോകേണ്ടതുണ്ട് (എല്ലാ 🤗 Transformers മോഡലുകളും ലോജിറ്റുകളാണ് ഔട്ട്‌പുട്ട് ചെയ്യുന്നത്, കാരണം പരിശീലനത്തിനുള്ള ലോസ് ഫംഗ്‌ഷൻ സാധാരണയായി SoftMax പോലുള്ള അവസാന ആക്റ്റിവേഷൻ ഫംഗ്‌ഷനെ ക്രോസ് എൻട്രോപ്പി പോലുള്ള യഥാർത്ഥ ലോസ് ഫംഗ്‌ഷനുമായി സംയോജിപ്പിക്കും): + +```py +import torch + +predictions = torch.nn.functional.softmax(outputs.logits, dim=-1) +print(predictions) +``` + +```python out +tensor([[4.0195e-02, 9.5980e-01], + [9.9946e-01, 5.4418e-04]], grad_fn=) +``` + +ഇപ്പോൾ, മോഡൽ ആദ്യ വാക്യത്തിന് `[0.0402, 0.9598]` എന്നും രണ്ടാമത്തേതിന് `[0.9995, 0.0005]` എന്നും പ്രവചിച്ചതായി കാണാം. ഇവ തിരിച്ചറിയാവുന്ന പ്രോബബിലിറ്റി സ്‌കോറുകളാണ്. + +ഓരോ സ്ഥാനത്തിനും അനുയോജ്യമായ ലേബലുകൾ ലഭിക്കാൻ, മോഡൽ കോൺഫിഗിന്റെ `id2label` ആട്രിബ്യൂട്ട് പരിശോധിക്കാം (ഇതിനെക്കുറിച്ച് കൂടുതൽ അടുത്ത ഭാഗത്തിൽ): + +```python +model.config.id2label +``` + +```python out +{0: 'NEGATIVE', 1: 'POSITIVE'} +``` + +മോഡൽ താഴെ പറയുന്നവ പ്രവചിച്ചു എന്ന് ഇപ്പോൾ നമുക്ക് നിഗമനത്തിലെത്താം: + +- ആദ്യ വാക്യം: NEGATIVE: 0.0402, POSITIVE: 0.9598 +- രണ്ടാമത്തെ വാക്യം: NEGATIVE: 0.9995, POSITIVE: 0.0005 + +പൈപ്പ്‌ലൈനിന്റെ മൂന്ന് ഘട്ടങ്ങളും നമ്മൾ വിജയകരമായി പുനഃസൃഷ്ടിച്ചു: ടോക്കണൈസറുകൾ ഉപയോഗിച്ചുള്ള പ്രീപ്രോസസ്സിംഗ്, ഇൻപുട്ടുകൾ മോഡലിലൂടെ കടത്തിവിടൽ, പോസ്‌റ്റ്‌പ്രോസസ്സിംഗ്! ഇനി ഈ ഘട്ടങ്ങളിൽ ഓരോന്നിലേക്കും കുറച്ചുകൂടി ആഴത്തിൽ ഇറങ്ങാൻ കുറച്ച് സമയമെടുക്കാം. + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** നിങ്ങളുടെ സ്വന്തം രണ്ടോ (അതിലധികമോ) ടെക്‌സ്‌റ്റുകൾ തിരഞ്ഞെടുത്ത് `sentiment-analysis` പൈപ്പ്‌ലൈനിലൂടെ റൺ ചെയ്യുക. തുടർന്ന്, ഇവിടെ കണ്ട ഘട്ടങ്ങൾ നിങ്ങൾ സ്വയം ആവർത്തിച്ച്, അതേ ഫലങ്ങൾ ലഭിക്കുന്നുണ്ടോ എന്ന് പരിശോധിക്കുക! diff --git a/chapters/ml/chapter2/3.mdx b/chapters/ml/chapter2/3.mdx new file mode 100644 index 000000000..41a66a80c --- /dev/null +++ b/chapters/ml/chapter2/3.mdx @@ -0,0 +1,297 @@ + + +# മോഡലുകൾ[[the-models]] + + + + + +ഈ ഭാഗത്തിൽ, മോഡലുകൾ ഉണ്ടാക്കുന്നതും ഉപയോഗിക്കുന്നതും കൂടുതൽ അടുത്ത് പരിശോധിക്കാം. ഒരു ചെക്ക്‌പോയിന്റിൽ നിന്ന് ഏത് മോഡലും ഉണ്ടാക്കാൻ (instantiate) ആഗ്രഹിക്കുമ്പോൾ സൗകര്യപ്രദമായ `AutoModel` ക്ലാസാണ് നമ്മൾ ഉപയോഗിക്കുന്നത്. + +## ഒരു Transformer ഉണ്ടാക്കുന്നു[[creating-a-transformer]] + +ഒരു `AutoModel` നമ്മൾ ഉണ്ടാക്കുമ്പോൾ എന്താണ് സംഭവിക്കുന്നത് എന്ന് പരിശോധിച്ചുകൊണ്ട് തുടങ്ങാം: + +```py +from transformers import AutoModel + +model = AutoModel.from_pretrained("bert-base-cased") +``` + +ടോക്കണൈസറിന്റെ കാര്യത്തിലേതുപോലെ, `from_pretrained()` മെത്തേഡ് Hugging Face Hub-ൽ നിന്ന് മോഡൽ ഡേറ്റ ഡൗൺലോഡ് ചെയ്ത് കാഷ് ചെയ്യും. മുമ്പ് പറഞ്ഞതുപോലെ, ചെക്ക്‌പോയിന്റ് പേര് ഒരു നിശ്ചിത മോഡൽ ആർക്കിടെക്ചറിനെയും വെയ്‌റ്റുകളെയും സൂചിപ്പിക്കുന്നു; ഈ സാഹചര്യത്തിൽ, അടിസ്ഥാന ആർക്കിടെക്ചറുള്ള (12 ലെയറുകൾ, 768 ഹിഡൻ സൈസ്, 12 അറ്റൻഷൻ ഹെഡുകൾ) ഒരു BERT മോഡലും cased ഇൻപുട്ടുകളും (അതായത്, വലിയക്ഷരം/ചെറിയക്ഷരം എന്ന വ്യത്യാസം പ്രധാനമാണ് എന്നർത്ഥം). Hub-ൽ നിരവധി ചെക്ക്‌പോയിന്റുകൾ ലഭ്യമാണ് — അവ [ഇവിടെ](https://huggingface.co/models) നിങ്ങൾക്ക് പരിശോധിക്കാം. + +`AutoModel` ക്ലാസും അതിന്റെ കൂട്ടാളികളും യഥാർത്ഥത്തിൽ, തന്നിരിക്കുന്ന ഒരു ചെക്ക്‌പോയിന്റിന് അനുയോജ്യമായ മോഡൽ ആർക്കിടെക്ചർ കണ്ടെത്താൻ രൂപകൽപ്പന ചെയ്ത ലളിതമായ റാപ്പറുകളാണ് (wrappers). ഇത് ഒരു "auto" ക്ലാസാണ്; അതായത്, അനുയോജ്യമായ മോഡൽ ആർക്കിടെക്ചർ ഇത് നിങ്ങൾക്കായി ഊഹിച്ചെടുത്ത്, ശരിയായ മോഡൽ ക്ലാസ് ഉണ്ടാക്കും. എന്നിരുന്നാലും, ഉപയോഗിക്കേണ്ട മോഡലിന്റെ തരം നിങ്ങൾക്ക് അറിയാമെങ്കിൽ, അതിന്റെ ആർക്കിടെക്ചർ നിർവചിക്കുന്ന ക്ലാസ് നേരിട്ട് ഉപയോഗിക്കാം: + +```py +from transformers import BertModel + +model = BertModel.from_pretrained("bert-base-cased") +``` + +## ലോഡ് ചെയ്യലും സേവ് ചെയ്യലും[[loading-and-saving]] + +ഒരു മോഡൽ സേവ് ചെയ്യുന്നത് ഒരു ടോക്കണൈസർ സേവ് ചെയ്യുന്നതുപോലെ എളുപ്പമാണ്. വാസ്തവത്തിൽ, മോഡലുകൾക്കും അതേ `save_pretrained()` മെത്തേഡ് തന്നെയാണ് ഉള്ളത്; ഇത് മോഡലിന്റെ വെയ്‌റ്റുകളും ആർക്കിടെക്ചർ കോൺഫിഗറേഷനും സേവ് ചെയ്യുന്നു: + +```py +model.save_pretrained("directory_on_my_computer") +``` + +ഇത് നിങ്ങളുടെ ഡിസ്‌കിലേക്ക് രണ്ട് ഫയലുകൾ സേവ് ചെയ്യും: + +``` +ls directory_on_my_computer + +config.json model.safetensors +``` + +*config.json* ഫയലിനുള്ളിൽ നോക്കിയാൽ, മോഡൽ ആർക്കിടെക്ചർ നിർമ്മിക്കാൻ ആവശ്യമായ എല്ലാ ആട്രിബ്യൂട്ടുകളും നിങ്ങൾക്ക് കാണാം. ചെക്ക്‌പോയിന്റ് എവിടെ നിന്ന് ഉത്ഭവിച്ചു, ചെക്ക്‌പോയിന്റ് അവസാനമായി സേവ് ചെയ്തപ്പോൾ നിങ്ങൾ ഏത് 🤗 Transformers പതിപ്പാണ് ഉപയോഗിച്ചിരുന്നത് തുടങ്ങിയ ചില മെറ്റാഡേറ്റയും ഈ ഫയലിൽ അടങ്ങിയിരിക്കുന്നു. + +*pytorch_model.safetensors* ഫയൽ സ്റ്റേറ്റ് ഡിക്‌ഷണറി (state dictionary) എന്നാണ് അറിയപ്പെടുന്നത്; നിങ്ങളുടെ മോഡലിന്റെ എല്ലാ വെയ്‌റ്റുകളും ഇതിൽ അടങ്ങിയിരിക്കുന്നു. ഈ രണ്ട് ഫയലുകളും ഒരുമിച്ചാണ് പ്രവർത്തിക്കുന്നത്: മോഡൽ ആർക്കിടെക്ചറിനെക്കുറിച്ച് അറിയാൻ കോൺഫിഗറേഷൻ ഫയൽ ആവശ്യമാണ്, അതേസമയം മോഡൽ വെയ്‌റ്റുകൾ മോഡലിന്റെ പാരാമീറ്ററുകളാണ്. + +സേവ് ചെയ്ത ഒരു മോഡൽ വീണ്ടും ഉപയോഗിക്കാൻ, `from_pretrained()` മെത്തേഡ് വീണ്ടും ഉപയോഗിക്കുക: + +```py +from transformers import AutoModel + +model = AutoModel.from_pretrained("directory_on_my_computer") +``` + +മോഡലുകളും ടോക്കണൈസറുകളും കമ്മ്യൂണിറ്റിയുമായി എളുപ്പത്തിൽ പങ്കുവെക്കാനുള്ള കഴിവാണ് 🤗 Transformers ലൈബ്രറിയുടെ അതിമനോഹരമായ ഒരു സവിശേഷത. ഇതിനായി, [Hugging Face](https://huggingface.co)-ൽ നിങ്ങൾക്ക് ഒരു അക്കൗണ്ട് ഉണ്ടെന്ന് ഉറപ്പാക്കുക. നിങ്ങൾ ഒരു നോട്ട്‌ബുക്ക് ഉപയോഗിക്കുന്നുണ്ടെങ്കിൽ, ഇതുപയോഗിച്ച് എളുപ്പത്തിൽ ലോഗിൻ ചെയ്യാം: + +```python +from huggingface_hub import notebook_login + +notebook_login() +``` + +അല്ലെങ്കിൽ, നിങ്ങളുടെ ടെർമിനലിൽ ഇത് റൺ ചെയ്യുക: + +```bash +huggingface-cli login +``` + +തുടർന്ന് `push_to_hub()` മെത്തേഡ് ഉപയോഗിച്ച് മോഡൽ Hub-ലേക്ക് പുഷ് ചെയ്യാം: + +```py +model.push_to_hub("my-awesome-model") +``` + +ഇത് മോഡൽ ഫയലുകൾ Hub-ലേക്ക്, നിങ്ങളുടെ നെയിംസ്‌പേസിന് കീഴിലുള്ള *my-awesome-model* എന്ന റിപ്പോസിറ്ററിയിലേക്ക് അപ്‌ലോഡ് ചെയ്യും. പിന്നീട്, ആർക്കും `from_pretrained()` മെത്തേഡ് ഉപയോഗിച്ച് നിങ്ങളുടെ മോഡൽ ലോഡ് ചെയ്യാം! + +```py +from transformers import AutoModel + +model = AutoModel.from_pretrained("your-username/my-awesome-model") +``` + +Hub API ഉപയോഗിച്ച് നിങ്ങൾക്ക് ഇനിയും ഒരുപാട് കാര്യങ്ങൾ ചെയ്യാം: +- ഒരു ലോക്കൽ റിപ്പോസിറ്ററിയിൽ നിന്ന് ഒരു മോഡൽ പുഷ് ചെയ്യുക +- എല്ലാം വീണ്ടും അപ്‌ലോഡ് ചെയ്യാതെ നിശ്ചിത ഫയലുകൾ മാത്രം അപ്‌ഡേറ്റ് ചെയ്യുക +- മോഡലിന്റെ കഴിവുകൾ, പരിമിതികൾ, അറിയപ്പെടുന്ന പക്ഷപാതങ്ങൾ (biases) മുതലായവ രേഖപ്പെടുത്താൻ മോഡൽ കാർഡുകൾ ചേർക്കുക + +ഇതിനെക്കുറിച്ചുള്ള ഒരു പൂർണ്ണമായ ട്യൂട്ടോറിയലിന് [ഡോക്യുമെന്റേഷൻ](https://huggingface.co/docs/huggingface_hub/how-to-upstream) കാണുക, അല്ലെങ്കിൽ കൂടുതൽ ഉയർന്ന തലത്തിലുള്ള [അധ്യായം 4](/course/chapter4) നോക്കുക. + +## ടെക്‌സ്‌റ്റ് എൻകോഡ് ചെയ്യുന്നു[[encoding-text]] + +Transformer മോഡലുകൾ ഇൻപുട്ടുകളെ സംഖ്യകളാക്കി മാറ്റിയാണ് ടെക്‌സ്‌റ്റ് കൈകാര്യം ചെയ്യുന്നത്. നിങ്ങളുടെ ടെക്‌സ്‌റ്റ് ടോക്കണൈസർ പ്രോസസ്സ് ചെയ്യുമ്പോൾ കൃത്യമായി എന്താണ് സംഭവിക്കുന്നത് എന്ന് ഇവിടെ നമ്മൾ നോക്കും. ടോക്കണൈസറുകൾ ടെക്‌സ്‌റ്റിനെ ടോക്കണുകളായി വിഭജിക്കുകയും പിന്നീട് ഈ ടോക്കണുകളെ സംഖ്യകളാക്കി മാറ്റുകയും ചെയ്യുന്നു എന്ന് [അധ്യായം 1](/course/chapter1)-ൽ നമ്മൾ ഇതിനകം കണ്ടു. ഒരു ലളിതമായ ടോക്കണൈസറിലൂടെ ഈ മാറ്റം നമുക്ക് കാണാം: + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") + +encoded_input = tokenizer("Hello, I'm a single sentence!") +print(encoded_input) +``` + +```python out +{'input_ids': [101, 8667, 117, 1000, 1045, 1005, 1049, 2235, 17662, 12172, 1012, 102], + 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]} +``` + +താഴെ പറയുന്ന ഫീൽഡുകളുള്ള ഒരു ഡിക്‌ഷണറി നമുക്ക് ലഭിക്കുന്നു: +- input_ids: നിങ്ങളുടെ ടോക്കണുകളുടെ സംഖ്യാ പ്രതിനിധാനങ്ങൾ +- token_type_ids: ഇൻപുട്ടിന്റെ ഏത് ഭാഗം വാക്യം A ആണെന്നും ഏത് ഭാഗം വാക്യം B ആണെന്നും ഇവ മോഡലിനോട് പറയുന്നു (അടുത്ത ഭാഗത്തിൽ കൂടുതൽ ചർച്ച ചെയ്യുന്നു) +- attention_mask: ഏതൊക്കെ ടോക്കണുകൾ ശ്രദ്ധിക്കണം (attend), ഏതൊക്കെ ശ്രദ്ധിക്കേണ്ടതില്ല എന്ന് ഇത് സൂചിപ്പിക്കുന്നു (അൽപ്പം കഴിഞ്ഞ് കൂടുതൽ ചർച്ച ചെയ്യുന്നു) + +യഥാർത്ഥ ടെക്‌സ്‌റ്റ് തിരികെ ലഭിക്കാൻ ഇൻപുട്ട് ID-കൾ ഡീകോഡ് ചെയ്യാം: + +```py +tokenizer.decode(encoded_input["input_ids"]) +``` + +```python out +"[CLS] Hello, I'm a single sentence! [SEP]" +``` + +മോഡലിന് ആവശ്യമായ പ്രത്യേക ടോക്കണുകൾ — `[CLS]`, `[SEP]` — ടോക്കണൈസർ ചേർത്തിട്ടുണ്ടെന്ന് നിങ്ങൾ ശ്രദ്ധിക്കും. എല്ലാ മോഡലുകൾക്കും പ്രത്യേക ടോക്കണുകൾ ആവശ്യമില്ല; ഒരു മോഡൽ അവ ഉപയോഗിച്ച് പ്രീട്രെയിൻ ചെയ്തിട്ടുണ്ടെങ്കിലാണ് അവ ഉപയോഗപ്പെടുത്തുന്നത്; അങ്ങനെയുള്ള സാഹചര്യത്തിൽ, ആ മോഡൽ ഈ ടോക്കണുകൾ പ്രതീക്ഷിക്കുന്നതിനാൽ ടോക്കണൈസർ അവ ചേർക്കേണ്ടതുണ്ട്. + +ഒന്നിലധികം വാക്യങ്ങൾ ഒരേസമയം എൻകോഡ് ചെയ്യാം — അവയെ ഒരുമിച്ച് ബാച്ച് ചെയ്യുന്നതിലൂടെയോ (ഇത് ഉടൻ ചർച്ച ചെയ്യും) ഒരു ലിസ്‌റ്റ് നൽകുന്നതിലൂടെയോ: + +```py +encoded_input = tokenizer("How are you?", "I'm fine, thank you!") +print(encoded_input) +``` + +```python out +{'input_ids': [[101, 1731, 1132, 1128, 136, 102], [101, 1045, 1005, 1049, 2503, 117, 5763, 1128, 136, 102]], + 'token_type_ids': [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]], + 'attention_mask': [[1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]} +``` + +ഒന്നിലധികം വാക്യങ്ങൾ നൽകുമ്പോൾ, ഓരോ ഡിക്‌ഷണറി മൂല്യത്തിനും ഓരോ വാക്യത്തിനുമായി ഒരു ലിസ്‌റ്റ് വീതം ടോക്കണൈസർ തിരികെ നൽകുന്നു എന്നത് ശ്രദ്ധിക്കുക. PyTorch-ൽ നിന്നുള്ള ടെൻസറുകൾ നേരിട്ട് തിരികെ നൽകാനും ടോക്കണൈസറിനോട് ആവശ്യപ്പെടാം: + +```py +encoded_input = tokenizer("How are you?", "I'm fine, thank you!", return_tensors="pt") +print(encoded_input) +``` + +```python out +{'input_ids': tensor([[ 101, 1731, 1132, 1128, 136, 102], + [ 101, 1045, 1005, 1049, 2503, 117, 5763, 1128, 136, 102]]), + 'token_type_ids': tensor([[0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]), + 'attention_mask': tensor([[1, 1, 1, 1, 1, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]])} +``` + +എന്നാൽ ഇവിടെ ഒരു പ്രശ്നമുണ്ട്: രണ്ട് ലിസ്‌റ്റുകൾക്കും ഒരേ നീളമല്ല! അറേകളും ടെൻസറുകളും ചതുരാകൃതിയിലുള്ളതാകണം (rectangular), അതിനാൽ ഈ ലിസ്‌റ്റുകളെ അതേപടി ഒരു PyTorch ടെൻസറാക്കി (അല്ലെങ്കിൽ NumPy അറേയാക്കി) മാറ്റാൻ കഴിയില്ല. ഇതിനായി ടോക്കണൈസർ ഒരു ഓപ്‌ഷൻ നൽകുന്നു: പാഡിംഗ്. + +### ഇൻപുട്ടുകൾ പാഡ് ചെയ്യുന്നു[[padding-inputs]] + +ഇൻപുട്ടുകൾ പാഡ് ചെയ്യാൻ ടോക്കണൈസറിനോട് ആവശ്യപ്പെട്ടാൽ, ഏറ്റവും നീളമുള്ള വാക്യത്തേക്കാൾ ചെറിയ വാക്യങ്ങളിൽ ഒരു പ്രത്യേക പാഡിംഗ് ടോക്കൺ ചേർത്ത് അത് എല്ലാ വാക്യങ്ങളെയും ഒരേ നീളത്തിലാക്കും: + +```py +encoded_input = tokenizer( + ["How are you?", "I'm fine, thank you!"], padding=True, return_tensors="pt" +) +print(encoded_input) +``` + +```python out +{'input_ids': tensor([[ 101, 1731, 1132, 1128, 136, 102, 0, 0, 0, 0], + [ 101, 1045, 1005, 1049, 2503, 117, 5763, 1128, 136, 102]]), + 'token_type_ids': tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]), + 'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 0, 0, 0, 0], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]])} +``` + +ഇപ്പോൾ നമുക്ക് ചതുരാകൃതിയിലുള്ള ടെൻസറുകൾ ലഭിച്ചു! പാഡിംഗ് ടോക്കണുകൾ ID 0 ഉള്ള ഇൻപുട്ട് ID-കളായി എൻകോഡ് ചെയ്യപ്പെട്ടിരിക്കുന്നു എന്നതും, അവയുടെ അറ്റൻഷൻ മാസ്‌ക് മൂല്യവും 0 ആണെന്നതും ശ്രദ്ധിക്കുക. ആ പാഡിംഗ് ടോക്കണുകൾ മോഡൽ വിശകലനം ചെയ്യേണ്ടതില്ല എന്നതാണ് ഇതിന് കാരണം: അവ യഥാർത്ഥ വാക്യത്തിന്റെ ഭാഗമല്ല. + +### ഇൻപുട്ടുകൾ ട്രങ്കേറ്റ് ചെയ്യുന്നു[[truncating-inputs]] + +മോഡലിന് പ്രോസസ്സ് ചെയ്യാൻ കഴിയാത്തവിധം ടെൻസറുകൾ വളരെ വലുതായേക്കാം. ഉദാഹരണത്തിന്, BERT 512 ടോക്കണുകൾ വരെയുള്ള സീക്വൻസുകൾ ഉപയോഗിച്ച് മാത്രമാണ് പ്രീട്രെയിൻ ചെയ്തിട്ടുള്ളത്, അതിനാൽ അതിനേക്കാൾ നീളമുള്ള സീക്വൻസുകൾ ഇതിന് പ്രോസസ്സ് ചെയ്യാൻ കഴിയില്ല. മോഡലിന് കൈകാര്യം ചെയ്യാൻ കഴിയുന്നതിലും നീളമുള്ള സീക്വൻസുകൾ നിങ്ങൾക്കുണ്ടെങ്കിൽ, `truncation` പാരാമീറ്റർ ഉപയോഗിച്ച് അവ ട്രങ്കേറ്റ് ചെയ്യേണ്ടിവരും (വെട്ടിച്ചുരുക്കേണ്ടിവരും): + +```py +encoded_input = tokenizer( + "This is a very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very very long sentence.", + truncation=True, +) +print(encoded_input["input_ids"]) +``` + +```python out +[101, 1188, 1110, 170, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1505, 1179, 5650, 119, 102] +``` + +പാഡിംഗ്, ട്രങ്കേഷൻ ആർഗ്യുമെന്റുകൾ സംയോജിപ്പിച്ച്, നിങ്ങളുടെ ടെൻസറുകൾക്ക് ആവശ്യമായ കൃത്യമായ വലിപ്പം ഉണ്ടെന്ന് ഉറപ്പാക്കാം: + +```py +encoded_input = tokenizer( + ["How are you?", "I'm fine, thank you!"], + padding=True, + truncation=True, + max_length=5, + return_tensors="pt", +) +print(encoded_input) +``` + +```python out +{'input_ids': tensor([[ 101, 1731, 1132, 1128, 102], + [ 101, 1045, 1005, 1049, 102]]), + 'token_type_ids': tensor([[0, 0, 0, 0, 0], + [0, 0, 0, 0, 0]]), + 'attention_mask': tensor([[1, 1, 1, 1, 1], + [1, 1, 1, 1, 1]])} +``` + +### പ്രത്യേക ടോക്കണുകൾ ചേർക്കുന്നു + +പ്രത്യേക ടോക്കണുകൾ (അല്ലെങ്കിൽ കുറഞ്ഞപക്ഷം അവയുടെ ആശയം) BERT-നും അതിൽ നിന്ന് ഉരുത്തിരിഞ്ഞ മോഡലുകൾക്കും വിശേഷിച്ചും പ്രധാനമാണ്. ഒരു വാക്യത്തിന്റെ തുടക്കം (`[CLS]`) അല്ലെങ്കിൽ വാക്യങ്ങൾക്കിടയിലുള്ള വേർതിരിവ് (`[SEP]`) പോലുള്ള വാക്യ അതിരുകളെ കൂടുതൽ നന്നായി പ്രതിനിധീകരിക്കാനാണ് ഈ ടോക്കണുകൾ ചേർക്കുന്നത്. ഒരു ലളിതമായ ഉദാഹരണം നോക്കാം: + +```py +encoded_input = tokenizer("How are you?") +print(encoded_input["input_ids"]) +tokenizer.decode(encoded_input["input_ids"]) +``` + +```python out +[101, 1731, 1132, 1128, 136, 102] +'[CLS] How are you? [SEP]' +``` + +ഈ പ്രത്യേക ടോക്കണുകൾ ടോക്കണൈസർ സ്വയമേവ ചേർക്കുന്നവയാണ്. എല്ലാ മോഡലുകൾക്കും പ്രത്യേക ടോക്കണുകൾ ആവശ്യമില്ല; ഒരു മോഡൽ അവ ഉപയോഗിച്ച് പ്രീട്രെയിൻ ചെയ്തിട്ടുണ്ടെങ്കിലാണ് പ്രധാനമായും അവ ഉപയോഗിക്കുന്നത്; അങ്ങനെയുള്ള സാഹചര്യത്തിൽ, മോഡൽ അവ പ്രതീക്ഷിക്കുന്നതിനാൽ ടോക്കണൈസർ അവ ചേർക്കും. + +### ഇതെല്ലാം എന്തിനാണ് ആവശ്യം? + +വ്യക്തമായ ഒരു ഉദാഹരണം ഇതാ. ഈ എൻകോഡ് ചെയ്ത സീക്വൻസുകൾ പരിഗണിക്കുക: + +```py +sequences = [ + "I've been waiting for a HuggingFace course my whole life.", + "I hate this so much!", +] +``` + +ടോക്കണൈസ് ചെയ്തുകഴിഞ്ഞാൽ, നമുക്ക് ലഭിക്കുന്നത്: + +```python +encoded_sequences = [ + [ + 101, + 1045, + 1005, + 2310, + 2042, + 3403, + 2005, + 1037, + 17662, + 12172, + 2607, + 2026, + 2878, + 2166, + 1012, + 102, + ], + [101, 1045, 5223, 2023, 2061, 2172, 999, 102], +] +``` + +ഇത് എൻകോഡ് ചെയ്ത സീക്വൻസുകളുടെ ഒരു ലിസ്‌റ്റാണ്: ലിസ്‌റ്റുകളുടെ ഒരു ലിസ്‌റ്റ്. ടെൻസറുകൾ ചതുരാകൃതിയിലുള്ള ഷേപ്പുകൾ മാത്രമേ സ്വീകരിക്കുകയുള്ളൂ (മാട്രിക്‌സുകൾ എന്ന് കരുതുക). ഈ "അറേ" ഇതിനകം ചതുരാകൃതിയിലുള്ളതാണ്, അതിനാൽ അതിനെ ഒരു ടെൻസറാക്കി മാറ്റുന്നത് എളുപ്പമാണ്: + +```py +import torch + +model_inputs = torch.tensor(encoded_sequences) +``` + +### ടെൻസറുകളെ മോഡലിന്റെ ഇൻപുട്ടുകളായി ഉപയോഗിക്കുന്നു[[using-the-tensors-as-inputs-to-the-model]] + +ടെൻസറുകളെ മോഡലിനൊപ്പം ഉപയോഗിക്കുന്നത് അതീവ ലളിതമാണ് — ഇൻപുട്ടുകൾ നൽകി മോഡലിനെ വിളിച്ചാൽ (call) മതി: + +```py +output = model(model_inputs) +``` + +മോഡൽ വ്യത്യസ്തങ്ങളായ നിരവധി ആർഗ്യുമെന്റുകൾ സ്വീകരിക്കുമെങ്കിലും, ഇൻപുട്ട് ID-കൾ മാത്രമേ അത്യാവശ്യമുള്ളൂ. മറ്റ് ആർഗ്യുമെന്റുകൾ എന്ത് ചെയ്യുന്നു എന്നും അവ എപ്പോഴാണ് ആവശ്യമായി വരുന്നത് എന്നും പിന്നീട് വിശദീകരിക്കാം, +എന്നാൽ അതിനുമുമ്പ്, ഒരു Transformer മോഡലിന് മനസ്സിലാക്കാൻ കഴിയുന്ന ഇൻപുട്ടുകൾ നിർമ്മിക്കുന്ന ടോക്കണൈസറുകളെ നമ്മൾ കൂടുതൽ അടുത്ത് പരിശോധിക്കേണ്ടതുണ്ട്. diff --git a/chapters/ml/chapter2/4.mdx b/chapters/ml/chapter2/4.mdx new file mode 100644 index 000000000..751423346 --- /dev/null +++ b/chapters/ml/chapter2/4.mdx @@ -0,0 +1,218 @@ + + +# ടോക്കണൈസറുകൾ[[tokenizers]] + + + + + +NLP പൈപ്പ്‌ലൈനിന്റെ അടിസ്ഥാന ഘടകങ്ങളിലൊന്നാണ് ടോക്കണൈസറുകൾ. അവയ്ക്ക് ഒരേയൊരു ലക്ഷ്യമാണുള്ളത്: ടെക്‌സ്‌റ്റിനെ മോഡലിന് പ്രോസസ്സ് ചെയ്യാൻ കഴിയുന്ന ഡേറ്റയിലേക്ക് മാറ്റുക. മോഡലുകൾക്ക് സംഖ്യകൾ മാത്രമേ പ്രോസസ്സ് ചെയ്യാൻ കഴിയൂ, അതിനാൽ നമ്മുടെ ടെക്‌സ്‌റ്റ് ഇൻപുട്ടുകളെ സംഖ്യാ ഡേറ്റയിലേക്ക് മാറ്റേണ്ട ജോലി ടോക്കണൈസറുകൾക്കാണ്. ടോക്കണൈസേഷൻ പൈപ്പ്‌ലൈനിൽ കൃത്യമായി എന്താണ് സംഭവിക്കുന്നത് എന്ന് ഈ ഭാഗത്തിൽ നമ്മൾ പരിശോധിക്കും. + +NLP ടാസ്‌ക്കുകളിൽ സാധാരണയായി പ്രോസസ്സ് ചെയ്യുന്ന ഡേറ്റ അസംസ്കൃത ടെക്‌സ്‌റ്റ് (raw text) ആണ്. അത്തരം ടെക്‌സ്‌റ്റിന്റെ ഒരു ഉദാഹരണം ഇതാ: + +``` +Jim Henson was a puppeteer +``` + +എന്നാൽ, മോഡലുകൾക്ക് സംഖ്യകൾ മാത്രമേ പ്രോസസ്സ് ചെയ്യാൻ കഴിയൂ, അതിനാൽ അസംസ്കൃത ടെക്‌സ്‌റ്റിനെ സംഖ്യകളാക്കി മാറ്റാൻ ഒരു വഴി നമ്മൾ കണ്ടെത്തേണ്ടതുണ്ട്. അതാണ് ടോക്കണൈസറുകൾ ചെയ്യുന്നത്, ഇത് ചെയ്യാൻ ഒരുപാട് വഴികളുമുണ്ട്. ഏറ്റവും അർത്ഥവത്തായ പ്രതിനിധാനം (representation) — അതായത്, മോഡലിന് ഏറ്റവും അർത്ഥപൂർണ്ണമായി തോന്നുന്നത് — കണ്ടെത്തുകയാണ് ലക്ഷ്യം; സാധ്യമെങ്കിൽ, ഏറ്റവും ചെറിയ പ്രതിനിധാനവും. + +ടോക്കണൈസേഷൻ അൽഗോരിതങ്ങളുടെ ചില ഉദാഹരണങ്ങൾ നോക്കാം, ടോക്കണൈസേഷനെക്കുറിച്ച് നിങ്ങൾക്കുണ്ടാകാവുന്ന ചില ചോദ്യങ്ങൾക്ക് ഉത്തരം കണ്ടെത്താൻ ശ്രമിക്കാം. + +## വാക്ക് അടിസ്ഥാനമാക്കിയുള്ളത് (Word-based)[[word-based]] + + + +ആദ്യം മനസ്സിൽ വരുന്ന തരം ടോക്കണൈസർ _വാക്ക് അടിസ്ഥാനമാക്കിയുള്ളത്_ (word-based) ആണ്. കുറച്ച് നിയമങ്ങൾ മാത്രം ഉപയോഗിച്ച് ഇത് സെറ്റപ്പ് ചെയ്യാനും ഉപയോഗിക്കാനും പൊതുവേ വളരെ എളുപ്പമാണ്, പലപ്പോഴും ഇത് തൃപ്തികരമായ ഫലങ്ങളും നൽകുന്നു. ഉദാഹരണത്തിന്, താഴെയുള്ള ചിത്രത്തിൽ, അസംസ്കൃത ടെക്‌സ്‌റ്റിനെ വാക്കുകളായി വിഭജിച്ച് അവയോരോന്നിനും ഒരു സംഖ്യാ പ്രതിനിധാനം കണ്ടെത്തുകയാണ് ലക്ഷ്യം: + +
+ വാക്ക് അടിസ്ഥാനമാക്കിയുള്ള ടോക്കണൈസേഷന്റെ ഒരു ഉദാഹരണം. + +
+ +ടെക്‌സ്‌റ്റ് വിഭജിക്കാൻ വ്യത്യസ്ത വഴികളുണ്ട്. ഉദാഹരണത്തിന്, Python-ന്റെ `split()` ഫംഗ്‌ഷൻ ഉപയോഗിച്ച്, വൈറ്റ്‌സ്‌പേസ് (whitespace) അടിസ്ഥാനമാക്കി ടെക്‌സ്‌റ്റിനെ വാക്കുകളായി ടോക്കണൈസ് ചെയ്യാം: + +```py +tokenized_text = "Jim Henson was a puppeteer".split() +print(tokenized_text) +``` + +```python out +['Jim', 'Henson', 'was', 'a', 'puppeteer'] +``` + +ചിഹ്നങ്ങൾക്കായി (punctuation) അധിക നിയമങ്ങളുള്ള വേഡ് ടോക്കണൈസറുകളുടെ വകഭേദങ്ങളുമുണ്ട്. ഇത്തരം ടോക്കണൈസർ ഉപയോഗിക്കുമ്പോൾ, വളരെ വലിയ "വൊക്കാബുലറികൾ" (vocabularies) നമുക്ക് ലഭിക്കാം; നമ്മുടെ കോർപ്പസിൽ (corpus) ഉള്ള സ്വതന്ത്ര ടോക്കണുകളുടെ മൊത്തം എണ്ണമാണ് ഒരു വൊക്കാബുലറിയെ നിർവചിക്കുന്നത്. + +ഓരോ വാക്കിനും 0 മുതൽ വൊക്കാബുലറിയുടെ വലുപ്പം വരെയുള്ള ഒരു ID നൽകപ്പെടുന്നു. ഓരോ വാക്കിനെയും തിരിച്ചറിയാൻ മോഡൽ ഈ ID-കൾ ഉപയോഗിക്കുന്നു. + +വാക്ക് അടിസ്ഥാനമാക്കിയുള്ള ഒരു ടോക്കണൈസർ ഉപയോഗിച്ച് ഒരു ഭാഷയെ പൂർണ്ണമായി ഉൾക്കൊള്ളണമെങ്കിൽ, ആ ഭാഷയിലെ ഓരോ വാക്കിനും ഒരു ഐഡന്റിഫയർ വേണ്ടിവരും, അത് വളരെയധികം ടോക്കണുകൾ സൃഷ്ടിക്കും. ഉദാഹരണത്തിന്, ഇംഗ്ലീഷ് ഭാഷയിൽ 500,000-ത്തിലധികം വാക്കുകളുണ്ട്, അതിനാൽ ഓരോ വാക്കിൽ നിന്നും ഒരു ഇൻപുട്ട് ID-യിലേക്കുള്ള ഒരു മാപ്പ് ഉണ്ടാക്കാൻ അത്രയും ID-കൾ നമ്മൾ സൂക്ഷിക്കേണ്ടിവരും. കൂടാതെ, "dog" പോലുള്ള വാക്കുകൾ "dogs" പോലുള്ള വാക്കുകളിൽ നിന്ന് വ്യത്യസ്തമായാണ് പ്രതിനിധീകരിക്കപ്പെടുന്നത്, "dog"-ഉം "dogs"-ഉം സമാനമാണെന്ന് അറിയാൻ മോഡലിന് തുടക്കത്തിൽ ഒരു വഴിയുമില്ല: രണ്ട് വാക്കുകളെയും പരസ്പരബന്ധമില്ലാത്തവയായി അത് തിരിച്ചറിയും. "run", "running" പോലുള്ള മറ്റ് സമാന വാക്കുകൾക്കും ഇത് ബാധകമാണ്; തുടക്കത്തിൽ മോഡൽ അവയെ സമാനമായി കാണില്ല. + +അവസാനമായി, നമ്മുടെ വൊക്കാബുലറിയിൽ ഇല്ലാത്ത വാക്കുകളെ പ്രതിനിധീകരിക്കാൻ ഒരു പ്രത്യേക ടോക്കൺ നമുക്ക് ആവശ്യമാണ്. ഇത് "unknown" ടോക്കൺ എന്ന് അറിയപ്പെടുന്നു, പലപ്പോഴും "[UNK]" അല്ലെങ്കിൽ "<unk>" എന്ന് പ്രതിനിധീകരിക്കപ്പെടുന്നു. ടോക്കണൈസർ ഇത്തരം ടോക്കണുകൾ ഒരുപാട് സൃഷ്ടിക്കുന്നതായി കണ്ടാൽ അത് പൊതുവേ ഒരു മോശം ലക്ഷണമാണ്, കാരണം ഒരു വാക്കിന്റെ അർത്ഥവത്തായ ഒരു പ്രതിനിധാനം കണ്ടെത്താൻ അതിന് കഴിഞ്ഞില്ല എന്നും ആ വഴിയിൽ നിങ്ങൾക്ക് വിവരങ്ങൾ നഷ്ടപ്പെടുന്നു എന്നുമാണ് അതിനർത്ഥം. വൊക്കാബുലറി രൂപപ്പെടുത്തുമ്പോൾ, കഴിയുന്നത്ര കുറച്ച് വാക്കുകൾ മാത്രം unknown ടോക്കണിലേക്ക് ടോക്കണൈസ് ചെയ്യപ്പെടുന്ന രീതിയിൽ അത് ചെയ്യുകയാണ് ലക്ഷ്യം. + +unknown ടോക്കണുകളുടെ എണ്ണം കുറയ്ക്കാനുള്ള ഒരു വഴി, ഒരു തലം കൂടി താഴേക്ക് പോയി _അക്ഷരം അടിസ്ഥാനമാക്കിയുള്ള_ (character-based) ഒരു ടോക്കണൈസർ ഉപയോഗിക്കുന്നതാണ്. + +## അക്ഷരം അടിസ്ഥാനമാക്കിയുള്ളത് (Character-based)[[character-based]] + + + +അക്ഷരം അടിസ്ഥാനമാക്കിയുള്ള ടോക്കണൈസറുകൾ ടെക്‌സ്‌റ്റിനെ വാക്കുകളായല്ല, അക്ഷരങ്ങളായാണ് വിഭജിക്കുന്നത്. ഇതിന് രണ്ട് പ്രധാന ഗുണങ്ങളുണ്ട്: + +- വൊക്കാബുലറി വളരെ ചെറുതാണ്. +- ഓരോ വാക്കും അക്ഷരങ്ങളിൽ നിന്ന് നിർമ്മിക്കാൻ കഴിയുന്നതിനാൽ, വൊക്കാബുലറിക്ക് പുറത്തുള്ള (unknown) ടോക്കണുകൾ വളരെ കുറവാണ്. + +എന്നാൽ ഇവിടെയും സ്‌പേസുകളെയും ചിഹ്നങ്ങളെയും സംബന്ധിച്ച് ചില ചോദ്യങ്ങൾ ഉയരുന്നു: + +
+ അക്ഷരം അടിസ്ഥാനമാക്കിയുള്ള ടോക്കണൈസേഷന്റെ ഒരു ഉദാഹരണം. + +
+ +ഈ സമീപനവും പൂർണ്ണമല്ല. പ്രതിനിധാനം ഇപ്പോൾ വാക്കുകളെയല്ല അക്ഷരങ്ങളെയാണ് അടിസ്ഥാനമാക്കുന്നത് എന്നതിനാൽ, അവബോധപരമായി ഇത് അർത്ഥം കുറഞ്ഞതാണെന്ന് ഒരാൾക്ക് വാദിക്കാം: ഓരോ അക്ഷരത്തിനും സ്വന്തമായി വലിയ അർത്ഥമില്ല, എന്നാൽ വാക്കുകളുടെ കാര്യത്തിൽ അങ്ങനെയല്ല. എങ്കിലും, ഇതും ഭാഷയനുസരിച്ച് വ്യത്യാസപ്പെടുന്നു; ഉദാഹരണത്തിന്, ചൈനീസിൽ ഓരോ അക്ഷരവും ഒരു ലാറ്റിൻ ഭാഷയിലെ അക്ഷരത്തെക്കാൾ കൂടുതൽ വിവരങ്ങൾ വഹിക്കുന്നു. + +പരിഗണിക്കേണ്ട മറ്റൊരു കാര്യം, നമ്മുടെ മോഡലിന് പ്രോസസ്സ് ചെയ്യാൻ വളരെ വലിയ അളവിലുള്ള ടോക്കണുകൾ ഉണ്ടാകും എന്നതാണ്: വാക്ക് അടിസ്ഥാനമാക്കിയുള്ള ഒരു ടോക്കണൈസറിൽ ഒരു വാക്ക് ഒരൊറ്റ ടോക്കൺ മാത്രമായിരിക്കുമ്പോൾ, അക്ഷരങ്ങളാക്കി മാറ്റുമ്പോൾ അത് എളുപ്പത്തിൽ 10-ഓ അതിലധികമോ ടോക്കണുകളായി മാറാം. + +രണ്ടിന്റെയും മികച്ച വശങ്ങൾ നേടാൻ, ഈ രണ്ട് സമീപനങ്ങളെയും സംയോജിപ്പിക്കുന്ന മൂന്നാമതൊരു സങ്കേതം നമുക്ക് ഉപയോഗിക്കാം: *സബ്‌വേഡ് ടോക്കണൈസേഷൻ* (subword tokenization). + +## സബ്‌വേഡ് ടോക്കണൈസേഷൻ[[subword-tokenization]] + + + +പതിവായി ഉപയോഗിക്കുന്ന വാക്കുകളെ ചെറിയ സബ്‌വേഡുകളായി വിഭജിക്കരുത്, എന്നാൽ അപൂർവ വാക്കുകളെ അർത്ഥവത്തായ സബ്‌വേഡുകളായി വിഘടിപ്പിക്കണം എന്ന തത്ത്വത്തെയാണ് സബ്‌വേഡ് ടോക്കണൈസേഷൻ അൽഗോരിതങ്ങൾ ആശ്രയിക്കുന്നത്. + +ഉദാഹരണത്തിന്, "annoyingly" ഒരു അപൂർവ വാക്കായി കണക്കാക്കപ്പെടാം, അതിനെ "annoying", "ly" എന്നിങ്ങനെ വിഘടിപ്പിക്കാം. ഇവ രണ്ടും സ്വതന്ത്ര സബ്‌വേഡുകളായി കൂടുതൽ പതിവായി പ്രത്യക്ഷപ്പെടാൻ സാധ്യതയുണ്ട്; അതേസമയം, "annoying", "ly" എന്നിവയുടെ സംയുക്ത അർത്ഥത്തിലൂടെ "annoyingly"-യുടെ അർത്ഥം നിലനിർത്തപ്പെടുകയും ചെയ്യുന്നു. + +"Let's do tokenization!" എന്ന സീക്വൻസിനെ ഒരു സബ്‌വേഡ് ടോക്കണൈസേഷൻ അൽഗോരിതം എങ്ങനെ ടോക്കണൈസ് ചെയ്യും എന്ന് കാണിക്കുന്ന ഒരു ഉദാഹരണം ഇതാ: + +
+ ഒരു സബ്‌വേഡ് ടോക്കണൈസേഷൻ അൽഗോരിതം. + +
+ +ഈ സബ്‌വേഡുകൾ ധാരാളം അർത്ഥപരമായ (semantic) വിവരങ്ങൾ നൽകുന്നു: ഉദാഹരണത്തിന്, മുകളിലെ ഉദാഹരണത്തിൽ "tokenization" എന്നത് "token", "ization" എന്നീ രണ്ട് ടോക്കണുകളായി വിഭജിക്കപ്പെട്ടു — ഇവ രണ്ടിനും അർത്ഥപരമായ പ്രാധാന്യമുണ്ട്, അതേസമയം സ്ഥലം ലാഭിക്കുകയും ചെയ്യുന്നു (ഒരു നീണ്ട വാക്കിനെ പ്രതിനിധീകരിക്കാൻ രണ്ട് ടോക്കണുകൾ മാത്രം മതി). ചെറിയ വൊക്കാബുലറികൾ ഉപയോഗിച്ച് താരതമ്യേന മികച്ച കവറേജ് നേടാനും, unknown ടോക്കണുകൾ ഏതാണ്ട് ഇല്ലാതാക്കാനും ഇത് നമ്മെ സഹായിക്കുന്നു. + +സബ്‌വേഡുകൾ കൂട്ടിച്ചേർത്ത് (ഏതാണ്ട്) എത്ര നീളമുള്ള സങ്കീർണ്ണ വാക്കുകളും രൂപപ്പെടുത്താൻ കഴിയുന്ന ടർക്കിഷ് പോലുള്ള സംയോജക (agglutinative) ഭാഷകളിൽ ഈ സമീപനം പ്രത്യേകിച്ചും ഉപകാരപ്രദമാണ്. + +### ഇനിയും ഉണ്ട്![[and-more]] + +പ്രതീക്ഷിക്കാവുന്നതുപോലെ, ഇനിയും ഒട്ടേറെ സങ്കേതങ്ങളുണ്ട്. ചിലത് പറയുകയാണെങ്കിൽ: + +- GPT-2-ൽ ഉപയോഗിക്കുന്ന Byte-level BPE +- BERT-ൽ ഉപയോഗിക്കുന്ന WordPiece +- പല ബഹുഭാഷാ മോഡലുകളിലും ഉപയോഗിക്കുന്ന SentencePiece അല്ലെങ്കിൽ Unigram + +API ഉപയോഗിച്ച് തുടങ്ങാൻ ആവശ്യമായത്ര അറിവ്, ടോക്കണൈസറുകൾ എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്നതിനെക്കുറിച്ച് ഇപ്പോൾ നിങ്ങൾക്ക് ഉണ്ടായിരിക്കണം. + +## ലോഡ് ചെയ്യലും സേവ് ചെയ്യലും[[loading-and-saving]] + +ടോക്കണൈസറുകൾ ലോഡ് ചെയ്യുന്നതും സേവ് ചെയ്യുന്നതും മോഡലുകളുടെ കാര്യത്തിലേതുപോലെ തന്നെ ലളിതമാണ്. വാസ്തവത്തിൽ, ഇത് അതേ രണ്ട് മെത്തേഡുകളെ അടിസ്ഥാനമാക്കിയുള്ളതാണ്: `from_pretrained()`, `save_pretrained()`. ഈ മെത്തേഡുകൾ ടോക്കണൈസർ ഉപയോഗിക്കുന്ന അൽഗോരിതവും (മോഡലിന്റെ *ആർക്കിടെക്‌ചർ* പോലെ) അതിന്റെ വൊക്കാബുലറിയും (മോഡലിന്റെ *വെയ്‌റ്റുകൾ* പോലെ) ലോഡ് ചെയ്യുകയോ സേവ് ചെയ്യുകയോ ചെയ്യും. + +BERT-ന്റെ അതേ ചെക്ക്‌പോയിന്റ് ഉപയോഗിച്ച് പരിശീലിപ്പിച്ച BERT ടോക്കണൈസർ ലോഡ് ചെയ്യുന്നത് മോഡൽ ലോഡ് ചെയ്യുന്ന അതേ രീതിയിലാണ്, ഒരു വ്യത്യാസം മാത്രം: നമ്മൾ `BertTokenizer` ക്ലാസ് ഉപയോഗിക്കുന്നു: + +```py +from transformers import BertTokenizer + +tokenizer = BertTokenizer.from_pretrained("bert-base-cased") +``` + +`AutoModel`-ന് സമാനമായി, `AutoTokenizer` ക്ലാസ് ചെക്ക്‌പോയിന്റിന്റെ പേരിന്റെ അടിസ്ഥാനത്തിൽ ലൈബ്രറിയിലെ ശരിയായ ടോക്കണൈസർ ക്ലാസ് കണ്ടെത്തും, ഏത് ചെക്ക്‌പോയിന്റിനോടൊപ്പവും ഇത് നേരിട്ട് ഉപയോഗിക്കാം: + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +``` + +മുൻ ഭാഗത്തിൽ കാണിച്ചതുപോലെ ഇപ്പോൾ നമുക്ക് ടോക്കണൈസർ ഉപയോഗിക്കാം: + +```python +tokenizer("Using a Transformer network is simple") +``` + +```python out +{'input_ids': [101, 7993, 170, 11303, 1200, 2443, 1110, 3014, 102], + 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 0], + 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]} +``` + +ഒരു ടോക്കണൈസർ സേവ് ചെയ്യുന്നത് ഒരു മോഡൽ സേവ് ചെയ്യുന്നതിന് സമാനമാണ്: + +```py +tokenizer.save_pretrained("directory_on_my_computer") +``` + +`token_type_ids`-നെക്കുറിച്ച് [അധ്യായം 3](/course/chapter3)-ൽ നമ്മൾ കൂടുതൽ സംസാരിക്കും, `attention_mask` കീ കുറച്ചു കഴിഞ്ഞ് വിശദീകരിക്കും. ആദ്യം, `input_ids` എങ്ങനെ സൃഷ്ടിക്കപ്പെടുന്നു എന്ന് നോക്കാം. ഇതിനായി, ടോക്കണൈസറിന്റെ ഇടനില മെത്തേഡുകൾ (intermediate methods) നമ്മൾ പരിശോധിക്കേണ്ടതുണ്ട്. + +## എൻകോഡിംഗ്[[encoding]] + + + +ടെക്‌സ്‌റ്റിനെ സംഖ്യകളാക്കി മാറ്റുന്നതിനെ _എൻകോഡിംഗ്_ (encoding) എന്ന് വിളിക്കുന്നു. എൻകോഡിംഗ് രണ്ട് ഘട്ടങ്ങളുള്ള ഒരു പ്രക്രിയയായാണ് നടക്കുന്നത്: ആദ്യം ടോക്കണൈസേഷൻ, തുടർന്ന് ഇൻപുട്ട് ID-കളിലേക്കുള്ള മാറ്റം. + +നമ്മൾ കണ്ടതുപോലെ, ആദ്യ ഘട്ടം ടെക്‌സ്‌റ്റിനെ വാക്കുകളായി (അല്ലെങ്കിൽ വാക്കുകളുടെ ഭാഗങ്ങൾ, ചിഹ്നങ്ങൾ തുടങ്ങിയവയായി) വിഭജിക്കുന്നതാണ്; ഇവയെ സാധാരണയായി *ടോക്കണുകൾ* എന്ന് വിളിക്കുന്നു. ആ പ്രക്രിയയെ നിയന്ത്രിക്കാൻ കഴിയുന്ന പല നിയമങ്ങളുണ്ട്, അതുകൊണ്ടാണ് മോഡലിന്റെ പേര് ഉപയോഗിച്ച് ടോക്കണൈസർ ഇൻസ്‌റ്റാൻഷ്യേറ്റ് ചെയ്യേണ്ടത് — മോഡൽ പ്രീട്രെയിൻ ചെയ്തപ്പോൾ ഉപയോഗിച്ച അതേ നിയമങ്ങൾ തന്നെയാണ് നമ്മൾ ഉപയോഗിക്കുന്നത് എന്ന് ഉറപ്പാക്കാൻ. + +രണ്ടാമത്തെ ഘട്ടം ആ ടോക്കണുകളെ സംഖ്യകളാക്കി മാറ്റുന്നതാണ്, അതുവഴി അവയിൽ നിന്ന് ഒരു ടെൻസർ (tensor) നിർമ്മിച്ച് മോഡലിലേക്ക് നൽകാൻ നമുക്ക് കഴിയും. ഇതിനായി, ടോക്കണൈസറിന് ഒരു *വൊക്കാബുലറി* ഉണ്ട്; `from_pretrained()` മെത്തേഡ് ഉപയോഗിച്ച് ടോക്കണൈസർ ഇൻസ്‌റ്റാൻഷ്യേറ്റ് ചെയ്യുമ്പോൾ നമ്മൾ ഡൗൺലോഡ് ചെയ്യുന്ന ഭാഗമാണ് ഇത്. ഇവിടെയും, മോഡൽ പ്രീട്രെയിൻ ചെയ്തപ്പോൾ ഉപയോഗിച്ച അതേ വൊക്കാബുലറി തന്നെ നമ്മൾ ഉപയോഗിക്കേണ്ടതുണ്ട്. + +ഈ രണ്ട് ഘട്ടങ്ങളും കൂടുതൽ നന്നായി മനസ്സിലാക്കാൻ, നമ്മൾ അവയെ വെവ്വേറെ പരിശോധിക്കും. ആ ഘട്ടങ്ങളുടെ ഇടക്കാല ഫലങ്ങൾ നിങ്ങൾക്ക് കാണിച്ചുതരാൻ, ടോക്കണൈസേഷൻ പൈപ്പ്‌ലൈനിന്റെ ഭാഗങ്ങൾ വെവ്വേറെ നിർവഹിക്കുന്ന ചില മെത്തേഡുകൾ നമ്മൾ ഉപയോഗിക്കും; എന്നാൽ പ്രായോഗികമായി, നിങ്ങളുടെ ഇൻപുട്ടുകളിൽ ടോക്കണൈസർ നേരിട്ട് വിളിക്കുകയാണ് വേണ്ടത് (ഭാഗം 2-ൽ കാണിച്ചതുപോലെ). + +### ടോക്കണൈസേഷൻ[[tokenization]] + +ടോക്കണൈസേഷൻ പ്രക്രിയ ടോക്കണൈസറിന്റെ `tokenize()` മെത്തേഡ് ആണ് നിർവഹിക്കുന്നത്: + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") + +sequence = "Using a Transformer network is simple" +tokens = tokenizer.tokenize(sequence) + +print(tokens) +``` + +ഈ മെത്തേഡിന്റെ ഔട്ട്‌പുട്ട് സ്ട്രിംഗുകളുടെ, അതായത് ടോക്കണുകളുടെ, ഒരു ലിസ്‌റ്റാണ്: + +```python out +['Using', 'a', 'transform', '##er', 'network', 'is', 'simple'] +``` + +ഈ ടോക്കണൈസർ ഒരു സബ്‌വേഡ് ടോക്കണൈസറാണ്: അതിന്റെ വൊക്കാബുലറി ഉപയോഗിച്ച് പ്രതിനിധീകരിക്കാൻ കഴിയുന്ന ടോക്കണുകൾ ലഭിക്കുന്നതുവരെ ഇത് വാക്കുകളെ വിഭജിക്കുന്നു. ഇവിടെ `transformer`-ന്റെ കാര്യത്തിൽ അതാണ് സംഭവിച്ചത്; അത് രണ്ട് ടോക്കണുകളായി വിഭജിക്കപ്പെട്ടു: `transform`, `##er`. + +### ടോക്കണുകളിൽ നിന്ന് ഇൻപുട്ട് ID-കളിലേക്ക്[[from-tokens-to-input-ids]] + +ഇൻപുട്ട് ID-കളിലേക്കുള്ള മാറ്റം ടോക്കണൈസറിന്റെ `convert_tokens_to_ids()` മെത്തേഡ് ആണ് കൈകാര്യം ചെയ്യുന്നത്: + +```py +ids = tokenizer.convert_tokens_to_ids(tokens) + +print(ids) +``` + +```python out +[7993, 170, 11303, 1200, 2443, 1110, 3014] +``` + +ഈ ഔട്ട്‌പുട്ടുകൾ, അനുയോജ്യമായ ഫ്രെയിംവർക്ക് ടെൻസറിലേക്ക് മാറ്റിയ ശേഷം, ഈ അധ്യായത്തിൽ മുമ്പ് കണ്ടതുപോലെ ഒരു മോഡലിന്റെ ഇൻപുട്ടുകളായി ഉപയോഗിക്കാം. + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** ഭാഗം 2-ൽ നമ്മൾ ഉപയോഗിച്ച ഇൻപുട്ട് വാക്യങ്ങളിൽ ("I've been waiting for a HuggingFace course my whole life.", "I hate this so much!") അവസാനത്തെ രണ്ട് ഘട്ടങ്ങൾ (ടോക്കണൈസേഷനും ഇൻപുട്ട് ID-കളിലേക്കുള്ള മാറ്റവും) ആവർത്തിക്കുക. മുമ്പ് നമുക്ക് ലഭിച്ച അതേ ഇൻപുട്ട് ID-കൾ തന്നെയാണ് നിങ്ങൾക്കും ലഭിക്കുന്നത് എന്ന് ഉറപ്പുവരുത്തുക! + +## ഡീകോഡിംഗ്[[decoding]] + +*ഡീകോഡിംഗ്* (decoding) എന്നത് ഇതിന്റെ വിപരീത ദിശയിലുള്ള യാത്രയാണ്: വൊക്കാബുലറി ഇൻഡെക്‌സുകളിൽ നിന്ന് ഒരു സ്ട്രിംഗ് ലഭിക്കണം. താഴെ കാണിച്ചിരിക്കുന്നതുപോലെ `decode()` മെത്തേഡ് ഉപയോഗിച്ച് ഇത് ചെയ്യാം: + +```py +decoded_string = tokenizer.decode([7993, 170, 11303, 1200, 2443, 1110, 3014]) +print(decoded_string) +``` + +```python out +'Using a Transformer network is simple' +``` + +`decode` മെത്തേഡ് ഇൻഡെക്‌സുകളെ ടോക്കണുകളാക്കി തിരികെ മാറ്റുക മാത്രമല്ല, വായിക്കാവുന്ന ഒരു വാക്യം ഉണ്ടാക്കാൻ ഒരേ വാക്കിന്റെ ഭാഗമായിരുന്ന ടോക്കണുകളെ ഒരുമിച്ച് കൂട്ടിച്ചേർക്കുകയും ചെയ്യുന്നു എന്നത് ശ്രദ്ധിക്കുക. പുതിയ ടെക്‌സ്‌റ്റ് പ്രവചിക്കുന്ന മോഡലുകൾ ഉപയോഗിക്കുമ്പോൾ (ഒരു പ്രോംപ്‌റ്റിൽ നിന്ന് സൃഷ്ടിക്കുന്ന ടെക്‌സ്‌റ്റ് ആയാലും, വിവർത്തനം അല്ലെങ്കിൽ സംഗ്രഹം പോലുള്ള സീക്വൻസ്-ടു-സീക്വൻസ് പ്രശ്നങ്ങൾക്കായാലും) ഈ പ്രവർത്തനരീതി അത്യധികം ഉപകാരപ്രദമാകും. + +ഒരു ടോക്കണൈസറിന് കൈകാര്യം ചെയ്യാൻ കഴിയുന്ന അടിസ്ഥാന പ്രവർത്തനങ്ങൾ ഇപ്പോൾ നിങ്ങൾക്ക് മനസ്സിലായിട്ടുണ്ടാകണം: ടോക്കണൈസേഷൻ, ID-കളിലേക്കുള്ള മാറ്റം, ID-കളെ തിരികെ ഒരു സ്ട്രിംഗിലേക്ക് മാറ്റൽ. എന്നാൽ, നമ്മൾ മഞ്ഞുമലയുടെ അറ്റം മാത്രമേ തൊട്ടിട്ടുള്ളൂ. അടുത്ത ഭാഗത്തിൽ, നമ്മുടെ സമീപനത്തെ അതിന്റെ പരിധികളിലേക്ക് കൊണ്ടുപോകുകയും അവയെ എങ്ങനെ മറികടക്കാം എന്ന് നോക്കുകയും ചെയ്യും. diff --git a/chapters/ml/chapter2/5.mdx b/chapters/ml/chapter2/5.mdx new file mode 100644 index 000000000..be00a241e --- /dev/null +++ b/chapters/ml/chapter2/5.mdx @@ -0,0 +1,200 @@ + + +# ഒന്നിലധികം സീക്വൻസുകൾ കൈകാര്യം ചെയ്യുന്നു[[handling-multiple-sequences]] + + + + + +മുൻ ഭാഗത്തിൽ, ഏറ്റവും ലളിതമായ ഉപയോഗസന്ദർഭം നമ്മൾ പരിശോധിച്ചു: ചെറിയ നീളമുള്ള ഒരൊറ്റ സീക്വൻസിൽ ഇൻഫറൻസ് നടത്തുക. എന്നാൽ, ഇപ്പോൾ തന്നെ ചില ചോദ്യങ്ങൾ ഉയർന്നുവരുന്നു: + +- ഒന്നിലധികം സീക്വൻസുകൾ നമ്മൾ എങ്ങനെ കൈകാര്യം ചെയ്യും? +- *വ്യത്യസ്ത നീളമുള്ള* ഒന്നിലധികം സീക്വൻസുകൾ നമ്മൾ എങ്ങനെ കൈകാര്യം ചെയ്യും? +- ഒരു മോഡൽ നന്നായി പ്രവർത്തിക്കാൻ സഹായിക്കുന്ന ഒരേയൊരു ഇൻപുട്ട് വൊക്കാബുലറി ഇൻഡെക്‌സുകൾ മാത്രമാണോ? +- വളരെ നീണ്ട സീക്വൻസ് എന്നൊരു കാര്യമുണ്ടോ? + +ഈ ചോദ്യങ്ങൾ ഏതുതരം പ്രശ്നങ്ങളാണ് ഉയർത്തുന്നത് എന്നും, 🤗 Transformers API ഉപയോഗിച്ച് അവ എങ്ങനെ പരിഹരിക്കാം എന്നും നോക്കാം. + +## മോഡലുകൾ പ്രതീക്ഷിക്കുന്നത് ഇൻപുട്ടുകളുടെ ഒരു ബാച്ചാണ്[[models-expect-a-batch-of-inputs]] + +മുൻ അഭ്യാസത്തിൽ, സീക്വൻസുകൾ എങ്ങനെ സംഖ്യകളുടെ ലിസ്‌റ്റുകളായി മാറ്റപ്പെടുന്നു എന്ന് നിങ്ങൾ കണ്ടു. ഈ സംഖ്യകളുടെ ലിസ്‌റ്റിനെ ഒരു ടെൻസറാക്കി മാറ്റി മോഡലിലേക്ക് അയയ്ക്കാം: + +```py +import torch +from transformers import AutoTokenizer, AutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = AutoModelForSequenceClassification.from_pretrained(checkpoint) + +sequence = "I've been waiting for a HuggingFace course my whole life." + +tokens = tokenizer.tokenize(sequence) +ids = tokenizer.convert_tokens_to_ids(tokens) +input_ids = torch.tensor(ids) +# This line will fail. +model(input_ids) +``` + +```python out +IndexError: Dimension out of range (expected to be in range of [-1, 0], but got 1) +``` + +അയ്യോ! ഇത് എന്തുകൊണ്ടാണ് പരാജയപ്പെട്ടത്? ഭാഗം 2-ലെ പൈപ്പ്‌ലൈനിലെ ഘട്ടങ്ങൾ തന്നെയാണല്ലോ നമ്മൾ പിന്തുടർന്നത്. + +പ്രശ്നം ഇതാണ്: നമ്മൾ മോഡലിലേക്ക് ഒരൊറ്റ സീക്വൻസ് അയച്ചു, എന്നാൽ 🤗 Transformers മോഡലുകൾ ഡിഫോൾട്ടായി ഒന്നിലധികം വാക്യങ്ങളാണ് പ്രതീക്ഷിക്കുന്നത്. ഒരു `sequence`-ൽ ടോക്കണൈസർ പ്രയോഗിച്ചപ്പോൾ അത് തിരശ്ശീലയ്ക്ക് പിന്നിൽ ചെയ്ത എല്ലാ കാര്യങ്ങളും ഇവിടെ നമ്മൾ സ്വയം ചെയ്യാൻ ശ്രമിച്ചു. എന്നാൽ സൂക്ഷിച്ചുനോക്കിയാൽ, ടോക്കണൈസർ ഇൻപുട്ട് ID-കളുടെ ലിസ്‌റ്റിനെ വെറുതെ ഒരു ടെൻസറാക്കി മാറ്റുക മാത്രമല്ല ചെയ്തത്, അതിന് മുകളിൽ ഒരു ഡൈമെൻഷൻ കൂടി ചേർത്തു എന്ന് നിങ്ങൾ കാണും: + +```py +tokenized_inputs = tokenizer(sequence, return_tensors="pt") +print(tokenized_inputs["input_ids"]) +``` + +```python out +tensor([[ 101, 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, + 2607, 2026, 2878, 2166, 1012, 102]]) +``` + +ഒരു പുതിയ ഡൈമെൻഷൻ ചേർത്ത് വീണ്ടും ശ്രമിക്കാം: + +```py +import torch +from transformers import AutoTokenizer, AutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = AutoModelForSequenceClassification.from_pretrained(checkpoint) + +sequence = "I've been waiting for a HuggingFace course my whole life." + +tokens = tokenizer.tokenize(sequence) +ids = tokenizer.convert_tokens_to_ids(tokens) + +input_ids = torch.tensor([ids]) +print("Input IDs:", input_ids) + +output = model(input_ids) +print("Logits:", output.logits) +``` + +ഇൻപുട്ട് ID-കളും അതിന്റെ ഫലമായി ലഭിക്കുന്ന ലോജിറ്റുകളും നമ്മൾ പ്രിന്റ് ചെയ്യുന്നു — ഔട്ട്‌പുട്ട് ഇതാ: + +```python out +Input IDs: [[ 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012]] +Logits: [[-2.7276, 2.8789]] +``` + +ഒന്നിലധികം വാക്യങ്ങൾ ഒരുമിച്ച്, ഒറ്റയടിക്ക് മോഡലിലൂടെ കടത്തിവിടുന്നതിനെയാണ് *ബാച്ചിംഗ്* (batching) എന്ന് പറയുന്നത്. നിങ്ങൾക്ക് ഒരു വാക്യം മാത്രമേ ഉള്ളൂവെങ്കിൽ, ഒരൊറ്റ സീക്വൻസ് ഉള്ള ഒരു ബാച്ച് ഉണ്ടാക്കിയാൽ മതി: + +``` +batched_ids = [ids, ids] +``` + +ഇത് ഒരേപോലുള്ള രണ്ട് സീക്വൻസുകളുടെ ഒരു ബാച്ചാണ്! + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** ഈ `batched_ids` ലിസ്‌റ്റിനെ ഒരു ടെൻസറാക്കി മാറ്റി നിങ്ങളുടെ മോഡലിലൂടെ കടത്തിവിടുക. മുമ്പത്തെ അതേ ലോജിറ്റുകൾ തന്നെയാണ് (പക്ഷേ രണ്ടുതവണ) നിങ്ങൾക്ക് ലഭിക്കുന്നത് എന്ന് ഉറപ്പുവരുത്തുക! + +ഒന്നിലധികം വാക്യങ്ങൾ നൽകുമ്പോൾ മോഡൽ പ്രവർത്തിക്കാൻ ബാച്ചിംഗ് സഹായിക്കുന്നു. ഒന്നിലധികം സീക്വൻസുകൾ ഉപയോഗിക്കുന്നത്, ഒരൊറ്റ സീക്വൻസ് ഉള്ള ഒരു ബാച്ച് ഉണ്ടാക്കുന്നതുപോലെ തന്നെ ലളിതമാണ്. എന്നാൽ, രണ്ടാമതൊരു പ്രശ്നമുണ്ട്. രണ്ടോ (അതിലധികമോ) വാക്യങ്ങൾ ഒരുമിച്ച് ബാച്ച് ചെയ്യാൻ ശ്രമിക്കുമ്പോൾ, അവ വ്യത്യസ്ത നീളമുള്ളവയായിരിക്കാം. നിങ്ങൾ മുമ്പ് ടെൻസറുകളുമായി പ്രവർത്തിച്ചിട്ടുണ്ടെങ്കിൽ, അവ ചതുരാകൃതിയിലുള്ളവയായിരിക്കണം (rectangular shape) എന്ന് നിങ്ങൾക്കറിയാം; അതിനാൽ ഇൻപുട്ട് ID-കളുടെ ലിസ്‌റ്റിനെ നേരിട്ട് ഒരു ടെൻസറാക്കി മാറ്റാൻ നിങ്ങൾക്ക് കഴിയില്ല. ഈ പ്രശ്നം മറികടക്കാൻ, സാധാരണയായി നമ്മൾ ഇൻപുട്ടുകളെ *പാഡ്* (pad) ചെയ്യുന്നു. + +## ഇൻപുട്ടുകൾ പാഡ് ചെയ്യുന്നു[[padding-the-inputs]] + +താഴെയുള്ള ലിസ്‌റ്റുകളുടെ ലിസ്‌റ്റ് ഒരു ടെൻസറാക്കി മാറ്റാൻ കഴിയില്ല: + +```py no-format +batched_ids = [ + [200, 200, 200], + [200, 200] +] +``` + +ഇത് മറികടക്കാൻ, നമ്മുടെ ടെൻസറുകൾക്ക് ചതുരാകൃതി ലഭിക്കാനായി നമ്മൾ *പാഡിംഗ്* (padding) ഉപയോഗിക്കും. കുറച്ച് മൂല്യങ്ങൾ മാത്രമുള്ള വാക്യങ്ങളിലേക്ക് *പാഡിംഗ് ടോക്കൺ* എന്ന് വിളിക്കുന്ന ഒരു പ്രത്യേക വാക്ക് ചേർത്ത്, നമ്മുടെ എല്ലാ വാക്യങ്ങൾക്കും ഒരേ നീളം ഉണ്ടെന്ന് പാഡിംഗ് ഉറപ്പാക്കുന്നു. ഉദാഹരണത്തിന്, 10 വാക്കുകൾ വീതമുള്ള 10 വാക്യങ്ങളും 20 വാക്കുകളുള്ള 1 വാക്യവും നിങ്ങൾക്കുണ്ടെങ്കിൽ, എല്ലാ വാക്യങ്ങൾക്കും 20 വാക്കുകൾ ഉണ്ടെന്ന് പാഡിംഗ് ഉറപ്പാക്കും. നമ്മുടെ ഉദാഹരണത്തിൽ, ഫലമായി ലഭിക്കുന്ന ടെൻസർ ഇങ്ങനെയിരിക്കും: + +```py no-format +padding_id = 100 + +batched_ids = [ + [200, 200, 200], + [200, 200, padding_id], +] +``` + +പാഡിംഗ് ടോക്കണിന്റെ ID `tokenizer.pad_token_id`-ൽ കാണാം. ഇത് ഉപയോഗിച്ച്, നമ്മുടെ രണ്ട് വാക്യങ്ങളെ വെവ്വേറെയായും ഒരുമിച്ച് ബാച്ച് ചെയ്തും മോഡലിലൂടെ കടത്തിവിടാം: + +```py no-format +model = AutoModelForSequenceClassification.from_pretrained(checkpoint) + +sequence1_ids = [[200, 200, 200]] +sequence2_ids = [[200, 200]] +batched_ids = [ + [200, 200, 200], + [200, 200, tokenizer.pad_token_id], +] + +print(model(torch.tensor(sequence1_ids)).logits) +print(model(torch.tensor(sequence2_ids)).logits) +print(model(torch.tensor(batched_ids)).logits) +``` + +```python out +tensor([[ 1.5694, -1.3895]], grad_fn=) +tensor([[ 0.5803, -0.4125]], grad_fn=) +tensor([[ 1.5694, -1.3895], + [ 1.3373, -1.2163]], grad_fn=) +``` + +നമ്മുടെ ബാച്ച് ചെയ്ത പ്രവചനങ്ങളിലെ ലോജിറ്റുകളിൽ എന്തോ പിശകുണ്ട്: രണ്ടാമത്തെ വരി രണ്ടാമത്തെ വാക്യത്തിന്റെ ലോജിറ്റുകൾക്ക് തുല്യമായിരിക്കണം, പക്ഷേ നമുക്ക് ലഭിച്ചത് തീർത്തും വ്യത്യസ്തമായ മൂല്യങ്ങളാണ്! + +ഓരോ ടോക്കണിനെയും *സന്ദർഭവത്കരിക്കുന്ന* (contextualize) അറ്റൻഷൻ ലെയറുകളാണ് Transformer മോഡലുകളുടെ പ്രധാന സവിശേഷത എന്നതാണ് ഇതിന് കാരണം. ഒരു സീക്വൻസിലെ എല്ലാ ടോക്കണുകളിലേക്കും ഇവ ശ്രദ്ധ കൊടുക്കുന്നതിനാൽ (attend), പാഡിംഗ് ടോക്കണുകളെയും ഇവ കണക്കിലെടുക്കും. വ്യത്യസ്ത നീളമുള്ള വാക്യങ്ങളെ വെവ്വേറെ മോഡലിലൂടെ കടത്തിവിടുമ്പോഴും, അതേ വാക്യങ്ങളെ പാഡിംഗ് പ്രയോഗിച്ച് ഒരു ബാച്ചായി കടത്തിവിടുമ്പോഴും ഒരേ ഫലം ലഭിക്കാൻ, പാഡിംഗ് ടോക്കണുകളെ അവഗണിക്കാൻ ആ അറ്റൻഷൻ ലെയറുകളോട് നമ്മൾ പറയേണ്ടതുണ്ട്. ഒരു അറ്റൻഷൻ മാസ്‌ക് ഉപയോഗിച്ചാണ് ഇത് ചെയ്യുന്നത്. + +## അറ്റൻഷൻ മാസ്‌ക്കുകൾ[[attention-masks]] + +*അറ്റൻഷൻ മാസ്‌ക്കുകൾ* (attention masks) എന്നത് ഇൻപുട്ട് ID-കളുടെ ടെൻസറിന്റെ അതേ ആകൃതിയുള്ള (shape), 0-കളും 1-കളും നിറഞ്ഞ ടെൻസറുകളാണ്: 1-കൾ അതത് ടോക്കണുകളിലേക്ക് ശ്രദ്ധ കൊടുക്കണം എന്ന് സൂചിപ്പിക്കുന്നു, 0-കൾ അതത് ടോക്കണുകളിലേക്ക് ശ്രദ്ധ കൊടുക്കേണ്ടതില്ല എന്ന് സൂചിപ്പിക്കുന്നു (അതായത്, മോഡലിന്റെ അറ്റൻഷൻ ലെയറുകൾ അവയെ അവഗണിക്കണം). + +മുൻ ഉദാഹരണം ഒരു അറ്റൻഷൻ മാസ്‌ക് ചേർത്ത് പൂർത്തിയാക്കാം: + +```py no-format +batched_ids = [ + [200, 200, 200], + [200, 200, tokenizer.pad_token_id], +] + +attention_mask = [ + [1, 1, 1], + [1, 1, 0], +] + +outputs = model(torch.tensor(batched_ids), attention_mask=torch.tensor(attention_mask)) +print(outputs.logits) +``` + +```python out +tensor([[ 1.5694, -1.3895], + [ 0.5803, -0.4125]], grad_fn=) +``` + +ഇപ്പോൾ ബാച്ചിലെ രണ്ടാമത്തെ വാക്യത്തിന് നമുക്ക് അതേ ലോജിറ്റുകൾ ലഭിക്കുന്നു. + +രണ്ടാമത്തെ സീക്വൻസിന്റെ അവസാന മൂല്യം ഒരു പാഡിംഗ് ID ആണെന്നും, അറ്റൻഷൻ മാസ്‌ക്കിൽ അത് 0 എന്ന മൂല്യമാണെന്നും ശ്രദ്ധിക്കുക. + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** ഭാഗം 2-ൽ ഉപയോഗിച്ച രണ്ട് വാക്യങ്ങളിൽ ("I've been waiting for a HuggingFace course my whole life.", "I hate this so much!") ടോക്കണൈസേഷൻ സ്വയം (manually) പ്രയോഗിക്കുക. അവയെ മോഡലിലൂടെ കടത്തിവിട്ട്, ഭാഗം 2-ലെ അതേ ലോജിറ്റുകൾ തന്നെയാണ് ലഭിക്കുന്നത് എന്ന് ഉറപ്പുവരുത്തുക. ഇനി പാഡിംഗ് ടോക്കൺ ഉപയോഗിച്ച് അവയെ ഒരുമിച്ച് ബാച്ച് ചെയ്യുക, തുടർന്ന് ശരിയായ അറ്റൻഷൻ മാസ്‌ക് ഉണ്ടാക്കുക. മോഡലിലൂടെ കടത്തിവിടുമ്പോൾ അതേ ഫലങ്ങൾ തന്നെ ലഭിക്കുന്നു എന്ന് ഉറപ്പുവരുത്തുക! + +## കൂടുതൽ നീണ്ട സീക്വൻസുകൾ[[longer-sequences]] + +Transformer മോഡലുകളുടെ കാര്യത്തിൽ, മോഡലുകളിലേക്ക് നമുക്ക് നൽകാൻ കഴിയുന്ന സീക്വൻസുകളുടെ നീളത്തിന് ഒരു പരിധിയുണ്ട്. മിക്ക മോഡലുകളും 512 അല്ലെങ്കിൽ 1024 ടോക്കണുകൾ വരെയുള്ള സീക്വൻസുകൾ കൈകാര്യം ചെയ്യുന്നു, അതിലും നീണ്ട സീക്വൻസുകൾ പ്രോസസ്സ് ചെയ്യാൻ ആവശ്യപ്പെട്ടാൽ അവ ക്രാഷ് ആകും. ഈ പ്രശ്നത്തിന് രണ്ട് പരിഹാരങ്ങളുണ്ട്: + +- കൂടുതൽ നീണ്ട സീക്വൻസ് നീളം പിന്തുണയ്ക്കുന്ന ഒരു മോഡൽ ഉപയോഗിക്കുക. +- നിങ്ങളുടെ സീക്വൻസുകൾ വെട്ടിച്ചുരുക്കുക (truncate). + +വ്യത്യസ്ത മോഡലുകൾ വ്യത്യസ്ത സീക്വൻസ് നീളങ്ങളാണ് പിന്തുണയ്ക്കുന്നത്, ചിലവ വളരെ നീണ്ട സീക്വൻസുകൾ കൈകാര്യം ചെയ്യുന്നതിൽ പ്രത്യേക വൈദഗ്ധ്യമുള്ളവയാണ്. [Longformer](https://huggingface.co/docs/transformers/model_doc/longformer) ഒരു ഉദാഹരണമാണ്, മറ്റൊന്ന് [LED](https://huggingface.co/docs/transformers/model_doc/led) ആണ്. വളരെ നീണ്ട സീക്വൻസുകൾ ആവശ്യമുള്ള ഒരു ടാസ്‌ക്കിലാണ് നിങ്ങൾ പ്രവർത്തിക്കുന്നതെങ്കിൽ, ആ മോഡലുകൾ ഒന്ന് നോക്കാൻ ഞങ്ങൾ ശുപാർശ ചെയ്യുന്നു. + +അല്ലാത്തപക്ഷം, `max_sequence_length` പാരാമീറ്റർ വ്യക്തമാക്കി നിങ്ങളുടെ സീക്വൻസുകൾ വെട്ടിച്ചുരുക്കാൻ ഞങ്ങൾ ശുപാർശ ചെയ്യുന്നു: + +```py +sequence = sequence[:max_sequence_length] +``` diff --git a/chapters/ml/chapter2/6.mdx b/chapters/ml/chapter2/6.mdx new file mode 100644 index 000000000..978d93b3d --- /dev/null +++ b/chapters/ml/chapter2/6.mdx @@ -0,0 +1,133 @@ + + +# എല്ലാം ഒരുമിച്ച് ചേർക്കുന്നു[[putting-it-all-together]] + + + +കഴിഞ്ഞ കുറച്ച് ഭാഗങ്ങളിൽ, മിക്ക ജോലികളും കഴിയുന്നത്ര സ്വന്തം കൈകൊണ്ട് ചെയ്യാൻ നമ്മൾ ശ്രമിച്ചുവരികയായിരുന്നു. ടോക്കണൈസറുകൾ എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് നമ്മൾ പരിശോധിച്ചു; ടോക്കണൈസേഷൻ, ഇൻപുട്ട് ID-കളിലേക്കുള്ള മാറ്റം, പാഡിംഗ്, ട്രങ്കേഷൻ (truncation), അറ്റൻഷൻ മാസ്‌ക്കുകൾ എന്നിവയും നോക്കി. + +എന്നാൽ, ഭാഗം 2-ൽ നമ്മൾ കണ്ടതുപോലെ, ഇതെല്ലാം നമുക്കുവേണ്ടി കൈകാര്യം ചെയ്യാൻ 🤗 Transformers API-ക്ക് ഒരു ഉയർന്ന തലത്തിലുള്ള (high-level) ഫംഗ്‌ഷനുണ്ട്; അതിലേക്കാണ് ഇവിടെ നമ്മൾ ആഴത്തിൽ കടക്കുന്നത്. നിങ്ങളുടെ `tokenizer` വാക്യത്തിൽ നേരിട്ട് വിളിക്കുമ്പോൾ, മോഡലിലൂടെ കടത്തിവിടാൻ തയ്യാറായ ഇൻപുട്ടുകൾ നിങ്ങൾക്ക് തിരികെ ലഭിക്കുന്നു: + +```py +from transformers import AutoTokenizer + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) + +sequence = "I've been waiting for a HuggingFace course my whole life." + +model_inputs = tokenizer(sequence) +``` + +ഇവിടെ, ഒരു മോഡൽ നന്നായി പ്രവർത്തിക്കാൻ ആവശ്യമായ എല്ലാ കാര്യങ്ങളും `model_inputs` എന്ന വേരിയബിളിൽ അടങ്ങിയിരിക്കുന്നു. DistilBERT-ന്, ഇതിൽ ഇൻപുട്ട് ID-കളും അറ്റൻഷൻ മാസ്‌ക്കും ഉൾപ്പെടുന്നു. അധിക ഇൻപുട്ടുകൾ സ്വീകരിക്കുന്ന മറ്റ് മോഡലുകൾക്ക്, അവയും `tokenizer` ഒബ്‌ജക്റ്റ് ഔട്ട്‌പുട്ടായി നൽകും. + +താഴെയുള്ള ചില ഉദാഹരണങ്ങളിൽ നമ്മൾ കാണുന്നതുപോലെ, ഈ മെത്തേഡ് വളരെ ശക്തമാണ്. ആദ്യമായി, ഇതിന് ഒരൊറ്റ സീക്വൻസ് ടോക്കണൈസ് ചെയ്യാൻ കഴിയും: + +```py +sequence = "I've been waiting for a HuggingFace course my whole life." + +model_inputs = tokenizer(sequence) +``` + +API-യിൽ ഒരു മാറ്റവുമില്ലാതെ, ഒരേസമയം ഒന്നിലധികം സീക്വൻസുകളും ഇത് കൈകാര്യം ചെയ്യുന്നു: + +```py +sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] + +model_inputs = tokenizer(sequences) +``` + +പല ലക്ഷ്യങ്ങൾക്കനുസരിച്ച് ഇതിന് പാഡ് ചെയ്യാൻ കഴിയും: + +```py +# Will pad the sequences up to the maximum sequence length +model_inputs = tokenizer(sequences, padding="longest") + +# Will pad the sequences up to the model max length +# (512 for BERT or DistilBERT) +model_inputs = tokenizer(sequences, padding="max_length") + +# Will pad the sequences up to the specified max length +model_inputs = tokenizer(sequences, padding="max_length", max_length=8) +``` + +ഇതിന് സീക്വൻസുകൾ വെട്ടിച്ചുരുക്കാനും (truncate) കഴിയും: + +```py +sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] + +# Will truncate the sequences that are longer than the model max length +# (512 for BERT or DistilBERT) +model_inputs = tokenizer(sequences, truncation=True) + +# Will truncate the sequences that are longer than the specified max length +model_inputs = tokenizer(sequences, max_length=8, truncation=True) +``` + +പ്രത്യേക ഫ്രെയിംവർക്ക് ടെൻസറുകളിലേക്കുള്ള മാറ്റവും `tokenizer` ഒബ്‌ജക്റ്റിന് കൈകാര്യം ചെയ്യാൻ കഴിയും; അവയെ പിന്നീട് നേരിട്ട് മോഡലിലേക്ക് അയയ്ക്കാം. ഉദാഹരണത്തിന്, താഴെയുള്ള കോഡ് സാമ്പിളിൽ, വ്യത്യസ്ത ഫ്രെയിംവർക്കുകളിൽ നിന്നുള്ള ടെൻസറുകൾ തിരികെ നൽകാൻ നമ്മൾ ടോക്കണൈസറോട് ആവശ്യപ്പെടുന്നു — `"pt"` PyTorch ടെൻസറുകൾ നൽകുന്നു, `"np"` NumPy അറേകൾ നൽകുന്നു: + +```py +sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] + +# Returns PyTorch tensors +model_inputs = tokenizer(sequences, padding=True, return_tensors="pt") + +# Returns NumPy arrays +model_inputs = tokenizer(sequences, padding=True, return_tensors="np") +``` + +## പ്രത്യേക ടോക്കണുകൾ[[special-tokens]] + +ടോക്കണൈസർ തിരികെ നൽകിയ ഇൻപുട്ട് ID-കൾ ഒന്ന് നോക്കിയാൽ, അവ മുമ്പ് നമുക്ക് ലഭിച്ചതിൽ നിന്ന് അൽപ്പം വ്യത്യസ്തമാണെന്ന് കാണാം: + +```py +sequence = "I've been waiting for a HuggingFace course my whole life." + +model_inputs = tokenizer(sequence) +print(model_inputs["input_ids"]) + +tokens = tokenizer.tokenize(sequence) +ids = tokenizer.convert_tokens_to_ids(tokens) +print(ids) +``` + +```python out +[101, 1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012, 102] +[1045, 1005, 2310, 2042, 3403, 2005, 1037, 17662, 12172, 2607, 2026, 2878, 2166, 1012] +``` + +തുടക്കത്തിൽ ഒരു ടോക്കൺ ID-യും അവസാനം ഒരു ടോക്കൺ ID-യും ചേർക്കപ്പെട്ടിരിക്കുന്നു. ഇത് എന്തിനെക്കുറിച്ചാണെന്ന് കാണാൻ മുകളിലെ രണ്ട് ID സീക്വൻസുകളും ഡീകോഡ് ചെയ്യാം: + +```py +print(tokenizer.decode(model_inputs["input_ids"])) +print(tokenizer.decode(ids)) +``` + +```python out +"[CLS] i've been waiting for a huggingface course my whole life. [SEP]" +"i've been waiting for a huggingface course my whole life." +``` + +ടോക്കണൈസർ തുടക്കത്തിൽ `[CLS]` എന്ന പ്രത്യേക വാക്കും അവസാനം `[SEP]` എന്ന പ്രത്യേക വാക്കും ചേർത്തു. മോഡൽ ഇവ ഉപയോഗിച്ചാണ് പ്രീട്രെയിൻ ചെയ്തത് എന്നതാണ് ഇതിന് കാരണം; അതിനാൽ ഇൻഫറൻസിൽ അതേ ഫലങ്ങൾ ലഭിക്കാൻ നമ്മളും ഇവ ചേർക്കേണ്ടതുണ്ട്. ചില മോഡലുകൾ പ്രത്യേക വാക്കുകൾ ചേർക്കുന്നില്ല, അല്ലെങ്കിൽ വ്യത്യസ്തമായവ ചേർക്കുന്നു എന്നത് ശ്രദ്ധിക്കുക; ചില മോഡലുകൾ ഈ പ്രത്യേക വാക്കുകൾ തുടക്കത്തിൽ മാത്രമോ അവസാനം മാത്രമോ ചേർക്കുകയും ചെയ്യാം. എന്തായാലും, ഏതൊക്കെയാണ് പ്രതീക്ഷിക്കുന്നത് എന്ന് ടോക്കണൈസറിന് അറിയാം, അത് നിങ്ങൾക്കായി ഇത് കൈകാര്യം ചെയ്യും. + +## ഉപസംഹാരം: ടോക്കണൈസറിൽ നിന്ന് മോഡലിലേക്ക്[[wrapping-up-from-tokenizer-to-model]] + +ടെക്‌സ്‌റ്റുകളിൽ പ്രയോഗിക്കുമ്പോൾ `tokenizer` ഒബ്‌ജക്റ്റ് ഉപയോഗിക്കുന്ന ഓരോ ഘട്ടവും നമ്മൾ ഇപ്പോൾ കണ്ടുകഴിഞ്ഞു. ഇനി അവസാനമായി ഒരിക്കൽ കൂടി, അതിന്റെ പ്രധാന API ഉപയോഗിച്ച് ഒന്നിലധികം സീക്വൻസുകൾ (പാഡിംഗ്!), വളരെ നീണ്ട സീക്വൻസുകൾ (ട്രങ്കേഷൻ!), പലതരം ടെൻസറുകൾ എന്നിവ ഇത് എങ്ങനെ കൈകാര്യം ചെയ്യുന്നു എന്ന് നോക്കാം: + +```py +import torch +from transformers import AutoTokenizer, AutoModelForSequenceClassification + +checkpoint = "distilbert-base-uncased-finetuned-sst-2-english" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = AutoModelForSequenceClassification.from_pretrained(checkpoint) +sequences = ["I've been waiting for a HuggingFace course my whole life.", "So have I!"] + +tokens = tokenizer(sequences, padding=True, truncation=True, return_tensors="pt") +output = model(**tokens) +``` diff --git a/chapters/ml/chapter2/7.mdx b/chapters/ml/chapter2/7.mdx new file mode 100644 index 000000000..5aa0b1990 --- /dev/null +++ b/chapters/ml/chapter2/7.mdx @@ -0,0 +1,18 @@ +# അടിസ്ഥാന ഉപയോഗം പൂർത്തിയായി![[basic-usage-completed]] + + + +ഇതുവരെ കോഴ്‌സ് പിന്തുടർന്നതിന് അഭിനന്ദനങ്ങൾ! ഒന്ന് ഓർത്തെടുക്കാം, ഈ അധ്യായത്തിൽ നിങ്ങൾ: + +- ഒരു Transformer മോഡലിന്റെ അടിസ്ഥാന നിർമ്മാണഘടകങ്ങൾ പഠിച്ചു. +- ഒരു ടോക്കണൈസേഷൻ പൈപ്പ്‌ലൈനിൽ എന്തൊക്കെ ഉൾപ്പെടുന്നു എന്ന് പഠിച്ചു. +- ഒരു Transformer മോഡൽ പ്രായോഗികമായി എങ്ങനെ ഉപയോഗിക്കാം എന്ന് കണ്ടു. +- ടെക്‌സ്‌റ്റിനെ മോഡലിന് മനസ്സിലാകുന്ന ടെൻസറുകളാക്കി മാറ്റാൻ ഒരു ടോക്കണൈസർ എങ്ങനെ പ്രയോജനപ്പെടുത്താം എന്ന് പഠിച്ചു. +- ടെക്‌സ്‌റ്റിൽ നിന്ന് പ്രവചനങ്ങളിലേക്ക് എത്താൻ ഒരു ടോക്കണൈസറും ഒരു മോഡലും ഒരുമിച്ച് സെറ്റപ്പ് ചെയ്തു. +- ഇൻപുട്ട് ID-കളുടെ പരിമിതികൾ മനസ്സിലാക്കി, അറ്റൻഷൻ മാസ്‌ക്കുകളെക്കുറിച്ച് പഠിച്ചു. +- വൈവിധ്യമാർന്നതും ക്രമീകരിക്കാവുന്നതുമായ ടോക്കണൈസർ മെത്തേഡുകൾ പരീക്ഷിച്ചുനോക്കി. + +ഇനി മുതൽ, 🤗 Transformers ഡോക്യുമെന്റേഷനിലൂടെ സ്വതന്ത്രമായി സഞ്ചരിക്കാൻ നിങ്ങൾക്ക് കഴിയണം: അതിലെ പദാവലി പരിചിതമായി തോന്നും, മിക്കപ്പോഴും നിങ്ങൾ ഉപയോഗിക്കാൻ പോകുന്ന മെത്തേഡുകൾ നിങ്ങൾ ഇതിനകം കണ്ടുകഴിഞ്ഞു. diff --git a/chapters/ml/chapter2/8.mdx b/chapters/ml/chapter2/8.mdx new file mode 100644 index 000000000..6e322e0b0 --- /dev/null +++ b/chapters/ml/chapter2/8.mdx @@ -0,0 +1,857 @@ +# ഒപ്റ്റിമൈസ് ചെയ്ത ഇൻഫറൻസ് ഡിപ്ലോയ്‌മെന്റ് + +ഈ ഭാഗത്തിൽ, LLM ഡിപ്ലോയ്‌മെന്റുകൾ ഒപ്റ്റിമൈസ് ചെയ്യാനുള്ള നൂതന ഫ്രെയിംവർക്കുകളായ Text Generation Inference (TGI), vLLM, llama.cpp എന്നിവ നമ്മൾ പരിചയപ്പെടും. ഉപയോക്താക്കൾക്ക് LLM-കൾ സേവനമായി നൽകാൻ (serve) പ്രൊഡക്ഷൻ പരിതസ്ഥിതികളിലാണ് ഈ ആപ്ലിക്കേഷനുകൾ പ്രധാനമായും ഉപയോഗിക്കുന്നത്. ഒരൊറ്റ മെഷീനിൽ ഇൻഫറൻസിനായി ഇവ എങ്ങനെ ഉപയോഗിക്കാം എന്നതിനെക്കാൾ, ഈ ഫ്രെയിംവർക്കുകൾ പ്രൊഡക്ഷനിൽ എങ്ങനെ ഡിപ്ലോയ് ചെയ്യാം എന്നതിലാണ് ഈ ഭാഗം ശ്രദ്ധ കേന്ദ്രീകരിക്കുന്നത്. + +ഈ ടൂളുകൾ ഇൻഫറൻസ് കാര്യക്ഷമത എങ്ങനെ പരമാവധി ഉയർത്തുന്നു എന്നും ലാർജ് ലാംഗ്വേജ് മോഡലുകളുടെ പ്രൊഡക്ഷൻ ഡിപ്ലോയ്‌മെന്റുകൾ എങ്ങനെ ലളിതമാക്കുന്നു എന്നും നമ്മൾ പരിശോധിക്കും. + +## ഫ്രെയിംവർക്ക് തിരഞ്ഞെടുക്കാനുള്ള ഗൈഡ് + +TGI, vLLM, llama.cpp എന്നിവ സമാനമായ ആവശ്യങ്ങൾക്കാണ് ഉപയോഗിക്കുന്നതെങ്കിലും, വ്യത്യസ്ത ഉപയോഗ സാഹചര്യങ്ങൾക്ക് (use cases) കൂടുതൽ യോജിച്ചവയാക്കുന്ന തനതായ സവിശേഷതകൾ ഓരോന്നിനുമുണ്ട്. പ്രകടനത്തിലും (performance) ഇന്റഗ്രേഷനിലും ശ്രദ്ധ കേന്ദ്രീകരിച്ച്, അവയ്ക്കിടയിലുള്ള പ്രധാന വ്യത്യാസങ്ങൾ നോക്കാം. + +### മെമ്മറി മാനേജ്‌മെന്റും പ്രകടനവും + +**TGI** പ്രൊഡക്ഷനിൽ സ്ഥിരതയോടെയും പ്രവചിക്കാവുന്ന രീതിയിലും പ്രവർത്തിക്കാൻ രൂപകൽപ്പന ചെയ്തതാണ്; മെമ്മറി ഉപയോഗം സ്ഥിരമായി നിലനിർത്താൻ ഇത് നിശ്ചിത സീക്വൻസ് ലെങ്ത്തുകൾ ഉപയോഗിക്കുന്നു. Flash Attention 2, കണ്ടിന്യുവസ് ബാച്ചിംഗ് (continuous batching) എന്നീ വിദ്യകൾ ഉപയോഗിച്ചാണ് TGI മെമ്മറി കൈകാര്യം ചെയ്യുന്നത്. അതായത്, അറ്റൻഷൻ കണക്കുകൂട്ടലുകൾ വളരെ കാര്യക്ഷമമായി പ്രോസസ്സ് ചെയ്യാനും, GPU-വിന് നിരന്തരം ജോലി നൽകിക്കൊണ്ട് അതിനെ തിരക്കിലാക്കി നിർത്താനും ഇതിന് കഴിയും. ആവശ്യമുള്ളപ്പോൾ മോഡലിന്റെ ഭാഗങ്ങൾ CPU-വിനും GPU-വിനും ഇടയിൽ മാറ്റാൻ ഈ സിസ്റ്റത്തിന് കഴിയും; ഇത് കൂടുതൽ വലിയ മോഡലുകൾ കൈകാര്യം ചെയ്യാൻ സഹായിക്കുന്നു. + +Flash Attention + + + +മെമ്മറി ബാൻഡ്‌വിഡ്ത്ത് തടസ്സങ്ങൾ (bottlenecks) പരിഹരിച്ചുകൊണ്ട് Transformer മോഡലുകളിലെ അറ്റൻഷൻ മെക്കാനിസം ഒപ്റ്റിമൈസ് ചെയ്യുന്ന ഒരു വിദ്യയാണ് Flash Attention. [അധ്യായം 1.8](/course/chapter1/8)-ൽ നേരത്തെ ചർച്ച ചെയ്തതുപോലെ, അറ്റൻഷൻ മെക്കാനിസത്തിന്റെ സങ്കീർണ്ണതയും മെമ്മറി ഉപയോഗവും ക്വാഡ്രാറ്റിക് (quadratic) ആണ്; ഇത് നീണ്ട സീക്വൻസുകൾക്ക് അതിനെ കാര്യക്ഷമമല്ലാതാക്കുന്നു. + +High Bandwidth Memory (HBM)-യും അതിലും വേഗതയേറിയ SRAM കാഷും തമ്മിലുള്ള മെമ്മറി കൈമാറ്റങ്ങൾ എങ്ങനെ കൈകാര്യം ചെയ്യുന്നു എന്നതിലാണ് ഇതിന്റെ പ്രധാന നൂതനത്വം. പരമ്പരാഗത അറ്റൻഷൻ HBM-നും SRAM-നും ഇടയിൽ ഡേറ്റ ആവർത്തിച്ച് കൈമാറുന്നു; ഇത് GPU-വിനെ വെറുതെയിരുത്തി തടസ്സങ്ങൾ സൃഷ്ടിക്കുന്നു. Flash Attention ഡേറ്റ ഒരിക്കൽ മാത്രം SRAM-ലേക്ക് ലോഡ് ചെയ്ത് എല്ലാ കണക്കുകൂട്ടലുകളും അവിടെത്തന്നെ നടത്തുന്നു; അതുവഴി ചെലവേറിയ മെമ്മറി കൈമാറ്റങ്ങൾ ഏറ്റവും കുറയ്ക്കുന്നു. + +ട്രെയിനിംഗ് സമയത്താണ് ഇതിന്റെ പ്രയോജനങ്ങൾ ഏറ്റവും പ്രകടമാകുന്നതെങ്കിലും, Flash Attention-ന്റെ കുറഞ്ഞ VRAM ഉപയോഗവും മെച്ചപ്പെട്ട കാര്യക്ഷമതയും ഇൻഫറൻസിനും അതിനെ വിലപ്പെട്ടതാക്കുന്നു; കൂടുതൽ വേഗതയേറിയതും സ്കേലബിളായതുമായ LLM സെർവിംഗ് ഇത് സാധ്യമാക്കുന്നു. + + + +**vLLM** PagedAttention ഉപയോഗിച്ച് വ്യത്യസ്തമായ ഒരു സമീപനമാണ് സ്വീകരിക്കുന്നത്. ഒരു കമ്പ്യൂട്ടർ തന്റെ മെമ്മറി പേജുകളായി കൈകാര്യം ചെയ്യുന്നതുപോലെ, vLLM മോഡലിന്റെ മെമ്മറിയെ ചെറിയ ബ്ലോക്കുകളായി വിഭജിക്കുന്നു. ഈ ബുദ്ധിപൂർവ്വമായ സംവിധാനം കാരണം, വ്യത്യസ്ത വലുപ്പത്തിലുള്ള റിക്വസ്‌റ്റുകൾ കൂടുതൽ വഴക്കത്തോടെ കൈകാര്യം ചെയ്യാൻ ഇതിന് കഴിയുന്നു, മെമ്മറി സ്ഥലം പാഴാക്കുന്നുമില്ല. വ്യത്യസ്ത റിക്വസ്‌റ്റുകൾക്കിടയിൽ മെമ്മറി പങ്കുവയ്ക്കുന്നതിൽ ഇത് പ്രത്യേകിച്ചും മികച്ചതാണ്; മെമ്മറി ഫ്രാഗ്‌മെന്റേഷൻ കുറയ്ക്കുകയും ചെയ്യുന്നു, ഇത് സിസ്റ്റത്തെ മൊത്തത്തിൽ കൂടുതൽ കാര്യക്ഷമമാക്കുന്നു. + + + +LLM ഇൻഫറൻസിലെ മറ്റൊരു നിർണ്ണായക തടസ്സം പരിഹരിക്കുന്ന ഒരു വിദ്യയാണ് PagedAttention: KV കാഷ് മെമ്മറി മാനേജ്‌മെന്റ്. [അധ്യായം 1.8](/course/chapter1/8)-ൽ ചർച്ച ചെയ്തതുപോലെ, ടെക്‌സ്‌റ്റ് ജനറേഷൻ സമയത്ത്, ആവർത്തിച്ചുള്ള കണക്കുകൂട്ടലുകൾ കുറയ്ക്കാൻ മോഡൽ ജനറേറ്റ് ചെയ്ത ഓരോ ടോക്കണിന്റെയും അറ്റൻഷൻ കീകളും വാല്യൂകളും (KV കാഷ്) സംഭരിച്ചുവയ്ക്കുന്നു. പ്രത്യേകിച്ച് നീണ്ട സീക്വൻസുകളോ ഒരേസമയം ഒന്നിലധികം റിക്വസ്‌റ്റുകളോ ഉള്ളപ്പോൾ, KV കാഷ് വളരെ വലുതായി മാറാം. + +ഈ കാഷ് എങ്ങനെ കൈകാര്യം ചെയ്യുന്നു എന്നതിലാണ് vLLM-ന്റെ പ്രധാന നൂതനത്വം: + +1. **മെമ്മറി പേജിംഗ് (Memory Paging)**: KV കാഷിനെ ഒരൊറ്റ വലിയ ബ്ലോക്കായി കണക്കാക്കുന്നതിനുപകരം, അതിനെ നിശ്ചിത വലുപ്പമുള്ള "പേജുകളായി" വിഭജിക്കുന്നു (ഓപ്പറേറ്റിംഗ് സിസ്റ്റങ്ങളിലെ വിർച്വൽ മെമ്മറിക്ക് സമാനമായി). +2. **തുടർച്ചയല്ലാത്ത സംഭരണം (Non-contiguous Storage)**: പേജുകൾ GPU മെമ്മറിയിൽ തുടർച്ചയായി സംഭരിക്കേണ്ട ആവശ്യമില്ല; ഇത് കൂടുതൽ വഴക്കമുള്ള മെമ്മറി അലോക്കേഷൻ സാധ്യമാക്കുന്നു. +3. **പേജ് ടേബിൾ മാനേജ്‌മെന്റ് (Page Table Management)**: ഏതൊക്കെ പേജുകൾ ഏത് സീക്വൻസിന്റേതാണ് എന്ന് ഒരു പേജ് ടേബിൾ ട്രാക്ക് ചെയ്യുന്നു; ഇത് കാര്യക്ഷമമായ തിരയലും ആക്‌സസ്സും സാധ്യമാക്കുന്നു. +4. **മെമ്മറി പങ്കുവയ്ക്കൽ (Memory Sharing)**: പാരലൽ സാംപ്ലിംഗ് പോലുള്ള പ്രവർത്തനങ്ങളിൽ, പ്രോംപ്‌റ്റിന്റെ KV കാഷ് സംഭരിക്കുന്ന പേജുകൾ ഒന്നിലധികം സീക്വൻസുകൾക്കിടയിൽ പങ്കുവയ്ക്കാം. + +പരമ്പരാഗത രീതികളെ അപേക്ഷിച്ച് 24 മടങ്ങ് വരെ ഉയർന്ന ത്രൂപുട്ട് (throughput) നേടാൻ PagedAttention സമീപനത്തിന് കഴിയും; ഇത് പ്രൊഡക്ഷൻ LLM ഡിപ്ലോയ്‌മെന്റുകളിൽ വലിയ മാറ്റം കൊണ്ടുവരുന്ന ഒന്നാണ്. PagedAttention എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്നതിലേക്ക് ശരിക്കും ആഴത്തിൽ ഇറങ്ങണമെന്നുണ്ടെങ്കിൽ, [vLLM ഡോക്യുമെന്റേഷനിലെ ഗൈഡ്](https://docs.vllm.ai/en/latest/design/kernel/paged_attention.html) നിങ്ങൾക്ക് വായിക്കാം. + + + +**llama.cpp** സാധാരണ ഉപഭോക്തൃ ഹാർഡ്‌വെയറിൽ (consumer hardware) LLaMA മോഡലുകൾ റൺ ചെയ്യാനായി ആദ്യം രൂപകൽപ്പന ചെയ്ത, ഉയർന്ന തോതിൽ ഒപ്റ്റിമൈസ് ചെയ്ത ഒരു C/C++ ഇംപ്ലിമെന്റേഷനാണ്. ഓപ്‌ഷണലായ GPU ആക്‌സിലറേഷനോടുകൂടി CPU കാര്യക്ഷമതയിലാണ് ഇത് ശ്രദ്ധ കേന്ദ്രീകരിക്കുന്നത്; വിഭവങ്ങൾ പരിമിതമായ പരിതസ്ഥിതികൾക്ക് ഇത് ഏറ്റവും അനുയോജ്യമാണ്. മികച്ച പ്രകടനം നിലനിർത്തിക്കൊണ്ടുതന്നെ മോഡലിന്റെ വലുപ്പവും മെമ്മറി ആവശ്യങ്ങളും കുറയ്ക്കാൻ llama.cpp ക്വാണ്ടൈസേഷൻ (quantization) വിദ്യകൾ ഉപയോഗിക്കുന്നു. വിവിധ CPU ആർക്കിടെക്ചറുകൾക്കായി ഒപ്റ്റിമൈസ് ചെയ്ത കെർണലുകൾ ഇത് ഇംപ്ലിമെന്റ് ചെയ്യുന്നു, കൂടാതെ കാര്യക്ഷമമായ ടോക്കൺ ജനറേഷനായി അടിസ്ഥാന KV കാഷ് മാനേജ്‌മെന്റിനെ പിന്തുണയ്ക്കുന്നു. + + + +llama.cpp-യിലെ ക്വാണ്ടൈസേഷൻ മോഡൽ വെയ്‌റ്റുകളുടെ പ്രിസിഷൻ 32-ബിറ്റ് അല്ലെങ്കിൽ 16-ബിറ്റ് ഫ്ലോട്ടിംഗ് പോയിന്റിൽ നിന്ന് 8-ബിറ്റ് ഇന്റിജർ (INT8), 4-ബിറ്റ്, അതിലും താഴെ എന്നിങ്ങനെയുള്ള കുറഞ്ഞ പ്രിസിഷൻ ഫോർമാറ്റുകളിലേക്ക് കുറയ്ക്കുന്നു. ഗുണനിലവാരത്തിൽ ഏറ്റവും കുറഞ്ഞ നഷ്ടത്തോടെ ഇത് മെമ്മറി ഉപയോഗം കാര്യമായി കുറയ്ക്കുകയും ഇൻഫറൻസ് വേഗം മെച്ചപ്പെടുത്തുകയും ചെയ്യുന്നു. + +llama.cpp-യിലെ പ്രധാന ക്വാണ്ടൈസേഷൻ സവിശേഷതകൾ ഇവയാണ്: +1. **ഒന്നിലധികം ക്വാണ്ടൈസേഷൻ ലെവലുകൾ (Multiple Quantization Levels)**: 8-ബിറ്റ്, 4-ബിറ്റ്, 3-ബിറ്റ്, എന്തിന്, 2-ബിറ്റ് ക്വാണ്ടൈസേഷൻ വരെ പിന്തുണയ്ക്കുന്നു +2. **GGML/GGUF ഫോർമാറ്റ്**: ക്വാണ്ടൈസ്ഡ് ഇൻഫറൻസിനായി ഒപ്റ്റിമൈസ് ചെയ്ത കസ്‌റ്റം ടെൻസർ ഫോർമാറ്റുകൾ ഉപയോഗിക്കുന്നു +3. **മിക്‌സഡ് പ്രിസിഷൻ (Mixed Precision)**: മോഡലിന്റെ വ്യത്യസ്ത ഭാഗങ്ങൾക്ക് വ്യത്യസ്ത ക്വാണ്ടൈസേഷൻ ലെവലുകൾ പ്രയോഗിക്കാൻ കഴിയും +4. **ഹാർഡ്‌വെയർ-നിർദ്ദിഷ്ട ഒപ്റ്റിമൈസേഷനുകൾ (Hardware-Specific Optimizations)**: വിവിധ CPU ആർക്കിടെക്ചറുകൾക്കായി (AVX2, AVX-512, NEON) ഒപ്റ്റിമൈസ് ചെയ്ത കോഡ് പാതകൾ ഉൾപ്പെടുന്നു + +പരിമിതമായ മെമ്മറിയുള്ള സാധാരണ ഉപഭോക്തൃ ഹാർഡ്‌വെയറിൽ ബില്യൺ കണക്കിന് പാരാമീറ്ററുകളുള്ള മോഡലുകൾ റൺ ചെയ്യാൻ ഈ സമീപനം സാധ്യമാക്കുന്നു; ഇത് ലോക്കൽ ഡിപ്ലോയ്‌മെന്റുകൾക്കും എഡ്ജ് ഡിവൈസുകൾക്കും ഇതിനെ തികച്ചും അനുയോജ്യമാക്കുന്നു. + + + +### ഡിപ്ലോയ്‌മെന്റും ഇന്റഗ്രേഷനും + +ഇനി ഈ ഫ്രെയിംവർക്കുകൾ തമ്മിലുള്ള ഡിപ്ലോയ്‌മെന്റ്, ഇന്റഗ്രേഷൻ വ്യത്യാസങ്ങളിലേക്ക് കടക്കാം. + +**TGI** അതിന്റെ പ്രൊഡക്ഷൻ-റെഡി സവിശേഷതകൾ കൊണ്ട് എന്റർപ്രൈസ് തലത്തിലുള്ള ഡിപ്ലോയ്‌മെന്റിൽ മികച്ചുനിൽക്കുന്നു. ബിൽറ്റ്-ഇൻ Kubernetes പിന്തുണയോടെ വരുന്ന ഇതിൽ, Prometheus, Grafana എന്നിവ വഴിയുള്ള മോണിറ്ററിംഗ്, ഓട്ടോമാറ്റിക് സ്കേലിംഗ്, സമഗ്രമായ സുരക്ഷാ സവിശേഷതകൾ എന്നിങ്ങനെ പ്രൊഡക്ഷനിൽ റൺ ചെയ്യാൻ നിങ്ങൾക്ക് ആവശ്യമുള്ളതെല്ലാം ഉൾപ്പെടുന്നു. നിങ്ങളുടെ ഡിപ്ലോയ്‌മെന്റ് സുരക്ഷിതവും സ്ഥിരതയുള്ളതുമായി നിലനിർത്താൻ എന്റർപ്രൈസ്-ഗ്രേഡ് ലോഗിംഗും, കണ്ടന്റ് ഫിൽറ്ററിംഗ്, റേറ്റ് ലിമിറ്റിംഗ് തുടങ്ങിയ വിവിധ സംരക്ഷണ നടപടികളും ഈ സിസ്റ്റത്തിൽ ഉൾപ്പെടുന്നു. + +**vLLM** ഡിപ്ലോയ്‌മെന്റിനോട് കൂടുതൽ വഴക്കമുള്ളതും ഡെവലപ്പർ-സൗഹൃദവുമായ ഒരു സമീപനമാണ് സ്വീകരിക്കുന്നത്. Python-നെ കാതലാക്കി നിർമ്മിച്ചിരിക്കുന്ന ഇതിന്, നിങ്ങളുടെ നിലവിലുള്ള ആപ്ലിക്കേഷനുകളിൽ OpenAI-യുടെ API-യെ എളുപ്പത്തിൽ പകരം വയ്ക്കാൻ കഴിയും. ഈ ഫ്രെയിംവർക്ക് അസംസ്കൃത പ്രകടനം (raw performance) നൽകുന്നതിൽ ശ്രദ്ധ കേന്ദ്രീകരിക്കുന്നു; നിങ്ങളുടെ പ്രത്യേക ആവശ്യങ്ങൾക്ക് അനുസരിച്ച് ഇത് ഇഷ്ടാനുസൃതമാക്കാനും കഴിയും. ക്ലസ്‌റ്ററുകൾ കൈകാര്യം ചെയ്യാൻ Ray-യുമായി ഇത് പ്രത്യേകിച്ചും നന്നായി പ്രവർത്തിക്കുന്നു; ഉയർന്ന പ്രകടനവും അനുരൂപപ്പെടാനുള്ള കഴിവും ആവശ്യമുള്ളപ്പോൾ ഇത് മികച്ചൊരു തിരഞ്ഞെടുപ്പാണ്. + +**llama.cpp** ലാളിത്യത്തിനും പോർട്ടബിലിറ്റിക്കും മുൻഗണന നൽകുന്നു. ഇതിന്റെ സെർവർ ഇംപ്ലിമെന്റേഷൻ ഭാരം കുറഞ്ഞതാണ്; ശക്തമായ സെർവറുകളിൽ നിന്ന് സാധാരണ ലാപ്‌ടോപ്പുകളിലേക്കും, എന്തിന്, ചില ഹൈ-എൻഡ് മൊബൈൽ ഡിവൈസുകളിലേക്കും വരെ, വിപുലമായ ഹാർഡ്‌വെയർ ശ്രേണിയിൽ ഇത് റൺ ചെയ്യാൻ കഴിയും. ഏറ്റവും കുറഞ്ഞ ഡിപ്പൻഡൻസികളും ലളിതമായ ഒരു C/C++ കാതലും ഉള്ളതിനാൽ, Python ഫ്രെയിംവർക്കുകൾ ഇൻസ്‌റ്റാൾ ചെയ്യുന്നത് വെല്ലുവിളിയാകുന്ന പരിതസ്ഥിതികളിൽ ഇത് ഡിപ്ലോയ് ചെയ്യാൻ എളുപ്പമാണ്. മറ്റ് പരിഹാരങ്ങളെ അപേക്ഷിച്ച് വളരെ ചെറിയ റിസോഴ്‌സ് ഉപയോഗം (resource footprint) നിലനിർത്തിക്കൊണ്ടുതന്നെ ഈ സെർവർ OpenAI-അനുയോജ്യമായ ഒരു API നൽകുന്നു. + +## തുടങ്ങാം + +ഇൻസ്‌റ്റലേഷനും അടിസ്ഥാന സെറ്റപ്പും മുതൽ തുടങ്ങി, LLM-കൾ ഡിപ്ലോയ് ചെയ്യാൻ ഈ ഫ്രെയിംവർക്കുകൾ എങ്ങനെ ഉപയോഗിക്കാം എന്ന് നോക്കാം. + +### ഇൻസ്‌റ്റലേഷനും അടിസ്ഥാന സെറ്റപ്പും + + + + + +TGI ഇൻസ്‌റ്റാൾ ചെയ്യാനും ഉപയോഗിക്കാനും എളുപ്പമാണ്; Hugging Face ഇക്കോസിസ്‌റ്റവുമായി ഇതിന് ആഴത്തിലുള്ള ഇന്റഗ്രേഷനുണ്ട്. + +ആദ്യം, Docker ഉപയോഗിച്ച് TGI സെർവർ ലോഞ്ച് ചെയ്യുക: + +```sh +docker run --gpus all \ + --shm-size 1g \ + -p 8080:80 \ + -v ~/.cache/huggingface:/data \ + ghcr.io/huggingface/text-generation-inference:latest \ + --model-id HuggingFaceTB/SmolLM2-360M-Instruct +``` + +തുടർന്ന്, Hugging Face-ന്റെ InferenceClient ഉപയോഗിച്ച് അതുമായി സംവദിക്കുക: + +```python +from huggingface_hub import InferenceClient + +# Initialize client pointing to TGI endpoint +client = InferenceClient( + model="http://localhost:8080", # URL to the TGI server +) + +# Text generation +response = client.text_generation( + "Tell me a story", + max_new_tokens=100, + temperature=0.7, + top_p=0.95, + details=True, + stop_sequences=[], +) +print(response.generated_text) + +# For chat format +response = client.chat_completion( + messages=[ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "Tell me a story"}, + ], + max_tokens=100, + temperature=0.7, + top_p=0.95, +) +print(response.choices[0].message.content) +``` + +പകരമായി, OpenAI ക്ലയന്റും നിങ്ങൾക്ക് ഉപയോഗിക്കാം: + +```python +from openai import OpenAI + +# Initialize client pointing to TGI endpoint +client = OpenAI( + base_url="http://localhost:8080/v1", # Make sure to include /v1 + api_key="not-needed", # TGI doesn't require an API key by default +) + +# Chat completion +response = client.chat.completions.create( + model="HuggingFaceTB/SmolLM2-360M-Instruct", + messages=[ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "Tell me a story"}, + ], + max_tokens=100, + temperature=0.7, + top_p=0.95, +) +print(response.choices[0].message.content) +``` + + + + + +llama.cpp ഇൻസ്‌റ്റാൾ ചെയ്യാനും ഉപയോഗിക്കാനും എളുപ്പമാണ്; ഇതിന് ഏറ്റവും കുറഞ്ഞ ഡിപ്പൻഡൻസികൾ മാത്രമേ ആവശ്യമുള്ളൂ, CPU, GPU ഇൻഫറൻസ് രണ്ടും ഇത് പിന്തുണയ്ക്കുന്നു. + +ആദ്യം, llama.cpp ഇൻസ്‌റ്റാൾ ചെയ്ത് ബിൽഡ് ചെയ്യുക: + +```sh +# Clone the repository +git clone https://github.com/ggerganov/llama.cpp +cd llama.cpp + +# Build the project +make + +# Download the SmolLM2-1.7B-Instruct-GGUF model +curl -L -O https://huggingface.co/HuggingFaceTB/SmolLM2-1.7B-Instruct-GGUF/resolve/main/smollm2-1.7b-instruct.Q4_K_M.gguf +``` + +തുടർന്ന്, സെർവർ ലോഞ്ച് ചെയ്യുക (OpenAI API അനുയോജ്യതയോടെ): + +```sh +# Start the server +./server \ + -m smollm2-1.7b-instruct.Q4_K_M.gguf \ + --host 0.0.0.0 \ + --port 8080 \ + -c 4096 \ + --n-gpu-layers 0 # Set to a higher number to use GPU +``` + +Hugging Face-ന്റെ InferenceClient ഉപയോഗിച്ച് സെർവറുമായി സംവദിക്കുക: + +```python +from huggingface_hub import InferenceClient + +# Initialize client pointing to llama.cpp server +client = InferenceClient( + model="http://localhost:8080/v1", # URL to the llama.cpp server + token="sk-no-key-required", # llama.cpp server requires this placeholder +) + +# Text generation +response = client.text_generation( + "Tell me a story", + max_new_tokens=100, + temperature=0.7, + top_p=0.95, + details=True, +) +print(response.generated_text) + +# For chat format +response = client.chat_completion( + messages=[ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "Tell me a story"}, + ], + max_tokens=100, + temperature=0.7, + top_p=0.95, +) +print(response.choices[0].message.content) +``` + +പകരമായി, OpenAI ക്ലയന്റും നിങ്ങൾക്ക് ഉപയോഗിക്കാം: + +```python +from openai import OpenAI + +# Initialize client pointing to llama.cpp server +client = OpenAI( + base_url="http://localhost:8080/v1", + api_key="sk-no-key-required", # llama.cpp server requires this placeholder +) + +# Chat completion +response = client.chat.completions.create( + model="smollm2-1.7b-instruct", # Model identifier can be anything as server only loads one model + messages=[ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "Tell me a story"}, + ], + max_tokens=100, + temperature=0.7, + top_p=0.95, +) +print(response.choices[0].message.content) +``` + + + + + +vLLM ഇൻസ്‌റ്റാൾ ചെയ്യാനും ഉപയോഗിക്കാനും എളുപ്പമാണ്; OpenAI API അനുയോജ്യതയും ഒരു നേറ്റീവ് Python ഇന്റർഫേസും ഇതിനുണ്ട്. + +ആദ്യം, vLLM-ന്റെ OpenAI-അനുയോജ്യമായ സെർവർ ലോഞ്ച് ചെയ്യുക: + +```sh +python -m vllm.entrypoints.openai.api_server \ + --model HuggingFaceTB/SmolLM2-360M-Instruct \ + --host 0.0.0.0 \ + --port 8000 +``` + +തുടർന്ന്, Hugging Face-ന്റെ InferenceClient ഉപയോഗിച്ച് അതുമായി സംവദിക്കുക: + +```python +from huggingface_hub import InferenceClient + +# Initialize client pointing to vLLM endpoint +client = InferenceClient( + model="http://localhost:8000/v1", # URL to the vLLM server +) + +# Text generation +response = client.text_generation( + "Tell me a story", + max_new_tokens=100, + temperature=0.7, + top_p=0.95, + details=True, +) +print(response.generated_text) + +# For chat format +response = client.chat_completion( + messages=[ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "Tell me a story"}, + ], + max_tokens=100, + temperature=0.7, + top_p=0.95, +) +print(response.choices[0].message.content) +``` + +പകരമായി, OpenAI ക്ലയന്റും നിങ്ങൾക്ക് ഉപയോഗിക്കാം: + +```python +from openai import OpenAI + +# Initialize client pointing to vLLM endpoint +client = OpenAI( + base_url="http://localhost:8000/v1", + api_key="not-needed", # vLLM doesn't require an API key by default +) + +# Chat completion +response = client.chat.completions.create( + model="HuggingFaceTB/SmolLM2-360M-Instruct", + messages=[ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "Tell me a story"}, + ], + max_tokens=100, + temperature=0.7, + top_p=0.95, +) +print(response.choices[0].message.content) +``` + + + + + +### അടിസ്ഥാന ടെക്‌സ്‌റ്റ് ജനറേഷൻ + +ഈ ഫ്രെയിംവർക്കുകൾ ഉപയോഗിച്ചുള്ള ടെക്‌സ്‌റ്റ് ജനറേഷന്റെ ഉദാഹരണങ്ങൾ നോക്കാം: + + + + + +ആദ്യം, നൂതന പാരാമീറ്ററുകളോടെ TGI ഡിപ്ലോയ് ചെയ്യുക: +```sh +docker run --gpus all \ + --shm-size 1g \ + -p 8080:80 \ + -v ~/.cache/huggingface:/data \ + ghcr.io/huggingface/text-generation-inference:latest \ + --model-id HuggingFaceTB/SmolLM2-360M-Instruct \ + --max-total-tokens 4096 \ + --max-input-length 3072 \ + --max-batch-total-tokens 8192 \ + --waiting-served-ratio 1.2 +``` + +വഴക്കമുള്ള ടെക്‌സ്‌റ്റ് ജനറേഷനായി InferenceClient ഉപയോഗിക്കുക: + +```python +from huggingface_hub import InferenceClient + +client = InferenceClient(model="http://localhost:8080") + +# Advanced parameters example +response = client.chat_completion( + messages=[ + {"role": "system", "content": "You are a creative storyteller."}, + {"role": "user", "content": "Write a creative story"}, + ], + temperature=0.8, + max_tokens=200, + top_p=0.95, +) +print(response.choices[0].message.content) + +# Raw text generation +response = client.text_generation( + "Write a creative story about space exploration", + max_new_tokens=200, + temperature=0.8, + top_p=0.95, + repetition_penalty=1.1, + do_sample=True, + details=True, +) +print(response.generated_text) +``` + +അല്ലെങ്കിൽ OpenAI ക്ലയന്റ് ഉപയോഗിക്കുക: +```python +from openai import OpenAI + +client = OpenAI(base_url="http://localhost:8080/v1", api_key="not-needed") + +# Advanced parameters example +response = client.chat.completions.create( + model="HuggingFaceTB/SmolLM2-360M-Instruct", + messages=[ + {"role": "system", "content": "You are a creative storyteller."}, + {"role": "user", "content": "Write a creative story"}, + ], + temperature=0.8, # Higher for more creativity +) +print(response.choices[0].message.content) +``` + + + + + +llama.cpp-യിൽ, സെർവർ ലോഞ്ച് ചെയ്യുമ്പോൾ തന്നെ നൂതന പാരാമീറ്ററുകൾ സെറ്റ് ചെയ്യാം: + +```sh +./server \ + -m smollm2-1.7b-instruct.Q4_K_M.gguf \ + --host 0.0.0.0 \ + --port 8080 \ + -c 4096 \ # Context size + --threads 8 \ # CPU threads to use + --batch-size 512 \ # Batch size for prompt evaluation + --n-gpu-layers 0 # GPU layers (0 = CPU only) +``` + +InferenceClient ഉപയോഗിക്കുക: + +```python +from huggingface_hub import InferenceClient + +client = InferenceClient(model="http://localhost:8080/v1", token="sk-no-key-required") + +# Advanced parameters example +response = client.chat_completion( + messages=[ + {"role": "system", "content": "You are a creative storyteller."}, + {"role": "user", "content": "Write a creative story"}, + ], + temperature=0.8, + max_tokens=200, + top_p=0.95, +) +print(response.choices[0].message.content) + +# For direct text generation +response = client.text_generation( + "Write a creative story about space exploration", + max_new_tokens=200, + temperature=0.8, + top_p=0.95, + repetition_penalty=1.1, + details=True, +) +print(response.generated_text) +``` + +അല്ലെങ്കിൽ, സാംപ്ലിംഗ് പാരാമീറ്ററുകളുടെ മേൽ നിയന്ത്രണത്തോടെ ജനറേറ്റ് ചെയ്യാൻ OpenAI ക്ലയന്റ് ഉപയോഗിക്കുക: + +```python +from openai import OpenAI + +client = OpenAI(base_url="http://localhost:8080/v1", api_key="sk-no-key-required") + +# Advanced parameters example +response = client.chat.completions.create( + model="smollm2-1.7b-instruct", + messages=[ + {"role": "system", "content": "You are a creative storyteller."}, + {"role": "user", "content": "Write a creative story"}, + ], + temperature=0.8, # Higher for more creativity + top_p=0.95, # Nucleus sampling probability + frequency_penalty=0.5, # Reduce repetition of frequent tokens + presence_penalty=0.5, # Reduce repetition by penalizing tokens already present + max_tokens=200, # Maximum generation length +) +print(response.choices[0].message.content) +``` + +കൂടുതൽ നിയന്ത്രണത്തിനായി llama.cpp-യുടെ നേറ്റീവ് ലൈബ്രറിയും നിങ്ങൾക്ക് ഉപയോഗിക്കാം: + +```python +# Using llama-cpp-python package for direct model access +from llama_cpp import Llama + +# Load the model +llm = Llama( + model_path="smollm2-1.7b-instruct.Q4_K_M.gguf", + n_ctx=4096, # Context window size + n_threads=8, # CPU threads + n_gpu_layers=0, # GPU layers (0 = CPU only) +) + +# Format prompt according to the model's expected format +prompt = """<|im_start|>system +You are a creative storyteller. +<|im_end|> +<|im_start|>user +Write a creative story +<|im_end|> +<|im_start|>assistant +""" + +# Generate response with precise parameter control +output = llm( + prompt, + max_tokens=200, + temperature=0.8, + top_p=0.95, + frequency_penalty=0.5, + presence_penalty=0.5, + stop=["<|im_end|>"], +) + +print(output["choices"][0]["text"]) +``` + + + + + +vLLM-ന്റെ നൂതന ഉപയോഗത്തിനായി, InferenceClient നിങ്ങൾക്ക് ഉപയോഗിക്കാം: + +```python +from huggingface_hub import InferenceClient + +client = InferenceClient(model="http://localhost:8000/v1") + +# Advanced parameters example +response = client.chat_completion( + messages=[ + {"role": "system", "content": "You are a creative storyteller."}, + {"role": "user", "content": "Write a creative story"}, + ], + temperature=0.8, + max_tokens=200, + top_p=0.95, +) +print(response.choices[0].message.content) + +# For direct text generation +response = client.text_generation( + "Write a creative story about space exploration", + max_new_tokens=200, + temperature=0.8, + top_p=0.95, + details=True, +) +print(response.generated_text) +``` + +OpenAI ക്ലയന്റും നിങ്ങൾക്ക് ഉപയോഗിക്കാം: + +```python +from openai import OpenAI + +client = OpenAI(base_url="http://localhost:8000/v1", api_key="not-needed") + +# Advanced parameters example +response = client.chat.completions.create( + model="HuggingFaceTB/SmolLM2-360M-Instruct", + messages=[ + {"role": "system", "content": "You are a creative storyteller."}, + {"role": "user", "content": "Write a creative story"}, + ], + temperature=0.8, + top_p=0.95, + max_tokens=200, +) +print(response.choices[0].message.content) +``` + +സൂക്ഷ്മമായ നിയന്ത്രണം (fine-grained control) നൽകുന്ന ഒരു നേറ്റീവ് Python ഇന്റർഫേസും vLLM നൽകുന്നു: + +```python +from vllm import LLM, SamplingParams + +# Initialize the model with advanced parameters +llm = LLM( + model="HuggingFaceTB/SmolLM2-360M-Instruct", + gpu_memory_utilization=0.85, + max_num_batched_tokens=8192, + max_num_seqs=256, + block_size=16, +) + +# Configure sampling parameters +sampling_params = SamplingParams( + temperature=0.8, # Higher for more creativity + top_p=0.95, # Consider top 95% probability mass + max_tokens=100, # Maximum length + presence_penalty=1.1, # Reduce repetition + frequency_penalty=1.1, # Reduce repetition + stop=["\n\n", "###"], # Stop sequences +) + +# Generate text +prompt = "Write a creative story" +outputs = llm.generate(prompt, sampling_params) +print(outputs[0].outputs[0].text) + +# For chat-style interactions +chat_prompt = [ + {"role": "system", "content": "You are a creative storyteller."}, + {"role": "user", "content": "Write a creative story"}, +] +formatted_prompt = llm.get_chat_template()(chat_prompt) # Uses model's chat template +outputs = llm.generate(formatted_prompt, sampling_params) +print(outputs[0].outputs[0].text) +``` + + + + + +## നൂതന ജനറേഷൻ നിയന്ത്രണം + +### ടോക്കൺ തിരഞ്ഞെടുപ്പും സാംപ്ലിംഗും + +ടെക്‌സ്‌റ്റ് ജനറേറ്റ് ചെയ്യുന്ന പ്രക്രിയയിൽ ഓരോ ഘട്ടത്തിലും അടുത്ത ടോക്കൺ തിരഞ്ഞെടുക്കേണ്ടതുണ്ട്. ഈ തിരഞ്ഞെടുപ്പ് പ്രക്രിയ വിവിധ പാരാമീറ്ററുകളിലൂടെ നിയന്ത്രിക്കാം: + +1. **റോ ലോജിറ്റ്‌സ് (Raw Logits)**: ഓരോ ടോക്കണിനുമുള്ള പ്രാരംഭ ഔട്ട്‌പുട്ട് പ്രോബബിലിറ്റികൾ +2. **ടെമ്പറേച്ചർ (Temperature)**: തിരഞ്ഞെടുപ്പിലെ ക്രമരഹിതത (randomness) നിയന്ത്രിക്കുന്നു (ഉയർന്നത് = കൂടുതൽ സർഗ്ഗാത്മകം) +3. **Top-p (Nucleus) സാംപ്ലിംഗ്**: പ്രോബബിലിറ്റി മാസ്സിന്റെ X% വരുന്ന മുൻനിര ടോക്കണുകളിലേക്ക് ഫിൽറ്റർ ചെയ്യുന്നു +4. **Top-k ഫിൽറ്ററിംഗ്**: ഏറ്റവും സാധ്യതയുള്ള k ടോക്കണുകളിലേക്ക് തിരഞ്ഞെടുപ്പ് പരിമിതപ്പെടുത്തുന്നു + +ഈ പാരാമീറ്ററുകൾ എങ്ങനെ കോൺഫിഗർ ചെയ്യാം എന്ന് നോക്കാം: + + + + + +```python +client.generate( + "Write a creative story", + temperature=0.8, # Higher for more creativity + top_p=0.95, # Consider top 95% probability mass + top_k=50, # Consider top 50 tokens + max_new_tokens=100, # Maximum length + repetition_penalty=1.1, # Reduce repetition +) +``` + + + + + +```python +# Via OpenAI API compatibility +response = client.completions.create( + model="smollm2-1.7b-instruct", # Model name (can be any string for llama.cpp server) + prompt="Write a creative story", + temperature=0.8, # Higher for more creativity + top_p=0.95, # Consider top 95% probability mass + frequency_penalty=1.1, # Reduce repetition + presence_penalty=0.1, # Reduce repetition + max_tokens=100, # Maximum length +) + +# Via llama-cpp-python direct access +output = llm( + "Write a creative story", + temperature=0.8, + top_p=0.95, + top_k=50, + max_tokens=100, + repeat_penalty=1.1, +) +``` + + + + + +```python +params = SamplingParams( + temperature=0.8, # Higher for more creativity + top_p=0.95, # Consider top 95% probability mass + top_k=50, # Consider top 50 tokens + max_tokens=100, # Maximum length + presence_penalty=0.1, # Reduce repetition +) +llm.generate("Write a creative story", sampling_params=params) +``` + + + + + +### ആവർത്തനം നിയന്ത്രിക്കുന്നു + +ആവർത്തന സ്വഭാവമുള്ള ടെക്‌സ്‌റ്റ് ജനറേഷൻ തടയാനുള്ള മാർഗ്ഗങ്ങൾ ഈ ഫ്രെയിംവർക്കുകളെല്ലാം നൽകുന്നു: + + + + + +```python +client.generate( + "Write a varied text", + repetition_penalty=1.1, # Penalize repeated tokens + no_repeat_ngram_size=3, # Prevent 3-gram repetition +) +``` + + + + + +```python +# Via OpenAI API +response = client.completions.create( + model="smollm2-1.7b-instruct", + prompt="Write a varied text", + frequency_penalty=1.1, # Penalize frequent tokens + presence_penalty=0.8, # Penalize tokens already present +) + +# Via direct library +output = llm( + "Write a varied text", + repeat_penalty=1.1, # Penalize repeated tokens + frequency_penalty=0.5, # Additional frequency penalty + presence_penalty=0.5, # Additional presence penalty +) +``` + + + + + +```python +params = SamplingParams( + presence_penalty=0.1, # Penalize token presence + frequency_penalty=0.1, # Penalize token frequency +) +``` + + + + + +### ദൈർഘ്യ നിയന്ത്രണവും സ്‌റ്റോപ്പ് സീക്വൻസുകളും + +ജനറേഷന്റെ ദൈർഘ്യം നിയന്ത്രിക്കാനും എപ്പോൾ നിർത്തണം എന്ന് വ്യക്തമാക്കാനും നിങ്ങൾക്ക് കഴിയും: + + + + + +```python +client.generate( + "Generate a short paragraph", + max_new_tokens=100, + min_new_tokens=10, + stop_sequences=["\n\n", "###"], +) +``` + + + + + +```python +# Via OpenAI API +response = client.completions.create( + model="smollm2-1.7b-instruct", + prompt="Generate a short paragraph", + max_tokens=100, + stop=["\n\n", "###"], +) + +# Via direct library +output = llm("Generate a short paragraph", max_tokens=100, stop=["\n\n", "###"]) +``` + + + + + +```python +params = SamplingParams( + max_tokens=100, + min_tokens=10, + stop=["###", "\n\n"], + ignore_eos=False, + skip_special_tokens=True, +) +``` + + + + + +## മെമ്മറി മാനേജ്‌മെന്റ് + +കാര്യക്ഷമമായ ഇൻഫറൻസിനായി ഈ ഫ്രെയിംവർക്കുകളെല്ലാം നൂതന മെമ്മറി മാനേജ്‌മെന്റ് വിദ്യകൾ ഇംപ്ലിമെന്റ് ചെയ്യുന്നു. + + + + + +TGI Flash Attention 2-ഉം കണ്ടിന്യുവസ് ബാച്ചിംഗും ഉപയോഗിക്കുന്നു: + +```sh +# Docker deployment with memory optimization +docker run --gpus all -p 8080:80 \ + --shm-size 1g \ + ghcr.io/huggingface/text-generation-inference:latest \ + --model-id HuggingFaceTB/SmolLM2-1.7B-Instruct \ + --max-batch-total-tokens 8192 \ + --max-input-length 4096 +``` + + + + + +llama.cpp ക്വാണ്ടൈസേഷനും ഒപ്റ്റിമൈസ് ചെയ്ത മെമ്മറി ലേഔട്ടും ഉപയോഗിക്കുന്നു: + +```sh +# Server with memory optimizations +./server \ + -m smollm2-1.7b-instruct.Q4_K_M.gguf \ + --host 0.0.0.0 \ + --port 8080 \ + -c 2048 \ # Context size + --threads 4 \ # CPU threads + --n-gpu-layers 32 \ # Use more GPU layers for larger models + --mlock \ # Lock memory to prevent swapping + --cont-batching # Enable continuous batching +``` + +നിങ്ങളുടെ GPU-വിന് താങ്ങാനാവാത്തത്ര വലിയ മോഡലുകൾക്ക്, CPU ഓഫ്‌ലോഡിംഗ് ഉപയോഗിക്കാം: + +```sh +./server \ + -m smollm2-1.7b-instruct.Q4_K_M.gguf \ + --n-gpu-layers 20 \ # Keep first 20 layers on GPU + --threads 8 # Use more CPU threads for CPU layers +``` + + + + + +ഏറ്റവും മികച്ച മെമ്മറി മാനേജ്‌മെന്റിനായി vLLM PagedAttention ഉപയോഗിക്കുന്നു: + +```python +from vllm.engine.arg_utils import AsyncEngineArgs + +engine_args = AsyncEngineArgs( + model="HuggingFaceTB/SmolLM2-1.7B-Instruct", + gpu_memory_utilization=0.85, + max_num_batched_tokens=8192, + block_size=16, +) + +llm = LLM(engine_args=engine_args) +``` + + + + + +## റിസോഴ്‌സുകൾ + +- [Text Generation Inference ഡോക്യുമെന്റേഷൻ](https://huggingface.co/docs/text-generation-inference) +- [TGI GitHub റിപ്പോസിറ്ററി](https://github.com/huggingface/text-generation-inference) +- [vLLM ഡോക്യുമെന്റേഷൻ](https://vllm.readthedocs.io/) +- [vLLM GitHub റിപ്പോസിറ്ററി](https://github.com/vllm-project/vllm) +- [PagedAttention പേപ്പർ](https://arxiv.org/abs/2309.06180) +- [llama.cpp GitHub റിപ്പോസിറ്ററി](https://github.com/ggerganov/llama.cpp) +- [llama-cpp-python റിപ്പോസിറ്ററി](https://github.com/abetlen/llama-cpp-python) diff --git a/chapters/ml/chapter2/9.mdx b/chapters/ml/chapter2/9.mdx new file mode 100644 index 000000000..4eedeb1a5 --- /dev/null +++ b/chapters/ml/chapter2/9.mdx @@ -0,0 +1,252 @@ + + + + +# അധ്യായത്തിന്റെ അവസാന ക്വിസ്[[end-of-chapter-quiz]] + + + +### 1. ലാംഗ്വേജ് മോഡലിംഗ് പൈപ്പ്‌ലൈനിന്റെ ക്രമം എന്താണ്? + + + +### 2. അടിസ്ഥാന Transformer മോഡൽ ഔട്ട്‌പുട്ട് ചെയ്യുന്ന ടെൻസറിന് എത്ര ഡൈമൻഷനുകളുണ്ട്, അവ ഏതൊക്കെയാണ്? + + + +### 3. താഴെ പറയുന്നവയിൽ ഏതാണ് സബ്‌വേഡ് ടോക്കണൈസേഷന്റെ (subword tokenization) ഒരു ഉദാഹരണം? + + + +### 4. എന്താണ് ഒരു മോഡൽ ഹെഡ് (model head)? + + + +### 5. എന്താണ് ഒരു AutoModel? + +AutoTrain ഉൽപ്പന്നവുമായി നിങ്ങൾ ഇതിനെ തെറ്റിദ്ധരിക്കുന്നുണ്ടോ?" + }, + { + text: "ചെക്ക്‌പോയിന്റിനെ അടിസ്ഥാനമാക്കി ശരിയായ ആർക്കിടെക്ചർ റിട്ടേൺ ചെയ്യുന്ന ഒരു ഒബ്‌ജക്റ്റ്", + explain: "കൃത്യമായി: ശരിയായ ആർക്കിടെക്ചർ റിട്ടേൺ ചെയ്യാൻ, ഏത് ചെക്ക്‌പോയിന്റിൽ നിന്ന് ഇനിഷ്യലൈസ് ചെയ്യണം എന്ന് മാത്രം അറിഞ്ഞാൽ AutoModel-ന് മതി.", + correct: true + }, + { + text: "ശരിയായ വെയ്‌റ്റുകൾ ലോഡ് ചെയ്യാൻ, ഇൻപുട്ടുകളിൽ ഉപയോഗിച്ചിരിക്കുന്ന ഭാഷ സ്വയമേവ കണ്ടെത്തുന്ന ഒരു മോഡൽ", + explain: "ചില ചെക്ക്‌പോയിന്റുകൾക്കും മോഡലുകൾക്കും ഒന്നിലധികം ഭാഷകൾ കൈകാര്യം ചെയ്യാൻ കഴിയുമെങ്കിലും, ഭാഷയ്ക്ക് അനുസരിച്ച് സ്വയമേവ ചെക്ക്‌പോയിന്റ് തിരഞ്ഞെടുക്കാനുള്ള ബിൽറ്റ്-ഇൻ ടൂളുകളൊന്നുമില്ല. നിങ്ങളുടെ ടാസ്‌കിന് ഏറ്റവും അനുയോജ്യമായ ചെക്ക്‌പോയിന്റ് കണ്ടെത്താൻ Model Hub-ലേക്ക് പോകുക!" + } + ]} +/> + +### 6. വ്യത്യസ്ത നീളമുള്ള സീക്വൻസുകൾ ഒരുമിച്ച് ബാച്ച് ചെയ്യുമ്പോൾ അറിഞ്ഞിരിക്കേണ്ട വിദ്യകൾ ഏതൊക്കെയാണ്? + + + +### 7. ഒരു സീക്വൻസ് ക്ലാസിഫിക്കേഷൻ മോഡൽ ഔട്ട്‌പുട്ട് ചെയ്യുന്ന ലോജിറ്റ്‌സിൽ ഒരു SoftMax ഫംഗ്‌ഷൻ പ്രയോഗിക്കുന്നതിന്റെ ഉദ്ദേശ്യം എന്താണ്? + + + +### 8. ടോക്കണൈസർ API-യുടെ ഭൂരിഭാഗവും ഏത് മെത്തേഡിനെ കേന്ദ്രീകരിച്ചാണ്? + +encode, കാരണം ഇതിന് ടെക്‌സ്‌റ്റിനെ ID-കളായും ID-കളെ പ്രവചനങ്ങളായും എൻകോഡ് ചെയ്യാൻ കഴിയും", + explain: "തെറ്റ്! ടോക്കണൈസറുകളിൽ encode മെത്തേഡ് ഉണ്ടെങ്കിലും, മോഡലുകളിൽ അതില്ല." + }, + { + text: "ടോക്കണൈസർ ഒബ്‌ജക്റ്റിനെ നേരിട്ട് വിളിക്കുന്നത് (call ചെയ്യുന്നത്).", + explain: "കൃത്യമായി! ടോക്കണൈസറിന്റെ __call__ മെത്തേഡ്, ഏറെക്കുറെ എന്തും കൈകാര്യം ചെയ്യാൻ കഴിയുന്ന വളരെ ശക്തമായ ഒരു മെത്തേഡാണ്. ഒരു മോഡലിൽ നിന്ന് പ്രവചനങ്ങൾ നേടാൻ ഉപയോഗിക്കുന്ന മെത്തേഡും ഇതുതന്നെയാണ്.", + correct: true + }, + { + text: "pad", + explain: "തെറ്റ്! പാഡിംഗ് വളരെ ഉപകാരപ്രദമാണ്, എന്നാൽ അത് ടോക്കണൈസർ API-യുടെ ഒരു ഭാഗം മാത്രമാണ്." + }, + { + text: "tokenize", + explain: "tokenize മെത്തേഡ് ഏറ്റവും ഉപകാരപ്രദമായ മെത്തേഡുകളിലൊന്നാണെന്ന് പറയാം, എന്നാൽ അത് ടോക്കണൈസർ API-യുടെ കാതലല്ല." + } + ]} +/> + +### 9. ഈ കോഡ് സാമ്പിളിൽ `result` എന്ന വേരിയബിളിൽ എന്താണ് അടങ്ങിയിരിക്കുന്നത്? + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +result = tokenizer.tokenize("Hello!") +``` + +__call__ അല്ലെങ്കിൽ convert_tokens_to_ids മെത്തേഡ്!" + }, + { + text: "എല്ലാ ടോക്കണുകളും അടങ്ങിയ ഒരു സ്‌ട്രിംഗ്", + explain: "ഇത് അത്ര ഉചിതമാകില്ല, കാരണം സ്‌ട്രിംഗിനെ ഒന്നിലധികം ടോക്കണുകളായി വിഭജിക്കുക എന്നതാണ് ലക്ഷ്യം." + } + ]} +/> + +### 10. താഴെ കൊടുത്ത കോഡിൽ എന്തെങ്കിലും തെറ്റുണ്ടോ? + +```py +from transformers import AutoTokenizer, AutoModel + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +model = AutoModel.from_pretrained("gpt2") + +encoded = tokenizer("Hey!", return_tensors="pt") +result = model(**encoded) +``` + + diff --git a/chapters/ml/chapter3/1.mdx b/chapters/ml/chapter3/1.mdx new file mode 100644 index 000000000..9237a9fd3 --- /dev/null +++ b/chapters/ml/chapter3/1.mdx @@ -0,0 +1,35 @@ + + +# ആമുഖം[[introduction]] + + + +[അധ്യായം 2](/course/chapter2)-ൽ, പ്രവചനങ്ങൾ (predictions) നടത്താൻ ടോക്കണൈസറുകളും പ്രീട്രെയിൻഡ് മോഡലുകളും എങ്ങനെ ഉപയോഗിക്കാം എന്ന് നമ്മൾ പരിശോധിച്ചു. എന്നാൽ ഒരു നിശ്ചിത ടാസ്‌ക്ക് പരിഹരിക്കാൻ ഒരു പ്രീട്രെയിൻഡ് മോഡൽ ഫൈൻ-ട്യൂൺ ചെയ്യണമെങ്കിലോ? അതാണ് ഈ അധ്യായത്തിന്റെ വിഷയം! നിങ്ങൾ പഠിക്കുന്നത്: + +* ഏറ്റവും പുതിയ 🤗 Datasets സവിശേഷതകൾ ഉപയോഗിച്ച് Hub-ൽ നിന്ന് ഒരു വലിയ ഡേറ്റാസെറ്റ് എങ്ങനെ തയ്യാറാക്കാം +* ആധുനിക മികച്ച രീതികൾ (best practices) പിന്തുടർന്ന് ഒരു മോഡൽ ഫൈൻ-ട്യൂൺ ചെയ്യാൻ ഹൈ-ലെവൽ `Trainer` API എങ്ങനെ ഉപയോഗിക്കാം +* ഒപ്‌റ്റിമൈസേഷൻ ടെക്‌നിക്കുകൾ ഉൾപ്പെടുത്തി ഒരു കസ്‌റ്റം ട്രെയിനിംഗ് ലൂപ്പ് എങ്ങനെ നടപ്പിലാക്കാം +* ഏത് സെറ്റപ്പിലും ഡിസ്‌ട്രിബ്യൂട്ടഡ് ട്രെയിനിംഗ് എളുപ്പത്തിൽ റൺ ചെയ്യാൻ 🤗 Accelerate ലൈബ്രറി എങ്ങനെ പ്രയോജനപ്പെടുത്താം +* പരമാവധി പ്രകടനത്തിനായി ഇന്നത്തെ ഫൈൻ-ട്യൂണിംഗ് മികച്ച രീതികൾ എങ്ങനെ പ്രയോഗിക്കാം + +> [!TIP] +> 📚 **അത്യാവശ്യ വിഭവങ്ങൾ**: തുടങ്ങുന്നതിന് മുമ്പ്, ഡേറ്റാ പ്രോസസ്സിംഗിനെക്കുറിച്ചുള്ള [🤗 Datasets ഡോക്യുമെന്റേഷൻ](https://huggingface.co/docs/datasets/) ഒന്ന് നോക്കുന്നത് നല്ലതായിരിക്കും. + +🤗 Transformers ലൈബ്രറിക്ക് പുറമെയുള്ള ചില Hugging Face ലൈബ്രറികളിലേക്കുള്ള ഒരു ആമുഖമായും ഈ അധ്യായം പ്രവർത്തിക്കും! 🤗 Datasets, 🤗 Tokenizers, 🤗 Accelerate, 🤗 Evaluate തുടങ്ങിയ ലൈബ്രറികൾ മോഡലുകളെ കൂടുതൽ കാര്യക്ഷമമായും ഫലപ്രദമായും ട്രെയിൻ ചെയ്യാൻ നിങ്ങളെ എങ്ങനെ സഹായിക്കുന്നു എന്ന് നമ്മൾ കാണും. + +ഈ അധ്യായത്തിലെ പ്രധാന ഭാഗങ്ങൾ ഓരോന്നും വ്യത്യസ്തമായ എന്തെങ്കിലും നിങ്ങളെ പഠിപ്പിക്കും: +- **ഭാഗം 2**: ആധുനിക ഡേറ്റാ പ്രീപ്രോസസ്സിംഗ് ടെക്‌നിക്കുകളും കാര്യക്ഷമമായ ഡേറ്റാസെറ്റ് കൈകാര്യവും പഠിക്കുക +- **ഭാഗം 3**: ശക്തമായ Trainer API-യും അതിന്റെ ഏറ്റവും പുതിയ എല്ലാ സവിശേഷതകളും സ്വായത്തമാക്കുക +- **ഭാഗം 4**: ട്രെയിനിംഗ് ലൂപ്പുകൾ ആദ്യം മുതൽ നടപ്പിലാക്കുകയും Accelerate ഉപയോഗിച്ചുള്ള ഡിസ്‌ട്രിബ്യൂട്ടഡ് ട്രെയിനിംഗ് മനസ്സിലാക്കുകയും ചെയ്യുക + +ഈ അധ്യായത്തിന്റെ അവസാനത്തോടെ, ഈ മേഖലയിലെ ഏറ്റവും പുതിയ മികച്ച രീതികൾ പ്രയോഗിച്ചുകൊണ്ട്, ഹൈ-ലെവൽ API-കളും കസ്‌റ്റം ട്രെയിനിംഗ് ലൂപ്പുകളും ഉപയോഗിച്ച് നിങ്ങളുടെ സ്വന്തം ഡേറ്റാസെറ്റുകളിൽ മോഡലുകൾ ഫൈൻ-ട്യൂൺ ചെയ്യാൻ നിങ്ങൾക്ക് കഴിയും. + +> [!TIP] +> 🎯 **നിങ്ങൾ എന്ത് നിർമ്മിക്കും**: ഈ അധ്യായത്തിന്റെ അവസാനത്തോടെ, ടെക്‌സ്‌റ്റ് ക്ലാസിഫിക്കേഷനായി ഒരു BERT മോഡൽ നിങ്ങൾ ഫൈൻ-ട്യൂൺ ചെയ്തിട്ടുണ്ടാകും; കൂടാതെ ഈ ടെക്‌നിക്കുകൾ നിങ്ങളുടെ സ്വന്തം ഡേറ്റാസെറ്റുകളിലേക്കും ടാസ്‌ക്കുകളിലേക്കും എങ്ങനെ അനുരൂപപ്പെടുത്താം എന്നും നിങ്ങൾക്ക് മനസ്സിലാകും. + +ആധുനിക ഡീപ് ലേണിംഗ് ഗവേഷണത്തിലും പ്രൊഡക്‌ഷനിലും സ്റ്റാൻഡേർഡ് ഫ്രെയിംവർക്കായി മാറിയതിനാൽ, ഈ അധ്യായം **PyTorch**-ൽ മാത്രമായി ശ്രദ്ധ കേന്ദ്രീകരിക്കുന്നു. Hugging Face ഇക്കോസിസ്റ്റത്തിലെ ഏറ്റവും പുതിയ API-കളും മികച്ച രീതികളും നമ്മൾ ഉപയോഗിക്കും. + +നിങ്ങൾ ട്രെയിൻ ചെയ്ത മോഡലുകൾ Hugging Face Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യാൻ, നിങ്ങൾക്ക് ഒരു Hugging Face അക്കൗണ്ട് ആവശ്യമാണ്: [ഒരു അക്കൗണ്ട് ഉണ്ടാക്കുക](https://huggingface.co/join) diff --git a/chapters/ml/chapter3/2.mdx b/chapters/ml/chapter3/2.mdx new file mode 100644 index 000000000..0271f526b --- /dev/null +++ b/chapters/ml/chapter3/2.mdx @@ -0,0 +1,419 @@ +# ഡേറ്റ പ്രോസസ്സ് ചെയ്യുന്നു[[processing-the-data]] + + + +[മുൻ അധ്യായത്തിലെ](/course/chapter2) ഉദാഹരണം തുടർന്നുകൊണ്ട്, ഒരു ബാച്ചിൽ ഒരു സീക്വൻസ് ക്ലാസിഫയർ നമ്മൾ എങ്ങനെ ട്രെയിൻ ചെയ്യും എന്ന് ഇതാ: + +```python +import torch +from torch.optim import AdamW +from transformers import AutoTokenizer, AutoModelForSequenceClassification + +# Same as before +checkpoint = "bert-base-uncased" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +model = AutoModelForSequenceClassification.from_pretrained(checkpoint) +sequences = [ + "I've been waiting for a HuggingFace course my whole life.", + "This course is amazing!", +] +batch = tokenizer(sequences, padding=True, truncation=True, return_tensors="pt") + +# This is new +batch["labels"] = torch.tensor([1, 1]) + +optimizer = AdamW(model.parameters()) +loss = model(**batch).loss +loss.backward() +optimizer.step() +``` + +തീർച്ചയായും, വെറും രണ്ട് വാക്യങ്ങളിൽ മോഡൽ ട്രെയിൻ ചെയ്തതുകൊണ്ട് വളരെ മികച്ച ഫലങ്ങൾ ലഭിക്കാൻ പോകുന്നില്ല. മികച്ച ഫലങ്ങൾ ലഭിക്കാൻ, നിങ്ങൾ ഒരു വലിയ ഡേറ്റാസെറ്റ് തയ്യാറാക്കേണ്ടതുണ്ട്. + +ഈ ഭാഗത്തിൽ, William B. Dolan-ഉം Chris Brockett-ഉം ചേർന്ന് ഒരു [പ്രബന്ധത്തിൽ](https://www.aclweb.org/anthology/I05-5002.pdf) അവതരിപ്പിച്ച MRPC (Microsoft Research Paraphrase Corpus) ഡേറ്റാസെറ്റ് നമ്മൾ ഉദാഹരണമായി ഉപയോഗിക്കും. 5,801 വാക്യജോഡികൾ അടങ്ങിയ ഈ ഡേറ്റാസെറ്റിൽ, ഓരോ ജോഡിയും പാരാഫ്രേസുകളാണോ അല്ലയോ (അതായത്, രണ്ട് വാക്യങ്ങളും ഒരേ അർത്ഥമാണോ നൽകുന്നത്) എന്ന് സൂചിപ്പിക്കുന്ന ഒരു ലേബലുമുണ്ട്. ചെറിയ ഒരു ഡേറ്റാസെറ്റായതിനാൽ അതിൽ ട്രെയിനിംഗ് പരീക്ഷിക്കാൻ എളുപ്പമാണ് എന്നതുകൊണ്ടാണ് ഈ അധ്യായത്തിനായി നമ്മൾ ഇത് തിരഞ്ഞെടുത്തത്. + +### Hub-ൽ നിന്ന് ഒരു ഡേറ്റാസെറ്റ് ലോഡ് ചെയ്യുന്നു[[loading-a-dataset-from-the-hub]] + + + +Hub-ൽ മോഡലുകൾ മാത്രമല്ല ഉള്ളത്; വിവിധ ഭാഷകളിലുള്ള ഒട്ടേറെ ഡേറ്റാസെറ്റുകളും അതിലുണ്ട്. നിങ്ങൾക്ക് ഡേറ്റാസെറ്റുകൾ [ഇവിടെ](https://huggingface.co/datasets) ബ്രൗസ് ചെയ്യാം; ഈ ഭാഗം പൂർത്തിയാക്കിയ ശേഷം ഒരു പുതിയ ഡേറ്റാസെറ്റ് ലോഡ് ചെയ്ത് പ്രോസസ്സ് ചെയ്യാൻ ശ്രമിക്കണമെന്ന് ഞങ്ങൾ ശുപാർശ ചെയ്യുന്നു (പൊതുവായ ഡോക്യുമെന്റേഷൻ [ഇവിടെ](https://huggingface.co/docs/datasets/loading) കാണുക). എന്നാൽ ഇപ്പോൾ, MRPC ഡേറ്റാസെറ്റിൽ ശ്രദ്ധ കേന്ദ്രീകരിക്കാം! [GLUE ബെഞ്ച്‌മാർക്ക്](https://gluebenchmark.com/) രൂപപ്പെടുത്തുന്ന 10 ഡേറ്റാസെറ്റുകളിൽ ഒന്നാണിത്; 10 വ്യത്യസ്ത ടെക്‌സ്‌റ്റ് ക്ലാസിഫിക്കേഷൻ ടാസ്‌ക്കുകളിൽ ML മോഡലുകളുടെ പ്രകടനം അളക്കാൻ ഉപയോഗിക്കുന്ന ഒരു അക്കാദമിക് ബെഞ്ച്‌മാർക്കാണ് GLUE. + +Hub-ലുള്ള ഒരു ഡേറ്റാസെറ്റ് ഡൗൺലോഡ് ചെയ്ത് കാഷ് ചെയ്യാൻ 🤗 Datasets ലൈബ്രറി വളരെ ലളിതമായ ഒരു കമാൻഡ് നൽകുന്നു. MRPC ഡേറ്റാസെറ്റ് നമുക്ക് ഇങ്ങനെ ഡൗൺലോഡ് ചെയ്യാം: + +> [!TIP] +> 💡 **അധിക വിഭവങ്ങൾ**: കൂടുതൽ ഡേറ്റാസെറ്റ് ലോഡിംഗ് രീതികൾക്കും ഉദാഹരണങ്ങൾക്കും, [🤗 Datasets ഡോക്യുമെന്റേഷൻ](https://huggingface.co/docs/datasets/) പരിശോധിക്കുക. + +```py +from datasets import load_dataset + +raw_datasets = load_dataset("glue", "mrpc") +raw_datasets +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['sentence1', 'sentence2', 'label', 'idx'], + num_rows: 3668 + }) + validation: Dataset({ + features: ['sentence1', 'sentence2', 'label', 'idx'], + num_rows: 408 + }) + test: Dataset({ + features: ['sentence1', 'sentence2', 'label', 'idx'], + num_rows: 1725 + }) +}) +``` + +നിങ്ങൾക്ക് കാണാൻ കഴിയുന്നതുപോലെ, ട്രെയിനിംഗ് സെറ്റ്, വാലിഡേഷൻ സെറ്റ്, ടെസ്‌റ്റ് സെറ്റ് എന്നിവ അടങ്ങിയ ഒരു `DatasetDict` ഒബ്‌ജക്റ്റാണ് നമുക്ക് ലഭിക്കുന്നത്. ഇവയിൽ ഓരോന്നിലും പല കോളങ്ങളും (`sentence1`, `sentence2`, `label`, `idx`) വ്യത്യസ്ത എണ്ണം വരികളും ഉണ്ട്; വരികളുടെ എണ്ണം ഓരോ സെറ്റിലെയും ഘടകങ്ങളുടെ എണ്ണമാണ് (അതായത്, ട്രെയിനിംഗ് സെറ്റിൽ 3,668 വാക്യജോഡികളും, വാലിഡേഷൻ സെറ്റിൽ 408-ഉം, ടെസ്‌റ്റ് സെറ്റിൽ 1,725-ഉം ഉണ്ട്). + +> [!TIP] +> ഈ കമാൻഡ് ഡേറ്റാസെറ്റ് ഡൗൺലോഡ് ചെയ്ത് കാഷ് ചെയ്യുന്നു; ഡിഫോൾട്ടായി *~/.cache/huggingface/datasets*-ൽ. `HF_HOME` എൻവയോൺമെന്റ് വേരിയബിൾ സെറ്റ് ചെയ്ത് നിങ്ങളുടെ കാഷ് ഫോൾഡർ ഇഷ്ടാനുസൃതമാക്കാം എന്ന് അധ്യായം 2-ൽ നിന്ന് ഓർക്കുക. + +ഒരു ഡിക്‌ഷണറിയിലേതുപോലെ ഇൻഡെക്‌സിംഗ് ഉപയോഗിച്ച്, നമ്മുടെ `raw_datasets` ഒബ്‌ജക്റ്റിലെ ഓരോ വാക്യജോഡിയും നമുക്ക് ആക്‌സസ് ചെയ്യാം: + +```py +raw_train_dataset = raw_datasets["train"] +raw_train_dataset[0] +``` + +```python out +{'idx': 0, + 'label': 1, + 'sentence1': 'Amrozi accused his brother , whom he called " the witness " , of deliberately distorting his evidence .', + 'sentence2': 'Referring to him as only " the witness " , Amrozi accused his brother of deliberately distorting his evidence .'} +``` + +ലേബലുകൾ ഇതിനകം തന്നെ ഇന്റിജറുകളാണ് (integers) എന്ന് നമുക്ക് കാണാം, അതിനാൽ അവിടെ ഒരു പ്രീപ്രോസസ്സിംഗും ചെയ്യേണ്ടതില്ല. ഏത് ഇന്റിജർ ഏത് ലേബലിനെ സൂചിപ്പിക്കുന്നു എന്നറിയാൻ, നമ്മുടെ `raw_train_dataset`-ന്റെ `features` പരിശോധിക്കാം. ഇത് ഓരോ കോളത്തിന്റെയും ടൈപ്പ് നമുക്ക് പറഞ്ഞുതരും: + +```py +raw_train_dataset.features +``` + +```python out +{'sentence1': Value(dtype='string', id=None), + 'sentence2': Value(dtype='string', id=None), + 'label': ClassLabel(num_classes=2, names=['not_equivalent', 'equivalent'], names_file=None, id=None), + 'idx': Value(dtype='int32', id=None)} +``` + +അകമേ, `label` എന്നത് `ClassLabel` ടൈപ്പിലുള്ളതാണ്; ഇന്റിജറുകളെ ലേബൽ പേരുകളുമായി ബന്ധിപ്പിക്കുന്ന മാപ്പിംഗ് *names* ഫോൾഡറിൽ സൂക്ഷിച്ചിരിക്കുന്നു. `0` എന്നത് `not_equivalent`-നെയും `1` എന്നത് `equivalent`-നെയും സൂചിപ്പിക്കുന്നു. + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** ട്രെയിനിംഗ് സെറ്റിന്റെ ഘടകം 15-ഉം വാലിഡേഷൻ സെറ്റിന്റെ ഘടകം 87-ഉം നോക്കുക. അവയുടെ ലേബലുകൾ എന്തൊക്കെയാണ്? + +### ഒരു ഡേറ്റാസെറ്റ് പ്രീപ്രോസസ്സ് ചെയ്യുന്നു[[preprocessing-a-dataset]] + + + +ഡേറ്റാസെറ്റ് പ്രീപ്രോസസ്സ് ചെയ്യാൻ, ടെക്‌സ്‌റ്റിനെ മോഡലിന് മനസ്സിലാക്കാൻ കഴിയുന്ന സംഖ്യകളാക്കി മാറ്റേണ്ടതുണ്ട്. [മുൻ അധ്യായത്തിൽ](/course/chapter2) നിങ്ങൾ കണ്ടതുപോലെ, ഇത് ഒരു ടോക്കണൈസർ ഉപയോഗിച്ചാണ് ചെയ്യുന്നത്. ടോക്കണൈസറിന് ഒരു വാക്യമോ വാക്യങ്ങളുടെ ഒരു ലിസ്‌റ്റോ നൽകാം, അതിനാൽ ഓരോ ജോഡിയിലെയും എല്ലാ ആദ്യ വാക്യങ്ങളും എല്ലാ രണ്ടാം വാക്യങ്ങളും നമുക്ക് നേരിട്ട് ഇങ്ങനെ ടോക്കണൈസ് ചെയ്യാം: + +```py +from transformers import AutoTokenizer + +checkpoint = "bert-base-uncased" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +tokenized_sentences_1 = tokenizer(raw_datasets["train"]["sentence1"]) +tokenized_sentences_2 = tokenizer(raw_datasets["train"]["sentence2"]) +``` + +> [!TIP] +> 💡 **ആഴത്തിൽ അറിയാൻ**: കൂടുതൽ വിപുലമായ ടോക്കണൈസേഷൻ ടെക്‌നിക്കുകൾക്കും വ്യത്യസ്ത ടോക്കണൈസറുകൾ എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് മനസ്സിലാക്കാനും, [🤗 Tokenizers ഡോക്യുമെന്റേഷനും](https://huggingface.co/docs/transformers/main/en/tokenizer_summary) [കുക്ക്‌ബുക്കിലെ ടോക്കണൈസേഷൻ ഗൈഡും](https://huggingface.co/learn/cookbook/en/advanced_rag#tokenization-strategies) പരിശോധിക്കുക. + +എന്നിരുന്നാലും, രണ്ട് സീക്വൻസുകൾ വെറുതെ മോഡലിന് നൽകി, ആ രണ്ട് വാക്യങ്ങൾ പാരാഫ്രേസുകളാണോ അല്ലയോ എന്ന പ്രവചനം നേടാൻ കഴിയില്ല. രണ്ട് സീക്വൻസുകളെയും ഒരു ജോഡിയായി കൈകാര്യം ചെയ്ത്, അനുയോജ്യമായ പ്രീപ്രോസസ്സിംഗ് പ്രയോഗിക്കേണ്ടതുണ്ട്. ഭാഗ്യവശാൽ, ടോക്കണൈസറിന് ഒരു ജോഡി സീക്വൻസുകൾ സ്വീകരിച്ച്, നമ്മുടെ BERT മോഡൽ പ്രതീക്ഷിക്കുന്ന രീതിയിൽ അത് തയ്യാറാക്കാനും കഴിയും: + +```py +inputs = tokenizer("This is the first sentence.", "This is the second one.") +inputs +``` + +```python out +{ + 'input_ids': [101, 2023, 2003, 1996, 2034, 6251, 1012, 102, 2023, 2003, 1996, 2117, 2028, 1012, 102], + 'token_type_ids': [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1], + 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] +} +``` + +`input_ids`, `attention_mask` എന്നീ കീകളെക്കുറിച്ച് [അധ്യായം 2](/course/chapter2)-ൽ നമ്മൾ ചർച്ച ചെയ്തു, എന്നാൽ `token_type_ids`-നെക്കുറിച്ച് പറയുന്നത് നമ്മൾ മാറ്റിവെച്ചിരുന്നു. ഈ ഉദാഹരണത്തിൽ, ഇൻപുട്ടിന്റെ ഏത് ഭാഗം ആദ്യ വാക്യമാണെന്നും ഏത് ഭാഗം രണ്ടാം വാക്യമാണെന്നും മോഡലിനോട് പറയുന്നത് ഇതാണ്. + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** ട്രെയിനിംഗ് സെറ്റിന്റെ ഘടകം 15 എടുത്ത്, അതിലെ രണ്ട് വാക്യങ്ങളും വെവ്വേറെയായും ഒരു ജോഡിയായും ടോക്കണൈസ് ചെയ്യുക. രണ്ട് ഫലങ്ങൾക്കിടയിലുള്ള വ്യത്യാസം എന്താണ്? + +`input_ids`-നുള്ളിലെ ID-കൾ വീണ്ടും വാക്കുകളിലേക്ക് ഡീകോഡ് ചെയ്താൽ: + +```py +tokenizer.convert_ids_to_tokens(inputs["input_ids"]) +``` + +നമുക്ക് ലഭിക്കുന്നത്: + +```python out +['[CLS]', 'this', 'is', 'the', 'first', 'sentence', '.', '[SEP]', 'this', 'is', 'the', 'second', 'one', '.', '[SEP]'] +``` + +അതായത്, രണ്ട് വാക്യങ്ങൾ ഉള്ളപ്പോൾ ഇൻപുട്ടുകൾ `[CLS] sentence1 [SEP] sentence2 [SEP]` എന്ന രൂപത്തിലായിരിക്കണം എന്നാണ് മോഡൽ പ്രതീക്ഷിക്കുന്നത് എന്ന് നമ്മൾ കാണുന്നു. ഇതിനെ `token_type_ids`-മായി ചേർത്തുവെച്ചാൽ നമുക്ക് ലഭിക്കുന്നത്: + +```python out +['[CLS]', 'this', 'is', 'the', 'first', 'sentence', '.', '[SEP]', 'this', 'is', 'the', 'second', 'one', '.', '[SEP]'] +[ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1] +``` + +നിങ്ങൾക്ക് കാണാൻ കഴിയുന്നതുപോലെ, ഇൻപുട്ടിൽ `[CLS] sentence1 [SEP]`-ന് അനുയോജ്യമായ ഭാഗങ്ങൾക്കെല്ലാം ടോക്കൺ ടൈപ്പ് ID `0` ആണ്, അതേസമയം `sentence2 [SEP]`-ന് അനുയോജ്യമായ മറ്റ് ഭാഗങ്ങൾക്കെല്ലാം ടോക്കൺ ടൈപ്പ് ID `1` ആണ്. + +മറ്റൊരു ചെക്ക്‌പോയിന്റ് തിരഞ്ഞെടുത്താൽ, നിങ്ങളുടെ ടോക്കണൈസ് ചെയ്ത ഇൻപുട്ടുകളിൽ `token_type_ids` ഉണ്ടാകണമെന്നില്ല എന്നത് ശ്രദ്ധിക്കുക (ഉദാഹരണത്തിന്, ഒരു DistilBERT മോഡൽ ഉപയോഗിച്ചാൽ അവ തിരികെ ലഭിക്കില്ല). മോഡൽ അവയെ പ്രീട്രെയിനിംഗ് സമയത്ത് കണ്ടിട്ടുള്ളതിനാൽ അവ എന്തുചെയ്യണമെന്ന് മോഡലിന് അറിയാമെങ്കിൽ മാത്രമേ അവ തിരികെ ലഭിക്കൂ. + +ഇവിടെ, BERT ടോക്കൺ ടൈപ്പ് ID-കളോടെയാണ് പ്രീട്രെയിൻ ചെയ്തിരിക്കുന്നത്; [അധ്യായം 1](/course/chapter1)-ൽ നമ്മൾ സംസാരിച്ച മാസ്‌ക്ഡ് ലാംഗ്വേജ് മോഡലിംഗ് ലക്ഷ്യത്തിന് പുറമെ, _next sentence prediction_ (അടുത്ത വാക്യ പ്രവചനം) എന്ന ഒരു അധിക ലക്ഷ്യവും ഇതിനുണ്ട്. വാക്യജോഡികൾക്കിടയിലുള്ള ബന്ധം മോഡൽ ചെയ്യുക എന്നതാണ് ഈ ടാസ്‌ക്കിന്റെ ലക്ഷ്യം. + +Next sentence prediction-ൽ, മോഡലിന് (റാൻഡമായി മാസ്‌ക് ചെയ്ത ടോക്കണുകളുള്ള) വാക്യജോഡികൾ നൽകുകയും, രണ്ടാം വാക്യം ആദ്യത്തേതിന് തൊട്ടുപിന്നാലെ വരുന്നതാണോ എന്ന് പ്രവചിക്കാൻ ആവശ്യപ്പെടുകയും ചെയ്യുന്നു. ടാസ്‌ക്ക് വളരെ എളുപ്പമാകാതിരിക്കാൻ, പകുതി തവണ ആ വാക്യങ്ങൾ അവ എടുത്ത യഥാർത്ഥ ഡോക്യുമെന്റിൽ ഒന്നിന് പിന്നാലെ ഒന്നായി വരുന്നവയാണ്; മറ്റേ പകുതി തവണ, രണ്ട് വാക്യങ്ങളും രണ്ട് വ്യത്യസ്ത ഡോക്യുമെന്റുകളിൽ നിന്നുള്ളവയാണ്. + +പൊതുവേ, നിങ്ങളുടെ ടോക്കണൈസ് ചെയ്ത ഇൻപുട്ടുകളിൽ `token_type_ids` ഉണ്ടോ ഇല്ലയോ എന്നതിനെക്കുറിച്ച് നിങ്ങൾ വിഷമിക്കേണ്ടതില്ല: ടോക്കണൈസറിനും മോഡലിനും ഒരേ ചെക്ക്‌പോയിന്റ് ഉപയോഗിക്കുന്നിടത്തോളം, തന്റെ മോഡലിന് എന്ത് നൽകണമെന്ന് ടോക്കണൈസറിന് അറിയാവുന്നതിനാൽ എല്ലാം ശരിയായിരിക്കും. + +നമ്മുടെ ടോക്കണൈസർ ഒരു വാക്യജോഡിയെ എങ്ങനെ കൈകാര്യം ചെയ്യുന്നു എന്ന് കണ്ടുകഴിഞ്ഞ സ്ഥിതിക്ക്, നമ്മുടെ മുഴുവൻ ഡേറ്റാസെറ്റും ടോക്കണൈസ് ചെയ്യാൻ ഇത് ഉപയോഗിക്കാം: [മുൻ അധ്യായത്തിലേതുപോലെ](/course/chapter2), ആദ്യ വാക്യങ്ങളുടെ ലിസ്‌റ്റും പിന്നെ രണ്ടാം വാക്യങ്ങളുടെ ലിസ്‌റ്റും നൽകിക്കൊണ്ട് ടോക്കണൈസറിന് വാക്യജോഡികളുടെ ഒരു ലിസ്‌റ്റ് നൽകാം. [അധ്യായം 2](/course/chapter2)-ൽ നമ്മൾ കണ്ട പാഡിംഗ്, ട്രങ്കേഷൻ ഓപ്‌ഷനുകളുമായും ഇത് പൊരുത്തപ്പെടുന്നു. അതിനാൽ, ട്രെയിനിംഗ് ഡേറ്റാസെറ്റ് പ്രീപ്രോസസ്സ് ചെയ്യാനുള്ള ഒരു വഴി ഇതാണ്: + +```py +tokenized_dataset = tokenizer( + raw_datasets["train"]["sentence1"], + raw_datasets["train"]["sentence2"], + padding=True, + truncation=True, +) +``` + +ഇത് നന്നായി പ്രവർത്തിക്കും, എന്നാൽ ഒരു ഡിക്‌ഷണറി (നമ്മുടെ കീകളായ `input_ids`, `attention_mask`, `token_type_ids` എന്നിവയും, ലിസ്‌റ്റുകളുടെ ലിസ്‌റ്റുകളായ മൂല്യങ്ങളും ഉള്ളത്) തിരികെ നൽകുന്നു എന്ന പോരായ്മ ഇതിനുണ്ട്. കൂടാതെ, ടോക്കണൈസേഷൻ സമയത്ത് നിങ്ങളുടെ മുഴുവൻ ഡേറ്റാസെറ്റും സൂക്ഷിക്കാൻ മതിയായ RAM ഉണ്ടെങ്കിൽ മാത്രമേ ഇത് പ്രവർത്തിക്കൂ (അതേസമയം 🤗 Datasets ലൈബ്രറിയിലെ ഡേറ്റാസെറ്റുകൾ ഡിസ്‌കിൽ സൂക്ഷിച്ചിരിക്കുന്ന [Apache Arrow](https://arrow.apache.org/) ഫയലുകളാണ്, അതിനാൽ നിങ്ങൾ ആവശ്യപ്പെടുന്ന സാമ്പിളുകൾ മാത്രമേ മെമ്മറിയിൽ ലോഡ് ചെയ്യപ്പെടുന്നുള്ളൂ). + +ഡേറ്റയെ ഒരു ഡേറ്റാസെറ്റായി തന്നെ നിലനിർത്താൻ, നമ്മൾ [`Dataset.map()`](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map) മെത്തേഡ് ഉപയോഗിക്കും. ടോക്കണൈസേഷന് പുറമെ കൂടുതൽ പ്രീപ്രോസസ്സിംഗ് ആവശ്യമായി വന്നാൽ, ഇത് നമുക്ക് കുറച്ച് അധിക വഴക്കവും (flexibility) നൽകുന്നു. ഡേറ്റാസെറ്റിലെ ഓരോ ഘടകത്തിലും ഒരു ഫംഗ്‌ഷൻ പ്രയോഗിച്ചാണ് `map()` മെത്തേഡ് പ്രവർത്തിക്കുന്നത്, അതിനാൽ നമ്മുടെ ഇൻപുട്ടുകൾ ടോക്കണൈസ് ചെയ്യുന്ന ഒരു ഫംഗ്‌ഷൻ നിർവചിക്കാം: + +```py +def tokenize_function(example): + return tokenizer(example["sentence1"], example["sentence2"], truncation=True) +``` + +ഈ ഫംഗ്‌ഷൻ ഒരു ഡിക്‌ഷണറി (നമ്മുടെ ഡേറ്റാസെറ്റിലെ ഐറ്റങ്ങൾ പോലെ) സ്വീകരിച്ച്, `input_ids`, `attention_mask`, `token_type_ids` എന്നീ കീകളുള്ള ഒരു പുതിയ ഡിക്‌ഷണറി തിരികെ നൽകുന്നു. മുമ്പ് കണ്ടതുപോലെ `tokenizer` വാക്യജോഡികളുടെ ലിസ്‌റ്റുകളിൽ പ്രവർത്തിക്കുന്നതിനാൽ, `example` ഡിക്‌ഷണറിയിൽ ഒന്നിലധികം സാമ്പിളുകൾ (ഓരോ കീയും വാക്യങ്ങളുടെ ഒരു ലിസ്‌റ്റായി) ഉണ്ടെങ്കിലും ഇത് പ്രവർത്തിക്കും എന്നത് ശ്രദ്ധിക്കുക. `map()` വിളിക്കുമ്പോൾ `batched=True` എന്ന ഓപ്‌ഷൻ ഉപയോഗിക്കാൻ ഇത് നമ്മെ അനുവദിക്കും, അത് ടോക്കണൈസേഷൻ വളരെയധികം വേഗത്തിലാക്കും. [🤗 Tokenizers](https://github.com/huggingface/tokenizers) ലൈബ്രറിയിൽ നിന്നുള്ള, Rust-ൽ എഴുതിയ ഒരു ടോക്കണൈസറാണ് `tokenizer`-ന് പിന്നിൽ പ്രവർത്തിക്കുന്നത്. ഈ ടോക്കണൈസർ വളരെ വേഗതയുള്ളതാകാം, എന്നാൽ ഒരേസമയം ധാരാളം ഇൻപുട്ടുകൾ നൽകിയാൽ മാത്രം. + +നമ്മുടെ ടോക്കണൈസേഷൻ ഫംഗ്‌ഷനിൽ `padding` ആർഗ്യുമെന്റ് ഇപ്പോൾ ഒഴിവാക്കിയിരിക്കുന്നു എന്നത് ശ്രദ്ധിക്കുക. എല്ലാ സാമ്പിളുകളെയും പരമാവധി നീളത്തിലേക്ക് പാഡ് ചെയ്യുന്നത് കാര്യക്ഷമമല്ല എന്നതാണ് ഇതിന് കാരണം: ഒരു ബാച്ച് നിർമ്മിക്കുമ്പോൾ സാമ്പിളുകൾ പാഡ് ചെയ്യുന്നതാണ് നല്ലത്, കാരണം അപ്പോൾ മുഴുവൻ ഡേറ്റാസെറ്റിലെയും പരമാവധി നീളത്തിലേക്കല്ല, ആ ബാച്ചിലെ പരമാവധി നീളത്തിലേക്ക് മാത്രം പാഡ് ചെയ്താൽ മതി. ഇൻപുട്ടുകളുടെ നീളം വളരെയധികം വ്യത്യാസപ്പെടുമ്പോൾ ഇത് ധാരാളം സമയവും പ്രോസസ്സിംഗ് ശേഷിയും ലാഭിക്കും! + +> [!TIP] +> 📚 **പെർഫോമൻസ് ടിപ്പുകൾ**: കാര്യക്ഷമമായ ഡേറ്റാ പ്രോസസ്സിംഗ് ടെക്‌നിക്കുകളെക്കുറിച്ച് കൂടുതൽ അറിയാൻ [🤗 Datasets പെർഫോമൻസ് ഗൈഡ്](https://huggingface.co/docs/datasets/about_arrow) കാണുക. + +നമ്മുടെ എല്ലാ ഡേറ്റാസെറ്റുകളിലും ഒറ്റയടിക്ക് ടോക്കണൈസേഷൻ ഫംഗ്‌ഷൻ എങ്ങനെ പ്രയോഗിക്കാം എന്ന് ഇതാ. `map` വിളിക്കുമ്പോൾ നമ്മൾ `batched=True` ഉപയോഗിക്കുന്നു, അതിനാൽ ഫംഗ്‌ഷൻ ഓരോ ഘടകത്തിലും വെവ്വേറെയല്ല, നമ്മുടെ ഡേറ്റാസെറ്റിലെ ഒന്നിലധികം ഘടകങ്ങളിൽ ഒരേസമയം പ്രയോഗിക്കപ്പെടുന്നു. ഇത് കൂടുതൽ വേഗത്തിലുള്ള പ്രീപ്രോസസ്സിംഗ് സാധ്യമാക്കുന്നു. + +```py +tokenized_datasets = raw_datasets.map(tokenize_function, batched=True) +tokenized_datasets +``` + +പ്രീപ്രോസസ്സിംഗ് ഫംഗ്‌ഷൻ തിരികെ നൽകുന്ന ഡിക്‌ഷണറിയിലെ ഓരോ കീയ്ക്കും ഒന്ന് വീതം, ഡേറ്റാസെറ്റുകളിലേക്ക് പുതിയ ഫീൽഡുകൾ ചേർത്താണ് 🤗 Datasets ലൈബ്രറി ഈ പ്രോസസ്സിംഗ് പ്രയോഗിക്കുന്നത്: + +```python out +DatasetDict({ + train: Dataset({ + features: ['attention_mask', 'idx', 'input_ids', 'label', 'sentence1', 'sentence2', 'token_type_ids'], + num_rows: 3668 + }) + validation: Dataset({ + features: ['attention_mask', 'idx', 'input_ids', 'label', 'sentence1', 'sentence2', 'token_type_ids'], + num_rows: 408 + }) + test: Dataset({ + features: ['attention_mask', 'idx', 'input_ids', 'label', 'sentence1', 'sentence2', 'token_type_ids'], + num_rows: 1725 + }) +}) +``` + +`num_proc` എന്ന ആർഗ്യുമെന്റ് നൽകിക്കൊണ്ട്, `map()` ഉപയോഗിച്ച് പ്രീപ്രോസസ്സിംഗ് ഫംഗ്‌ഷൻ പ്രയോഗിക്കുമ്പോൾ മൾട്ടിപ്രോസസ്സിംഗ് പോലും നിങ്ങൾക്ക് ഉപയോഗിക്കാം. നമ്മുടെ സാമ്പിളുകൾ വേഗത്തിൽ ടോക്കണൈസ് ചെയ്യാൻ 🤗 Tokenizers ലൈബ്രറി ഇതിനകം തന്നെ ഒന്നിലധികം ത്രെഡുകൾ ഉപയോഗിക്കുന്നതിനാൽ ഇവിടെ നമ്മൾ അത് ചെയ്തില്ല; എന്നാൽ ഈ ലൈബ്രറിയുടെ പിന്തുണയുള്ള ഒരു ഫാസ്‌റ്റ് ടോക്കണൈസർ അല്ല നിങ്ങൾ ഉപയോഗിക്കുന്നതെങ്കിൽ, ഇത് നിങ്ങളുടെ പ്രീപ്രോസസ്സിംഗ് വേഗത്തിലാക്കാം. + +നമ്മുടെ `tokenize_function` `input_ids`, `attention_mask`, `token_type_ids` എന്നീ കീകളുള്ള ഒരു ഡിക്‌ഷണറി തിരികെ നൽകുന്നു, അതിനാൽ ആ മൂന്ന് ഫീൽഡുകളും നമ്മുടെ ഡേറ്റാസെറ്റിന്റെ എല്ലാ സ്‌പ്ലിറ്റുകളിലേക്കും ചേർക്കപ്പെടുന്നു. `map()` പ്രയോഗിച്ച ഡേറ്റാസെറ്റിൽ ഇതിനകമുള്ള ഒരു കീയ്ക്ക് നമ്മുടെ പ്രീപ്രോസസ്സിംഗ് ഫംഗ്‌ഷൻ ഒരു പുതിയ മൂല്യം തിരികെ നൽകിയിരുന്നെങ്കിൽ, നിലവിലുള്ള ഫീൽഡുകൾ മാറ്റാനും നമുക്ക് കഴിയുമായിരുന്നു എന്നത് ശ്രദ്ധിക്കുക. + +ഘടകങ്ങളെ ഒരുമിച്ച് ബാച്ച് ചെയ്യുമ്പോൾ എല്ലാ ഉദാഹരണങ്ങളെയും ഏറ്റവും നീളമുള്ള ഘടകത്തിന്റെ നീളത്തിലേക്ക് പാഡ് ചെയ്യുക എന്നതാണ് നമുക്ക് ചെയ്യാൻ ബാക്കിയുള്ള അവസാന കാര്യം — ഈ ടെക്‌നിക്കിനെ നമ്മൾ *ഡൈനാമിക് പാഡിംഗ്* (dynamic padding) എന്ന് വിളിക്കുന്നു. + +##### ഡൈനാമിക് പാഡിംഗ്[[dynamic-padding]] + + + +ഒരു ബാച്ചിനുള്ളിൽ സാമ്പിളുകളെ ഒരുമിച്ച് ചേർക്കുന്നതിന് ഉത്തരവാദിയായ ഫംഗ്‌ഷനെ *കൊളേറ്റ് ഫംഗ്‌ഷൻ* (collate function) എന്ന് വിളിക്കുന്നു. ഒരു `DataLoader` നിർമ്മിക്കുമ്പോൾ നിങ്ങൾക്ക് നൽകാവുന്ന ഒരു ആർഗ്യുമെന്റാണിത്; ഡിഫോൾട്ടായി ഇത്, നിങ്ങളുടെ സാമ്പിളുകളെ PyTorch ടെൻസറുകളാക്കി മാറ്റി അവയെ കൂട്ടിച്ചേർക്കുക മാത്രം ചെയ്യുന്ന ഒരു ഫംഗ്‌ഷനാണ് (നിങ്ങളുടെ ഘടകങ്ങൾ ലിസ്‌റ്റുകളോ ട്യൂപ്പിളുകളോ ഡിക്‌ഷണറികളോ ആണെങ്കിൽ റിക്കർസീവായി). നമ്മുടെ ഇൻപുട്ടുകൾ എല്ലാം ഒരേ വലുപ്പത്തിലാകില്ല എന്നതിനാൽ നമ്മുടെ കാര്യത്തിൽ ഇത് സാധ്യമാകില്ല. ഓരോ ബാച്ചിലും ആവശ്യമുള്ളത്ര മാത്രം പാഡിംഗ് പ്രയോഗിക്കാനും, ധാരാളം പാഡിംഗുള്ള അമിതനീളമുള്ള ഇൻപുട്ടുകൾ ഒഴിവാക്കാനുമാണ് നമ്മൾ പാഡിംഗ് മനഃപൂർവ്വം മാറ്റിവെച്ചത്. ഇത് ട്രെയിനിംഗ് നല്ലതുപോലെ വേഗത്തിലാക്കും, എന്നാൽ ഒരു TPU-വിലാണ് ട്രെയിൻ ചെയ്യുന്നതെങ്കിൽ ഇത് പ്രശ്‌നങ്ങൾ ഉണ്ടാക്കാം എന്നത് ശ്രദ്ധിക്കുക — അധിക പാഡിംഗ് ആവശ്യമായി വന്നാലും, TPU-കൾ നിശ്ചിത ഷെയ്‌പ്പുകളാണ് ഇഷ്ടപ്പെടുന്നത്. + +> [!TIP] +> 🚀 **ഒപ്‌റ്റിമൈസേഷൻ ഗൈഡ്**: പാഡിംഗ് തന്ത്രങ്ങളും TPU സംബന്ധമായ പരിഗണനകളും ഉൾപ്പെടെ, ട്രെയിനിംഗ് പെർഫോമൻസ് ഒപ്‌റ്റിമൈസ് ചെയ്യുന്നതിനെക്കുറിച്ചുള്ള കൂടുതൽ വിവരങ്ങൾക്ക് [🤗 Transformers പെർഫോമൻസ് ഡോക്യുമെന്റേഷൻ](https://huggingface.co/docs/transformers/main/en/performance) കാണുക. + +ഇത് പ്രായോഗികമായി ചെയ്യാൻ, ഒരുമിച്ച് ബാച്ച് ചെയ്യേണ്ട ഡേറ്റാസെറ്റ് ഐറ്റങ്ങൾക്ക് ശരിയായ അളവിൽ പാഡിംഗ് പ്രയോഗിക്കുന്ന ഒരു കൊളേറ്റ് ഫംഗ്‌ഷൻ നമ്മൾ നിർവചിക്കേണ്ടതുണ്ട്. ഭാഗ്യവശാൽ, `DataCollatorWithPadding` വഴി 🤗 Transformers ലൈബ്രറി അത്തരമൊരു ഫംഗ്‌ഷൻ നമുക്ക് നൽകുന്നു. ഇത് ഇൻസ്‌റ്റാൻഷിയേറ്റ് ചെയ്യുമ്പോൾ ഒരു ടോക്കണൈസർ സ്വീകരിക്കുന്നു (ഏത് പാഡിംഗ് ടോക്കൺ ഉപയോഗിക്കണമെന്നും, പാഡിംഗ് ഇൻപുട്ടുകളുടെ ഇടതുവശത്താണോ വലതുവശത്താണോ മോഡൽ പ്രതീക്ഷിക്കുന്നത് എന്നും അറിയാൻ), കൂടാതെ നിങ്ങൾക്ക് ആവശ്യമായതെല്ലാം ഇത് ചെയ്യും: + +```py +from transformers import DataCollatorWithPadding + +data_collator = DataCollatorWithPadding(tokenizer=tokenizer) +``` + +ഈ പുതിയ കളിപ്പാട്ടം പരീക്ഷിക്കാൻ, ഒരുമിച്ച് ബാച്ച് ചെയ്യാൻ ആഗ്രഹിക്കുന്ന കുറച്ച് സാമ്പിളുകൾ നമ്മുടെ ട്രെയിനിംഗ് സെറ്റിൽ നിന്ന് എടുക്കാം. ഇവിടെ, `idx`, `sentence1`, `sentence2` എന്നീ കോളങ്ങൾ നമ്മൾ നീക്കം ചെയ്യുന്നു, കാരണം അവ ആവശ്യമില്ല, മാത്രമല്ല അവയിൽ സ്ട്രിംഗുകളാണുള്ളത് (സ്ട്രിംഗുകൾ ഉപയോഗിച്ച് ടെൻസറുകൾ ഉണ്ടാക്കാൻ കഴിയില്ല); തുടർന്ന് ബാച്ചിലെ ഓരോ എൻട്രിയുടെയും നീളം നോക്കാം: + +```py +samples = tokenized_datasets["train"][:8] +samples = {k: v for k, v in samples.items() if k not in ["idx", "sentence1", "sentence2"]} +[len(x) for x in samples["input_ids"]] +``` + +```python out +[50, 59, 47, 67, 59, 50, 62, 32] +``` + +അതിശയമില്ല, 32 മുതൽ 67 വരെ വ്യത്യസ്ത നീളമുള്ള സാമ്പിളുകളാണ് നമുക്ക് ലഭിക്കുന്നത്. ഡൈനാമിക് പാഡിംഗ് എന്നാൽ, ഈ ബാച്ചിലെ എല്ലാ സാമ്പിളുകളെയും ബാച്ചിനുള്ളിലെ പരമാവധി നീളമായ 67-ലേക്ക് പാഡ് ചെയ്യണം എന്നാണ്. ഡൈനാമിക് പാഡിംഗ് ഇല്ലെങ്കിൽ, എല്ലാ സാമ്പിളുകളെയും മുഴുവൻ ഡേറ്റാസെറ്റിലെയും പരമാവധി നീളത്തിലേക്കോ, അല്ലെങ്കിൽ മോഡലിന് സ്വീകരിക്കാൻ കഴിയുന്ന പരമാവധി നീളത്തിലേക്കോ പാഡ് ചെയ്യേണ്ടി വരും. നമ്മുടെ `data_collator` ബാച്ചിനെ ശരിയായി ഡൈനാമിക്കായി പാഡ് ചെയ്യുന്നുണ്ടോ എന്ന് ഒന്നുകൂടി ഉറപ്പുവരുത്താം: + +```py +batch = data_collator(samples) +{k: v.shape for k, v in batch.items()} +``` + +```python out +{'attention_mask': torch.Size([8, 67]), + 'input_ids': torch.Size([8, 67]), + 'token_type_ids': torch.Size([8, 67]), + 'labels': torch.Size([8])} +``` + +കൊള്ളാം! അസംസ്‌കൃത ടെക്‌സ്‌റ്റിൽ നിന്ന് നമ്മുടെ മോഡലിന് കൈകാര്യം ചെയ്യാൻ കഴിയുന്ന ബാച്ചുകളിലേക്ക് നമ്മൾ എത്തിയ സ്ഥിതിക്ക്, ഇനി അതിനെ ഫൈൻ-ട്യൂൺ ചെയ്യാൻ നമ്മൾ തയ്യാറാണ്! + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** GLUE SST-2 ഡേറ്റാസെറ്റിൽ ഈ പ്രീപ്രോസസ്സിംഗ് ആവർത്തിക്കുക. ജോഡികൾക്ക് പകരം ഒറ്റ വാക്യങ്ങളാണ് അതിലുള്ളത് എന്നതിനാൽ ഇത് ചെറുതായി വ്യത്യസ്തമാണ്, എന്നാൽ നമ്മൾ ചെയ്ത ബാക്കിയെല്ലാം ഒരുപോലെ തന്നെയായിരിക്കണം. കൂടുതൽ കഠിനമായ ഒരു വെല്ലുവിളിക്ക്, GLUE ടാസ്‌ക്കുകളിൽ ഏതിലും പ്രവർത്തിക്കുന്ന ഒരു പ്രീപ്രോസസ്സിംഗ് ഫംഗ്‌ഷൻ എഴുതാൻ ശ്രമിക്കുക. +> +> 📖 **അധിക പരിശീലനം**: [🤗 Transformers ഉദാഹരണങ്ങളിൽ](https://huggingface.co/docs/transformers/main/en/notebooks) നിന്നുള്ള ഈ പ്രായോഗിക ഉദാഹരണങ്ങൾ പരിശോധിക്കുക. + +വളരെ നന്നായി! 🤗 Datasets ലൈബ്രറിയിലെ ഏറ്റവും പുതിയ മികച്ച രീതികൾ ഉപയോഗിച്ച് നമ്മുടെ ഡേറ്റ പ്രീപ്രോസസ്സ് ചെയ്തുകഴിഞ്ഞ സ്ഥിതിക്ക്, ആധുനിക Trainer API ഉപയോഗിച്ച് നമ്മുടെ മോഡൽ ട്രെയിൻ ചെയ്യുന്നതിലേക്ക് നീങ്ങാൻ നമ്മൾ തയ്യാറാണ്. Hugging Face ഇക്കോസിസ്റ്റത്തിൽ ലഭ്യമായ ഏറ്റവും പുതിയ സവിശേഷതകളും ഒപ്‌റ്റിമൈസേഷനുകളും ഉപയോഗിച്ച് നിങ്ങളുടെ മോഡൽ എങ്ങനെ ഫലപ്രദമായി ഫൈൻ-ട്യൂൺ ചെയ്യാം എന്ന് അടുത്ത ഭാഗം കാണിച്ചുതരും. + +## ഈ ഭാഗത്തിന്റെ ക്വിസ്[[section-quiz]] + +ഡേറ്റാ പ്രോസസ്സിംഗ് ആശയങ്ങളെക്കുറിച്ചുള്ള നിങ്ങളുടെ ധാരണ പരീക്ഷിക്കുക: + +### 1. `batched=True` ഉപയോഗിച്ച് `Dataset.map()` പ്രയോഗിക്കുന്നതിന്റെ പ്രധാന നേട്ടം എന്താണ്? + + + +### 2. ഡേറ്റാസെറ്റിലെ പരമാവധി നീളത്തിലേക്ക് എല്ലാ സീക്വൻസുകളെയും പാഡ് ചെയ്യുന്നതിന് പകരം ഡൈനാമിക് പാഡിംഗ് ഉപയോഗിക്കുന്നത് എന്തുകൊണ്ട്? + + + +### 3. BERT ടോക്കണൈസേഷനിൽ `token_type_ids` ഫീൽഡ് എന്തിനെ പ്രതിനിധീകരിക്കുന്നു? + + + +### 4. `load_dataset('glue', 'mrpc')` ഉപയോഗിച്ച് ഒരു ഡേറ്റാസെറ്റ് ലോഡ് ചെയ്യുമ്പോൾ, രണ്ടാമത്തെ ആർഗ്യുമെന്റ് എന്താണ് വ്യക്തമാക്കുന്നത്? + + + +### 5. ട്രെയിനിംഗിന് മുമ്പ് 'sentence1', 'sentence2' തുടങ്ങിയ കോളങ്ങൾ നീക്കം ചെയ്യുന്നതിന്റെ ഉദ്ദേശ്യം എന്താണ്? + + + +> [!TIP] +> 💡 **പ്രധാന പാഠങ്ങൾ:** +> - ഗണ്യമായി വേഗത്തിലുള്ള പ്രീപ്രോസസ്സിംഗിനായി `Dataset.map()`-നോടൊപ്പം `batched=True` ഉപയോഗിക്കുക +> - `DataCollatorWithPadding` ഉപയോഗിച്ചുള്ള ഡൈനാമിക് പാഡിംഗ്, നിശ്ചിത നീളത്തിലേക്കുള്ള പാഡിംഗിനെക്കാൾ കാര്യക്ഷമമാണ് +> - നിങ്ങളുടെ മോഡൽ പ്രതീക്ഷിക്കുന്നതിന് (സംഖ്യാ ടെൻസറുകൾ, ശരിയായ കോളം പേരുകൾ) അനുസൃതമായി എപ്പോഴും ഡേറ്റ പ്രീപ്രോസസ്സ് ചെയ്യുക +> - വലിയ തോതിൽ കാര്യക്ഷമമായ ഡേറ്റാ പ്രോസസ്സിംഗിനുള്ള ശക്തമായ ടൂളുകൾ 🤗 Datasets ലൈബ്രറി നൽകുന്നു diff --git a/chapters/ml/chapter3/3.mdx b/chapters/ml/chapter3/3.mdx new file mode 100644 index 000000000..d2a7e9ff5 --- /dev/null +++ b/chapters/ml/chapter3/3.mdx @@ -0,0 +1,372 @@ + + +# Trainer API ഉപയോഗിച്ച് ഒരു മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യുന്നു[[fine-tuning-a-model-with-the-trainer-api]] + + + + + +🤗 Transformers-ൽ ലഭ്യമായ ഏത് പ്രീട്രെയിൻഡ് മോഡലും, ആധുനികമായ മികച്ച രീതികൾ (best practices) പിന്തുടർന്ന്, നിങ്ങളുടെ ഡേറ്റാസെറ്റിൽ ഫൈൻ-ട്യൂൻ ചെയ്യാൻ സഹായിക്കുന്ന ഒരു `Trainer` ക്ലാസ് 🤗 Transformers നൽകുന്നു. കഴിഞ്ഞ ഭാഗത്തിലെ ഡേറ്റാ പ്രീപ്രോസസ്സിംഗ് ജോലികളെല്ലാം പൂർത്തിയാക്കിക്കഴിഞ്ഞാൽ, `Trainer` നിർവചിക്കാൻ ഇനി ഏതാനും ഘട്ടങ്ങൾ മാത്രമേ ബാക്കിയുള്ളൂ. `Trainer.train()` റൺ ചെയ്യാനുള്ള എൻവയോൺമെന്റ് തയ്യാറാക്കുന്നതായിരിക്കും ഒരുപക്ഷേ ഏറ്റവും ബുദ്ധിമുട്ടുള്ള ഭാഗം, കാരണം ഒരു CPU-വിൽ ഇത് വളരെ പതുക്കെയായിരിക്കും റൺ ചെയ്യുക. നിങ്ങൾക്ക് ഒരു GPU സെറ്റപ്പ് ചെയ്തിട്ടില്ലെങ്കിൽ, [Google Colab](https://colab.research.google.com/)-ൽ സൗജന്യ GPU-കളോ TPU-കളോ നിങ്ങൾക്ക് ഉപയോഗിക്കാം. + +> [!TIP] +> 📚 **ട്രെയിനിംഗ് റിസോഴ്‌സുകൾ**: ട്രെയിനിംഗിലേക്ക് കടക്കുന്നതിന് മുമ്പ്, സമഗ്രമായ [🤗 Transformers ട്രെയിനിംഗ് ഗൈഡ്](https://huggingface.co/docs/transformers/main/en/training) പരിചയപ്പെടുകയും [ഫൈൻ-ട്യൂണിംഗ് കുക്ക്‌ബുക്കിലെ](https://huggingface.co/learn/cookbook/en/fine_tuning_code_llm_on_single_gpu) പ്രായോഗിക ഉദാഹരണങ്ങൾ പരിശോധിക്കുകയും ചെയ്യുക. + +മുൻ ഭാഗത്തിലെ ഉദാഹരണങ്ങൾ നിങ്ങൾ ഇതിനകം റൺ ചെയ്തിട്ടുണ്ട് എന്ന അനുമാനത്തിലാണ് താഴെയുള്ള കോഡ് ഉദാഹരണങ്ങൾ. നിങ്ങൾക്ക് ആവശ്യമുള്ളവ ഓർമ്മിപ്പിക്കുന്ന ഒരു ചെറിയ സംഗ്രഹം ഇതാ: + +```py +from datasets import load_dataset +from transformers import AutoTokenizer, DataCollatorWithPadding + +raw_datasets = load_dataset("glue", "mrpc") +checkpoint = "bert-base-uncased" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) + + +def tokenize_function(example): + return tokenizer(example["sentence1"], example["sentence2"], truncation=True) + + +tokenized_datasets = raw_datasets.map(tokenize_function, batched=True) +data_collator = DataCollatorWithPadding(tokenizer=tokenizer) +``` + +### ട്രെയിനിംഗ്[[training]] + +നമ്മുടെ `Trainer` നിർവചിക്കുന്നതിന് മുമ്പുള്ള ആദ്യ ഘട്ടം, ട്രെയിനിംഗിനും ഇവാല്യുവേഷനും (evaluation) `Trainer` ഉപയോഗിക്കുന്ന എല്ലാ ഹൈപ്പർപാരാമീറ്ററുകളും ഉൾക്കൊള്ളുന്ന ഒരു `TrainingArguments` ക്ലാസ് നിർവചിക്കുകയാണ്. ട്രെയിൻ ചെയ്ത മോഡലും ഇടയ്ക്കിടെയുള്ള ചെക്ക്‌പോയിന്റുകളും സേവ് ചെയ്യേണ്ട ഡയറക്ടറി മാത്രമാണ് നിങ്ങൾ നിർബന്ധമായും നൽകേണ്ട ഒരേയൊരു ആർഗ്യുമെന്റ്. ബാക്കിയെല്ലാം ഡിഫോൾട്ടുകളായി വിടാം; ഒരു അടിസ്ഥാന ഫൈൻ-ട്യൂണിംഗിന് അവ നന്നായി പ്രവർത്തിക്കേണ്ടതാണ്. + +```py +from transformers import TrainingArguments + +training_args = TrainingArguments("test-trainer") +``` + +ട്രെയിനിംഗ് സമയത്ത് നിങ്ങളുടെ മോഡൽ Hub-ലേക്ക് സ്വയമേവ അപ്‌ലോഡ് ചെയ്യണമെങ്കിൽ, `TrainingArguments`-ൽ `push_to_hub=True` നൽകുക. ഇതേക്കുറിച്ച് [അധ്യായം 4](/course/chapter4/3)-ൽ നമ്മൾ കൂടുതൽ പഠിക്കും + +> [!TIP] +> 🚀 **അഡ്വാൻസ്ഡ് കോൺഫിഗറേഷൻ**: ലഭ്യമായ എല്ലാ ട്രെയിനിംഗ് ആർഗ്യുമെന്റുകളെയും ഒപ്‌റ്റിമൈസേഷൻ തന്ത്രങ്ങളെയും കുറിച്ചുള്ള വിശദമായ വിവരങ്ങൾക്ക്, [TrainingArguments ഡോക്യുമെന്റേഷനും](https://huggingface.co/docs/transformers/main/en/main_classes/trainer#transformers.TrainingArguments) [ട്രെയിനിംഗ് കോൺഫിഗറേഷൻ കുക്ക്‌ബുക്കും](https://huggingface.co/learn/cookbook/en/fine_tuning_code_llm_on_single_gpu) പരിശോധിക്കുക. + +രണ്ടാമത്തെ ഘട്ടം നമ്മുടെ മോഡൽ നിർവചിക്കുകയാണ്. [മുൻ അധ്യായത്തിലേതുപോലെ](/course/chapter2), രണ്ട് ലേബലുകളോടെ `AutoModelForSequenceClassification` ക്ലാസ് നമ്മൾ ഉപയോഗിക്കും: + +```py +from transformers import AutoModelForSequenceClassification + +model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) +``` + +[അധ്യായം 2](/course/chapter2)-ൽ നിന്ന് വ്യത്യസ്തമായി, ഈ പ്രീട്രെയിൻഡ് മോഡൽ ഇൻസ്‌റ്റാൻഷിയേറ്റ് ചെയ്ത ശേഷം നിങ്ങൾക്ക് ഒരു മുന്നറിയിപ്പ് (warning) ലഭിക്കുന്നത് നിങ്ങൾ ശ്രദ്ധിക്കും. വാക്യജോഡികൾ വർഗ്ഗീകരിക്കാൻ BERT പ്രീട്രെയിൻ ചെയ്യപ്പെട്ടിട്ടില്ല എന്നതാണ് ഇതിന് കാരണം; അതിനാൽ പ്രീട്രെയിൻഡ് മോഡലിന്റെ ഹെഡ് (head) ഒഴിവാക്കി, പകരം സീക്വൻസ് ക്ലാസിഫിക്കേഷന് അനുയോജ്യമായ ഒരു പുതിയ ഹെഡ് ചേർത്തിരിക്കുന്നു. ചില വെയ്‌റ്റുകൾ ഉപയോഗിച്ചിട്ടില്ലെന്നും (ഒഴിവാക്കിയ പ്രീട്രെയിനിംഗ് ഹെഡിന്റേത്) മറ്റു ചിലത് ക്രമരഹിതമായി (randomly) ഇനിഷ്യലൈസ് ചെയ്യപ്പെട്ടിരിക്കുന്നു എന്നും (പുതിയ ഹെഡിന്റേത്) ഈ മുന്നറിയിപ്പുകൾ സൂചിപ്പിക്കുന്നു. മോഡൽ ട്രെയിൻ ചെയ്യാൻ നിങ്ങളെ പ്രോത്സാഹിപ്പിച്ചുകൊണ്ടാണ് അത് അവസാനിക്കുന്നത് — അതുതന്നെയാണ് നമ്മൾ ഇപ്പോൾ ചെയ്യാൻ പോകുന്നതും. + +മോഡൽ തയ്യാറായിക്കഴിഞ്ഞാൽ, ഇതുവരെ നിർമ്മിച്ച എല്ലാ ഒബ്‌ജക്റ്റുകളും — `model`, `training_args`, ട്രെയിനിംഗ്, വാലിഡേഷൻ ഡേറ്റാസെറ്റുകൾ, നമ്മുടെ `data_collator`, നമ്മുടെ `processing_class` — നൽകിക്കൊണ്ട് ഒരു `Trainer` നിർവചിക്കാം. `processing_class` എന്ന പാരാമീറ്റർ അടുത്തകാലത്ത് ചേർത്ത ഒന്നാണ്; പ്രോസസ്സിംഗിന് ഏത് ടോക്കണൈസർ ഉപയോഗിക്കണമെന്ന് ഇത് Trainer-നോട് പറയുന്നു: + +```py +from transformers import Trainer + +trainer = Trainer( + model, + training_args, + train_dataset=tokenized_datasets["train"], + eval_dataset=tokenized_datasets["validation"], + data_collator=data_collator, + processing_class=tokenizer, +) +``` + +`processing_class` ആയി ഒരു ടോക്കണൈസർ നൽകുമ്പോൾ, `Trainer` ഉപയോഗിക്കുന്ന ഡിഫോൾട്ട് `data_collator` ഒരു `DataCollatorWithPadding` ആയിരിക്കും. ഈ സാഹചര്യത്തിൽ `data_collator=data_collator` എന്ന വരി നിങ്ങൾക്ക് ഒഴിവാക്കാം, എന്നാൽ പ്രോസസ്സിംഗ് പൈപ്പ്‌ലൈനിന്റെ ഈ പ്രധാന ഭാഗം നിങ്ങൾക്ക് കാണിച്ചുതരാനാണ് ഞങ്ങൾ ഇവിടെ അത് ഉൾപ്പെടുത്തിയത്. + +> [!TIP] +> 📖 **കൂടുതൽ അറിയാൻ**: Trainer ക്ലാസിനെയും അതിന്റെ പാരാമീറ്ററുകളെയും കുറിച്ചുള്ള സമഗ്രമായ വിവരങ്ങൾക്ക്, [Trainer API ഡോക്യുമെന്റേഷൻ](https://huggingface.co/docs/transformers/main/en/main_classes/trainer) സന്ദർശിക്കുകയും [ട്രെയിനിംഗ് കുക്ക്‌ബുക്ക് റെസിപ്പികളിലെ](https://huggingface.co/learn/cookbook/en/fine_tuning_code_llm_on_single_gpu) അഡ്വാൻസ്ഡ് ഉപയോഗരീതികൾ പരിശോധിക്കുകയും ചെയ്യുക. + +നമ്മുടെ ഡേറ്റാസെറ്റിൽ മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യാൻ, നമ്മുടെ `Trainer`-ന്റെ `train()` മെത്തേഡ് വിളിച്ചാൽ മാത്രം മതി: + +```py +trainer.train() +``` + +ഇത് ഫൈൻ-ട്യൂണിംഗ് ആരംഭിക്കുകയും (ഒരു GPU-വിൽ ഇതിന് ഏതാനും മിനിറ്റുകൾ എടുക്കും) ഓരോ 500 സ്‌റ്റെപ്പിലും ട്രെയിനിംഗ് ലോസ് റിപ്പോർട്ട് ചെയ്യുകയും ചെയ്യും. എന്നാൽ, നിങ്ങളുടെ മോഡൽ എത്ര നന്നായി (അല്ലെങ്കിൽ മോശമായി) പ്രവർത്തിക്കുന്നു എന്ന് ഇത് നിങ്ങളോട് പറയില്ല. അതിന് കാരണം: + +1. `TrainingArguments`-ലെ `eval_strategy` `"steps"` (ഓരോ `eval_steps`-ലും ഇവാല്യുവേറ്റ് ചെയ്യുക) അല്ലെങ്കിൽ `"epoch"` (ഓരോ എപ്പോക്കിന്റെയും അവസാനം ഇവാല്യുവേറ്റ് ചെയ്യുക) എന്ന് സെറ്റ് ചെയ്തുകൊണ്ട്, ട്രെയിനിംഗ് സമയത്ത് ഇവാല്യുവേറ്റ് ചെയ്യാൻ നമ്മൾ `Trainer`-നോട് പറഞ്ഞില്ല. +2. ആ ഇവാല്യുവേഷൻ സമയത്ത് ഒരു മെട്രിക് കണക്കാക്കാനുള്ള `compute_metrics()` ഫംഗ്‌ഷൻ നമ്മൾ `Trainer`-ന് നൽകിയില്ല (അല്ലാത്തപക്ഷം ഇവാല്യുവേഷൻ ലോസ് മാത്രമേ പ്രിന്റ് ചെയ്യുമായിരുന്നുള്ളൂ, അത് അത്ര അവബോധജന്യമായ ഒരു സംഖ്യയല്ല). + + +### ഇവാല്യുവേഷൻ[[evaluation]] + +ഉപകാരപ്രദമായ ഒരു `compute_metrics()` ഫംഗ്‌ഷൻ എങ്ങനെ നിർമ്മിക്കാമെന്നും അടുത്ത തവണ ട്രെയിൻ ചെയ്യുമ്പോൾ അത് എങ്ങനെ ഉപയോഗിക്കാമെന്നും നോക്കാം. ഈ ഫംഗ്‌ഷൻ ഒരു `EvalPrediction` ഒബ്‌ജക്റ്റ് സ്വീകരിക്കണം (`predictions` എന്ന ഫീൽഡും `label_ids` എന്ന ഫീൽഡും ഉള്ള ഒരു named tuple ആണിത്), കൂടാതെ സ്‌ട്രിംഗുകളെ ഫ്ലോട്ടുകളുമായി ബന്ധിപ്പിക്കുന്ന ഒരു ഡിക്‌ഷണറി റിട്ടേൺ ചെയ്യും (സ്‌ട്രിംഗുകൾ റിട്ടേൺ ചെയ്യുന്ന മെട്രിക്കുകളുടെ പേരുകളും, ഫ്ലോട്ടുകൾ അവയുടെ മൂല്യങ്ങളുമാണ്). നമ്മുടെ മോഡലിൽ നിന്ന് ചില പ്രവചനങ്ങൾ (predictions) ലഭിക്കാൻ, `Trainer.predict()` കമാൻഡ് ഉപയോഗിക്കാം: + +```py +predictions = trainer.predict(tokenized_datasets["validation"]) +print(predictions.predictions.shape, predictions.label_ids.shape) +``` + +```python out +(408, 2) (408,) +``` + +`predict()` മെത്തേഡിന്റെ ഔട്ട്‌പുട്ട് മൂന്ന് ഫീൽഡുകളുള്ള മറ്റൊരു named tuple ആണ്: `predictions`, `label_ids`, `metrics`. `metrics` ഫീൽഡിൽ, നൽകിയ ഡേറ്റാസെറ്റിലെ ലോസും ചില സമയ മെട്രിക്കുകളും (പ്രവചിക്കാൻ മൊത്തത്തിലും ശരാശരിയായും എത്ര സമയമെടുത്തു) മാത്രമേ ഉണ്ടാകൂ. നമ്മുടെ `compute_metrics()` ഫംഗ്‌ഷൻ പൂർത്തിയാക്കി `Trainer`-ന് നൽകിക്കഴിഞ്ഞാൽ, `compute_metrics()` റിട്ടേൺ ചെയ്യുന്ന മെട്രിക്കുകളും ആ ഫീൽഡിൽ ഉണ്ടാകും. + +നിങ്ങൾക്ക് കാണാവുന്നതുപോലെ, `predictions` എന്നത് 408 x 2 ഷേപ്പുള്ള ഒരു ദ്വിമാന അറേ (two-dimensional array) ആണ് (408 എന്നത് നമ്മൾ ഉപയോഗിച്ച ഡേറ്റാസെറ്റിലെ എലമെന്റുകളുടെ എണ്ണമാണ്). `predict()`-ന് നമ്മൾ നൽകിയ ഡേറ്റാസെറ്റിലെ ഓരോ എലമെന്റിന്റെയും ലോജിറ്റുകളാണ് (logits) ഇവ ([മുൻ അധ്യായത്തിൽ](/course/chapter2) നിങ്ങൾ കണ്ടതുപോലെ, എല്ലാ Transformer മോഡലുകളും ലോജിറ്റുകളാണ് റിട്ടേൺ ചെയ്യുന്നത്). നമ്മുടെ ലേബലുകളുമായി താരതമ്യം ചെയ്യാവുന്ന പ്രവചനങ്ങളാക്കി ഇവയെ മാറ്റാൻ, രണ്ടാമത്തെ ആക്‌സിസിൽ ഏറ്റവും ഉയർന്ന മൂല്യമുള്ള ഇൻഡെക്‌സ് നമ്മൾ എടുക്കണം: + +```py +import numpy as np + +preds = np.argmax(predictions.predictions, axis=-1) +``` + +ഇപ്പോൾ ആ `preds` ലേബലുകളുമായി നമുക്ക് താരതമ്യം ചെയ്യാം. നമ്മുടെ `compute_metric()` ഫംഗ്‌ഷൻ നിർമ്മിക്കാൻ, 🤗 [Evaluate](https://github.com/huggingface/evaluate/) ലൈബ്രറിയിലെ മെട്രിക്കുകളെ നമ്മൾ ആശ്രയിക്കും. ഡേറ്റാസെറ്റ് ലോഡ് ചെയ്തതുപോലെ അത്ര എളുപ്പത്തിൽ MRPC ഡേറ്റാസെറ്റുമായി ബന്ധപ്പെട്ട മെട്രിക്കുകളും ലോഡ് ചെയ്യാം; ഇത്തവണ `evaluate.load()` ഫംഗ്‌ഷൻ ഉപയോഗിച്ചാണ്. റിട്ടേൺ ചെയ്യുന്ന ഒബ്‌ജക്റ്റിന്, മെട്രിക് കണക്കുകൂട്ടലിനായി ഉപയോഗിക്കാവുന്ന ഒരു `compute()` മെത്തേഡ് ഉണ്ട്: + +```py +import evaluate + +metric = evaluate.load("glue", "mrpc") +metric.compute(predictions=preds, references=predictions.label_ids) +``` + +```python out +{'accuracy': 0.8578431372549019, 'f1': 0.8996539792387542} +``` + +> [!TIP] +> വിവിധ ഇവാല്യുവേഷൻ മെട്രിക്കുകളെയും തന്ത്രങ്ങളെയും കുറിച്ച് [🤗 Evaluate ഡോക്യുമെന്റേഷനിൽ](https://huggingface.co/docs/evaluate/) പഠിക്കുക. + +മോഡൽ ഹെഡിന്റെ ക്രമരഹിതമായ ഇനിഷ്യലൈസേഷൻ അത് നേടുന്ന മെട്രിക്കുകളെ മാറ്റിയേക്കാം എന്നതിനാൽ, നിങ്ങൾക്ക് ലഭിക്കുന്ന കൃത്യമായ ഫലങ്ങൾ വ്യത്യാസപ്പെടാം. ഇവിടെ, നമ്മുടെ മോഡലിന് വാലിഡേഷൻ സെറ്റിൽ 85.78% അക്യുറസിയും (accuracy) 89.97 F1 സ്‌കോറും ഉണ്ടെന്ന് കാണാം. GLUE ബെഞ്ച്‌മാർക്കിനായി MRPC ഡേറ്റാസെറ്റിലെ ഫലങ്ങൾ ഇവാല്യുവേറ്റ് ചെയ്യാൻ ഉപയോഗിക്കുന്ന രണ്ട് മെട്രിക്കുകളാണ് ഇവ. [BERT പ്രബന്ധത്തിലെ](https://arxiv.org/pdf/1810.04805.pdf) പട്ടിക ബേസ് മോഡലിന് 88.9 എന്ന F1 സ്‌കോർ റിപ്പോർട്ട് ചെയ്തിരുന്നു. അത് `uncased` മോഡലായിരുന്നു, നമ്മൾ ഇപ്പോൾ ഉപയോഗിക്കുന്നത് `cased` മോഡലാണ്; അതാണ് മെച്ചപ്പെട്ട ഫലത്തിന്റെ കാരണം. + +എല്ലാം ഒരുമിച്ച് ചേർത്താൽ, നമ്മുടെ `compute_metrics()` ഫംഗ്‌ഷൻ ലഭിക്കും: + +```py +def compute_metrics(eval_preds): + metric = evaluate.load("glue", "mrpc") + logits, labels = eval_preds + predictions = np.argmax(logits, axis=-1) + return metric.compute(predictions=predictions, references=labels) +``` + +ഓരോ എപ്പോക്കിന്റെയും അവസാനം മെട്രിക്കുകൾ റിപ്പോർട്ട് ചെയ്യാൻ ഇത് പ്രവർത്തിക്കുന്നത് കാണാൻ, ഈ `compute_metrics()` ഫംഗ്‌ഷനോടെ ഒരു പുതിയ `Trainer` എങ്ങനെ നിർവചിക്കാമെന്ന് ഇതാ: + +```py +training_args = TrainingArguments("test-trainer", eval_strategy="epoch") +model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) + +trainer = Trainer( + model, + training_args, + train_dataset=tokenized_datasets["train"], + eval_dataset=tokenized_datasets["validation"], + data_collator=data_collator, + processing_class=tokenizer, + compute_metrics=compute_metrics, +) +``` + +`eval_strategy` `"epoch"` എന്ന് സെറ്റ് ചെയ്ത ഒരു പുതിയ `TrainingArguments`-ഉം ഒരു പുതിയ മോഡലും നമ്മൾ ഉണ്ടാക്കുന്നു എന്നത് ശ്രദ്ധിക്കുക — അല്ലാത്തപക്ഷം, ഇതിനകം ട്രെയിൻ ചെയ്ത മോഡലിന്റെ ട്രെയിനിംഗ് തുടരുകയാകും നമ്മൾ ചെയ്യുന്നത്. ഒരു പുതിയ ട്രെയിനിംഗ് റൺ ആരംഭിക്കാൻ, നമ്മൾ ഇത് എക്‌സിക്യൂട്ട് ചെയ്യുന്നു: + +```py +trainer.train() +``` + +ഇത്തവണ, ട്രെയിനിംഗ് ലോസിനൊപ്പം ഓരോ എപ്പോക്കിന്റെയും അവസാനം വാലിഡേഷൻ ലോസും മെട്രിക്കുകളും ഇത് റിപ്പോർട്ട് ചെയ്യും. മോഡൽ ഹെഡിന്റെ ക്രമരഹിതമായ ഇനിഷ്യലൈസേഷൻ കാരണം, നിങ്ങൾക്ക് ലഭിക്കുന്ന കൃത്യമായ അക്യുറസി/F1 സ്‌കോർ നമ്മൾ കണ്ടതിൽ നിന്ന് അൽപ്പം വ്യത്യസ്തമായിരിക്കാം, എന്നാൽ അത് ഏറെക്കുറെ അതേ പരിധിയിലായിരിക്കണം. + +### അഡ്വാൻസ്ഡ് ട്രെയിനിംഗ് സവിശേഷതകൾ[[advanced-training-features]] + +ആധുനിക ഡീപ് ലേണിംഗിലെ മികച്ച രീതികൾ എളുപ്പത്തിൽ ലഭ്യമാക്കുന്ന ധാരാളം ബിൽറ്റ്-ഇൻ സവിശേഷതകളോടെയാണ് `Trainer` വരുന്നത്: + +**മിക്‌സഡ് പ്രിസിഷൻ ട്രെയിനിംഗ് (Mixed Precision Training)**: വേഗതയേറിയ ട്രെയിനിംഗിനും കുറഞ്ഞ മെമ്മറി ഉപയോഗത്തിനും നിങ്ങളുടെ ട്രെയിനിംഗ് ആർഗ്യുമെന്റുകളിൽ `fp16=True` ഉപയോഗിക്കുക: + +```py +training_args = TrainingArguments( + "test-trainer", + eval_strategy="epoch", + fp16=True, # Enable mixed precision +) +``` + +**ഗ്രേഡിയന്റ് അക്യുമുലേഷൻ (Gradient Accumulation)**: GPU മെമ്മറി പരിമിതമായിരിക്കുമ്പോൾ ഫലത്തിൽ വലിയ ബാച്ച് സൈസുകൾ ലഭിക്കാൻ: + +```py +training_args = TrainingArguments( + "test-trainer", + eval_strategy="epoch", + per_device_train_batch_size=4, + gradient_accumulation_steps=4, # Effective batch size = 4 * 4 = 16 +) +``` + +**ലേണിംഗ് റേറ്റ് ഷെഡ്യൂളിംഗ് (Learning Rate Scheduling)**: Trainer ഡിഫോൾട്ടായി ലീനിയർ ഡികേ (linear decay) ഉപയോഗിക്കുന്നു, എന്നാൽ ഇത് നിങ്ങൾക്ക് ഇഷ്ടാനുസൃതമാക്കാം: + +```py +training_args = TrainingArguments( + "test-trainer", + eval_strategy="epoch", + learning_rate=2e-5, + lr_scheduler_type="cosine", # Try different schedulers +) +``` + +> [!TIP] +> 🎯 **പെർഫോമൻസ് ഒപ്‌റ്റിമൈസേഷൻ**: ഡിസ്‌ട്രിബ്യൂട്ടഡ് ട്രെയിനിംഗ്, മെമ്മറി ഒപ്‌റ്റിമൈസേഷൻ, ഹാർഡ്‌വെയർ-നിർദ്ദിഷ്ട ഒപ്‌റ്റിമൈസേഷനുകൾ എന്നിവയുൾപ്പെടെയുള്ള കൂടുതൽ അഡ്വാൻസ്ഡ് ട്രെയിനിംഗ് ടെക്‌നിക്കുകൾക്കായി, [🤗 Transformers പെർഫോമൻസ് ഗൈഡ്](https://huggingface.co/docs/transformers/main/en/performance) പരിശോധിക്കുക. + +`Trainer` ഒന്നിലധികം GPU-കളിലോ TPU-കളിലോ യാതൊരു അധിക സജ്ജീകരണവുമില്ലാതെ പ്രവർത്തിക്കും, കൂടാതെ ഡിസ്‌ട്രിബ്യൂട്ടഡ് ട്രെയിനിംഗിനായി ധാരാളം ഓപ്‌ഷനുകളും നൽകുന്നു. ഇത് പിന്തുണയ്ക്കുന്ന എല്ലാ കാര്യങ്ങളും അധ്യായം 10-ൽ നമ്മൾ പരിശോധിക്കും. + +`Trainer` API ഉപയോഗിച്ചുള്ള ഫൈൻ-ട്യൂണിംഗിന്റെ ആമുഖം ഇവിടെ അവസാനിക്കുന്നു. ഏറ്റവും സാധാരണമായ NLP ടാസ്‌ക്കുകൾക്ക് ഇത് എങ്ങനെ ചെയ്യാമെന്നതിന്റെ ഒരു ഉദാഹരണം [അധ്യായം 7](/course/chapter7)-ൽ നൽകും, എന്നാൽ ഇപ്പോൾ ഇതേ കാര്യം ശുദ്ധമായ PyTorch ട്രെയിനിംഗ് ലൂപ്പ് ഉപയോഗിച്ച് എങ്ങനെ ചെയ്യാമെന്ന് നോക്കാം. + +> [!TIP] +> 📝 **കൂടുതൽ ഉദാഹരണങ്ങൾ**: [🤗 Transformers നോട്ട്‌ബുക്കുകളുടെ](https://huggingface.co/docs/transformers/main/en/notebooks) സമഗ്രമായ ശേഖരം പരിശോധിക്കുക. + +## സെക്‌ഷൻ ക്വിസ്[[section-quiz]] + +Trainer API-യെയും ഫൈൻ-ട്യൂണിംഗ് ആശയങ്ങളെയും കുറിച്ചുള്ള നിങ്ങളുടെ ധാരണ പരീക്ഷിക്കുക: + +### 1. Trainer-ലെ processing_class പാരാമീറ്ററിന്റെ ഉദ്ദേശ്യം എന്താണ്? + + + +### 2. ട്രെയിനിംഗ് സമയത്ത് എത്ര ഇടവിട്ട് ഇവാല്യുവേഷൻ നടക്കണമെന്ന് നിയന്ത്രിക്കുന്ന TrainingArguments പാരാമീറ്റർ ഏതാണ്? + + + +### 3. TrainingArguments-ലെ fp16=True എന്താണ് പ്രവർത്തനക്ഷമമാക്കുന്നത്? + + + +### 4. Trainer-ലെ compute_metrics ഫംഗ്‌ഷന്റെ പങ്ക് എന്താണ്? + + + +### 5. Trainer-ന് ഒരു eval_dataset നൽകാതിരുന്നാൽ എന്ത് സംഭവിക്കും? + + + +### 6. ഗ്രേഡിയന്റ് അക്യുമുലേഷൻ എന്താണ്, അത് എങ്ങനെ പ്രവർത്തനക്ഷമമാക്കാം? + + + +> [!TIP] +> 💡 **പ്രധാന പാഠങ്ങൾ:** +> - `Trainer` API ട്രെയിനിംഗിന്റെ സങ്കീർണ്ണതകളിൽ മിക്കതും കൈകാര്യം ചെയ്യുന്ന ഒരു ഉയർന്ന തലത്തിലുള്ള (high-level) ഇന്റർഫേസ് നൽകുന്നു +> - ശരിയായ ഡേറ്റാ കൈകാര്യത്തിനായി നിങ്ങളുടെ ടോക്കണൈസർ വ്യക്തമാക്കാൻ `processing_class` ഉപയോഗിക്കുക +> - `TrainingArguments` ട്രെയിനിംഗിന്റെ എല്ലാ വശങ്ങളും നിയന്ത്രിക്കുന്നു: ലേണിംഗ് റേറ്റ്, ബാച്ച് സൈസ്, ഇവാല്യുവേഷൻ സ്‌ട്രാറ്റജി, ഒപ്‌റ്റിമൈസേഷനുകൾ +> - ട്രെയിനിംഗ് ലോസിനപ്പുറം ഇഷ്ടാനുസൃത ഇവാല്യുവേഷൻ മെട്രിക്കുകൾ `compute_metrics` സാധ്യമാക്കുന്നു +> - മിക്‌സഡ് പ്രിസിഷൻ (`fp16=True`), ഗ്രേഡിയന്റ് അക്യുമുലേഷൻ പോലുള്ള ആധുനിക സവിശേഷതകൾ ട്രെയിനിംഗ് കാര്യക്ഷമത ഗണ്യമായി മെച്ചപ്പെടുത്തും + diff --git a/chapters/ml/chapter3/4.mdx b/chapters/ml/chapter3/4.mdx new file mode 100644 index 000000000..088c0741a --- /dev/null +++ b/chapters/ml/chapter3/4.mdx @@ -0,0 +1,543 @@ +# ഒരു പൂർണ്ണ ട്രെയിനിംഗ് ലൂപ്പ്[[a-full-training]] + + + + + +`Trainer` ക്ലാസ് ഉപയോഗിക്കാതെ, ആധുനിക PyTorch മികച്ച രീതികൾ (best practices) പിന്തുടർന്ന് തുടക്കം മുതൽ ഒരു ട്രെയിനിംഗ് ലൂപ്പ് ഇംപ്ലിമെന്റ് ചെയ്തുകൊണ്ട്, കഴിഞ്ഞ വിഭാഗത്തിൽ നേടിയ അതേ ഫലങ്ങൾ എങ്ങനെ നേടാം എന്ന് ഇനി നമ്മൾ നോക്കും. വിഭാഗം 2-ലെ ഡേറ്റ പ്രോസസ്സിംഗ് നിങ്ങൾ ചെയ്തിട്ടുണ്ടെന്ന് ഇവിടെയും നമ്മൾ അനുമാനിക്കുന്നു. നിങ്ങൾക്ക് ആവശ്യമായതെല്ലാം ഉൾക്കൊള്ളുന്ന ഒരു ചെറിയ സംഗ്രഹം ഇതാ: + +> [!TIP] +> 🏗️ **തുടക്കം മുതൽ ട്രെയിൻ ചെയ്യുന്നു**: ഈ വിഭാഗം മുൻ ഉള്ളടക്കത്തിന്മേൽ കെട്ടിപ്പടുത്തിരിക്കുന്നതാണ്. PyTorch ട്രെയിനിംഗ് ലൂപ്പുകളെയും മികച്ച രീതികളെയും കുറിച്ചുള്ള സമഗ്രമായ മാർഗ്ഗനിർദ്ദേശങ്ങൾക്ക്, [🤗 Transformers ട്രെയിനിംഗ് ഡോക്യുമെന്റേഷനും](https://huggingface.co/docs/transformers/main/en/training#train-in-native-pytorch) [കസ്‌റ്റം ട്രെയിനിംഗ് കുക്ക്‌ബുക്കും](https://huggingface.co/learn/cookbook/en/fine_tuning_code_llm_on_single_gpu#model) നോക്കുക. + +```py +from datasets import load_dataset +from transformers import AutoTokenizer, DataCollatorWithPadding + +raw_datasets = load_dataset("glue", "mrpc") +checkpoint = "bert-base-uncased" +tokenizer = AutoTokenizer.from_pretrained(checkpoint) + + +def tokenize_function(example): + return tokenizer(example["sentence1"], example["sentence2"], truncation=True) + + +tokenized_datasets = raw_datasets.map(tokenize_function, batched=True) +data_collator = DataCollatorWithPadding(tokenizer=tokenizer) +``` + +### ട്രെയിനിംഗിനായി തയ്യാറെടുക്കുന്നു[[prepare-for-training]] + +നമ്മുടെ ട്രെയിനിംഗ് ലൂപ്പ് യഥാർത്ഥത്തിൽ എഴുതുന്നതിന് മുമ്പ്, ഏതാനും ഒബ്‌ജക്റ്റുകൾ നമുക്ക് നിർവചിക്കേണ്ടതുണ്ട്. ബാച്ചുകളിലൂടെ ആവർത്തിച്ച് കടന്നുപോകാൻ (iterate) നമ്മൾ ഉപയോഗിക്കുന്ന ഡേറ്റാലോഡറുകളാണ് (dataloaders) ആദ്യത്തേത്. എന്നാൽ ആ ഡേറ്റാലോഡറുകൾ നിർവചിക്കുന്നതിന് മുമ്പ്, `Trainer` നമുക്കായി സ്വയമേവ ചെയ്തുതന്ന ചില കാര്യങ്ങൾ കൈകാര്യം ചെയ്യാൻ, നമ്മുടെ `tokenized_datasets`-ൽ കുറച്ച് പോസ്‌റ്റ്‌പ്രോസസ്സിംഗ് നമുക്ക് ചെയ്യേണ്ടതുണ്ട്. കൃത്യമായി പറഞ്ഞാൽ, നമ്മൾ ചെയ്യേണ്ടത്: + +- മോഡൽ പ്രതീക്ഷിക്കാത്ത മൂല്യങ്ങളുമായി ബന്ധപ്പെട്ട കോളങ്ങൾ (`sentence1`, `sentence2` കോളങ്ങൾ പോലുള്ളവ) നീക്കം ചെയ്യുക. +- `label` എന്ന കോളത്തിന്റെ പേര് `labels` എന്നാക്കി മാറ്റുക (കാരണം ആർഗ്യുമെന്റിന്റെ പേര് `labels` ആയിരിക്കണമെന്നാണ് മോഡൽ പ്രതീക്ഷിക്കുന്നത്). +- ലിസ്‌റ്റുകൾക്ക് പകരം PyTorch ടെൻസറുകൾ റിട്ടേൺ ചെയ്യുന്ന വിധത്തിൽ ഡേറ്റാസെറ്റുകളുടെ ഫോർമാറ്റ് സെറ്റ് ചെയ്യുക. + +ഈ ഓരോ ഘട്ടത്തിനും നമ്മുടെ `tokenized_datasets`-ൽ ഒരു മെത്തേഡ് വീതമുണ്ട്: + +```py +tokenized_datasets = tokenized_datasets.remove_columns(["sentence1", "sentence2", "idx"]) +tokenized_datasets = tokenized_datasets.rename_column("label", "labels") +tokenized_datasets.set_format("torch") +tokenized_datasets["train"].column_names +``` + +നമ്മുടെ മോഡൽ സ്വീകരിക്കുന്ന കോളങ്ങൾ മാത്രമേ ഫലത്തിൽ ഉള്ളൂ എന്ന് പിന്നീട് നമുക്ക് പരിശോധിക്കാം: + +```python +["attention_mask", "input_ids", "labels", "token_type_ids"] +``` + +ഇത് പൂർത്തിയായ സ്ഥിതിക്ക്, നമ്മുടെ ഡേറ്റാലോഡറുകൾ എളുപ്പത്തിൽ നിർവചിക്കാം: + +```py +from torch.utils.data import DataLoader + +train_dataloader = DataLoader( + tokenized_datasets["train"], shuffle=True, batch_size=8, collate_fn=data_collator +) +eval_dataloader = DataLoader( + tokenized_datasets["validation"], batch_size=8, collate_fn=data_collator +) +``` + +ഡേറ്റ പ്രോസസ്സിംഗിൽ തെറ്റുകളൊന്നുമില്ലെന്ന് വേഗത്തിൽ ഉറപ്പുവരുത്താൻ, ഒരു ബാച്ച് ഇങ്ങനെ പരിശോധിക്കാം: + +```py +for batch in train_dataloader: + break +{k: v.shape for k, v in batch.items()} +``` + +```python out +{'attention_mask': torch.Size([8, 65]), + 'input_ids': torch.Size([8, 65]), + 'labels': torch.Size([8]), + 'token_type_ids': torch.Size([8, 65])} +``` + +ട്രെയിനിംഗ് ഡേറ്റാലോഡറിന് `shuffle=True` എന്ന് സെറ്റ് ചെയ്തിരിക്കുന്നതിനാലും ബാച്ചിനുള്ളിലെ പരമാവധി നീളത്തിലേക്ക് നമ്മൾ പാഡിംഗ് ചെയ്യുന്നതിനാലും, യഥാർത്ഥ ഷേപ്പുകൾ (shapes) നിങ്ങൾക്ക് ഒരുപക്ഷേ ചെറുതായി വ്യത്യസ്തമായിരിക്കും എന്നത് ശ്രദ്ധിക്കുക. + +ഡേറ്റ പ്രീപ്രോസസ്സിംഗ് പൂർണ്ണമായി തീർന്ന സ്ഥിതിക്ക് (ഏതൊരു ML പ്രാക്റ്റീഷണർക്കും സംതൃപ്തി നൽകുന്ന, എന്നാൽ അപൂർവ്വമായി മാത്രം കൈവരുന്ന ഒരു ലക്ഷ്യം), ഇനി മോഡലിലേക്ക് തിരിയാം. മുൻ വിഭാഗത്തിൽ ചെയ്തതുപോലെ തന്നെ നമ്മൾ അത് ഇൻസ്‌റ്റാൻഷിയേറ്റ് ചെയ്യുന്നു: + +```py +from transformers import AutoModelForSequenceClassification + +model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) +``` + +ട്രെയിനിംഗ് സമയത്ത് എല്ലാം സുഗമമായി നടക്കുമെന്ന് ഉറപ്പാക്കാൻ, നമ്മുടെ ബാച്ച് ഈ മോഡലിലേക്ക് നൽകുന്നു: + +```py +outputs = model(**batch) +print(outputs.loss, outputs.logits.shape) +``` + +```python out +tensor(0.5441, grad_fn=) torch.Size([8, 2]) +``` + +`labels` നൽകുമ്പോൾ എല്ലാ 🤗 Transformers മോഡലുകളും ലോസ് (loss) റിട്ടേൺ ചെയ്യും; കൂടാതെ ലോജിറ്റുകളും (logits) നമുക്ക് ലഭിക്കും (നമ്മുടെ ബാച്ചിലെ ഓരോ ഇൻപുട്ടിനും രണ്ട് വീതം, അതിനാൽ 8 x 2 വലിപ്പമുള്ള ഒരു ടെൻസർ). + +നമ്മുടെ ട്രെയിനിംഗ് ലൂപ്പ് എഴുതാൻ നമ്മൾ ഏകദേശം തയ്യാറായി! രണ്ട് കാര്യങ്ങൾ മാത്രമാണ് ഇനി വേണ്ടത്: ഒരു ഒപ്‌റ്റിമൈസറും (optimizer) ഒരു ലേണിംഗ് റേറ്റ് ഷെഡ്യൂളറും (learning rate scheduler). `Trainer` ചെയ്തിരുന്നത് സ്വന്തമായി പുനഃസൃഷ്ടിക്കാനാണ് നമ്മൾ ശ്രമിക്കുന്നത് എന്നതിനാൽ, അതേ ഡിഫോൾട്ടുകൾ തന്നെ ഉപയോഗിക്കും. `Trainer` ഉപയോഗിക്കുന്ന ഒപ്‌റ്റിമൈസർ `AdamW` ആണ്; ഇത് Adam-ന് തുല്യമാണ്, എന്നാൽ വെയ്‌റ്റ് ഡികേ റെഗുലറൈസേഷനിൽ (weight decay regularization) ഒരു ചെറിയ മാറ്റമുണ്ട് (Ilya Loshchilov, Frank Hutter എന്നിവരുടെ ["Decoupled Weight Decay Regularization"](https://arxiv.org/abs/1711.05101) കാണുക): + +```py +from torch.optim import AdamW + +optimizer = AdamW(model.parameters(), lr=5e-5) +``` + +> [!TIP] +> 💡 **ആധുനിക ഒപ്‌റ്റിമൈസേഷൻ നുറുങ്ങുകൾ**: കൂടുതൽ മികച്ച പ്രകടനത്തിനായി, ഇവ പരീക്ഷിക്കാം: +> - **വെയ്‌റ്റ് ഡികേയോടുകൂടിയ AdamW**: `AdamW(model.parameters(), lr=5e-5, weight_decay=0.01)` +> - **8-bit Adam**: മെമ്മറി-കാര്യക്ഷമമായ ഒപ്‌റ്റിമൈസേഷനായി `bitsandbytes` ഉപയോഗിക്കുക +> - **വ്യത്യസ്ത ലേണിംഗ് റേറ്റുകൾ**: വലിയ മോഡലുകൾക്ക് കുറഞ്ഞ ലേണിംഗ് റേറ്റുകൾ (1e-5 മുതൽ 3e-5 വരെ) പലപ്പോഴും കൂടുതൽ നന്നായി പ്രവർത്തിക്കും +> +> 🚀 **ഒപ്‌റ്റിമൈസേഷൻ വിഭവങ്ങൾ**: ഒപ്‌റ്റിമൈസറുകളെയും ട്രെയിനിംഗ് തന്ത്രങ്ങളെയും കുറിച്ച് കൂടുതൽ അറിയാൻ [🤗 Transformers ഒപ്‌റ്റിമൈസേഷൻ ഗൈഡ്](https://huggingface.co/docs/transformers/main/en/performance#optimizer) കാണുക. + +അവസാനമായി, ഡിഫോൾട്ടായി ഉപയോഗിക്കുന്ന ലേണിംഗ് റേറ്റ് ഷെഡ്യൂളർ പരമാവധി മൂല്യത്തിൽ (5e-5) നിന്ന് 0-ലേക്കുള്ള ഒരു ലീനിയർ ഡികേ (linear decay) മാത്രമാണ്. ഇത് ശരിയായി നിർവചിക്കാൻ, നമ്മൾ എടുക്കുന്ന ട്രെയിനിംഗ് സ്‌റ്റെപ്പുകളുടെ എണ്ണം അറിയേണ്ടതുണ്ട്; അത് നമുക്ക് റൺ ചെയ്യേണ്ട എപ്പോക്കുകളുടെ (epochs) എണ്ണത്തെ ട്രെയിനിംഗ് ബാച്ചുകളുടെ എണ്ണം (അതായത് നമ്മുടെ ട്രെയിനിംഗ് ഡേറ്റാലോഡറിന്റെ നീളം) കൊണ്ട് ഗുണിച്ചതാണ്. `Trainer` ഡിഫോൾട്ടായി മൂന്ന് എപ്പോക്കുകൾ ഉപയോഗിക്കുന്നു, അതിനാൽ നമ്മളും അത് പിന്തുടരും: + +```py +from transformers import get_scheduler + +num_epochs = 3 +num_training_steps = num_epochs * len(train_dataloader) +lr_scheduler = get_scheduler( + "linear", + optimizer=optimizer, + num_warmup_steps=0, + num_training_steps=num_training_steps, +) +print(num_training_steps) +``` + +```python out +1377 +``` + +### ട്രെയിനിംഗ് ലൂപ്പ്[[the-training-loop]] + +അവസാനത്തെ ഒരു കാര്യം: ഒരു GPU ലഭ്യമാണെങ്കിൽ അത് ഉപയോഗിക്കാൻ നമ്മൾ ആഗ്രഹിക്കും (ഒരു CPU-വിൽ, ട്രെയിനിംഗിന് ഏതാനും മിനിറ്റുകൾക്ക് പകരം മണിക്കൂറുകൾ എടുത്തേക്കാം). ഇതിനായി, നമ്മുടെ മോഡലും ബാച്ചുകളും വയ്ക്കാനുള്ള ഒരു `device` നമ്മൾ നിർവചിക്കുന്നു: + +```py +import torch + +device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu") +model.to(device) +device +``` + +```python out +device(type='cuda') +``` + +ഇനി നമ്മൾ ട്രെയിൻ ചെയ്യാൻ തയ്യാറാണ്! ട്രെയിനിംഗ് എപ്പോൾ പൂർത്തിയാകും എന്നതിനെക്കുറിച്ച് ഒരു ധാരണ ലഭിക്കാൻ, `tqdm` ലൈബ്രറി ഉപയോഗിച്ച് നമ്മുടെ ട്രെയിനിംഗ് സ്‌റ്റെപ്പുകളുടെ എണ്ണത്തിന് മേൽ ഒരു പ്രോഗ്രസ് ബാർ ചേർക്കുന്നു: + +```py +from tqdm.auto import tqdm + +progress_bar = tqdm(range(num_training_steps)) + +model.train() +for epoch in range(num_epochs): + for batch in train_dataloader: + batch = {k: v.to(device) for k, v in batch.items()} + outputs = model(**batch) + loss = outputs.loss + loss.backward() + + optimizer.step() + lr_scheduler.step() + optimizer.zero_grad() + progress_bar.update(1) +``` + +> [!TIP] +> 💡 **ആധുനിക ട്രെയിനിംഗ് ഒപ്‌റ്റിമൈസേഷനുകൾ**: നിങ്ങളുടെ ട്രെയിനിംഗ് ലൂപ്പ് കൂടുതൽ കാര്യക്ഷമമാക്കാൻ, ഇവ പരിഗണിക്കുക: +> +> - **ഗ്രേഡിയന്റ് ക്ലിപ്പിംഗ് (Gradient Clipping)**: `optimizer.step()`-ന് മുമ്പ് `torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)` ചേർക്കുക +> - **മിക്‌സഡ് പ്രിസിഷൻ (Mixed Precision)**: വേഗത്തിലുള്ള ട്രെയിനിംഗിനായി `torch.cuda.amp.autocast()`, `GradScaler` എന്നിവ ഉപയോഗിക്കുക +> - **ഗ്രേഡിയന്റ് അക്യുമുലേഷൻ (Gradient Accumulation)**: വലിയ ബാച്ച് സൈസുകൾ അനുകരിക്കാൻ ഒന്നിലധികം ബാച്ചുകളിലായി ഗ്രേഡിയന്റുകൾ സംഭരിക്കുക +> - **ചെക്ക്‌പോയിന്റിംഗ് (Checkpointing)**: ട്രെയിനിംഗ് തടസ്സപ്പെട്ടാൽ പുനരാരംഭിക്കാൻ കഴിയുന്ന വിധത്തിൽ മോഡൽ ചെക്ക്‌പോയിന്റുകൾ ഇടയ്ക്കിടെ സേവ് ചെയ്യുക +> +> 🔧 **ഇംപ്ലിമെന്റേഷൻ ഗൈഡ്**: ഈ ഒപ്‌റ്റിമൈസേഷനുകളുടെ വിശദമായ ഉദാഹരണങ്ങൾക്ക്, [🤗 Transformers കാര്യക്ഷമ ട്രെയിനിംഗ് ഗൈഡും](https://huggingface.co/docs/transformers/main/en/perf_train_gpu_one) [ലഭ്യമായ ഒപ്‌റ്റിമൈസറുകളുടെ പട്ടികയും](https://huggingface.co/docs/transformers/main/en/optimizers) കാണുക. + +ട്രെയിനിംഗ് ലൂപ്പിന്റെ കാതലായ ഭാഗം ആമുഖത്തിൽ കണ്ടതിനോട് ഏറെ സാമ്യമുള്ളതാണെന്ന് നിങ്ങൾക്ക് കാണാം. നമ്മൾ ഒരു റിപ്പോർട്ടിംഗും ആവശ്യപ്പെട്ടിട്ടില്ല, അതിനാൽ മോഡൽ എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്നതിനെക്കുറിച്ച് ഈ ട്രെയിനിംഗ് ലൂപ്പ് നമ്മോട് ഒന്നും പറയില്ല. അതിനായി ഒരു ഇവാലുവേഷൻ ലൂപ്പ് (evaluation loop) നമുക്ക് ചേർക്കേണ്ടതുണ്ട്. + + +### ഇവാലുവേഷൻ ലൂപ്പ്[[the-evaluation-loop]] + +മുമ്പ് ചെയ്തതുപോലെ, 🤗 Evaluate ലൈബ്രറി നൽകുന്ന ഒരു മെട്രിക് നമ്മൾ ഉപയോഗിക്കും. `metric.compute()` മെത്തേഡ് നമ്മൾ ഇതിനകം കണ്ടിട്ടുണ്ട്, എന്നാൽ പ്രെഡിക്‌ഷൻ ലൂപ്പിലൂടെ കടന്നുപോകുമ്പോൾ `add_batch()` മെത്തേഡ് ഉപയോഗിച്ച് മെട്രിക്കുകൾക്ക് നമുക്കായി ബാച്ചുകൾ സംഭരിച്ചുവയ്ക്കാനും കഴിയും. എല്ലാ ബാച്ചുകളും സംഭരിച്ചുകഴിഞ്ഞാൽ, `metric.compute()` ഉപയോഗിച്ച് അന്തിമ ഫലം നമുക്ക് ലഭിക്കും. ഇതെല്ലാം ഒരു ഇവാലുവേഷൻ ലൂപ്പിൽ എങ്ങനെ ഇംപ്ലിമെന്റ് ചെയ്യാം എന്ന് ഇതാ: + +> [!TIP] +> 📊 **ഇവാലുവേഷനിലെ മികച്ച രീതികൾ**: കൂടുതൽ സങ്കീർണ്ണമായ ഇവാലുവേഷൻ തന്ത്രങ്ങൾക്കും മെട്രിക്കുകൾക്കും, [🤗 Evaluate ഡോക്യുമെന്റേഷനും](https://huggingface.co/docs/evaluate/) [സമഗ്രമായ ഇവാലുവേഷൻ കുക്ക്‌ബുക്കും](https://github.com/huggingface/evaluation-guidebook) പരിശോധിക്കുക. + +```py +import evaluate + +metric = evaluate.load("glue", "mrpc") +model.eval() +for batch in eval_dataloader: + batch = {k: v.to(device) for k, v in batch.items()} + with torch.no_grad(): + outputs = model(**batch) + + logits = outputs.logits + predictions = torch.argmax(logits, dim=-1) + metric.add_batch(predictions=predictions, references=batch["labels"]) + +metric.compute() +``` + +```python out +{'accuracy': 0.8431372549019608, 'f1': 0.8907849829351535} +``` + +മോഡൽ ഹെഡിന്റെ ഇനിഷ്യലൈസേഷനിലെയും ഡേറ്റ ഷഫ്‌ളിംഗിലെയും റാൻഡംനെസ് കാരണം നിങ്ങളുടെ ഫലങ്ങൾ ഇവിടെയും ചെറുതായി വ്യത്യസ്തമായിരിക്കും, എന്നാൽ അവ ഏകദേശം ഇതേ പരിധിയിൽ തന്നെ വരണം. + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** SST-2 ഡേറ്റാസെറ്റിൽ നിങ്ങളുടെ മോഡൽ ഫൈൻ-ട്യൂൺ ചെയ്യാൻ മുമ്പത്തെ ട്രെയിനിംഗ് ലൂപ്പ് പരിഷ്‌കരിക്കുക. + +### 🤗 Accelerate ഉപയോഗിച്ച് നിങ്ങളുടെ ട്രെയിനിംഗ് ലൂപ്പിന് കൂടുതൽ കരുത്ത് പകരുക[[supercharge-your-training-loop-with-accelerate]] + + + +നമ്മൾ മുമ്പ് നിർവചിച്ച ട്രെയിനിംഗ് ലൂപ്പ് ഒരൊറ്റ CPU-വിലോ GPU-വിലോ നന്നായി പ്രവർത്തിക്കും. എന്നാൽ [🤗 Accelerate](https://github.com/huggingface/accelerate) ലൈബ്രറി ഉപയോഗിച്ച്, ഏതാനും ചെറിയ മാറ്റങ്ങൾ മാത്രം വരുത്തി, ഒന്നിലധികം GPU-കളിലോ TPU-കളിലോ ഡിസ്‌ട്രിബ്യൂട്ടഡ് ട്രെയിനിംഗ് (distributed training) നമുക്ക് സാധ്യമാക്കാം. ഡിസ്‌ട്രിബ്യൂട്ടഡ് ട്രെയിനിംഗ്, മിക്‌സഡ് പ്രിസിഷൻ, ഡിവൈസ് പ്ലേസ്‌മെന്റ് എന്നിവയുടെ സങ്കീർണ്ണതകൾ 🤗 Accelerate സ്വയമേവ കൈകാര്യം ചെയ്യുന്നു. ട്രെയിനിംഗ്, വാലിഡേഷൻ ഡേറ്റാലോഡറുകൾ സൃഷ്ടിക്കുന്നിടത്തു നിന്ന് തുടങ്ങിയാൽ, നമ്മുടെ മാനുവൽ ട്രെയിനിംഗ് ലൂപ്പ് ഇങ്ങനെയാണ് കാണപ്പെടുന്നത്: + +> [!TIP] +> ⚡ **Accelerate-ലേക്ക് ആഴത്തിൽ**: ഡിസ്‌ട്രിബ്യൂട്ടഡ് ട്രെയിനിംഗ്, മിക്‌സഡ് പ്രിസിഷൻ, ഹാർഡ്‌വെയർ ഒപ്‌റ്റിമൈസേഷൻ എന്നിവയെക്കുറിച്ച് എല്ലാം [🤗 Accelerate ഡോക്യുമെന്റേഷനിൽ](https://huggingface.co/docs/accelerate/) പഠിക്കുക, [transformers ഡോക്യുമെന്റേഷനിലെ](https://huggingface.co/docs/transformers/main/en/accelerate) പ്രായോഗിക ഉദാഹരണങ്ങൾ പരിശോധിക്കുക. + +```py +from accelerate import Accelerator +from torch.optim import AdamW +from transformers import AutoModelForSequenceClassification, get_scheduler + +accelerator = Accelerator() + +model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) +optimizer = AdamW(model.parameters(), lr=3e-5) + +train_dl, eval_dl, model, optimizer = accelerator.prepare( + train_dataloader, eval_dataloader, model, optimizer +) + +num_epochs = 3 +num_training_steps = num_epochs * len(train_dl) +lr_scheduler = get_scheduler( + "linear", + optimizer=optimizer, + num_warmup_steps=0, + num_training_steps=num_training_steps, +) + +progress_bar = tqdm(range(num_training_steps)) + +model.train() +for epoch in range(num_epochs): + for batch in train_dl: + outputs = model(**batch) + loss = outputs.loss + accelerator.backward(loss) + + optimizer.step() + lr_scheduler.step() + optimizer.zero_grad() + progress_bar.update(1) +``` + +ചേർക്കേണ്ട ആദ്യ വരി ഇംപോർട്ട് വരിയാണ്. രണ്ടാമത്തെ വരി ഒരു `Accelerator` ഒബ്‌ജക്റ്റ് ഇൻസ്‌റ്റാൻഷിയേറ്റ് ചെയ്യുന്നു; അത് പരിസ്ഥിതി (environment) പരിശോധിച്ച് ശരിയായ ഡിസ്‌ട്രിബ്യൂട്ടഡ് സെറ്റപ്പ് ഇനിഷ്യലൈസ് ചെയ്യും. ഡിവൈസ് പ്ലേസ്‌മെന്റ് 🤗 Accelerate നിങ്ങൾക്കായി കൈകാര്യം ചെയ്യുന്നു, അതിനാൽ മോഡലിനെ ഡിവൈസിൽ വയ്ക്കുന്ന വരികൾ നിങ്ങൾക്ക് നീക്കം ചെയ്യാം (അല്ലെങ്കിൽ, വേണമെങ്കിൽ, `device`-ന് പകരം `accelerator.device` ഉപയോഗിക്കുന്ന വിധത്തിൽ അവ മാറ്റാം). + +പിന്നീട്, ഡേറ്റാലോഡറുകളും മോഡലും ഒപ്‌റ്റിമൈസറും `accelerator.prepare()`-ലേക്ക് അയയ്ക്കുന്ന വരിയിലാണ് പ്രധാന ജോലിയുടെ സിംഹഭാഗവും നടക്കുന്നത്. നിങ്ങളുടെ ഡിസ്‌ട്രിബ്യൂട്ടഡ് ട്രെയിനിംഗ് ഉദ്ദേശിച്ചതുപോലെ പ്രവർത്തിക്കുമെന്ന് ഉറപ്പാക്കാൻ ഇത് ആ ഒബ്‌ജക്റ്റുകളെ ശരിയായ കണ്ടെയ്‌നറിൽ പൊതിയും (wrap). ബാക്കി വരുത്തേണ്ട മാറ്റങ്ങൾ ഇവയാണ്: ബാച്ചിനെ `device`-ൽ വയ്ക്കുന്ന വരി നീക്കം ചെയ്യുക (ഇത് നിലനിർത്തണമെങ്കിൽ, `accelerator.device` ഉപയോഗിക്കുന്ന വിധത്തിൽ മാറ്റിയാൽ മതി), `loss.backward()`-ന് പകരം `accelerator.backward(loss)` ഉപയോഗിക്കുക. + +> [!TIP] +> ⚠️ Cloud TPU-കൾ നൽകുന്ന വേഗതാവർദ്ധനവ് പ്രയോജനപ്പെടുത്താൻ, ടോക്കണൈസറിന്റെ `padding="max_length"`, `max_length` എന്നീ ആർഗ്യുമെന്റുകൾ ഉപയോഗിച്ച് നിങ്ങളുടെ സാമ്പിളുകൾ ഒരു നിശ്ചിത നീളത്തിലേക്ക് പാഡ് ചെയ്യാൻ ഞങ്ങൾ ശുപാർശ ചെയ്യുന്നു. + +കോപ്പി-പേസ്‌റ്റ് ചെയ്ത് പരീക്ഷിച്ചുനോക്കാൻ നിങ്ങൾക്ക് താൽപ്പര്യമുണ്ടെങ്കിൽ, 🤗 Accelerate ഉപയോഗിച്ചുള്ള പൂർണ്ണമായ ട്രെയിനിംഗ് ലൂപ്പ് ഇങ്ങനെയാണ്: + +```py +from accelerate import Accelerator +from torch.optim import AdamW +from transformers import AutoModelForSequenceClassification, get_scheduler + +accelerator = Accelerator() + +model = AutoModelForSequenceClassification.from_pretrained(checkpoint, num_labels=2) +optimizer = AdamW(model.parameters(), lr=3e-5) + +train_dl, eval_dl, model, optimizer = accelerator.prepare( + train_dataloader, eval_dataloader, model, optimizer +) + +num_epochs = 3 +num_training_steps = num_epochs * len(train_dl) +lr_scheduler = get_scheduler( + "linear", + optimizer=optimizer, + num_warmup_steps=0, + num_training_steps=num_training_steps, +) + +progress_bar = tqdm(range(num_training_steps)) + +model.train() +for epoch in range(num_epochs): + for batch in train_dl: + outputs = model(**batch) + loss = outputs.loss + accelerator.backward(loss) + + optimizer.step() + lr_scheduler.step() + optimizer.zero_grad() + progress_bar.update(1) +``` + +ഇത് ഒരു `train.py` സ്‌ക്രിപ്‌റ്റിൽ ഇട്ടാൽ, ഏതുതരം ഡിസ്‌ട്രിബ്യൂട്ടഡ് സെറ്റപ്പിലും ആ സ്‌ക്രിപ്‌റ്റ് റൺ ചെയ്യാൻ കഴിയും. നിങ്ങളുടെ ഡിസ്‌ട്രിബ്യൂട്ടഡ് സെറ്റപ്പിൽ ഇത് പരീക്ഷിക്കാൻ, ഈ കമാൻഡ് റൺ ചെയ്യുക: + +```bash +accelerate config +``` + +ഇത് ഏതാനും ചോദ്യങ്ങൾക്ക് ഉത്തരം നൽകാൻ നിങ്ങളോട് ആവശ്യപ്പെടുകയും, നിങ്ങളുടെ ഉത്തരങ്ങൾ താഴെപ്പറയുന്ന കമാൻഡ് ഉപയോഗിക്കുന്ന ഒരു കോൻഫിഗറേഷൻ ഫയലിൽ എഴുതിവയ്ക്കുകയും ചെയ്യും: + +``` +accelerate launch train.py +``` + +ഇത് ഡിസ്‌ട്രിബ്യൂട്ടഡ് ട്രെയിനിംഗ് ആരംഭിക്കും. + +ഇത് ഒരു നോട്ട്‌ബുക്കിൽ പരീക്ഷിക്കണമെങ്കിൽ (ഉദാഹരണത്തിന്, Colab-ൽ TPU-കൾ ഉപയോഗിച്ച് ടെസ്‌റ്റ് ചെയ്യാൻ), കോഡ് ഒരു `training_function()`-ൽ പേസ്‌റ്റ് ചെയ്ത്, അവസാന സെൽ ഇങ്ങനെ റൺ ചെയ്താൽ മതി: + +```python +from accelerate import notebook_launcher + +notebook_launcher(training_function) +``` + +കൂടുതൽ ഉദാഹരണങ്ങൾ [🤗 Accelerate റിപ്പോയിൽ](https://github.com/huggingface/accelerate/tree/main/examples) കാണാം. + +> [!TIP] +> 🌐 **ഡിസ്‌ട്രിബ്യൂട്ടഡ് ട്രെയിനിംഗ്**: മൾട്ടി-GPU, മൾട്ടി-നോഡ് ട്രെയിനിംഗിനെക്കുറിച്ചുള്ള സമഗ്രമായ വിവരങ്ങൾക്ക്, [🤗 Transformers ഡിസ്‌ട്രിബ്യൂട്ടഡ് ട്രെയിനിംഗ് ഗൈഡും](https://huggingface.co/docs/transformers/main/en/perf_train_gpu_many) [സ്‌കേലിംഗ് ട്രെയിനിംഗ് കുക്ക്‌ബുക്കും](https://huggingface.co/docs/transformers/main/en/accelerate) നോക്കുക. + +### അടുത്ത ഘട്ടങ്ങളും മികച്ച രീതികളും[[next-steps-and-best-practices]] + +തുടക്കം മുതൽ ട്രെയിനിംഗ് എങ്ങനെ ഇംപ്ലിമെന്റ് ചെയ്യാമെന്ന് നിങ്ങൾ പഠിച്ച സ്ഥിതിക്ക്, പ്രൊഡക്‌ഷൻ ഉപയോഗത്തിനായി പരിഗണിക്കേണ്ട ചില അധിക കാര്യങ്ങൾ ഇതാ: + +**മോഡൽ ഇവാലുവേഷൻ**: നിങ്ങളുടെ മോഡൽ എപ്പോഴും ഒന്നിലധികം മെട്രിക്കുകളിൽ വിലയിരുത്തുക, അക്യുറസി (accuracy) മാത്രം നോക്കരുത്. സമഗ്രമായ ഇവാലുവേഷനായി 🤗 Evaluate ലൈബ്രറി ഉപയോഗിക്കുക. + +**ഹൈപ്പർപാരാമീറ്റർ ട്യൂണിംഗ്**: വ്യവസ്ഥാപിതമായ ഹൈപ്പർപാരാമീറ്റർ ഒപ്‌റ്റിമൈസേഷനായി Optuna, Ray Tune പോലുള്ള ലൈബ്രറികൾ ഉപയോഗിക്കുന്നത് പരിഗണിക്കുക. + +**മോഡൽ മോണിറ്ററിംഗ്**: ട്രെയിനിംഗിലുടനീളം ട്രെയിനിംഗ് മെട്രിക്കുകൾ, ലേണിംഗ് കർവുകൾ, വാലിഡേഷൻ പ്രകടനം എന്നിവ നിരീക്ഷിക്കുക. + +**മോഡൽ പങ്കുവയ്ക്കൽ**: ട്രെയിൻ ചെയ്തുകഴിഞ്ഞാൽ, കമ്മ്യൂണിറ്റിക്ക് ലഭ്യമാക്കാൻ നിങ്ങളുടെ മോഡൽ Hugging Face Hub-ൽ പങ്കുവയ്ക്കുക. + +**കാര്യക്ഷമത**: വലിയ മോഡലുകൾക്ക്, ഗ്രേഡിയന്റ് ചെക്ക്‌പോയിന്റിംഗ്, പാരാമീറ്റർ-കാര്യക്ഷമമായ ഫൈൻ-ട്യൂണിംഗ് (LoRA, AdaLoRA), ക്വാണ്ടൈസേഷൻ (quantization) രീതികൾ തുടങ്ങിയ സങ്കേതങ്ങൾ പരിഗണിക്കുക. + +കസ്‌റ്റം ട്രെയിനിംഗ് ലൂപ്പുകൾ ഉപയോഗിച്ചുള്ള ഫൈൻ-ട്യൂണിംഗിലേക്കുള്ള നമ്മുടെ ആഴത്തിലുള്ള അന്വേഷണം ഇവിടെ അവസാനിക്കുന്നു. ട്രെയിനിംഗ് പ്രക്രിയയിൽ പൂർണ്ണ നിയന്ത്രണം ആവശ്യമായി വരുമ്പോഴോ, `Trainer` API നൽകുന്നതിനപ്പുറമുള്ള കസ്‌റ്റം ട്രെയിനിംഗ് ലോജിക് ഇംപ്ലിമെന്റ് ചെയ്യാൻ ആഗ്രഹിക്കുമ്പോഴോ, ഇവിടെ നിങ്ങൾ പഠിച്ച കഴിവുകൾ നിങ്ങൾക്ക് ഏറെ ഉപകാരപ്പെടും. + +## വിഭാഗ ക്വിസ്[[section-quiz]] + +കസ്‌റ്റം ട്രെയിനിംഗ് ലൂപ്പുകളെയും വിപുലമായ ട്രെയിനിംഗ് സങ്കേതങ്ങളെയും കുറിച്ചുള്ള നിങ്ങളുടെ ധാരണ പരീക്ഷിക്കുക: + +### 1. Adam, AdamW എന്നീ ഒപ്‌റ്റിമൈസറുകൾക്കിടയിലെ പ്രധാന വ്യത്യാസം എന്താണ്? + + + +### 2. ഒരു ട്രെയിനിംഗ് ലൂപ്പിൽ, പ്രവർത്തനങ്ങളുടെ ശരിയായ ക്രമം ഏതാണ്? + + + +### 3. 🤗 Accelerate ലൈബ്രറി പ്രധാനമായും എന്തിനാണ് സഹായിക്കുന്നത്? + + + +### 4. ഒരു ട്രെയിനിംഗ് ലൂപ്പിൽ ബാച്ചുകളെ നമ്മൾ ഡിവൈസിലേക്ക് മാറ്റുന്നത് എന്തുകൊണ്ട്? + + + +### 5. ഇവാലുവേഷന് മുമ്പ് `model.eval()` എന്താണ് ചെയ്യുന്നത്? + + + +### 6. ഇവാലുവേഷൻ സമയത്ത് `torch.no_grad()`-ന്റെ ഉദ്ദേശ്യം എന്താണ്? + + + +### 7. നിങ്ങളുടെ ട്രെയിനിംഗ് ലൂപ്പിൽ 🤗 Accelerate ഉപയോഗിക്കുമ്പോൾ എന്താണ് മാറുന്നത്? + + + +> [!TIP] +> 💡 **പ്രധാന പാഠങ്ങൾ:** +> - മാനുവൽ ട്രെയിനിംഗ് ലൂപ്പുകൾ നിങ്ങൾക്ക് പൂർണ്ണ നിയന്ത്രണം നൽകുന്നു, എന്നാൽ ശരിയായ ക്രമം മനസ്സിലാക്കേണ്ടതുണ്ട്: ഫോർവേഡ് → ബാക്ക്‌വേഡ് → ഒപ്‌റ്റിമൈസർ സ്‌റ്റെപ്പ് → ഷെഡ്യൂളർ സ്‌റ്റെപ്പ് → ഗ്രേഡിയന്റുകൾ പൂജ്യമാക്കുക +> - transformer മോഡലുകൾക്ക് ശുപാർശ ചെയ്യുന്ന ഒപ്‌റ്റിമൈസർ വെയ്‌റ്റ് ഡികേയോടുകൂടിയ AdamW ആണ് +> - ശരിയായ പെരുമാറ്റത്തിനും കാര്യക്ഷമതയ്ക്കും ഇവാലുവേഷൻ സമയത്ത് എപ്പോഴും `model.eval()`, `torch.no_grad()` എന്നിവ ഉപയോഗിക്കുക +> - കുറഞ്ഞ കോഡ് മാറ്റങ്ങളോടെ ഡിസ്‌ട്രിബ്യൂട്ടഡ് ട്രെയിനിംഗ് 🤗 Accelerate എളുപ്പത്തിൽ ലഭ്യമാക്കുന്നു +> - PyTorch ഓപ്പറേഷനുകൾക്ക് ഡിവൈസ് മാനേജ്‌മെന്റ് (ടെൻസറുകളെ GPU/CPU-വിലേക്ക് മാറ്റുന്നത്) നിർണ്ണായകമാണ് +> - മിക്‌സഡ് പ്രിസിഷൻ, ഗ്രേഡിയന്റ് അക്യുമുലേഷൻ, ഗ്രേഡിയന്റ് ക്ലിപ്പിംഗ് പോലുള്ള ആധുനിക സങ്കേതങ്ങൾ ട്രെയിനിംഗ് കാര്യക്ഷമത ഗണ്യമായി മെച്ചപ്പെടുത്തും diff --git a/chapters/ml/chapter3/5.mdx b/chapters/ml/chapter3/5.mdx new file mode 100644 index 000000000..cb94bb470 --- /dev/null +++ b/chapters/ml/chapter3/5.mdx @@ -0,0 +1,408 @@ +# ലേണിംഗ് കർവുകൾ മനസ്സിലാക്കുന്നു[[understanding-learning-curves]] + + + +`Trainer` API ഉപയോഗിച്ചും കസ്‌റ്റം ട്രെയിനിംഗ് ലൂപ്പുകൾ ഉപയോഗിച്ചും ഫൈൻ-ട്യൂണിംഗ് എങ്ങനെ നടപ്പിലാക്കാം എന്ന് ഇപ്പോൾ നിങ്ങൾ പഠിച്ചുകഴിഞ്ഞു; അതിനാൽ ആ ഫലങ്ങൾ എങ്ങനെ വ്യാഖ്യാനിക്കണം എന്ന് മനസ്സിലാക്കുന്നത് വളരെ പ്രധാനമാണ്. ട്രെയിനിംഗ് സമയത്ത് നിങ്ങളുടെ മോഡലിന്റെ പ്രകടനം വിലയിരുത്താനും, പ്രകടനം കുറയ്ക്കുന്നതിന് മുമ്പ് തന്നെ സാധ്യമായ പ്രശ്നങ്ങൾ തിരിച്ചറിയാനും സഹായിക്കുന്ന അമൂല്യമായ ടൂളുകളാണ് ലേണിംഗ് കർവുകൾ (learning curves). + +ഈ ഭാഗത്തിൽ, അക്യുറസി (accuracy) കർവുകളും ലോസ് (loss) കർവുകളും എങ്ങനെ വായിക്കാമെന്നും വ്യാഖ്യാനിക്കാമെന്നും നമ്മൾ പരിശോധിക്കും; വ്യത്യസ്ത കർവ് ആകൃതികൾ നമ്മുടെ മോഡലിന്റെ പെരുമാറ്റത്തെക്കുറിച്ച് എന്താണ് പറയുന്നതെന്ന് മനസ്സിലാക്കും; സാധാരണ ട്രെയിനിംഗ് പ്രശ്നങ്ങൾ എങ്ങനെ പരിഹരിക്കാമെന്നും പഠിക്കും. + +## ലേണിംഗ് കർവുകൾ എന്താണ്?[[what-are-learning-curves]] + +ട്രെയിനിംഗ് സമയത്ത് കാലക്രമേണ നിങ്ങളുടെ മോഡലിന്റെ പ്രകടന മെട്രിക്കുകൾ എങ്ങനെ മാറുന്നു എന്നതിന്റെ ദൃശ്യ പ്രതിനിധാനങ്ങളാണ് ലേണിംഗ് കർവുകൾ. നിരീക്ഷിക്കേണ്ട ഏറ്റവും പ്രധാനപ്പെട്ട രണ്ട് കർവുകൾ ഇവയാണ്: + +- **ലോസ് കർവുകൾ**: ട്രെയിനിംഗ് സ്‌റ്റെപ്പുകളിലൂടെയോ എപ്പോക്കുകളിലൂടെയോ (epochs) മോഡലിന്റെ പിഴവ് (ലോസ്) എങ്ങനെ മാറുന്നു എന്ന് കാണിക്കുന്നു +- **അക്യുറസി കർവുകൾ**: ട്രെയിനിംഗ് സ്‌റ്റെപ്പുകളിലൂടെയോ എപ്പോക്കുകളിലൂടെയോ ശരിയായ പ്രവചനങ്ങളുടെ ശതമാനം എങ്ങനെ മാറുന്നു എന്ന് കാണിക്കുന്നു + +നമ്മുടെ മോഡൽ ഫലപ്രദമായി പഠിക്കുന്നുണ്ടോ എന്ന് മനസ്സിലാക്കാൻ ഈ കർവുകൾ നമ്മെ സഹായിക്കുന്നു; പ്രകടനം മെച്ചപ്പെടുത്താൻ എന്തൊക്കെ മാറ്റങ്ങൾ വരുത്തണം എന്നതിലും ഇവ നമുക്ക് വഴികാട്ടിയാകും. Transformers-ൽ, ഈ മെട്രിക്കുകൾ ഓരോ ബാച്ചിനും വെവ്വേറെ കണക്കാക്കി ഡിസ്‌കിലേക്ക് ലോഗ് ചെയ്യുന്നു. തുടർന്ന്, ഈ കർവുകൾ ദൃശ്യവത്കരിക്കാനും കാലക്രമേണ നമ്മുടെ മോഡലിന്റെ പ്രകടനം ട്രാക്ക് ചെയ്യാനും [Weights & Biases](https://wandb.ai/) പോലുള്ള ലൈബ്രറികൾ നമുക്ക് ഉപയോഗിക്കാം. + +### ലോസ് കർവുകൾ[[loss-curves]] + +കാലക്രമേണ മോഡലിന്റെ പിഴവ് എങ്ങനെ കുറയുന്നു എന്ന് ലോസ് കർവ് കാണിക്കുന്നു. വിജയകരമായ ഒരു സാധാരണ ട്രെയിനിംഗ് റണ്ണിൽ, താഴെ കാണുന്നതിന് സമാനമായ ഒരു കർവ് നിങ്ങൾ കാണും: + +![ലോസ് കർവ്](https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter3/1.png) + +- **ഉയർന്ന പ്രാരംഭ ലോസ്**: ഒപ്‌ടിമൈസേഷൻ ഒന്നും ഇല്ലാതെയാണ് മോഡൽ തുടങ്ങുന്നത്, അതിനാൽ തുടക്കത്തിൽ പ്രവചനങ്ങൾ മോശമായിരിക്കും +- **കുറഞ്ഞുവരുന്ന ലോസ്**: ട്രെയിനിംഗ് പുരോഗമിക്കുമ്പോൾ, ലോസ് പൊതുവെ കുറയണം +- **കൺവർജൻസ് (convergence)**: ഒടുവിൽ, ലോസ് ഒരു താഴ്ന്ന മൂല്യത്തിൽ സ്ഥിരത കൈവരിക്കുന്നു; ഡേറ്റയിലെ പാറ്റേണുകൾ മോഡൽ പഠിച്ചു എന്നാണ് ഇത് സൂചിപ്പിക്കുന്നത് + +മുൻ അധ്യായങ്ങളിലേതുപോലെ, ഈ മെട്രിക്കുകൾ ട്രാക്ക് ചെയ്യാനും ഒരു ഡാഷ്‌ബോർഡിൽ ദൃശ്യവത്കരിക്കാനും `Trainer` API നമുക്ക് ഉപയോഗിക്കാം. Weights & Biases ഉപയോഗിച്ച് ഇത് എങ്ങനെ ചെയ്യാം എന്നതിന്റെ ഒരു ഉദാഹരണം താഴെ കൊടുക്കുന്നു. + +```python +# Example of tracking loss during training with the Trainer +from transformers import Trainer, TrainingArguments +import wandb + +# Initialize Weights & Biases for experiment tracking +wandb.init(project="transformer-fine-tuning", name="bert-mrpc-analysis") + +training_args = TrainingArguments( + output_dir="./results", + eval_strategy="steps", + eval_steps=50, + save_steps=100, + logging_steps=10, # Log metrics every 10 steps + num_train_epochs=3, + per_device_train_batch_size=16, + per_device_eval_batch_size=16, + report_to="wandb", # Send logs to Weights & Biases +) + +trainer = Trainer( + model=model, + args=training_args, + train_dataset=tokenized_datasets["train"], + eval_dataset=tokenized_datasets["validation"], + data_collator=data_collator, + processing_class=tokenizer, + compute_metrics=compute_metrics, +) + +# Train and automatically log metrics +trainer.train() +``` + +### അക്യുറസി കർവുകൾ[[accuracy-curves]] + +കാലക്രമേണ ശരിയായ പ്രവചനങ്ങളുടെ ശതമാനം എങ്ങനെ മാറുന്നു എന്ന് അക്യുറസി കർവ് കാണിക്കുന്നു. ലോസ് കർവുകളിൽ നിന്ന് വ്യത്യസ്തമായി, മോഡൽ പഠിക്കുന്നതിനനുസരിച്ച് അക്യുറസി കർവുകൾ പൊതുവെ ഉയരണം; സാധാരണയായി ലോസ് കർവിനെക്കാൾ കൂടുതൽ സ്‌റ്റെപ്പുകൾ ഇവയിൽ ഉൾപ്പെടാം. + +![അക്യുറസി കർവ്](https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter3/2.png) + +- **താഴ്ന്ന നിലയിൽ തുടങ്ങുന്നു**: ഡേറ്റയിലെ പാറ്റേണുകൾ മോഡൽ ഇതുവരെ പഠിച്ചിട്ടില്ലാത്തതിനാൽ, പ്രാരംഭ അക്യുറസി താഴ്ന്നതായിരിക്കും +- **ട്രെയിനിംഗിനൊപ്പം ഉയരുന്നു**: ഡേറ്റയിലെ പാറ്റേണുകൾ പഠിക്കാൻ മോഡലിന് കഴിയുന്നുണ്ടെങ്കിൽ, അത് പഠിക്കുന്നതിനനുസരിച്ച് അക്യുറസി പൊതുവെ മെച്ചപ്പെടണം +- **പ്ലേറ്റോകൾ (plateaus) കാണിക്കാം**: മോഡൽ ശരിയായ ലേബലുകളോട് അടുത്ത പ്രവചനങ്ങൾ നടത്തുമ്പോൾ, അക്യുറസി പലപ്പോഴും സുഗമമായി ഉയരുന്നതിന് പകരം വേറിട്ട കുതിപ്പുകളായാണ് (discrete jumps) ഉയരുന്നത് + +> [!TIP] +> 💡 **അക്യുറസി കർവുകൾ എന്തുകൊണ്ട് "പടിപടിയായി" (steppy) കാണപ്പെടുന്നു**: തുടർച്ചയായ (continuous) ഒരു അളവായ ലോസിൽ നിന്ന് വ്യത്യസ്തമായി, അക്യുറസി കണക്കാക്കുന്നത് വേറിട്ട (discrete) പ്രവചനങ്ങളെ ശരിയായ ലേബലുകളുമായി താരതമ്യം ചെയ്താണ്. മോഡലിന്റെ ആത്മവിശ്വാസത്തിലെ (confidence) ചെറിയ പുരോഗതികൾ അന്തിമ പ്രവചനത്തെ മാറ്റണമെന്നില്ല; അതിനാൽ ഒരു പരിധി (threshold) കടക്കുന്നതുവരെ അക്യുറസി മാറ്റമില്ലാതെ തുടരുന്നു. + +### കൺവർജൻസ്[[convergence]] + +മോഡലിന്റെ പ്രകടനം സ്ഥിരത കൈവരിക്കുകയും ലോസ്, അക്യുറസി കർവുകൾ നിരപ്പാകുകയും ചെയ്യുമ്പോഴാണ് കൺവർജൻസ് സംഭവിക്കുന്നത്. ഡേറ്റയിലെ പാറ്റേണുകൾ മോഡൽ പഠിച്ചുവെന്നും അത് ഉപയോഗിക്കാൻ തയ്യാറാണെന്നും ഇത് സൂചിപ്പിക്കുന്നു. ലളിതമായി പറഞ്ഞാൽ, ഓരോ തവണ ട്രെയിൻ ചെയ്യുമ്പോഴും മോഡൽ സ്ഥിരമായ ഒരു പ്രകടനത്തിലേക്ക് കൺവർജ് ചെയ്യണം എന്നതാണ് നമ്മുടെ ലക്ഷ്യം. + +![കൺവർജൻസ്](https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter3/4.png) + +മോഡലുകൾ കൺവർജ് ചെയ്തുകഴിഞ്ഞാൽ, പുതിയ ഡേറ്റയിൽ പ്രവചനങ്ങൾ നടത്താൻ നമുക്ക് അവ ഉപയോഗിക്കാം; മോഡൽ എത്ര നന്നായി പ്രവർത്തിക്കുന്നു എന്ന് മനസ്സിലാക്കാൻ ഇവാലുവേഷൻ മെട്രിക്കുകൾ പരിശോധിക്കുകയും ചെയ്യാം. + +## ലേണിംഗ് കർവ് പാറ്റേണുകൾ വ്യാഖ്യാനിക്കുന്നു[[interpreting-learning-curve-patterns]] + +വ്യത്യസ്ത കർവ് ആകൃതികൾ നിങ്ങളുടെ മോഡലിന്റെ ട്രെയിനിംഗിന്റെ വ്യത്യസ്ത വശങ്ങൾ വെളിപ്പെടുത്തുന്നു. ഏറ്റവും സാധാരണമായ പാറ്റേണുകളും അവയുടെ അർത്ഥവും നമുക്ക് പരിശോധിക്കാം. + +### ആരോഗ്യകരമായ ലേണിംഗ് കർവുകൾ[[healthy-learning-curves]] + +നന്നായി നടക്കുന്ന ഒരു ട്രെയിനിംഗ് റൺ സാധാരണയായി താഴെ കാണുന്നതിന് സമാനമായ കർവ് ആകൃതികൾ കാണിക്കും: + +![ആരോഗ്യകരമായ ലോസ് കർവ്](https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter3/5.png) + +മുകളിലെ ചിത്രം നോക്കാം. ഇത് ലോസ് കർവും (ഇടതുവശത്ത്) അതിനോട് ബന്ധപ്പെട്ട അക്യുറസി കർവും (വലതുവശത്ത്) കാണിക്കുന്നു. ഈ കർവുകൾക്ക് വ്യത്യസ്തമായ സവിശേഷതകളുണ്ട്. + +കാലക്രമേണ മോഡലിന്റെ ലോസ് മൂല്യം എങ്ങനെ മാറുന്നു എന്ന് ലോസ് കർവ് കാണിക്കുന്നു. തുടക്കത്തിൽ ലോസ് ഉയർന്നതാണ്, പിന്നീട് അത് ക്രമേണ കുറയുന്നു; മോഡൽ മെച്ചപ്പെടുന്നു എന്നാണ് ഇത് സൂചിപ്പിക്കുന്നത്. പ്രവചിച്ച ഔട്ട്‌പുട്ടും യഥാർത്ഥ ഔട്ട്‌പുട്ടും തമ്മിലുള്ള പിഴവാണ് ലോസ് പ്രതിനിധീകരിക്കുന്നത് എന്നതിനാൽ, ലോസ് മൂല്യം കുറയുന്നത് മോഡൽ മികച്ച പ്രവചനങ്ങൾ നടത്തുന്നു എന്നതിന്റെ സൂചനയാണ്. + +ഇനി നമ്മുടെ ശ്രദ്ധ അക്യുറസി കർവിലേക്ക് തിരിക്കാം. കാലക്രമേണ മോഡലിന്റെ അക്യുറസി എങ്ങനെ മാറുന്നു എന്നാണ് ഇത് കാണിക്കുന്നത്. അക്യുറസി കർവ് താഴ്ന്ന ഒരു മൂല്യത്തിൽ തുടങ്ങി, ട്രെയിനിംഗ് പുരോഗമിക്കുന്നതിനനുസരിച്ച് ഉയരുന്നു. ശരിയായി വർഗ്ഗീകരിച്ച ഉദാഹരണങ്ങളുടെ അനുപാതമാണ് അക്യുറസി അളക്കുന്നത്. അതിനാൽ, അക്യുറസി കർവ് ഉയരുമ്പോൾ, മോഡൽ കൂടുതൽ ശരിയായ പ്രവചനങ്ങൾ നടത്തുന്നു എന്നാണ് അർത്ഥം. + +ഈ കർവുകൾ തമ്മിലുള്ള ശ്രദ്ധേയമായ ഒരു വ്യത്യാസം, അവയുടെ സുഗമതയും അക്യുറസി കർവിലെ "പ്ലേറ്റോകളുടെ" സാന്നിധ്യവുമാണ്. ലോസ് സുഗമമായി കുറയുമ്പോൾ, അക്യുറസി കർവിലെ പ്ലേറ്റോകൾ സൂചിപ്പിക്കുന്നത് അക്യുറസി തുടർച്ചയായി ഉയരുന്നതിന് പകരം വേറിട്ട കുതിപ്പുകളായി ഉയരുന്നു എന്നാണ്. അക്യുറസി അളക്കുന്ന രീതിയാണ് ഈ പെരുമാറ്റത്തിന് കാരണം. അന്തിമ പ്രവചനം ഇപ്പോഴും തെറ്റാണെങ്കിലും, മോഡലിന്റെ ഔട്ട്‌പുട്ട് ലക്ഷ്യത്തോട് കൂടുതൽ അടുക്കുമ്പോൾ ലോസ് മെച്ചപ്പെടാം. എന്നാൽ അക്യുറസി മെച്ചപ്പെടുന്നത്, പ്രവചനം ശരിയാകാനുള്ള പരിധി കടക്കുമ്പോൾ മാത്രമാണ്. + +ഉദാഹരണത്തിന്, പൂച്ചകളെ (0) നായ്ക്കളിൽ (1) നിന്ന് വേർതിരിക്കുന്ന ഒരു ബൈനറി ക്ലാസിഫയറിൽ, ഒരു നായയുടെ ചിത്രത്തിന് (യഥാർത്ഥ മൂല്യം 1) മോഡൽ 0.3 എന്ന് പ്രവചിച്ചാൽ, അത് 0 ആയി റൗണ്ട് ചെയ്യപ്പെടുകയും തെറ്റായ വർഗ്ഗീകരണമാകുകയും ചെയ്യുന്നു. അടുത്ത സ്‌റ്റെപ്പിൽ അത് 0.4 എന്ന് പ്രവചിച്ചാലും, അപ്പോഴും തെറ്റാണ്. 0.3-നെക്കാൾ 0.4 ആണ് 1-നോട് അടുത്തത് എന്നതിനാൽ ലോസ് കുറഞ്ഞിട്ടുണ്ടാകും, എന്നാൽ അക്യുറസി മാറ്റമില്ലാതെ തുടരുന്നു — ഇതാണ് ഒരു പ്ലേറ്റോ ഉണ്ടാക്കുന്നത്. 1 ആയി റൗണ്ട് ചെയ്യപ്പെടുന്ന, 0.5-ൽ കൂടുതലുള്ള ഒരു മൂല്യം മോഡൽ പ്രവചിക്കുമ്പോൾ മാത്രമേ അക്യുറസി മുകളിലേക്ക് കുതിക്കുകയുള്ളൂ. + +> [!TIP] +> **ആരോഗ്യകരമായ കർവുകളുടെ സവിശേഷതകൾ:** +> - **ലോസിലെ സുഗമമായ കുറവ്**: ട്രെയിനിംഗ് ലോസും വാലിഡേഷൻ ലോസും സ്ഥിരമായി കുറയുന്നു +> - **ട്രെയിനിംഗ്/വാലിഡേഷൻ പ്രകടനങ്ങൾ അടുത്തടുത്ത്**: ട്രെയിനിംഗ്, വാലിഡേഷൻ മെട്രിക്കുകൾ തമ്മിൽ ചെറിയ വിടവ് മാത്രം +> - **കൺവർജൻസ്**: കർവുകൾ നിരപ്പാകുന്നു; മോഡൽ പാറ്റേണുകൾ പഠിച്ചു എന്ന് ഇത് സൂചിപ്പിക്കുന്നു + +### പ്രായോഗിക ഉദാഹരണങ്ങൾ[[practical-examples]] + +ലേണിംഗ് കർവുകളുടെ ചില പ്രായോഗിക ഉദാഹരണങ്ങൾ നമുക്ക് പരിശോധിക്കാം. ആദ്യം, ട്രെയിനിംഗ് സമയത്ത് ലേണിംഗ് കർവുകൾ നിരീക്ഷിക്കാനുള്ള ചില രീതികൾ നമ്മൾ എടുത്തുകാണിക്കും. അതിനു താഴെ, ലേണിംഗ് കർവുകളിൽ കാണാൻ കഴിയുന്ന വ്യത്യസ്ത പാറ്റേണുകൾ നമ്മൾ വിശദമായി പരിശോധിക്കും. + +#### ട്രെയിനിംഗ് സമയത്ത്[[during-training]] + +ട്രെയിനിംഗ് പ്രോസസ്സിനിടയിൽ (`trainer.train()` റൺ ചെയ്തതിന് ശേഷം), ഈ പ്രധാന സൂചകങ്ങൾ നിങ്ങൾക്ക് നിരീക്ഷിക്കാം: + +1. **ലോസ് കൺവർജൻസ്**: ലോസ് ഇപ്പോഴും കുറയുന്നുണ്ടോ, അതോ ഒരു പ്ലേറ്റോയിൽ എത്തിയോ? +2. **ഓവർഫിറ്റിംഗിന്റെ (overfitting) ലക്ഷണങ്ങൾ**: ട്രെയിനിംഗ് ലോസ് കുറയുമ്പോൾ വാലിഡേഷൻ ലോസ് ഉയരാൻ തുടങ്ങുന്നുണ്ടോ? +3. **ലേണിംഗ് റേറ്റ്**: കർവുകൾ അമിതമായി ചാഞ്ചാടുന്നുണ്ടോ (LR വളരെ ഉയർന്നത്), അതോ അമിതമായി പരന്നതാണോ (LR വളരെ താഴ്ന്നത്)? +4. **സ്ഥിരത**: പ്രശ്നങ്ങളെ സൂചിപ്പിക്കുന്ന പെട്ടെന്നുള്ള കുതിപ്പുകളോ വീഴ്ചകളോ ഉണ്ടോ? + +#### ട്രെയിനിംഗിന് ശേഷം[[after-training]] + +ട്രെയിനിംഗ് പ്രോസസ്സ് പൂർത്തിയായ ശേഷം, മോഡലിന്റെ പ്രകടനം മനസ്സിലാക്കാൻ പൂർണ്ണമായ കർവുകൾ നിങ്ങൾക്ക് വിശകലനം ചെയ്യാം. + +1. **അന്തിമ പ്രകടനം**: മോഡൽ സ്വീകാര്യമായ പ്രകടന നിലവാരത്തിൽ എത്തിയോ? +2. **കാര്യക്ഷമത**: കുറച്ച് എപ്പോക്കുകൾ കൊണ്ട് അതേ പ്രകടനം നേടാൻ കഴിയുമായിരുന്നോ? +3. **ജനറലൈസേഷൻ (generalization)**: ട്രെയിനിംഗ്, വാലിഡേഷൻ പ്രകടനങ്ങൾ എത്രത്തോളം അടുത്താണ്? +4. **പ്രവണതകൾ**: കൂടുതൽ ട്രെയിനിംഗ് നടത്തിയാൽ പ്രകടനം മെച്ചപ്പെടാൻ സാധ്യതയുണ്ടോ? + +> [!TIP] +> 🔍 **W&B ഡാഷ്‌ബോർഡ് സവിശേഷതകൾ**: നിങ്ങളുടെ ലേണിംഗ് കർവുകളുടെ മനോഹരവും ഇന്ററാക്‌ടീവുമായ പ്ലോട്ടുകൾ Weights & Biases സ്വയമേവ സൃഷ്ടിക്കുന്നു. നിങ്ങൾക്ക് ചെയ്യാവുന്നത്: +> - ഒന്നിലധികം റണ്ണുകൾ അടുത്തടുത്ത് വെച്ച് താരതമ്യം ചെയ്യുക +> - കസ്‌റ്റം മെട്രിക്കുകളും വിഷ്വലൈസേഷനുകളും ചേർക്കുക +> - അസാധാരണമായ പെരുമാറ്റങ്ങൾക്ക് അലേർട്ടുകൾ സജ്ജീകരിക്കുക +> - ഫലങ്ങൾ നിങ്ങളുടെ ടീമുമായി പങ്കുവെക്കുക +> +> കൂടുതലറിയാൻ [Weights & Biases ഡോക്യുമെന്റേഷൻ](https://docs.wandb.ai/) കാണുക. + +#### ഓവർഫിറ്റിംഗ്[[overfitting]] + +ട്രെയിനിംഗ് ഡേറ്റയിൽ നിന്ന് മോഡൽ അമിതമായി പഠിക്കുകയും, വ്യത്യസ്ത ഡേറ്റയിലേക്ക് (വാലിഡേഷൻ സെറ്റ് പ്രതിനിധീകരിക്കുന്നത്) ജനറലൈസ് ചെയ്യാൻ കഴിയാതെ വരികയും ചെയ്യുമ്പോഴാണ് ഓവർഫിറ്റിംഗ് സംഭവിക്കുന്നത്. + +![ഓവർഫിറ്റിംഗ്](https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter3/10.png) + +**ലക്ഷണങ്ങൾ:** + +- ട്രെയിനിംഗ് ലോസ് കുറഞ്ഞുകൊണ്ടിരിക്കുമ്പോൾ വാലിഡേഷൻ ലോസ് ഉയരുകയോ ഒരു പ്ലേറ്റോയിൽ എത്തുകയോ ചെയ്യുന്നു +- ട്രെയിനിംഗ് അക്യുറസിയും വാലിഡേഷൻ അക്യുറസിയും തമ്മിൽ വലിയ വിടവ് +- വാലിഡേഷൻ അക്യുറസിയെക്കാൾ ട്രെയിനിംഗ് അക്യുറസി വളരെ ഉയർന്നത് + +**ഓവർഫിറ്റിംഗിനുള്ള പരിഹാരങ്ങൾ:** +- **റെഗുലറൈസേഷൻ (regularization)**: ഡ്രോപ്പ്ഔട്ട്, വെയ്‌റ്റ് ഡികേ, അല്ലെങ്കിൽ മറ്റ് റെഗുലറൈസേഷൻ ടെക്‌നിക്കുകൾ ചേർക്കുക +- **എർലി സ്‌റ്റോപ്പിംഗ് (early stopping)**: വാലിഡേഷൻ പ്രകടനം മെച്ചപ്പെടാതെ വരുമ്പോൾ ട്രെയിനിംഗ് നിർത്തുക +- **ഡേറ്റ ഓഗ്‌മെന്റേഷൻ (data augmentation)**: ട്രെയിനിംഗ് ഡേറ്റയുടെ വൈവിധ്യം കൂട്ടുക +- **മോഡലിന്റെ സങ്കീർണ്ണത കുറയ്ക്കുക**: ചെറിയ ഒരു മോഡലോ കുറച്ച് പാരാമീറ്ററുകളോ ഉപയോഗിക്കുക + +താഴെയുള്ള ഉദാഹരണത്തിൽ, ഓവർഫിറ്റിംഗ് തടയാൻ നമ്മൾ എർലി സ്‌റ്റോപ്പിംഗ് ഉപയോഗിക്കുന്നു. `early_stopping_patience` നമ്മൾ 3 ആയി സെറ്റ് ചെയ്യുന്നു; അതായത്, തുടർച്ചയായ 3 എപ്പോക്കുകളിൽ വാലിഡേഷൻ ലോസ് മെച്ചപ്പെട്ടില്ലെങ്കിൽ ട്രെയിനിംഗ് നിർത്തും. + +```python +# Example of detecting overfitting with early stopping +from transformers import EarlyStoppingCallback + +training_args = TrainingArguments( + output_dir="./results", + eval_strategy="steps", + eval_steps=100, + save_strategy="steps", + save_steps=100, + load_best_model_at_end=True, + metric_for_best_model="eval_loss", + greater_is_better=False, + num_train_epochs=10, # Set high, but we'll stop early +) + +# Add early stopping to prevent overfitting +trainer = Trainer( + model=model, + args=training_args, + train_dataset=tokenized_datasets["train"], + eval_dataset=tokenized_datasets["validation"], + data_collator=data_collator, + processing_class=tokenizer, + compute_metrics=compute_metrics, + callbacks=[EarlyStoppingCallback(early_stopping_patience=3)], +) +``` + +#### 2. അണ്ടർഫിറ്റിംഗ്[[underfitting]] + +ഡേറ്റയിലെ അടിസ്ഥാന പാറ്റേണുകൾ പിടിച്ചെടുക്കാൻ കഴിയാത്തവിധം മോഡൽ വളരെ ലളിതമാകുമ്പോഴാണ് അണ്ടർഫിറ്റിംഗ് (underfitting) സംഭവിക്കുന്നത്. ഇത് പല കാരണങ്ങളാൽ സംഭവിക്കാം: + +- മോഡൽ വളരെ ചെറുതാണ്, അല്ലെങ്കിൽ പാറ്റേണുകൾ പഠിക്കാനുള്ള ശേഷി (capacity) അതിനില്ല +- ലേണിംഗ് റേറ്റ് വളരെ താഴ്ന്നതാണ്, അതിനാൽ പഠനം മന്ദഗതിയിലാകുന്നു +- ഡേറ്റാസെറ്റ് വളരെ ചെറുതാണ്, അല്ലെങ്കിൽ പ്രശ്നത്തെ ശരിയായി പ്രതിനിധീകരിക്കുന്നില്ല +- മോഡൽ ശരിയായി റെഗുലറൈസ് ചെയ്തിട്ടില്ല + +![അണ്ടർഫിറ്റിംഗ്](https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter3/7.png) + +**ലക്ഷണങ്ങൾ:** +- ട്രെയിനിംഗ് ലോസും വാലിഡേഷൻ ലോസും ഉയർന്നുതന്നെ നിൽക്കുന്നു +- ട്രെയിനിംഗിന്റെ തുടക്കത്തിൽ തന്നെ മോഡലിന്റെ പ്രകടനം ഒരു പ്ലേറ്റോയിൽ എത്തുന്നു +- ട്രെയിനിംഗ് അക്യുറസി പ്രതീക്ഷിച്ചതിലും താഴ്ന്നതാണ് + +**അണ്ടർഫിറ്റിംഗിനുള്ള പരിഹാരങ്ങൾ:** +- **മോഡലിന്റെ ശേഷി കൂട്ടുക**: വലിയ ഒരു മോഡലോ കൂടുതൽ പാരാമീറ്ററുകളോ ഉപയോഗിക്കുക +- **കൂടുതൽ സമയം ട്രെയിൻ ചെയ്യുക**: എപ്പോക്കുകളുടെ എണ്ണം കൂട്ടുക +- **ലേണിംഗ് റേറ്റ് ക്രമീകരിക്കുക**: വ്യത്യസ്ത ലേണിംഗ് റേറ്റുകൾ പരീക്ഷിക്കുക +- **ഡേറ്റയുടെ ഗുണനിലവാരം പരിശോധിക്കുക**: നിങ്ങളുടെ ഡേറ്റ ശരിയായി പ്രീപ്രോസസ്സ് ചെയ്തിട്ടുണ്ടെന്ന് ഉറപ്പാക്കുക + +താഴെയുള്ള ഉദാഹരണത്തിൽ, ഡേറ്റയിലെ പാറ്റേണുകൾ മോഡലിന് പഠിക്കാൻ കഴിയുമോ എന്ന് കാണാൻ നമ്മൾ കൂടുതൽ എപ്പോക്കുകൾ ട്രെയിൻ ചെയ്യുന്നു. + +```python +from transformers import TrainingArguments + +training_args = TrainingArguments( + output_dir="./results", + -num_train_epochs=5, + +num_train_epochs=10, +) +``` + +#### 3. ചാഞ്ചാടുന്ന ലേണിംഗ് കർവുകൾ[[erratic-learning-curves]] + +മോഡൽ ഫലപ്രദമായി പഠിക്കാത്തപ്പോഴാണ് ചാഞ്ചാടുന്ന (erratic) ലേണിംഗ് കർവുകൾ ഉണ്ടാകുന്നത്. ഇത് പല കാരണങ്ങളാൽ സംഭവിക്കാം: + +- ലേണിംഗ് റേറ്റ് വളരെ ഉയർന്നതാണ്, അതിനാൽ മോഡൽ ഒപ്‌ടിമൽ പാരാമീറ്ററുകളെ മറികടന്നുപോകുന്നു (overshoot) +- ബാച്ച് സൈസ് വളരെ ചെറുതാണ്, അതിനാൽ മോഡൽ മന്ദഗതിയിൽ പഠിക്കുന്നു +- മോഡൽ ശരിയായി റെഗുലറൈസ് ചെയ്തിട്ടില്ല, അതിനാൽ അത് ട്രെയിനിംഗ് ഡേറ്റയിലേക്ക് ഓവർഫിറ്റ് ചെയ്യുന്നു +- ഡേറ്റാസെറ്റ് ശരിയായി പ്രീപ്രോസസ്സ് ചെയ്തിട്ടില്ല, അതിനാൽ മോഡൽ നോയ്‌സിൽ (noise) നിന്ന് പഠിക്കുന്നു + +![ചാഞ്ചാടുന്ന ലേണിംഗ് കർവുകൾ](https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter3/3.png) + +**ലക്ഷണങ്ങൾ:** +- ലോസിലോ അക്യുറസിയിലോ ഇടയ്ക്കിടെയുള്ള ചാഞ്ചാട്ടങ്ങൾ +- കർവുകൾ ഉയർന്ന വേരിയൻസോ അസ്ഥിരതയോ കാണിക്കുന്നു +- വ്യക്തമായ പ്രവണതയില്ലാതെ പ്രകടനം മുകളിലേക്കും താഴേക്കും ആടുന്നു + +ട്രെയിനിംഗ് കർവും വാലിഡേഷൻ കർവും ചാഞ്ചാടുന്ന പെരുമാറ്റം കാണിക്കുന്നു. + +![ചാഞ്ചാടുന്ന ലേണിംഗ് കർവുകൾ](https://huggingface.co/datasets/huggingface-course/documentation-images/resolve/main/en/chapter3/9.png) + +**ചാഞ്ചാടുന്ന കർവുകൾക്കുള്ള പരിഹാരങ്ങൾ:** +- **ലേണിംഗ് റേറ്റ് കുറയ്ക്കുക**: കൂടുതൽ സ്ഥിരതയുള്ള ട്രെയിനിംഗിനായി സ്‌റ്റെപ്പ് സൈസ് കുറയ്ക്കുക +- **ബാച്ച് സൈസ് കൂട്ടുക**: വലിയ ബാച്ചുകൾ കൂടുതൽ സ്ഥിരതയുള്ള ഗ്രേഡിയന്റുകൾ നൽകുന്നു +- **ഗ്രേഡിയന്റ് ക്ലിപ്പിംഗ് (gradient clipping)**: ഗ്രേഡിയന്റുകൾ അമിതമായി വളരുന്നത് (exploding gradients) തടയുക +- **മികച്ച ഡേറ്റ പ്രീപ്രോസസ്സിംഗ്**: ഡേറ്റയുടെ ഗുണനിലവാരം ഏകീകൃതമാണെന്ന് ഉറപ്പാക്കുക + +താഴെയുള്ള ഉദാഹരണത്തിൽ, നമ്മൾ ലേണിംഗ് റേറ്റ് കുറയ്ക്കുകയും ബാച്ച് സൈസ് കൂട്ടുകയും ചെയ്യുന്നു. + +```python +from transformers import TrainingArguments + +training_args = TrainingArguments( + output_dir="./results", + -learning_rate=1e-5, + +learning_rate=1e-4, + -per_device_train_batch_size=16, + +per_device_train_batch_size=32, +) +``` + +## പ്രധാന പാഠങ്ങൾ[[key-takeaways]] + +ഫലപ്രദമായ ഒരു മെഷീൻ ലേണിംഗ് പ്രാക്‌ടീഷണറാകാൻ ലേണിംഗ് കർവുകൾ മനസ്സിലാക്കുന്നത് അത്യാവശ്യമാണ്. നിങ്ങളുടെ മോഡലിന്റെ ട്രെയിനിംഗ് പുരോഗതിയെക്കുറിച്ച് ഈ ദൃശ്യ ടൂളുകൾ തത്സമയ ഫീഡ്‌ബാക്ക് നൽകുന്നു; എപ്പോൾ ട്രെയിനിംഗ് നിർത്തണം, ഹൈപ്പർപാരാമീറ്ററുകൾ എപ്പോൾ ക്രമീകരിക്കണം, അല്ലെങ്കിൽ എപ്പോൾ വ്യത്യസ്ത സമീപനങ്ങൾ പരീക്ഷിക്കണം എന്നതിനെക്കുറിച്ച് അറിവോടെയുള്ള തീരുമാനങ്ങൾ എടുക്കാൻ ഇവ നിങ്ങളെ സഹായിക്കുന്നു. പരിശീലനത്തിലൂടെ, ആരോഗ്യകരമായ ലേണിംഗ് കർവുകൾ എങ്ങനെയിരിക്കും എന്നതിനെക്കുറിച്ചും പ്രശ്നങ്ങൾ ഉണ്ടാകുമ്പോൾ അവ എങ്ങനെ പരിഹരിക്കാം എന്നതിനെക്കുറിച്ചും ഒരു അവബോധപൂർവ്വമായ ധാരണ നിങ്ങൾ വികസിപ്പിക്കും. + +> [!TIP] +> 💡 **പ്രധാന പാഠങ്ങൾ:** +> - മോഡൽ ട്രെയിനിംഗിന്റെ പുരോഗതി മനസ്സിലാക്കാനുള്ള അത്യാവശ്യ ടൂളുകളാണ് ലേണിംഗ് കർവുകൾ +> - ലോസ് കർവും അക്യുറസി കർവും രണ്ടും നിരീക്ഷിക്കുക, എന്നാൽ അവയ്ക്ക് വ്യത്യസ്ത സവിശേഷതകളുണ്ടെന്ന് ഓർക്കുക +> - ട്രെയിനിംഗ്/വാലിഡേഷൻ പ്രകടനങ്ങൾ പരസ്പരം അകന്നുപോകുന്നതായാണ് ഓവർഫിറ്റിംഗ് പ്രത്യക്ഷപ്പെടുന്നത് +> - ട്രെയിനിംഗ് ഡേറ്റയിലും വാലിഡേഷൻ ഡേറ്റയിലും മോശം പ്രകടനമായാണ് അണ്ടർഫിറ്റിംഗ് പ്രത്യക്ഷപ്പെടുന്നത് +> - Weights & Biases പോലുള്ള ടൂളുകൾ ലേണിംഗ് കർവുകൾ ട്രാക്ക് ചെയ്യുന്നതും വിശകലനം ചെയ്യുന്നതും എളുപ്പമാക്കുന്നു +> - എർലി സ്‌റ്റോപ്പിംഗും ശരിയായ റെഗുലറൈസേഷനും ഉപയോഗിച്ച് സാധാരണ ട്രെയിനിംഗ് പ്രശ്നങ്ങളിൽ മിക്കതും പരിഹരിക്കാം +> +> 🔬 **അടുത്ത ഘട്ടങ്ങൾ**: നിങ്ങളുടെ സ്വന്തം ഫൈൻ-ട്യൂണിംഗ് പരീക്ഷണങ്ങളിൽ ലേണിംഗ് കർവുകൾ വിശകലനം ചെയ്ത് പരിശീലിക്കുക. വ്യത്യസ്ത ഹൈപ്പർപാരാമീറ്ററുകൾ പരീക്ഷിച്ച്, അവ കർവുകളുടെ ആകൃതിയെ എങ്ങനെ ബാധിക്കുന്നു എന്ന് നിരീക്ഷിക്കുക. ട്രെയിനിംഗ് പുരോഗതി വായിക്കാനുള്ള അവബോധം വികസിപ്പിക്കാനുള്ള ഏറ്റവും നല്ല മാർഗ്ഗം ഈ പ്രായോഗിക അനുഭവമാണ്. + +## ഈ ഭാഗത്തിന്റെ ക്വിസ്[[section-quiz]] + +ലേണിംഗ് കർവുകളെയും ട്രെയിനിംഗ് വിശകലനത്തെയും കുറിച്ചുള്ള നിങ്ങളുടെ ധാരണ പരീക്ഷിക്കുക: + +### 1. ട്രെയിനിംഗ് ലോസ് കുറയുമ്പോൾ വാലിഡേഷൻ ലോസ് ഉയരാൻ തുടങ്ങിയാൽ, അത് സാധാരണയായി എന്താണ് അർത്ഥമാക്കുന്നത്? + + + +### 2. അക്യുറസി കർവുകൾ സുഗമമായ ഉയർച്ചയ്ക്ക് പകരം "പടിപടിയായ" അല്ലെങ്കിൽ പ്ലേറ്റോ പോലുള്ള പാറ്റേൺ പലപ്പോഴും കാണിക്കുന്നത് എന്തുകൊണ്ട്? + + + +### 3. ചാഞ്ചാടുന്ന, വളരെയധികം ഏറ്റക്കുറച്ചിലുകളുള്ള ലേണിംഗ് കർവുകൾ കാണുമ്പോൾ ഏറ്റവും നല്ല സമീപനം എന്താണ്? + + + +### 4. എർലി സ്‌റ്റോപ്പിംഗ് ഉപയോഗിക്കുന്നത് എപ്പോഴാണ് പരിഗണിക്കേണ്ടത്? + + + +### 5. നിങ്ങളുടെ മോഡൽ അണ്ടർഫിറ്റ് ചെയ്യുന്നുണ്ടാകാം എന്ന് സൂചിപ്പിക്കുന്നത് എന്താണ്? + + + diff --git a/chapters/ml/chapter3/6.mdx b/chapters/ml/chapter3/6.mdx new file mode 100644 index 000000000..aa14a0148 --- /dev/null +++ b/chapters/ml/chapter3/6.mdx @@ -0,0 +1,40 @@ + + +# ഫൈൻ-ട്യൂണിംഗ്, പൂർത്തിയായി![[fine-tuning-check]] + + + +അത് വളരെ സമഗ്രമായിരുന്നു! ആദ്യത്തെ രണ്ട് അധ്യായങ്ങളിൽ നിങ്ങൾ മോഡലുകളെയും ടോക്കണൈസറുകളെയും കുറിച്ച് പഠിച്ചു; ഇപ്പോൾ ആധുനികമായ മികച്ച രീതികൾ (best practices) ഉപയോഗിച്ച് നിങ്ങളുടെ സ്വന്തം ഡേറ്റയ്ക്കായി അവ എങ്ങനെ ഫൈൻ-ട്യൂൻ ചെയ്യാമെന്നും നിങ്ങൾക്കറിയാം. ഒന്ന് ഓർത്തുനോക്കിയാൽ, ഈ അധ്യായത്തിൽ നിങ്ങൾ: + +* [Hub](https://huggingface.co/datasets)-ലെ ഡേറ്റാസെറ്റുകളെക്കുറിച്ചും ആധുനിക ഡേറ്റാ പ്രോസസ്സിംഗ് ടെക്‌നിക്കുകളെക്കുറിച്ചും പഠിച്ചു +* ഡൈനാമിക് പാഡിംഗും ഡേറ്റാ കൊളേറ്ററുകളും ഉപയോഗിക്കുന്നതുൾപ്പെടെ, ഡേറ്റാസെറ്റുകൾ കാര്യക്ഷമമായി ലോഡ് ചെയ്യാനും പ്രീപ്രോസസ്സ് ചെയ്യാനും പഠിച്ചു +* ഏറ്റവും പുതിയ സവിശേഷതകളോടെ, ഉയർന്ന തലത്തിലുള്ള (high-level) `Trainer` API ഉപയോഗിച്ച് ഫൈൻ-ട്യൂണിംഗും ഇവാല്യുവേഷനും ഇംപ്ലിമെന്റ് ചെയ്തു +* PyTorch ഉപയോഗിച്ച് പൂജ്യത്തിൽ നിന്ന് ഒരു പൂർണ്ണമായ കസ്‌റ്റം ട്രെയിനിംഗ് ലൂപ്പ് ഇംപ്ലിമെന്റ് ചെയ്തു +* നിങ്ങളുടെ ട്രെയിനിംഗ് കോഡ് ഒന്നിലധികം GPU-കളിലോ TPU-കളിലോ തടസ്സമില്ലാതെ പ്രവർത്തിക്കാൻ 🤗 Accelerate ഉപയോഗിച്ചു +* മിക്‌സഡ് പ്രിസിഷൻ ട്രെയിനിംഗ്, ഗ്രേഡിയന്റ് അക്യുമുലേഷൻ പോലുള്ള ആധുനിക ഒപ്‌റ്റിമൈസേഷൻ ടെക്‌നിക്കുകൾ പ്രയോഗിച്ചു + +> [!TIP] +> 🎉 **അഭിനന്ദനങ്ങൾ!** Transformer മോഡലുകൾ ഫൈൻ-ട്യൂൻ ചെയ്യുന്നതിന്റെ അടിസ്ഥാനങ്ങൾ നിങ്ങൾ സ്വായത്തമാക്കിയിരിക്കുന്നു. യഥാർത്ഥ ലോകത്തിലെ ML പ്രോജക്റ്റുകൾ ഏറ്റെടുക്കാൻ ഇപ്പോൾ നിങ്ങൾ തയ്യാറാണ്! +> +> 📖 **പഠനം തുടരുക**: നിങ്ങളുടെ അറിവ് ആഴത്തിലാക്കാൻ ഈ റിസോഴ്‌സുകൾ പരിശോധിക്കുക: +> - നിർദ്ദിഷ്ട NLP ടാസ്‌ക്കുകൾക്കായി [🤗 Transformers ടാസ്‌ക് ഗൈഡുകൾ](https://huggingface.co/docs/transformers/main/en/tasks/sequence_classification) +> - സമഗ്രമായ നോട്ട്‌ബുക്കുകൾക്കായി [🤗 Transformers ഉദാഹരണങ്ങൾ](https://huggingface.co/docs/transformers/main/en/notebooks) +> +> 🚀 **അടുത്ത ഘട്ടങ്ങൾ**: +> - നിങ്ങൾ പഠിച്ച ടെക്‌നിക്കുകൾ ഉപയോഗിച്ച് നിങ്ങളുടെ സ്വന്തം ഡേറ്റാസെറ്റിൽ ഫൈൻ-ട്യൂണിംഗ് പരീക്ഷിക്കുക +> - [Hugging Face Hub](https://huggingface.co/models)-ൽ ലഭ്യമായ വ്യത്യസ്ത മോഡൽ ആർക്കിടെക്ചറുകൾ ഉപയോഗിച്ച് പരീക്ഷണം നടത്തുക +> - നിങ്ങളുടെ പ്രോജക്റ്റുകൾ പങ്കുവയ്ക്കാനും സഹായം നേടാനും [Hugging Face കമ്മ്യൂണിറ്റിയിൽ](https://discuss.huggingface.co/) ചേരുക + +🤗 Transformers-നൊപ്പമുള്ള നിങ്ങളുടെ യാത്രയുടെ തുടക്കം മാത്രമാണിത്. അടുത്ത അധ്യായത്തിൽ, നിങ്ങളുടെ മോഡലുകളും ടോക്കണൈസറുകളും കമ്മ്യൂണിറ്റിയുമായി എങ്ങനെ പങ്കുവയ്ക്കാമെന്നും, നിരന്തരം വളരുന്ന പ്രീട്രെയിൻഡ് മോഡലുകളുടെ ഇക്കോസിസ്‌റ്റത്തിലേക്ക് എങ്ങനെ സംഭാവന ചെയ്യാമെന്നും നമ്മൾ പരിശോധിക്കും. + +നിങ്ങൾ ഇവിടെ വികസിപ്പിച്ച കഴിവുകൾ - ഡേറ്റാ പ്രീപ്രോസസ്സിംഗ്, ട്രെയിനിംഗ് കോൺഫിഗറേഷൻ, ഇവാല്യുവേഷൻ, ഒപ്‌റ്റിമൈസേഷൻ - ഏതൊരു മെഷീൻ ലേണിംഗ് പ്രോജക്റ്റിനും അടിസ്ഥാനപരമാണ്. ടെക്‌സ്‌റ്റ് വർഗ്ഗീകരണം, നാമ-സത്ത തിരിച്ചറിയൽ (named entity recognition), ചോദ്യോത്തരം (question answering), അല്ലെങ്കിൽ മറ്റേതെങ്കിലും NLP ടാസ്‌ക് — ഏതിലാണ് നിങ്ങൾ പ്രവർത്തിക്കുന്നതെങ്കിലും, ഈ ടെക്‌നിക്കുകൾ നിങ്ങൾക്ക് നന്നായി ഉപകാരപ്പെടും. + +> [!TIP] +> 💡 **വിജയത്തിനുള്ള പ്രോ ടിപ്പുകൾ**: +> - കസ്‌റ്റം ട്രെയിനിംഗ് ലൂപ്പുകൾ ഇംപ്ലിമെന്റ് ചെയ്യുന്നതിന് മുമ്പ്, എപ്പോഴും `Trainer` API ഉപയോഗിച്ച് ശക്തമായ ഒരു ബേസ്‌ലൈനിൽ നിന്ന് തുടങ്ങുക +> - മികച്ച തുടക്കത്തിനായി, നിങ്ങളുടെ ടാസ്‌ക്കിനോട് അടുത്തുനിൽക്കുന്ന പ്രീട്രെയിൻഡ് മോഡലുകൾ കണ്ടെത്താൻ 🤗 Hub ഉപയോഗിക്കുക +> - ശരിയായ ഇവാല്യുവേഷൻ മെട്രിക്കുകൾ ഉപയോഗിച്ച് നിങ്ങളുടെ ട്രെയിനിംഗ് നിരീക്ഷിക്കുക, ചെക്ക്‌പോയിന്റുകൾ സേവ് ചെയ്യാൻ മറക്കരുത് +> - കമ്മ്യൂണിറ്റിയെ പ്രയോജനപ്പെടുത്തുക - മറ്റുള്ളവരെ സഹായിക്കാനും നിങ്ങളുടെ ജോലിയെക്കുറിച്ച് ഫീഡ്‌ബാക്ക് നേടാനും നിങ്ങളുടെ മോഡലുകളും ഡേറ്റാസെറ്റുകളും പങ്കുവയ്ക്കുക diff --git a/chapters/ml/chapter3/7.mdx b/chapters/ml/chapter3/7.mdx new file mode 100644 index 000000000..99b8c6212 --- /dev/null +++ b/chapters/ml/chapter3/7.mdx @@ -0,0 +1,27 @@ + + +# അധ്യായം പൂർത്തിയാക്കിയതിനുള്ള സർട്ടിഫിക്കറ്റ് + + + +കോഴ്‌സ് പൂർത്തിയാക്കിയതിന് അഭിനന്ദനങ്ങൾ! പ്രീട്രെയിൻഡ് മോഡലുകൾ എങ്ങനെ ഫൈൻ-ട്യൂൻ ചെയ്യാമെന്നും, ലേണിംഗ് കർവുകൾ (learning curves) എങ്ങനെ മനസ്സിലാക്കാമെന്നും, നിങ്ങളുടെ മോഡലുകൾ കമ്മ്യൂണിറ്റിയുമായി എങ്ങനെ പങ്കുവയ്ക്കാമെന്നും നിങ്ങൾ പഠിച്ചു. ഇനി നിങ്ങളുടെ അറിവ് പരീക്ഷിക്കാനും സർട്ടിഫിക്കറ്റ് നേടാനും ക്വിസിൽ പങ്കെടുക്കാനുള്ള സമയമായി. + +ക്വിസിൽ പങ്കെടുക്കാൻ, നിങ്ങൾ ഈ ഘട്ടങ്ങൾ പിന്തുടരേണ്ടതുണ്ട്: + +1. നിങ്ങളുടെ Hugging Face അക്കൗണ്ടിലേക്ക് സൈൻ ഇൻ ചെയ്യുക. +2. ക്വിസിലെ ചോദ്യങ്ങൾക്ക് ഉത്തരം നൽകുക. +3. നിങ്ങളുടെ ഉത്തരങ്ങൾ സമർപ്പിക്കുക. + + +## മൾട്ടിപ്പിൾ ചോയ്‌സ് ക്വിസ് + +ഈ ക്വിസിൽ, ഓപ്‌ഷനുകളുടെ ഒരു പട്ടികയിൽ നിന്ന് ശരിയായ ഉത്തരം തിരഞ്ഞെടുക്കാൻ നിങ്ങളോട് ആവശ്യപ്പെടും. supervised ഫൈൻ-ട്യൂണിംഗിന്റെ അടിസ്ഥാനങ്ങളിലാണ് നാം നിങ്ങളെ പരീക്ഷിക്കുന്നത്. + + diff --git a/chapters/ml/chapter4/1.mdx b/chapters/ml/chapter4/1.mdx new file mode 100644 index 000000000..f2a4a6e2d --- /dev/null +++ b/chapters/ml/chapter4/1.mdx @@ -0,0 +1,22 @@ +# Hugging Face Hub[[the-hugging-face-hub]] + + + +[Hugging Face Hub](https://huggingface.co/) –- ഞങ്ങളുടെ പ്രധാന വെബ്‌സൈറ്റ് –- അത്യാധുനിക (state-of-the-art) മോഡലുകളും ഡേറ്റാസെറ്റുകളും കണ്ടെത്താനും ഉപയോഗിക്കാനും പുതിയവ സംഭാവന ചെയ്യാനും ആർക്കും കഴിയുന്ന ഒരു കേന്ദ്ര പ്ലാറ്റ്‌ഫോമാണ്. പലതരത്തിലുള്ള മോഡലുകൾ ഇത് ഹോസ്‌റ്റ് ചെയ്യുന്നു; അവയിൽ 10,000-ത്തിലധികം പൊതുവായി ലഭ്യമാണ്. ഈ അധ്യായത്തിൽ നമ്മൾ മോഡലുകളിലാണ് ശ്രദ്ധ കേന്ദ്രീകരിക്കുന്നത്; ഡേറ്റാസെറ്റുകൾ അധ്യായം 5-ൽ നോക്കാം. + +Hub-ലെ മോഡലുകൾ 🤗 Transformers-ലോ NLP-യിലോ മാത്രം ഒതുങ്ങുന്നില്ല. ചിലത് മാത്രം പറയുകയാണെങ്കിൽ, NLP-ക്കായി [Flair](https://github.com/flairNLP/flair), [AllenNLP](https://github.com/allenai/allennlp) എന്നിവയിൽ നിന്നുള്ള മോഡലുകളും, സ്പീച്ചിനായി [Asteroid](https://github.com/asteroid-team/asteroid), [pyannote](https://github.com/pyannote/pyannote-audio) എന്നിവയിൽ നിന്നുള്ളവയും, വിഷനായി [timm](https://github.com/rwightman/pytorch-image-models)-ൽ നിന്നുള്ളവയും ഇവിടെയുണ്ട്. + +ഈ മോഡലുകൾ ഓരോന്നും ഒരു Git റിപ്പോസിറ്ററിയായാണ് ഹോസ്‌റ്റ് ചെയ്യപ്പെടുന്നത്; ഇത് വേർഷനിംഗും (versioning) പുനരുൽപ്പാദനക്ഷമതയും (reproducibility) സാധ്യമാക്കുന്നു. ഒരു മോഡൽ Hub-ൽ പങ്കുവെക്കുക എന്നാൽ അത് കമ്മ്യൂണിറ്റിക്ക് തുറന്നുകൊടുക്കുകയും, എളുപ്പത്തിൽ ഉപയോഗിക്കാൻ ആഗ്രഹിക്കുന്ന ആർക്കും അത് ലഭ്യമാക്കുകയും ചെയ്യുക എന്നാണ്; അതുവഴി അവർക്ക് സ്വന്തമായി ഒരു മോഡൽ ട്രെയിൻ ചെയ്യേണ്ട ആവശ്യം ഇല്ലാതാകുകയും, പങ്കുവെക്കലും ഉപയോഗവും ലളിതമാകുകയും ചെയ്യുന്നു. + +കൂടാതെ, ഒരു മോഡൽ Hub-ൽ പങ്കുവെക്കുമ്പോൾ ആ മോഡലിനായി ഒരു ഹോസ്‌റ്റഡ് Inference API സ്വയമേവ ഡിപ്ലോയ് ചെയ്യപ്പെടുന്നു. കമ്മ്യൂണിറ്റിയിലെ ആർക്കും, സ്വന്തം ഇൻപുട്ടുകളും അനുയോജ്യമായ വിജറ്റുകളും ഉപയോഗിച്ച്, മോഡലിന്റെ പേജിൽ നേരിട്ട് അത് പരീക്ഷിച്ചുനോക്കാം. + +ഏറ്റവും നല്ല കാര്യം, Hub-ലെ ഏത് പൊതു മോഡലും പങ്കുവെക്കുന്നതും ഉപയോഗിക്കുന്നതും പൂർണ്ണമായും സൗജന്യമാണ് എന്നതാണ്! മോഡലുകൾ സ്വകാര്യമായി പങ്കുവെക്കാൻ ആഗ്രഹിക്കുന്നെങ്കിൽ [പെയ്ഡ് പ്ലാനുകളും](https://huggingface.co/pricing) ലഭ്യമാണ്. + +Hub-ൽ എങ്ങനെ സഞ്ചരിക്കാം (navigate) എന്ന് താഴെയുള്ള വീഡിയോ കാണിക്കുന്നു. + + + +ഈ ഭാഗം പിന്തുടരാൻ ഒരു huggingface.co അക്കൗണ്ട് ആവശ്യമാണ്, കാരണം നമ്മൾ Hugging Face Hub-ൽ റിപ്പോസിറ്ററികൾ ഉണ്ടാക്കുകയും കൈകാര്യം ചെയ്യുകയും ചെയ്യും: [ഒരു അക്കൗണ്ട് ഉണ്ടാക്കുക](https://huggingface.co/join) diff --git a/chapters/ml/chapter4/2.mdx b/chapters/ml/chapter4/2.mdx new file mode 100644 index 000000000..759e132a3 --- /dev/null +++ b/chapters/ml/chapter4/2.mdx @@ -0,0 +1,95 @@ + + +# പ്രീട്രെയിൻഡ് മോഡലുകൾ ഉപയോഗിക്കുന്നു[[using-pretrained-models]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +അനുയോജ്യമായ മോഡൽ തിരഞ്ഞെടുക്കുന്നത് Model Hub ലളിതമാക്കുന്നു; അതുവഴി ഏത് ഡൗൺസ്ട്രീം ലൈബ്രറിയിലും ഏതാനും വരി കോഡ് കൊണ്ട് അത് ഉപയോഗിക്കാൻ കഴിയും. ഈ മോഡലുകളിൽ ഒന്ന് യഥാർത്ഥത്തിൽ എങ്ങനെ ഉപയോഗിക്കാമെന്നും, കമ്മ്യൂണിറ്റിക്ക് തിരികെ എങ്ങനെ സംഭാവന ചെയ്യാമെന്നും നോക്കാം. + +മാസ്‌ക് ഫില്ലിംഗ് ചെയ്യാൻ കഴിയുന്ന, ഫ്രഞ്ച് ഭാഷ അടിസ്ഥാനമാക്കിയ ഒരു മോഡലാണ് നമ്മൾ തിരയുന്നത് എന്ന് കരുതുക. + +
+Camembert മോഡൽ തിരഞ്ഞെടുക്കുന്നു. +
+ +ഇത് പരീക്ഷിച്ചുനോക്കാൻ നമ്മൾ `camembert-base` ചെക്ക്‌പോയിന്റ് തിരഞ്ഞെടുക്കുന്നു. ഇത് ഉപയോഗിക്കാൻ തുടങ്ങാൻ `camembert-base` എന്ന ഐഡന്റിഫയർ മാത്രം മതി! മുൻ അധ്യായങ്ങളിൽ കണ്ടതുപോലെ, `pipeline()` ഫംഗ്‌ഷൻ ഉപയോഗിച്ച് നമുക്ക് ഇത് ഇൻസ്‌റ്റാൻഷിയേറ്റ് ചെയ്യാം: + +```py +from transformers import pipeline + +camembert_fill_mask = pipeline("fill-mask", model="camembert-base") +results = camembert_fill_mask("Le camembert est :)") +``` + +```python out +[ + {'sequence': 'Le camembert est délicieux :)', 'score': 0.49091005325317383, 'token': 7200, 'token_str': 'délicieux'}, + {'sequence': 'Le camembert est excellent :)', 'score': 0.1055697426199913, 'token': 2183, 'token_str': 'excellent'}, + {'sequence': 'Le camembert est succulent :)', 'score': 0.03453313186764717, 'token': 26202, 'token_str': 'succulent'}, + {'sequence': 'Le camembert est meilleur :)', 'score': 0.0330314114689827, 'token': 528, 'token_str': 'meilleur'}, + {'sequence': 'Le camembert est parfait :)', 'score': 0.03007650189101696, 'token': 1654, 'token_str': 'parfait'} +] +``` + +നിങ്ങൾ കാണുന്നതുപോലെ, ഒരു പൈപ്പ്‌ലൈനിനുള്ളിൽ ഒരു മോഡൽ ലോഡ് ചെയ്യുന്നത് അതീവ ലളിതമാണ്. തിരഞ്ഞെടുത്ത ചെക്ക്‌പോയിന്റ് അത് ഉപയോഗിക്കാൻ പോകുന്ന ടാസ്‌ക്കിന് അനുയോജ്യമാണോ എന്നത് മാത്രമാണ് നിങ്ങൾ ശ്രദ്ധിക്കേണ്ട ഒരേയൊരു കാര്യം. ഉദാഹരണത്തിന്, ഇവിടെ നമ്മൾ `camembert-base` ചെക്ക്‌പോയിന്റ് `fill-mask` പൈപ്പ്‌ലൈനിൽ ലോഡ് ചെയ്യുന്നു, അത് തികച്ചും ശരിയാണ്. എന്നാൽ ഈ ചെക്ക്‌പോയിന്റ് `text-classification` പൈപ്പ്‌ലൈനിൽ ലോഡ് ചെയ്താൽ, ഫലങ്ങൾക്ക് ഒരു അർത്ഥവുമുണ്ടാകില്ല, കാരണം `camembert-base`-ന്റെ ഹെഡ് (head) ഈ ടാസ്‌ക്കിന് അനുയോജ്യമല്ല! അനുയോജ്യമായ ചെക്ക്‌പോയിന്റുകൾ തിരഞ്ഞെടുക്കാൻ Hugging Face Hub ഇന്റർഫേസിലെ ടാസ്‌ക് സെലക്ടർ ഉപയോഗിക്കാൻ ഞങ്ങൾ ശുപാർശ ചെയ്യുന്നു: + +
+വെബ് ഇന്റർഫേസിലെ ടാസ്‌ക് സെലക്ടർ. +
+ +മോഡൽ ആർക്കിടെക്‌ചർ നേരിട്ട് ഉപയോഗിച്ചും നിങ്ങൾക്ക് ചെക്ക്‌പോയിന്റ് ഇൻസ്‌റ്റാൻഷിയേറ്റ് ചെയ്യാം: + +{#if fw === 'pt'} +```py +from transformers import CamembertTokenizer, CamembertForMaskedLM + +tokenizer = CamembertTokenizer.from_pretrained("camembert-base") +model = CamembertForMaskedLM.from_pretrained("camembert-base") +``` + +എന്നിരുന്നാലും, പകരം [`Auto*` ക്ലാസുകൾ](https://huggingface.co/transformers/model_doc/auto?highlight=auto#auto-classes) ഉപയോഗിക്കാനാണ് ഞങ്ങൾ ശുപാർശ ചെയ്യുന്നത്, കാരണം ഇവ രൂപകൽപ്പനയിൽ തന്നെ ആർക്കിടെക്‌ചർ-നിരപേക്ഷമാണ് (architecture-agnostic). മുമ്പത്തെ കോഡ് സാമ്പിൾ ഉപയോക്താക്കളെ CamemBERT ആർക്കിടെക്‌ചറിൽ ലോഡ് ചെയ്യാവുന്ന ചെക്ക്‌പോയിന്റുകളിലേക്ക് പരിമിതപ്പെടുത്തുമ്പോൾ, `Auto*` ക്ലാസുകൾ ഉപയോഗിക്കുന്നത് ചെക്ക്‌പോയിന്റുകൾ മാറ്റുന്നത് ലളിതമാക്കുന്നു: + +```py +from transformers import AutoTokenizer, AutoModelForMaskedLM + +tokenizer = AutoTokenizer.from_pretrained("camembert-base") +model = AutoModelForMaskedLM.from_pretrained("camembert-base") +``` +{:else} +```py +from transformers import CamembertTokenizer, TFCamembertForMaskedLM + +tokenizer = CamembertTokenizer.from_pretrained("camembert-base") +model = TFCamembertForMaskedLM.from_pretrained("camembert-base") +``` + +എന്നിരുന്നാലും, പകരം [`TFAuto*` ക്ലാസുകൾ](https://huggingface.co/transformers/model_doc/auto?highlight=auto#auto-classes) ഉപയോഗിക്കാനാണ് ഞങ്ങൾ ശുപാർശ ചെയ്യുന്നത്, കാരണം ഇവ രൂപകൽപ്പനയിൽ തന്നെ ആർക്കിടെക്‌ചർ-നിരപേക്ഷമാണ് (architecture-agnostic). മുമ്പത്തെ കോഡ് സാമ്പിൾ ഉപയോക്താക്കളെ CamemBERT ആർക്കിടെക്‌ചറിൽ ലോഡ് ചെയ്യാവുന്ന ചെക്ക്‌പോയിന്റുകളിലേക്ക് പരിമിതപ്പെടുത്തുമ്പോൾ, `TFAuto*` ക്ലാസുകൾ ഉപയോഗിക്കുന്നത് ചെക്ക്‌പോയിന്റുകൾ മാറ്റുന്നത് ലളിതമാക്കുന്നു: + +```py +from transformers import AutoTokenizer, TFAutoModelForMaskedLM + +tokenizer = AutoTokenizer.from_pretrained("camembert-base") +model = TFAutoModelForMaskedLM.from_pretrained("camembert-base") +``` +{/if} + +> [!TIP] +> ഒരു പ്രീട്രെയിൻഡ് മോഡൽ ഉപയോഗിക്കുമ്പോൾ, അത് എങ്ങനെ ട്രെയിൻ ചെയ്തു, ഏതൊക്കെ ഡേറ്റാസെറ്റുകളിൽ, അതിന്റെ പരിമിതികൾ, അതിന്റെ പക്ഷപാതങ്ങൾ (biases) എന്നിവ പരിശോധിക്കാൻ മറക്കരുത്. ഈ വിവരങ്ങളെല്ലാം അതിന്റെ മോഡൽ കാർഡിൽ സൂചിപ്പിച്ചിരിക്കണം. diff --git a/chapters/ml/chapter4/3.mdx b/chapters/ml/chapter4/3.mdx new file mode 100644 index 000000000..8040dd426 --- /dev/null +++ b/chapters/ml/chapter4/3.mdx @@ -0,0 +1,637 @@ + + +# പ്രീട്രെയിൻഡ് മോഡലുകൾ പങ്കുവെക്കുന്നു[[sharing-pretrained-models]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +താഴെയുള്ള ഘട്ടങ്ങളിൽ, പ്രീട്രെയിൻഡ് മോഡലുകൾ 🤗 Hub-ലേക്ക് പങ്കുവെക്കാനുള്ള ഏറ്റവും എളുപ്പമുള്ള വഴികൾ നമ്മൾ നോക്കും. Hub-ൽ നേരിട്ട് മോഡലുകൾ പങ്കുവെക്കാനും അപ്‌ഡേറ്റ് ചെയ്യാനും ലളിതമാക്കുന്ന ടൂളുകളും യൂട്ടിലിറ്റികളും ലഭ്യമാണ്; അവ നമ്മൾ താഴെ പരിശോധിക്കും. + + + +മോഡലുകൾ ട്രെയിൻ ചെയ്യുന്ന എല്ലാ ഉപയോക്താക്കളെയും അവ കമ്മ്യൂണിറ്റിയുമായി പങ്കുവെച്ച് സംഭാവന ചെയ്യാൻ ഞങ്ങൾ പ്രോത്സാഹിപ്പിക്കുന്നു — വളരെ പ്രത്യേകമായ ഡേറ്റാസെറ്റുകളിൽ ട്രെയിൻ ചെയ്തവയാണെങ്കിൽ പോലും, മോഡലുകൾ പങ്കുവെക്കുന്നത് മറ്റുള്ളവർക്ക് സഹായകമാകും; അത് അവരുടെ സമയവും കമ്പ്യൂട്ട് വിഭവങ്ങളും ലാഭിക്കുകയും, ഉപകാരപ്രദമായ ട്രെയിൻഡ് ആർട്ടിഫാക്റ്റുകളിലേക്ക് പ്രവേശനം നൽകുകയും ചെയ്യുന്നു. അതുപോലെ, മറ്റുള്ളവർ ചെയ്ത ജോലിയിൽ നിന്ന് നിങ്ങൾക്കും പ്രയോജനം നേടാം! + +പുതിയ മോഡൽ റിപ്പോസിറ്ററികൾ ഉണ്ടാക്കാൻ മൂന്ന് വഴികളുണ്ട്: + +- `push_to_hub` API ഉപയോഗിച്ച് +- `huggingface_hub` Python ലൈബ്രറി ഉപയോഗിച്ച് +- വെബ് ഇന്റർഫേസ് ഉപയോഗിച്ച് + +ഒരു റിപ്പോസിറ്ററി ഉണ്ടാക്കിക്കഴിഞ്ഞാൽ, git-ഉം git-lfs-ഉം വഴി അതിലേക്ക് ഫയലുകൾ അപ്‌ലോഡ് ചെയ്യാം. തുടർന്നുള്ള വിഭാഗങ്ങളിൽ മോഡൽ റിപ്പോസിറ്ററികൾ ഉണ്ടാക്കുന്നതും അവയിലേക്ക് ഫയലുകൾ അപ്‌ലോഡ് ചെയ്യുന്നതും ഞങ്ങൾ ഘട്ടം ഘട്ടമായി കാണിച്ചുതരാം. + + +## `push_to_hub` API ഉപയോഗിക്കുന്നു[[using-the-pushtohub-api]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +Hub-ലേക്ക് ഫയലുകൾ അപ്‌ലോഡ് ചെയ്യാനുള്ള ഏറ്റവും ലളിതമായ വഴി `push_to_hub` API പ്രയോജനപ്പെടുത്തുന്നതാണ്. + +മുന്നോട്ട് പോകുന്നതിന് മുമ്പ്, നിങ്ങൾ ആരാണെന്നും ഏതൊക്കെ നെയിംസ്‌പേസുകളിൽ നിങ്ങൾക്ക് എഴുതാനുള്ള അനുമതി (write access) ഉണ്ടെന്നും `huggingface_hub` API-ക്ക് അറിയാൻ ഒരു ഓതന്റിക്കേഷൻ ടോക്കൺ നിങ്ങൾ ജനറേറ്റ് ചെയ്യേണ്ടതുണ്ട്. `transformers` ഇൻസ്‌റ്റാൾ ചെയ്തിട്ടുള്ള ഒരു എൻവയോൺമെന്റിലാണ് നിങ്ങൾ എന്ന് ഉറപ്പാക്കുക ([സെറ്റപ്പ്](/course/chapter0) കാണുക). നിങ്ങൾ ഒരു നോട്ട്‌ബുക്കിലാണെങ്കിൽ, ലോഗിൻ ചെയ്യാൻ താഴെയുള്ള ഫംഗ്‌ഷൻ ഉപയോഗിക്കാം: + +```python +from huggingface_hub import notebook_login + +notebook_login() +``` + +ഒരു ടെർമിനലിൽ, നിങ്ങൾക്ക് ഇത് റൺ ചെയ്യാം: + +```bash +huggingface-cli login +``` + +രണ്ട് സാഹചര്യങ്ങളിലും, നിങ്ങളുടെ യൂസർനെയിമും പാസ്‌വേഡും ചോദിക്കും; Hub-ൽ ലോഗിൻ ചെയ്യാൻ നിങ്ങൾ ഉപയോഗിക്കുന്ന അതേ വിവരങ്ങളാണ് ഇവ. നിങ്ങൾക്ക് ഇതുവരെ ഒരു Hub പ്രൊഫൈൽ ഇല്ലെങ്കിൽ, [ഇവിടെ](https://huggingface.co/join) ഒന്ന് ഉണ്ടാക്കുക. + +കൊള്ളാം! നിങ്ങളുടെ ഓതന്റിക്കേഷൻ ടോക്കൺ ഇപ്പോൾ നിങ്ങളുടെ കാഷ് ഫോൾഡറിൽ സംഭരിച്ചിരിക്കുന്നു. ഇനി കുറച്ച് റിപ്പോസിറ്ററികൾ ഉണ്ടാക്കാം! + +{#if fw === 'pt'} + +ഒരു മോഡൽ ട്രെയിൻ ചെയ്യാൻ `Trainer` API നിങ്ങൾ പരീക്ഷിച്ചിട്ടുണ്ടെങ്കിൽ, അത് Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യാനുള്ള ഏറ്റവും എളുപ്പമുള്ള വഴി നിങ്ങളുടെ `TrainingArguments` നിർവചിക്കുമ്പോൾ `push_to_hub=True` എന്ന് സെറ്റ് ചെയ്യുന്നതാണ്: + +```py +from transformers import TrainingArguments + +training_args = TrainingArguments( + "bert-finetuned-mrpc", save_strategy="epoch", push_to_hub=True +) +``` + +നിങ്ങൾ `trainer.train()` വിളിക്കുമ്പോൾ, മോഡൽ സേവ് ചെയ്യപ്പെടുന്ന ഓരോ തവണയും (ഇവിടെ ഓരോ എപ്പോക്കിലും) `Trainer` അത് നിങ്ങളുടെ നെയിംസ്‌പേസിലെ ഒരു റിപ്പോസിറ്ററിയിലേക്ക് Hub-ൽ അപ്‌ലോഡ് ചെയ്യും. നിങ്ങൾ തിരഞ്ഞെടുത്ത ഔട്ട്‌പുട്ട് ഡയറക്ടറിയുടെ പേരായിരിക്കും (ഇവിടെ `bert-finetuned-mrpc`) ആ റിപ്പോസിറ്ററിക്ക്, എന്നാൽ `hub_model_id = "a_different_name"` ഉപയോഗിച്ച് നിങ്ങൾക്ക് മറ്റൊരു പേര് തിരഞ്ഞെടുക്കാം. + +നിങ്ങൾ അംഗമായ ഒരു ഓർഗനൈസേഷനിലേക്ക് നിങ്ങളുടെ മോഡൽ അപ്‌ലോഡ് ചെയ്യാൻ, `hub_model_id = "my_organization/my_repo_name"` എന്ന് നൽകിയാൽ മതി. + +ട്രെയിനിംഗ് പൂർത്തിയായിക്കഴിഞ്ഞാൽ, നിങ്ങളുടെ മോഡലിന്റെ അവസാന പതിപ്പ് അപ്‌ലോഡ് ചെയ്യാൻ അവസാനമായി ഒരു `trainer.push_to_hub()` ചെയ്യണം. ഉപയോഗിച്ച ഹൈപ്പർപാരാമീറ്ററുകളും ഇവാല്യുവേഷൻ ഫലങ്ങളും റിപ്പോർട്ട് ചെയ്യുന്ന, പ്രസക്തമായ എല്ലാ മെറ്റാഡേറ്റയും അടങ്ങിയ ഒരു മോഡൽ കാർഡും ഇത് ജനറേറ്റ് ചെയ്യും! അങ്ങനെയുള്ള ഒരു മോഡൽ കാർഡിൽ നിങ്ങൾ കണ്ടേക്കാവുന്ന ഉള്ളടക്കത്തിന്റെ ഒരു ഉദാഹരണം ഇതാ: + +
+ സ്വയമേവ ജനറേറ്റ് ചെയ്ത ഒരു മോഡൽ കാർഡിന്റെ ഉദാഹരണം. +
+ +{:else} + +നിങ്ങളുടെ മോഡൽ ട്രെയിൻ ചെയ്യാൻ Keras ആണ് ഉപയോഗിക്കുന്നതെങ്കിൽ, അത് Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യാനുള്ള ഏറ്റവും എളുപ്പമുള്ള വഴി `model.fit()` വിളിക്കുമ്പോൾ ഒരു `PushToHubCallback` കൈമാറുന്നതാണ്: + +```py +from transformers import PushToHubCallback + +callback = PushToHubCallback( + "bert-finetuned-mrpc", save_strategy="epoch", tokenizer=tokenizer +) +``` + +തുടർന്ന് നിങ്ങളുടെ `model.fit()` കോളിൽ `callbacks=[callback]` ചേർക്കണം. മോഡൽ സേവ് ചെയ്യപ്പെടുന്ന ഓരോ തവണയും (ഇവിടെ ഓരോ എപ്പോക്കിലും) കോൾബാക്ക് അത് നിങ്ങളുടെ നെയിംസ്‌പേസിലെ ഒരു റിപ്പോസിറ്ററിയിലേക്ക് Hub-ൽ അപ്‌ലോഡ് ചെയ്യും. നിങ്ങൾ തിരഞ്ഞെടുത്ത ഔട്ട്‌പുട്ട് ഡയറക്ടറിയുടെ പേരായിരിക്കും (ഇവിടെ `bert-finetuned-mrpc`) ആ റിപ്പോസിറ്ററിക്ക്, എന്നാൽ `hub_model_id = "a_different_name"` ഉപയോഗിച്ച് നിങ്ങൾക്ക് മറ്റൊരു പേര് തിരഞ്ഞെടുക്കാം. + +നിങ്ങൾ അംഗമായ ഒരു ഓർഗനൈസേഷനിലേക്ക് നിങ്ങളുടെ മോഡൽ അപ്‌ലോഡ് ചെയ്യാൻ, `hub_model_id = "my_organization/my_repo_name"` എന്ന് നൽകിയാൽ മതി. + +{/if} + +കുറച്ചുകൂടി താഴ്ന്ന തലത്തിൽ, മോഡലുകൾ, ടോക്കണൈസറുകൾ, കോൺഫിഗറേഷൻ ഒബ്‌ജക്റ്റുകൾ എന്നിവയുടെ `push_to_hub()` മെത്തേഡ് വഴി അവയിൽ നേരിട്ട് Model Hub ആക്‌സസ് ചെയ്യാം. റിപ്പോസിറ്ററി ഉണ്ടാക്കുന്നതും മോഡൽ, ടോക്കണൈസർ ഫയലുകൾ നേരിട്ട് റിപ്പോസിറ്ററിയിലേക്ക് പുഷ് ചെയ്യുന്നതും ഈ മെത്തേഡ് തന്നെ കൈകാര്യം ചെയ്യുന്നു. താഴെ നമ്മൾ കാണുന്ന API-യിൽ നിന്ന് വ്യത്യസ്തമായി, ഇവിടെ മാനുവലായി ഒന്നും ചെയ്യേണ്ടതില്ല. + +ഇത് എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് മനസ്സിലാക്കാൻ, ആദ്യം ഒരു മോഡലും ഒരു ടോക്കണൈസറും ഇനിഷ്യലൈസ് ചെയ്യാം: + +{#if fw === 'pt'} +```py +from transformers import AutoModelForMaskedLM, AutoTokenizer + +checkpoint = "camembert-base" + +model = AutoModelForMaskedLM.from_pretrained(checkpoint) +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +``` +{:else} +```py +from transformers import TFAutoModelForMaskedLM, AutoTokenizer + +checkpoint = "camembert-base" + +model = TFAutoModelForMaskedLM.from_pretrained(checkpoint) +tokenizer = AutoTokenizer.from_pretrained(checkpoint) +``` +{/if} + +ഇവ ഉപയോഗിച്ച് നിങ്ങൾക്ക് ഇഷ്ടമുള്ളതെന്തും ചെയ്യാം — ടോക്കണൈസറിലേക്ക് ടോക്കണുകൾ ചേർക്കുക, മോഡൽ ട്രെയിൻ ചെയ്യുക, ഫൈൻ-ട്യൂൺ ചെയ്യുക. ലഭിച്ച മോഡൽ, വെയ്‌റ്റുകൾ, ടോക്കണൈസർ എന്നിവയിൽ നിങ്ങൾ തൃപ്തരായിക്കഴിഞ്ഞാൽ, `model` ഒബ്‌ജക്റ്റിൽ നേരിട്ട് ലഭ്യമായ `push_to_hub()` മെത്തേഡ് നിങ്ങൾക്ക് പ്രയോജനപ്പെടുത്താം: + +```py +model.push_to_hub("dummy-model") +``` + +ഇത് നിങ്ങളുടെ പ്രൊഫൈലിൽ `dummy-model` എന്ന പുതിയ റിപ്പോസിറ്ററി ഉണ്ടാക്കി, നിങ്ങളുടെ മോഡൽ ഫയലുകൾ അതിൽ നിറയ്ക്കും. +ടോക്കണൈസറിനും ഇതേ കാര്യം ചെയ്യുക, അങ്ങനെ എല്ലാ ഫയലുകളും ഇപ്പോൾ ഈ റിപ്പോസിറ്ററിയിൽ ലഭ്യമാകും: + +```py +tokenizer.push_to_hub("dummy-model") +``` + +നിങ്ങൾ ഒരു ഓർഗനൈസേഷനിൽ അംഗമാണെങ്കിൽ, ആ ഓർഗനൈസേഷന്റെ നെയിംസ്‌പേസിലേക്ക് അപ്‌ലോഡ് ചെയ്യാൻ `organization` ആർഗ്യുമെന്റ് വ്യക്തമാക്കിയാൽ മതി: + +```py +tokenizer.push_to_hub("dummy-model", organization="huggingface") +``` + +ഒരു പ്രത്യേക Hugging Face ടോക്കൺ ഉപയോഗിക്കാൻ ആഗ്രഹിക്കുന്നെങ്കിൽ, അതും `push_to_hub()` മെത്തേഡിന് നൽകാൻ നിങ്ങൾക്ക് സ്വാതന്ത്ര്യമുണ്ട്: + +```py +tokenizer.push_to_hub("dummy-model", organization="huggingface", use_auth_token="") +``` + +ഇനി Model Hub-ലേക്ക് പോയി നിങ്ങൾ പുതുതായി അപ്‌ലോഡ് ചെയ്ത മോഡൽ കണ്ടെത്തുക: *https://huggingface.co/user-or-organization/dummy-model*. + +"Files and versions" ടാബിൽ ക്ലിക്ക് ചെയ്യുക; താഴെയുള്ള സ്ക്രീൻഷോട്ടിൽ കാണുന്ന ഫയലുകൾ നിങ്ങൾക്ക് കാണാൻ കഴിയണം: + +{#if fw === 'pt'} +
+ടോക്കണൈസർ ഫയലുകളും മോഡൽ ഫയലുകളും അടങ്ങിയ ഡമ്മി മോഡൽ. +
+{:else} +
+ടോക്കണൈസർ ഫയലുകളും മോഡൽ ഫയലുകളും അടങ്ങിയ ഡമ്മി മോഡൽ. +
+{/if} + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** `bert-base-cased` ചെക്ക്‌പോയിന്റുമായി ബന്ധപ്പെട്ട മോഡലും ടോക്കണൈസറും എടുത്ത്, `push_to_hub()` മെത്തേഡ് ഉപയോഗിച്ച് നിങ്ങളുടെ നെയിംസ്‌പേസിലെ ഒരു റിപ്പോയിലേക്ക് അപ്‌ലോഡ് ചെയ്യുക. റിപ്പോ ഡിലീറ്റ് ചെയ്യുന്നതിന് മുമ്പ് അത് നിങ്ങളുടെ പേജിൽ ശരിയായി കാണുന്നുണ്ടെന്ന് ഒന്നുകൂടി ഉറപ്പുവരുത്തുക. + +നിങ്ങൾ കണ്ടതുപോലെ, `push_to_hub()` മെത്തേഡ് പല ആർഗ്യുമെന്റുകൾ സ്വീകരിക്കുന്നു; അതുവഴി ഒരു പ്രത്യേക റിപ്പോസിറ്ററിയിലേക്കോ ഓർഗനൈസേഷൻ നെയിംസ്‌പേസിലേക്കോ അപ്‌ലോഡ് ചെയ്യാനും, മറ്റൊരു API ടോക്കൺ ഉപയോഗിക്കാനും സാധിക്കും. എന്തൊക്കെ സാധ്യമാണ് എന്ന് മനസ്സിലാക്കാൻ [🤗 Transformers ഡോക്യുമെന്റേഷനിൽ](https://huggingface.co/transformers/model_sharing) നേരിട്ട് ലഭ്യമായ മെത്തേഡ് സ്‌പെസിഫിക്കേഷൻ ഒന്ന് നോക്കാൻ ഞങ്ങൾ ശുപാർശ ചെയ്യുന്നു. + +`push_to_hub()` മെത്തേഡിന് പിന്നിൽ പ്രവർത്തിക്കുന്നത് [`huggingface_hub`](https://github.com/huggingface/huggingface_hub) Python പാക്കേജാണ്; ഇത് Hugging Face Hub-ലേക്ക് ഒരു നേരിട്ടുള്ള API നൽകുന്നു. 🤗 Transformers-ലും, [`allenlp`](https://github.com/allenai/allennlp) പോലുള്ള മറ്റ് പല മെഷീൻ ലേണിംഗ് ലൈബ്രറികളിലും ഇത് ഇന്റഗ്രേറ്റ് ചെയ്തിട്ടുണ്ട്. ഈ അധ്യായത്തിൽ നമ്മൾ 🤗 Transformers ഇന്റഗ്രേഷനിലാണ് ശ്രദ്ധ കേന്ദ്രീകരിക്കുന്നതെങ്കിലും, നിങ്ങളുടെ സ്വന്തം കോഡിലോ ലൈബ്രറിയിലോ ഇത് ഇന്റഗ്രേറ്റ് ചെയ്യുന്നത് ലളിതമാണ്. + +നിങ്ങൾ പുതുതായി ഉണ്ടാക്കിയ റിപ്പോസിറ്ററിയിലേക്ക് ഫയലുകൾ എങ്ങനെ അപ്‌ലോഡ് ചെയ്യാമെന്ന് കാണാൻ അവസാന വിഭാഗത്തിലേക്ക് പോകുക! + +## `huggingface_hub` Python ലൈബ്രറി ഉപയോഗിക്കുന്നു[[using-the-huggingfacehub-python-library]] + +`huggingface_hub` Python ലൈബ്രറി, മോഡൽ, ഡേറ്റാസെറ്റ് ഹബ്ബുകൾക്കായുള്ള ഒരു കൂട്ടം ടൂളുകൾ നൽകുന്ന ഒരു പാക്കേജാണ്. Hub-ലെ റിപ്പോസിറ്ററികളെക്കുറിച്ചുള്ള വിവരങ്ങൾ നേടുക, അവ കൈകാര്യം ചെയ്യുക തുടങ്ങിയ +സാധാരണ ടാസ്‌ക്കുകൾക്കായി ലളിതമായ മെത്തേഡുകളും ക്ലാസുകളും ഇത് നൽകുന്നു. ആ റിപ്പോസിറ്ററികളുടെ ഉള്ളടക്കം കൈകാര്യം ചെയ്യാനും നിങ്ങളുടെ പ്രോജക്റ്റുകളിലും ലൈബ്രറികളിലും Hub-നെ +സംയോജിപ്പിക്കാനും git-ന് മുകളിൽ പ്രവർത്തിക്കുന്ന ലളിതമായ API-കളും ഇത് നൽകുന്നു. + +`push_to_hub` API ഉപയോഗിക്കുന്നതുപോലെ, ഇതിനും നിങ്ങളുടെ API ടോക്കൺ കാഷിൽ സേവ് ചെയ്തിരിക്കണം. അതിനായി, മുൻ വിഭാഗത്തിൽ പറഞ്ഞതുപോലെ CLI-യിലെ `login` കമാൻഡ് നിങ്ങൾ ഉപയോഗിക്കേണ്ടതുണ്ട് (Google Colab-ൽ റൺ ചെയ്യുന്നെങ്കിൽ ഈ കമാൻഡുകൾക്ക് മുന്നിൽ `!` എന്ന ചിഹ്നം ചേർക്കാൻ വീണ്ടും ഓർക്കുക): + +```bash +huggingface-cli login +``` + +നമ്മുടെ ആവശ്യത്തിന് ഉപകാരപ്രദമായ പല മെത്തേഡുകളും ക്ലാസുകളും `huggingface_hub` പാക്കേജ് നൽകുന്നു. ആദ്യമായി, റിപ്പോസിറ്ററി ഉണ്ടാക്കൽ, ഡിലീറ്റ് ചെയ്യൽ തുടങ്ങിയവ കൈകാര്യം ചെയ്യാൻ ഏതാനും മെത്തേഡുകളുണ്ട്: + +```python no-format +from huggingface_hub import ( + # User management + login, + logout, + whoami, + + # Repository creation and management + create_repo, + delete_repo, + update_repo_visibility, + + # And some methods to retrieve/change information about the content + list_models, + list_datasets, + list_metrics, + list_repo_files, + upload_file, + delete_file, +) +``` + + +കൂടാതെ, ഒരു ലോക്കൽ റിപ്പോസിറ്ററി കൈകാര്യം ചെയ്യാൻ വളരെ ശക്തമായ `Repository` ക്ലാസും ഇത് നൽകുന്നു. ഇവ എങ്ങനെ പ്രയോജനപ്പെടുത്താം എന്ന് മനസ്സിലാക്കാൻ അടുത്ത ഏതാനും വിഭാഗങ്ങളിൽ ഈ മെത്തേഡുകളും ആ ക്ലാസും നമ്മൾ പരിശോധിക്കും. + +Hub-ൽ ഒരു പുതിയ റിപ്പോസിറ്ററി ഉണ്ടാക്കാൻ `create_repo` മെത്തേഡ് ഉപയോഗിക്കാം: + +```py +from huggingface_hub import create_repo + +create_repo("dummy-model") +``` + +ഇത് നിങ്ങളുടെ നെയിംസ്‌പേസിൽ `dummy-model` എന്ന റിപ്പോസിറ്ററി ഉണ്ടാക്കും. വേണമെങ്കിൽ, `organization` ആർഗ്യുമെന്റ് ഉപയോഗിച്ച് റിപ്പോസിറ്ററി ഏത് ഓർഗനൈസേഷന്റേതായിരിക്കണം എന്ന് നിങ്ങൾക്ക് വ്യക്തമാക്കാം: + +```py +from huggingface_hub import create_repo + +create_repo("dummy-model", organization="huggingface") +``` + +നിങ്ങൾ ആ ഓർഗനൈസേഷനിൽ അംഗമാണെങ്കിൽ, ഇത് `huggingface` നെയിംസ്‌പേസിൽ `dummy-model` റിപ്പോസിറ്ററി ഉണ്ടാക്കും. +ഉപകാരപ്രദമാകാവുന്ന മറ്റ് ആർഗ്യുമെന്റുകൾ: + +- `private`, റിപ്പോസിറ്ററി മറ്റുള്ളവർക്ക് കാണാവുന്നതായിരിക്കണോ വേണ്ടയോ എന്ന് വ്യക്തമാക്കാൻ. +- `token`, നിങ്ങളുടെ കാഷിൽ സംഭരിച്ചിരിക്കുന്ന ടോക്കണിന് പകരം ഒരു നിശ്ചിത ടോക്കൺ ഉപയോഗിക്കാൻ ആഗ്രഹിക്കുന്നെങ്കിൽ. +- `repo_type`, ഒരു മോഡലിന് പകരം ഒരു `dataset` അല്ലെങ്കിൽ ഒരു `space` ഉണ്ടാക്കാൻ ആഗ്രഹിക്കുന്നെങ്കിൽ. സ്വീകരിക്കുന്ന മൂല്യങ്ങൾ `"dataset"`, `"space"` എന്നിവയാണ്. + +റിപ്പോസിറ്ററി ഉണ്ടാക്കിക്കഴിഞ്ഞാൽ, അതിലേക്ക് ഫയലുകൾ ചേർക്കണം! ഇത് ചെയ്യാവുന്ന മൂന്ന് വഴികൾ കാണാൻ അടുത്ത വിഭാഗത്തിലേക്ക് പോകുക. + + +## വെബ് ഇന്റർഫേസ് ഉപയോഗിക്കുന്നു[[using-the-web-interface]] + +Hub-ൽ നേരിട്ട് റിപ്പോസിറ്ററികൾ കൈകാര്യം ചെയ്യാനുള്ള ടൂളുകൾ വെബ് ഇന്റർഫേസ് നൽകുന്നു. ഇന്റർഫേസ് ഉപയോഗിച്ച്, റിപ്പോസിറ്ററികൾ ഉണ്ടാക്കാനും, ഫയലുകൾ (വലുതായവ പോലും!) ചേർക്കാനും, മോഡലുകൾ പരിശോധിക്കാനും, ഡിഫുകൾ (diffs) കാണാനും, മറ്റ് പലതും എളുപ്പത്തിൽ ചെയ്യാം. + +ഒരു പുതിയ റിപ്പോസിറ്ററി ഉണ്ടാക്കാൻ, [huggingface.co/new](https://huggingface.co/new) സന്ദർശിക്കുക: + +
+ഒരു പുതിയ മോഡൽ റിപ്പോസിറ്ററി ഉണ്ടാക്കാൻ ഉപയോഗിക്കുന്ന പേജ്. +
+ +ആദ്യം, റിപ്പോസിറ്ററിയുടെ ഉടമ ആരാണെന്ന് വ്യക്തമാക്കുക: ഇത് നിങ്ങളോ, നിങ്ങൾ ഭാഗമായ ഏതെങ്കിലും ഓർഗനൈസേഷനോ ആകാം. ഒരു ഓർഗനൈസേഷൻ തിരഞ്ഞെടുത്താൽ, മോഡൽ ആ ഓർഗനൈസേഷന്റെ പേജിൽ പ്രദർശിപ്പിക്കപ്പെടും, കൂടാതെ ഓർഗനൈസേഷനിലെ ഓരോ അംഗത്തിനും റിപ്പോസിറ്ററിയിലേക്ക് സംഭാവന ചെയ്യാൻ കഴിയും. + +അടുത്തതായി, നിങ്ങളുടെ മോഡലിന്റെ പേര് നൽകുക. ഇത് തന്നെയായിരിക്കും റിപ്പോസിറ്ററിയുടെ പേരും. അവസാനമായി, നിങ്ങളുടെ മോഡൽ പബ്ലിക് ആയിരിക്കണോ പ്രൈവറ്റ് ആയിരിക്കണോ എന്ന് വ്യക്തമാക്കാം. പ്രൈവറ്റ് മോഡലുകൾ പൊതുജനങ്ങൾക്ക് കാണാൻ കഴിയില്ല. + +നിങ്ങളുടെ മോഡൽ റിപ്പോസിറ്ററി ഉണ്ടാക്കിയ ശേഷം, ഇതുപോലൊരു പേജ് നിങ്ങൾക്ക് കാണാൻ കഴിയണം: + +
+ഒരു പുതിയ റിപ്പോസിറ്ററി ഉണ്ടാക്കിയ ശേഷമുള്ള ഒഴിഞ്ഞ മോഡൽ പേജ്. +
+ +ഇവിടെയാണ് നിങ്ങളുടെ മോഡൽ ഹോസ്‌റ്റ് ചെയ്യപ്പെടുന്നത്. ഇതിൽ ഉള്ളടക്കം ചേർക്കാൻ തുടങ്ങാൻ, വെബ് ഇന്റർഫേസിൽ നിന്ന് നേരിട്ട് ഒരു README ഫയൽ ചേർക്കാം. + +
+Markdown സാധ്യതകൾ കാണിക്കുന്ന README ഫയൽ. +
+ +README ഫയൽ Markdown-ലാണ് — അതിൽ നിങ്ങൾക്ക് ഇഷ്ടമുള്ളതുപോലെ പരീക്ഷിക്കാം! ഈ അധ്യായത്തിന്റെ മൂന്നാം ഭാഗം ഒരു മോഡൽ കാർഡ് നിർമ്മിക്കുന്നതിനായി മാറ്റിവെച്ചിരിക്കുന്നു. നിങ്ങളുടെ മോഡലിന് മൂല്യം നൽകുന്നതിൽ ഇവയ്ക്ക് വളരെ പ്രധാന പങ്കുണ്ട്, കാരണം മോഡലിന് എന്തൊക്കെ ചെയ്യാൻ കഴിയുമെന്ന് മറ്റുള്ളവരോട് പറയുന്നത് ഇവിടെയാണ്. + +"Files and versions" ടാബ് നോക്കിയാൽ, അവിടെ ഇതുവരെ അധികം ഫയലുകൾ ഇല്ലെന്ന് കാണാം — നിങ്ങൾ ഇപ്പോൾ ഉണ്ടാക്കിയ *README.md*-ഉം, വലിയ ഫയലുകളുടെ ട്രാക്ക് സൂക്ഷിക്കുന്ന *.gitattributes* ഫയലും മാത്രം. + +
+'Files and versions' ടാബിൽ .gitattributes, README.md ഫയലുകൾ മാത്രം കാണിക്കുന്നു. +
+ +അടുത്തതായി, കുറച്ച് പുതിയ ഫയലുകൾ എങ്ങനെ ചേർക്കാം എന്ന് നോക്കാം. + +## മോഡൽ ഫയലുകൾ അപ്‌ലോഡ് ചെയ്യുന്നു[[uploading-the-model-files]] + +Hugging Face Hub-ൽ ഫയലുകൾ കൈകാര്യം ചെയ്യുന്ന സിസ്‌റ്റം, സാധാരണ ഫയലുകൾക്ക് git-ഉം, വലിയ ഫയലുകൾക്ക് git-lfs-ഉം ([Git Large File Storage](https://git-lfs.github.com/) എന്നതിന്റെ ചുരുക്കം) അടിസ്ഥാനമാക്കിയുള്ളതാണ്. + +അടുത്ത വിഭാഗത്തിൽ, Hub-ലേക്ക് ഫയലുകൾ അപ്‌ലോഡ് ചെയ്യാനുള്ള മൂന്ന് വ്യത്യസ്ത വഴികൾ നമ്മൾ പരിശോധിക്കും: `huggingface_hub` വഴിയും git കമാൻഡുകൾ വഴിയും. + +### `upload_file` രീതി[[the-uploadfile-approach]] + +`upload_file` ഉപയോഗിക്കാൻ നിങ്ങളുടെ സിസ്‌റ്റത്തിൽ git-ഉം git-lfs-ഉം ഇൻസ്‌റ്റാൾ ചെയ്തിരിക്കണമെന്നില്ല. HTTP POST റിക്വസ്‌റ്റുകൾ ഉപയോഗിച്ച് ഇത് ഫയലുകൾ നേരിട്ട് 🤗 Hub-ലേക്ക് പുഷ് ചെയ്യുന്നു. 5GB-യിൽ കൂടുതൽ വലുപ്പമുള്ള ഫയലുകൾ ഇത് കൈകാര്യം ചെയ്യില്ല എന്നതാണ് ഈ രീതിയുടെ ഒരു പരിമിതി. +നിങ്ങളുടെ ഫയലുകൾ 5GB-യിൽ കൂടുതലാണെങ്കിൽ, താഴെ വിശദീകരിക്കുന്ന മറ്റ് രണ്ട് രീതികൾ പിന്തുടരുക. + +API ഇങ്ങനെ ഉപയോഗിക്കാം: + +```py +from huggingface_hub import upload_file + +upload_file( + "/config.json", + path_in_repo="config.json", + repo_id="/dummy-model", +) +``` + +ഇത് ``-ൽ ലഭ്യമായ `config.json` ഫയലിനെ `config.json` എന്ന പേരിൽ `dummy-model` റിപ്പോസിറ്ററിയുടെ റൂട്ടിലേക്ക് അപ്‌ലോഡ് ചെയ്യും. +ഉപകാരപ്രദമാകാവുന്ന മറ്റ് ആർഗ്യുമെന്റുകൾ: + +- `token`, നിങ്ങളുടെ കാഷിൽ സംഭരിച്ചിരിക്കുന്ന ടോക്കണിന് പകരം ഒരു നിശ്ചിത ടോക്കൺ ഉപയോഗിക്കാൻ ആഗ്രഹിക്കുന്നെങ്കിൽ. +- `repo_type`, ഒരു മോഡലിന് പകരം ഒരു `dataset`-ലേക്കോ `space`-ലേക്കോ അപ്‌ലോഡ് ചെയ്യാൻ ആഗ്രഹിക്കുന്നെങ്കിൽ. സ്വീകരിക്കുന്ന മൂല്യങ്ങൾ `"dataset"`, `"space"` എന്നിവയാണ്. + + +### `Repository` ക്ലാസ്[[the-repository-class]] + +`Repository` ക്ലാസ് ഒരു ലോക്കൽ റിപ്പോസിറ്ററിയെ git-ന് സമാനമായ രീതിയിൽ കൈകാര്യം ചെയ്യുന്നു. git ഉപയോഗിക്കുമ്പോൾ ഉണ്ടാകാവുന്ന മിക്ക ബുദ്ധിമുട്ടുകളും മറച്ചുവെച്ച് (abstract), നമുക്ക് ആവശ്യമായ എല്ലാ ഫീച്ചറുകളും ഇത് നൽകുന്നു. + +ഈ ക്ലാസ് ഉപയോഗിക്കാൻ git-ഉം git-lfs-ഉം ഇൻസ്‌റ്റാൾ ചെയ്തിരിക്കണം; അതിനാൽ തുടങ്ങുന്നതിന് മുമ്പ് git-lfs ഇൻസ്‌റ്റാൾ ചെയ്ത് (ഇൻസ്‌റ്റാളേഷൻ നിർദ്ദേശങ്ങൾക്ക് [ഇവിടെ](https://git-lfs.github.com/) കാണുക) സെറ്റപ്പ് ചെയ്തിട്ടുണ്ടെന്ന് ഉറപ്പാക്കുക. + +നമ്മൾ ഇപ്പോൾ ഉണ്ടാക്കിയ റിപ്പോസിറ്ററിയുമായി പ്രവർത്തിക്കാൻ തുടങ്ങാൻ, റിമോട്ട് റിപ്പോസിറ്ററി ക്ലോൺ ചെയ്ത് അതിനെ ഒരു ലോക്കൽ ഫോൾഡറിലേക്ക് ഇനിഷ്യലൈസ് ചെയ്യുന്നതിലൂടെ തുടങ്ങാം: + +```py +from huggingface_hub import Repository + +repo = Repository("", clone_from="/dummy-model") +``` + +ഇത് നമ്മുടെ വർക്കിംഗ് ഡയറക്ടറിയിൽ `` എന്ന ഫോൾഡർ ഉണ്ടാക്കി. `create_repo` വഴി റിപ്പോസിറ്ററി ഉണ്ടാക്കുമ്പോൾ സൃഷ്ടിക്കപ്പെടുന്ന ഒരേയൊരു ഫയൽ `.gitattributes` ആയതിനാൽ, ഈ ഫോൾഡറിൽ ആ ഫയൽ മാത്രമേ ഉണ്ടാകൂ. + +ഇവിടെ നിന്ന്, പരമ്പരാഗത git മെത്തേഡുകളിൽ പലതും നമുക്ക് പ്രയോജനപ്പെടുത്താം: + +```py +repo.git_pull() +repo.git_add() +repo.git_commit() +repo.git_push() +repo.git_tag() +``` + +ഇനിയും പലതും! ലഭ്യമായ എല്ലാ മെത്തേഡുകളുടെയും ഒരു അവലോകനത്തിനായി [ഇവിടെ](https://github.com/huggingface/huggingface_hub/tree/main/src/huggingface_hub#advanced-programmatic-repository-management) ലഭ്യമായ `Repository` ഡോക്യുമെന്റേഷൻ ഒന്ന് നോക്കാൻ ഞങ്ങൾ ശുപാർശ ചെയ്യുന്നു. + +ഇപ്പോൾ, Hub-ലേക്ക് പുഷ് ചെയ്യാൻ ആഗ്രഹിക്കുന്ന ഒരു മോഡലും ഒരു ടോക്കണൈസറും നമ്മുടെ പക്കലുണ്ട്. റിപ്പോസിറ്ററി നമ്മൾ വിജയകരമായി ക്ലോൺ ചെയ്തിട്ടുണ്ട്, അതിനാൽ ആ റിപ്പോസിറ്ററിക്കുള്ളിൽ നമുക്ക് ഫയലുകൾ സേവ് ചെയ്യാം. + +ഏറ്റവും പുതിയ മാറ്റങ്ങൾ പുൾ ചെയ്ത് നമ്മുടെ ലോക്കൽ ക്ലോൺ കാലികമാണെന്ന് ആദ്യം ഉറപ്പാക്കാം: + +```py +repo.git_pull() +``` + +അത് കഴിഞ്ഞാൽ, മോഡൽ, ടോക്കണൈസർ ഫയലുകൾ സേവ് ചെയ്യാം: + +```py +model.save_pretrained("") +tokenizer.save_pretrained("") +``` + +``-ൽ ഇപ്പോൾ എല്ലാ മോഡൽ, ടോക്കണൈസർ ഫയലുകളും ഉണ്ട്. ഫയലുകൾ സ്‌റ്റേജിംഗ് ഏരിയയിലേക്ക് ചേർത്ത്, കമ്മിറ്റ് ചെയ്ത്, Hub-ലേക്ക് പുഷ് ചെയ്യുന്ന സാധാരണ git വർക്ക്‌ഫ്ലോ നമ്മൾ പിന്തുടരുന്നു: + +```py +repo.git_add() +repo.git_commit("Add model and tokenizer files") +repo.git_push() +``` + +അഭിനന്ദനങ്ങൾ! നിങ്ങൾ ആദ്യമായി Hub-ലേക്ക് ഫയലുകൾ പുഷ് ചെയ്തിരിക്കുന്നു. + +### git അടിസ്ഥാനമാക്കിയ രീതി[[the-git-based-approach]] + +ഫയലുകൾ അപ്‌ലോഡ് ചെയ്യാനുള്ള ഏറ്റവും അടിസ്ഥാനപരമായ രീതിയാണിത്: git-ഉം git-lfs-ഉം നേരിട്ട് ഉപയോഗിച്ചാണ് നമ്മൾ ഇത് ചെയ്യുന്നത്. മുമ്പത്തെ രീതികൾ ബുദ്ധിമുട്ടുകളിൽ ഭൂരിഭാഗവും മറച്ചുവെക്കുന്നു, എന്നാൽ താഴെയുള്ള രീതിയിൽ ചില മുന്നറിയിപ്പുകൾ (caveats) ഉള്ളതിനാൽ കുറച്ചുകൂടി സങ്കീർണ്ണമായ ഒരു ഉപയോഗസന്ദർഭം നമ്മൾ പിന്തുടരും. + +ഈ ക്ലാസ് ഉപയോഗിക്കാൻ git-ഉം git-lfs-ഉം ഇൻസ്‌റ്റാൾ ചെയ്തിരിക്കണം; അതിനാൽ തുടങ്ങുന്നതിന് മുമ്പ് [git-lfs](https://git-lfs.github.com/) ഇൻസ്‌റ്റാൾ ചെയ്ത് (ഇൻസ്‌റ്റാളേഷൻ നിർദ്ദേശങ്ങൾക്ക് ഇവിടെ കാണുക) സെറ്റപ്പ് ചെയ്തിട്ടുണ്ടെന്ന് ഉറപ്പാക്കുക. + +ആദ്യം git-lfs ഇനിഷ്യലൈസ് ചെയ്ത് തുടങ്ങാം: + +```bash +git lfs install +``` + +```bash +Updated git hooks. +Git LFS initialized. +``` + +അത് കഴിഞ്ഞാൽ, ആദ്യ ഘട്ടം നിങ്ങളുടെ മോഡൽ റിപ്പോസിറ്ററി ക്ലോൺ ചെയ്യുകയാണ്: + +```bash +git clone https://huggingface.co// +``` + +എന്റെ യൂസർനെയിം `lysandre` ആണ്, ഞാൻ `dummy` എന്ന മോഡൽ പേരാണ് ഉപയോഗിച്ചത്; അതിനാൽ എനിക്ക് കമാൻഡ് ഇങ്ങനെയാണ് വരുന്നത്: + +``` +git clone https://huggingface.co/lysandre/dummy +``` + +ഇപ്പോൾ എന്റെ വർക്കിംഗ് ഡയറക്ടറിയിൽ *dummy* എന്ന പേരിൽ ഒരു ഫോൾഡർ ഉണ്ട്. ആ ഫോൾഡറിലേക്ക് `cd` ചെയ്ത് അതിലെ ഉള്ളടക്കം നോക്കാം: + +```bash +cd dummy && ls +``` + +```bash +README.md +``` + +Hugging Face Hub-ന്റെ `create_repo` മെത്തേഡ് ഉപയോഗിച്ചാണ് നിങ്ങൾ റിപ്പോസിറ്ററി ഉണ്ടാക്കിയതെങ്കിൽ, ഈ ഫോൾഡറിൽ മറഞ്ഞിരിക്കുന്ന (hidden) ഒരു `.gitattributes` ഫയൽ മാത്രമേ ഉണ്ടാകൂ. മുൻ വിഭാഗത്തിലെ നിർദ്ദേശങ്ങൾ പിന്തുടർന്ന് വെബ് ഇന്റർഫേസ് ഉപയോഗിച്ചാണ് റിപ്പോസിറ്ററി ഉണ്ടാക്കിയതെങ്കിൽ, ഇവിടെ കാണിച്ചിരിക്കുന്നതുപോലെ, മറഞ്ഞിരിക്കുന്ന `.gitattributes` ഫയലിനൊപ്പം ഒരു *README.md* ഫയലും ഫോൾഡറിൽ ഉണ്ടാകും. + +ഒരു കോൺഫിഗറേഷൻ ഫയൽ, ഒരു വൊക്കാബുലറി ഫയൽ, അല്ലെങ്കിൽ ഏതാനും മെഗാബൈറ്റിൽ താഴെയുള്ള ഏത് ഫയലും പോലുള്ള സാധാരണ വലുപ്പമുള്ള ഒരു ഫയൽ ചേർക്കുന്നത്, git അടിസ്ഥാനമാക്കിയ ഏത് സിസ്‌റ്റത്തിലും ചെയ്യുന്നതുപോലെ തന്നെയാണ്. എന്നാൽ, വലിയ ഫയലുകൾ *huggingface.co*-യിലേക്ക് പുഷ് ചെയ്യാൻ അവ git-lfs വഴി രജിസ്‌റ്റർ ചെയ്യണം. + +നമ്മുടെ dummy റിപ്പോസിറ്ററിയിലേക്ക് കമ്മിറ്റ് ചെയ്യാൻ ആഗ്രഹിക്കുന്ന ഒരു മോഡലും ടോക്കണൈസറും ജനറേറ്റ് ചെയ്യാൻ, കുറച്ചുനേരത്തേക്ക് Python-ലേക്ക് തിരികെ പോകാം: + +{#if fw === 'pt'} +```py +from transformers import AutoModelForMaskedLM, AutoTokenizer + +checkpoint = "camembert-base" + +model = AutoModelForMaskedLM.from_pretrained(checkpoint) +tokenizer = AutoTokenizer.from_pretrained(checkpoint) + +# Do whatever with the model, train it, fine-tune it... + +model.save_pretrained("") +tokenizer.save_pretrained("") +``` +{:else} +```py +from transformers import TFAutoModelForMaskedLM, AutoTokenizer + +checkpoint = "camembert-base" + +model = TFAutoModelForMaskedLM.from_pretrained(checkpoint) +tokenizer = AutoTokenizer.from_pretrained(checkpoint) + +# Do whatever with the model, train it, fine-tune it... + +model.save_pretrained("") +tokenizer.save_pretrained("") +``` +{/if} + +ഇപ്പോൾ കുറച്ച് മോഡൽ, ടോക്കണൈസർ ആർട്ടിഫാക്റ്റുകൾ സേവ് ചെയ്തിരിക്കുന്നതിനാൽ, *dummy* ഫോൾഡർ ഒന്നുകൂടി നോക്കാം: + +```bash +ls +``` + +{#if fw === 'pt'} +```bash +config.json pytorch_model.bin README.md sentencepiece.bpe.model special_tokens_map.json tokenizer_config.json tokenizer.json +``` + +ഫയലുകളുടെ വലുപ്പം നോക്കിയാൽ (ഉദാഹരണത്തിന്, `ls -lh` ഉപയോഗിച്ച്), 400 MB-യിൽ കൂടുതൽ വലുപ്പമുള്ള മോഡൽ സ്‌റ്റേറ്റ് ഡിക്‌റ്റ് ഫയൽ (*pytorch_model.bin*) മാത്രമാണ് വേറിട്ടുനിൽക്കുന്നത് എന്ന് കാണാം. + +{:else} +```bash +config.json README.md sentencepiece.bpe.model special_tokens_map.json tf_model.h5 tokenizer_config.json tokenizer.json +``` + +ഫയലുകളുടെ വലുപ്പം നോക്കിയാൽ (ഉദാഹരണത്തിന്, `ls -lh` ഉപയോഗിച്ച്), 400 MB-യിൽ കൂടുതൽ വലുപ്പമുള്ള മോഡൽ സ്‌റ്റേറ്റ് ഡിക്‌റ്റ് ഫയൽ (*t5_model.h5*) മാത്രമാണ് വേറിട്ടുനിൽക്കുന്നത് എന്ന് കാണാം. + +{/if} + +> [!TIP] +> ✏️ വെബ് ഇന്റർഫേസിൽ നിന്ന് റിപ്പോസിറ്ററി ഉണ്ടാക്കുമ്പോൾ, *.bin*, *.h5* പോലുള്ള ചില എക്‌സ്‌റ്റൻഷനുകളുള്ള ഫയലുകളെ വലിയ ഫയലുകളായി പരിഗണിക്കാൻ *.gitattributes* ഫയൽ സ്വയമേവ സെറ്റപ്പ് ചെയ്യപ്പെടുന്നു; നിങ്ങളുടെ ഭാഗത്ത് ഒരു സെറ്റപ്പും ആവശ്യമില്ലാതെ git-lfs അവയെ ട്രാക്ക് ചെയ്യും. + +ഇനി പരമ്പരാഗത Git റിപ്പോസിറ്ററികളിൽ സാധാരണ ചെയ്യുന്നതുപോലെ നമുക്ക് മുന്നോട്ട് പോകാം. `git add` കമാൻഡ് ഉപയോഗിച്ച് എല്ലാ ഫയലുകളും Git-ന്റെ സ്‌റ്റേജിംഗ് എൻവയോൺമെന്റിലേക്ക് ചേർക്കാം: + +```bash +git add . +``` + +തുടർന്ന് ഇപ്പോൾ സ്‌റ്റേജ് ചെയ്തിരിക്കുന്ന ഫയലുകൾ ഒന്ന് നോക്കാം: + +```bash +git status +``` + +{#if fw === 'pt'} +```bash +On branch main +Your branch is up to date with 'origin/main'. + +Changes to be committed: + (use "git restore --staged ..." to unstage) + modified: .gitattributes + new file: config.json + new file: pytorch_model.bin + new file: sentencepiece.bpe.model + new file: special_tokens_map.json + new file: tokenizer.json + new file: tokenizer_config.json +``` +{:else} +```bash +On branch main +Your branch is up to date with 'origin/main'. + +Changes to be committed: + (use "git restore --staged ..." to unstage) + modified: .gitattributes + new file: config.json + new file: sentencepiece.bpe.model + new file: special_tokens_map.json + new file: tf_model.h5 + new file: tokenizer.json + new file: tokenizer_config.json +``` +{/if} + +അതുപോലെ, git-lfs-ന്റെ `status` കമാൻഡ് ഉപയോഗിച്ച് അത് ശരിയായ ഫയലുകളാണ് ട്രാക്ക് ചെയ്യുന്നതെന്ന് ഉറപ്പാക്കാം: + +```bash +git lfs status +``` + +{#if fw === 'pt'} +```bash +On branch main +Objects to be pushed to origin/main: + + +Objects to be committed: + + config.json (Git: bc20ff2) + pytorch_model.bin (LFS: 35686c2) + sentencepiece.bpe.model (LFS: 988bc5a) + special_tokens_map.json (Git: cb23931) + tokenizer.json (Git: 851ff3e) + tokenizer_config.json (Git: f0f7783) + +Objects not staged for commit: + + +``` + +*pytorch_model.bin*, *sentencepiece.bpe.model* എന്നിവ ഒഴികെ എല്ലാ ഫയലുകൾക്കും `Git` ആണ് ഹാൻഡ്‌ലർ എന്ന് കാണാം; ആ രണ്ടെണ്ണത്തിന് `LFS` ആണ്. കൊള്ളാം! + +{:else} +```bash +On branch main +Objects to be pushed to origin/main: + + +Objects to be committed: + + config.json (Git: bc20ff2) + sentencepiece.bpe.model (LFS: 988bc5a) + special_tokens_map.json (Git: cb23931) + tf_model.h5 (LFS: 86fce29) + tokenizer.json (Git: 851ff3e) + tokenizer_config.json (Git: f0f7783) + +Objects not staged for commit: + + +``` + +*t5_model.h5* ഒഴികെ എല്ലാ ഫയലുകൾക്കും `Git` ആണ് ഹാൻഡ്‌ലർ എന്ന് കാണാം; അതിന് `LFS` ആണ്. കൊള്ളാം! + +{/if} + +ഇനി അവസാന ഘട്ടങ്ങളിലേക്ക് കടക്കാം: കമ്മിറ്റ് ചെയ്യുകയും *huggingface.co* റിമോട്ട് റിപ്പോസിറ്ററിയിലേക്ക് പുഷ് ചെയ്യുകയും: + +```bash +git commit -m "First model version" +``` + +{#if fw === 'pt'} +```bash +[main b08aab1] First model version + 7 files changed, 29027 insertions(+) + 6 files changed, 36 insertions(+) + create mode 100644 config.json + create mode 100644 pytorch_model.bin + create mode 100644 sentencepiece.bpe.model + create mode 100644 special_tokens_map.json + create mode 100644 tokenizer.json + create mode 100644 tokenizer_config.json +``` +{:else} +```bash +[main b08aab1] First model version + 6 files changed, 36 insertions(+) + create mode 100644 config.json + create mode 100644 sentencepiece.bpe.model + create mode 100644 special_tokens_map.json + create mode 100644 tf_model.h5 + create mode 100644 tokenizer.json + create mode 100644 tokenizer_config.json +``` +{/if} + +നിങ്ങളുടെ ഇന്റർനെറ്റ് കണക്ഷന്റെ വേഗതയും ഫയലുകളുടെ വലുപ്പവും അനുസരിച്ച്, പുഷ് ചെയ്യാൻ കുറച്ച് സമയമെടുക്കാം: + +```bash +git push +``` + +```bash +Uploading LFS objects: 100% (1/1), 433 MB | 1.3 MB/s, done. +Enumerating objects: 11, done. +Counting objects: 100% (11/11), done. +Delta compression using up to 12 threads +Compressing objects: 100% (9/9), done. +Writing objects: 100% (9/9), 288.27 KiB | 6.27 MiB/s, done. +Total 9 (delta 1), reused 0 (delta 0), pack-reused 0 +To https://huggingface.co/lysandre/dummy + 891b41d..b08aab1 main -> main +``` + +{#if fw === 'pt'} +ഇത് പൂർത്തിയാകുമ്പോൾ മോഡൽ റിപ്പോസിറ്ററി നോക്കിയാൽ, അടുത്തിടെ ചേർത്ത എല്ലാ ഫയലുകളും നമുക്ക് കാണാം: + +
+'Files and versions' ടാബിൽ ഇപ്പോൾ അടുത്തിടെ അപ്‌ലോഡ് ചെയ്ത എല്ലാ ഫയലുകളും ഉണ്ട്. +
+ +മോഡൽ ഫയലുകളും കമ്മിറ്റുകളും പരിശോധിക്കാനും ഓരോ കമ്മിറ്റും വരുത്തിയ ഡിഫ് കാണാനും UI നിങ്ങളെ അനുവദിക്കുന്നു: + +
+സമീപകാല കമ്മിറ്റ് വരുത്തിയ ഡിഫ്. +
+{:else} +ഇത് പൂർത്തിയാകുമ്പോൾ മോഡൽ റിപ്പോസിറ്ററി നോക്കിയാൽ, അടുത്തിടെ ചേർത്ത എല്ലാ ഫയലുകളും നമുക്ക് കാണാം: + +
+'Files and versions' ടാബിൽ ഇപ്പോൾ അടുത്തിടെ അപ്‌ലോഡ് ചെയ്ത എല്ലാ ഫയലുകളും ഉണ്ട്. +
+ +മോഡൽ ഫയലുകളും കമ്മിറ്റുകളും പരിശോധിക്കാനും ഓരോ കമ്മിറ്റും വരുത്തിയ ഡിഫ് കാണാനും UI നിങ്ങളെ അനുവദിക്കുന്നു: + +
+സമീപകാല കമ്മിറ്റ് വരുത്തിയ ഡിഫ്. +
+{/if} diff --git a/chapters/ml/chapter4/4.mdx b/chapters/ml/chapter4/4.mdx new file mode 100644 index 000000000..dd1123f72 --- /dev/null +++ b/chapters/ml/chapter4/4.mdx @@ -0,0 +1,87 @@ +# ഒരു മോഡൽ കാർഡ് നിർമ്മിക്കുന്നു[[building-a-model-card]] + + + +ഒരു മോഡൽ റിപ്പോസിറ്ററിയിലെ മോഡൽ, ടോക്കണൈസർ ഫയലുകളോളം തന്നെ പ്രധാനമാണെന്ന് പറയാവുന്ന ഒരു ഫയലാണ് മോഡൽ കാർഡ്. ഇത് മോഡലിന്റെ കേന്ദ്ര നിർവചനമാണ്: കമ്മ്യൂണിറ്റിയിലെ മറ്റ് അംഗങ്ങൾക്ക് മോഡൽ പുനരുപയോഗിക്കാൻ കഴിയുമെന്നും ഫലങ്ങൾ വീണ്ടും ഉണ്ടാക്കിയെടുക്കാൻ കഴിയുമെന്നും (reproducibility) ഇത് ഉറപ്പുവരുത്തുന്നു, കൂടാതെ മറ്റ് അംഗങ്ങൾക്ക് തങ്ങളുടെ ആർട്ടിഫാക്റ്റുകൾ നിർമ്മിച്ചെടുക്കാനുള്ള ഒരു അടിത്തറയും ഇത് നൽകുന്നു. + +ട്രെയിനിംഗ്, ഇവാലുവേഷൻ (evaluation) പ്രക്രിയകൾ ഡോക്യുമെന്റ് ചെയ്യുന്നത്, ഒരു മോഡലിൽ നിന്ന് എന്ത് പ്രതീക്ഷിക്കണം എന്ന് മറ്റുള്ളവർക്ക് മനസ്സിലാക്കാൻ സഹായിക്കുന്നു — കൂടാതെ ഉപയോഗിച്ച ഡേറ്റയെക്കുറിച്ചും അതിൽ ചെയ്ത പ്രീപ്രോസസ്സിംഗിനെയും പോസ്‌റ്റ്‌പ്രോസസ്സിംഗിനെയും കുറിച്ചും മതിയായ വിവരങ്ങൾ നൽകുന്നത്, മോഡലിന്റെ പരിമിതികളും പക്ഷപാതങ്ങളും (biases), മോഡൽ ഉപകാരപ്രദമാകുന്നതും അല്ലാത്തതുമായ സന്ദർഭങ്ങളും തിരിച്ചറിയാനും മനസ്സിലാക്കാനും കഴിയുമെന്ന് ഉറപ്പാക്കുന്നു. + +അതിനാൽ, നിങ്ങളുടെ മോഡലിനെ വ്യക്തമായി നിർവചിക്കുന്ന ഒരു മോഡൽ കാർഡ് ഉണ്ടാക്കുന്നത് വളരെ പ്രധാനപ്പെട്ട ഒരു ഘട്ടമാണ്. ഇതിന് നിങ്ങളെ സഹായിക്കുന്ന ചില നുറുങ്ങുകൾ ഇവിടെ ഞങ്ങൾ നൽകുന്നു. നിങ്ങൾ മുമ്പ് കണ്ട *README.md* ഫയലിലൂടെയാണ് മോഡൽ കാർഡ് ഉണ്ടാക്കുന്നത്; അത് ഒരു Markdown ഫയലാണ്. + +"മോഡൽ കാർഡ്" എന്ന ആശയം Google-ലെ ഒരു ഗവേഷണ ദിശയിൽ നിന്ന് ഉത്ഭവിച്ചതാണ്; Margaret Mitchell et al. എഴുതിയ ["Model Cards for Model Reporting"](https://arxiv.org/abs/1810.03993) എന്ന പ്രബന്ധത്തിലാണ് ഇത് ആദ്യമായി പങ്കുവെച്ചത്. ഇവിടെ അടങ്ങിയിരിക്കുന്ന വിവരങ്ങളിൽ ഏറെയും ആ പ്രബന്ധത്തെ അടിസ്ഥാനമാക്കിയുള്ളതാണ്; പുനരുൽപ്പാദനക്ഷമത (reproducibility), പുനരുപയോഗം (reusability), നീതി (fairness) എന്നിവയ്ക്ക് വിലകൽപ്പിക്കുന്ന ഒരു ലോകത്ത് മോഡൽ കാർഡുകൾ എന്തുകൊണ്ട് ഇത്ര പ്രധാനമാണ് എന്ന് മനസ്സിലാക്കാൻ അത് ഒന്ന് വായിച്ചുനോക്കാൻ ഞങ്ങൾ ശുപാർശ ചെയ്യുന്നു. + +മോഡൽ എന്തിനുള്ളതാണ് എന്നതിന്റെ വളരെ ഹ്രസ്വമായ, ഉയർന്ന തലത്തിലുള്ള ഒരു അവലോകനത്തോടെയാണ് മോഡൽ കാർഡ് സാധാരണയായി ആരംഭിക്കുന്നത്; അതിനെ തുടർന്ന് താഴെ പറയുന്ന വിഭാഗങ്ങളിൽ കൂടുതൽ വിശദാംശങ്ങൾ വരുന്നു: + +- മോഡൽ വിവരണം (Model description) +- ഉദ്ദേശിച്ച ഉപയോഗങ്ങളും പരിമിതികളും (Intended uses & limitations) +- എങ്ങനെ ഉപയോഗിക്കണം (How to use) +- പരിമിതികളും പക്ഷപാതവും (Limitations and bias) +- ട്രെയിനിംഗ് ഡേറ്റ (Training data) +- ട്രെയിനിംഗ് നടപടിക്രമം (Training procedure) +- ഇവാലുവേഷൻ ഫലങ്ങൾ (Evaluation results) + +ഈ വിഭാഗങ്ങളിൽ ഓരോന്നിലും എന്തൊക്കെ ഉണ്ടായിരിക്കണം എന്ന് നോക്കാം. + +### മോഡൽ വിവരണം (Model description)[[model-description]] + +മോഡൽ വിവരണം മോഡലിനെക്കുറിച്ചുള്ള അടിസ്ഥാന വിശദാംശങ്ങൾ നൽകുന്നു. ആർക്കിടെക്ചർ, പതിപ്പ് (version), ഇത് ഒരു പ്രബന്ധത്തിലാണോ അവതരിപ്പിച്ചത്, ഒറിജിനൽ ഇംപ്ലിമെന്റേഷൻ ലഭ്യമാണോ, രചയിതാവ് ആരാണ്, മോഡലിനെക്കുറിച്ചുള്ള പൊതുവായ വിവരങ്ങൾ എന്നിവ ഇതിൽ ഉൾപ്പെടുന്നു. പകർപ്പവകാശം (copyright) എന്തെങ്കിലുമുണ്ടെങ്കിൽ അത് ഇവിടെ രേഖപ്പെടുത്തണം. ട്രെയിനിംഗ് നടപടിക്രമങ്ങളെയും പാരാമീറ്ററുകളെയും കുറിച്ചുള്ള പൊതുവിവരങ്ങളും പ്രധാനപ്പെട്ട നിരാകരണങ്ങളും (disclaimers) ഈ വിഭാഗത്തിൽ പരാമർശിക്കാം. + +### ഉദ്ദേശിച്ച ഉപയോഗങ്ങളും പരിമിതികളും (Intended uses & limitations)[[intended-uses-limitations]] + +മോഡൽ ഏതൊക്കെ ഉപയോഗ സാഹചര്യങ്ങൾക്കായി (use cases) ഉദ്ദേശിച്ചിട്ടുള്ളതാണ് എന്ന് ഇവിടെ നിങ്ങൾ വിവരിക്കുന്നു — അത് പ്രയോഗിക്കാൻ കഴിയുന്ന ഭാഷകൾ, മേഖലകൾ, ഡൊമെയ്‌നുകൾ എന്നിവ ഉൾപ്പെടെ. മോഡലിന്റെ പരിധിക്ക് പുറത്താണെന്ന് അറിയപ്പെടുന്നതോ, മോഡൽ മികച്ച രീതിയിൽ പ്രവർത്തിക്കാൻ സാധ്യതയില്ലാത്തതോ ആയ മേഖലകളും മോഡൽ കാർഡിന്റെ ഈ വിഭാഗത്തിൽ രേഖപ്പെടുത്താം. + +### എങ്ങനെ ഉപയോഗിക്കണം (How to use)[[how-to-use]] + +മോഡൽ എങ്ങനെ ഉപയോഗിക്കാം എന്നതിന്റെ ചില ഉദാഹരണങ്ങൾ ഈ വിഭാഗത്തിൽ ഉൾപ്പെടുത്തണം. `pipeline()` ഫംഗ്‌ഷന്റെ ഉപയോഗം, മോഡൽ, ടോക്കണൈസർ ക്ലാസുകളുടെ ഉപയോഗം, സഹായകമാകുമെന്ന് നിങ്ങൾ കരുതുന്ന മറ്റേതെങ്കിലും കോഡ് എന്നിവ ഇവിടെ കാണിക്കാം. + +### ട്രെയിനിംഗ് ഡേറ്റ (Training data)[[training-data]] + +മോഡൽ ഏത് ഡേറ്റാസെറ്റിലാണ് (അല്ലെങ്കിൽ ഡേറ്റാസെറ്റുകളിലാണ്) ട്രെയിൻ ചെയ്തത് എന്ന് ഈ ഭാഗം സൂചിപ്പിക്കണം. ഡേറ്റാസെറ്റുകളുടെ ഒരു ഹ്രസ്വ വിവരണവും നൽകുന്നത് നല്ലതാണ്. + +### ട്രെയിനിംഗ് നടപടിക്രമം (Training procedure)[[training-procedure]] + +പുനരുൽപ്പാദനക്ഷമതയുടെ (reproducibility) കാഴ്ചപ്പാടിൽ ഉപകാരപ്രദമായ, ട്രെയിനിംഗിന്റെ പ്രസക്തമായ എല്ലാ വശങ്ങളും ഈ വിഭാഗത്തിൽ നിങ്ങൾ വിവരിക്കണം. ഡേറ്റയിൽ ചെയ്ത പ്രീപ്രോസസ്സിംഗും പോസ്‌റ്റ്‌പ്രോസസ്സിംഗും, മോഡൽ എത്ര എപ്പോക്കുകൾ (epochs) ട്രെയിൻ ചെയ്തു, ബാച്ച് സൈസ്, ലേണിംഗ് റേറ്റ് തുടങ്ങിയ വിശദാംശങ്ങളും ഇതിൽ ഉൾപ്പെടുന്നു. + +### വേരിയബിളുകളും മെട്രിക്കുകളും (Variable and metrics)[[variable-and-metrics]] + +ഇവാലുവേഷനായി നിങ്ങൾ ഉപയോഗിക്കുന്ന മെട്രിക്കുകളും നിങ്ങൾ അളക്കുന്ന വിവിധ ഘടകങ്ങളും ഇവിടെ വിവരിക്കണം. ഏതൊക്കെ മെട്രിക്കുകൾ ഉപയോഗിച്ചു, ഏത് ഡേറ്റാസെറ്റിലും ഏത് ഡേറ്റാസെറ്റ് സ്‌പ്ലിറ്റിലും എന്ന് പരാമർശിക്കുന്നത്, നിങ്ങളുടെ മോഡലിന്റെ പ്രകടനം മറ്റ് മോഡലുകളുടേതുമായി താരതമ്യം ചെയ്യുന്നത് എളുപ്പമാക്കുന്നു. ഉദ്ദേശിച്ച ഉപയോക്താക്കൾ, ഉപയോഗ സാഹചര്യങ്ങൾ തുടങ്ങിയ മുൻ വിഭാഗങ്ങളിലെ വിവരങ്ങളെ അടിസ്ഥാനമാക്കിയായിരിക്കണം ഇവ തിരഞ്ഞെടുക്കുന്നത്. + +### ഇവാലുവേഷൻ ഫലങ്ങൾ (Evaluation results)[[evaluation-results]] + +അവസാനമായി, ഇവാലുവേഷൻ ഡേറ്റാസെറ്റിൽ മോഡൽ എത്ര നന്നായി പ്രവർത്തിക്കുന്നു എന്നതിന്റെ ഒരു സൂചന നൽകുക. മോഡൽ ഒരു ഡിസിഷൻ ത്രെഷോൾഡ് (decision threshold) ഉപയോഗിക്കുന്നുണ്ടെങ്കിൽ, ഇവാലുവേഷനിൽ ഉപയോഗിച്ച ത്രെഷോൾഡ് നൽകുകയോ, അല്ലെങ്കിൽ ഉദ്ദേശിച്ച ഉപയോഗങ്ങൾക്കായി വ്യത്യസ്ത ത്രെഷോൾഡുകളിൽ നടത്തിയ ഇവാലുവേഷന്റെ വിശദാംശങ്ങൾ നൽകുകയോ ചെയ്യുക. + +## ഉദാഹരണം[[example]] + +നന്നായി തയ്യാറാക്കിയ മോഡൽ കാർഡുകളുടെ ചില ഉദാഹരണങ്ങൾക്കായി താഴെ പറയുന്നവ നോക്കുക: + +- [`bert-base-cased`](https://huggingface.co/bert-base-cased) +- [`gpt2`](https://huggingface.co/gpt2) +- [`distilbert`](https://huggingface.co/distilbert-base-uncased) + +വിവിധ സ്ഥാപനങ്ങളിൽ നിന്നും കമ്പനികളിൽ നിന്നുമുള്ള കൂടുതൽ ഉദാഹരണങ്ങൾ [ഇവിടെ](https://github.com/huggingface/model_card/blob/master/examples.md) ലഭ്യമാണ്. + +## കുറിപ്പ്[[note]] + +മോഡലുകൾ പ്രസിദ്ധീകരിക്കുമ്പോൾ മോഡൽ കാർഡുകൾ നിർബന്ധമല്ല; ഒന്ന് ഉണ്ടാക്കുമ്പോൾ മുകളിൽ വിവരിച്ച എല്ലാ വിഭാഗങ്ങളും ഉൾപ്പെടുത്തേണ്ട ആവശ്യവുമില്ല. എന്നിരുന്നാലും, മോഡലിന്റെ വ്യക്തമായ ഡോക്യുമെന്റേഷൻ ഭാവിയിലെ ഉപയോക്താക്കൾക്ക് ഗുണം മാത്രമേ ചെയ്യൂ; അതിനാൽ നിങ്ങളുടെ അറിവും കഴിവും അനുസരിച്ച് കഴിയുന്നത്ര വിഭാഗങ്ങൾ പൂരിപ്പിക്കാൻ ഞങ്ങൾ ശുപാർശ ചെയ്യുന്നു. + +## മോഡൽ കാർഡ് മെറ്റാഡേറ്റ[[model-card-metadata]] + +Hugging Face Hub ഒന്ന് പരതി നോക്കിയിട്ടുണ്ടെങ്കിൽ, ചില മോഡലുകൾ ചില പ്രത്യേക വിഭാഗങ്ങളിൽ പെടുന്നതായി നിങ്ങൾ കണ്ടിട്ടുണ്ടാകും: ടാസ്‌കുകൾ, ഭാഷകൾ, ലൈബ്രറികൾ തുടങ്ങിയവ അനുസരിച്ച് അവയെ ഫിൽട്ടർ ചെയ്യാൻ കഴിയും. മോഡൽ കാർഡിന്റെ ഹെഡറിൽ നിങ്ങൾ ചേർക്കുന്ന മെറ്റാഡേറ്റ അനുസരിച്ചാണ് ഒരു മോഡൽ ഏതൊക്കെ വിഭാഗങ്ങളിൽ പെടുന്നു എന്ന് തിരിച്ചറിയുന്നത്. + +ഉദാഹരണത്തിന്, [`camembert-base` മോഡൽ കാർഡ്](https://huggingface.co/camembert-base/blob/main/README.md) ഒന്ന് നോക്കിയാൽ, മോഡൽ കാർഡ് ഹെഡറിൽ താഴെ പറയുന്ന വരികൾ നിങ്ങൾക്ക് കാണാം: + +``` +--- +language: fr +license: mit +datasets: +- oscar +--- +``` + +ഈ മെറ്റാഡേറ്റ Hugging Face Hub പാഴ്‌സ് ചെയ്യുന്നു; അതിലൂടെ, ഈ മോഡൽ MIT ലൈസൻസുള്ള, Oscar ഡേറ്റാസെറ്റിൽ ട്രെയിൻ ചെയ്ത ഒരു ഫ്രഞ്ച് മോഡലാണെന്ന് Hub തിരിച്ചറിയുന്നു. + +ഭാഷകൾ, ലൈസൻസുകൾ, ടാഗുകൾ, ഡേറ്റാസെറ്റുകൾ, മെട്രിക്കുകൾ എന്നിവയും, ട്രെയിനിംഗ് സമയത്ത് മോഡൽ നേടിയ ഇവാലുവേഷൻ ഫലങ്ങളും വ്യക്തമാക്കാൻ [പൂർണ്ണ മോഡൽ കാർഡ് സ്‌പെസിഫിക്കേഷൻ](https://github.com/huggingface/hub-docs/blame/main/modelcard.md) അനുവദിക്കുന്നു. diff --git a/chapters/ml/chapter4/5.mdx b/chapters/ml/chapter4/5.mdx new file mode 100644 index 000000000..251b99ce0 --- /dev/null +++ b/chapters/ml/chapter4/5.mdx @@ -0,0 +1,12 @@ +# ഭാഗം 1 പൂർത്തിയായി![[part-1-completed]] + + + +ഇത് കോഴ്‌സിന്റെ ആദ്യ ഭാഗത്തിന്റെ അവസാനമാണ്! ഭാഗം 2 നവംബർ 15-ന് ഒരു വലിയ കമ്മ്യൂണിറ്റി ഇവന്റോടെ പുറത്തിറങ്ങും; കൂടുതൽ വിവരങ്ങൾ [ഇവിടെ](https://huggingface.co/blog/course-launch-event) കാണുക. + +ഒരു ടെക്‌സ്‌റ്റ് ക്ലാസിഫിക്കേഷൻ പ്രശ്നത്തിൽ (ഒറ്റ വാക്യങ്ങളോ വാക്യ ജോഡികളോ) ഒരു പ്രീട്രെയിൻഡ് മോഡൽ ഫൈൻ-ട്യൂൺ ചെയ്യാനും അതിന്റെ ഫലം Model Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യാനും ഇപ്പോൾ നിങ്ങൾക്ക് കഴിയണം. ഈ ആദ്യ ഭാഗം നിങ്ങൾ നന്നായി പഠിച്ചു എന്ന് ഉറപ്പാക്കാൻ, നിങ്ങൾക്ക് താൽപ്പര്യമുള്ള ഒരു പ്രശ്നത്തിൽ കൃത്യമായി അതുതന്നെ ചെയ്തുനോക്കണം (നിങ്ങൾ മറ്റൊരു ഭാഷ സംസാരിക്കുന്ന ആളാണെങ്കിൽ അത് ഇംഗ്ലീഷിൽ തന്നെ ആകണമെന്നില്ല)! [Hugging Face ഫോറങ്ങളിൽ](https://discuss.huggingface.co/) നിങ്ങൾക്ക് സഹായം ലഭിക്കും; പൂർത്തിയാക്കിയ ശേഷം നിങ്ങളുടെ പ്രോജക്റ്റ് [ഈ ടോപ്പിക്കിൽ](https://discuss.huggingface.co/t/share-your-projects/6803) പങ്കുവെക്കാം. + +ഇതുപയോഗിച്ച് നിങ്ങൾ എന്തൊക്കെ നിർമ്മിക്കുമെന്ന് കാണാൻ ഞങ്ങൾ ആകാംക്ഷയോടെ കാത്തിരിക്കുന്നു! diff --git a/chapters/ml/chapter4/6.mdx b/chapters/ml/chapter4/6.mdx new file mode 100644 index 000000000..e57ada3c6 --- /dev/null +++ b/chapters/ml/chapter4/6.mdx @@ -0,0 +1,228 @@ + + + + +# അധ്യായത്തിന്റെ അവസാന ക്വിസ്[[end-of-chapter-quiz]] + + + +ഈ അധ്യായത്തിൽ നിങ്ങൾ പഠിച്ചത് ഒന്ന് പരീക്ഷിച്ചുനോക്കാം! + +### 1. Hub-ലെ മോഡലുകൾ എന്തിലേക്കാണ് പരിമിതപ്പെടുത്തിയിരിക്കുന്നത്? + + + +### 2. Hub-ലെ മോഡലുകൾ എങ്ങനെ കൈകാര്യം ചെയ്യാം? + +git-lfs ഉപയോഗിക്കുന്നു.", + correct: true + } + ]} +/> + +### 3. Hugging Face Hub വെബ് ഇന്റർഫേസ് ഉപയോഗിച്ച് നിങ്ങൾക്ക് എന്തൊക്കെ ചെയ്യാൻ കഴിയും? + + + +### 4. എന്താണ് ഒരു മോഡൽ കാർഡ്? + + + +### 5. 🤗 Transformers ലൈബ്രറിയിലെ ഈ ഒബ്‌ജക്റ്റുകളിൽ ഏതൊക്കെ `push_to_hub()` ഉപയോഗിച്ച് Hub-ൽ നേരിട്ട് പങ്കുവെക്കാൻ കഴിയും? + +{#if fw === 'pt'} +push_to_hub മെത്തേഡ് ഉണ്ട്; അത് ഉപയോഗിച്ചാൽ ടോക്കണൈസറിന്റെ എല്ലാ ഫയലുകളും (വൊക്കാബുലറി, ടോക്കണൈസറിന്റെ ആർക്കിടെക്ചർ മുതലായവ) ഒരു നിശ്ചിത റിപ്പോയിലേക്ക് പുഷ് ചെയ്യപ്പെടും. എന്നാൽ ഇത് മാത്രമല്ല ശരിയായ ഉത്തരം!", + correct: true + }, + { + text: "ഒരു മോഡൽ കോൺഫിഗറേഷൻ", + explain: "ശരിയാണ്! എല്ലാ മോഡൽ കോൺഫിഗറേഷനുകൾക്കും push_to_hub മെത്തേഡ് ഉണ്ട്; അത് ഉപയോഗിച്ചാൽ അവ ഒരു നിശ്ചിത റിപ്പോയിലേക്ക് പുഷ് ചെയ്യപ്പെടും. മറ്റെന്തൊക്കെ നിങ്ങൾക്ക് പങ്കുവെക്കാൻ കഴിയും?", + correct: true + }, + { + text: "ഒരു മോഡൽ", + explain: "ശരിയാണ്! എല്ലാ മോഡലുകൾക്കും push_to_hub മെത്തേഡ് ഉണ്ട്; അത് ഉപയോഗിച്ചാൽ മോഡലുകളും അവയുടെ കോൺഫിഗറേഷൻ ഫയലുകളും ഒരു നിശ്ചിത റിപ്പോയിലേക്ക് പുഷ് ചെയ്യപ്പെടും. എന്നാൽ നിങ്ങൾക്ക് പങ്കുവെക്കാൻ കഴിയുന്നത് ഇത് മാത്രമല്ല.", + correct: true + }, + { + text: "ഒരു Trainer", + explain: "ശരിയാണ് — Trainer-ഉം push_to_hub മെത്തേഡ് ഇംപ്ലിമെന്റ് ചെയ്യുന്നു; അത് ഉപയോഗിച്ചാൽ മോഡൽ, അതിന്റെ കോൺഫിഗറേഷൻ, ടോക്കണൈസർ, ഒരു മോഡൽ കാർഡ് ഡ്രാഫ്‌റ്റ് എന്നിവ ഒരു നിശ്ചിത റിപ്പോയിലേക്ക് അപ്‌ലോഡ് ചെയ്യപ്പെടും. മറ്റൊരു ഉത്തരം കൂടി പരീക്ഷിക്കുക!", + correct: true + } + ]} +/> +{:else} +push_to_hub മെത്തേഡ് ഉണ്ട്; അത് ഉപയോഗിച്ചാൽ ടോക്കണൈസറിന്റെ എല്ലാ ഫയലുകളും (വൊക്കാബുലറി, ടോക്കണൈസറിന്റെ ആർക്കിടെക്ചർ മുതലായവ) ഒരു നിശ്ചിത റിപ്പോയിലേക്ക് പുഷ് ചെയ്യപ്പെടും. എന്നാൽ ഇത് മാത്രമല്ല ശരിയായ ഉത്തരം!", + correct: true + }, + { + text: "ഒരു മോഡൽ കോൺഫിഗറേഷൻ", + explain: "ശരിയാണ്! എല്ലാ മോഡൽ കോൺഫിഗറേഷനുകൾക്കും push_to_hub മെത്തേഡ് ഉണ്ട്; അത് ഉപയോഗിച്ചാൽ അവ ഒരു നിശ്ചിത റിപ്പോയിലേക്ക് പുഷ് ചെയ്യപ്പെടും. മറ്റെന്തൊക്കെ നിങ്ങൾക്ക് പങ്കുവെക്കാൻ കഴിയും?", + correct: true + }, + { + text: "ഒരു മോഡൽ", + explain: "ശരിയാണ്! എല്ലാ മോഡലുകൾക്കും push_to_hub മെത്തേഡ് ഉണ്ട്; അത് ഉപയോഗിച്ചാൽ മോഡലുകളും അവയുടെ കോൺഫിഗറേഷൻ ഫയലുകളും ഒരു നിശ്ചിത റിപ്പോയിലേക്ക് പുഷ് ചെയ്യപ്പെടും. എന്നാൽ നിങ്ങൾക്ക് പങ്കുവെക്കാൻ കഴിയുന്നത് ഇത് മാത്രമല്ല.", + correct: true + }, + { + text: "ഒരു പ്രത്യേക callback ഉപയോഗിച്ച് മുകളിൽ പറഞ്ഞവയെല്ലാം", + explain: "ശരിയാണ് — PushToHubCallback ട്രെയിനിംഗ് സമയത്ത് ഈ ഒബ്‌ജക്റ്റുകളെല്ലാം കൃത്യമായ ഇടവേളകളിൽ ഒരു റിപ്പോയിലേക്ക് അയയ്ക്കും.", + correct: true + } + ]} +/> +{/if} + +### 6. `push_to_hub()` മെത്തേഡോ CLI ടൂളുകളോ ഉപയോഗിക്കുമ്പോൾ ആദ്യ ഘട്ടം എന്താണ്? + + + +### 7. നിങ്ങൾ ഒരു മോഡലും ഒരു ടോക്കണൈസറും ഉപയോഗിക്കുന്നു — അവ എങ്ങനെ Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യാം? + +huggingface_hub യൂട്ടിലിറ്റിയിൽ പൊതിഞ്ഞുകൊണ്ട് (wrap).", + explain: "മോഡലുകളും ടോക്കണൈസറുകളും ഇതിനകം തന്നെ huggingface_hub യൂട്ടിലിറ്റികൾ പ്രയോജനപ്പെടുത്തുന്നുണ്ട്: അധികമായി പൊതിയേണ്ട ആവശ്യമില്ല!" + }, + { + text: "അവയെ ഡിസ്‌കിൽ സേവ് ചെയ്ത് transformers-cli upload-model വിളിച്ചുകൊണ്ട്", + explain: "upload-model എന്ന കമാൻഡ് നിലവിലില്ല." + } + ]} +/> + +### 8. `Repository` ക്ലാസ് ഉപയോഗിച്ച് ഏതൊക്കെ git ഓപ്പറേഷനുകൾ നിങ്ങൾക്ക് ചെയ്യാൻ കഴിയും? + +git_commit() മെത്തേഡ് ഉണ്ട്.", + correct: true + }, + { + text: "ഒരു പുൾ (pull)", + explain: "അതാണ് git_pull() മെത്തേഡിന്റെ ഉദ്ദേശ്യം.", + correct: true + }, + { + text: "ഒരു പുഷ് (push)", + explain: "git_push() മെത്തേഡ് ഇത് ചെയ്യുന്നു.", + correct: true + }, + { + text: "ഒരു മെർജ് (merge)", + explain: "ഇല്ല, ഈ API ഉപയോഗിച്ച് ആ ഓപ്പറേഷൻ ഒരിക്കലും സാധ്യമാകില്ല." + } + ]} +/> diff --git a/chapters/ml/chapter5/1.mdx b/chapters/ml/chapter5/1.mdx new file mode 100644 index 000000000..0ba898e54 --- /dev/null +++ b/chapters/ml/chapter5/1.mdx @@ -0,0 +1,22 @@ +# ആമുഖം[[introduction]] + + + +[അധ്യായം 3](/course/chapter3)-ൽ 🤗 Datasets ലൈബ്രറിയുമായി നിങ്ങൾക്ക് ആദ്യ പരിചയം ലഭിച്ചു; ഒരു മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യുമ്പോൾ മൂന്ന് പ്രധാന ഘട്ടങ്ങളുണ്ടെന്ന് നിങ്ങൾ കണ്ടു: + +1. Hugging Face Hub-ൽ നിന്ന് ഒരു ഡേറ്റാസെറ്റ് ലോഡ് ചെയ്യുക. +2. `Dataset.map()` ഉപയോഗിച്ച് ഡേറ്റ പ്രീപ്രോസസ്സ് ചെയ്യുക. +3. മെട്രിക്കുകൾ ലോഡ് ചെയ്യുകയും കണക്കാക്കുകയും ചെയ്യുക. + +എന്നാൽ 🤗 Datasets-ന് ചെയ്യാൻ കഴിയുന്ന കാര്യങ്ങളുടെ ഒരു ചെറിയ അംശം മാത്രമാണിത്! ഈ അധ്യായത്തിൽ, ഈ ലൈബ്രറിയെ നമ്മൾ ആഴത്തിൽ പരിശോധിക്കും. അതിനിടയിൽ, താഴെപ്പറയുന്ന ചോദ്യങ്ങൾക്ക് നമ്മൾ ഉത്തരം കണ്ടെത്തും: + +* നിങ്ങളുടെ ഡേറ്റാസെറ്റ് Hub-ൽ ഇല്ലെങ്കിൽ എന്ത് ചെയ്യും? +* ഒരു ഡേറ്റാസെറ്റ് എങ്ങനെ വേണ്ടതുപോലെ മുറിച്ചും തിരിച്ചും (slice and dice) കൈകാര്യം ചെയ്യാം? (പിന്നെ, നിങ്ങൾക്ക് _ശരിക്കും_ Pandas ഉപയോഗിക്കേണ്ടി വന്നാലോ?) +* നിങ്ങളുടെ ഡേറ്റാസെറ്റ് വളരെ വലുതും നിങ്ങളുടെ ലാപ്‌ടോപ്പിന്റെ RAM ഉരുക്കിക്കളയുന്നതും ആണെങ്കിൽ എന്ത് ചെയ്യും? +* എന്താണ് ഈ "മെമ്മറി മാപ്പിംഗ്" (memory mapping), Apache Arrow എന്നൊക്കെ പറയുന്നത്? +* നിങ്ങളുടെ സ്വന്തം ഡേറ്റാസെറ്റ് എങ്ങനെ ഉണ്ടാക്കി Hub-ലേക്ക് പുഷ് ചെയ്യാം? + +ഇവിടെ നിങ്ങൾ പഠിക്കുന്ന ടെക്‌നിക്കുകൾ [അധ്യായം 6](/course/chapter6)-ലെയും [അധ്യായം 7](/course/chapter7)-ലെയും അഡ്വാൻസ്ഡ് ടോക്കണൈസേഷൻ, ഫൈൻ-ട്യൂണിംഗ് ടാസ്‌ക്കുകൾക്കായി നിങ്ങളെ തയ്യാറാക്കും -- അതുകൊണ്ട് ഒരു കാപ്പിയെടുത്ത് നമുക്ക് തുടങ്ങാം! diff --git a/chapters/ml/chapter5/2.mdx b/chapters/ml/chapter5/2.mdx new file mode 100644 index 000000000..e058e43e9 --- /dev/null +++ b/chapters/ml/chapter5/2.mdx @@ -0,0 +1,158 @@ +# എന്റെ ഡേറ്റാസെറ്റ് Hub-ൽ ഇല്ലെങ്കിലോ?[[what-if-my-dataset-isnt-on-the-hub]] + + + +ഡേറ്റാസെറ്റുകൾ ഡൗൺലോഡ് ചെയ്യാൻ [Hugging Face Hub](https://huggingface.co/datasets) എങ്ങനെ ഉപയോഗിക്കണമെന്ന് നിങ്ങൾക്ക് അറിയാം, എന്നാൽ നിങ്ങളുടെ ലാപ്‌ടോപ്പിലോ ഒരു റിമോട്ട് സെർവറിലോ സൂക്ഷിച്ചിരിക്കുന്ന ഡേറ്റയുമായി പ്രവർത്തിക്കേണ്ടി വരുന്ന സാഹചര്യങ്ങൾ നിങ്ങൾക്ക് പലപ്പോഴും ഉണ്ടാകും. Hugging Face Hub-ൽ ലഭ്യമല്ലാത്ത ഡേറ്റാസെറ്റുകൾ ലോഡ് ചെയ്യാൻ 🤗 Datasets എങ്ങനെ ഉപയോഗിക്കാമെന്ന് ഈ ഭാഗത്തിൽ ഞങ്ങൾ നിങ്ങൾക്ക് കാണിച്ചുതരും. + + + +## ലോക്കൽ, റിമോട്ട് ഡേറ്റാസെറ്റുകളുമായി പ്രവർത്തിക്കുന്നു[[working-with-local-and-remote-datasets]] + +ലോക്കൽ, റിമോട്ട് ഡേറ്റാസെറ്റുകൾ ലോഡ് ചെയ്യുന്നത് കൈകാര്യം ചെയ്യാൻ 🤗 Datasets ലോഡിംഗ് സ്‌ക്രിപ്‌റ്റുകൾ (loading scripts) നൽകുന്നു. താഴെപ്പറയുന്നവ പോലുള്ള നിരവധി സാധാരണ ഡേറ്റാ ഫോർമാറ്റുകളെ ഇത് പിന്തുണയ്ക്കുന്നു: + +| ഡേറ്റാ ഫോർമാറ്റ് | ലോഡിംഗ് സ്‌ക്രിപ്‌റ്റ് | ഉദാഹരണം | +| :----------------: | :------------: | :-----------------------------------------------------: | +| CSV & TSV | `csv` | `load_dataset("csv", data_files="my_file.csv")` | +| ടെക്‌സ്‌റ്റ് ഫയലുകൾ | `text` | `load_dataset("text", data_files="my_file.txt")` | +| JSON & JSON Lines | `json` | `load_dataset("json", data_files="my_file.jsonl")` | +| പിക്കിൾ ചെയ്ത DataFrame-കൾ | `pandas` | `load_dataset("pandas", data_files="my_dataframe.pkl")` | + +പട്ടികയിൽ കാണിച്ചിരിക്കുന്നതുപോലെ, ഓരോ ഡേറ്റാ ഫോർമാറ്റിനും `load_dataset()` ഫംഗ്‌ഷനിൽ ലോഡിംഗ് സ്‌ക്രിപ്‌റ്റിന്റെ തരവും, ഒന്നോ അതിലധികമോ ഫയലുകളുടെ പാത വ്യക്തമാക്കുന്ന ഒരു `data_files` ആർഗ്യുമെന്റും നൽകിയാൽ മാത്രം മതി. ലോക്കൽ ഫയലുകളിൽ നിന്ന് ഒരു ഡേറ്റാസെറ്റ് ലോഡ് ചെയ്തുകൊണ്ട് നമുക്ക് തുടങ്ങാം; റിമോട്ട് ഫയലുകളുമായി ഇതേ കാര്യം എങ്ങനെ ചെയ്യാമെന്ന് പിന്നീട് നോക്കാം. + +## ഒരു ലോക്കൽ ഡേറ്റാസെറ്റ് ലോഡ് ചെയ്യുന്നു[[loading-a-local-dataset]] + +ഈ ഉദാഹരണത്തിനായി നമ്മൾ [SQuAD-it ഡേറ്റാസെറ്റ്](https://github.com/crux82/squad-it/) ഉപയോഗിക്കും; ഇറ്റാലിയൻ ഭാഷയിലെ ചോദ്യോത്തരത്തിനുള്ള (question answering) ഒരു വലിയ ഡേറ്റാസെറ്റാണിത്. + +ട്രെയിനിംഗ്, ടെസ്‌റ്റ് സ്‌പ്ലിറ്റുകൾ GitHub-ൽ ഹോസ്‌റ്റ് ചെയ്തിരിക്കുന്നതിനാൽ, ഒരു ലളിതമായ `wget` കമാൻഡ് ഉപയോഗിച്ച് നമുക്ക് അവ ഡൗൺലോഡ് ചെയ്യാം: + +```python +!wget https://github.com/crux82/squad-it/raw/master/SQuAD_it-train.json.gz +!wget https://github.com/crux82/squad-it/raw/master/SQuAD_it-test.json.gz +``` + +ഇത് *SQuAD_it-train.json.gz*, *SQuAD_it-test.json.gz* എന്നീ രണ്ട് കംപ്രസ് ചെയ്ത ഫയലുകൾ ഡൗൺലോഡ് ചെയ്യും; Linux-ലെ `gzip` കമാൻഡ് ഉപയോഗിച്ച് നമുക്ക് അവ ഡീകംപ്രസ് ചെയ്യാം: + +```python +!gzip -dkv SQuAD_it-*.json.gz +``` + +```bash +SQuAD_it-test.json.gz: 87.4% -- replaced with SQuAD_it-test.json +SQuAD_it-train.json.gz: 82.2% -- replaced with SQuAD_it-train.json +``` + +കംപ്രസ് ചെയ്ത ഫയലുകൾക്ക് പകരം _SQuAD_it-train.json_, _SQuAD_it-test.json_ എന്നിവ വന്നിരിക്കുന്നതായും, ഡേറ്റ JSON ഫോർമാറ്റിലാണ് സൂക്ഷിച്ചിരിക്കുന്നതെന്നും നമുക്ക് കാണാം. + +> [!TIP] +> ✎ മുകളിലെ ഷെൽ കമാൻഡുകളിൽ എന്തിനാണ് ഒരു `!` ചിഹ്നം എന്ന് നിങ്ങൾ ആലോചിക്കുന്നുണ്ടെങ്കിൽ, അതിന് കാരണം നമ്മൾ അവ ഒരു Jupyter നോട്ട്‌ബുക്കിനുള്ളിലാണ് റൺ ചെയ്യുന്നത് എന്നതാണ്. ഒരു ടെർമിനലിനുള്ളിൽ ഡേറ്റാസെറ്റ് ഡൗൺലോഡ് ചെയ്ത് അൺസിപ്പ് ചെയ്യണമെങ്കിൽ ആ പ്രിഫിക്‌സ് ഒഴിവാക്കിയാൽ മതി. + +`load_dataset()` ഫംഗ്‌ഷൻ ഉപയോഗിച്ച് ഒരു JSON ഫയൽ ലോഡ് ചെയ്യാൻ, നമ്മൾ കൈകാര്യം ചെയ്യുന്നത് സാധാരണ JSON ആണോ (ഒരു നെസ്‌റ്റഡ് ഡിക്‌ഷണറിക്ക് സമാനമായത്) അതോ JSON Lines ആണോ (വരികളായി വേർതിരിച്ച JSON) എന്ന് അറിഞ്ഞാൽ മാത്രം മതി. പല ചോദ്യോത്തര ഡേറ്റാസെറ്റുകളെയും പോലെ, SQuAD-it നെസ്‌റ്റഡ് ഫോർമാറ്റാണ് ഉപയോഗിക്കുന്നത്; എല്ലാ ടെക്‌സ്‌റ്റും ഒരു `data` ഫീൽഡിലാണ് സൂക്ഷിച്ചിരിക്കുന്നത്. അതായത്, താഴെ കാണിച്ചിരിക്കുന്നതുപോലെ `field` ആർഗ്യുമെന്റ് വ്യക്തമാക്കിക്കൊണ്ട് നമുക്ക് ഡേറ്റാസെറ്റ് ലോഡ് ചെയ്യാം: + +```py +from datasets import load_dataset + +squad_it_dataset = load_dataset("json", data_files="SQuAD_it-train.json", field="data") +``` + +ഡിഫോൾട്ടായി, ലോക്കൽ ഫയലുകൾ ലോഡ് ചെയ്യുമ്പോൾ ഒരു `train` സ്‌പ്ലിറ്റോടുകൂടിയ ഒരു `DatasetDict` ഒബ്‌ജക്റ്റ് ഉണ്ടാകുന്നു. `squad_it_dataset` ഒബ്‌ജക്റ്റ് പരിശോധിച്ചാൽ നമുക്ക് ഇത് കാണാം: + +```py +squad_it_dataset +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['title', 'paragraphs'], + num_rows: 442 + }) +}) +``` + +ട്രെയിനിംഗ് സെറ്റുമായി ബന്ധപ്പെട്ട വരികളുടെ എണ്ണവും കോളങ്ങളുടെ പേരുകളും ഇത് നമുക്ക് കാണിച്ചുതരുന്നു. താഴെ കാണിച്ചിരിക്കുന്നതുപോലെ `train` സ്‌പ്ലിറ്റിലേക്ക് ഇൻഡെക്‌സ് ചെയ്തുകൊണ്ട് ഉദാഹരണങ്ങളിലൊന്ന് നമുക്ക് കാണാം: + +```py +squad_it_dataset["train"][0] +``` + +```python out +{ + "title": "Terremoto del Sichuan del 2008", + "paragraphs": [ + { + "context": "Il terremoto del Sichuan del 2008 o il terremoto...", + "qas": [ + { + "answers": [{"answer_start": 29, "text": "2008"}], + "id": "56cdca7862d2951400fa6826", + "question": "In quale anno si è verificato il terremoto nel Sichuan?", + }, + ... + ], + }, + ... + ], +} +``` + +കൊള്ളാം, നമ്മുടെ ആദ്യത്തെ ലോക്കൽ ഡേറ്റാസെറ്റ് നമ്മൾ ലോഡ് ചെയ്തു! എന്നാൽ ട്രെയിനിംഗ് സെറ്റിന് ഇത് പ്രവർത്തിച്ചെങ്കിലും, നമുക്ക് ശരിക്കും വേണ്ടത് `train`, `test` സ്‌പ്ലിറ്റുകൾ രണ്ടും ഒരൊറ്റ `DatasetDict` ഒബ്‌ജക്റ്റിൽ ഉൾപ്പെടുത്തുകയാണ്; അപ്പോൾ രണ്ട് സ്‌പ്ലിറ്റുകളിലും ഒരേസമയം `Dataset.map()` ഫംഗ്‌ഷനുകൾ പ്രയോഗിക്കാൻ നമുക്ക് കഴിയും. ഇതിനായി, ഓരോ സ്‌പ്ലിറ്റിന്റെ പേരിനെയും ആ സ്‌പ്ലിറ്റുമായി ബന്ധപ്പെട്ട ഒരു ഫയലുമായി ബന്ധിപ്പിക്കുന്ന ഒരു ഡിക്‌ഷണറി `data_files` ആർഗ്യുമെന്റിന് നമുക്ക് നൽകാം: + +```py +data_files = {"train": "SQuAD_it-train.json", "test": "SQuAD_it-test.json"} +squad_it_dataset = load_dataset("json", data_files=data_files, field="data") +squad_it_dataset +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['title', 'paragraphs'], + num_rows: 442 + }) + test: Dataset({ + features: ['title', 'paragraphs'], + num_rows: 48 + }) +}) +``` + +ഇതാണ് നമുക്ക് കൃത്യമായി വേണ്ടിയിരുന്നത്. ഇപ്പോൾ, ഡേറ്റ വൃത്തിയാക്കാനും റിവ്യൂകൾ ടോക്കണൈസ് ചെയ്യാനും മറ്റുമായി വിവിധ പ്രീപ്രോസസ്സിംഗ് ടെക്‌നിക്കുകൾ നമുക്ക് പ്രയോഗിക്കാം. + +> [!TIP] +> `load_dataset()` ഫംഗ്‌ഷന്റെ `data_files` ആർഗ്യുമെന്റ് വളരെ ഫ്ലെക്‌സിബിൾ ആണ്; ഇത് ഒരൊറ്റ ഫയൽ പാതയോ, ഫയൽ പാതകളുടെ ഒരു ലിസ്‌റ്റോ, അല്ലെങ്കിൽ സ്‌പ്ലിറ്റ് പേരുകളെ ഫയൽ പാതകളുമായി ബന്ധിപ്പിക്കുന്ന ഒരു ഡിക്‌ഷണറിയോ ആകാം. Unix ഷെൽ ഉപയോഗിക്കുന്ന നിയമങ്ങൾ അനുസരിച്ച്, ഒരു നിശ്ചിത പാറ്റേണുമായി പൊരുത്തപ്പെടുന്ന ഫയലുകൾ glob ചെയ്യാനും നിങ്ങൾക്ക് കഴിയും (ഉദാ., `data_files="*.json"` എന്ന് സെറ്റ് ചെയ്തുകൊണ്ട് ഒരു ഡയറക്ടറിയിലെ എല്ലാ JSON ഫയലുകളും ഒരൊറ്റ സ്‌പ്ലിറ്റായി glob ചെയ്യാം). കൂടുതൽ വിവരങ്ങൾക്ക് 🤗 Datasets [ഡോക്യുമെന്റേഷൻ](https://huggingface.co/docs/datasets/loading#local-and-remote-files) കാണുക. + +🤗 Datasets-ലെ ലോഡിംഗ് സ്‌ക്രിപ്‌റ്റുകൾ ഇൻപുട്ട് ഫയലുകളുടെ സ്വയമേവയുള്ള ഡീകംപ്രഷൻ യഥാർത്ഥത്തിൽ പിന്തുണയ്ക്കുന്നുണ്ട്; അതിനാൽ `data_files` ആർഗ്യുമെന്റ് നേരിട്ട് കംപ്രസ് ചെയ്ത ഫയലുകളിലേക്ക് ചൂണ്ടിക്കൊണ്ട് `gzip`-ന്റെ ഉപയോഗം നമുക്ക് ഒഴിവാക്കാമായിരുന്നു: + +```py +data_files = {"train": "SQuAD_it-train.json.gz", "test": "SQuAD_it-test.json.gz"} +squad_it_dataset = load_dataset("json", data_files=data_files, field="data") +``` + +ധാരാളം GZIP ഫയലുകൾ സ്വയം (manually) ഡീകംപ്രസ് ചെയ്യാൻ നിങ്ങൾക്ക് താൽപ്പര്യമില്ലെങ്കിൽ ഇത് ഉപകാരപ്രദമാകും. ZIP, TAR പോലുള്ള മറ്റ് സാധാരണ ഫോർമാറ്റുകൾക്കും സ്വയമേവയുള്ള ഡീകംപ്രഷൻ ബാധകമാണ്; അതിനാൽ `data_files` കംപ്രസ് ചെയ്ത ഫയലുകളിലേക്ക് ചൂണ്ടിയാൽ മാത്രം മതി, എല്ലാം തയ്യാർ! + +നിങ്ങളുടെ ലാപ്‌ടോപ്പിലോ ഡെസ്‌ക്‌ടോപ്പിലോ ഉള്ള ലോക്കൽ ഫയലുകൾ എങ്ങനെ ലോഡ് ചെയ്യാമെന്ന് ഇപ്പോൾ നിങ്ങൾക്ക് അറിയാം; ഇനി റിമോട്ട് ഫയലുകൾ ലോഡ് ചെയ്യുന്നത് നോക്കാം. + +## ഒരു റിമോട്ട് ഡേറ്റാസെറ്റ് ലോഡ് ചെയ്യുന്നു[[loading-a-remote-dataset]] + +നിങ്ങൾ ഒരു കമ്പനിയിൽ ഡേറ്റാ സയന്റിസ്‌റ്റായോ കോഡറായോ ജോലി ചെയ്യുന്നുണ്ടെങ്കിൽ, നിങ്ങൾ വിശകലനം ചെയ്യാൻ ആഗ്രഹിക്കുന്ന ഡേറ്റാസെറ്റുകൾ ഏതെങ്കിലും റിമോട്ട് സെർവറിലായിരിക്കാൻ നല്ല സാധ്യതയുണ്ട്. ഭാഗ്യവശാൽ, റിമോട്ട് ഫയലുകൾ ലോഡ് ചെയ്യുന്നത് ലോക്കൽ ഫയലുകൾ ലോഡ് ചെയ്യുന്നതുപോലെ തന്നെ ലളിതമാണ്! ലോക്കൽ ഫയലുകളിലേക്കുള്ള പാത നൽകുന്നതിന് പകരം, റിമോട്ട് ഫയലുകൾ സൂക്ഷിച്ചിരിക്കുന്ന ഒന്നോ അതിലധികമോ URL-കളിലേക്ക് `load_dataset()`-ന്റെ `data_files` ആർഗ്യുമെന്റ് നമ്മൾ ചൂണ്ടുന്നു. ഉദാഹരണത്തിന്, GitHub-ൽ ഹോസ്‌റ്റ് ചെയ്തിരിക്കുന്ന SQuAD-it ഡേറ്റാസെറ്റിന്, താഴെ കാണിച്ചിരിക്കുന്നതുപോലെ `data_files` _SQuAD_it-*.json.gz_ URL-കളിലേക്ക് ചൂണ്ടിയാൽ മാത്രം മതി: + +```py +url = "https://github.com/crux82/squad-it/raw/master/" +data_files = { + "train": url + "SQuAD_it-train.json.gz", + "test": url + "SQuAD_it-test.json.gz", +} +squad_it_dataset = load_dataset("json", data_files=data_files, field="data") +``` + +ഇത് മുകളിൽ ലഭിച്ച അതേ `DatasetDict` ഒബ്‌ജക്റ്റ് തന്നെ റിട്ടേൺ ചെയ്യുന്നു, എന്നാൽ _SQuAD_it-*.json.gz_ ഫയലുകൾ സ്വയം ഡൗൺലോഡ് ചെയ്ത് ഡീകംപ്രസ് ചെയ്യുന്ന ഘട്ടം നമുക്ക് ലാഭിക്കാം. Hugging Face Hub-ൽ ഹോസ്‌റ്റ് ചെയ്യാത്ത ഡേറ്റാസെറ്റുകൾ ലോഡ് ചെയ്യാനുള്ള വിവിധ വഴികളിലേക്കുള്ള നമ്മുടെ ഈ ചെറുയാത്ര ഇവിടെ അവസാനിക്കുന്നു. ഇപ്പോൾ പരീക്ഷിക്കാൻ ഒരു ഡേറ്റാസെറ്റ് കൈയിലുള്ളതിനാൽ, ഡേറ്റ കൈകാര്യം ചെയ്യാനുള്ള (data-wrangling) വിവിധ ടെക്‌നിക്കുകളുമായി നമുക്ക് നേരിട്ട് ഇറങ്ങി പണിയെടുക്കാം! + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** GitHub-ലോ [UCI Machine Learning Repository](https://archive.ics.uci.edu/ml/index.php)-യിലോ ഹോസ്‌റ്റ് ചെയ്തിരിക്കുന്ന മറ്റൊരു ഡേറ്റാസെറ്റ് തിരഞ്ഞെടുത്ത്, മുകളിൽ പരിചയപ്പെടുത്തിയ ടെക്‌നിക്കുകൾ ഉപയോഗിച്ച് അത് ലോക്കലായും റിമോട്ടായും ലോഡ് ചെയ്യാൻ ശ്രമിക്കുക. ബോണസ് പോയിന്റുകൾക്കായി, CSV അല്ലെങ്കിൽ ടെക്‌സ്‌റ്റ് ഫോർമാറ്റിൽ സൂക്ഷിച്ചിരിക്കുന്ന ഒരു ഡേറ്റാസെറ്റ് ലോഡ് ചെയ്യാൻ ശ്രമിക്കുക (ഈ ഫോർമാറ്റുകളെക്കുറിച്ചുള്ള കൂടുതൽ വിവരങ്ങൾക്ക് [ഡോക്യുമെന്റേഷൻ](https://huggingface.co/docs/datasets/loading#local-and-remote-files) കാണുക). + + diff --git a/chapters/ml/chapter5/3.mdx b/chapters/ml/chapter5/3.mdx new file mode 100644 index 000000000..80897264a --- /dev/null +++ b/chapters/ml/chapter5/3.mdx @@ -0,0 +1,720 @@ +# ഡേറ്റ അരിഞ്ഞു മുറിക്കാൻ സമയമായി[[time-to-slice-and-dice]] + + + +മിക്കപ്പോഴും, നിങ്ങൾ പ്രവർത്തിക്കുന്ന ഡേറ്റ മോഡലുകൾ ട്രെയിൻ ചെയ്യാൻ പൂർണ്ണമായി തയ്യാറാക്കിയ രൂപത്തിലായിരിക്കില്ല. നിങ്ങളുടെ ഡേറ്റാസെറ്റുകൾ വൃത്തിയാക്കാൻ (clean up) 🤗 Datasets നൽകുന്ന വിവിധ ഫീച്ചറുകൾ ഈ ഭാഗത്തിൽ നമ്മൾ പരിശോധിക്കും. + + + +## നമ്മുടെ ഡേറ്റ അരിഞ്ഞു മുറിക്കുന്നു[[slicing-and-dicing-our-data]] + +Pandas-ന് സമാനമായി, `Dataset`, `DatasetDict` ഒബ്‌ജക്റ്റുകളുടെ ഉള്ളടക്കം കൈകാര്യം ചെയ്യാൻ 🤗 Datasets നിരവധി ഫംഗ്‌ഷനുകൾ നൽകുന്നു. `Dataset.map()` മെത്തേഡ് [അധ്യായം 3](/course/chapter3)-ൽ നമ്മൾ ഇതിനകം കണ്ടിട്ടുണ്ട്; നമുക്ക് ലഭ്യമായ മറ്റു ചില ഫംഗ്‌ഷനുകൾ ഈ ഭാഗത്തിൽ നമ്മൾ പരിശോധിക്കും. + +ഈ ഉദാഹരണത്തിനായി നമ്മൾ [Drug Review Dataset](https://archive.ics.uci.edu/ml/datasets/Drug+Review+Dataset+%28Drugs.com%29) ഉപയോഗിക്കും; [UC Irvine Machine Learning Repository](https://archive.ics.uci.edu/ml/index.php)-യിൽ ഹോസ്‌റ്റ് ചെയ്തിരിക്കുന്ന ഈ ഡേറ്റാസെറ്റിൽ വിവിധ മരുന്നുകളെക്കുറിച്ചുള്ള രോഗികളുടെ റിവ്യൂകളും, ചികിത്സിക്കുന്ന രോഗാവസ്ഥയും (condition), രോഗിയുടെ സംതൃപ്തി സൂചിപ്പിക്കുന്ന 10-സ്‌റ്റാർ റേറ്റിംഗും അടങ്ങിയിരിക്കുന്നു. + +ആദ്യം നമുക്ക് ഡേറ്റ ഡൗൺലോഡ് ചെയ്ത് എക്‌സ്‌ട്രാക്റ്റ് ചെയ്യണം; `wget`, `unzip` കമാൻഡുകൾ ഉപയോഗിച്ച് ഇത് ചെയ്യാം: + +```py +!wget "https://archive.ics.uci.edu/ml/machine-learning-databases/00462/drugsCom_raw.zip" +!unzip drugsCom_raw.zip +``` + +സെപ്പറേറ്ററായി കോമകൾക്ക് പകരം ടാബുകൾ ഉപയോഗിക്കുന്ന CSV-യുടെ ഒരു വകഭേദം മാത്രമാണ് TSV എന്നതിനാൽ, `csv` ലോഡിംഗ് സ്‌ക്രിപ്‌റ്റ് ഉപയോഗിച്ചും `load_dataset()` ഫംഗ്‌ഷനിൽ `delimiter` ആർഗ്യുമെന്റ് വ്യക്തമാക്കിയും താഴെ കാണിച്ചിരിക്കുന്നതുപോലെ നമുക്ക് ഈ ഫയലുകൾ ലോഡ് ചെയ്യാം: + +```py +from datasets import load_dataset + +data_files = {"train": "drugsComTrain_raw.tsv", "test": "drugsComTest_raw.tsv"} +# \t is the tab character in Python +drug_dataset = load_dataset("csv", data_files=data_files, delimiter="\t") +``` + +ഏതു തരത്തിലുള്ള ഡേറ്റാ അനാലിസിസ് ചെയ്യുമ്പോഴും, നിങ്ങൾ പ്രവർത്തിക്കുന്ന ഡേറ്റയുടെ സ്വഭാവം വേഗത്തിൽ മനസ്സിലാക്കാൻ ഒരു ചെറിയ ക്രമരഹിതമായ (random) സാമ്പിൾ എടുത്തു നോക്കുന്നത് ഒരു നല്ല ശീലമാണ്. 🤗 Datasets-ൽ, `Dataset.shuffle()`, `Dataset.select()` ഫംഗ്‌ഷനുകൾ ഒന്നിനു പിറകെ ഒന്നായി ചേർത്തുകൊണ്ട് (chaining) ഒരു ക്രമരഹിത സാമ്പിൾ നമുക്ക് ഉണ്ടാക്കാം: + +```py +drug_sample = drug_dataset["train"].shuffle(seed=42).select(range(1000)) +# Peek at the first few examples +drug_sample[:3] +``` + +```python out +{'Unnamed: 0': [87571, 178045, 80482], + 'drugName': ['Naproxen', 'Duloxetine', 'Mobic'], + 'condition': ['Gout, Acute', 'ibromyalgia', 'Inflammatory Conditions'], + 'review': ['"like the previous person mention, I'm a strong believer of aleve, it works faster for my gout than the prescription meds I take. No more going to the doctor for refills.....Aleve works!"', + '"I have taken Cymbalta for about a year and a half for fibromyalgia pain. It is great\r\nas a pain reducer and an anti-depressant, however, the side effects outweighed \r\nany benefit I got from it. I had trouble with restlessness, being tired constantly,\r\ndizziness, dry mouth, numbness and tingling in my feet, and horrible sweating. I am\r\nbeing weaned off of it now. Went from 60 mg to 30mg and now to 15 mg. I will be\r\noff completely in about a week. The fibro pain is coming back, but I would rather deal with it than the side effects."', + '"I have been taking Mobic for over a year with no side effects other than an elevated blood pressure. I had severe knee and ankle pain which completely went away after taking Mobic. I attempted to stop the medication however pain returned after a few days."'], + 'rating': [9.0, 3.0, 10.0], + 'date': ['September 2, 2015', 'November 7, 2011', 'June 5, 2013'], + 'usefulCount': [36, 13, 128]} +``` + +പുനരുത്പാദനക്ഷമതയ്ക്കായി (reproducibility) `Dataset.shuffle()`-ൽ സീഡ് (seed) ഒരു നിശ്ചിത മൂല്യത്തിൽ നമ്മൾ ഉറപ്പിച്ചിട്ടുണ്ട് എന്നത് ശ്രദ്ധിക്കുക. `Dataset.select()` ഇൻഡെക്‌സുകളുടെ ഒരു ഇറ്ററബിൾ (iterable) ആണ് പ്രതീക്ഷിക്കുന്നത്; അതിനാൽ ഷഫിൾ ചെയ്ത ഡേറ്റാസെറ്റിലെ ആദ്യത്തെ 1,000 ഉദാഹരണങ്ങൾ എടുക്കാൻ നമ്മൾ `range(1000)` നൽകി. ഈ സാമ്പിളിൽ നിന്നുതന്നെ നമ്മുടെ ഡേറ്റാസെറ്റിലെ ചില വൈചിത്ര്യങ്ങൾ (quirks) നമുക്ക് കാണാം: + +* `Unnamed: 0` കോളം ഓരോ രോഗിയുടെയും അജ്ഞാതമാക്കിയ (anonymized) ഒരു ID പോലെ തോന്നിക്കുന്നു. +* `condition` കോളത്തിൽ വലിയക്ഷരങ്ങളും (uppercase) ചെറിയക്ഷരങ്ങളും (lowercase) കലർന്ന ലേബലുകൾ ഉണ്ട്. +* റിവ്യൂകൾ വ്യത്യസ്ത നീളമുള്ളവയാണ്; അവയിൽ Python ലൈൻ സെപ്പറേറ്ററുകളും (`\r\n`) `&\#039;` പോലുള്ള HTML ക്യാരക്റ്റർ കോഡുകളും കലർന്നിരിക്കുന്നു. + +ഈ ഓരോ പ്രശ്‌നവും പരിഹരിക്കാൻ 🤗 Datasets എങ്ങനെ ഉപയോഗിക്കാമെന്ന് നോക്കാം. `Unnamed: 0` കോളം രോഗിയുടെ ID ആണെന്ന അനുമാനം (hypothesis) പരീക്ഷിക്കാൻ, ഓരോ സ്‌പ്ലിറ്റിലെയും ID-കളുടെ എണ്ണം വരികളുടെ (rows) എണ്ണത്തിന് തുല്യമാണോ എന്ന് `Dataset.unique()` ഫംഗ്‌ഷൻ ഉപയോഗിച്ച് നമുക്ക് പരിശോധിക്കാം: + +```py +for split in drug_dataset.keys(): + assert len(drug_dataset[split]) == len(drug_dataset[split].unique("Unnamed: 0")) +``` + +ഇത് നമ്മുടെ അനുമാനം ശരിവയ്ക്കുന്നതായി തോന്നുന്നു; അതിനാൽ `Unnamed: 0` കോളത്തിന് കുറച്ചുകൂടി അർത്ഥവ്യക്തതയുള്ള ഒരു പേര് നൽകി ഡേറ്റാസെറ്റ് ഒന്ന് വൃത്തിയാക്കാം. `DatasetDict.rename_column()` ഫംഗ്‌ഷൻ ഉപയോഗിച്ച് രണ്ട് സ്‌പ്ലിറ്റുകളിലെയും കോളത്തിന്റെ പേര് ഒറ്റയടിക്ക് മാറ്റാം: + +```py +drug_dataset = drug_dataset.rename_column( + original_column_name="Unnamed: 0", new_column_name="patient_id" +) +drug_dataset +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount'], + num_rows: 161297 + }) + test: Dataset({ + features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount'], + num_rows: 53766 + }) +}) +``` + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** ട്രെയിനിംഗ്, ടെസ്‌റ്റ് സെറ്റുകളിലെ വ്യത്യസ്ത (unique) മരുന്നുകളുടെയും രോഗാവസ്ഥകളുടെയും എണ്ണം കണ്ടെത്താൻ `Dataset.unique()` ഫംഗ്‌ഷൻ ഉപയോഗിക്കുക. + +അടുത്തതായി, `Dataset.map()` ഉപയോഗിച്ച് എല്ലാ `condition` ലേബലുകളും നോർമലൈസ് ചെയ്യാം. [അധ്യായം 3](/course/chapter3)-ൽ ടോക്കണൈസേഷന് നമ്മൾ ചെയ്തതുപോലെ, `drug_dataset`-ലെ ഓരോ സ്‌പ്ലിറ്റിന്റെയും എല്ലാ വരികളിലും പ്രയോഗിക്കാവുന്ന ഒരു ലളിതമായ ഫംഗ്‌ഷൻ നമുക്ക് നിർവചിക്കാം: + +```py +def lowercase_condition(example): + return {"condition": example["condition"].lower()} + + +drug_dataset.map(lowercase_condition) +``` + +```python out +AttributeError: 'NoneType' object has no attribute 'lower' +``` + +അയ്യോ, നമ്മുടെ map ഫംഗ്‌ഷനിൽ ഒരു പ്രശ്‌നം വന്നിരിക്കുന്നു! `condition` കോളത്തിലെ ചില എൻട്രികൾ `None` ആണെന്നും, അവ സ്‌ട്രിംഗുകളല്ലാത്തതിനാൽ ചെറിയക്ഷരമാക്കാൻ കഴിയില്ലെന്നും എററിൽ നിന്ന് നമുക്ക് അനുമാനിക്കാം. `Dataset.filter()` ഉപയോഗിച്ച് ഈ വരികൾ ഒഴിവാക്കാം; ഇത് `Dataset.map()`-ന് സമാനമായ രീതിയിൽ പ്രവർത്തിക്കുകയും, ഡേറ്റാസെറ്റിലെ ഒരൊറ്റ ഉദാഹരണം സ്വീകരിക്കുന്ന ഒരു ഫംഗ്‌ഷൻ പ്രതീക്ഷിക്കുകയും ചെയ്യുന്നു. ഇതുപോലുള്ള ഒരു ഫംഗ്‌ഷൻ വ്യക്തമായി എഴുതി: + +```py +def filter_nones(x): + return x["condition"] is not None +``` + +എന്നിട്ട് `drug_dataset.filter(filter_nones)` റൺ ചെയ്യുന്നതിനു പകരം, ഒരു _ലാംഡ ഫംഗ്‌ഷൻ_ (lambda function) ഉപയോഗിച്ച് ഒറ്റ വരിയിൽ നമുക്ക് ഇത് ചെയ്യാം. Python-ൽ, പേര് വ്യക്തമായി നൽകാതെ നിർവചിക്കാവുന്ന ചെറിയ ഫംഗ്‌ഷനുകളാണ് ലാംഡ ഫംഗ്‌ഷനുകൾ. അവയുടെ പൊതുവായ രൂപം ഇതാണ്: + +``` +lambda : +``` + +ഇവിടെ `lambda` എന്നത് Python-ന്റെ പ്രത്യേക [കീവേഡുകളിൽ](https://docs.python.org/3/reference/lexical_analysis.html#keywords) ഒന്നാണ്; `` എന്നത് ഫംഗ്‌ഷന്റെ ഇൻപുട്ടുകൾ നിർവചിക്കുന്ന, കോമ ഉപയോഗിച്ച് വേർതിരിച്ച മൂല്യങ്ങളുടെ ഒരു ലിസ്‌റ്റ്/സെറ്റ് ആണ്; `` എന്നത് നിങ്ങൾ എക്‌സിക്യൂട്ട് ചെയ്യാൻ ആഗ്രഹിക്കുന്ന പ്രവർത്തനങ്ങളെ സൂചിപ്പിക്കുന്നു. ഉദാഹരണത്തിന്, ഒരു സംഖ്യയുടെ വർഗ്ഗം (square) കണക്കാക്കുന്ന ഒരു ലളിതമായ ലാംഡ ഫംഗ്‌ഷൻ താഴെ കാണിച്ചിരിക്കുന്നതുപോലെ നമുക്ക് നിർവചിക്കാം: + +``` +lambda x : x * x +``` + +ഈ ഫംഗ്‌ഷൻ ഒരു ഇൻപുട്ടിൽ പ്രയോഗിക്കാൻ, ഫംഗ്‌ഷനെയും ഇൻപുട്ടിനെയും ബ്രാക്കറ്റുകളിൽ (parentheses) പൊതിയണം: + +```py +(lambda x: x * x)(3) +``` + +```python out +9 +``` + +അതുപോലെ, ആർഗ്യുമെന്റുകൾ കോമ ഉപയോഗിച്ച് വേർതിരിച്ചുകൊണ്ട് ഒന്നിലധികം ആർഗ്യുമെന്റുകളുള്ള ലാംഡ ഫംഗ്‌ഷനുകളും നമുക്ക് നിർവചിക്കാം. ഉദാഹരണത്തിന്, ഒരു ത്രികോണത്തിന്റെ വിസ്‌തീർണ്ണം ഇങ്ങനെ കണക്കാക്കാം: + +```py +(lambda base, height: 0.5 * base * height)(4, 8) +``` + +```python out +16.0 +``` + +ചെറിയ, ഒറ്റത്തവണ ഉപയോഗിക്കാനുള്ള ഫംഗ്‌ഷനുകൾ നിർവചിക്കാൻ ലാംഡ ഫംഗ്‌ഷനുകൾ സൗകര്യപ്രദമാണ് (ഇവയെക്കുറിച്ച് കൂടുതൽ അറിയാൻ, Andre Burgaud എഴുതിയ മികച്ച [Real Python ട്യൂട്ടോറിയൽ](https://realpython.com/python-lambda/) വായിക്കാൻ ഞങ്ങൾ ശുപാർശ ചെയ്യുന്നു). 🤗 Datasets-ന്റെ പശ്ചാത്തലത്തിൽ, ലളിതമായ map, filter ഓപ്പറേഷനുകൾ നിർവചിക്കാൻ ലാംഡ ഫംഗ്‌ഷനുകൾ നമുക്ക് ഉപയോഗിക്കാം; അതിനാൽ നമ്മുടെ ഡേറ്റാസെറ്റിലെ `None` എൻട്രികൾ ഒഴിവാക്കാൻ ഈ തന്ത്രം ഉപയോഗിക്കാം: + +```py +drug_dataset = drug_dataset.filter(lambda x: x["condition"] is not None) +``` + +`None` എൻട്രികൾ നീക്കം ചെയ്തതോടെ, നമ്മുടെ `condition` കോളം നോർമലൈസ് ചെയ്യാം: + +```py +drug_dataset = drug_dataset.map(lowercase_condition) +# Check that lowercasing worked +drug_dataset["train"]["condition"][:3] +``` + +```python out +['left ventricular dysfunction', 'adhd', 'birth control'] +``` + +ഇത് പ്രവർത്തിക്കുന്നു! ലേബലുകൾ വൃത്തിയാക്കിക്കഴിഞ്ഞ സ്ഥിതിക്ക്, ഇനി റിവ്യൂകൾ തന്നെ വൃത്തിയാക്കുന്നത് എങ്ങനെയെന്ന് നോക്കാം. + +## പുതിയ കോളങ്ങൾ ഉണ്ടാക്കുന്നു[[creating-new-columns]] + +ഉപഭോക്തൃ റിവ്യൂകൾ കൈകാര്യം ചെയ്യുമ്പോഴെല്ലാം, ഓരോ റിവ്യൂവിലെയും വാക്കുകളുടെ എണ്ണം പരിശോധിക്കുന്നത് ഒരു നല്ല ശീലമാണ്. ഒരു റിവ്യൂ "Great!" പോലുള്ള ഒരൊറ്റ വാക്കാകാം, അല്ലെങ്കിൽ ആയിരക്കണക്കിന് വാക്കുകളുള്ള ഒരു നീണ്ട ഉപന്യാസമാകാം; ഉപയോഗസന്ദർഭം (use case) അനുസരിച്ച് ഈ രണ്ട് അതിരുകളെയും നിങ്ങൾ വ്യത്യസ്തമായി കൈകാര്യം ചെയ്യേണ്ടി വരും. ഓരോ റിവ്യൂവിലെയും വാക്കുകളുടെ എണ്ണം കണക്കാക്കാൻ, ഓരോ ടെക്‌സ്‌റ്റും വൈറ്റ്‌സ്‌പേസ് (whitespace) അടിസ്ഥാനമാക്കി വിഭജിക്കുന്ന ഒരു ഏകദേശ രീതി (heuristic) നമ്മൾ ഉപയോഗിക്കും. + +ഓരോ റിവ്യൂവിലെയും വാക്കുകളുടെ എണ്ണം കണക്കാക്കുന്ന ഒരു ലളിതമായ ഫംഗ്‌ഷൻ നിർവചിക്കാം: + +```py +def compute_review_length(example): + return {"review_length": len(example["review"].split())} +``` + +നമ്മുടെ `lowercase_condition()` ഫംഗ്‌ഷനിൽ നിന്ന് വ്യത്യസ്തമായി, `compute_review_length()` റിട്ടേൺ ചെയ്യുന്ന ഡിക്‌ഷണറിയുടെ കീ (key) ഡേറ്റാസെറ്റിലെ കോളങ്ങളുടെ പേരുകളിലൊന്നുമായി പൊരുത്തപ്പെടുന്നില്ല. ഈ സാഹചര്യത്തിൽ, `compute_review_length()` `Dataset.map()`-ന് നൽകുമ്പോൾ, അത് ഡേറ്റാസെറ്റിലെ എല്ലാ വരികളിലും പ്രയോഗിക്കപ്പെട്ട് `review_length` എന്ന ഒരു പുതിയ കോളം ഉണ്ടാക്കും: + +```py +drug_dataset = drug_dataset.map(compute_review_length) +# Inspect the first training example +drug_dataset["train"][0] +``` + +```python out +{'patient_id': 206461, + 'drugName': 'Valsartan', + 'condition': 'left ventricular dysfunction', + 'review': '"It has no side effect, I take it in combination of Bystolic 5 Mg and Fish Oil"', + 'rating': 9.0, + 'date': 'May 20, 2012', + 'usefulCount': 27, + 'review_length': 17} +``` + +പ്രതീക്ഷിച്ചതുപോലെ, നമ്മുടെ ട്രെയിനിംഗ് സെറ്റിൽ ഒരു `review_length` കോളം ചേർക്കപ്പെട്ടതായി കാണാം. അതിരുകളിലുള്ള മൂല്യങ്ങൾ (extreme values) എങ്ങനെയുണ്ടെന്ന് കാണാൻ `Dataset.sort()` ഉപയോഗിച്ച് ഈ പുതിയ കോളം നമുക്ക് സോർട്ട് ചെയ്യാം: + +```py +drug_dataset["train"].sort("review_length")[:3] +``` + +```python out +{'patient_id': [103488, 23627, 20558], + 'drugName': ['Loestrin 21 1 / 20', 'Chlorzoxazone', 'Nucynta'], + 'condition': ['birth control', 'muscle spasm', 'pain'], + 'review': ['"Excellent."', '"useless"', '"ok"'], + 'rating': [10.0, 1.0, 6.0], + 'date': ['November 4, 2008', 'March 24, 2017', 'August 20, 2016'], + 'usefulCount': [5, 2, 10], + 'review_length': [1, 1, 1]} +``` + +നമ്മൾ സംശയിച്ചതുപോലെ, ചില റിവ്യൂകളിൽ ഒരൊറ്റ വാക്ക് മാത്രമേയുള്ളൂ; സെന്റിമെന്റ് അനാലിസിസിന് ഇത് കുഴപ്പമില്ലായിരിക്കാമെങ്കിലും, രോഗാവസ്ഥ പ്രവചിക്കാനാണ് നമ്മുടെ ലക്ഷ്യമെങ്കിൽ ഇവയിൽ നിന്ന് കാര്യമായ വിവരങ്ങളൊന്നും ലഭിക്കില്ല. + +> [!TIP] +> 🙋 ഒരു ഡേറ്റാസെറ്റിൽ പുതിയ കോളങ്ങൾ ചേർക്കാനുള്ള മറ്റൊരു മാർഗ്ഗം `Dataset.add_column()` ഫംഗ്‌ഷനാണ്. കോളം ഒരു Python ലിസ്‌റ്റായോ NumPy അറേയായോ നൽകാൻ ഇത് നിങ്ങളെ അനുവദിക്കുന്നു; നിങ്ങളുടെ അനാലിസിസിന് `Dataset.map()` അത്ര അനുയോജ്യമല്ലാത്ത സാഹചര്യങ്ങളിൽ ഇത് സൗകര്യപ്രദമാകും. + +30-ൽ താഴെ വാക്കുകളുള്ള റിവ്യൂകൾ നീക്കം ചെയ്യാൻ `Dataset.filter()` ഫംഗ്‌ഷൻ ഉപയോഗിക്കാം. `condition` കോളത്തിൽ നമ്മൾ ചെയ്തതിന് സമാനമായി, റിവ്യൂകളുടെ നീളം ഈ പരിധിക്ക് (threshold) മുകളിലായിരിക്കണം എന്ന് നിബന്ധന വെച്ചുകൊണ്ട് വളരെ ചെറിയ റിവ്യൂകൾ നമുക്ക് ഫിൽട്ടർ ചെയ്ത് ഒഴിവാക്കാം: + +```py +drug_dataset = drug_dataset.filter(lambda x: x["review_length"] > 30) +print(drug_dataset.num_rows) +``` + +```python out +{'train': 138514, 'test': 46108} +``` + +നിങ്ങൾക്ക് കാണാവുന്നതുപോലെ, ഇത് നമ്മുടെ യഥാർത്ഥ ട്രെയിനിംഗ്, ടെസ്‌റ്റ് സെറ്റുകളിലെ ഏകദേശം 15% റിവ്യൂകൾ നീക്കം ചെയ്തിരിക്കുന്നു. + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** ഏറ്റവും കൂടുതൽ വാക്കുകളുള്ള റിവ്യൂകൾ പരിശോധിക്കാൻ `Dataset.sort()` ഫംഗ്‌ഷൻ ഉപയോഗിക്കുക. റിവ്യൂകളെ നീളമനുസരിച്ച് അവരോഹണ ക്രമത്തിൽ (descending order) സോർട്ട് ചെയ്യാൻ ഏത് ആർഗ്യുമെന്റാണ് ഉപയോഗിക്കേണ്ടതെന്ന് അറിയാൻ [ഡോക്യുമെന്റേഷൻ](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.sort) നോക്കുക. + +നമുക്ക് അവസാനമായി കൈകാര്യം ചെയ്യേണ്ടത് നമ്മുടെ റിവ്യൂകളിലെ HTML ക്യാരക്റ്റർ കോഡുകളുടെ സാന്നിധ്യമാണ്. ഈ ക്യാരക്റ്ററുകൾ അൺഎസ്‌കേപ്പ് (unescape) ചെയ്യാൻ Python-ന്റെ `html` മൊഡ്യൂൾ നമുക്ക് ഉപയോഗിക്കാം, ഇങ്ങനെ: + +```py +import html + +text = "I'm a transformer called BERT" +html.unescape(text) +``` + +```python out +"I'm a transformer called BERT" +``` + +നമ്മുടെ കോർപ്പസിലെ എല്ലാ HTML ക്യാരക്റ്ററുകളും അൺഎസ്‌കേപ്പ് ചെയ്യാൻ `Dataset.map()` ഉപയോഗിക്കാം: + +```python +drug_dataset = drug_dataset.map(lambda x: {"review": html.unescape(x["review"])}) +``` + +നിങ്ങൾക്ക് കാണാവുന്നതുപോലെ, ഡേറ്റ പ്രോസസ്സ് ചെയ്യാൻ `Dataset.map()` മെത്തേഡ് വളരെ ഉപകാരപ്രദമാണ് -- അതിന് ചെയ്യാൻ കഴിയുന്ന കാര്യങ്ങളുടെ ഉപരിതലം പോലും നമ്മൾ ഇതുവരെ തൊട്ടിട്ടില്ല! + +## `map()` മെത്തേഡിന്റെ സൂപ്പർപവറുകൾ[[the-map-methods-superpowers]] + +`Dataset.map()` മെത്തേഡിന് ഒരു `batched` ആർഗ്യുമെന്റ് ഉണ്ട്; ഇത് `True` ആയി സെറ്റ് ചെയ്താൽ, ഉദാഹരണങ്ങളുടെ ഒരു ബാച്ച് ഒരുമിച്ച് map ഫംഗ്‌ഷനിലേക്ക് അയയ്ക്കും (ബാച്ച് സൈസ് ക്രമീകരിക്കാവുന്നതാണ്, എന്നാൽ ഡിഫോൾട്ട് 1,000 ആണ്). ഉദാഹരണത്തിന്, എല്ലാ HTML-ഉം അൺഎസ്‌കേപ്പ് ചെയ്ത മുൻപത്തെ map ഫംഗ്‌ഷൻ റൺ ചെയ്യാൻ കുറച്ച് സമയമെടുത്തു (എടുത്ത സമയം പ്രോഗ്രസ് ബാറുകളിൽ നിന്ന് നിങ്ങൾക്ക് വായിക്കാം). ഒരു ലിസ്‌റ്റ് കോംപ്രിഹെൻഷൻ (list comprehension) ഉപയോഗിച്ച് ഒരേ സമയം നിരവധി എലമെന്റുകൾ പ്രോസസ്സ് ചെയ്തുകൊണ്ട് ഇത് വേഗത്തിലാക്കാം. + +നിങ്ങൾ `batched=True` നൽകുമ്പോൾ, ഡേറ്റാസെറ്റിന്റെ ഫീൽഡുകളുള്ള ഒരു ഡിക്‌ഷണറിയാണ് ഫംഗ്‌ഷന് ലഭിക്കുന്നത്; എന്നാൽ ഓരോ മൂല്യവും ഇപ്പോൾ ഒരൊറ്റ മൂല്യമല്ല, _മൂല്യങ്ങളുടെ ഒരു ലിസ്‌റ്റ്_ ആണ്. `Dataset.map()`-ന്റെ റിട്ടേൺ മൂല്യവും അതേ രീതിയിലായിരിക്കണം: നമ്മുടെ ഡേറ്റാസെറ്റിൽ അപ്‌ഡേറ്റ് ചെയ്യാനോ ചേർക്കാനോ ആഗ്രഹിക്കുന്ന ഫീൽഡുകളും, മൂല്യങ്ങളുടെ ഒരു ലിസ്‌റ്റും ഉള്ള ഒരു ഡിക്‌ഷണറി. ഉദാഹരണത്തിന്, എല്ലാ HTML ക്യാരക്റ്ററുകളും അൺഎസ്‌കേപ്പ് ചെയ്യാനുള്ള മറ്റൊരു മാർഗ്ഗം ഇതാ, എന്നാൽ ഇത്തവണ `batched=True` ഉപയോഗിച്ച്: + +```python +new_drug_dataset = drug_dataset.map( + lambda x: {"review": [html.unescape(o) for o in x["review"]]}, batched=True +) +``` + +ഈ കോഡ് ഒരു നോട്ട്‌ബുക്കിലാണ് നിങ്ങൾ റൺ ചെയ്യുന്നതെങ്കിൽ, ഈ കമാൻഡ് മുൻപത്തേതിനെക്കാൾ വളരെ വേഗത്തിൽ എക്‌സിക്യൂട്ട് ചെയ്യുന്നതായി നിങ്ങൾ കാണും. നമ്മുടെ റിവ്യൂകൾ ഇതിനകം HTML-അൺഎസ്‌കേപ്പ് ചെയ്യപ്പെട്ടതുകൊണ്ടല്ല ഇത് -- മുൻ ഭാഗത്തിലെ നിർദ്ദേശം (`batched=True` ഇല്ലാതെ) നിങ്ങൾ വീണ്ടും എക്‌സിക്യൂട്ട് ചെയ്താൽ, അത് മുൻപത്തെ അതേ സമയമെടുക്കും. ഒരേ കോഡ് ഒരു `for` ലൂപ്പിൽ എക്‌സിക്യൂട്ട് ചെയ്യുന്നതിനെക്കാൾ ലിസ്‌റ്റ് കോംപ്രിഹെൻഷനുകൾ സാധാരണയായി വേഗതയുള്ളതാണ് എന്നതാണ് ഇതിന് കാരണം; കൂടാതെ, എലമെന്റുകൾ ഒന്നൊന്നായി എടുക്കുന്നതിനു പകരം ഒരേ സമയം ധാരാളം എലമെന്റുകൾ ആക്‌സസ് ചെയ്യുന്നതിലൂടെയും നമുക്ക് കുറച്ച് പ്രകടനനേട്ടം ലഭിക്കുന്നു. + +[അധ്യായം 6](/course/chapter6)-ൽ നമ്മൾ പരിചയപ്പെടാൻ പോകുന്ന, ടെക്‌സ്‌റ്റുകളുടെ വലിയ ലിസ്‌റ്റുകൾ വേഗത്തിൽ ടോക്കണൈസ് ചെയ്യാൻ കഴിയുന്ന "ഫാസ്‌റ്റ്" ടോക്കണൈസറുകളുടെ വേഗത പൂർണ്ണമായി പ്രയോജനപ്പെടുത്താൻ `Dataset.map()` `batched=True` സഹിതം ഉപയോഗിക്കുന്നത് അത്യാവശ്യമായിരിക്കും. ഉദാഹരണത്തിന്, ഒരു ഫാസ്‌റ്റ് ടോക്കണൈസർ ഉപയോഗിച്ച് എല്ലാ മരുന്ന് റിവ്യൂകളും ടോക്കണൈസ് ചെയ്യാൻ, ഇതുപോലുള്ള ഒരു ഫംഗ്‌ഷൻ നമുക്ക് ഉപയോഗിക്കാം: + +```python +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") + + +def tokenize_function(examples): + return tokenizer(examples["review"], truncation=True) +``` + +[അധ്യായം 3](/course/chapter3)-ൽ നിങ്ങൾ കണ്ടതുപോലെ, ഒന്നോ അതിലധികമോ ഉദാഹരണങ്ങൾ ടോക്കണൈസറിന് നൽകാം; അതിനാൽ ഈ ഫംഗ്‌ഷൻ `batched=True` ഉപയോഗിച്ചും അല്ലാതെയും നമുക്ക് ഉപയോഗിക്കാം. വ്യത്യസ്ത ഓപ്‌ഷനുകളുടെ പ്രകടനം താരതമ്യം ചെയ്യാൻ ഈ അവസരം ഉപയോഗപ്പെടുത്താം. ഒരു നോട്ട്‌ബുക്കിൽ, അളക്കാൻ ആഗ്രഹിക്കുന്ന കോഡ് വരിയുടെ മുന്നിൽ `%time` ചേർത്തുകൊണ്ട് ഒറ്റവരി നിർദ്ദേശത്തിന്റെ സമയം നിങ്ങൾക്ക് അളക്കാം: + +```python no-format +%time tokenized_dataset = drug_dataset.map(tokenize_function, batched=True) +``` + +സെല്ലിന്റെ തുടക്കത്തിൽ `%%time` ചേർത്തുകൊണ്ട് ഒരു സെൽ മുഴുവന്റെയും സമയവും നിങ്ങൾക്ക് അളക്കാം. നമ്മൾ ഇത് എക്‌സിക്യൂട്ട് ചെയ്ത ഹാർഡ്‌വെയറിൽ, ഈ നിർദ്ദേശത്തിന് 10.8s ആണ് കാണിച്ചത് ("Wall time" എന്നതിന് ശേഷം എഴുതിയിരിക്കുന്ന സംഖ്യയാണിത്). + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** ഇതേ നിർദ്ദേശം `batched=True` ഉപയോഗിച്ചും അല്ലാതെയും എക്‌സിക്യൂട്ട് ചെയ്യുക; പിന്നീട് ഒരു സ്ലോ ടോക്കണൈസർ ഉപയോഗിച്ചും (`AutoTokenizer.from_pretrained()` മെത്തേഡിൽ `use_fast=False` ചേർക്കുക) പരീക്ഷിക്കുക; അങ്ങനെ നിങ്ങളുടെ ഹാർഡ്‌വെയറിൽ എന്ത് സംഖ്യകളാണ് ലഭിക്കുന്നതെന്ന് നിങ്ങൾക്ക് കാണാം. + +ബാച്ചിംഗ് ഉപയോഗിച്ചും അല്ലാതെയും, ഒരു ഫാസ്‌റ്റ് ടോക്കണൈസറും ഒരു സ്ലോ ടോക്കണൈസറും ഉപയോഗിച്ച് നമുക്ക് ലഭിച്ച ഫലങ്ങൾ ഇതാ: + +ഓപ്‌ഷനുകൾ | ഫാസ്‌റ്റ് ടോക്കണൈസർ | സ്ലോ ടോക്കണൈസർ +:--------------:|:--------------:|:-------------: +`batched=True` | 10.8s | 4min41s +`batched=False` | 59.2s | 5min3s + +അതായത്, `batched=True` ഓപ്‌ഷനോടെ ഒരു ഫാസ്‌റ്റ് ടോക്കണൈസർ ഉപയോഗിക്കുന്നത്, ബാച്ചിംഗ് ഇല്ലാതെ അതിന്റെ സ്ലോ പതിപ്പ് ഉപയോഗിക്കുന്നതിനെക്കാൾ 30 മടങ്ങ് വേഗതയുള്ളതാണ് -- ഇത് ശരിക്കും അതിശയകരമാണ്! `AutoTokenizer` ഉപയോഗിക്കുമ്പോൾ ഫാസ്‌റ്റ് ടോക്കണൈസറുകൾ ഡിഫോൾട്ടായിരിക്കുന്നതിന്റെ (അവയെ "ഫാസ്‌റ്റ്" എന്ന് വിളിക്കുന്നതിന്റെയും) പ്രധാന കാരണം അതാണ്. തിരശ്ശീലയ്ക്ക് പിന്നിൽ ടോക്കണൈസേഷൻ കോഡ് Rust-ൽ എക്‌സിക്യൂട്ട് ചെയ്യുന്നതുകൊണ്ടാണ് അവയ്ക്ക് ഇത്രയും വേഗത കൈവരിക്കാൻ കഴിയുന്നത്; കോഡ് എക്‌സിക്യൂഷൻ പാരലലൈസ് ചെയ്യുന്നത് എളുപ്പമാക്കുന്ന ഒരു ഭാഷയാണ് Rust. + +ബാച്ചിംഗിലൂടെ ഫാസ്‌റ്റ് ടോക്കണൈസർ കൈവരിക്കുന്ന ഏകദേശം 6 മടങ്ങ് വേഗതയ്ക്കുള്ള കാരണവും പാരലലൈസേഷൻ (parallelization) തന്നെയാണ്: ഒരൊറ്റ ടോക്കണൈസേഷൻ ഓപ്പറേഷൻ പാരലലൈസ് ചെയ്യാൻ കഴിയില്ല, എന്നാൽ ഒരേ സമയം ധാരാളം ടെക്‌സ്‌റ്റുകൾ ടോക്കണൈസ് ചെയ്യണമെങ്കിൽ, എക്‌സിക്യൂഷൻ നിരവധി പ്രോസസ്സുകളിലേക്ക് വിഭജിക്കാം; ഓരോ പ്രോസസ്സും അതിന്റേതായ ടെക്‌സ്‌റ്റുകളുടെ ഉത്തരവാദിത്തം ഏറ്റെടുക്കും. + +`Dataset.map()`-ന് അതിന്റേതായ ചില പാരലലൈസേഷൻ കഴിവുകളും ഉണ്ട്. അവയ്ക്ക് Rust-ന്റെ പിന്തുണയില്ലാത്തതിനാൽ, ഒരു സ്ലോ ടോക്കണൈസറിനെ ഒരു ഫാസ്‌റ്റ് ടോക്കണൈസറിനൊപ്പം എത്തിക്കാൻ അവയ്ക്ക് കഴിയില്ല; എന്നിരുന്നാലും അവ സഹായകമാകും (പ്രത്യേകിച്ച്, ഫാസ്‌റ്റ് പതിപ്പില്ലാത്ത ഒരു ടോക്കണൈസറാണ് നിങ്ങൾ ഉപയോഗിക്കുന്നതെങ്കിൽ). മൾട്ടിപ്രോസസ്സിംഗ് പ്രവർത്തനക്ഷമമാക്കാൻ, `Dataset.map()` വിളിക്കുമ്പോൾ `num_proc` ആർഗ്യുമെന്റ് ഉപയോഗിച്ച് ഉപയോഗിക്കേണ്ട പ്രോസസ്സുകളുടെ എണ്ണം വ്യക്തമാക്കുക: + +```py +slow_tokenizer = AutoTokenizer.from_pretrained("bert-base-cased", use_fast=False) + + +def slow_tokenize_function(examples): + return slow_tokenizer(examples["review"], truncation=True) + + +tokenized_dataset = drug_dataset.map(slow_tokenize_function, batched=True, num_proc=8) +``` + +ഉപയോഗിക്കേണ്ട പ്രോസസ്സുകളുടെ ഏറ്റവും അനുയോജ്യമായ എണ്ണം നിർണ്ണയിക്കാൻ സമയം അളന്നുകൊണ്ട് നിങ്ങൾക്ക് കുറച്ച് പരീക്ഷണങ്ങൾ നടത്താം; നമ്മുടെ കാര്യത്തിൽ 8 ആണ് ഏറ്റവും മികച്ച വേഗതനേട്ടം നൽകിയതായി തോന്നിയത്. മൾട്ടിപ്രോസസ്സിംഗ് ഉപയോഗിച്ചും അല്ലാതെയും നമുക്ക് ലഭിച്ച സംഖ്യകൾ ഇതാ: + +ഓപ്‌ഷനുകൾ | ഫാസ്‌റ്റ് ടോക്കണൈസർ | സ്ലോ ടോക്കണൈസർ +:--------------:|:--------------:|:-------------: +`batched=True` | 10.8s | 4min41s +`batched=False` | 59.2s | 5min3s +`batched=True`, `num_proc=8` | 6.52s | 41.3s +`batched=False`, `num_proc=8` | 9.49s | 45.2s + +സ്ലോ ടോക്കണൈസറിന് ഇവ കുറച്ചുകൂടി ന്യായമായ ഫലങ്ങളാണ്, എന്നാൽ ഫാസ്‌റ്റ് ടോക്കണൈസറിന്റെ പ്രകടനവും ഗണ്യമായി മെച്ചപ്പെട്ടു. എന്നിരുന്നാലും, ഇത് എപ്പോഴും അങ്ങനെയായിരിക്കില്ല എന്നത് ശ്രദ്ധിക്കുക -- 8 അല്ലാത്ത `num_proc` മൂല്യങ്ങൾക്ക്, ആ ഓപ്‌ഷൻ ഇല്ലാതെ `batched=True` ഉപയോഗിക്കുന്നതാണ് വേഗതയേറിയത് എന്ന് ഞങ്ങളുടെ പരീക്ഷണങ്ങൾ കാണിച്ചു. പൊതുവേ, `batched=True` ഉപയോഗിക്കുന്ന ഫാസ്‌റ്റ് ടോക്കണൈസറുകൾക്ക് Python മൾട്ടിപ്രോസസ്സിംഗ് ഉപയോഗിക്കാൻ ഞങ്ങൾ ശുപാർശ ചെയ്യുന്നില്ല. + +> [!TIP] +> നിങ്ങൾ ഉപയോഗിക്കുന്ന ഫംഗ്‌ഷൻ ഇതിനകം സ്വന്തമായി ഏതെങ്കിലും തരത്തിലുള്ള മൾട്ടിപ്രോസസ്സിംഗ് ചെയ്യുന്നില്ലെങ്കിൽ, പ്രോസസ്സിംഗ് വേഗത്തിലാക്കാൻ `num_proc` ഉപയോഗിക്കുന്നത് സാധാരണയായി ഒരു മികച്ച ആശയമാണ്. + +ഈ പ്രവർത്തനക്ഷമതയെല്ലാം ഒരൊറ്റ മെത്തേഡിൽ ഒതുക്കിയിരിക്കുന്നത് തന്നെ അതിശയകരമാണ്, പക്ഷേ ഇനിയും ഉണ്ട്! `Dataset.map()`-ഉം `batched=True`-ഉം ഉപയോഗിച്ച് നിങ്ങളുടെ ഡേറ്റാസെറ്റിലെ എലമെന്റുകളുടെ എണ്ണം മാറ്റാൻ നിങ്ങൾക്ക് കഴിയും. ഒരു ഉദാഹരണത്തിൽ നിന്ന് നിരവധി ട്രെയിനിംഗ് ഫീച്ചറുകൾ ഉണ്ടാക്കേണ്ട പല സാഹചര്യങ്ങളിലും ഇത് വളരെ ഉപകാരപ്രദമാണ്; [അധ്യായം 7](/course/chapter7)-ൽ നമ്മൾ ഏറ്റെടുക്കുന്ന പല NLP ടാസ്‌ക്കുകളുടെയും പ്രീപ്രോസസ്സിംഗിന്റെ ഭാഗമായി നമുക്ക് ഇത് ചെയ്യേണ്ടി വരും. + +> [!TIP] +> 💡 മെഷീൻ ലേണിംഗിൽ, മോഡലിന് നമ്മൾ നൽകുന്ന _ഫീച്ചറുകളുടെ_ (features) കൂട്ടത്തെയാണ് സാധാരണയായി ഒരു _ഉദാഹരണം_ (example) എന്ന് നിർവചിക്കുന്നത്. ചില സന്ദർഭങ്ങളിൽ, ഈ ഫീച്ചറുകൾ ഒരു `Dataset`-ലെ കോളങ്ങളുടെ കൂട്ടമായിരിക്കും; എന്നാൽ മറ്റു ചില സന്ദർഭങ്ങളിൽ (ഇവിടെയും, ചോദ്യോത്തരത്തിലും (question answering) പോലെ), ഒരൊറ്റ ഉദാഹരണത്തിൽ നിന്ന് ഒന്നിലധികം ഫീച്ചറുകൾ വേർതിരിച്ചെടുക്കാം, അവ ഒരൊറ്റ കോളത്തിൽ ഉൾപ്പെടുന്നവയുമാകാം. + +ഇത് എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് നോക്കാം! ഇവിടെ നമ്മൾ നമ്മുടെ ഉദാഹരണങ്ങൾ ടോക്കണൈസ് ചെയ്ത് പരമാവധി 128 നീളത്തിലേക്ക് ട്രങ്കേറ്റ് (truncate) ചെയ്യും; എന്നാൽ ടെക്‌സ്‌റ്റുകളുടെ ആദ്യത്തെ ഭാഗം (chunk) മാത്രമല്ല, *എല്ലാ* ഭാഗങ്ങളും റിട്ടേൺ ചെയ്യാൻ ടോക്കണൈസറിനോട് നമ്മൾ ആവശ്യപ്പെടും. `return_overflowing_tokens=True` ഉപയോഗിച്ച് ഇത് ചെയ്യാം: + +```py +def tokenize_and_split(examples): + return tokenizer( + examples["review"], + truncation=True, + max_length=128, + return_overflowing_tokens=True, + ) +``` + +മുഴുവൻ ഡേറ്റാസെറ്റിലും `Dataset.map()` ഉപയോഗിക്കുന്നതിന് മുമ്പ്, ഒരു ഉദാഹരണത്തിൽ ഇത് പരീക്ഷിക്കാം: + +```py +result = tokenize_and_split(drug_dataset["train"][0]) +[len(inp) for inp in result["input_ids"]] +``` + +```python out +[128, 49] +``` + +അതായത്, നമ്മൾ വ്യക്തമാക്കിയ പരമാവധി ടോക്കണുകളുടെ എണ്ണത്തിലും കൂടുതലായി ടോക്കണൈസ് ചെയ്യപ്പെട്ടതിനാൽ, ട്രെയിനിംഗ് സെറ്റിലെ നമ്മുടെ ആദ്യ ഉദാഹരണം രണ്ട് ഫീച്ചറുകളായി മാറി: ആദ്യത്തേതിന് 128 നീളവും രണ്ടാമത്തേതിന് 49 നീളവും. ഇനി ഡേറ്റാസെറ്റിലെ എല്ലാ എലമെന്റുകൾക്കും ഇത് ചെയ്യാം! + +```py +tokenized_dataset = drug_dataset.map(tokenize_and_split, batched=True) +``` + +```python out +ArrowInvalid: Column 1 named condition expected length 1463 but got length 1000 +``` + +അയ്യോ! അത് പ്രവർത്തിച്ചില്ല! എന്തുകൊണ്ട്? എറർ മെസ്സേജ് നോക്കിയാൽ നമുക്ക് ഒരു സൂചന ലഭിക്കും: കോളങ്ങളിലൊന്നിന്റെ നീളത്തിൽ ഒരു പൊരുത്തക്കേടുണ്ട്; ഒന്നിന് 1,463 നീളവും മറ്റേതിന് 1,000 നീളവുമാണ്. `Dataset.map()`-ന്റെ [ഡോക്യുമെന്റേഷൻ](https://huggingface.co/docs/datasets/package_reference/main_classes#datasets.Dataset.map) നിങ്ങൾ നോക്കിയിട്ടുണ്ടെങ്കിൽ, നമ്മൾ map ചെയ്യുന്ന ഫംഗ്‌ഷന് നൽകുന്ന സാമ്പിളുകളുടെ എണ്ണമാണ് അത് എന്ന് നിങ്ങൾ ഓർക്കുന്നുണ്ടാകാം; ഇവിടെ ആ 1,000 ഉദാഹരണങ്ങൾ 1,463 പുതിയ ഫീച്ചറുകൾ നൽകി, അതിന്റെ ഫലമായി ഒരു ഷേപ്പ് എറർ (shape error) ഉണ്ടായി. + +വ്യത്യസ്ത വലുപ്പങ്ങളുള്ള രണ്ട് വ്യത്യസ്ത ഡേറ്റാസെറ്റുകൾ കൂട്ടിക്കലർത്താൻ നമ്മൾ ശ്രമിക്കുന്നു എന്നതാണ് പ്രശ്‌നം: `drug_dataset` കോളങ്ങളിൽ ഒരു നിശ്ചിത എണ്ണം ഉദാഹരണങ്ങളുണ്ടാകും (നമ്മുടെ എററിലെ 1,000), എന്നാൽ നമ്മൾ നിർമ്മിക്കുന്ന `tokenized_dataset`-ൽ അതിലും കൂടുതലുണ്ടാകും (എറർ മെസ്സേജിലെ 1,463; `return_overflowing_tokens=True` ഉപയോഗിച്ച് നീണ്ട റിവ്യൂകളെ ഒന്നിലധികം ഉദാഹരണങ്ങളായി ടോക്കണൈസ് ചെയ്യുന്നതിനാലാണ് ഇത് 1,000-ത്തിലും കൂടുതലാകുന്നത്). ഒരു `Dataset`-ന് ഇത് പ്രവർത്തിക്കില്ല; അതിനാൽ ഒന്നുകിൽ പഴയ ഡേറ്റാസെറ്റിൽ നിന്ന് കോളങ്ങൾ നീക്കം ചെയ്യുകയോ, അല്ലെങ്കിൽ പുതിയ ഡേറ്റാസെറ്റിലെ അതേ വലുപ്പത്തിലേക്ക് അവയെ മാറ്റുകയോ ചെയ്യണം. ആദ്യത്തേത് `remove_columns` ആർഗ്യുമെന്റ് ഉപയോഗിച്ച് നമുക്ക് ചെയ്യാം: + +```py +tokenized_dataset = drug_dataset.map( + tokenize_and_split, batched=True, remove_columns=drug_dataset["train"].column_names +) +``` + +ഇപ്പോൾ ഇത് എററില്ലാതെ പ്രവർത്തിക്കുന്നു. നീളങ്ങൾ താരതമ്യം ചെയ്തുകൊണ്ട്, യഥാർത്ഥ ഡേറ്റാസെറ്റിനെക്കാൾ വളരെയധികം എലമെന്റുകൾ നമ്മുടെ പുതിയ ഡേറ്റാസെറ്റിൽ ഉണ്ടെന്ന് നമുക്ക് പരിശോധിക്കാം: + +```py +len(tokenized_dataset["train"]), len(drug_dataset["train"]) +``` + +```python out +(206772, 138514) +``` + +പഴയ കോളങ്ങളെ പുതിയവയുടെ അതേ വലുപ്പത്തിലാക്കിക്കൊണ്ടും നീളത്തിലെ പൊരുത്തക്കേടിന്റെ പ്രശ്‌നം പരിഹരിക്കാമെന്ന് നമ്മൾ സൂചിപ്പിച്ചിരുന്നു. ഇതിനായി, `return_overflowing_tokens=True` സെറ്റ് ചെയ്യുമ്പോൾ ടോക്കണൈസർ റിട്ടേൺ ചെയ്യുന്ന `overflow_to_sample_mapping` ഫീൽഡ് നമുക്ക് ആവശ്യമാണ്. ഒരു പുതിയ ഫീച്ചർ ഇൻഡെക്‌സിൽ നിന്ന്, അത് ഉത്ഭവിച്ച സാമ്പിളിന്റെ ഇൻഡെക്‌സിലേക്കുള്ള ഒരു മാപ്പിംഗ് ഇത് നമുക്ക് നൽകുന്നു. ഇത് ഉപയോഗിച്ച്, ഓരോ ഉദാഹരണവും എത്ര പുതിയ ഫീച്ചറുകൾ ഉണ്ടാക്കുന്നുവോ അത്രയും തവണ അതിന്റെ മൂല്യങ്ങൾ ആവർത്തിച്ചുകൊണ്ട്, നമ്മുടെ യഥാർത്ഥ ഡേറ്റാസെറ്റിലെ ഓരോ കീയെയും ശരിയായ വലുപ്പമുള്ള മൂല്യങ്ങളുടെ ഒരു ലിസ്‌റ്റുമായി ബന്ധിപ്പിക്കാം: + +```py +def tokenize_and_split(examples): + result = tokenizer( + examples["review"], + truncation=True, + max_length=128, + return_overflowing_tokens=True, + ) + # Extract mapping between new and old indices + sample_map = result.pop("overflow_to_sample_mapping") + for key, values in examples.items(): + result[key] = [values[i] for i in sample_map] + return result +``` + +പഴയ കോളങ്ങൾ നീക്കം ചെയ്യേണ്ട ആവശ്യമില്ലാതെ തന്നെ ഇത് `Dataset.map()`-നൊപ്പം പ്രവർത്തിക്കുന്നതായി നമുക്ക് കാണാം: + +```py +tokenized_dataset = drug_dataset.map(tokenize_and_split, batched=True) +tokenized_dataset +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['attention_mask', 'condition', 'date', 'drugName', 'input_ids', 'patient_id', 'rating', 'review', 'review_length', 'token_type_ids', 'usefulCount'], + num_rows: 206772 + }) + test: Dataset({ + features: ['attention_mask', 'condition', 'date', 'drugName', 'input_ids', 'patient_id', 'rating', 'review', 'review_length', 'token_type_ids', 'usefulCount'], + num_rows: 68876 + }) +}) +``` + +മുൻപത്തെ അതേ എണ്ണം ട്രെയിനിംഗ് ഫീച്ചറുകളാണ് നമുക്ക് ലഭിക്കുന്നത്, എന്നാൽ ഇവിടെ എല്ലാ പഴയ ഫീൽഡുകളും നമ്മൾ നിലനിർത്തിയിട്ടുണ്ട്. നിങ്ങളുടെ മോഡൽ പ്രയോഗിച്ചതിനു ശേഷമുള്ള എന്തെങ്കിലും പോസ്‌റ്റ്-പ്രോസസ്സിംഗിന് അവ ആവശ്യമുണ്ടെങ്കിൽ, ഈ രീതി ഉപയോഗിക്കുന്നത് നിങ്ങൾക്ക് പരിഗണിക്കാം. + +ഒരു ഡേറ്റാസെറ്റ് വിവിധ രീതികളിൽ പ്രീപ്രോസസ്സ് ചെയ്യാൻ 🤗 Datasets എങ്ങനെ ഉപയോഗിക്കാമെന്ന് നിങ്ങൾ ഇപ്പോൾ കണ്ടു. നിങ്ങളുടെ മോഡൽ ട്രെയിനിംഗ് ആവശ്യങ്ങളിൽ മിക്കതും 🤗 Datasets-ന്റെ പ്രോസസ്സിംഗ് ഫംഗ്‌ഷനുകൾ നിറവേറ്റുമെങ്കിലും, +`DataFrame.groupby()` പോലുള്ള കൂടുതൽ ശക്തമായ ഫീച്ചറുകളോ വിഷ്വലൈസേഷനുള്ള ഉയർന്ന തലത്തിലുള്ള API-കളോ ആക്‌സസ് ചെയ്യാൻ Pandas-ലേക്ക് മാറേണ്ടി വരുന്ന സന്ദർഭങ്ങൾ ഉണ്ടാകാം. ഭാഗ്യവശാൽ, Pandas, NumPy, PyTorch, TensorFlow, JAX തുടങ്ങിയ ലൈബ്രറികളുമായി പരസ്പരം പ്രവർത്തിക്കാൻ (interoperable) കഴിയുന്ന രീതിയിലാണ് 🤗 Datasets രൂപകൽപ്പന ചെയ്തിരിക്കുന്നത്. ഇത് എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് നോക്കാം. + +## `Dataset`-കളിൽ നിന്ന് `DataFrame`-കളിലേക്കും തിരിച്ചും[[from-datasets-to-dataframes-and-back]] + + + +വിവിധ മൂന്നാം കക്ഷി (third-party) ലൈബ്രറികൾക്കിടയിലുള്ള പരിവർത്തനം സാധ്യമാക്കാൻ, 🤗 Datasets ഒരു `Dataset.set_format()` ഫംഗ്‌ഷൻ നൽകുന്നു. ഈ ഫംഗ്‌ഷൻ ഡേറ്റാസെറ്റിന്റെ _ഔട്ട്‌പുട്ട് ഫോർമാറ്റ്_ മാത്രമേ മാറ്റുന്നുള്ളൂ; അതിനാൽ അടിസ്ഥാനപരമായ _ഡേറ്റാ ഫോർമാറ്റിനെ_ (അത് Apache Arrow ആണ്) ബാധിക്കാതെ മറ്റൊരു ഫോർമാറ്റിലേക്ക് നിങ്ങൾക്ക് എളുപ്പത്തിൽ മാറാം. ഫോർമാറ്റിംഗ് അതേ സ്ഥാനത്ത് തന്നെ (in place) നടക്കുന്നു. ഇത് കാണിക്കാൻ, നമ്മുടെ ഡേറ്റാസെറ്റ് Pandas-ലേക്ക് മാറ്റാം: + +```py +drug_dataset.set_format("pandas") +``` + +ഇപ്പോൾ ഡേറ്റാസെറ്റിലെ എലമെന്റുകൾ ആക്‌സസ് ചെയ്യുമ്പോൾ ഒരു ഡിക്‌ഷണറിക്ക് പകരം ഒരു `pandas.DataFrame` ആണ് നമുക്ക് ലഭിക്കുന്നത്: + +```py +drug_dataset["train"][:3] +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
patient_iddrugNameconditionreviewratingdateusefulCountreview_length
095260Guanfacineadhd"My son is halfway through his fourth week of Intuniv..."8.0April 27, 2010192141
192703Lybrelbirth control"I used to take another oral contraceptive, which had 21 pill cycle, and was very happy- very light periods, max 5 days, no other side effects..."5.0December 14, 200917134
2138000Ortho Evrabirth control"This is my first time using any form of birth control..."8.0November 3, 20151089
+ +`drug_dataset["train"]`-ലെ എല്ലാ എലമെന്റുകളും തിരഞ്ഞെടുത്തുകൊണ്ട് മുഴുവൻ ട്രെയിനിംഗ് സെറ്റിനുമായി ഒരു `pandas.DataFrame` ഉണ്ടാക്കാം: + +```py +train_df = drug_dataset["train"][:] +``` + +> [!TIP] +> 🚨 അകമേ, `Dataset.set_format()` ഡേറ്റാസെറ്റിന്റെ `__getitem__()` ഡണ്ടർ (dunder) മെത്തേഡിന്റെ റിട്ടേൺ ഫോർമാറ്റാണ് മാറ്റുന്നത്. അതായത്, `"pandas"` ഫോർമാറ്റിലുള്ള ഒരു `Dataset`-ൽ നിന്ന് `train_df` പോലുള്ള ഒരു പുതിയ ഒബ്‌ജക്റ്റ് ഉണ്ടാക്കണമെങ്കിൽ, ഒരു `pandas.DataFrame` ലഭിക്കാൻ മുഴുവൻ ഡേറ്റാസെറ്റും സ്ലൈസ് ചെയ്യണം. ഔട്ട്‌പുട്ട് ഫോർമാറ്റ് എന്തായാലും `drug_dataset["train"]`-ന്റെ ടൈപ്പ് `Dataset` തന്നെയാണെന്ന് നിങ്ങൾക്ക് സ്വയം പരിശോധിച്ച് ഉറപ്പാക്കാം. + + +ഇവിടെ നിന്ന് നമുക്ക് ആവശ്യമുള്ള എല്ലാ Pandas പ്രവർത്തനക്ഷമതയും ഉപയോഗിക്കാം. ഉദാഹരണത്തിന്, `condition` എൻട്രികൾക്കിടയിലുള്ള ക്ലാസ് വിതരണം (class distribution) കണക്കാക്കാൻ നമുക്ക് മനോഹരമായ ചെയിനിംഗ് ചെയ്യാം: + +```py +frequencies = ( + train_df["condition"] + .value_counts() + .to_frame() + .reset_index() + .rename(columns={"index": "condition", "count": "frequency"}) +) +frequencies.head() +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
conditionfrequency
0birth control27655
1depression8023
2acne5209
3anxiety4991
4pain4744
+ + +നമ്മുടെ Pandas അനാലിസിസ് പൂർത്തിയായിക്കഴിഞ്ഞാൽ, `Dataset.from_pandas()` ഫംഗ്‌ഷൻ ഉപയോഗിച്ച് താഴെ കാണിച്ചിരിക്കുന്നതുപോലെ ഒരു പുതിയ `Dataset` ഒബ്‌ജക്റ്റ് എപ്പോഴും നമുക്ക് ഉണ്ടാക്കാം: + + +```py +from datasets import Dataset + +freq_dataset = Dataset.from_pandas(frequencies) +freq_dataset +``` + +```python out +Dataset({ + features: ['condition', 'frequency'], + num_rows: 819 +}) +``` + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** ഓരോ മരുന്നിന്റെയും ശരാശരി റേറ്റിംഗ് കണക്കാക്കി ഫലം ഒരു പുതിയ `Dataset`-ൽ സൂക്ഷിക്കുക. + +🤗 Datasets-ൽ ലഭ്യമായ വിവിധ പ്രീപ്രോസസ്സിംഗ് രീതികളിലൂടെയുള്ള നമ്മുടെ യാത്ര ഇവിടെ അവസാനിക്കുന്നു. ഈ ഭാഗം പൂർത്തിയാക്കാൻ, ഒരു ക്ലാസിഫയർ ട്രെയിൻ ചെയ്യുന്നതിനായി ഡേറ്റാസെറ്റ് തയ്യാറാക്കാൻ ഒരു വാലിഡേഷൻ സെറ്റ് ഉണ്ടാക്കാം. അതിനു മുമ്പ്, `drug_dataset`-ന്റെ ഔട്ട്‌പുട്ട് ഫോർമാറ്റ് `"pandas"`-ൽ നിന്ന് `"arrow"`-ലേക്ക് നമ്മൾ റീസെറ്റ് ചെയ്യും: + +```python +drug_dataset.reset_format() +``` + +## ഒരു വാലിഡേഷൻ സെറ്റ് ഉണ്ടാക്കുന്നു[[creating-a-validation-set]] + +ഇവാല്യുവേഷനായി ഉപയോഗിക്കാവുന്ന ഒരു ടെസ്‌റ്റ് സെറ്റ് നമുക്കുണ്ടെങ്കിലും, ടെസ്‌റ്റ് സെറ്റ് തൊടാതെ വെച്ചിട്ട്, ഡെവലപ്‌മെന്റ് സമയത്ത് ഒരു പ്രത്യേക വാലിഡേഷൻ സെറ്റ് ഉണ്ടാക്കുന്നത് ഒരു നല്ല ശീലമാണ്. വാലിഡേഷൻ സെറ്റിലെ നിങ്ങളുടെ മോഡലുകളുടെ പ്രകടനത്തിൽ നിങ്ങൾ സംതൃപ്തരായിക്കഴിഞ്ഞാൽ, ടെസ്‌റ്റ് സെറ്റിൽ ഒരു അവസാന പരിശോധന (sanity check) നടത്താം. ടെസ്‌റ്റ് സെറ്റിലേക്ക് ഓവർഫിറ്റ് ചെയ്ത്, യഥാർത്ഥ ലോകത്തിലെ ഡേറ്റയിൽ പരാജയപ്പെടുന്ന ഒരു മോഡൽ ഡിപ്ലോയ് ചെയ്യാനുള്ള സാധ്യത കുറയ്ക്കാൻ ഈ പ്രക്രിയ സഹായിക്കുന്നു. + +`scikit-learn`-ലെ പ്രശസ്‌തമായ പ്രവർത്തനക്ഷമതയെ അടിസ്ഥാനമാക്കിയുള്ള ഒരു `Dataset.train_test_split()` ഫംഗ്‌ഷൻ 🤗 Datasets നൽകുന്നു. നമ്മുടെ ട്രെയിനിംഗ് സെറ്റിനെ `train`, `validation` സ്‌പ്ലിറ്റുകളായി വിഭജിക്കാൻ ഇത് ഉപയോഗിക്കാം (പുനരുത്പാദനക്ഷമതയ്ക്കായി നമ്മൾ `seed` ആർഗ്യുമെന്റ് സെറ്റ് ചെയ്യുന്നു): + +```py +drug_dataset_clean = drug_dataset["train"].train_test_split(train_size=0.8, seed=42) +# Rename the default "test" split to "validation" +drug_dataset_clean["validation"] = drug_dataset_clean.pop("test") +# Add the "test" set to our `DatasetDict` +drug_dataset_clean["test"] = drug_dataset["test"] +drug_dataset_clean +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount', 'review_length', 'review_clean'], + num_rows: 110811 + }) + validation: Dataset({ + features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount', 'review_length', 'review_clean'], + num_rows: 27703 + }) + test: Dataset({ + features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount', 'review_length', 'review_clean'], + num_rows: 46108 + }) +}) +``` + +കൊള്ളാം, ചില മോഡലുകൾ ട്രെയിൻ ചെയ്യാൻ തയ്യാറായ ഒരു ഡേറ്റാസെറ്റ് നമ്മൾ ഇപ്പോൾ തയ്യാറാക്കിയിരിക്കുന്നു! ഡേറ്റാസെറ്റുകൾ Hugging Face Hub-ലേക്ക് എങ്ങനെ അപ്‌ലോഡ് ചെയ്യാമെന്ന് [ഭാഗം 5](/course/chapter5/5)-ൽ ഞങ്ങൾ നിങ്ങൾക്ക് കാണിച്ചുതരും; എന്നാൽ ഇപ്പോൾ, ഡേറ്റാസെറ്റുകൾ നിങ്ങളുടെ ലോക്കൽ മെഷീനിൽ സേവ് ചെയ്യാനുള്ള ചില മാർഗ്ഗങ്ങൾ നോക്കിക്കൊണ്ട് നമ്മുടെ അനാലിസിസ് പൂർത്തിയാക്കാം. + +## ഒരു ഡേറ്റാസെറ്റ് സേവ് ചെയ്യുന്നു[[saving-a-dataset]] + + + +ഡൗൺലോഡ് ചെയ്യുന്ന ഓരോ ഡേറ്റാസെറ്റും അതിൽ നടത്തുന്ന ഓപ്പറേഷനുകളും 🤗 Datasets കാഷ് (cache) ചെയ്യുമെങ്കിലും, ഒരു ഡേറ്റാസെറ്റ് ഡിസ്‌കിലേക്ക് സേവ് ചെയ്യേണ്ടി വരുന്ന സന്ദർഭങ്ങൾ ഉണ്ടാകാം (ഉദാ., കാഷ് ഡിലീറ്റ് ആയിപ്പോകുന്ന സാഹചര്യത്തിൽ). താഴെയുള്ള പട്ടികയിൽ കാണിച്ചിരിക്കുന്നതുപോലെ, നിങ്ങളുടെ ഡേറ്റാസെറ്റ് വ്യത്യസ്ത ഫോർമാറ്റുകളിൽ സേവ് ചെയ്യാൻ 🤗 Datasets മൂന്ന് പ്രധാന ഫംഗ്‌ഷനുകൾ നൽകുന്നു: + +| ഡേറ്റാ ഫോർമാറ്റ് | ഫംഗ്‌ഷൻ | +| :---------: | :--------------------: | +| Arrow | `Dataset.save_to_disk()` | +| CSV | `Dataset.to_csv()` | +| JSON | `Dataset.to_json()` | + +ഉദാഹരണത്തിന്, നമ്മുടെ വൃത്തിയാക്കിയ ഡേറ്റാസെറ്റ് Arrow ഫോർമാറ്റിൽ സേവ് ചെയ്യാം: + +```py +drug_dataset_clean.save_to_disk("drug-reviews") +``` + +ഇത് താഴെപ്പറയുന്ന ഘടനയുള്ള ഒരു ഡയറക്ടറി ഉണ്ടാക്കും: + +``` +drug-reviews/ +├── dataset_dict.json +├── test +│ ├── dataset.arrow +│ ├── dataset_info.json +│ └── state.json +├── train +│ ├── dataset.arrow +│ ├── dataset_info.json +│ ├── indices.arrow +│ └── state.json +└── validation + ├── dataset.arrow + ├── dataset_info.json + ├── indices.arrow + └── state.json +``` + +ഇവിടെ ഓരോ സ്‌പ്ലിറ്റിനും അതിന്റേതായ *dataset.arrow* ടേബിളും, *dataset_info.json*, *state.json* എന്നിവയിൽ ചില മെറ്റാഡേറ്റയും ഉണ്ടെന്ന് നമുക്ക് കാണാം. വലിയ ഡേറ്റാസെറ്റുകൾ പ്രോസസ്സ് ചെയ്യുകയും കൈമാറുകയും ചെയ്യുന്ന ഉയർന്ന പ്രകടനശേഷിയുള്ള ആപ്ലിക്കേഷനുകൾ നിർമ്മിക്കാൻ ഒപ്‌റ്റിമൈസ് ചെയ്ത, കോളങ്ങളും വരികളുമുള്ള ഒരു മികച്ച ടേബിളായി Arrow ഫോർമാറ്റിനെ നിങ്ങൾക്ക് കണക്കാക്കാം. + +ഡേറ്റാസെറ്റ് സേവ് ചെയ്തുകഴിഞ്ഞാൽ, `load_from_disk()` ഫംഗ്‌ഷൻ ഉപയോഗിച്ച് താഴെ കാണിച്ചിരിക്കുന്നതുപോലെ അത് ലോഡ് ചെയ്യാം: + +```py +from datasets import load_from_disk + +drug_dataset_reloaded = load_from_disk("drug-reviews") +drug_dataset_reloaded +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount', 'review_length'], + num_rows: 110811 + }) + validation: Dataset({ + features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount', 'review_length'], + num_rows: 27703 + }) + test: Dataset({ + features: ['patient_id', 'drugName', 'condition', 'review', 'rating', 'date', 'usefulCount', 'review_length'], + num_rows: 46108 + }) +}) +``` + +CSV, JSON ഫോർമാറ്റുകളിൽ, ഓരോ സ്‌പ്ലിറ്റും ഒരു പ്രത്യേക ഫയലായി സൂക്ഷിക്കണം. `DatasetDict` ഒബ്‌ജക്റ്റിലെ കീകളിലൂടെയും മൂല്യങ്ങളിലൂടെയും ഇറ്ററേറ്റ് ചെയ്യുന്നതാണ് ഇതിനുള്ള ഒരു മാർഗ്ഗം: + +```py +for split, dataset in drug_dataset_clean.items(): + dataset.to_json(f"drug-reviews-{split}.jsonl") +``` + +ഇത് ഓരോ സ്‌പ്ലിറ്റും [JSON Lines ഫോർമാറ്റിൽ](https://jsonlines.org) സേവ് ചെയ്യുന്നു; ഇവിടെ ഡേറ്റാസെറ്റിലെ ഓരോ വരിയും JSON-ന്റെ ഒരൊറ്റ വരിയായി സൂക്ഷിക്കപ്പെടുന്നു. ആദ്യത്തെ ഉദാഹരണം എങ്ങനെയുണ്ടെന്ന് ഇതാ: + +```py +!head -n 1 drug-reviews-train.jsonl +``` + +```python out +{"patient_id":141780,"drugName":"Escitalopram","condition":"depression","review":"\"I seemed to experience the regular side effects of LEXAPRO, insomnia, low sex drive, sleepiness during the day. I am taking it at night because my doctor said if it made me tired to take it at night. I assumed it would and started out taking it at night. Strange dreams, some pleasant. I was diagnosed with fibromyalgia. Seems to be helping with the pain. Have had anxiety and depression in my family, and have tried quite a few other medications that haven't worked. Only have been on it for two weeks but feel more positive in my mind, want to accomplish more in my life. Hopefully the side effects will dwindle away, worth it to stick with it from hearing others responses. Great medication.\"","rating":9.0,"date":"May 29, 2011","usefulCount":10,"review_length":125} +``` + +തുടർന്ന് [ഭാഗം 2](/course/chapter5/2)-ലെ രീതികൾ ഉപയോഗിച്ച് താഴെ കാണിച്ചിരിക്കുന്നതുപോലെ JSON ഫയലുകൾ നമുക്ക് ലോഡ് ചെയ്യാം: + +```py +data_files = { + "train": "drug-reviews-train.jsonl", + "validation": "drug-reviews-validation.jsonl", + "test": "drug-reviews-test.jsonl", +} +drug_dataset_reloaded = load_dataset("json", data_files=data_files) +``` + +🤗 Datasets ഉപയോഗിച്ചുള്ള ഡേറ്റാ റാംഗ്ലിംഗിലേക്കുള്ള (data wrangling) നമ്മുടെ യാത്ര ഇവിടെ അവസാനിക്കുന്നു! ഒരു മോഡൽ ട്രെയിൻ ചെയ്യാനുള്ള വൃത്തിയാക്കിയ ഒരു ഡേറ്റാസെറ്റ് ഇപ്പോൾ നമ്മുടെ കൈയിലുള്ളതിനാൽ, നിങ്ങൾക്ക് പരീക്ഷിച്ചു നോക്കാവുന്ന ചില ആശയങ്ങൾ ഇതാ: + +1. മരുന്ന് റിവ്യൂവിനെ അടിസ്ഥാനമാക്കി രോഗിയുടെ രോഗാവസ്ഥ പ്രവചിക്കാൻ കഴിയുന്ന ഒരു ക്ലാസിഫയർ ട്രെയിൻ ചെയ്യാൻ [അധ്യായം 3](/course/chapter3)-ലെ രീതികൾ ഉപയോഗിക്കുക. +2. റിവ്യൂകളുടെ സംഗ്രഹങ്ങൾ ഉണ്ടാക്കാൻ [അധ്യായം 1](/course/chapter1)-ലെ `summarization` പൈപ്പ്‌ലൈൻ ഉപയോഗിക്കുക. + +അടുത്തതായി, നിങ്ങളുടെ ലാപ്‌ടോപ്പ് തകരാതെ തന്നെ വലിയ ഡേറ്റാസെറ്റുകളുമായി പ്രവർത്തിക്കാൻ 🤗 Datasets നിങ്ങളെ എങ്ങനെ സഹായിക്കുന്നു എന്ന് നോക്കാം! diff --git a/chapters/ml/chapter5/4.mdx b/chapters/ml/chapter5/4.mdx new file mode 100644 index 000000000..aa31b95c3 --- /dev/null +++ b/chapters/ml/chapter5/4.mdx @@ -0,0 +1,272 @@ +# ബിഗ് ഡേറ്റയോ? 🤗 Datasets രക്ഷയ്‌ക്കെത്തുന്നു![[big-data-datasets-to-the-rescue]] + + + + +ഇക്കാലത്ത് പല ഗിഗാബൈറ്റ് വലുപ്പമുള്ള ഡേറ്റാസെറ്റുകളുമായി പ്രവർത്തിക്കേണ്ടി വരുന്നത് അസാധാരണമല്ല; പ്രത്യേകിച്ചും BERT അല്ലെങ്കിൽ GPT-2 പോലുള്ള ഒരു ട്രാൻസ്‌ഫോർമർ ആദ്യം മുതൽ (from scratch) പ്രീട്രെയിൻ ചെയ്യാൻ നിങ്ങൾ ഉദ്ദേശിക്കുന്നുണ്ടെങ്കിൽ. ഇത്തരം സന്ദർഭങ്ങളിൽ, ഡേറ്റ _ലോഡ് ചെയ്യുന്നത്_ പോലും ഒരു വെല്ലുവിളിയാകാം. ഉദാഹരണത്തിന്, GPT-2 പ്രീട്രെയിൻ ചെയ്യാൻ ഉപയോഗിച്ച WebText കോർപ്പസിൽ 8 ദശലക്ഷത്തിലധികം ഡോക്യുമെന്റുകളും 40 GB ടെക്‌സ്‌റ്റും അടങ്ങിയിരിക്കുന്നു -- ഇത് നിങ്ങളുടെ ലാപ്‌ടോപ്പിന്റെ RAM-ലേക്ക് ലോഡ് ചെയ്താൽ അതിന് ഒരു ഹൃദയാഘാതം വരാൻ സാധ്യതയുണ്ട്! + +ഭാഗ്യവശാൽ, ഈ പരിമിതികളെ മറികടക്കാൻ വേണ്ടിയാണ് 🤗 Datasets രൂപകൽപ്പന ചെയ്തിരിക്കുന്നത്. ഡേറ്റാസെറ്റുകളെ _മെമ്മറി-മാപ്പ്ഡ്_ (memory-mapped) ഫയലുകളായി കൈകാര്യം ചെയ്തുകൊണ്ട് മെമ്മറി മാനേജ്‌മെന്റ് പ്രശ്‌നങ്ങളിൽ നിന്നും, ഒരു കോർപ്പസിലെ എൻട്രികൾ _സ്‌ട്രീം_ (streaming) ചെയ്തുകൊണ്ട് ഹാർഡ് ഡ്രൈവിന്റെ പരിധികളിൽ നിന്നും ഇത് നിങ്ങളെ മോചിപ്പിക്കുന്നു. + + + +ഈ ഭാഗത്തിൽ, [the Pile](https://pile.eleuther.ai) എന്നറിയപ്പെടുന്ന 825 GB വലുപ്പമുള്ള ഒരു ഭീമൻ കോർപ്പസ് ഉപയോഗിച്ച് 🤗 Datasets-ന്റെ ഈ ഫീച്ചറുകൾ നമ്മൾ പരിശോധിക്കും. നമുക്ക് തുടങ്ങാം! + +## എന്താണ് Pile?[[what-is-the-pile]] + +വലിയ തോതിലുള്ള ലാംഗ്വേജ് മോഡലുകൾ ട്രെയിൻ ചെയ്യുന്നതിനായി [EleutherAI](https://www.eleuther.ai) സൃഷ്ടിച്ച ഒരു ഇംഗ്ലീഷ് ടെക്‌സ്‌റ്റ് കോർപ്പസാണ് Pile. ശാസ്ത്രീയ ലേഖനങ്ങൾ, GitHub കോഡ് റിപ്പോസിറ്ററികൾ, ഫിൽട്ടർ ചെയ്ത വെബ് ടെക്‌സ്‌റ്റ് എന്നിങ്ങനെ വൈവിധ്യമാർന്ന ഡേറ്റാസെറ്റുകൾ ഇതിൽ ഉൾപ്പെടുന്നു. ട്രെയിനിംഗ് കോർപ്പസ് [14 GB വീതമുള്ള ഭാഗങ്ങളായി](https://the-eye.eu/public/AI/pile/) ലഭ്യമാണ്; കൂടാതെ [വ്യക്തിഗത ഘടകങ്ങളിൽ](https://the-eye.eu/public/AI/pile_preliminary_components/) പലതും നിങ്ങൾക്ക് ഡൗൺലോഡ് ചെയ്യാനും കഴിയും. [PubMed](https://pubmed.ncbi.nlm.nih.gov/)-ലെ 15 ദശലക്ഷം ബയോമെഡിക്കൽ പ്രസിദ്ധീകരണങ്ങളുടെ സംഗ്രഹങ്ങൾ (abstracts) അടങ്ങിയ ഒരു കോർപ്പസായ PubMed Abstracts ഡേറ്റാസെറ്റ് പരിശോധിച്ചുകൊണ്ട് നമുക്ക് തുടങ്ങാം. ഈ ഡേറ്റാസെറ്റ് [JSON Lines ഫോർമാറ്റിലാണ്](https://jsonlines.org); `zstandard` ലൈബ്രറി ഉപയോഗിച്ച് കംപ്രസ് ചെയ്തിരിക്കുന്നതിനാൽ, ആദ്യം നമുക്ക് അത് ഇൻസ്‌റ്റാൾ ചെയ്യണം: + +```py +!pip install zstandard +``` + +അടുത്തതായി, [ഭാഗം 2](/course/chapter5/2)-ൽ നമ്മൾ പഠിച്ച റിമോട്ട് ഫയലുകൾക്കുള്ള രീതി ഉപയോഗിച്ച് ഡേറ്റാസെറ്റ് ലോഡ് ചെയ്യാം: + +```py +from datasets import load_dataset + +# This takes a few minutes to run, so go grab a tea or coffee while you wait :) +data_files = "https://the-eye.eu/public/AI/pile_preliminary_components/PUBMED_title_abstracts_2019_baseline.jsonl.zst" +pubmed_dataset = load_dataset("json", data_files=data_files, split="train") +pubmed_dataset +``` + +```python out +Dataset({ + features: ['meta', 'text'], + num_rows: 15518009 +}) +``` + +നമ്മുടെ ഡേറ്റാസെറ്റിൽ 15,518,009 വരികളും 2 കോളങ്ങളും ഉണ്ടെന്ന് നമുക്ക് കാണാം -- അത് ഒരുപാടാണ്! + +> [!TIP] +> ✎ ഡിഫോൾട്ടായി, ഒരു ഡേറ്റാസെറ്റ് ലോഡ് ചെയ്യാൻ ആവശ്യമായ ഫയലുകൾ 🤗 Datasets ഡീകംപ്രസ് ചെയ്യും. ഹാർഡ് ഡ്രൈവിലെ സ്ഥലം ലാഭിക്കണമെങ്കിൽ, `load_dataset()`-ന്റെ `download_config` ആർഗ്യുമെന്റിലേക്ക് `DownloadConfig(delete_extracted=True)` നൽകാം. കൂടുതൽ വിവരങ്ങൾക്ക് [ഡോക്യുമെന്റേഷൻ](https://huggingface.co/docs/datasets/package_reference/builder_classes#datasets.DownloadConfig) കാണുക. + +ആദ്യത്തെ ഉദാഹരണത്തിന്റെ ഉള്ളടക്കം നമുക്ക് പരിശോധിക്കാം: + +```py +pubmed_dataset[0] +``` + +```python out +{'meta': {'pmid': 11409574, 'language': 'eng'}, + 'text': 'Epidemiology of hypoxaemia in children with acute lower respiratory infection.\nTo determine the prevalence of hypoxaemia in children aged under 5 years suffering acute lower respiratory infections (ALRI), the risk factors for hypoxaemia in children under 5 years of age with ALRI, and the association of hypoxaemia with an increased risk of dying in children of the same age ...'} +``` + +ശരി, ഇത് ഒരു മെഡിക്കൽ ലേഖനത്തിന്റെ സംഗ്രഹം (abstract) പോലെ തോന്നുന്നു. ഇനി, ഡേറ്റാസെറ്റ് ലോഡ് ചെയ്യാൻ നമ്മൾ എത്ര RAM ഉപയോഗിച്ചു എന്ന് നോക്കാം! + +## മെമ്മറി മാപ്പിംഗിന്റെ മാജിക്[[the-magic-of-memory-mapping]] + +Python-ൽ മെമ്മറി ഉപയോഗം അളക്കാനുള്ള ഒരു ലളിതമായ മാർഗ്ഗം [`psutil`](https://psutil.readthedocs.io/en/latest/) ലൈബ്രറി ഉപയോഗിക്കുന്നതാണ്; താഴെ കാണിച്ചിരിക്കുന്നതുപോലെ `pip` ഉപയോഗിച്ച് ഇത് ഇൻസ്‌റ്റാൾ ചെയ്യാം: + +```python +!pip install psutil +``` + +നിലവിലെ പ്രോസസ്സിന്റെ മെമ്മറി ഉപയോഗം താഴെ കാണിച്ചിരിക്കുന്നതുപോലെ പരിശോധിക്കാൻ നമ്മെ അനുവദിക്കുന്ന ഒരു `Process` ക്ലാസ് ഇത് നൽകുന്നു: + +```py +import psutil + +# Process.memory_info is expressed in bytes, so convert to megabytes +print(f"RAM used: {psutil.Process().memory_info().rss / (1024 * 1024):.2f} MB") +``` + +```python out +RAM used: 5678.33 MB +``` + +ഇവിടെ `rss` ആട്രിബ്യൂട്ട് _റെസിഡന്റ് സെറ്റ് സൈസ്_ (resident set size) എന്നതിനെ സൂചിപ്പിക്കുന്നു; ഒരു പ്രോസസ്സ് RAM-ൽ കൈവശം വയ്ക്കുന്ന മെമ്മറിയുടെ അംശമാണിത്. Python ഇന്റർപ്രെറ്ററും നമ്മൾ ലോഡ് ചെയ്ത ലൈബ്രറികളും ഉപയോഗിക്കുന്ന മെമ്മറിയും ഈ അളവിൽ ഉൾപ്പെടുന്നു; അതിനാൽ ഡേറ്റാസെറ്റ് ലോഡ് ചെയ്യാൻ യഥാർത്ഥത്തിൽ ഉപയോഗിച്ച മെമ്മറിയുടെ അളവ് ഇതിലും കുറച്ച് ചെറുതാണ്. താരതമ്യത്തിനായി, `dataset_size` ആട്രിബ്യൂട്ട് ഉപയോഗിച്ച് ഡേറ്റാസെറ്റിന് ഡിസ്‌കിൽ എത്ര വലുപ്പമുണ്ടെന്ന് നോക്കാം. മുമ്പത്തേതുപോലെ ഫലം ബൈറ്റുകളിലാണ് പ്രകടിപ്പിക്കുന്നത് എന്നതിനാൽ, നമുക്ക് അത് സ്വയം ഗിഗാബൈറ്റുകളിലേക്ക് മാറ്റേണ്ടതുണ്ട്: + +```py +print(f"Dataset size in bytes: {pubmed_dataset.dataset_size}") +size_gb = pubmed_dataset.dataset_size / (1024**3) +print(f"Dataset size (cache file) : {size_gb:.2f} GB") +``` + +```python out +Dataset size in bytes : 20979437051 +Dataset size (cache file) : 19.54 GB +``` + +കൊള്ളാം -- ഏകദേശം 20 GB വലുപ്പമുണ്ടെങ്കിലും, അതിലും വളരെ കുറഞ്ഞ RAM ഉപയോഗിച്ച് ഡേറ്റാസെറ്റ് ലോഡ് ചെയ്യാനും ആക്‌സസ് ചെയ്യാനും നമുക്ക് കഴിയുന്നു! + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** നിങ്ങളുടെ ലാപ്‌ടോപ്പിന്റെയോ ഡെസ്‌ക്‌ടോപ്പിന്റെയോ RAM-നേക്കാൾ വലുപ്പമുള്ള, Pile-ലെ [സബ്‌സെറ്റുകളിൽ](https://the-eye.eu/public/AI/pile_preliminary_components/) ഒന്ന് തിരഞ്ഞെടുത്ത്, 🤗 Datasets ഉപയോഗിച്ച് അത് ലോഡ് ചെയ്ത്, ഉപയോഗിച്ച RAM-ന്റെ അളവ് അളക്കുക. കൃത്യമായ ഒരു അളവ് ലഭിക്കാൻ ഇത് ഒരു പുതിയ പ്രോസസ്സിൽ ചെയ്യേണ്ടതുണ്ട് എന്നത് ശ്രദ്ധിക്കുക. ഓരോ സബ്‌സെറ്റിന്റെയും ഡീകംപ്രസ് ചെയ്ത വലുപ്പങ്ങൾ [Pile പേപ്പറിലെ](https://arxiv.org/abs/2101.00027) ടേബിൾ 1-ൽ നിങ്ങൾക്ക് കാണാം. + +നിങ്ങൾക്ക് Pandas പരിചയമുണ്ടെങ്കിൽ, ഈ ഫലം ഒരു അത്ഭുതമായി തോന്നാം; കാരണം, നിങ്ങളുടെ ഡേറ്റാസെറ്റിന്റെ വലുപ്പത്തിന്റെ 5 മുതൽ 10 മടങ്ങ് വരെ RAM സാധാരണയായി ആവശ്യമാണെന്ന Wes Kinney-യുടെ പ്രശസ്തമായ ഒരു [പൊതുനിയമം (rule of thumb)](https://wesmckinney.com/blog/apache-arrow-pandas-internals/) ഉണ്ട്. അപ്പോൾ 🤗 Datasets ഈ മെമ്മറി മാനേജ്‌മെന്റ് പ്രശ്‌നം എങ്ങനെ പരിഹരിക്കുന്നു? 🤗 Datasets ഓരോ ഡേറ്റാസെറ്റിനെയും ഒരു [മെമ്മറി-മാപ്പ്ഡ് ഫയലായി](https://en.wikipedia.org/wiki/Memory-mapped_file) കൈകാര്യം ചെയ്യുന്നു; RAM-നും ഫയൽസിസ്‌റ്റം സ്‌റ്റോറേജിനും ഇടയിൽ ഒരു മാപ്പിംഗ് ഇത് നൽകുന്നു, അതുവഴി ഡേറ്റാസെറ്റ് പൂർണ്ണമായി മെമ്മറിയിലേക്ക് ലോഡ് ചെയ്യാതെ തന്നെ അതിലെ എലമെന്റുകൾ ആക്‌സസ് ചെയ്യാനും അവയിൽ പ്രവർത്തിക്കാനും ലൈബ്രറിക്ക് കഴിയുന്നു. + +മെമ്മറി-മാപ്പ്ഡ് ഫയലുകൾ ഒന്നിലധികം പ്രോസസ്സുകൾക്കിടയിൽ പങ്കുവയ്ക്കാനും കഴിയും; ഡേറ്റാസെറ്റ് നീക്കുകയോ പകർത്തുകയോ ചെയ്യാതെ തന്നെ `Dataset.map()` പോലുള്ള മെത്തേഡുകൾ പാരലലൈസ് ചെയ്യാൻ ഇത് സാധ്യമാക്കുന്നു. ഉള്ളിൽ, ഈ കഴിവുകളെല്ലാം സാക്ഷാത്കരിക്കുന്നത് [Apache Arrow](https://arrow.apache.org) മെമ്മറി ഫോർമാറ്റും [`pyarrow`](https://arrow.apache.org/docs/python/index.html) ലൈബ്രറിയുമാണ്; ഇവയാണ് ഡേറ്റാ ലോഡിംഗും പ്രോസസ്സിംഗും മിന്നൽ വേഗത്തിലാക്കുന്നത്. (Apache Arrow-യെക്കുറിച്ചുള്ള കൂടുതൽ വിവരങ്ങൾക്കും Pandas-മായുള്ള താരതമ്യങ്ങൾക്കും, [Dejan Simic-ന്റെ ബ്ലോഗ് പോസ്‌റ്റ്](https://towardsdatascience.com/apache-arrow-read-dataframe-with-zero-memory-69634092b1a) പരിശോധിക്കുക.) ഇത് പ്രവർത്തനത്തിൽ കാണാൻ, PubMed Abstracts ഡേറ്റാസെറ്റിലെ എല്ലാ എലമെന്റുകളിലൂടെയും ഇറ്ററേറ്റ് ചെയ്തുകൊണ്ട് ഒരു ചെറിയ വേഗതാ പരീക്ഷണം നടത്താം: + +```py +import timeit + +code_snippet = """batch_size = 1000 + +for idx in range(0, len(pubmed_dataset), batch_size): + _ = pubmed_dataset[idx:idx + batch_size] +""" + +time = timeit.timeit(stmt=code_snippet, number=1, globals=globals()) +print( + f"Iterated over {len(pubmed_dataset)} examples (about {size_gb:.1f} GB) in " + f"{time:.1f}s, i.e. {size_gb/time:.3f} GB/s" +) +``` + +```python out +'Iterated over 15518009 examples (about 19.5 GB) in 64.2s, i.e. 0.304 GB/s' +``` + +`code_snippet` എക്‌സിക്യൂട്ട് ചെയ്യാൻ എടുത്ത സമയം അളക്കാൻ ഇവിടെ നമ്മൾ Python-ന്റെ `timeit` മൊഡ്യൂൾ ഉപയോഗിച്ചു. സാധാരണയായി, ഒരു GB/s-ന്റെ ഏതാനും പത്തിലൊന്ന് മുതൽ നിരവധി GB/s വരെ വേഗതയിൽ ഒരു ഡേറ്റാസെറ്റിലൂടെ ഇറ്ററേറ്റ് ചെയ്യാൻ നിങ്ങൾക്ക് കഴിയും. ബഹുഭൂരിപക്ഷം ആപ്ലിക്കേഷനുകൾക്കും ഇത് നന്നായി പ്രവർത്തിക്കും, എന്നാൽ ചിലപ്പോൾ നിങ്ങളുടെ ലാപ്‌ടോപ്പിന്റെ ഹാർഡ് ഡ്രൈവിൽ സൂക്ഷിക്കാൻ പോലും കഴിയാത്തത്ര വലിയ ഒരു ഡേറ്റാസെറ്റുമായി നിങ്ങൾക്ക് പ്രവർത്തിക്കേണ്ടി വരും. ഉദാഹരണത്തിന്, Pile പൂർണ്ണമായി ഡൗൺലോഡ് ചെയ്യാൻ ശ്രമിച്ചാൽ, നമുക്ക് 825 GB ഒഴിഞ്ഞ ഡിസ്‌ക് സ്ഥലം വേണ്ടിവരും! ഇത്തരം സന്ദർഭങ്ങൾ കൈകാര്യം ചെയ്യാൻ, മുഴുവൻ ഡേറ്റാസെറ്റും ഡൗൺലോഡ് ചെയ്യാതെ തന്നെ എലമെന്റുകൾ തത്സമയം (on the fly) ഡൗൺലോഡ് ചെയ്യാനും ആക്‌സസ് ചെയ്യാനും അനുവദിക്കുന്ന ഒരു സ്‌ട്രീമിംഗ് ഫീച്ചർ 🤗 Datasets നൽകുന്നു. ഇത് എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് നോക്കാം. + +> [!TIP] +> 💡 Jupyter നോട്ട്‌ബുക്കുകളിൽ [`%%timeit` മാജിക് ഫംഗ്‌ഷൻ](https://ipython.readthedocs.io/en/stable/interactive/magics.html#magic-timeit) ഉപയോഗിച്ചും സെല്ലുകളുടെ സമയം അളക്കാം. + +## ഡേറ്റാസെറ്റുകൾ സ്‌ട്രീം ചെയ്യുന്നു[[streaming-datasets]] + +ഡേറ്റാസെറ്റ് സ്‌ട്രീമിംഗ് പ്രവർത്തനക്ഷമമാക്കാൻ `load_dataset()` ഫംഗ്‌ഷനിലേക്ക് `streaming=True` എന്ന ആർഗ്യുമെന്റ് നൽകിയാൽ മാത്രം മതി. ഉദാഹരണത്തിന്, PubMed Abstracts ഡേറ്റാസെറ്റ് ഒരിക്കൽക്കൂടി ലോഡ് ചെയ്യാം, പക്ഷേ ഇത്തവണ സ്‌ട്രീമിംഗ് മോഡിൽ: + +```py +pubmed_dataset_streamed = load_dataset( + "json", data_files=data_files, split="train", streaming=True +) +``` + +ഈ അധ്യായത്തിൽ മറ്റിടങ്ങളിൽ നമ്മൾ കണ്ടുപരിചയിച്ച `Dataset`-ന് പകരം, `streaming=True` ഉപയോഗിക്കുമ്പോൾ റിട്ടേൺ ചെയ്യുന്ന ഒബ്‌ജക്റ്റ് ഒരു `IterableDataset` ആണ്. പേര് സൂചിപ്പിക്കുന്നതുപോലെ, ഒരു `IterableDataset`-ലെ എലമെന്റുകൾ ആക്‌സസ് ചെയ്യാൻ നമുക്ക് അതിലൂടെ ഇറ്ററേറ്റ് ചെയ്യേണ്ടതുണ്ട്. നമ്മുടെ സ്‌ട്രീം ചെയ്ത ഡേറ്റാസെറ്റിലെ ആദ്യത്തെ എലമെന്റ് താഴെ കാണിച്ചിരിക്കുന്നതുപോലെ ആക്‌സസ് ചെയ്യാം: + + +```py +next(iter(pubmed_dataset_streamed)) +``` + +```python out +{'meta': {'pmid': 11409574, 'language': 'eng'}, + 'text': 'Epidemiology of hypoxaemia in children with acute lower respiratory infection.\nTo determine the prevalence of hypoxaemia in children aged under 5 years suffering acute lower respiratory infections (ALRI), the risk factors for hypoxaemia in children under 5 years of age with ALRI, and the association of hypoxaemia with an increased risk of dying in children of the same age ...'} +``` + +സ്‌ട്രീം ചെയ്ത ഒരു ഡേറ്റാസെറ്റിലെ എലമെന്റുകൾ `IterableDataset.map()` ഉപയോഗിച്ച് തത്സമയം പ്രോസസ്സ് ചെയ്യാം; ട്രെയിനിംഗ് സമയത്ത് ഇൻപുട്ടുകൾ ടോക്കണൈസ് ചെയ്യേണ്ടതുണ്ടെങ്കിൽ ഇത് ഉപകാരപ്രദമാണ്. [അധ്യായം 3](/course/chapter3)-ൽ നമ്മുടെ ഡേറ്റാസെറ്റ് ടോക്കണൈസ് ചെയ്യാൻ നമ്മൾ ഉപയോഗിച്ച അതേ പ്രക്രിയ തന്നെയാണിത്; ഔട്ട്‌പുട്ടുകൾ ഒന്നൊന്നായി റിട്ടേൺ ചെയ്യപ്പെടുന്നു എന്നതാണ് ഒരേയൊരു വ്യത്യാസം: + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("distilbert-base-uncased") +tokenized_dataset = pubmed_dataset_streamed.map(lambda x: tokenizer(x["text"])) +next(iter(tokenized_dataset)) +``` + +```python out +{'input_ids': [101, 4958, 5178, 4328, 6779, ...], 'attention_mask': [1, 1, 1, 1, 1, ...]} +``` + +> [!TIP] +> 💡 സ്‌ട്രീമിംഗിനൊപ്പം ടോക്കണൈസേഷൻ വേഗത്തിലാക്കാൻ, കഴിഞ്ഞ ഭാഗത്തിൽ നമ്മൾ കണ്ടതുപോലെ `batched=True` നൽകാം. ഇത് ഉദാഹരണങ്ങളെ ബാച്ച് ബാച്ചായി പ്രോസസ്സ് ചെയ്യും; ഡിഫോൾട്ട് ബാച്ച് സൈസ് 1,000 ആണ്, ഇത് `batch_size` ആർഗ്യുമെന്റ് ഉപയോഗിച്ച് വ്യക്തമാക്കാം. + +`IterableDataset.shuffle()` ഉപയോഗിച്ച് സ്‌ട്രീം ചെയ്ത ഒരു ഡേറ്റാസെറ്റ് ഷഫിൾ ചെയ്യാനും കഴിയും, എന്നാൽ `Dataset.shuffle()`-ൽ നിന്ന് വ്യത്യസ്തമായി, മുൻകൂട്ടി നിശ്ചയിച്ച ഒരു `buffer_size`-ലെ എലമെന്റുകൾ മാത്രമേ ഇത് ഷഫിൾ ചെയ്യുന്നുള്ളൂ: + +```py +shuffled_dataset = pubmed_dataset_streamed.shuffle(buffer_size=10_000, seed=42) +next(iter(shuffled_dataset)) +``` + +```python out +{'meta': {'pmid': 11410799, 'language': 'eng'}, + 'text': 'Randomized study of dose or schedule modification of granulocyte colony-stimulating factor in platinum-based chemotherapy for elderly patients with lung cancer ...'} +``` + +ഈ ഉദാഹരണത്തിൽ, ബഫറിലെ ആദ്യത്തെ 10,000 ഉദാഹരണങ്ങളിൽ നിന്ന് ക്രമരഹിതമായ (random) ഒരു ഉദാഹരണം നമ്മൾ തിരഞ്ഞെടുത്തു. ഒരു ഉദാഹരണം ആക്‌സസ് ചെയ്തുകഴിഞ്ഞാൽ, ബഫറിലെ അതിന്റെ സ്ഥാനം കോർപ്പസിലെ അടുത്ത ഉദാഹരണം കൊണ്ട് നിറയ്ക്കപ്പെടുന്നു (അതായത്, മുകളിലെ സന്ദർഭത്തിൽ 10,001-ാമത്തെ ഉദാഹരണം). `Dataset.select()`-ന് സമാനമായ രീതിയിൽ പ്രവർത്തിക്കുന്ന `IterableDataset.take()`, `IterableDataset.skip()` ഫംഗ്‌ഷനുകൾ ഉപയോഗിച്ച് സ്‌ട്രീം ചെയ്ത ഒരു ഡേറ്റാസെറ്റിൽ നിന്ന് എലമെന്റുകൾ തിരഞ്ഞെടുക്കാനും കഴിയും. ഉദാഹരണത്തിന്, PubMed Abstracts ഡേറ്റാസെറ്റിലെ ആദ്യത്തെ 5 ഉദാഹരണങ്ങൾ തിരഞ്ഞെടുക്കാൻ നമുക്ക് ഇങ്ങനെ ചെയ്യാം: + +```py +dataset_head = pubmed_dataset_streamed.take(5) +list(dataset_head) +``` + +```python out +[{'meta': {'pmid': 11409574, 'language': 'eng'}, + 'text': 'Epidemiology of hypoxaemia in children with acute lower respiratory infection ...'}, + {'meta': {'pmid': 11409575, 'language': 'eng'}, + 'text': 'Clinical signs of hypoxaemia in children with acute lower respiratory infection: indicators of oxygen therapy ...'}, + {'meta': {'pmid': 11409576, 'language': 'eng'}, + 'text': "Hypoxaemia in children with severe pneumonia in Papua New Guinea ..."}, + {'meta': {'pmid': 11409577, 'language': 'eng'}, + 'text': 'Oxygen concentrators and cylinders ...'}, + {'meta': {'pmid': 11409578, 'language': 'eng'}, + 'text': 'Oxygen supply in rural africa: a personal experience ...'}] +``` + +അതുപോലെ, ഷഫിൾ ചെയ്ത ഒരു ഡേറ്റാസെറ്റിൽ നിന്ന് ട്രെയിനിംഗ്, വാലിഡേഷൻ സ്‌പ്ലിറ്റുകൾ ഉണ്ടാക്കാൻ `IterableDataset.skip()` ഫംഗ്‌ഷൻ താഴെ കാണിച്ചിരിക്കുന്നതുപോലെ ഉപയോഗിക്കാം: + +```py +# Skip the first 1,000 examples and include the rest in the training set +train_dataset = shuffled_dataset.skip(1000) +# Take the first 1,000 examples for the validation set +validation_dataset = shuffled_dataset.take(1000) +``` + +ഡേറ്റാസെറ്റ് സ്‌ട്രീമിംഗിനെക്കുറിച്ചുള്ള നമ്മുടെ അന്വേഷണം ഒരു സാധാരണ ഉപയോഗത്തോടെ പൂർത്തിയാക്കാം: ഒന്നിലധികം ഡേറ്റാസെറ്റുകൾ കൂട്ടിച്ചേർത്ത് ഒരൊറ്റ കോർപ്പസ് ഉണ്ടാക്കുന്നത്. `IterableDataset` ഒബ്‌ജക്റ്റുകളുടെ ഒരു ലിസ്‌റ്റിനെ ഒരൊറ്റ `IterableDataset`-ലേക്ക് മാറ്റുന്ന `interleave_datasets()` എന്ന ഫംഗ്‌ഷൻ 🤗 Datasets നൽകുന്നു; ഇവിടെ പുതിയ ഡേറ്റാസെറ്റിലെ എലമെന്റുകൾ ലഭിക്കുന്നത് ഉറവിട ഉദാഹരണങ്ങൾക്കിടയിൽ മാറിമാറി എടുത്തുകൊണ്ടാണ്. വലിയ ഡേറ്റാസെറ്റുകൾ കൂട്ടിച്ചേർക്കാൻ ശ്രമിക്കുമ്പോൾ ഈ ഫംഗ്‌ഷൻ പ്രത്യേകിച്ചും ഉപകാരപ്രദമാണ്; അതിനാൽ ഒരു ഉദാഹരണമായി, Pile-ലെ FreeLaw സബ്‌സെറ്റ് നമുക്ക് സ്‌ട്രീം ചെയ്യാം — US കോടതികളിൽ നിന്നുള്ള നിയമപരമായ വിധിന്യായങ്ങളുടെ (legal opinions) 51 GB വലുപ്പമുള്ള ഒരു ഡേറ്റാസെറ്റാണിത്: + +```py +law_dataset_streamed = load_dataset( + "json", + data_files="https://the-eye.eu/public/AI/pile_preliminary_components/FreeLaw_Opinions.jsonl.zst", + split="train", + streaming=True, +) +next(iter(law_dataset_streamed)) +``` + +```python out +{'meta': {'case_ID': '110921.json', + 'case_jurisdiction': 'scotus.tar.gz', + 'date_created': '2010-04-28T17:12:49Z'}, + 'text': '\n461 U.S. 238 (1983)\nOLIM ET AL.\nv.\nWAKINEKONA\nNo. 81-1581.\nSupreme Court of United States.\nArgued January 19, 1983.\nDecided April 26, 1983.\nCERTIORARI TO THE UNITED STATES COURT OF APPEALS FOR THE NINTH CIRCUIT\n*239 Michael A. Lilly, First Deputy Attorney General of Hawaii, argued the cause for petitioners. With him on the brief was James H. Dannenberg, Deputy Attorney General...'} +``` + +മിക്ക ലാപ്‌ടോപ്പുകളുടെയും RAM-ന് സമ്മർദ്ദമുണ്ടാക്കാൻ മാത്രം വലുപ്പമുള്ള ഡേറ്റാസെറ്റാണിത്, എന്നിട്ടും ഒരു തുള്ളി വിയർക്കാതെ ഇത് ലോഡ് ചെയ്യാനും ആക്‌സസ് ചെയ്യാനും നമുക്ക് കഴിഞ്ഞു! ഇനി `interleave_datasets()` ഫംഗ്‌ഷൻ ഉപയോഗിച്ച് FreeLaw, PubMed Abstracts ഡേറ്റാസെറ്റുകളിലെ ഉദാഹരണങ്ങൾ കൂട്ടിച്ചേർക്കാം: + +```py +from itertools import islice +from datasets import interleave_datasets + +combined_dataset = interleave_datasets([pubmed_dataset_streamed, law_dataset_streamed]) +list(islice(combined_dataset, 2)) +``` + +```python out +[{'meta': {'pmid': 11409574, 'language': 'eng'}, + 'text': 'Epidemiology of hypoxaemia in children with acute lower respiratory infection ...'}, + {'meta': {'case_ID': '110921.json', + 'case_jurisdiction': 'scotus.tar.gz', + 'date_created': '2010-04-28T17:12:49Z'}, + 'text': '\n461 U.S. 238 (1983)\nOLIM ET AL.\nv.\nWAKINEKONA\nNo. 81-1581.\nSupreme Court of United States.\nArgued January 19, 1983.\nDecided April 26, 1983.\nCERTIORARI TO THE UNITED STATES COURT OF APPEALS FOR THE NINTH CIRCUIT\n*239 Michael A. Lilly, First Deputy Attorney General of Hawaii, argued the cause for petitioners. With him on the brief was James H. Dannenberg, Deputy Attorney General...'}] +``` + +കൂട്ടിച്ചേർത്ത ഡേറ്റാസെറ്റിലെ ആദ്യത്തെ രണ്ട് ഉദാഹരണങ്ങൾ തിരഞ്ഞെടുക്കാൻ ഇവിടെ നമ്മൾ Python-ന്റെ `itertools` മൊഡ്യൂളിലെ `islice()` ഫംഗ്‌ഷൻ ഉപയോഗിച്ചു; രണ്ട് ഉറവിട ഡേറ്റാസെറ്റുകളിലെയും ആദ്യ ഉദാഹരണങ്ങളുമായി അവ പൊരുത്തപ്പെടുന്നതായി നമുക്ക് കാണാം. + +അവസാനമായി, 825 GB വലുപ്പമുള്ള Pile പൂർണ്ണമായി സ്‌ട്രീം ചെയ്യണമെങ്കിൽ, തയ്യാറാക്കിയ എല്ലാ ഫയലുകളും താഴെ കാണിച്ചിരിക്കുന്നതുപോലെ എടുക്കാം: + +```py +base_url = "https://the-eye.eu/public/AI/pile/" +data_files = { + "train": [base_url + "train/" + f"{idx:02d}.jsonl.zst" for idx in range(30)], + "validation": base_url + "val.jsonl.zst", + "test": base_url + "test.jsonl.zst", +} +pile_dataset = load_dataset("json", data_files=data_files, streaming=True) +next(iter(pile_dataset["train"])) +``` + +```python out +{'meta': {'pile_set_name': 'Pile-CC'}, + 'text': 'It is done, and submitted. You can play “Survival of the Tastiest” on Android, and on the web...'} +``` + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** നിങ്ങൾ തിരഞ്ഞെടുക്കുന്ന ഒരു രാജ്യത്തിലെ ഭാഷകൾ സംസാരിക്കുന്നവരുടെ അനുപാതം പ്രതിനിധീകരിക്കുന്ന ഒരു സ്‌ട്രീമിംഗ് ബഹുഭാഷാ ഡേറ്റാസെറ്റ് ഉണ്ടാക്കാൻ, [`mc4`](https://huggingface.co/datasets/mc4) അല്ലെങ്കിൽ [`oscar`](https://huggingface.co/datasets/oscar) പോലുള്ള വലിയ Common Crawl കോർപ്പസുകളിലൊന്ന് ഉപയോഗിക്കുക. ഉദാഹരണത്തിന്, സ്വിറ്റ്‌സർലൻഡിലെ നാല് ദേശീയ ഭാഷകൾ ജർമ്മൻ, ഫ്രഞ്ച്, ഇറ്റാലിയൻ, റൊമാൻഷ് എന്നിവയാണ്; അതിനാൽ Oscar സബ്‌സെറ്റുകളെ അവ സംസാരിക്കുന്നവരുടെ അനുപാതമനുസരിച്ച് സാമ്പിൾ ചെയ്തുകൊണ്ട് ഒരു സ്വിസ് കോർപ്പസ് ഉണ്ടാക്കാൻ നിങ്ങൾക്ക് ശ്രമിക്കാം. + +എല്ലാ രൂപത്തിലും വലുപ്പത്തിലുമുള്ള ഡേറ്റാസെറ്റുകൾ ലോഡ് ചെയ്യാനും പ്രോസസ്സ് ചെയ്യാനും ആവശ്യമായ എല്ലാ ടൂളുകളും ഇപ്പോൾ നിങ്ങളുടെ കൈയിലുണ്ട് -- എന്നാൽ നിങ്ങൾ അസാധാരണമാംവിധം ഭാഗ്യവാനല്ലെങ്കിൽ, കൈയിലുള്ള പ്രശ്‌നം പരിഹരിക്കാൻ യഥാർത്ഥത്തിൽ ഒരു ഡേറ്റാസെറ്റ് സ്വയം ഉണ്ടാക്കേണ്ടി വരുന്ന ഒരു ഘട്ടം നിങ്ങളുടെ NLP യാത്രയിൽ വരും. അതാണ് അടുത്ത ഭാഗത്തിന്റെ വിഷയം! diff --git a/chapters/ml/chapter5/5.mdx b/chapters/ml/chapter5/5.mdx new file mode 100644 index 000000000..837768cbf --- /dev/null +++ b/chapters/ml/chapter5/5.mdx @@ -0,0 +1,388 @@ +# നിങ്ങളുടെ സ്വന്തം ഡേറ്റാസെറ്റ് ഉണ്ടാക്കുന്നു[[creating-your-own-dataset]] + + + +ചില സമയങ്ങളിൽ ഒരു NLP ആപ്ലിക്കേഷൻ നിർമ്മിക്കാൻ നിങ്ങൾക്ക് ആവശ്യമായ ഡേറ്റാസെറ്റ് നിലവിലുണ്ടാകില്ല; അപ്പോൾ അത് നിങ്ങൾ സ്വയം ഉണ്ടാക്കേണ്ടിവരും. GitHub റെപ്പോസിറ്ററികളിലെ ബഗ്ഗുകളോ ഫീച്ചറുകളോ ട്രാക്ക് ചെയ്യാൻ സാധാരണയായി ഉപയോഗിക്കുന്ന [GitHub ഇഷ്യൂകളുടെ](https://github.com/features/issues/) ഒരു കോർപ്പസ് (corpus) എങ്ങനെ ഉണ്ടാക്കാമെന്ന് ഈ ഭാഗത്തിൽ ഞങ്ങൾ നിങ്ങൾക്ക് കാണിച്ചുതരും. ഈ കോർപ്പസ് താഴെപ്പറയുന്നവ ഉൾപ്പെടെ വിവിധ ആവശ്യങ്ങൾക്ക് ഉപയോഗിക്കാം: + +* തുറന്നിരിക്കുന്ന ഇഷ്യൂകളോ പുൾ റിക്വസ്റ്റുകളോ ക്ലോസ് ചെയ്യാൻ എത്ര സമയമെടുക്കുന്നു എന്ന് പരിശോധിക്കുക +* ഇഷ്യൂവിന്റെ വിവരണത്തെ അടിസ്ഥാനമാക്കി ഇഷ്യൂകൾക്ക് മെറ്റാഡേറ്റ ടാഗുകൾ (ഉദാ., "bug", "enhancement", അല്ലെങ്കിൽ "question") നൽകാൻ കഴിയുന്ന ഒരു _മൾട്ടിലേബൽ ക്ലാസിഫയർ_ (multilabel classifier) ട്രെയിൻ ചെയ്യുക +* ഒരു ഉപയോക്താവിന്റെ ക്വറിയുമായി (query) ഏതെല്ലാം ഇഷ്യൂകൾ പൊരുത്തപ്പെടുന്നു എന്ന് കണ്ടെത്താൻ ഒരു സെമാന്റിക് സെർച്ച് എഞ്ചിൻ നിർമ്മിക്കുക + +ഇവിടെ നമ്മൾ കോർപ്പസ് ഉണ്ടാക്കുന്നതിൽ ശ്രദ്ധ കേന്ദ്രീകരിക്കും; അടുത്ത ഭാഗത്തിൽ സെമാന്റിക് സെർച്ച് ആപ്ലിക്കേഷൻ നമ്മൾ കൈകാര്യം ചെയ്യും. കാര്യങ്ങൾ ഒന്ന് "മെറ്റാ" (meta) ആക്കാൻ, ജനപ്രിയമായ ഒരു ഓപ്പൺ സോഴ്‌സ് പ്രോജക്റ്റുമായി ബന്ധപ്പെട്ട GitHub ഇഷ്യൂകൾ നമ്മൾ ഉപയോഗിക്കും: 🤗 Datasets! ഡേറ്റ എങ്ങനെ നേടാമെന്നും ഈ ഇഷ്യൂകളിൽ അടങ്ങിയിരിക്കുന്ന വിവരങ്ങൾ എങ്ങനെ പരിശോധിക്കാമെന്നും നോക്കാം. + +## ഡേറ്റ ശേഖരിക്കുന്നു[[getting-the-data]] + +റെപ്പോസിറ്ററിയുടെ [Issues ടാബിലേക്ക്](https://github.com/huggingface/datasets/issues) പോയാൽ 🤗 Datasets-ലെ എല്ലാ ഇഷ്യൂകളും നിങ്ങൾക്ക് കാണാം. താഴെയുള്ള സ്‌ക്രീൻഷോട്ടിൽ കാണിച്ചിരിക്കുന്നതുപോലെ, ഇത് എഴുതുന്ന സമയത്ത് 331 തുറന്ന ഇഷ്യൂകളും 668 ക്ലോസ് ചെയ്തവയും ഉണ്ടായിരുന്നു. + +
+🤗 Datasets-മായി ബന്ധപ്പെട്ട GitHub ഇഷ്യൂകൾ. +
+ +ഈ ഇഷ്യൂകളിലൊന്നിൽ ക്ലിക്ക് ചെയ്താൽ, അതിൽ ഒരു തലക്കെട്ടും (title), ഒരു വിവരണവും (description), ഇഷ്യൂവിന്റെ സ്വഭാവം വ്യക്തമാക്കുന്ന ഒരു കൂട്ടം ലേബലുകളും അടങ്ങിയിരിക്കുന്നതായി നിങ്ങൾ കാണും. താഴെയുള്ള സ്‌ക്രീൻഷോട്ടിൽ ഒരു ഉദാഹരണം കാണിച്ചിരിക്കുന്നു. + +
+🤗 Datasets റെപ്പോസിറ്ററിയിലെ ഒരു സാധാരണ GitHub ഇഷ്യൂ. +
+ +റെപ്പോസിറ്ററിയിലെ എല്ലാ ഇഷ്യൂകളും ഡൗൺലോഡ് ചെയ്യാൻ, നമ്മൾ [GitHub REST API](https://docs.github.com/en/rest) ഉപയോഗിച്ച് [`Issues` എൻഡ്‌പോയിന്റിനെ](https://docs.github.com/en/rest/reference/issues#list-repository-issues) പോൾ ചെയ്യും (poll). ഈ എൻഡ്‌പോയിന്റ് JSON ഒബ്‌ജക്റ്റുകളുടെ ഒരു ലിസ്‌റ്റ് റിട്ടേൺ ചെയ്യുന്നു; ഓരോ ഒബ്‌ജക്റ്റിലും തലക്കെട്ടും വിവരണവും ഉൾപ്പെടെ, ഇഷ്യൂവിന്റെ സ്ഥിതിയെക്കുറിച്ചുള്ള മെറ്റാഡേറ്റ തുടങ്ങിയ ധാരാളം ഫീൽഡുകൾ അടങ്ങിയിരിക്കുന്നു. + +ഇഷ്യൂകൾ ഡൗൺലോഡ് ചെയ്യാനുള്ള സൗകര്യപ്രദമായ ഒരു മാർഗം `requests` ലൈബ്രറി ഉപയോഗിക്കുകയാണ്; Python-ൽ HTTP റിക്വസ്റ്റുകൾ അയയ്ക്കാനുള്ള സ്‌റ്റാൻഡേർഡ് രീതിയാണിത്. താഴെയുള്ള കമാൻഡ് റൺ ചെയ്ത് നിങ്ങൾക്ക് ഈ ലൈബ്രറി ഇൻസ്‌റ്റാൾ ചെയ്യാം: + +```python +!pip install requests +``` + +ലൈബ്രറി ഇൻസ്‌റ്റാൾ ചെയ്തുകഴിഞ്ഞാൽ, `requests.get()` ഫംഗ്‌ഷൻ വിളിച്ച് `Issues` എൻഡ്‌പോയിന്റിലേക്ക് നിങ്ങൾക്ക് GET റിക്വസ്റ്റുകൾ അയയ്ക്കാം. ഉദാഹരണത്തിന്, ആദ്യ പേജിലെ ആദ്യത്തെ ഇഷ്യൂ എടുക്കാൻ താഴെയുള്ള കമാൻഡ് നിങ്ങൾക്ക് റൺ ചെയ്യാം: + +```py +import requests + +url = "https://api.github.com/repos/huggingface/datasets/issues?page=1&per_page=1" +response = requests.get(url) +``` + +`response` ഒബ്‌ജക്റ്റിൽ HTTP സ്‌റ്റാറ്റസ് കോഡ് ഉൾപ്പെടെ, റിക്വസ്റ്റിനെക്കുറിച്ചുള്ള ധാരാളം ഉപകാരപ്രദമായ വിവരങ്ങൾ അടങ്ങിയിരിക്കുന്നു: + +```py +response.status_code +``` + +```python out +200 +``` + +ഇവിടെ `200` എന്ന സ്‌റ്റാറ്റസ്, റിക്വസ്റ്റ് വിജയകരമായിരുന്നു എന്നാണ് അർത്ഥമാക്കുന്നത് (സാധ്യമായ HTTP സ്‌റ്റാറ്റസ് കോഡുകളുടെ ഒരു ലിസ്‌റ്റ് [ഇവിടെ](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes) കാണാം). എന്നാൽ, നമുക്ക് ശരിക്കും താൽപ്പര്യമുള്ളത് _പേലോഡിലാണ്_ (payload); ബൈറ്റുകൾ, സ്‌ട്രിംഗുകൾ, JSON എന്നിങ്ങനെ വിവിധ ഫോർമാറ്റുകളിൽ ഇത് ആക്‌സസ് ചെയ്യാം. നമ്മുടെ ഇഷ്യൂകൾ JSON ഫോർമാറ്റിലാണെന്ന് നമുക്ക് അറിയാവുന്നതിനാൽ, പേലോഡ് താഴെ കാണിച്ചിരിക്കുന്നതുപോലെ പരിശോധിക്കാം: + +```py +response.json() +``` + +```python out +[{'url': 'https://api.github.com/repos/huggingface/datasets/issues/2792', + 'repository_url': 'https://api.github.com/repos/huggingface/datasets', + 'labels_url': 'https://api.github.com/repos/huggingface/datasets/issues/2792/labels{/name}', + 'comments_url': 'https://api.github.com/repos/huggingface/datasets/issues/2792/comments', + 'events_url': 'https://api.github.com/repos/huggingface/datasets/issues/2792/events', + 'html_url': 'https://github.com/huggingface/datasets/pull/2792', + 'id': 968650274, + 'node_id': 'MDExOlB1bGxSZXF1ZXN0NzEwNzUyMjc0', + 'number': 2792, + 'title': 'Update GooAQ', + 'user': {'login': 'bhavitvyamalik', + 'id': 19718818, + 'node_id': 'MDQ6VXNlcjE5NzE4ODE4', + 'avatar_url': 'https://avatars.githubusercontent.com/u/19718818?v=4', + 'gravatar_id': '', + 'url': 'https://api.github.com/users/bhavitvyamalik', + 'html_url': 'https://github.com/bhavitvyamalik', + 'followers_url': 'https://api.github.com/users/bhavitvyamalik/followers', + 'following_url': 'https://api.github.com/users/bhavitvyamalik/following{/other_user}', + 'gists_url': 'https://api.github.com/users/bhavitvyamalik/gists{/gist_id}', + 'starred_url': 'https://api.github.com/users/bhavitvyamalik/starred{/owner}{/repo}', + 'subscriptions_url': 'https://api.github.com/users/bhavitvyamalik/subscriptions', + 'organizations_url': 'https://api.github.com/users/bhavitvyamalik/orgs', + 'repos_url': 'https://api.github.com/users/bhavitvyamalik/repos', + 'events_url': 'https://api.github.com/users/bhavitvyamalik/events{/privacy}', + 'received_events_url': 'https://api.github.com/users/bhavitvyamalik/received_events', + 'type': 'User', + 'site_admin': False}, + 'labels': [], + 'state': 'open', + 'locked': False, + 'assignee': None, + 'assignees': [], + 'milestone': None, + 'comments': 1, + 'created_at': '2021-08-12T11:40:18Z', + 'updated_at': '2021-08-12T12:31:17Z', + 'closed_at': None, + 'author_association': 'CONTRIBUTOR', + 'active_lock_reason': None, + 'pull_request': {'url': 'https://api.github.com/repos/huggingface/datasets/pulls/2792', + 'html_url': 'https://github.com/huggingface/datasets/pull/2792', + 'diff_url': 'https://github.com/huggingface/datasets/pull/2792.diff', + 'patch_url': 'https://github.com/huggingface/datasets/pull/2792.patch'}, + 'body': '[GooAQ](https://github.com/allenai/gooaq) dataset was recently updated after splits were added for the same. This PR contains new updated GooAQ with train/val/test splits and updated README as well.', + 'performed_via_github_app': None}] +``` + +ഹോ, അതൊരുപാട് വിവരങ്ങളാണ്! ഇഷ്യൂവിനെ വിവരിക്കുന്ന `title`, `body`, `number` എന്നിവ പോലുള്ള ഉപകാരപ്രദമായ ഫീൽഡുകളും, ഇഷ്യൂ തുറന്ന GitHub ഉപയോക്താവിനെക്കുറിച്ചുള്ള വിവരങ്ങളും നമുക്ക് കാണാം. + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** ഓരോ GitHub ഇഷ്യൂവും ഏതുതരം വിവരങ്ങളുമായി ബന്ധപ്പെട്ടിരിക്കുന്നു എന്ന് ഒരു ധാരണ കിട്ടാൻ, മുകളിലെ JSON പേലോഡിലെ ഏതാനും URL-കളിൽ ക്ലിക്ക് ചെയ്യുക. + +GitHub [ഡോക്യുമെന്റേഷനിൽ](https://docs.github.com/en/rest/overview/resources-in-the-rest-api#rate-limiting) വിവരിച്ചിരിക്കുന്നതുപോലെ, ഓതന്റിക്കേറ്റ് ചെയ്യാത്ത റിക്വസ്റ്റുകൾ മണിക്കൂറിൽ 60 എണ്ണമായി പരിമിതപ്പെടുത്തിയിരിക്കുന്നു. നിങ്ങൾ അയയ്ക്കുന്ന റിക്വസ്റ്റുകളുടെ എണ്ണം കുറയ്ക്കാൻ `per_page` ക്വറി പാരാമീറ്റർ കൂട്ടാമെങ്കിലും, ഏതാനും ആയിരത്തിലധികം ഇഷ്യൂകളുള്ള ഏതൊരു റെപ്പോസിറ്ററിയിലും നിങ്ങൾ ഈ റേറ്റ് ലിമിറ്റിൽ (rate limit) തട്ടും. അതിനാൽ പകരം, റേറ്റ് ലിമിറ്റ് മണിക്കൂറിൽ 5,000 റിക്വസ്റ്റുകളായി ഉയർത്താൻ കഴിയുന്ന വിധത്തിൽ, ഒരു _പേഴ്‌സണൽ ആക്‌സസ് ടോക്കൺ_ (personal access token) ഉണ്ടാക്കുന്നതിനുള്ള GitHub-ന്റെ [നിർദ്ദേശങ്ങൾ](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token) നിങ്ങൾ പിന്തുടരണം. ടോക്കൺ കിട്ടിക്കഴിഞ്ഞാൽ, റിക്വസ്റ്റ് ഹെഡറിന്റെ ഭാഗമായി അത് നിങ്ങൾക്ക് ഉൾപ്പെടുത്താം: + +```py +GITHUB_TOKEN = xxx # Copy your GitHub token here +headers = {"Authorization": f"token {GITHUB_TOKEN}"} +``` + +> [!WARNING] +> ⚠️ നിങ്ങളുടെ `GITHUB_TOKEN` പേസ്‌റ്റ് ചെയ്തിരിക്കുന്ന ഒരു നോട്ട്‌ബുക്ക് ആരുമായും പങ്കിടരുത്. ഈ വിവരം അബദ്ധത്തിൽ ചോരുന്നത് ഒഴിവാക്കാൻ, അവസാനത്തെ സെൽ എക്‌സിക്യൂട്ട് ചെയ്തുകഴിഞ്ഞാൽ അത് ഡിലീറ്റ് ചെയ്യാൻ ഞങ്ങൾ ശുപാർശ ചെയ്യുന്നു. അതിലും നല്ലത്, ടോക്കൺ ഒരു *.env* ഫയലിൽ സൂക്ഷിക്കുകയും, അത് ഒരു എൻവയോൺമെന്റ് വേരിയബിളായി സ്വയമേവ ലോഡ് ചെയ്യാൻ [`python-dotenv` ലൈബ്രറി](https://github.com/theskumar/python-dotenv) ഉപയോഗിക്കുകയും ചെയ്യുന്നതാണ്. + +ഇപ്പോൾ നമുക്ക് ആക്‌സസ് ടോക്കൺ ഉള്ളതിനാൽ, ഒരു GitHub റെപ്പോസിറ്ററിയിൽ നിന്ന് എല്ലാ ഇഷ്യൂകളും ഡൗൺലോഡ് ചെയ്യാൻ കഴിയുന്ന ഒരു ഫംഗ്‌ഷൻ ഉണ്ടാക്കാം: + +```py +import time +import math +from pathlib import Path +import pandas as pd +from tqdm.notebook import tqdm + + +def fetch_issues( + owner="huggingface", + repo="datasets", + num_issues=10_000, + rate_limit=5_000, + issues_path=Path("."), +): + if not issues_path.is_dir(): + issues_path.mkdir(exist_ok=True) + + batch = [] + all_issues = [] + per_page = 100 # Number of issues to return per page + num_pages = math.ceil(num_issues / per_page) + base_url = "https://api.github.com/repos" + + for page in tqdm(range(num_pages)): + # Query with state=all to get both open and closed issues + query = f"issues?page={page}&per_page={per_page}&state=all" + issues = requests.get(f"{base_url}/{owner}/{repo}/{query}", headers=headers) + batch.extend(issues.json()) + + if len(batch) > rate_limit and len(all_issues) < num_issues: + all_issues.extend(batch) + batch = [] # Flush batch for next time period + print(f"Reached GitHub rate limit. Sleeping for one hour ...") + time.sleep(60 * 60 + 1) + + all_issues.extend(batch) + df = pd.DataFrame.from_records(all_issues) + df.to_json(f"{issues_path}/{repo}-issues.jsonl", orient="records", lines=True) + print( + f"Downloaded all the issues for {repo}! Dataset stored at {issues_path}/{repo}-issues.jsonl" + ) +``` + +ഇപ്പോൾ നമ്മൾ `fetch_issues()` വിളിക്കുമ്പോൾ, മണിക്കൂറിലെ റിക്വസ്റ്റുകളുടെ എണ്ണത്തിൽ GitHub വെച്ചിരിക്കുന്ന പരിധി കവിയാതിരിക്കാൻ അത് എല്ലാ ഇഷ്യൂകളും ബാച്ചുകളായി ഡൗൺലോഡ് ചെയ്യും; ഫലം ഒരു _repository_name-issues.jsonl_ ഫയലിൽ സൂക്ഷിക്കപ്പെടും, അതിലെ ഓരോ വരിയും ഒരു ഇഷ്യൂവിനെ പ്രതിനിധീകരിക്കുന്ന ഒരു JSON ഒബ്‌ജക്റ്റാണ്. 🤗 Datasets-ലെ എല്ലാ ഇഷ്യൂകളും എടുക്കാൻ ഈ ഫംഗ്‌ഷൻ ഉപയോഗിക്കാം: + +```py +# Depending on your internet connection, this can take several minutes to run... +fetch_issues() +``` + +ഇഷ്യൂകൾ ഡൗൺലോഡ് ചെയ്തുകഴിഞ്ഞാൽ, [ഭാഗം 2](/course/chapter5/2)-ൽ നമ്മൾ പുതുതായി പഠിച്ച കഴിവുകൾ ഉപയോഗിച്ച് അവ ലോക്കലായി ലോഡ് ചെയ്യാം: + +```py +issues_dataset = load_dataset("json", data_files="datasets-issues.jsonl", split="train") +issues_dataset +``` + +```python out +Dataset({ + features: ['url', 'repository_url', 'labels_url', 'comments_url', 'events_url', 'html_url', 'id', 'node_id', 'number', 'title', 'user', 'labels', 'state', 'locked', 'assignee', 'assignees', 'milestone', 'comments', 'created_at', 'updated_at', 'closed_at', 'author_association', 'active_lock_reason', 'pull_request', 'body', 'timeline_url', 'performed_via_github_app'], + num_rows: 3019 +}) +``` + +കൊള്ളാം, നമ്മുടെ ആദ്യത്തെ ഡേറ്റാസെറ്റ് നമ്മൾ പൂജ്യത്തിൽ നിന്ന് (from scratch) ഉണ്ടാക്കിയിരിക്കുന്നു! എന്നാൽ 🤗 Datasets റെപ്പോസിറ്ററിയുടെ [Issues ടാബ്](https://github.com/huggingface/datasets/issues) മൊത്തം ഏകദേശം 1,000 ഇഷ്യൂകൾ മാത്രം കാണിക്കുമ്പോൾ, ഇവിടെ എന്തുകൊണ്ടാണ് ആയിരക്കണക്കിന് ഇഷ്യൂകൾ ഉള്ളത് 🤔? GitHub [ഡോക്യുമെന്റേഷനിൽ](https://docs.github.com/en/rest/reference/issues#list-issues-assigned-to-the-authenticated-user) വിവരിച്ചിരിക്കുന്നതുപോലെ, നമ്മൾ എല്ലാ പുൾ റിക്വസ്റ്റുകളും കൂടി ഡൗൺലോഡ് ചെയ്തതുകൊണ്ടാണ് അത്: + +> GitHub-ന്റെ REST API v3 എല്ലാ പുൾ റിക്വസ്റ്റുകളെയും ഇഷ്യൂകളായി കണക്കാക്കുന്നു, എന്നാൽ എല്ലാ ഇഷ്യൂകളും പുൾ റിക്വസ്റ്റുകളല്ല. ഇക്കാരണത്താൽ, "Issues" എൻഡ്‌പോയിന്റുകൾ റെസ്‌പോൺസിൽ ഇഷ്യൂകളും പുൾ റിക്വസ്റ്റുകളും ഒരുപോലെ റിട്ടേൺ ചെയ്യാം. `pull_request` കീ ഉപയോഗിച്ച് നിങ്ങൾക്ക് പുൾ റിക്വസ്റ്റുകളെ തിരിച്ചറിയാം. "Issues" എൻഡ്‌പോയിന്റുകളിൽ നിന്ന് റിട്ടേൺ ചെയ്യുന്ന ഒരു പുൾ റിക്വസ്റ്റിന്റെ `id` ഒരു ഇഷ്യൂ id ആയിരിക്കും എന്നത് ശ്രദ്ധിക്കുക. + +ഇഷ്യൂകളുടെയും പുൾ റിക്വസ്റ്റുകളുടെയും ഉള്ളടക്കം തമ്മിൽ വലിയ വ്യത്യാസമുള്ളതിനാൽ, അവയെ തമ്മിൽ വേർതിരിക്കാൻ നമ്മെ സഹായിക്കുന്ന ചെറിയ ചില പ്രീപ്രോസസ്സിംഗ് നമുക്ക് ചെയ്യാം. + +## ഡേറ്റ വൃത്തിയാക്കുന്നു[[cleaning-up-the-data]] + +ഇഷ്യൂകളും പുൾ റിക്വസ്റ്റുകളും തമ്മിൽ വേർതിരിക്കാൻ `pull_request` കോളം ഉപയോഗിക്കാമെന്ന് GitHub ഡോക്യുമെന്റേഷനിൽ നിന്നുള്ള മുകളിലെ ഭാഗം നമ്മോട് പറയുന്നു. എന്താണ് വ്യത്യാസമെന്ന് കാണാൻ ഒരു റാൻഡം സാമ്പിൾ നോക്കാം. [ഭാഗം 3](/course/chapter5/3)-ൽ ചെയ്തതുപോലെ, ഒരു റാൻഡം സാമ്പിൾ ഉണ്ടാക്കാൻ `Dataset.shuffle()`-ഉം `Dataset.select()`-ഉം ചെയിൻ ചെയ്യുകയും, തുടർന്ന് വിവിധ URL-കൾ താരതമ്യം ചെയ്യാൻ കഴിയുന്ന വിധത്തിൽ `html_url`, `pull_request` കോളങ്ങൾ zip ചെയ്യുകയും ചെയ്യും: + +```py +sample = issues_dataset.shuffle(seed=666).select(range(3)) + +# Print out the URL and pull request entries +for url, pr in zip(sample["html_url"], sample["pull_request"]): + print(f">> URL: {url}") + print(f">> Pull request: {pr}\n") +``` + +```python out +>> URL: https://github.com/huggingface/datasets/pull/850 +>> Pull request: {'url': 'https://api.github.com/repos/huggingface/datasets/pulls/850', 'html_url': 'https://github.com/huggingface/datasets/pull/850', 'diff_url': 'https://github.com/huggingface/datasets/pull/850.diff', 'patch_url': 'https://github.com/huggingface/datasets/pull/850.patch'} + +>> URL: https://github.com/huggingface/datasets/issues/2773 +>> Pull request: None + +>> URL: https://github.com/huggingface/datasets/pull/783 +>> Pull request: {'url': 'https://api.github.com/repos/huggingface/datasets/pulls/783', 'html_url': 'https://github.com/huggingface/datasets/pull/783', 'diff_url': 'https://github.com/huggingface/datasets/pull/783.diff', 'patch_url': 'https://github.com/huggingface/datasets/pull/783.patch'} +``` + +ഓരോ പുൾ റിക്വസ്റ്റും വിവിധ URL-കളുമായി ബന്ധപ്പെട്ടിരിക്കുന്നു, അതേസമയം സാധാരണ ഇഷ്യൂകൾക്ക് ഒരു `None` എൻട്രിയാണുള്ളത് എന്ന് ഇവിടെ നമുക്ക് കാണാം. `pull_request` ഫീൽഡ് `None` ആണോ അല്ലയോ എന്ന് പരിശോധിക്കുന്ന ഒരു പുതിയ `is_pull_request` കോളം ഉണ്ടാക്കാൻ ഈ വ്യത്യാസം നമുക്ക് ഉപയോഗിക്കാം: + +```py +issues_dataset = issues_dataset.map( + lambda x: {"is_pull_request": False if x["pull_request"] is None else True} +) +``` + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** 🤗 Datasets-ലെ ഇഷ്യൂകൾ ക്ലോസ് ചെയ്യാൻ എടുക്കുന്ന ശരാശരി സമയം കണക്കാക്കുക. പുൾ റിക്വസ്റ്റുകളും തുറന്നിരിക്കുന്ന ഇഷ്യൂകളും ഒഴിവാക്കാൻ `Dataset.filter()` ഫംഗ്‌ഷൻ നിങ്ങൾക്ക് ഉപകാരപ്രദമാകും; `created_at`, `closed_at` ടൈംസ്‌റ്റാമ്പുകൾ എളുപ്പത്തിൽ കൈകാര്യം ചെയ്യാൻ കഴിയുന്ന വിധത്തിൽ ഡേറ്റാസെറ്റിനെ ഒരു `DataFrame`-ലേക്ക് മാറ്റാൻ `Dataset.set_format()` ഫംഗ്‌ഷൻ ഉപയോഗിക്കാം. ബോണസ് പോയിന്റുകൾക്കായി, പുൾ റിക്വസ്റ്റുകൾ ക്ലോസ് ചെയ്യാൻ എടുക്കുന്ന ശരാശരി സമയം കണക്കാക്കുക. + +ചില കോളങ്ങൾ ഒഴിവാക്കിയോ പേരുമാറ്റിയോ ഡേറ്റാസെറ്റ് കൂടുതൽ വൃത്തിയാക്കാൻ നമുക്ക് കഴിയുമെങ്കിലും, ഒന്നിലധികം ആപ്ലിക്കേഷനുകളിൽ എളുപ്പത്തിൽ ഉപയോഗിക്കാൻ കഴിയുന്ന വിധത്തിൽ, ഈ ഘട്ടത്തിൽ ഡേറ്റാസെറ്റ് കഴിയുന്നത്ര "റോ" (raw) ആയി സൂക്ഷിക്കുന്നതാണ് പൊതുവെ നല്ല രീതി. + +നമ്മുടെ ഡേറ്റാസെറ്റ് Hugging Face Hub-ലേക്ക് പുഷ് ചെയ്യുന്നതിന് മുമ്പ്, അതിൽ ഇല്ലാത്ത ഒരു കാര്യം നമുക്ക് പരിഹരിക്കാം: ഓരോ ഇഷ്യൂവുമായും പുൾ റിക്വസ്റ്റുമായും ബന്ധപ്പെട്ട കമന്റുകൾ. അടുത്തതായി അവ നമ്മൾ ചേർക്കും -- നിങ്ങൾ ഊഹിച്ചതുപോലെ -- GitHub REST API ഉപയോഗിച്ച്! + +## ഡേറ്റാസെറ്റ് വിപുലീകരിക്കുന്നു[[augmenting-the-dataset]] + +താഴെയുള്ള സ്‌ക്രീൻഷോട്ടിൽ കാണിച്ചിരിക്കുന്നതുപോലെ, ഒരു ഇഷ്യൂവുമായോ പുൾ റിക്വസ്റ്റുമായോ ബന്ധപ്പെട്ട കമന്റുകൾ വിവരങ്ങളുടെ ഒരു സമ്പന്നമായ ഉറവിടമാണ്; ലൈബ്രറിയെക്കുറിച്ചുള്ള ഉപയോക്താക്കളുടെ ചോദ്യങ്ങൾക്ക് ഉത്തരം നൽകുന്ന ഒരു സെർച്ച് എഞ്ചിൻ നിർമ്മിക്കാനാണ് നമുക്ക് താൽപ്പര്യമെങ്കിൽ പ്രത്യേകിച്ചും. + +
+🤗 Datasets-നെക്കുറിച്ചുള്ള ഒരു ഇഷ്യൂവുമായി ബന്ധപ്പെട്ട കമന്റുകൾ. +
+ +ഒരു ഇഷ്യൂ നമ്പറുമായി ബന്ധപ്പെട്ട എല്ലാ കമന്റുകളും റിട്ടേൺ ചെയ്യുന്ന ഒരു [`Comments` എൻഡ്‌പോയിന്റ്](https://docs.github.com/en/rest/reference/issues#list-issue-comments) GitHub REST API നൽകുന്നു. അത് എന്താണ് റിട്ടേൺ ചെയ്യുന്നതെന്ന് കാണാൻ ഈ എൻഡ്‌പോയിന്റ് ടെസ്‌റ്റ് ചെയ്യാം: + +```py +issue_number = 2792 +url = f"https://api.github.com/repos/huggingface/datasets/issues/{issue_number}/comments" +response = requests.get(url, headers=headers) +response.json() +``` + +```python out +[{'url': 'https://api.github.com/repos/huggingface/datasets/issues/comments/897594128', + 'html_url': 'https://github.com/huggingface/datasets/pull/2792#issuecomment-897594128', + 'issue_url': 'https://api.github.com/repos/huggingface/datasets/issues/2792', + 'id': 897594128, + 'node_id': 'IC_kwDODunzps41gDMQ', + 'user': {'login': 'bhavitvyamalik', + 'id': 19718818, + 'node_id': 'MDQ6VXNlcjE5NzE4ODE4', + 'avatar_url': 'https://avatars.githubusercontent.com/u/19718818?v=4', + 'gravatar_id': '', + 'url': 'https://api.github.com/users/bhavitvyamalik', + 'html_url': 'https://github.com/bhavitvyamalik', + 'followers_url': 'https://api.github.com/users/bhavitvyamalik/followers', + 'following_url': 'https://api.github.com/users/bhavitvyamalik/following{/other_user}', + 'gists_url': 'https://api.github.com/users/bhavitvyamalik/gists{/gist_id}', + 'starred_url': 'https://api.github.com/users/bhavitvyamalik/starred{/owner}{/repo}', + 'subscriptions_url': 'https://api.github.com/users/bhavitvyamalik/subscriptions', + 'organizations_url': 'https://api.github.com/users/bhavitvyamalik/orgs', + 'repos_url': 'https://api.github.com/users/bhavitvyamalik/repos', + 'events_url': 'https://api.github.com/users/bhavitvyamalik/events{/privacy}', + 'received_events_url': 'https://api.github.com/users/bhavitvyamalik/received_events', + 'type': 'User', + 'site_admin': False}, + 'created_at': '2021-08-12T12:21:52Z', + 'updated_at': '2021-08-12T12:31:17Z', + 'author_association': 'CONTRIBUTOR', + 'body': "@albertvillanova my tests are failing here:\r\n```\r\ndataset_name = 'gooaq'\r\n\r\n def test_load_dataset(self, dataset_name):\r\n configs = self.dataset_tester.load_all_configs(dataset_name, is_local=True)[:1]\r\n> self.dataset_tester.check_load_dataset(dataset_name, configs, is_local=True, use_local_dummy_data=True)\r\n\r\ntests/test_dataset_common.py:234: \r\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \r\ntests/test_dataset_common.py:187: in check_load_dataset\r\n self.parent.assertTrue(len(dataset[split]) > 0)\r\nE AssertionError: False is not true\r\n```\r\nWhen I try loading dataset on local machine it works fine. Any suggestions on how can I avoid this error?", + 'performed_via_github_app': None}] +``` + +കമന്റ് `body` ഫീൽഡിലാണ് സൂക്ഷിച്ചിരിക്കുന്നതെന്ന് നമുക്ക് കാണാം; അതിനാൽ `response.json()`-ലെ ഓരോ എലമെന്റിന്റെയും `body` ഉള്ളടക്കം എടുത്ത്, ഒരു ഇഷ്യൂവുമായി ബന്ധപ്പെട്ട എല്ലാ കമന്റുകളും റിട്ടേൺ ചെയ്യുന്ന ഒരു ലളിതമായ ഫംഗ്‌ഷൻ എഴുതാം: + +```py +def get_comments(issue_number): + url = f"https://api.github.com/repos/huggingface/datasets/issues/{issue_number}/comments" + response = requests.get(url, headers=headers) + return [r["body"] for r in response.json()] + + +# Test our function works as expected +get_comments(2792) +``` + +```python out +["@albertvillanova my tests are failing here:\r\n```\r\ndataset_name = 'gooaq'\r\n\r\n def test_load_dataset(self, dataset_name):\r\n configs = self.dataset_tester.load_all_configs(dataset_name, is_local=True)[:1]\r\n> self.dataset_tester.check_load_dataset(dataset_name, configs, is_local=True, use_local_dummy_data=True)\r\n\r\ntests/test_dataset_common.py:234: \r\n_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ \r\ntests/test_dataset_common.py:187: in check_load_dataset\r\n self.parent.assertTrue(len(dataset[split]) > 0)\r\nE AssertionError: False is not true\r\n```\r\nWhen I try loading dataset on local machine it works fine. Any suggestions on how can I avoid this error?"] +``` + +ഇത് നന്നായി തോന്നുന്നു; അതിനാൽ നമ്മുടെ ഡേറ്റാസെറ്റിലെ ഓരോ ഇഷ്യൂവിനും ഒരു പുതിയ `comments` കോളം ചേർക്കാൻ `Dataset.map()` ഉപയോഗിക്കാം: + +```py +# Depending on your internet connection, this can take a few minutes... +issues_with_comments_dataset = issues_dataset.map( + lambda x: {"comments": get_comments(x["number"])} +) +``` + +അവസാന ഘട്ടം നമ്മുടെ ഡേറ്റാസെറ്റ് Hub-ലേക്ക് പുഷ് ചെയ്യുകയാണ്. അത് എങ്ങനെ ചെയ്യാമെന്ന് നോക്കാം. + +## ഡേറ്റാസെറ്റ് Hugging Face Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യുന്നു[[uploading-the-dataset-to-the-hugging-face-hub]] + + + +ഇപ്പോൾ നമ്മുടെ വിപുലീകരിച്ച ഡേറ്റാസെറ്റ് തയ്യാറായതിനാൽ, കമ്മ്യൂണിറ്റിയുമായി പങ്കിടാൻ അത് Hub-ലേക്ക് പുഷ് ചെയ്യാനുള്ള സമയമായി! ഒരു ഡേറ്റാസെറ്റ് അപ്‌ലോഡ് ചെയ്യുന്നത് വളരെ ലളിതമാണ്: 🤗 Transformers-ലെ മോഡലുകളും ടോക്കണൈസറുകളും പോലെ തന്നെ, ഒരു ഡേറ്റാസെറ്റ് പുഷ് ചെയ്യാൻ `push_to_hub()` മെത്തേഡ് നമുക്ക് ഉപയോഗിക്കാം. അതിനായി നമുക്ക് ഒരു ഓതന്റിക്കേഷൻ ടോക്കൺ ആവശ്യമാണ്; `notebook_login()` ഫംഗ്‌ഷൻ ഉപയോഗിച്ച് ആദ്യം Hugging Face Hub-ൽ ലോഗിൻ ചെയ്താൽ അത് ലഭിക്കും: + +```py +from huggingface_hub import notebook_login + +notebook_login() +``` + +നിങ്ങളുടെ യൂസർനെയിമും പാസ്‌വേഡും നൽകാൻ കഴിയുന്ന ഒരു വിഡ്‌ജറ്റ് ഇത് ഉണ്ടാക്കും, ഒരു API ടോക്കൺ *~/.huggingface/token*-ൽ സേവ് ചെയ്യപ്പെടും. നിങ്ങൾ കോഡ് ഒരു ടെർമിനലിലാണ് റൺ ചെയ്യുന്നതെങ്കിൽ, പകരം CLI വഴി ലോഗിൻ ചെയ്യാം: + +```bash +huggingface-cli login +``` + +ഇത് ചെയ്തുകഴിഞ്ഞാൽ, താഴെയുള്ളത് റൺ ചെയ്ത് നമ്മുടെ ഡേറ്റാസെറ്റ് അപ്‌ലോഡ് ചെയ്യാം: + +```py +issues_with_comments_dataset.push_to_hub("github-issues") +``` + +ഇനി മുതൽ, `load_dataset()`-ന് റെപ്പോസിറ്ററി ID `path` ആർഗ്യുമെന്റായി നൽകിയാൽ മാത്രം മതി, ആർക്കും ഈ ഡേറ്റാസെറ്റ് ഡൗൺലോഡ് ചെയ്യാം: + +```py +remote_dataset = load_dataset("lewtun/github-issues", split="train") +remote_dataset +``` + +```python out +Dataset({ + features: ['url', 'repository_url', 'labels_url', 'comments_url', 'events_url', 'html_url', 'id', 'node_id', 'number', 'title', 'user', 'labels', 'state', 'locked', 'assignee', 'assignees', 'milestone', 'comments', 'created_at', 'updated_at', 'closed_at', 'author_association', 'active_lock_reason', 'pull_request', 'body', 'performed_via_github_app', 'is_pull_request'], + num_rows: 2855 +}) +``` + +കൊള്ളാം, നമ്മുടെ ഡേറ്റാസെറ്റ് നമ്മൾ Hub-ലേക്ക് പുഷ് ചെയ്തു, ഇപ്പോൾ അത് മറ്റുള്ളവർക്ക് ഉപയോഗിക്കാൻ ലഭ്യമാണ്! ഇനി ചെയ്യാൻ ബാക്കിയുള്ളത് ഒരു പ്രധാന കാര്യം മാത്രമാണ്: കോർപ്പസ് എങ്ങനെ ഉണ്ടാക്കിയെന്ന് വിശദീകരിക്കുകയും കമ്മ്യൂണിറ്റിക്ക് ഉപകാരപ്രദമായ മറ്റ് വിവരങ്ങൾ നൽകുകയും ചെയ്യുന്ന ഒരു _ഡേറ്റാസെറ്റ് കാർഡ്_ (dataset card) ചേർക്കുക. + +> [!TIP] +> 💡 `huggingface-cli`-യും കുറച്ച് Git മാജിക്കും ഉപയോഗിച്ച് ടെർമിനലിൽ നിന്ന് നേരിട്ടും നിങ്ങൾക്ക് ഒരു ഡേറ്റാസെറ്റ് Hugging Face Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യാം. ഇത് എങ്ങനെ ചെയ്യാമെന്നതിന്റെ വിശദാംശങ്ങൾക്ക് [🤗 Datasets ഗൈഡ്](https://huggingface.co/docs/datasets/share#share-a-dataset-using-the-cli) കാണുക. + +## ഒരു ഡേറ്റാസെറ്റ് കാർഡ് ഉണ്ടാക്കുന്നു[[creating-a-dataset-card]] + +നന്നായി ഡോക്യുമെന്റ് ചെയ്ത ഡേറ്റാസെറ്റുകൾ മറ്റുള്ളവർക്ക് (ഭാവിയിലെ നിങ്ങൾക്കും ഉൾപ്പെടെ!) ഉപകാരപ്രദമാകാൻ കൂടുതൽ സാധ്യതയുണ്ട്; കാരണം, ഡേറ്റാസെറ്റ് തങ്ങളുടെ ടാസ്‌ക്കിന് പ്രസക്തമാണോ എന്ന് തീരുമാനിക്കാനും, ഡേറ്റാസെറ്റിലെ സാധ്യമായ പക്ഷപാതങ്ങളോ (biases) അത് ഉപയോഗിക്കുന്നതുമായി ബന്ധപ്പെട്ട അപകടസാധ്യതകളോ വിലയിരുത്താനും ഉപയോക്താക്കളെ പ്രാപ്തരാക്കുന്ന സന്ദർഭം (context) അവ നൽകുന്നു. + +Hugging Face Hub-ൽ, ഈ വിവരങ്ങൾ ഓരോ ഡേറ്റാസെറ്റ് റെപ്പോസിറ്ററിയുടെയും *README.md* ഫയലിലാണ് സൂക്ഷിക്കുന്നത്. ഈ ഫയൽ ഉണ്ടാക്കുന്നതിന് മുമ്പ് നിങ്ങൾ ചെയ്യേണ്ട രണ്ട് പ്രധാന ഘട്ടങ്ങളുണ്ട്: + +1. YAML ഫോർമാറ്റിൽ മെറ്റാഡേറ്റ ടാഗുകൾ ഉണ്ടാക്കാൻ [`datasets-tagging` ആപ്ലിക്കേഷൻ](https://huggingface.co/datasets/tagging/) ഉപയോഗിക്കുക. Hugging Face Hub-ലെ വിവിധ സെർച്ച് ഫീച്ചറുകൾക്കായി ഈ ടാഗുകൾ ഉപയോഗിക്കുന്നു; കമ്മ്യൂണിറ്റിയിലെ അംഗങ്ങൾക്ക് നിങ്ങളുടെ ഡേറ്റാസെറ്റ് എളുപ്പത്തിൽ കണ്ടെത്താൻ കഴിയുമെന്ന് അവ ഉറപ്പാക്കുന്നു. ഇവിടെ നമ്മൾ ഒരു കസ്‌റ്റം ഡേറ്റാസെറ്റ് ഉണ്ടാക്കിയതിനാൽ, `datasets-tagging` റെപ്പോസിറ്ററി ക്ലോൺ ചെയ്ത് ആപ്ലിക്കേഷൻ ലോക്കലായി റൺ ചെയ്യേണ്ടിവരും. ഇന്റർഫേസ് കാണുന്നത് ഇങ്ങനെയാണ്: + +
+`datasets-tagging` ഇന്റർഫേസ്. +
+ +2. വിവരസമ്പന്നമായ ഡേറ്റാസെറ്റ് കാർഡുകൾ ഉണ്ടാക്കുന്നതിനെക്കുറിച്ചുള്ള [🤗 Datasets ഗൈഡ്](https://github.com/huggingface/datasets/blob/master/templates/README_guide.md) വായിക്കുകയും അത് ഒരു ടെംപ്ലേറ്റായി ഉപയോഗിക്കുകയും ചെയ്യുക. + +*README.md* ഫയൽ നിങ്ങൾക്ക് Hub-ൽ നേരിട്ട് ഉണ്ടാക്കാം; `lewtun/github-issues` ഡേറ്റാസെറ്റ് റെപ്പോസിറ്ററിയിൽ ഒരു ടെംപ്ലേറ്റ് ഡേറ്റാസെറ്റ് കാർഡ് നിങ്ങൾക്ക് കാണാം. പൂരിപ്പിച്ച ഡേറ്റാസെറ്റ് കാർഡിന്റെ ഒരു സ്‌ക്രീൻഷോട്ട് താഴെ കാണിച്ചിരിക്കുന്നു. + +
+ഒരു ഡേറ്റാസെറ്റ് കാർഡ്. +
+ +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** നിങ്ങളുടെ GitHub ഇഷ്യൂസ് ഡേറ്റാസെറ്റിനുള്ള *README.md* ഫയൽ പൂർത്തിയാക്കാൻ `dataset-tagging` ആപ്ലിക്കേഷനും [🤗 Datasets ഗൈഡും](https://github.com/huggingface/datasets/blob/master/templates/README_guide.md) ഉപയോഗിക്കുക. + +അത്രമാത്രം! ഒരു നല്ല ഡേറ്റാസെറ്റ് ഉണ്ടാക്കുന്നത് കുറച്ച് ശ്രമകരമായ കാര്യമാകാമെന്ന് ഈ ഭാഗത്തിൽ നമ്മൾ കണ്ടു; എന്നാൽ ഭാഗ്യവശാൽ, അത് അപ്‌ലോഡ് ചെയ്യുന്നതും കമ്മ്യൂണിറ്റിയുമായി പങ്കിടുന്നതും അങ്ങനെയല്ല. അടുത്ത ഭാഗത്തിൽ, ചോദ്യങ്ങളെ ഏറ്റവും പ്രസക്തമായ ഇഷ്യൂകളുമായും കമന്റുകളുമായും പൊരുത്തപ്പെടുത്താൻ കഴിയുന്ന ഒരു സെമാന്റിക് സെർച്ച് എഞ്ചിൻ 🤗 Datasets ഉപയോഗിച്ച് നിർമ്മിക്കാൻ നമ്മുടെ പുതിയ ഡേറ്റാസെറ്റ് നമ്മൾ ഉപയോഗിക്കും. + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** നിങ്ങളുടെ ഇഷ്ടപ്പെട്ട ഓപ്പൺ സോഴ്‌സ് ലൈബ്രറിയുടെ GitHub ഇഷ്യൂകളുടെ ഒരു ഡേറ്റാസെറ്റ് ഉണ്ടാക്കാൻ ഈ ഭാഗത്തിൽ നമ്മൾ ചെയ്ത ഘട്ടങ്ങൾ പിന്തുടരുക (തീർച്ചയായും, 🤗 Datasets അല്ലാത്ത മറ്റെന്തെങ്കിലും തിരഞ്ഞെടുക്കുക!). ബോണസ് പോയിന്റുകൾക്കായി, `labels` ഫീൽഡിലുള്ള ടാഗുകൾ പ്രവചിക്കാൻ ഒരു മൾട്ടിലേബൽ ക്ലാസിഫയർ ഫൈൻ-ട്യൂൻ ചെയ്യുക. + + diff --git a/chapters/ml/chapter5/6.mdx b/chapters/ml/chapter5/6.mdx new file mode 100644 index 000000000..94663aa03 --- /dev/null +++ b/chapters/ml/chapter5/6.mdx @@ -0,0 +1,512 @@ + + +# FAISS ഉപയോഗിച്ചുള്ള സെമാന്റിക് സെർച്ച്[[semantic-search-with-faiss]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +[ഭാഗം 5](/course/chapter5/5)-ൽ, 🤗 Datasets റിപ്പോസിറ്ററിയിലെ GitHub ഇഷ്യൂകളുടെയും കമന്റുകളുടെയും ഒരു ഡേറ്റാസെറ്റ് നമ്മൾ നിർമ്മിച്ചു. ഈ ഭാഗത്തിൽ, ഈ ലൈബ്രറിയെക്കുറിച്ചുള്ള നമ്മുടെ ഏറ്റവും അടിയന്തരമായ ചോദ്യങ്ങൾക്ക് ഉത്തരം കണ്ടെത്താൻ സഹായിക്കുന്ന ഒരു സെർച്ച് എഞ്ചിൻ നിർമ്മിക്കാൻ ഈ വിവരങ്ങൾ നമ്മൾ ഉപയോഗിക്കും! + + + +## സെമാന്റിക് സെർച്ചിനായി എംബെഡ്ഡിംഗുകൾ ഉപയോഗിക്കുന്നു[[using-embeddings-for-semantic-search]] + +[അധ്യായം 1](/course/chapter1)-ൽ നമ്മൾ കണ്ടതുപോലെ, Transformer അടിസ്ഥാനമാക്കിയ ലാംഗ്വേജ് മോഡലുകൾ ഒരു ടെക്‌സ്‌റ്റ് ഭാഗത്തിലെ ഓരോ ടോക്കണിനെയും ഒരു _എംബെഡ്ഡിംഗ് വെക്റ്റർ_ (embedding vector) ആയി പ്രതിനിധീകരിക്കുന്നു. ഈ വ്യക്തിഗത എംബെഡ്ഡിംഗുകളെ "പൂൾ" (pool) ചെയ്ത്, മുഴുവൻ വാക്യങ്ങൾക്കും, പാരഗ്രാഫുകൾക്കും, അല്ലെങ്കിൽ (ചില സന്ദർഭങ്ങളിൽ) ഡോക്യുമെന്റുകൾക്കും ഒരു വെക്റ്റർ പ്രാതിനിധ്യം (vector representation) ഉണ്ടാക്കാൻ കഴിയുമെന്ന് തെളിഞ്ഞിട്ടുണ്ട്. ഓരോ എംബെഡ്ഡിംഗിനും ഇടയിലുള്ള ഡോട്ട്-പ്രോഡക്റ്റ് സാമ്യം (dot-product similarity) (അല്ലെങ്കിൽ മറ്റേതെങ്കിലും സാമ്യ മെട്രിക്) കണക്കാക്കി, ഏറ്റവും കൂടുതൽ ഓവർലാപ്പ് ഉള്ള ഡോക്യുമെന്റുകൾ റിട്ടേൺ ചെയ്തുകൊണ്ട്, കോർപ്പസിലെ സമാനമായ ഡോക്യുമെന്റുകൾ കണ്ടെത്താൻ ഈ എംബെഡ്ഡിംഗുകൾ പിന്നീട് ഉപയോഗിക്കാം. + +ഈ ഭാഗത്തിൽ, ഒരു സെമാന്റിക് സെർച്ച് എഞ്ചിൻ (semantic search engine) വികസിപ്പിക്കാൻ നമ്മൾ എംബെഡ്ഡിംഗുകൾ ഉപയോഗിക്കും. ഒരു ക്വറിയിലെ കീവേഡുകളെ ഡോക്യുമെന്റുകളുമായി പൊരുത്തപ്പെടുത്തുന്നതിനെ അടിസ്ഥാനമാക്കിയ പരമ്പരാഗത രീതികളെ അപേക്ഷിച്ച് ഈ സെർച്ച് എഞ്ചിനുകൾക്ക് നിരവധി മേന്മകളുണ്ട്. + +
+സെമാന്റിക് സെർച്ച്. + +
+ +## ഡേറ്റാസെറ്റ് ലോഡ് ചെയ്യുകയും തയ്യാറാക്കുകയും ചെയ്യുന്നു[[loading-and-preparing-the-dataset]] + +GitHub ഇഷ്യൂകളുടെ നമ്മുടെ ഡേറ്റാസെറ്റ് ഡൗൺലോഡ് ചെയ്യുകയാണ് ആദ്യം ചെയ്യേണ്ടത്; അതിനാൽ പതിവുപോലെ `load_dataset()` ഫംഗ്‌ഷൻ ഉപയോഗിക്കാം: + +```py +from datasets import load_dataset + +issues_dataset = load_dataset("lewtun/github-issues", split="train") +issues_dataset +``` + +```python out +Dataset({ + features: ['url', 'repository_url', 'labels_url', 'comments_url', 'events_url', 'html_url', 'id', 'node_id', 'number', 'title', 'user', 'labels', 'state', 'locked', 'assignee', 'assignees', 'milestone', 'comments', 'created_at', 'updated_at', 'closed_at', 'author_association', 'active_lock_reason', 'pull_request', 'body', 'performed_via_github_app', 'is_pull_request'], + num_rows: 2855 +}) +``` + +ഇവിടെ `load_dataset()`-ൽ ഡിഫോൾട്ട് `train` സ്‌പ്ലിറ്റ് നമ്മൾ വ്യക്തമാക്കിയിട്ടുണ്ട്, അതിനാൽ ഇത് ഒരു `DatasetDict`-ന് പകരം ഒരു `Dataset` റിട്ടേൺ ചെയ്യുന്നു. ആദ്യം ചെയ്യേണ്ട കാര്യം പുൾ റിക്വസ്‌റ്റുകൾ ഫിൽറ്റർ ചെയ്ത് ഒഴിവാക്കുകയാണ്, കാരണം ഉപയോക്താക്കളുടെ ചോദ്യങ്ങൾക്ക് ഉത്തരം നൽകാൻ ഇവ വളരെ അപൂർവമായി മാത്രമേ ഉപയോഗിക്കപ്പെടാറുള്ളൂ, കൂടാതെ ഇവ നമ്മുടെ സെർച്ച് എഞ്ചിനിൽ നോയ്‌സ് (noise) ഉണ്ടാക്കുകയും ചെയ്യും. ഇപ്പോൾ നിങ്ങൾക്ക് പരിചിതമായിരിക്കേണ്ടതുപോലെ, നമ്മുടെ ഡേറ്റാസെറ്റിലെ ഈ വരികൾ ഒഴിവാക്കാൻ `Dataset.filter()` ഫംഗ്‌ഷൻ ഉപയോഗിക്കാം. ഇതിനൊപ്പം, കമന്റുകളില്ലാത്ത വരികളും ഫിൽറ്റർ ചെയ്ത് ഒഴിവാക്കാം, കാരണം അവ ഉപയോക്താക്കളുടെ ചോദ്യങ്ങൾക്ക് ഉത്തരങ്ങളൊന്നും നൽകുന്നില്ല: + +```py +issues_dataset = issues_dataset.filter( + lambda x: (x["is_pull_request"] == False and len(x["comments"]) > 0) +) +issues_dataset +``` + +```python out +Dataset({ + features: ['url', 'repository_url', 'labels_url', 'comments_url', 'events_url', 'html_url', 'id', 'node_id', 'number', 'title', 'user', 'labels', 'state', 'locked', 'assignee', 'assignees', 'milestone', 'comments', 'created_at', 'updated_at', 'closed_at', 'author_association', 'active_lock_reason', 'pull_request', 'body', 'performed_via_github_app', 'is_pull_request'], + num_rows: 771 +}) +``` + +നമ്മുടെ ഡേറ്റാസെറ്റിൽ ധാരാളം കോളങ്ങൾ ഉണ്ടെന്ന് നമുക്ക് കാണാം; അവയിൽ മിക്കതും നമ്മുടെ സെർച്ച് എഞ്ചിൻ നിർമ്മിക്കാൻ ആവശ്യമില്ല. സെർച്ചിന്റെ കാഴ്ചപ്പാടിൽ, ഏറ്റവും കൂടുതൽ വിവരങ്ങൾ നൽകുന്ന കോളങ്ങൾ `title`, `body`, `comments` എന്നിവയാണ്; അതേസമയം `html_url` നമുക്ക് ഉറവിട ഇഷ്യൂവിലേക്കുള്ള ഒരു ലിങ്ക് നൽകുന്നു. ബാക്കിയുള്ളവ ഒഴിവാക്കാൻ `Dataset.remove_columns()` ഫംഗ്‌ഷൻ ഉപയോഗിക്കാം: + +```py +columns = issues_dataset.column_names +columns_to_keep = ["title", "body", "html_url", "comments"] +columns_to_remove = set(columns_to_keep).symmetric_difference(columns) +issues_dataset = issues_dataset.remove_columns(columns_to_remove) +issues_dataset +``` + +```python out +Dataset({ + features: ['html_url', 'title', 'comments', 'body'], + num_rows: 771 +}) +``` + +നമ്മുടെ എംബെഡ്ഡിംഗുകൾ ഉണ്ടാക്കാൻ, ഓരോ കമന്റിനോടും ഇഷ്യൂവിന്റെ ടൈറ്റിലും ബോഡിയും നമ്മൾ കൂട്ടിച്ചേർക്കും, കാരണം ഈ ഫീൽഡുകളിൽ പലപ്പോഴും ഉപകാരപ്രദമായ സന്ദർഭ വിവരങ്ങൾ (contextual information) ഉൾപ്പെടുന്നു. നമ്മുടെ `comments` കോളം ഇപ്പോൾ ഓരോ ഇഷ്യൂവിനുമുള്ള കമന്റുകളുടെ ഒരു ലിസ്‌റ്റായതിനാൽ, ഓരോ വരിയും ഒരു `(html_url, title, body, comment)` ട്യൂപ്പിൾ ആയിരിക്കുന്ന വിധത്തിൽ ഈ കോളം നമ്മൾ "എക്‌സ്‌പ്ലോഡ്" (explode) ചെയ്യേണ്ടതുണ്ട്. Pandas-ൽ ഇത് [`DataFrame.explode()` ഫംഗ്‌ഷൻ](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.explode.html) ഉപയോഗിച്ച് ചെയ്യാം; ലിസ്‌റ്റ് പോലുള്ള ഒരു കോളത്തിലെ ഓരോ എലമെന്റിനും ഇത് ഒരു പുതിയ വരി ഉണ്ടാക്കുന്നു, അതേസമയം മറ്റെല്ലാ കോളങ്ങളുടെയും മൂല്യങ്ങൾ അതേപടി ആവർത്തിക്കുന്നു. ഇത് പ്രവർത്തിക്കുന്നത് കാണാൻ, ആദ്യം Pandas `DataFrame` ഫോർമാറ്റിലേക്ക് മാറാം: + +```py +issues_dataset.set_format("pandas") +df = issues_dataset[:] +``` + +ഈ `DataFrame`-ലെ ആദ്യ വരി പരിശോധിച്ചാൽ, ഈ ഇഷ്യൂവുമായി ബന്ധപ്പെട്ട് നാല് കമന്റുകൾ ഉണ്ടെന്ന് നമുക്ക് കാണാം: + +```py +df["comments"][0].tolist() +``` + +```python out +['the bug code locate in :\r\n if data_args.task_name is not None:\r\n # Downloading and loading a dataset from the hub.\r\n datasets = load_dataset("glue", data_args.task_name, cache_dir=model_args.cache_dir)', + 'Hi @jinec,\r\n\r\nFrom time to time we get this kind of `ConnectionError` coming from the github.com website: https://raw.githubusercontent.com\r\n\r\nNormally, it should work if you wait a little and then retry.\r\n\r\nCould you please confirm if the problem persists?', + 'cannot connect,even by Web browser,please check that there is some problems。', + 'I can access https://raw.githubusercontent.com/huggingface/datasets/1.7.0/datasets/glue/glue.py without problem...'] +``` + +`df` എക്‌സ്‌പ്ലോഡ് ചെയ്യുമ്പോൾ, ഈ കമന്റുകൾ ഓരോന്നിനും ഒരു വരി വീതം ലഭിക്കുമെന്ന് നമ്മൾ പ്രതീക്ഷിക്കുന്നു. അങ്ങനെയാണോ എന്ന് പരിശോധിക്കാം: + +```py +comments_df = df.explode("comments", ignore_index=True) +comments_df.head(4) +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
html_urltitlecommentsbody
0https://github.com/huggingface/datasets/issues/2787ConnectionError: Couldn't reach https://raw.githubusercontent.comthe bug code locate in :\r\n if data_args.task_name is not None...Hello,\r\nI am trying to run run_glue.py and it gives me this error...
1https://github.com/huggingface/datasets/issues/2787ConnectionError: Couldn't reach https://raw.githubusercontent.comHi @jinec,\r\n\r\nFrom time to time we get this kind of `ConnectionError` coming from the github.com website: https://raw.githubusercontent.com...Hello,\r\nI am trying to run run_glue.py and it gives me this error...
2https://github.com/huggingface/datasets/issues/2787ConnectionError: Couldn't reach https://raw.githubusercontent.comcannot connect,even by Web browser,please check that there is some problems。Hello,\r\nI am trying to run run_glue.py and it gives me this error...
3https://github.com/huggingface/datasets/issues/2787ConnectionError: Couldn't reach https://raw.githubusercontent.comI can access https://raw.githubusercontent.com/huggingface/datasets/1.7.0/datasets/glue/glue.py without problem...Hello,\r\nI am trying to run run_glue.py and it gives me this error...
+ +കൊള്ളാം, വരികൾ ആവർത്തിക്കപ്പെട്ടിരിക്കുന്നതും `comments` കോളത്തിൽ ഓരോ കമന്റും വെവ്വേറെ ഉള്ളതും നമുക്ക് കാണാം! Pandas-ലെ പണി കഴിഞ്ഞതിനാൽ, `DataFrame` മെമ്മറിയിൽ ലോഡ് ചെയ്തുകൊണ്ട് വേഗത്തിൽ ഒരു `Dataset`-ലേക്ക് തിരികെ മാറാം: + +```py +from datasets import Dataset + +comments_dataset = Dataset.from_pandas(comments_df) +comments_dataset +``` + +```python out +Dataset({ + features: ['html_url', 'title', 'comments', 'body'], + num_rows: 2842 +}) +``` + +ശരി, ഇത് നമുക്ക് പ്രവർത്തിക്കാൻ ഏതാനും ആയിരം കമന്റുകൾ നൽകിയിരിക്കുന്നു! + + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** Pandas _ഉപയോഗിക്കാതെ_, `issues_dataset`-ന്റെ `comments` കോളം എക്‌സ്‌പ്ലോഡ് ചെയ്യാൻ `Dataset.map()` ഉപയോഗിക്കാൻ കഴിയുമോ എന്ന് നോക്കുക. ഇത് കുറച്ച് ബുദ്ധിമുട്ടുള്ളതാണ്; ഈ ടാസ്‌ക്കിന് 🤗 Datasets ഡോക്യുമെന്റേഷനിലെ ["Batch mapping"](https://huggingface.co/docs/datasets/about_map_batch#batch-mapping) വിഭാഗം നിങ്ങൾക്ക് ഉപകാരപ്രദമായേക്കാം. + +ഇപ്പോൾ ഓരോ വരിയിലും ഒരു കമന്റ് വീതം ഉള്ളതിനാൽ, ഓരോ കമന്റിലെയും വാക്കുകളുടെ എണ്ണം ഉൾക്കൊള്ളുന്ന ഒരു പുതിയ `comments_length` കോളം ഉണ്ടാക്കാം: + +```py +comments_dataset = comments_dataset.map( + lambda x: {"comment_length": len(x["comments"].split())} +) +``` + +ചെറിയ കമന്റുകൾ ഫിൽറ്റർ ചെയ്ത് ഒഴിവാക്കാൻ ഈ പുതിയ കോളം നമുക്ക് ഉപയോഗിക്കാം; ഇവയിൽ സാധാരണയായി "cc @lewtun" അല്ലെങ്കിൽ "Thanks!" പോലുള്ള, നമ്മുടെ സെർച്ച് എഞ്ചിന് പ്രസക്തമല്ലാത്ത കാര്യങ്ങളാണ് ഉണ്ടാകാറുള്ളത്. ഫിൽറ്ററിനായി തിരഞ്ഞെടുക്കാൻ കൃത്യമായ ഒരു സംഖ്യയില്ല, എന്നാൽ ഏകദേശം 15 വാക്കുകൾ ഒരു നല്ല തുടക്കമായി തോന്നുന്നു: + +```py +comments_dataset = comments_dataset.filter(lambda x: x["comment_length"] > 15) +comments_dataset +``` + +```python out +Dataset({ + features: ['html_url', 'title', 'comments', 'body', 'comment_length'], + num_rows: 2098 +}) +``` + +നമ്മുടെ ഡേറ്റാസെറ്റ് കുറച്ച് വൃത്തിയാക്കിയ ശേഷം, ഇഷ്യൂവിന്റെ ടൈറ്റിൽ, വിവരണം, കമന്റുകൾ എന്നിവ ഒരു പുതിയ `text` കോളത്തിൽ ഒരുമിച്ച് ചേർക്കാം (concatenate). പതിവുപോലെ, `Dataset.map()`-ന് നൽകാവുന്ന ഒരു ലളിതമായ ഫംഗ്‌ഷൻ നമ്മൾ എഴുതും: + +```py +def concatenate_text(examples): + return { + "text": examples["title"] + + " \n " + + examples["body"] + + " \n " + + examples["comments"] + } + + +comments_dataset = comments_dataset.map(concatenate_text) +``` + +ഒടുവിൽ കുറച്ച് എംബെഡ്ഡിംഗുകൾ ഉണ്ടാക്കാൻ നമ്മൾ തയ്യാറായി! നമുക്ക് നോക്കാം. + +## ടെക്‌സ്‌റ്റ് എംബെഡ്ഡിംഗുകൾ ഉണ്ടാക്കുന്നു[[creating-text-embeddings]] + +`AutoModel` ക്ലാസ് ഉപയോഗിച്ച് ടോക്കൺ എംബെഡ്ഡിംഗുകൾ ലഭിക്കുമെന്ന് [അധ്യായം 2](/course/chapter2)-ൽ നമ്മൾ കണ്ടു. മോഡൽ ലോഡ് ചെയ്യാൻ അനുയോജ്യമായ ഒരു ചെക്ക്‌പോയിന്റ് തിരഞ്ഞെടുക്കുക മാത്രമാണ് നമ്മൾ ചെയ്യേണ്ടത്. ഭാഗ്യവശാൽ, എംബെഡ്ഡിംഗുകൾ ഉണ്ടാക്കാൻ മാത്രമായി സമർപ്പിതമായ `sentence-transformers` എന്ന ഒരു ലൈബ്രറിയുണ്ട്. ലൈബ്രറിയുടെ [ഡോക്യുമെന്റേഷനിൽ](https://www.sbert.net/examples/applications/semantic-search/README.html#symmetric-vs-asymmetric-semantic-search) വിവരിച്ചിരിക്കുന്നതുപോലെ, നമ്മുടെ ഉപയോഗം _അസിമെട്രിക് സെമാന്റിക് സെർച്ചിന്റെ_ (asymmetric semantic search) ഒരു ഉദാഹരണമാണ്, കാരണം നമുക്ക് ഒരു ചെറിയ ക്വറിയുണ്ട്, അതിന്റെ ഉത്തരം ഒരു ഇഷ്യൂ കമന്റ് പോലുള്ള കൂടുതൽ നീളമുള്ള ഒരു ഡോക്യുമെന്റിൽ കണ്ടെത്താനാണ് നമ്മൾ ആഗ്രഹിക്കുന്നത്. സെമാന്റിക് സെർച്ചിന് ഏറ്റവും മികച്ച പ്രകടനം `multi-qa-mpnet-base-dot-v1` ചെക്ക്‌പോയിന്റിനാണെന്ന് ഡോക്യുമെന്റേഷനിലെ ഉപകാരപ്രദമായ [മോഡൽ ഓവർവ്യൂ ടേബിൾ](https://www.sbert.net/docs/pretrained_models.html#model-overview) സൂചിപ്പിക്കുന്നു; അതിനാൽ നമ്മുടെ ആപ്ലിക്കേഷന് അത് നമ്മൾ ഉപയോഗിക്കും. അതേ ചെക്ക്‌പോയിന്റ് ഉപയോഗിച്ച് ടോക്കണൈസറും നമ്മൾ ലോഡ് ചെയ്യും: + +{#if fw === 'pt'} + +```py +from transformers import AutoTokenizer, AutoModel + +model_ckpt = "sentence-transformers/multi-qa-mpnet-base-dot-v1" +tokenizer = AutoTokenizer.from_pretrained(model_ckpt) +model = AutoModel.from_pretrained(model_ckpt) +``` + +എംബെഡ്ഡിംഗ് പ്രോസസ്സ് വേഗത്തിലാക്കാൻ, മോഡലും ഇൻപുട്ടുകളും ഒരു GPU ഡിവൈസിൽ വയ്ക്കുന്നത് സഹായകമാണ്; അതിനാൽ ഇപ്പോൾ അത് ചെയ്യാം: + +```py +import torch + +device = torch.device("cuda") +model.to(device) +``` + +{:else} + +```py +from transformers import AutoTokenizer, TFAutoModel + +model_ckpt = "sentence-transformers/multi-qa-mpnet-base-dot-v1" +tokenizer = AutoTokenizer.from_pretrained(model_ckpt) +model = TFAutoModel.from_pretrained(model_ckpt, from_pt=True) +``` + +`from_pretrained()` മെത്തേഡിന്റെ ഒരു ആർഗ്യുമെന്റായി `from_pt=True` നമ്മൾ സെറ്റ് ചെയ്തിരിക്കുന്നത് ശ്രദ്ധിക്കുക. `multi-qa-mpnet-base-dot-v1` ചെക്ക്‌പോയിന്റിന് PyTorch വെയ്‌റ്റുകൾ മാത്രമേ ഉള്ളൂ എന്നതാണ് ഇതിന് കാരണം; അതിനാൽ `from_pt=True` സെറ്റ് ചെയ്യുന്നത് അവയെ നമുക്കായി TensorFlow ഫോർമാറ്റിലേക്ക് സ്വയമേവ മാറ്റും. നിങ്ങൾക്ക് കാണാവുന്നതുപോലെ, 🤗 Transformers-ൽ ഫ്രെയിംവർക്കുകൾക്കിടയിൽ മാറുന്നത് വളരെ ലളിതമാണ്! + +{/if} + +നേരത്തെ സൂചിപ്പിച്ചതുപോലെ, നമ്മുടെ GitHub ഇഷ്യൂ കോർപ്പസിലെ ഓരോ എൻട്രിയെയും ഒരൊറ്റ വെക്റ്ററായി പ്രതിനിധീകരിക്കാനാണ് നമ്മൾ ആഗ്രഹിക്കുന്നത്; അതിനാൽ നമ്മുടെ ടോക്കൺ എംബെഡ്ഡിംഗുകളെ ഏതെങ്കിലും വിധത്തിൽ "പൂൾ" ചെയ്യുകയോ ശരാശരി എടുക്കുകയോ ചെയ്യേണ്ടതുണ്ട്. നമ്മുടെ മോഡലിന്റെ ഔട്ട്‌പുട്ടുകളിൽ *CLS പൂളിംഗ്* (CLS pooling) നടത്തുന്നതാണ് ഒരു ജനപ്രിയ രീതി; ഇവിടെ പ്രത്യേക `[CLS]` ടോക്കണിന്റെ അവസാനത്തെ ഹിഡൻ സ്‌റ്റേറ്റ് (last hidden state) മാത്രം നമ്മൾ എടുക്കുന്നു. താഴെയുള്ള ഫംഗ്‌ഷൻ ഇത് നമുക്കായി ചെയ്യുന്നു: + +```py +def cls_pooling(model_output): + return model_output.last_hidden_state[:, 0] +``` + +അടുത്തതായി, ഡോക്യുമെന്റുകളുടെ ഒരു ലിസ്‌റ്റ് ടോക്കണൈസ് ചെയ്യുകയും, ടെൻസറുകൾ GPU-വിൽ വയ്ക്കുകയും, അവ മോഡലിന് നൽകുകയും, ഒടുവിൽ ഔട്ട്‌പുട്ടുകളിൽ CLS പൂളിംഗ് പ്രയോഗിക്കുകയും ചെയ്യുന്ന ഒരു ഹെൽപ്പർ ഫംഗ്‌ഷൻ നമ്മൾ ഉണ്ടാക്കും: + +{#if fw === 'pt'} + +```py +def get_embeddings(text_list): + encoded_input = tokenizer( + text_list, padding=True, truncation=True, return_tensors="pt" + ) + encoded_input = {k: v.to(device) for k, v in encoded_input.items()} + model_output = model(**encoded_input) + return cls_pooling(model_output) +``` + +നമ്മുടെ കോർപ്പസിലെ ആദ്യത്തെ ടെക്‌സ്‌റ്റ് എൻട്രി ഈ ഫംഗ്‌ഷന് നൽകി ഔട്ട്‌പുട്ടിന്റെ ഷേപ്പ് പരിശോധിച്ചുകൊണ്ട് ഫംഗ്‌ഷൻ പ്രവർത്തിക്കുന്നുണ്ടോ എന്ന് നമുക്ക് ടെസ്‌റ്റ് ചെയ്യാം: + +```py +embedding = get_embeddings(comments_dataset["text"][0]) +embedding.shape +``` + +```python out +torch.Size([1, 768]) +``` + +കൊള്ളാം, നമ്മുടെ കോർപ്പസിലെ ആദ്യത്തെ എൻട്രിയെ 768-ഡൈമെൻഷനുള്ള ഒരു വെക്റ്ററായി നമ്മൾ മാറ്റിയിരിക്കുന്നു! നമ്മുടെ കോർപ്പസിലെ ഓരോ വരിയിലും `get_embeddings()` ഫംഗ്‌ഷൻ പ്രയോഗിക്കാൻ `Dataset.map()` ഉപയോഗിക്കാം; അതിനാൽ താഴെ കാണുന്നതുപോലെ ഒരു പുതിയ `embeddings` കോളം ഉണ്ടാക്കാം: + +```py +embeddings_dataset = comments_dataset.map( + lambda x: {"embeddings": get_embeddings(x["text"]).detach().cpu().numpy()[0]} +) +``` + +{:else} + +```py +def get_embeddings(text_list): + encoded_input = tokenizer( + text_list, padding=True, truncation=True, return_tensors="tf" + ) + encoded_input = {k: v for k, v in encoded_input.items()} + model_output = model(**encoded_input) + return cls_pooling(model_output) +``` + +നമ്മുടെ കോർപ്പസിലെ ആദ്യത്തെ ടെക്‌സ്‌റ്റ് എൻട്രി ഈ ഫംഗ്‌ഷന് നൽകി ഔട്ട്‌പുട്ടിന്റെ ഷേപ്പ് പരിശോധിച്ചുകൊണ്ട് ഫംഗ്‌ഷൻ പ്രവർത്തിക്കുന്നുണ്ടോ എന്ന് നമുക്ക് ടെസ്‌റ്റ് ചെയ്യാം: + +```py +embedding = get_embeddings(comments_dataset["text"][0]) +embedding.shape +``` + +```python out +TensorShape([1, 768]) +``` + +കൊള്ളാം, നമ്മുടെ കോർപ്പസിലെ ആദ്യത്തെ എൻട്രിയെ 768-ഡൈമെൻഷനുള്ള ഒരു വെക്റ്ററായി നമ്മൾ മാറ്റിയിരിക്കുന്നു! നമ്മുടെ കോർപ്പസിലെ ഓരോ വരിയിലും `get_embeddings()` ഫംഗ്‌ഷൻ പ്രയോഗിക്കാൻ `Dataset.map()` ഉപയോഗിക്കാം; അതിനാൽ താഴെ കാണുന്നതുപോലെ ഒരു പുതിയ `embeddings` കോളം ഉണ്ടാക്കാം: + +```py +embeddings_dataset = comments_dataset.map( + lambda x: {"embeddings": get_embeddings(x["text"]).numpy()[0]} +) +``` + +{/if} + +എംബെഡ്ഡിംഗുകളെ നമ്മൾ NumPy അറേകളായി മാറ്റിയിരിക്കുന്നത് ശ്രദ്ധിക്കുക -- FAISS ഉപയോഗിച്ച് അവയെ ഇൻഡെക്‌സ് ചെയ്യാൻ ശ്രമിക്കുമ്പോൾ 🤗 Datasets-ന് ഈ ഫോർമാറ്റ് ആവശ്യമാണ് എന്നതാണ് കാരണം; അതാണ് നമ്മൾ അടുത്തതായി ചെയ്യാൻ പോകുന്നത്. + + +## കാര്യക്ഷമമായ സിമിലാരിറ്റി സെർച്ചിനായി FAISS ഉപയോഗിക്കുന്നു[[using-faiss-for-efficient-similarity-search]] + +ഇപ്പോൾ എംബെഡ്ഡിംഗുകളുടെ ഒരു ഡേറ്റാസെറ്റ് നമ്മുടെ കൈയിലുള്ളതിനാൽ, അവയിൽ തിരയാൻ എന്തെങ്കിലും ഒരു മാർഗ്ഗം നമുക്ക് ആവശ്യമാണ്. ഇതിനായി, 🤗 Datasets-ലെ _FAISS ഇൻഡെക്‌സ്_ (FAISS index) എന്ന ഒരു പ്രത്യേക ഡേറ്റാ സ്‌ട്രക്ചർ നമ്മൾ ഉപയോഗിക്കും. [FAISS](https://faiss.ai/) (Facebook AI Similarity Search എന്നതിന്റെ ചുരുക്കം) എംബെഡ്ഡിംഗ് വെക്റ്ററുകൾ വേഗത്തിൽ തിരയാനും ക്ലസ്‌റ്റർ ചെയ്യാനുമുള്ള കാര്യക്ഷമമായ അൽഗോരിതങ്ങൾ നൽകുന്ന ഒരു ലൈബ്രറിയാണ്. + +ഒരു ഇൻപുട്ട് എംബെഡ്ഡിംഗിനോട് ഏതെല്ലാം എംബെഡ്ഡിംഗുകൾ സാമ്യമുള്ളവയാണെന്ന് കണ്ടെത്താൻ സഹായിക്കുന്ന _ഇൻഡെക്‌സ്_ (index) എന്ന ഒരു പ്രത്യേക ഡേറ്റാ സ്‌ട്രക്ചർ ഉണ്ടാക്കുക എന്നതാണ് FAISS-ന്റെ പിന്നിലെ അടിസ്ഥാന ആശയം. 🤗 Datasets-ൽ ഒരു FAISS ഇൻഡെക്‌സ് ഉണ്ടാക്കുന്നത് ലളിതമാണ് -- `Dataset.add_faiss_index()` ഫംഗ്‌ഷൻ ഉപയോഗിച്ച്, നമ്മുടെ ഡേറ്റാസെറ്റിലെ ഏത് കോളമാണ് ഇൻഡെക്‌സ് ചെയ്യേണ്ടതെന്ന് നമ്മൾ വ്യക്തമാക്കുന്നു: + +```py +embeddings_dataset.add_faiss_index(column="embeddings") +``` + +`Dataset.get_nearest_examples()` ഫംഗ്‌ഷൻ ഉപയോഗിച്ച് ഒരു നിയറസ്‌റ്റ് നെയ്‌ബർ ലുക്കപ്പ് (nearest neighbor lookup) നടത്തി ഈ ഇൻഡെക്‌സിൽ നമുക്ക് ഇപ്പോൾ ക്വറികൾ നടത്താം. താഴെ കാണുന്നതുപോലെ ആദ്യം ഒരു ചോദ്യം എംബെഡ് ചെയ്തുകൊണ്ട് ഇത് ടെസ്‌റ്റ് ചെയ്യാം: + +{#if fw === 'pt'} + +```py +question = "How can I load a dataset offline?" +question_embedding = get_embeddings([question]).cpu().detach().numpy() +question_embedding.shape +``` + +```python out +torch.Size([1, 768]) +``` + +{:else} + +```py +question = "How can I load a dataset offline?" +question_embedding = get_embeddings([question]).numpy() +question_embedding.shape +``` + +```python out +(1, 768) +``` + +{/if} + +ഡോക്യുമെന്റുകളുടെ കാര്യത്തിലെന്നപോലെ, ക്വറിയെ പ്രതിനിധീകരിക്കുന്ന 768-ഡൈമെൻഷനുള്ള ഒരു വെക്റ്റർ ഇപ്പോൾ നമ്മുടെ കൈയിലുണ്ട്; ഏറ്റവും സാമ്യമുള്ള എംബെഡ്ഡിംഗുകൾ കണ്ടെത്താൻ ഇത് മുഴുവൻ കോർപ്പസുമായി താരതമ്യം ചെയ്യാം: + +```py +scores, samples = embeddings_dataset.get_nearest_examples( + "embeddings", question_embedding, k=5 +) +``` + +`Dataset.get_nearest_examples()` ഫംഗ്‌ഷൻ, ക്വറിയും ഡോക്യുമെന്റും തമ്മിലുള്ള ഓവർലാപ്പ് റാങ്ക് ചെയ്യുന്ന സ്‌കോറുകളുടെയും, അവയോട് അനുബന്ധമായ സാമ്പിളുകളുടെ ഒരു സെറ്റിന്റെയും (ഇവിടെ, ഏറ്റവും മികച്ച 5 പൊരുത്തങ്ങൾ) ഒരു ട്യൂപ്പിൾ റിട്ടേൺ ചെയ്യുന്നു. എളുപ്പത്തിൽ സോർട്ട് ചെയ്യാനായി ഇവ ഒരു `pandas.DataFrame`-ൽ ശേഖരിക്കാം: + +```py +import pandas as pd + +samples_df = pd.DataFrame.from_dict(samples) +samples_df["scores"] = scores +samples_df.sort_values("scores", ascending=False, inplace=True) +``` + +ലഭ്യമായ കമന്റുകളുമായി നമ്മുടെ ക്വറി എത്ര നന്നായി പൊരുത്തപ്പെട്ടു എന്ന് കാണാൻ, ആദ്യത്തെ കുറച്ച് വരികളിലൂടെ ഇപ്പോൾ നമുക്ക് ഇറ്ററേറ്റ് ചെയ്യാം: + +```py +for _, row in samples_df.iterrows(): + print(f"COMMENT: {row.comments}") + print(f"SCORE: {row.scores}") + print(f"TITLE: {row.title}") + print(f"URL: {row.html_url}") + print("=" * 50) + print() +``` + +```python out +""" +COMMENT: Requiring online connection is a deal breaker in some cases unfortunately so it'd be great if offline mode is added similar to how `transformers` loads models offline fine. + +@mandubian's second bullet point suggests that there's a workaround allowing you to use your offline (custom?) dataset with `datasets`. Could you please elaborate on how that should look like? +SCORE: 25.505046844482422 +TITLE: Discussion using datasets in offline mode +URL: https://github.com/huggingface/datasets/issues/824 +================================================== + +COMMENT: The local dataset builders (csv, text , json and pandas) are now part of the `datasets` package since #1726 :) +You can now use them offline +\`\`\`python +datasets = load_dataset("text", data_files=data_files) +\`\`\` + +We'll do a new release soon +SCORE: 24.555509567260742 +TITLE: Discussion using datasets in offline mode +URL: https://github.com/huggingface/datasets/issues/824 +================================================== + +COMMENT: I opened a PR that allows to reload modules that have already been loaded once even if there's no internet. + +Let me know if you know other ways that can make the offline mode experience better. I'd be happy to add them :) + +I already note the "freeze" modules option, to prevent local modules updates. It would be a cool feature. + +---------- + +> @mandubian's second bullet point suggests that there's a workaround allowing you to use your offline (custom?) dataset with `datasets`. Could you please elaborate on how that should look like? + +Indeed `load_dataset` allows to load remote dataset script (squad, glue, etc.) but also you own local ones. +For example if you have a dataset script at `./my_dataset/my_dataset.py` then you can do +\`\`\`python +load_dataset("./my_dataset") +\`\`\` +and the dataset script will generate your dataset once and for all. + +---------- + +About I'm looking into having `csv`, `json`, `text`, `pandas` dataset builders already included in the `datasets` package, so that they are available offline by default, as opposed to the other datasets that require the script to be downloaded. +cf #1724 +SCORE: 24.14896583557129 +TITLE: Discussion using datasets in offline mode +URL: https://github.com/huggingface/datasets/issues/824 +================================================== + +COMMENT: > here is my way to load a dataset offline, but it **requires** an online machine +> +> 1. (online machine) +> +> ``` +> +> import datasets +> +> data = datasets.load_dataset(...) +> +> data.save_to_disk(/YOUR/DATASET/DIR) +> +> ``` +> +> 2. copy the dir from online to the offline machine +> +> 3. (offline machine) +> +> ``` +> +> import datasets +> +> data = datasets.load_from_disk(/SAVED/DATA/DIR) +> +> ``` +> +> +> +> HTH. + + +SCORE: 22.893993377685547 +TITLE: Discussion using datasets in offline mode +URL: https://github.com/huggingface/datasets/issues/824 +================================================== + +COMMENT: here is my way to load a dataset offline, but it **requires** an online machine +1. (online machine) +\`\`\` +import datasets +data = datasets.load_dataset(...) +data.save_to_disk(/YOUR/DATASET/DIR) +\`\`\` +2. copy the dir from online to the offline machine +3. (offline machine) +\`\`\` +import datasets +data = datasets.load_from_disk(/SAVED/DATA/DIR) +\`\`\` + +HTH. +SCORE: 22.406635284423828 +TITLE: Discussion using datasets in offline mode +URL: https://github.com/huggingface/datasets/issues/824 +================================================== +""" +``` + +മോശമില്ല! നമ്മുടെ രണ്ടാമത്തെ ഫലം (hit) ക്വറിയുമായി പൊരുത്തപ്പെടുന്നതായി തോന്നുന്നു. + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** നിങ്ങളുടെ സ്വന്തം ക്വറി ഉണ്ടാക്കി, തിരിച്ചെടുത്ത (retrieved) ഡോക്യുമെന്റുകളിൽ ഒരു ഉത്തരം കണ്ടെത്താൻ കഴിയുമോ എന്ന് നോക്കുക. തിരയൽ വിപുലമാക്കാൻ `Dataset.get_nearest_examples()`-ലെ `k` പാരാമീറ്റർ നിങ്ങൾക്ക് കൂട്ടേണ്ടി വന്നേക്കാം. diff --git a/chapters/ml/chapter5/7.mdx b/chapters/ml/chapter5/7.mdx new file mode 100644 index 000000000..9ef128936 --- /dev/null +++ b/chapters/ml/chapter5/7.mdx @@ -0,0 +1,16 @@ +# 🤗 Datasets, പൂർത്തിയായി![[datasets-check]] + + + +🤗 Datasets ലൈബ്രറിയിലൂടെയുള്ള ഒരു നീണ്ട യാത്രയായിരുന്നു അത് -- ഇത്രയും ദൂരം എത്തിയതിന് അഭിനന്ദനങ്ങൾ! ഈ അധ്യായത്തിൽ നിന്ന് നിങ്ങൾ നേടിയ അറിവുകൊണ്ട്, നിങ്ങൾക്ക് താഴെപ്പറയുന്നവ ചെയ്യാൻ കഴിയണം: + +- Hugging Face Hub ആയാലും, നിങ്ങളുടെ ലാപ്‌ടോപ്പ് ആയാലും, നിങ്ങളുടെ കമ്പനിയിലെ ഒരു റിമോട്ട് സെർവർ ആയാലും — എവിടെനിന്നും ഡേറ്റാസെറ്റുകൾ ലോഡ് ചെയ്യുക. +- `Dataset.map()`, `Dataset.filter()` ഫംഗ്‌ഷനുകൾ ഒരുമിച്ച് ഉപയോഗിച്ച് നിങ്ങളുടെ ഡേറ്റ കൈകാര്യം ചെയ്യുക. +- `Dataset.set_format()` ഉപയോഗിച്ച് Pandas, NumPy പോലുള്ള ഡേറ്റാ ഫോർമാറ്റുകൾക്കിടയിൽ വേഗത്തിൽ മാറുക. +- നിങ്ങളുടെ തനി സ്വന്തം ഡേറ്റാസെറ്റ് ഉണ്ടാക്കി Hugging Face Hub-ലേക്ക് പുഷ് ചെയ്യുക. +- ഒരു Transformer മോഡൽ ഉപയോഗിച്ച് നിങ്ങളുടെ ഡോക്യുമെന്റുകൾ എംബെഡ് ചെയ്യുകയും FAISS ഉപയോഗിച്ച് ഒരു സെമാന്റിക് സെർച്ച് എഞ്ചിൻ നിർമ്മിക്കുകയും ചെയ്യുക. + +[അധ്യായം 7](/course/chapter7)-ൽ, Transformer മോഡലുകൾ മികവ് പുലർത്തുന്ന പ്രധാന NLP ടാസ്‌ക്കുകളിലേക്ക് ആഴത്തിൽ ഇറങ്ങുമ്പോൾ ഇതെല്ലാം നമ്മൾ നന്നായി പ്രയോജനപ്പെടുത്തും. എന്നാൽ മുന്നോട്ട് കുതിക്കുന്നതിന് മുമ്പ്, 🤗 Datasets-നെക്കുറിച്ചുള്ള നിങ്ങളുടെ അറിവ് ഒരു ചെറിയ ക്വിസിലൂടെ പരീക്ഷിക്കുക! diff --git a/chapters/ml/chapter5/8.mdx b/chapters/ml/chapter5/8.mdx new file mode 100644 index 000000000..4bcf0020d --- /dev/null +++ b/chapters/ml/chapter5/8.mdx @@ -0,0 +1,231 @@ + + +# അധ്യായത്തിന്റെ അവസാന ക്വിസ്[[end-of-chapter-quiz]] + + + +ഈ അധ്യായത്തിൽ നമ്മൾ ഒരുപാട് കാര്യങ്ങൾ പഠിച്ചു! എല്ലാ വിശദാംശങ്ങളും മനസ്സിലായില്ലെങ്കിൽ വിഷമിക്കേണ്ട; കാര്യങ്ങൾ ഉള്ളിൽ എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് മനസ്സിലാക്കാൻ അടുത്ത അധ്യായങ്ങൾ നിങ്ങളെ സഹായിക്കും. + +എന്നാൽ മുന്നോട്ട് പോകുന്നതിന് മുമ്പ്, ഈ അധ്യായത്തിൽ നിങ്ങൾ പഠിച്ചത് ഒന്ന് പരീക്ഷിക്കാം. + +### 1. 🤗 Datasets-ലെ `load_dataset()` ഫംഗ്‌ഷൻ താഴെപ്പറയുന്ന ഏതൊക്കെ സ്ഥലങ്ങളിൽ നിന്ന് ഒരു ഡേറ്റാസെറ്റ് ലോഡ് ചെയ്യാൻ നിങ്ങളെ അനുവദിക്കുന്നു? + +load_dataset()-ന്റെ data_files ആർഗ്യുമെന്റിലേക്ക് ലോക്കൽ ഫയലുകളുടെ പാതകൾ നൽകാം.", + correct: true + }, + { + text: "Hugging Face Hub", + explain: "ശരിയാണ്! ഡേറ്റാസെറ്റ് ID നൽകിക്കൊണ്ട് Hub-ലെ ഡേറ്റാസെറ്റുകൾ ലോഡ് ചെയ്യാം, ഉദാ. load_dataset('emotion').", + correct: true + }, + { + text: "ഒരു റിമോട്ട് സെർവർ", + explain: "ശരിയാണ്! റിമോട്ട് ഫയലുകൾ ലോഡ് ചെയ്യാൻ load_dataset()-ന്റെ data_files ആർഗ്യുമെന്റിലേക്ക് URL-കൾ നൽകാം.", + correct: true + }, + ]} +/> + +### 2. GLUE ടാസ്‌ക്കുകളിലൊന്ന് താഴെ കാണിച്ചിരിക്കുന്നതുപോലെ നിങ്ങൾ ലോഡ് ചെയ്യുന്നു എന്ന് കരുതുക: + +```py +from datasets import load_dataset + +dataset = load_dataset("glue", "mrpc", split="train") +``` + +താഴെപ്പറയുന്ന കമാൻഡുകളിൽ ഏതാണ് `dataset`-ൽ നിന്ന് 50 എലമെന്റുകളുടെ ഒരു ക്രമരഹിത (random) സാമ്പിൾ ഉണ്ടാക്കുന്നത്? + +dataset.sample(50)", + explain: "ഇത് തെറ്റാണ് -- Dataset.sample() എന്നൊരു മെത്തേഡ് ഇല്ല." + }, + { + text: "dataset.shuffle().select(range(50))", + explain: "ശരിയാണ്! ഈ അധ്യായത്തിൽ നിങ്ങൾ കണ്ടതുപോലെ, ആദ്യം ഡേറ്റാസെറ്റ് ഷഫിൾ ചെയ്യുകയും പിന്നീട് അതിൽ നിന്ന് സാമ്പിളുകൾ തിരഞ്ഞെടുക്കുകയും ചെയ്യുന്നു.", + correct: true + }, + { + text: "dataset.select(range(50)).shuffle()", + explain: "ഇത് തെറ്റാണ് -- കോഡ് റൺ ചെയ്യുമെങ്കിലും, ഇത് ഡേറ്റാസെറ്റിലെ ആദ്യത്തെ 50 എലമെന്റുകൾ മാത്രമേ ഷഫിൾ ചെയ്യുകയുള്ളൂ." + } + ]} +/> + +### 3. വളർത്തുമൃഗങ്ങളെക്കുറിച്ചുള്ള `pets_dataset` എന്ന ഒരു ഡേറ്റാസെറ്റ് നിങ്ങളുടെ പക്കലുണ്ടെന്ന് കരുതുക; ഓരോ വളർത്തുമൃഗത്തിന്റെയും പേര് സൂചിപ്പിക്കുന്ന ഒരു `name` കോളം ഇതിലുണ്ട്. "L" എന്ന അക്ഷരത്തിൽ പേര് തുടങ്ങുന്ന എല്ലാ വളർത്തുമൃഗങ്ങളെയും കണ്ടെത്താൻ ഡേറ്റാസെറ്റ് ഫിൽട്ടർ ചെയ്യാൻ താഴെപ്പറയുന്ന ഏതൊക്കെ രീതികൾ നിങ്ങളെ അനുവദിക്കും? + +pets_dataset.filter(lambda x : x['name'].startswith('L'))", + explain: "ശരിയാണ്! ഇത്തരം പെട്ടെന്നുള്ള ഫിൽട്ടറുകൾക്ക് ഒരു Python ലാംഡ ഫംഗ്‌ഷൻ (lambda function) ഉപയോഗിക്കുന്നത് മികച്ച ആശയമാണ്. മറ്റൊരു പരിഹാരം നിങ്ങൾക്ക് ചിന്തിക്കാൻ കഴിയുമോ?", + correct: true + }, + { + text: "pets_dataset.filter(lambda x['name'].startswith('L'))", + explain: "ഇത് തെറ്റാണ് -- ഒരു ലാംഡ ഫംഗ്‌ഷന്റെ പൊതുരൂപം lambda *arguments* : *expression* എന്നാണ്; അതിനാൽ ഈ സന്ദർഭത്തിൽ നിങ്ങൾ ആർഗ്യുമെന്റുകൾ നൽകേണ്ടതുണ്ട്." + }, + { + text: "def filter_names(x): return x['name'].startswith('L') പോലുള്ള ഒരു ഫംഗ്‌ഷൻ ഉണ്ടാക്കി pets_dataset.filter(filter_names) റൺ ചെയ്യുക.", + explain: "ശരിയാണ്! Dataset.map()-ന്റെ കാര്യത്തിലെന്നപോലെ, Dataset.filter()-ലേക്കും വ്യക്തമായി നിർവചിച്ച (explicit) ഫംഗ്‌ഷനുകൾ നൽകാം. ഒരു ചെറിയ ലാംഡ ഫംഗ്‌ഷന് അനുയോജ്യമല്ലാത്ത സങ്കീർണ്ണമായ ലോജിക് ഉള്ളപ്പോൾ ഇത് ഉപകാരപ്രദമാണ്. മറ്റ് പരിഹാരങ്ങളിൽ ഏതാണ് പ്രവർത്തിക്കുക?", + correct: true + } + ]} +/> + +### 4. എന്താണ് മെമ്മറി മാപ്പിംഗ് (memory mapping)? + + + +### 5. താഴെപ്പറയുന്നവയിൽ ഏതൊക്കെയാണ് മെമ്മറി മാപ്പിംഗിന്റെ പ്രധാന പ്രയോജനങ്ങൾ? + + + +### 6. താഴെയുള്ള കോഡ് പരാജയപ്പെടുന്നത് എന്തുകൊണ്ടാണ്? + +```py +from datasets import load_dataset + +dataset = load_dataset("allocine", streaming=True, split="train") +dataset[0] +``` + +IterableDataset ആക്‌സസ് ചെയ്യാൻ ഇത് ശ്രമിക്കുന്നു.", + explain: "ശരിയാണ്! ഒരു IterableDataset ഒരു ജനറേറ്റർ (generator) ആണ്, ഒരു കണ്ടെയ്‌നർ അല്ല; അതിനാൽ അതിലെ എലമെന്റുകൾ next(iter(dataset)) ഉപയോഗിച്ചാണ് ആക്‌സസ് ചെയ്യേണ്ടത്.", + correct: true + }, + { + text: "allocine ഡേറ്റാസെറ്റിന് ഒരു train സ്‌പ്ലിറ്റ് ഇല്ല.", + explain: "ഇത് തെറ്റാണ് -- ഇതിൽ ഏതൊക്കെ സ്‌പ്ലിറ്റുകൾ ഉണ്ടെന്ന് കാണാൻ Hub-ലെ [allocine ഡേറ്റാസെറ്റ് കാർഡ്](https://huggingface.co/datasets/allocine) പരിശോധിക്കുക." + } + ]} +/> + +### 7. താഴെപ്പറയുന്നവയിൽ ഏതൊക്കെയാണ് ഒരു ഡേറ്റാസെറ്റ് കാർഡ് ഉണ്ടാക്കുന്നതിന്റെ പ്രധാന പ്രയോജനങ്ങൾ? + + + + +### 8. എന്താണ് സെമാന്റിക് സെർച്ച് (semantic search)? + + + +### 9. അസിമെട്രിക് (asymmetric) സെമാന്റിക് സെർച്ചിൽ സാധാരണയായി നിങ്ങൾക്കുണ്ടാകുന്നത്: + + + +### 10. സ്‌പീച്ച് പ്രോസസ്സിംഗ് പോലുള്ള മറ്റ് മേഖലകളിൽ ഉപയോഗിക്കാനുള്ള ഡേറ്റ ലോഡ് ചെയ്യാൻ എനിക്ക് 🤗 Datasets ഉപയോഗിക്കാമോ? + +MNIST ഡേറ്റാസെറ്റ് പരിശോധിക്കുക." + }, + { + text: "അതെ", + explain: "ശരിയാണ്! ഈ മേഖലകളിൽ 🤗 Datasets എങ്ങനെ ഉപയോഗിക്കുന്നു എന്ന് കാണാൻ, 🤗 Transformers ലൈബ്രറിയിലെ സ്‌പീച്ച്, വിഷൻ എന്നിവയുമായി ബന്ധപ്പെട്ട ആവേശകരമായ പുരോഗതികൾ പരിശോധിക്കുക.", + correct : true + }, + ]} +/> diff --git a/chapters/ml/chapter6/1.mdx b/chapters/ml/chapter6/1.mdx new file mode 100644 index 000000000..2fd0df619 --- /dev/null +++ b/chapters/ml/chapter6/1.mdx @@ -0,0 +1,19 @@ +# ആമുഖം[[introduction]] + + + +[അധ്യായം 3](/course/chapter3)-ൽ, ഒരു നിശ്ചിത ടാസ്‌ക്കിൽ ഒരു മോഡൽ എങ്ങനെ ഫൈൻ-ട്യൂൻ ചെയ്യാമെന്ന് നമ്മൾ നോക്കി. അങ്ങനെ ചെയ്യുമ്പോൾ, മോഡൽ പ്രീട്രെയിൻ ചെയ്യാൻ ഉപയോഗിച്ച അതേ ടോക്കണൈസർ തന്നെയാണ് നമ്മൾ ഉപയോഗിക്കുന്നത് -- എന്നാൽ ഒരു മോഡൽ പൂജ്യത്തിൽ നിന്ന് (from scratch) ട്രെയിൻ ചെയ്യണമെങ്കിൽ നമ്മൾ എന്ത് ചെയ്യും? ഇത്തരം സന്ദർഭങ്ങളിൽ, മറ്റൊരു ഡൊമെയ്‌നിൽ നിന്നോ ഭാഷയിൽ നിന്നോ ഉള്ള ഒരു കോർപ്പസിൽ (corpus) പ്രീട്രെയിൻ ചെയ്ത ഒരു ടോക്കണൈസർ ഉപയോഗിക്കുന്നത് സാധാരണയായി അത്ര മികച്ചതായിരിക്കില്ല. ഉദാഹരണത്തിന്, ഒരു ഇംഗ്ലീഷ് കോർപ്പസിൽ ട്രെയിൻ ചെയ്ത ഒരു ടോക്കണൈസർ ജാപ്പനീസ് ടെക്‌സ്‌റ്റുകളുടെ ഒരു കോർപ്പസിൽ മോശമായി പ്രവർത്തിക്കും, കാരണം സ്‌പേസുകളുടെയും ചിഹ്നങ്ങളുടെയും (punctuation) ഉപയോഗം ഈ രണ്ട് ഭാഷകളിലും വളരെ വ്യത്യസ്തമാണ്. + +ഈ അധ്യായത്തിൽ, ടെക്‌സ്‌റ്റുകളുടെ ഒരു കോർപ്പസിൽ തികച്ചും പുതിയ ഒരു ടോക്കണൈസർ എങ്ങനെ ട്രെയിൻ ചെയ്യാമെന്ന് നിങ്ങൾ പഠിക്കും; അങ്ങനെ അത് പിന്നീട് ഒരു ലാംഗ്വേജ് മോഡൽ പ്രീട്രെയിൻ ചെയ്യാൻ ഉപയോഗിക്കാം. [🤗 Tokenizers](https://github.com/huggingface/tokenizers) ലൈബ്രറിയുടെ സഹായത്തോടെയാണ് ഇതെല്ലാം ചെയ്യുന്നത്; [🤗 Transformers](https://github.com/huggingface/transformers) ലൈബ്രറിയിലെ "ഫാസ്‌റ്റ്" ടോക്കണൈസറുകൾ നൽകുന്നത് ഈ ലൈബ്രറിയാണ്. ഈ ലൈബ്രറി നൽകുന്ന ഫീച്ചറുകൾ നമ്മൾ അടുത്ത് പരിശോധിക്കും, കൂടാതെ ഫാസ്‌റ്റ് ടോക്കണൈസറുകൾ "സ്ലോ" പതിപ്പുകളിൽ നിന്ന് എങ്ങനെ വ്യത്യാസപ്പെട്ടിരിക്കുന്നു എന്നും നമ്മൾ പരിശോധിക്കും. + +നമ്മൾ ചർച്ച ചെയ്യുന്ന വിഷയങ്ങളിൽ ഇവ ഉൾപ്പെടുന്നു: + +* ഒരു നിശ്ചിത ചെക്ക്‌പോയിന്റ് ഉപയോഗിക്കുന്ന ടോക്കണൈസറിന് സമാനമായ ഒരു പുതിയ ടോക്കണൈസർ, ടെക്‌സ്‌റ്റുകളുടെ ഒരു പുതിയ കോർപ്പസിൽ എങ്ങനെ ട്രെയിൻ ചെയ്യാം +* ഫാസ്‌റ്റ് ടോക്കണൈസറുകളുടെ പ്രത്യേക ഫീച്ചറുകൾ +* ഇന്ന് NLP-യിൽ ഉപയോഗിക്കുന്ന മൂന്ന് പ്രധാന സബ്‌വേഡ് ടോക്കണൈസേഷൻ അൽഗോരിതങ്ങൾ തമ്മിലുള്ള വ്യത്യാസങ്ങൾ +* 🤗 Tokenizers ലൈബ്രറി ഉപയോഗിച്ച് പൂജ്യത്തിൽ നിന്ന് ഒരു ടോക്കണൈസർ എങ്ങനെ നിർമ്മിക്കാമെന്നും അത് കുറച്ച് ഡേറ്റയിൽ എങ്ങനെ ട്രെയിൻ ചെയ്യാമെന്നും + +ഈ അധ്യായത്തിൽ പരിചയപ്പെടുത്തുന്ന ടെക്‌നിക്കുകൾ, Python സോഴ്‌സ് കോഡിനായി ഒരു ലാംഗ്വേജ് മോഡൽ ഉണ്ടാക്കുന്നത് നമ്മൾ പരിശോധിക്കുന്ന [അധ്യായം 7](/course/chapter7/6)-ലെ ഭാഗത്തിനായി നിങ്ങളെ തയ്യാറാക്കും. ആദ്യം തന്നെ, ഒരു ടോക്കണൈസർ "ട്രെയിൻ" ചെയ്യുക എന്നതിന്റെ അർത്ഥമെന്താണ് എന്ന് നോക്കിക്കൊണ്ട് നമുക്ക് തുടങ്ങാം. diff --git a/chapters/ml/chapter6/10.mdx b/chapters/ml/chapter6/10.mdx new file mode 100644 index 000000000..29249526a --- /dev/null +++ b/chapters/ml/chapter6/10.mdx @@ -0,0 +1,283 @@ + + +# അധ്യായത്തിന്റെ അവസാന ക്വിസ്[[end-of-chapter-quiz]] + + + +ഈ അധ്യായത്തിൽ നിങ്ങൾ പഠിച്ചത് പരീക്ഷിച്ചുനോക്കാം! + +### 1. നിങ്ങൾ എപ്പോഴാണ് ഒരു പുതിയ ടോക്കണൈസർ ട്രെയിൻ ചെയ്യേണ്ടത്? + + + +### 2. `train_new_from_iterator()` ഉപയോഗിക്കുമ്പോൾ, ടെക്‌സ്‌റ്റുകളുടെ ലിസ്‌റ്റുകളുടെ ഒരു ലിസ്‌റ്റിനെ അപേക്ഷിച്ച് ടെക്‌സ്‌റ്റുകളുടെ ലിസ്‌റ്റുകളുടെ ഒരു ജനറേറ്റർ ഉപയോഗിക്കുന്നതിന്റെ പ്രയോജനം എന്താണ്? + +train_new_from_iterator() മെത്തേഡ് സ്വീകരിക്കുന്ന ഒരേയൊരു തരം അതാണ്.", + explain: "ടെക്‌സ്‌റ്റുകളുടെ ലിസ്‌റ്റുകളുടെ ഒരു ലിസ്‌റ്റ് എന്നത് ടെക്‌സ്‌റ്റുകളുടെ ലിസ്‌റ്റുകളുടെ ജനറേറ്ററിന്റെ ഒരു പ്രത്യേക തരമാണ്, അതിനാൽ മെത്തേഡ് ഇതും സ്വീകരിക്കും. വീണ്ടും ശ്രമിക്കുക!" + }, + { + text: "ഡേറ്റാസെറ്റ് മുഴുവനും ഒരേസമയം മെമ്മറിയിലേക്ക് ലോഡ് ചെയ്യുന്നത് നിങ്ങൾക്ക് ഒഴിവാക്കാം.", + explain: "ശരിയാണ്! നിങ്ങൾ ഇറ്ററേറ്റ് ചെയ്യുമ്പോൾ ടെക്‌സ്‌റ്റുകളുടെ ഓരോ ബാച്ചും മെമ്മറിയിൽ നിന്ന് ഒഴിവാക്കപ്പെടും; നിങ്ങളുടെ ടെക്‌സ്‌റ്റുകൾ സൂക്ഷിക്കാൻ 🤗 Datasets ഉപയോഗിക്കുകയാണെങ്കിൽ ഈ നേട്ടം പ്രത്യേകിച്ചും പ്രകടമാകും.", + correct: true + }, + { + text: "ഇത് 🤗 Tokenizers ലൈബ്രറിയെ മൾട്ടിപ്രോസസ്സിംഗ് ഉപയോഗിക്കാൻ അനുവദിക്കും.", + explain: "അല്ല, ഏത് വിധത്തിലായാലും അത് മൾട്ടിപ്രോസസ്സിംഗ് ഉപയോഗിക്കും." + }, + { + text: "നിങ്ങൾ ട്രെയിൻ ചെയ്യുന്ന ടോക്കണൈസർ കൂടുതൽ മികച്ച ടെക്‌സ്‌റ്റുകൾ ജനറേറ്റ് ചെയ്യും.", + explain: "ടോക്കണൈസർ ടെക്‌സ്‌റ്റ് ജനറേറ്റ് ചെയ്യുന്നില്ല -- നിങ്ങൾ അതിനെ ഒരു ലാംഗ്വേജ് മോഡലുമായി തെറ്റിദ്ധരിക്കുന്നുണ്ടോ?" + } + ]} +/> + +### 3. ഒരു "ഫാസ്‌റ്റ്" ടോക്കണൈസർ ഉപയോഗിക്കുന്നതിന്റെ പ്രയോജനങ്ങൾ എന്തൊക്കെയാണ്? + + + +### 4. ഒന്നിലധികം ടോക്കണുകളിലായി വ്യാപിച്ചുകിടക്കുന്ന എന്റിറ്റികളെ `token-classification` പൈപ്പ്‌ലൈൻ എങ്ങനെ കൈകാര്യം ചെയ്യുന്നു? + + + +### 5. നീണ്ട കോൺടെക്‌സ്‌റ്റുകളെ `question-answering` പൈപ്പ്‌ലൈൻ എങ്ങനെ കൈകാര്യം ചെയ്യുന്നു? + + + +### 6. എന്താണ് നോർമലൈസേഷൻ (normalization)? + + + +### 7. ഒരു സബ്‌വേഡ് ടോക്കണൈസറിന് പ്രീ-ടോക്കണൈസേഷൻ (pre-tokenization) എന്നാൽ എന്താണ്? + + + +### 8. BPE ടോക്കണൈസേഷൻ മോഡലിന് ബാധകമായ വാക്യങ്ങൾ തിരഞ്ഞെടുക്കുക. + + + +### 9. WordPiece ടോക്കണൈസേഷൻ മോഡലിന് ബാധകമായ വാക്യങ്ങൾ തിരഞ്ഞെടുക്കുക. + + + +### 10. Unigram ടോക്കണൈസേഷൻ മോഡലിന് ബാധകമായ വാക്യങ്ങൾ തിരഞ്ഞെടുക്കുക. + + diff --git a/chapters/ml/chapter6/2.mdx b/chapters/ml/chapter6/2.mdx new file mode 100644 index 000000000..2a543de36 --- /dev/null +++ b/chapters/ml/chapter6/2.mdx @@ -0,0 +1,254 @@ +# ഒരു പഴയ ടോക്കണൈസറിൽ നിന്ന് ഒരു പുതിയ ടോക്കണൈസർ ട്രെയിൻ ചെയ്യുന്നു[[training-a-new-tokenizer-from-an-old-one]] + + + +നിങ്ങൾക്ക് താൽപ്പര്യമുള്ള ഭാഷയിൽ ഒരു ലാംഗ്വേജ് മോഡൽ ലഭ്യമല്ലെങ്കിൽ, അല്ലെങ്കിൽ നിങ്ങളുടെ ലാംഗ്വേജ് മോഡൽ ട്രെയിൻ ചെയ്ത കോർപ്പസിൽ (corpus) നിന്ന് നിങ്ങളുടെ കോർപ്പസ് വളരെ വ്യത്യസ്തമാണെങ്കിൽ, നിങ്ങളുടെ ഡേറ്റയ്ക്ക് അനുയോജ്യമായ ഒരു ടോക്കണൈസർ ഉപയോഗിച്ച് മോഡൽ പൂജ്യത്തിൽ നിന്ന് (from scratch) വീണ്ടും ട്രെയിൻ ചെയ്യാനാണ് നിങ്ങൾ മിക്കവാറും ആഗ്രഹിക്കുക. അതിന് നിങ്ങളുടെ ഡേറ്റാസെറ്റിൽ ഒരു പുതിയ ടോക്കണൈസർ ട്രെയിൻ ചെയ്യേണ്ടിവരും. എന്നാൽ അതിന്റെ കൃത്യമായ അർത്ഥമെന്താണ്? [അധ്യായം 2](/course/chapter2)-ൽ ടോക്കണൈസറുകളെ നമ്മൾ ആദ്യമായി പരിശോധിച്ചപ്പോൾ, മിക്ക Transformer മോഡലുകളും ഒരു _സബ്‌വേഡ് ടോക്കണൈസേഷൻ അൽഗോരിതം_ ഉപയോഗിക്കുന്നു എന്ന് നമ്മൾ കണ്ടു. കൈവശമുള്ള കോർപ്പസിൽ ഏതൊക്കെ സബ്‌വേഡുകളാണ് പ്രസക്തമായതും ഏറ്റവും കൂടുതൽ തവണ വരുന്നതും എന്ന് തിരിച്ചറിയാൻ, കോർപ്പസിലെ എല്ലാ ടെക്‌സ്‌റ്റുകളും ടോക്കണൈസർ സൂക്ഷ്മമായി പരിശോധിക്കേണ്ടതുണ്ട് -- ഈ പ്രക്രിയയെയാണ് നമ്മൾ *ട്രെയിനിംഗ്* എന്ന് വിളിക്കുന്നത്. ഈ ട്രെയിനിംഗിനെ നിയന്ത്രിക്കുന്ന കൃത്യമായ നിയമങ്ങൾ ഉപയോഗിക്കുന്ന ടോക്കണൈസറിന്റെ തരത്തെ ആശ്രയിച്ചിരിക്കും; ഈ അധ്യായത്തിൽ പിന്നീട് മൂന്ന് പ്രധാന അൽഗോരിതങ്ങളും നമ്മൾ പരിശോധിക്കും. + + + +> [!WARNING] +> ⚠️ ഒരു ടോക്കണൈസർ ട്രെയിൻ ചെയ്യുന്നത് ഒരു മോഡൽ ട്രെയിൻ ചെയ്യുന്നതിന് തുല്യമല്ല! ഓരോ ബാച്ചിനും ലോസ് അൽപ്പം കുറയ്ക്കാൻ മോഡൽ ട്രെയിനിംഗ് സ്‌റ്റൊക്കാസ്‌റ്റിക് ഗ്രേഡിയന്റ് ഡിസെന്റ് (stochastic gradient descent) ഉപയോഗിക്കുന്നു. അത് സ്വഭാവത്താൽ തന്നെ ക്രമരഹിതമാണ് (randomized) — അതായത്, ഒരേ ട്രെയിനിംഗ് രണ്ട് തവണ ചെയ്യുമ്പോൾ ഒരേ ഫലങ്ങൾ ലഭിക്കാൻ നിങ്ങൾ ചില സീഡുകൾ (seeds) സെറ്റ് ചെയ്യേണ്ടിവരും. ഒരു ടോക്കണൈസർ ട്രെയിൻ ചെയ്യുന്നത് ഒരു സ്‌റ്റാറ്റിസ്‌റ്റിക്കൽ പ്രക്രിയയാണ്; ഒരു നിശ്ചിത കോർപ്പസിന് ഏതൊക്കെ സബ്‌വേഡുകളാണ് തിരഞ്ഞെടുക്കാൻ ഏറ്റവും മികച്ചത് എന്ന് തിരിച്ചറിയാൻ അത് ശ്രമിക്കുന്നു, അവ തിരഞ്ഞെടുക്കാൻ ഉപയോഗിക്കുന്ന കൃത്യമായ നിയമങ്ങൾ ടോക്കണൈസേഷൻ അൽഗോരിതത്തെ ആശ്രയിച്ചിരിക്കും. അത് ഡിറ്റർമിനിസ്‌റ്റിക് (deterministic) ആണ്, അതായത് ഒരേ കോർപ്പസിൽ ഒരേ അൽഗോരിതം ഉപയോഗിച്ച് ട്രെയിൻ ചെയ്യുമ്പോൾ എപ്പോഴും ഒരേ ഫലങ്ങൾ തന്നെ നിങ്ങൾക്ക് ലഭിക്കും. + +## ഒരു കോർപ്പസ് തയ്യാറാക്കുന്നു[[assembling-a-corpus]] + +നിലവിലുള്ള ഒരു ടോക്കണൈസറിന്റെ അതേ സവിശേഷതകളുള്ള ഒരു പുതിയ ടോക്കണൈസർ ട്രെയിൻ ചെയ്യാൻ നിങ്ങൾക്ക് ഉപയോഗിക്കാവുന്ന വളരെ ലളിതമായ ഒരു API 🤗 Transformers-ൽ ഉണ്ട്: `AutoTokenizer.train_new_from_iterator()`. ഇത് പ്രവർത്തിക്കുന്നത് കാണാൻ, GPT-2 പൂജ്യത്തിൽ നിന്ന് ട്രെയിൻ ചെയ്യണമെന്ന് നമ്മൾ ആഗ്രഹിക്കുന്നു എന്ന് കരുതുക, എന്നാൽ ഇംഗ്ലീഷ് അല്ലാത്ത ഒരു ഭാഷയിൽ. ആ ഭാഷയിലുള്ള ധാരാളം ഡേറ്റ ഒരു ട്രെയിനിംഗ് കോർപ്പസിൽ ശേഖരിക്കുകയാണ് നമ്മുടെ ആദ്യ ജോലി. എല്ലാവർക്കും മനസ്സിലാകുന്ന ഉദാഹരണങ്ങൾ നൽകാൻ, ഇവിടെ റഷ്യൻ, ചൈനീസ് പോലുള്ള ഒരു ഭാഷ നമ്മൾ ഉപയോഗിക്കുന്നില്ല; പകരം, ഒരു പ്രത്യേകതരം ഇംഗ്ലീഷ് ഭാഷയാണ് ഉപയോഗിക്കുന്നത്: Python കോഡ്. + +Python സോഴ്‌സ് കോഡിന്റെ ഒരു കോർപ്പസ് തയ്യാറാക്കാൻ [🤗 Datasets](https://github.com/huggingface/datasets) ലൈബ്രറി നമ്മെ സഹായിക്കും. [CodeSearchNet](https://huggingface.co/datasets/code_search_net) ഡേറ്റാസെറ്റ് ഡൗൺലോഡ് ചെയ്ത് കാഷ് ചെയ്യാൻ പതിവുപോലെ `load_dataset()` ഫംഗ്‌ഷൻ നമ്മൾ ഉപയോഗിക്കും. ഈ ഡേറ്റാസെറ്റ് [CodeSearchNet ചലഞ്ചിനായി](https://wandb.ai/github/CodeSearchNet/benchmark) ഉണ്ടാക്കിയതാണ്; GitHub-ലെ ഓപ്പൻ സോഴ്‌സ് ലൈബ്രറികളിൽ നിന്നുള്ള, പല പ്രോഗ്രാമിംഗ് ഭാഷകളിലുള്ള ദശലക്ഷക്കണക്കിന് ഫംഗ്‌ഷനുകൾ ഇതിൽ അടങ്ങിയിരിക്കുന്നു. ഇവിടെ, ഈ ഡേറ്റാസെറ്റിന്റെ Python ഭാഗം നമ്മൾ ലോഡ് ചെയ്യും: + +```py +from datasets import load_dataset + +# This can take a few minutes to load, so grab a coffee or tea while you wait! +raw_datasets = load_dataset("code_search_net", "python") +``` + +നമുക്ക് ഏതൊക്കെ കോളങ്ങൾ ലഭ്യമാണെന്ന് കാണാൻ ട്രെയിനിംഗ് സ്‌പ്ലിറ്റ് ഒന്ന് നോക്കാം: + +```py +raw_datasets["train"] +``` + +```python out +Dataset({ + features: ['repository_name', 'func_path_in_repository', 'func_name', 'whole_func_string', 'language', + 'func_code_string', 'func_code_tokens', 'func_documentation_string', 'func_documentation_tokens', 'split_name', + 'func_code_url' + ], + num_rows: 412178 +}) +``` + +ഡേറ്റാസെറ്റ് ഡോക്‌സ്‌ട്രിംഗുകളെ (docstrings) കോഡിൽ നിന്ന് വേർതിരിക്കുന്നുവെന്നും രണ്ടിന്റെയും ഒരു ടോക്കണൈസേഷൻ നിർദ്ദേശിക്കുന്നുവെന്നും നമുക്ക് കാണാം. ഇവിടെ, നമ്മുടെ ടോക്കണൈസർ ട്രെയിൻ ചെയ്യാൻ `whole_func_string` കോളം മാത്രമേ നമ്മൾ ഉപയോഗിക്കൂ. `train` സ്‌പ്ലിറ്റിലേക്ക് ഇൻഡെക്‌സ് ചെയ്തുകൊണ്ട് ഈ ഫംഗ്‌ഷനുകളിൽ ഒന്നിന്റെ ഒരു ഉദാഹരണം നമുക്ക് നോക്കാം: + +```py +print(raw_datasets["train"][123456]["whole_func_string"]) +``` + +ഇത് താഴെപ്പറയുന്നത് പ്രിന്റ് ചെയ്യണം: + +```out +def handle_simple_responses( + self, timeout_ms=None, info_cb=DEFAULT_MESSAGE_CALLBACK): + """Accepts normal responses from the device. + + Args: + timeout_ms: Timeout in milliseconds to wait for each response. + info_cb: Optional callback for text sent from the bootloader. + + Returns: + OKAY packet's message. + """ + return self._accept_responses('OKAY', info_cb, timeout_ms=timeout_ms) +``` + +നമ്മൾ ആദ്യം ചെയ്യേണ്ടത്, ഡേറ്റാസെറ്റിനെ ടെക്‌സ്‌റ്റുകളുടെ ലിസ്‌റ്റുകളുടെ ഒരു _ഇറ്ററേറ്റർ_ (iterator) ആക്കി മാറ്റുകയാണ് -- ഉദാഹരണത്തിന്, ടെക്‌സ്‌റ്റുകളുടെ ലിസ്‌റ്റുകളുടെ ഒരു ലിസ്‌റ്റ്. ടെക്‌സ്‌റ്റുകളുടെ ലിസ്‌റ്റുകൾ ഉപയോഗിക്കുന്നത് നമ്മുടെ ടോക്കണൈസറിന് വേഗത്തിൽ പ്രവർത്തിക്കാൻ സഹായിക്കും (ഓരോ ടെക്‌സ്‌റ്റും ഒന്നൊന്നായി പ്രോസസ്സ് ചെയ്യുന്നതിന് പകരം ടെക്‌സ്‌റ്റുകളുടെ ബാച്ചുകളിൽ ട്രെയിൻ ചെയ്യുന്നു), കൂടാതെ എല്ലാം ഒരേസമയം മെമ്മറിയിൽ വരുന്നത് ഒഴിവാക്കണമെങ്കിൽ അത് ഒരു ഇറ്ററേറ്റർ ആയിരിക്കണം. നിങ്ങളുടെ കോർപ്പസ് വളരെ വലുതാണെങ്കിൽ, 🤗 Datasets എല്ലാം RAM-ലേക്ക് ലോഡ് ചെയ്യുന്നില്ല, പകരം ഡേറ്റാസെറ്റിലെ എലമെന്റുകൾ ഡിസ്‌കിൽ സൂക്ഷിക്കുന്നു എന്ന വസ്തുത നിങ്ങൾ പ്രയോജനപ്പെടുത്താൻ ആഗ്രഹിക്കും. + +താഴെ കാണുന്നത് ചെയ്യുന്നത്, ഓരോന്നിലും 1,000 ടെക്‌സ്‌റ്റുകൾ വീതമുള്ള ലിസ്‌റ്റുകളുടെ ഒരു ലിസ്‌റ്റ് ഉണ്ടാക്കും, എന്നാൽ അത് എല്ലാം മെമ്മറിയിലേക്ക് ലോഡ് ചെയ്യും: + +```py +# Don't uncomment the following line unless your dataset is small! +# training_corpus = [raw_datasets["train"][i: i + 1000]["whole_func_string"] for i in range(0, len(raw_datasets["train"]), 1000)] +``` + +ഒരു Python ജനറേറ്റർ (generator) ഉപയോഗിച്ച്, ശരിക്കും ആവശ്യമാകുന്നതുവരെ Python ഒന്നും മെമ്മറിയിലേക്ക് ലോഡ് ചെയ്യുന്നത് നമുക്ക് ഒഴിവാക്കാം. അങ്ങനെയൊരു ജനറേറ്റർ ഉണ്ടാക്കാൻ, സ്‌ക്വയർ ബ്രാക്കറ്റുകൾക്ക് പകരം വട്ട ബ്രാക്കറ്റുകൾ (parentheses) ഇട്ടാൽ മാത്രം മതി: + +```py +training_corpus = ( + raw_datasets["train"][i : i + 1000]["whole_func_string"] + for i in range(0, len(raw_datasets["train"]), 1000) +) +``` + +ഈ കോഡ് വരി ഡേറ്റാസെറ്റിലെ ഒരു എലമെന്റും എടുക്കുന്നില്ല; ഒരു Python `for` ലൂപ്പിൽ നിങ്ങൾക്ക് ഉപയോഗിക്കാവുന്ന ഒരു ഒബ്‌ജക്റ്റ് മാത്രമാണ് അത് ഉണ്ടാക്കുന്നത്. ടെക്‌സ്‌റ്റുകൾ നിങ്ങൾക്ക് ആവശ്യമുള്ളപ്പോൾ മാത്രമേ ലോഡ് ചെയ്യപ്പെടുകയുള്ളൂ (അതായത്, അവ ആവശ്യമായ `for` ലൂപ്പിന്റെ സ്‌റ്റെപ്പിൽ നിങ്ങൾ എത്തുമ്പോൾ), ഒരു സമയം 1,000 ടെക്‌സ്‌റ്റുകൾ മാത്രമേ ലോഡ് ചെയ്യപ്പെടുകയുള്ളൂ. ഇങ്ങനെ, വളരെ വലിയ ഒരു ഡേറ്റാസെറ്റ് പ്രോസസ്സ് ചെയ്യുകയാണെങ്കിൽ പോലും നിങ്ങളുടെ മെമ്മറി മുഴുവൻ തീർന്നുപോകില്ല. + +ഒരു ജനറേറ്റർ ഒബ്‌ജക്റ്റിന്റെ പ്രശ്‌നം, അത് ഒരു തവണ മാത്രമേ ഉപയോഗിക്കാൻ കഴിയൂ എന്നതാണ്. അതുകൊണ്ട്, ഇത് ആദ്യത്തെ 10 അക്കങ്ങളുടെ ലിസ്‌റ്റ് രണ്ട് തവണ നൽകുന്നതിന് പകരം: + +```py +gen = (i for i in range(10)) +print(list(gen)) +print(list(gen)) +``` + +ഒരു തവണ അവയും പിന്നീട് ഒരു ഒഴിഞ്ഞ ലിസ്‌റ്റുമാണ് നമുക്ക് ലഭിക്കുന്നത്: + +```python out +[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] +[] +``` + +അതുകൊണ്ടാണ് പകരം ഒരു ജനറേറ്റർ റിട്ടേൺ ചെയ്യുന്ന ഒരു ഫംഗ്‌ഷൻ നമ്മൾ നിർവചിക്കുന്നത്: + +```py +def get_training_corpus(): + return ( + raw_datasets["train"][i : i + 1000]["whole_func_string"] + for i in range(0, len(raw_datasets["train"]), 1000) + ) + + +training_corpus = get_training_corpus() +``` + +`yield` സ്‌റ്റേറ്റ്‌മെന്റ് ഉപയോഗിച്ച് ഒരു `for` ലൂപ്പിനുള്ളിൽ നിങ്ങളുടെ ജനറേറ്റർ നിർവചിക്കാനും കഴിയും: + +```py +def get_training_corpus(): + dataset = raw_datasets["train"] + for start_idx in range(0, len(dataset), 1000): + samples = dataset[start_idx : start_idx + 1000] + yield samples["whole_func_string"] +``` + +ഇത് മുമ്പത്തെ അതേ ജനറേറ്റർ തന്നെ ഉണ്ടാക്കും, എന്നാൽ ഒരു ലിസ്‌റ്റ് കോംപ്രിഹെൻഷനിൽ (list comprehension) സാധ്യമാകുന്നതിനെക്കാൾ സങ്കീർണ്ണമായ ലോജിക് ഉപയോഗിക്കാൻ ഇത് നിങ്ങളെ അനുവദിക്കുന്നു. + +## ഒരു പുതിയ ടോക്കണൈസർ ട്രെയിൻ ചെയ്യുന്നു[[training-a-new-tokenizer]] + +ടെക്‌സ്‌റ്റുകളുടെ ബാച്ചുകളുടെ ഒരു ഇറ്ററേറ്റർ എന്ന രൂപത്തിൽ നമ്മുടെ കോർപ്പസ് ഇപ്പോൾ നമ്മുടെ കൈയിലുള്ളതിനാൽ, ഒരു പുതിയ ടോക്കണൈസർ ട്രെയിൻ ചെയ്യാൻ നമ്മൾ തയ്യാറാണ്. ഇതിനായി, നമ്മുടെ മോഡലിനൊപ്പം (ഇവിടെ, GPT-2) ചേർത്ത് ഉപയോഗിക്കാൻ ആഗ്രഹിക്കുന്ന ടോക്കണൈസർ ആദ്യം നമ്മൾ ലോഡ് ചെയ്യണം: + +```py +from transformers import AutoTokenizer + +old_tokenizer = AutoTokenizer.from_pretrained("gpt2") +``` + +നമ്മൾ ഒരു പുതിയ ടോക്കണൈസർ ട്രെയിൻ ചെയ്യാൻ പോകുന്നുവെങ്കിലും, പൂർണ്ണമായും പൂജ്യത്തിൽ നിന്ന് തുടങ്ങുന്നത് ഒഴിവാക്കാൻ ഇങ്ങനെ ചെയ്യുന്നത് നല്ലൊരു ആശയമാണ്. ഇങ്ങനെയാകുമ്പോൾ, ടോക്കണൈസേഷൻ അൽഗോരിതത്തെക്കുറിച്ചോ നമ്മൾ ഉപയോഗിക്കാൻ ആഗ്രഹിക്കുന്ന സ്‌പെഷ്യൽ ടോക്കണുകളെക്കുറിച്ചോ ഒന്നും നമ്മൾ വ്യക്തമാക്കേണ്ടതില്ല; നമ്മുടെ പുതിയ ടോക്കണൈസർ GPT-2-ന്റേതിന് തികച്ചും സമാനമായിരിക്കും, മാറുന്ന ഒരേയൊരു കാര്യം വൊക്കാബുലറി (vocabulary) മാത്രമാണ് — അത് നമ്മുടെ കോർപ്പസിലെ ട്രെയിനിംഗിലൂടെ നിർണ്ണയിക്കപ്പെടും. + +ആദ്യം, ഒരു ഉദാഹരണ ഫംഗ്‌ഷനെ ഈ ടോക്കണൈസർ എങ്ങനെ കൈകാര്യം ചെയ്യുമെന്ന് നമുക്ക് നോക്കാം: + +```py +example = '''def add_numbers(a, b): + """Add the two numbers `a` and `b`.""" + return a + b''' + +tokens = old_tokenizer.tokenize(example) +tokens +``` + +```python out +['def', 'Ġadd', '_', 'n', 'umbers', '(', 'a', ',', 'Ġb', '):', 'Ċ', 'Ġ', 'Ġ', 'Ġ', 'Ġ"""', 'Add', 'Ġthe', 'Ġtwo', + 'Ġnumbers', 'Ġ`', 'a', '`', 'Ġand', 'Ġ`', 'b', '`', '."', '""', 'Ċ', 'Ġ', 'Ġ', 'Ġ', 'Ġreturn', 'Ġa', 'Ġ+', 'Ġb'] +``` + +ഈ ടോക്കണൈസറിന് `Ġ`, `Ċ` പോലുള്ള ചില പ്രത്യേക ചിഹ്നങ്ങളുണ്ട്; ഇവ യഥാക്രമം സ്‌പേസുകളെയും ന്യൂലൈനുകളെയും (newlines) സൂചിപ്പിക്കുന്നു. നമുക്ക് കാണാവുന്നതുപോലെ, ഇത് അത്ര കാര്യക്ഷമമല്ല: ഇൻഡന്റേഷൻ ലെവലുകൾ ഒരുമിച്ച് ഗ്രൂപ്പ് ചെയ്യാമായിരുന്നിട്ടും (നാലോ എട്ടോ സ്‌പേസുകളുടെ കൂട്ടങ്ങൾ കോഡിൽ വളരെ സാധാരണമായിരിക്കും എന്നതിനാൽ), ഓരോ സ്‌പേസിനും ടോക്കണൈസർ പ്രത്യേകം ടോക്കണുകൾ റിട്ടേൺ ചെയ്യുന്നു. `_` എന്ന ക്യാരക്ടറുള്ള വാക്കുകൾ കാണാൻ ശീലമില്ലാത്തതിനാൽ, ഫംഗ്‌ഷന്റെ പേരും അത് കുറച്ച് വിചിത്രമായി വിഭജിച്ചു. + +ഒരു പുതിയ ടോക്കണൈസർ ട്രെയിൻ ചെയ്ത് അത് ഈ പ്രശ്‌നങ്ങൾ പരിഹരിക്കുന്നുണ്ടോ എന്ന് നോക്കാം. ഇതിനായി, `train_new_from_iterator()` മെത്തേഡ് നമ്മൾ ഉപയോഗിക്കും: + +```py +tokenizer = old_tokenizer.train_new_from_iterator(training_corpus, 52000) +``` + +നിങ്ങളുടെ കോർപ്പസ് വളരെ വലുതാണെങ്കിൽ ഈ കമാൻഡിന് കുറച്ച് സമയമെടുത്തേക്കാം, എന്നാൽ 1.6 GB ടെക്‌സ്‌റ്റുകളുള്ള ഈ ഡേറ്റാസെറ്റിന് ഇത് അതിവേഗത്തിലാണ് (12 കോറുകളുള്ള ഒരു AMD Ryzen 9 3900X CPU-വിൽ 1 മിനിറ്റ് 16 സെക്കൻഡ്). + +നിങ്ങൾ ഉപയോഗിക്കുന്ന ടോക്കണൈസർ ഒരു "ഫാസ്‌റ്റ്" ടോക്കണൈസർ ആണെങ്കിൽ മാത്രമേ `AutoTokenizer.train_new_from_iterator()` പ്രവർത്തിക്കുകയുള്ളൂ എന്നത് ശ്രദ്ധിക്കുക. അടുത്ത ഭാഗത്തിൽ നിങ്ങൾ കാണാൻ പോകുന്നതുപോലെ, 🤗 Transformers ലൈബ്രറിയിൽ രണ്ട് തരം ടോക്കണൈസറുകളുണ്ട്: ചിലത് പൂർണ്ണമായും Python-ൽ എഴുതിയവയാണ്, മറ്റുള്ളവയ്ക്ക് (ഫാസ്‌റ്റ് ടോക്കണൈസറുകൾക്ക്) [Rust](https://www.rust-lang.org) പ്രോഗ്രാമിംഗ് ഭാഷയിൽ എഴുതിയ 🤗 Tokenizers ലൈബ്രറിയുടെ പിന്തുണയുണ്ട്. ഡേറ്റാ സയൻസിനും ഡീപ് ലേണിംഗ് ആപ്ലിക്കേഷനുകൾക്കും ഏറ്റവും കൂടുതൽ ഉപയോഗിക്കുന്ന ഭാഷ Python ആണ്, എന്നാൽ എന്തെങ്കിലും വേഗത്തിലാക്കാൻ പാരലലൈസ് ചെയ്യേണ്ടിവരുമ്പോൾ, അത് മറ്റൊരു ഭാഷയിൽ എഴുതേണ്ടിവരും. ഉദാഹരണത്തിന്, മോഡൽ കംപ്യൂട്ടേഷന്റെ കാതലായ മാട്രിക്‌സ് ഗുണനങ്ങൾ (matrix multiplications) GPU-കൾക്കായുള്ള ഒപ്‌റ്റിമൈസ് ചെയ്ത ഒരു C ലൈബ്രറിയായ CUDA-യിലാണ് എഴുതിയിരിക്കുന്നത്. + +തികച്ചും പുതിയ ഒരു ടോക്കണൈസർ ശുദ്ധമായ Python-ൽ ട്രെയിൻ ചെയ്യുന്നത് അസഹനീയമാംവിധം പതുക്കെയായിരിക്കും; അതുകൊണ്ടാണ് ഞങ്ങൾ 🤗 Tokenizers ലൈബ്രറി വികസിപ്പിച്ചത്. ഒരു GPU-വിൽ ഇൻപുട്ടുകളുടെ ഒരു ബാച്ചിൽ നിങ്ങളുടെ മോഡൽ എക്‌സിക്യൂട്ട് ചെയ്യാൻ നിങ്ങൾക്ക് CUDA ഭാഷ പഠിക്കേണ്ടിവന്നില്ല എന്നതുപോലെ, ഒരു ഫാസ്‌റ്റ് ടോക്കണൈസർ ഉപയോഗിക്കാൻ നിങ്ങൾ Rust പഠിക്കേണ്ടതില്ല എന്നത് ശ്രദ്ധിക്കുക. ആന്തരികമായി Rust-ലെ ഏതെങ്കിലും കോഡ് ഭാഗം വിളിക്കുന്ന നിരവധി മെത്തേഡുകൾക്ക് 🤗 Tokenizers ലൈബ്രറി Python ബൈൻഡിംഗുകൾ നൽകുന്നു; ഉദാഹരണത്തിന്, നിങ്ങളുടെ പുതിയ ടോക്കണൈസറിന്റെ ട്രെയിനിംഗ് പാരലലൈസ് ചെയ്യാൻ, അല്ലെങ്കിൽ [അധ്യായം 3](/course/chapter3)-ൽ നമ്മൾ കണ്ടതുപോലെ, ഇൻപുട്ടുകളുടെ ഒരു ബാച്ചിന്റെ ടോക്കണൈസേഷന്. + +മിക്ക Transformer മോഡലുകൾക്കും ഒരു ഫാസ്‌റ്റ് ടോക്കണൈസർ ലഭ്യമാണ് (ചില അപവാദങ്ങളുണ്ട്, അവ നിങ്ങൾക്ക് [ഇവിടെ](https://huggingface.co/transformers/#supported-frameworks) പരിശോധിക്കാം), കൂടാതെ ലഭ്യമാണെങ്കിൽ `AutoTokenizer` API എപ്പോഴും ഫാസ്‌റ്റ് ടോക്കണൈസർ തന്നെയാണ് നിങ്ങൾക്കായി തിരഞ്ഞെടുക്കുന്നത്. അടുത്ത ഭാഗത്തിൽ, ഫാസ്‌റ്റ് ടോക്കണൈസറുകളുടെ മറ്റ് ചില പ്രത്യേക ഫീച്ചറുകൾ നമ്മൾ പരിശോധിക്കും; ടോക്കൺ ക്ലാസിഫിക്കേഷൻ, ക്വസ്‌ചൻ ആൻസറിംഗ് പോലുള്ള ടാസ്‌ക്കുകൾക്ക് ഇവ വളരെ ഉപകാരപ്രദമായിരിക്കും. എന്നാൽ അതിലേക്ക് കടക്കുന്നതിന് മുമ്പ്, നമ്മുടെ തികച്ചും പുതിയ ടോക്കണൈസർ മുമ്പത്തെ ഉദാഹരണത്തിൽ ഒന്ന് പരീക്ഷിക്കാം: + +```py +tokens = tokenizer.tokenize(example) +tokens +``` + +```python out +['def', 'Ġadd', '_', 'numbers', '(', 'a', ',', 'Ġb', '):', 'ĊĠĠĠ', 'Ġ"""', 'Add', 'Ġthe', 'Ġtwo', 'Ġnumbers', 'Ġ`', + 'a', '`', 'Ġand', 'Ġ`', 'b', '`."""', 'ĊĠĠĠ', 'Ġreturn', 'Ġa', 'Ġ+', 'Ġb'] +``` + +സ്‌പേസുകളെയും ന്യൂലൈനുകളെയും സൂചിപ്പിക്കുന്ന `Ġ`, `Ċ` എന്ന പ്രത്യേക ചിഹ്നങ്ങൾ ഇവിടെയും നമ്മൾ കാണുന്നു, എന്നാൽ Python ഫംഗ്‌ഷനുകളുടെ ഒരു കോർപ്പസിന് വളരെ പ്രത്യേകമായ ചില ടോക്കണുകൾ നമ്മുടെ ടോക്കണൈസർ പഠിച്ചെടുത്തതായും നമുക്ക് കാണാം: ഉദാഹരണത്തിന്, ഒരു ഇൻഡന്റേഷനെ പ്രതിനിധീകരിക്കുന്ന ഒരു `ĊĠĠĠ` ടോക്കണും, ഒരു ഡോക്‌സ്‌ട്രിംഗ് ആരംഭിക്കുന്ന മൂന്ന് ഉദ്ധരണചിഹ്നങ്ങളെ പ്രതിനിധീകരിക്കുന്ന ഒരു `Ġ"""` ടോക്കണും ഉണ്ട്. ഫംഗ്‌ഷന്റെ പേര് `_`-ൽ ടോക്കണൈസർ ശരിയായി വിഭജിക്കുകയും ചെയ്തു. ഇത് വളരെ ഒതുക്കമുള്ള ഒരു പ്രതിനിധാനമാണ്; താരതമ്യേന, അതേ ഉദാഹരണത്തിൽ സാധാരണ ഇംഗ്ലീഷ് ടോക്കണൈസർ ഉപയോഗിക്കുന്നത് കൂടുതൽ നീളമുള്ള ഒരു വാക്യം നമുക്ക് നൽകും: + +```py +print(len(tokens)) +print(len(old_tokenizer.tokenize(example))) +``` + +```python out +27 +36 +``` + +മറ്റൊരു ഉദാഹരണം നോക്കാം: + +```python +example = """class LinearLayer(): + def __init__(self, input_size, output_size): + self.weight = torch.randn(input_size, output_size) + self.bias = torch.zeros(output_size) + + def __call__(self, x): + return x @ self.weights + self.bias + """ +tokenizer.tokenize(example) +``` + +```python out +['class', 'ĠLinear', 'Layer', '():', 'ĊĠĠĠ', 'Ġdef', 'Ġ__', 'init', '__(', 'self', ',', 'Ġinput', '_', 'size', ',', + 'Ġoutput', '_', 'size', '):', 'ĊĠĠĠĠĠĠĠ', 'Ġself', '.', 'weight', 'Ġ=', 'Ġtorch', '.', 'randn', '(', 'input', '_', + 'size', ',', 'Ġoutput', '_', 'size', ')', 'ĊĠĠĠĠĠĠĠ', 'Ġself', '.', 'bias', 'Ġ=', 'Ġtorch', '.', 'zeros', '(', + 'output', '_', 'size', ')', 'ĊĊĠĠĠ', 'Ġdef', 'Ġ__', 'call', '__(', 'self', ',', 'Ġx', '):', 'ĊĠĠĠĠĠĠĠ', + 'Ġreturn', 'Ġx', 'Ġ@', 'Ġself', '.', 'weights', 'Ġ+', 'Ġself', '.', 'bias', 'ĊĠĠĠĠ'] +``` + +ഒരു ഇൻഡന്റേഷനുമായി ബന്ധപ്പെട്ട ടോക്കണിന് പുറമേ, ഇവിടെ ഒരു ഡബിൾ ഇൻഡന്റേഷനുള്ള ഒരു ടോക്കണും നമുക്ക് കാണാം: `ĊĠĠĠĠĠĠĠ`. `class`, `init`, `call`, `self`, `return` പോലുള്ള പ്രത്യേക Python വാക്കുകൾ ഓരോന്നും ഒറ്റ ടോക്കണായി ടോക്കണൈസ് ചെയ്യപ്പെടുന്നു; കൂടാതെ `_`, `.` എന്നിവയിൽ വിഭജിക്കുന്നതിനൊപ്പം, ക്യാമൽ-കേസ് (camel-cased) പേരുകൾ പോലും ടോക്കണൈസർ ശരിയായി വിഭജിക്കുന്നതായി നമുക്ക് കാണാം: `LinearLayer` എന്നത് `["ĠLinear", "Layer"]` എന്നാണ് ടോക്കണൈസ് ചെയ്യപ്പെടുന്നത്. + +## ടോക്കണൈസർ സേവ് ചെയ്യുന്നു[[saving-the-tokenizer]] + +പിന്നീട് ഉപയോഗിക്കാൻ കഴിയുമെന്ന് ഉറപ്പാക്കാൻ, നമ്മുടെ പുതിയ ടോക്കണൈസർ നമ്മൾ സേവ് ചെയ്യണം. മോഡലുകളുടെ കാര്യത്തിലേതുപോലെ, ഇത് `save_pretrained()` മെത്തേഡ് ഉപയോഗിച്ചാണ് ചെയ്യുന്നത്: + +```py +tokenizer.save_pretrained("code-search-net-tokenizer") +``` + +ഇത് *code-search-net-tokenizer* എന്ന പേരിൽ ഒരു പുതിയ ഫോൾഡർ ഉണ്ടാക്കും; ടോക്കണൈസർ വീണ്ടും ലോഡ് ചെയ്യാൻ ആവശ്യമായ എല്ലാ ഫയലുകളും അതിൽ ഉണ്ടാകും. ഈ ടോക്കണൈസർ നിങ്ങളുടെ സഹപ്രവർത്തകരുമായും സുഹൃത്തുക്കളുമായും പങ്കുവയ്ക്കണമെങ്കിൽ, നിങ്ങളുടെ അക്കൗണ്ടിലേക്ക് ലോഗിൻ ചെയ്ത് അത് Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യാം. നിങ്ങൾ ഒരു നോട്ട്‌ബുക്കിലാണ് പ്രവർത്തിക്കുന്നതെങ്കിൽ, ഇതിന് നിങ്ങളെ സഹായിക്കാൻ സൗകര്യപ്രദമായ ഒരു ഫംഗ്‌ഷൻ ഉണ്ട്: + +```python +from huggingface_hub import notebook_login + +notebook_login() +``` + +നിങ്ങളുടെ Hugging Face ലോഗിൻ വിവരങ്ങൾ (credentials) നൽകാവുന്ന ഒരു വിജറ്റ് ഇത് കാണിക്കും. നിങ്ങൾ ഒരു നോട്ട്‌ബുക്കിലല്ല പ്രവർത്തിക്കുന്നതെങ്കിൽ, നിങ്ങളുടെ ടെർമിനലിൽ താഴെപ്പറയുന്ന വരി ടൈപ്പ് ചെയ്താൽ മതി: + +```bash +huggingface-cli login +``` + +ലോഗിൻ ചെയ്തുകഴിഞ്ഞാൽ, താഴെപ്പറയുന്ന കമാൻഡ് എക്‌സിക്യൂട്ട് ചെയ്തുകൊണ്ട് നിങ്ങളുടെ ടോക്കണൈസർ പുഷ് ചെയ്യാം: + +```py +tokenizer.push_to_hub("code-search-net-tokenizer") +``` + +ഇത് നിങ്ങളുടെ നെയിംസ്‌പേസിൽ `code-search-net-tokenizer` എന്ന പേരിൽ, ടോക്കണൈസർ ഫയൽ അടങ്ങിയ ഒരു പുതിയ റിപ്പോസിറ്ററി ഉണ്ടാക്കും. പിന്നീട് `from_pretrained()` മെത്തേഡ് ഉപയോഗിച്ച് എവിടെനിന്നും നിങ്ങൾക്ക് ടോക്കണൈസർ ലോഡ് ചെയ്യാം: + +```py +# Replace "huggingface-course" below with your actual namespace to use your own tokenizer +tokenizer = AutoTokenizer.from_pretrained("huggingface-course/code-search-net-tokenizer") +``` + +ഒരു ലാംഗ്വേജ് മോഡൽ പൂജ്യത്തിൽ നിന്ന് ട്രെയിൻ ചെയ്യാനും നിങ്ങളുടെ കൈയിലുള്ള ടാസ്‌ക്കിൽ അത് ഫൈൻ-ട്യൂൻ ചെയ്യാനും നിങ്ങൾ ഇപ്പോൾ പൂർണ്ണമായി തയ്യാറാണ്! [അധ്യായം 7](/course/chapter7)-ൽ നമ്മൾ അതിലേക്ക് എത്തും, എന്നാൽ ആദ്യം, ഈ അധ്യായത്തിന്റെ ബാക്കി ഭാഗത്ത് ഫാസ്‌റ്റ് ടോക്കണൈസറുകളെ നമ്മൾ കൂടുതൽ അടുത്ത് പരിശോധിക്കും, കൂടാതെ `train_new_from_iterator()` മെത്തേഡ് വിളിക്കുമ്പോൾ യഥാർത്ഥത്തിൽ എന്താണ് സംഭവിക്കുന്നത് എന്ന് വിശദമായി പരിശോധിക്കും. diff --git a/chapters/ml/chapter6/3.mdx b/chapters/ml/chapter6/3.mdx new file mode 100644 index 000000000..727a3e2d5 --- /dev/null +++ b/chapters/ml/chapter6/3.mdx @@ -0,0 +1,464 @@ + + +# ഫാസ്‌റ്റ് ടോക്കണൈസറുകളുടെ പ്രത്യേക ശക്തികൾ[[fast-tokenizers-special-powers]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +ഈ ഭാഗത്തിൽ 🤗 Transformers-ലെ ടോക്കണൈസറുകളുടെ കഴിവുകൾ നമ്മൾ കൂടുതൽ അടുത്തറിയാൻ പോകുന്നു. ഇതുവരെ ഇൻപുട്ടുകൾ ടോക്കണൈസ് ചെയ്യാനോ ID-കൾ തിരികെ ടെക്‌സ്‌റ്റാക്കി ഡീകോഡ് ചെയ്യാനോ മാത്രമേ നമ്മൾ അവ ഉപയോഗിച്ചിട്ടുള്ളൂ; എന്നാൽ ടോക്കണൈസറുകൾക്ക് -- പ്രത്യേകിച്ച് 🤗 Tokenizers ലൈബ്രറിയുടെ പിന്തുണയുള്ളവയ്ക്ക് -- ഇതിലും ഒരുപാട് കാര്യങ്ങൾ ചെയ്യാൻ കഴിയും. ഈ അധിക ഫീച്ചറുകൾ വ്യക്തമാക്കാൻ, [അധ്യായം 1](/course/chapter1)-ൽ നമ്മൾ ആദ്യമായി കണ്ടുമുട്ടിയ `token-classification` (`ner` എന്ന് നമ്മൾ വിളിച്ചത്), `question-answering` എന്നീ പൈപ്പ്‌ലൈനുകളുടെ ഫലങ്ങൾ എങ്ങനെ പുനഃസൃഷ്ടിക്കാമെന്ന് നമ്മൾ പരിശോധിക്കും. + + + +തുടർന്നുള്ള ചർച്ചയിൽ, "സ്ലോ" (slow) ടോക്കണൈസറുകളും "ഫാസ്‌റ്റ്" (fast) ടോക്കണൈസറുകളും തമ്മിലുള്ള വ്യത്യാസം നമ്മൾ പലപ്പോഴും എടുത്തുപറയും. 🤗 Transformers ലൈബ്രറിക്കുള്ളിൽ Python-ൽ എഴുതിയവയാണ് സ്ലോ ടോക്കണൈസറുകൾ; അതേസമയം Rust-ൽ എഴുതിയ, 🤗 Tokenizers നൽകുന്നവയാണ് ഫാസ്‌റ്റ് പതിപ്പുകൾ. Drug Review Dataset ടോക്കണൈസ് ചെയ്യാൻ ഒരു ഫാസ്‌റ്റ് ടോക്കണൈസറും ഒരു സ്ലോ ടോക്കണൈസറും എത്ര സമയമെടുത്തു എന്ന് കാണിച്ച [അധ്യായം 5](/course/chapter5/3)-ലെ ടേബിൽ നിങ്ങൾ ഓർക്കുന്നുണ്ടെങ്കിൽ, അവയെ എന്തുകൊണ്ട് ഫാസ്‌റ്റ്, സ്ലോ എന്ന് വിളിക്കുന്നു എന്നതിനെക്കുറിച്ച് നിങ്ങൾക്ക് ഒരു ധാരണ ഉണ്ടായിരിക്കും: + +| | ഫാസ്‌റ്റ് ടോക്കണൈസർ | സ്ലോ ടോക്കണൈസർ +:--------------:|:--------------:|:-------------: +`batched=True` | 10.8s | 4min41s +`batched=False` | 59.2s | 5min3s + +> [!WARNING] +> ⚠️ ഒരൊറ്റ വാക്യം ടോക്കണൈസ് ചെയ്യുമ്പോൾ, ഒരേ ടോക്കണൈസറിന്റെ സ്ലോ, ഫാസ്‌റ്റ് പതിപ്പുകൾ തമ്മിൽ വേഗതയിൽ വ്യത്യാസം എപ്പോഴും നിങ്ങൾ കാണണമെന്നില്ല. വാസ്തവത്തിൽ, ഫാസ്‌റ്റ് പതിപ്പ് കൂടുതൽ പതുക്കെയായിരിക്കാനും സാധ്യതയുണ്ട്! ധാരാളം ടെക്‌സ്‌റ്റുകൾ ഒരേ സമയം പാരലലായി ടോക്കണൈസ് ചെയ്യുമ്പോൾ മാത്രമേ ഈ വ്യത്യാസം നിങ്ങൾക്ക് വ്യക്തമായി കാണാൻ കഴിയൂ. + +## ബാച്ച് എൻകോഡിംഗ്[[batch-encoding]] + + + +ഒരു ടോക്കണൈസറിന്റെ ഔട്ട്‌പുട്ട് ഒരു സാധാരണ Python ഡിക്‌ഷണറിയല്ല; നമുക്ക് ലഭിക്കുന്നത് യഥാർത്ഥത്തിൽ ഒരു പ്രത്യേക `BatchEncoding` ഒബ്‌ജക്റ്റാണ്. ഇത് ഡിക്‌ഷണറിയുടെ ഒരു സബ്‌ക്ലാസാണ് (അതുകൊണ്ടാണ് മുമ്പ് ആ ഫലത്തിലേക്ക് ഒരു പ്രശ്നവുമില്ലാതെ ഇൻഡെക്‌സ് ചെയ്യാൻ നമുക്ക് കഴിഞ്ഞത്); എന്നാൽ പ്രധാനമായും ഫാസ്‌റ്റ് ടോക്കണൈസറുകൾ ഉപയോഗിക്കുന്ന ചില അധിക മെത്തേഡുകളും ഇതിനുണ്ട്. + +പാരലലൈസേഷൻ കഴിവുകൾക്ക് പുറമേ, ഫാസ്‌റ്റ് ടോക്കണൈസറുകളുടെ പ്രധാന സവിശേഷത, അന്തിമ ടോക്കണുകൾ വരുന്ന ടെക്‌സ്‌റ്റിന്റെ യഥാർത്ഥ സ്‌പാൻ (span) അവ എപ്പോഴും ട്രാക്ക് ചെയ്യുന്നു എന്നതാണ് -- ഈ ഫീച്ചറിനെ നമ്മൾ *ഓഫ്‌സെറ്റ് മാപ്പിംഗ്* (offset mapping) എന്ന് വിളിക്കുന്നു. ഓരോ വാക്കിനെയും അത് സൃഷ്ടിച്ച ടോക്കണുകളുമായി ബന്ധിപ്പിക്കുക, യഥാർത്ഥ ടെക്‌സ്‌റ്റിലെ ഓരോ അക്ഷരത്തെയും (character) അത് ഉൾപ്പെടുന്ന ടോക്കണുമായി ബന്ധിപ്പിക്കുക, ഇവ തിരിച്ചും ചെയ്യുക തുടങ്ങിയ ഫീച്ചറുകൾ ഇത് സാധ്യമാക്കുന്നു. + +ഒരു ഉദാഹരണം നോക്കാം: + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +example = "My name is Sylvain and I work at Hugging Face in Brooklyn." +encoding = tokenizer(example) +print(type(encoding)) +``` + +മുമ്പ് പറഞ്ഞതുപോലെ, ടോക്കണൈസറിന്റെ ഔട്ട്‌പുട്ടിൽ നമുക്ക് ഒരു `BatchEncoding` ഒബ്‌ജക്റ്റ് ലഭിക്കുന്നു: + +```python out + +``` + +`AutoTokenizer` ക്ലാസ് ഡിഫോൾട്ടായി ഒരു ഫാസ്‌റ്റ് ടോക്കണൈസറാണ് തിരഞ്ഞെടുക്കുന്നത് എന്നതിനാൽ, ഈ `BatchEncoding` ഒബ്‌ജക്റ്റ് നൽകുന്ന അധിക മെത്തേഡുകൾ നമുക്ക് ഉപയോഗിക്കാം. നമ്മുടെ ടോക്കണൈസർ ഫാസ്‌റ്റാണോ സ്ലോ ആണോ എന്ന് പരിശോധിക്കാൻ രണ്ട് വഴികളുണ്ട്. ഒന്നുകിൽ `tokenizer`-ന്റെ `is_fast` ആട്രിബ്യൂട്ട് പരിശോധിക്കാം: + +```python +tokenizer.is_fast +``` + +```python out +True +``` + +അല്ലെങ്കിൽ നമ്മുടെ `encoding`-ന്റെ അതേ ആട്രിബ്യൂട്ട് പരിശോധിക്കാം: + +```python +encoding.is_fast +``` + +```python out +True +``` + +ഒരു ഫാസ്‌റ്റ് ടോക്കണൈസർ നമുക്ക് എന്തെല്ലാം ചെയ്യാൻ സഹായിക്കുന്നു എന്ന് നോക്കാം. ആദ്യമായി, ID-കളെ തിരികെ ടോക്കണുകളാക്കി മാറ്റാതെ തന്നെ നമുക്ക് ടോക്കണുകൾ ആക്‌സസ് ചെയ്യാം: + +```py +encoding.tokens() +``` + +```python out +['[CLS]', 'My', 'name', 'is', 'S', '##yl', '##va', '##in', 'and', 'I', 'work', 'at', 'Hu', '##gging', 'Face', 'in', + 'Brooklyn', '.', '[SEP]'] +``` + +ഇവിടെ ഇൻഡെക്‌സ് 5-ലെ ടോക്കൺ `##yl` ആണ്; യഥാർത്ഥ വാക്യത്തിലെ "Sylvain" എന്ന വാക്കിന്റെ ഒരു ഭാഗമാണിത്. ഓരോ ടോക്കണും ഏത് വാക്കിൽ നിന്നാണ് വരുന്നത് എന്നതിന്റെ ഇൻഡെക്‌സ് ലഭിക്കാൻ `word_ids()` മെത്തേഡും നമുക്ക് ഉപയോഗിക്കാം: + +```py +encoding.word_ids() +``` + +```python out +[None, 0, 1, 2, 3, 3, 3, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 12, None] +``` + +ടോക്കണൈസറിന്റെ സ്‌പെഷ്യൽ ടോക്കണുകളായ `[CLS]`, `[SEP]` എന്നിവ `None`-ലേക്ക് മാപ്പ് ചെയ്യപ്പെട്ടിരിക്കുന്നതും, തുടർന്ന് ഓരോ ടോക്കണും അത് ഉത്ഭവിച്ച വാക്കിലേക്ക് മാപ്പ് ചെയ്യപ്പെട്ടിരിക്കുന്നതും നമുക്ക് കാണാം. ഒരു ടോക്കൺ ഒരു വാക്കിന്റെ തുടക്കത്തിലാണോ, അല്ലെങ്കിൽ രണ്ട് ടോക്കണുകൾ ഒരേ വാക്കിലാണോ എന്ന് നിർണ്ണയിക്കാൻ ഇത് പ്രത്യേകിച്ചും ഉപകാരപ്രദമാണ്. അതിനായി `##` എന്ന പ്രിഫിക്‌സിനെ നമുക്ക് ആശ്രയിക്കാമായിരുന്നു, എന്നാൽ അത് BERT-പോലുള്ള ടോക്കണൈസറുകൾക്ക് മാത്രമേ പ്രവർത്തിക്കൂ; ഈ മെത്തേഡ് ഫാസ്‌റ്റ് ആണെങ്കിൽ ഏത് തരം ടോക്കണൈസറിനും പ്രവർത്തിക്കും. നെയിംഡ് എന്റിറ്റി റെക്കഗ്നിഷൻ (NER), പാർട്ട്-ഓഫ്-സ്‌പീച്ച് (POS) ടാഗിംഗ് പോലുള്ള ടാസ്‌ക്കുകളിൽ, ഓരോ വാക്കിനും നമ്മുടെ പക്കലുള്ള ലേബലുകൾ ടോക്കണുകളിലേക്ക് ശരിയായി പ്രയോഗിക്കാൻ ഈ കഴിവ് എങ്ങനെ ഉപയോഗിക്കാമെന്ന് അടുത്ത അധ്യായത്തിൽ നമ്മൾ കാണും. മാസ്‌ക്‌ഡ് ലാംഗ്വേജ് മോഡലിംഗിൽ ഒരേ വാക്കിൽ നിന്ന് വരുന്ന എല്ലാ ടോക്കണുകളും മാസ്‌ക് ചെയ്യാനും ഇത് നമുക്ക് ഉപയോഗിക്കാം (_whole word masking_ എന്നറിയപ്പെടുന്ന ഒരു സങ്കേതമാണിത്). + +> [!TIP] +> ഒരു വാക്ക് എന്താണ് എന്ന ധാരണ സങ്കീർണ്ണമാണ്. ഉദാഹരണത്തിന്, "I'll" ("I will"-ന്റെ ചുരുക്കരൂപം) ഒരു വാക്കായാണോ രണ്ട് വാക്കായാണോ കണക്കാക്കേണ്ടത്? അത് യഥാർത്ഥത്തിൽ ടോക്കണൈസറിനെയും അത് പ്രയോഗിക്കുന്ന പ്രീ-ടോക്കണൈസേഷൻ (pre-tokenization) ഓപ്പറേഷനെയും ആശ്രയിച്ചിരിക്കുന്നു. ചില ടോക്കണൈസറുകൾ സ്‌പേസുകളിൽ മാത്രമാണ് വിഭജിക്കുന്നത്, അതിനാൽ അവ ഇതിനെ ഒരു വാക്കായി കണക്കാക്കും. മറ്റുള്ളവ സ്‌പേസുകൾക്കൊപ്പം ചിഹ്നങ്ങളും (punctuation) ഉപയോഗിക്കുന്നു, അതിനാൽ അവ ഇതിനെ രണ്ട് വാക്കുകളായി കണക്കാക്കും. +> +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** `bert-base-cased`, `roberta-base` ചെക്ക്‌പോയിന്റുകളിൽ നിന്ന് ഓരോ ടോക്കണൈസർ നിർമ്മിച്ച് അവ ഉപയോഗിച്ച് "81s" ടോക്കണൈസ് ചെയ്യുക. നിങ്ങൾ എന്താണ് നിരീക്ഷിക്കുന്നത്? വേഡ് ID-കൾ എന്തൊക്കെയാണ്? + +അതുപോലെ, ഒരു ടോക്കണിനെ അത് വന്ന വാക്യവുമായി ബന്ധിപ്പിക്കാൻ ഉപയോഗിക്കാവുന്ന ഒരു `sentence_ids()` മെത്തേഡും ഉണ്ട് (ഈ സാഹചര്യത്തിൽ, ടോക്കണൈസർ റിട്ടേൺ ചെയ്യുന്ന `token_type_ids` നമുക്ക് അതേ വിവരം നൽകുമെങ്കിലും). + +അവസാനമായി, `word_to_chars()` അല്ലെങ്കിൽ `token_to_chars()`, `char_to_word()` അല്ലെങ്കിൽ `char_to_token()` എന്നീ മെത്തേഡുകൾ വഴി ഏത് വാക്കിനെയോ ടോക്കണിനെയോ യഥാർത്ഥ ടെക്‌സ്‌റ്റിലെ അക്ഷരങ്ങളുമായി ബന്ധിപ്പിക്കാം, തിരിച്ചും ചെയ്യാം. ഉദാഹരണത്തിന്, `##yl` എന്നത് ഇൻഡെക്‌സ് 3-ലെ വാക്കിന്റെ ഭാഗമാണെന്ന് `word_ids()` മെത്തേഡ് നമ്മോട് പറഞ്ഞു; എന്നാൽ വാക്യത്തിലെ ഏത് വാക്കാണ് അത്? ഇങ്ങനെ നമുക്ക് കണ്ടെത്താം: + +```py +start, end = encoding.word_to_chars(3) +example[start:end] +``` + +```python out +Sylvain +``` + +മുമ്പ് സൂചിപ്പിച്ചതുപോലെ, ഓരോ ടോക്കണും വരുന്ന ടെക്‌സ്‌റ്റ് സ്‌പാൻ *ഓഫ്‌സെറ്റുകളുടെ* (offsets) ഒരു ലിസ്‌റ്റിൽ ഫാസ്‌റ്റ് ടോക്കണൈസർ ട്രാക്ക് ചെയ്യുന്നു എന്ന വസ്തുതയാണ് ഇതെല്ലാം സാധ്യമാക്കുന്നത്. അവയുടെ ഉപയോഗം വ്യക്തമാക്കാൻ, `token-classification` പൈപ്പ്‌ലൈനിന്റെ ഫലങ്ങൾ എങ്ങനെ സ്വന്തമായി (manually) പുനഃസൃഷ്ടിക്കാമെന്ന് അടുത്തതായി ഞങ്ങൾ നിങ്ങൾക്ക് കാണിച്ചുതരാം. + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** നിങ്ങളുടെ സ്വന്തം ഉദാഹരണ ടെക്‌സ്‌റ്റ് ഉണ്ടാക്കി, ഏതൊക്കെ ടോക്കണുകളാണ് ഓരോ വേഡ് ID-യുമായി ബന്ധപ്പെട്ടിരിക്കുന്നത് എന്ന് നിങ്ങൾക്ക് മനസ്സിലാക്കാൻ കഴിയുമോ എന്നും, ഒരൊറ്റ വാക്കിന്റെ ക്യാരക്റ്റർ സ്‌പാനുകൾ എങ്ങനെ എടുക്കാമെന്നും നോക്കുക. ബോണസ് പോയിന്റുകൾക്കായി, രണ്ട് വാക്യങ്ങൾ ഇൻപുട്ടായി നൽകി, സെന്റൻസ് ID-കൾ നിങ്ങൾക്ക് അർത്ഥവത്തായി തോന്നുന്നുണ്ടോ എന്ന് പരിശോധിക്കുക. + +## `token-classification` പൈപ്പ്‌ലൈനിന്റെ ഉള്ളിൽ[[inside-the-token-classification-pipeline]] + +[അധ്യായം 1](/course/chapter1)-ൽ, 🤗 Transformers-ന്റെ `pipeline()` ഫംഗ്‌ഷൻ ഉപയോഗിച്ച് NER പ്രയോഗിക്കുന്നതിന്റെ ആദ്യ അനുഭവം നമുക്ക് ലഭിച്ചു -- ടെക്‌സ്‌റ്റിന്റെ ഏതൊക്കെ ഭാഗങ്ങളാണ് വ്യക്തികൾ, സ്ഥലങ്ങൾ, സംഘടനകൾ എന്നിവ പോലുള്ള എന്റിറ്റികളുമായി (entities) പൊരുത്തപ്പെടുന്നത് എന്ന് തിരിച്ചറിയുന്നതാണ് അതിലെ ടാസ്‌ക്. പിന്നീട്, [അധ്യായം 2](/course/chapter2)-ൽ, അസംസ്‌കൃത ടെക്‌സ്‌റ്റിൽ നിന്ന് പ്രവചനങ്ങൾ ലഭിക്കാൻ ആവശ്യമായ മൂന്ന് ഘട്ടങ്ങളെ -- ടോക്കണൈസേഷൻ, ഇൻപുട്ടുകൾ മോഡലിലൂടെ കടത്തിവിടൽ, പോസ്‌റ്റ്-പ്രോസസ്സിംഗ് -- ഒരു പൈപ്പ്‌ലൈൻ എങ്ങനെ ഒരുമിച്ച് ചേർക്കുന്നു എന്ന് നമ്മൾ കണ്ടു. `token-classification` പൈപ്പ്‌ലൈനിലെ ആദ്യ രണ്ട് ഘട്ടങ്ങൾ മറ്റേത് പൈപ്പ്‌ലൈനിലേതും പോലെ തന്നെയാണ്, എന്നാൽ പോസ്‌റ്റ്-പ്രോസസ്സിംഗ് കുറച്ചുകൂടി സങ്കീർണ്ണമാണ് -- എങ്ങനെയെന്ന് നോക്കാം! + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +### പൈപ്പ്‌ലൈൻ ഉപയോഗിച്ച് അടിസ്ഥാന ഫലങ്ങൾ നേടുന്നു[[getting-the-base-results-with-the-pipeline]] + +ആദ്യമായി, സ്വന്തമായി താരതമ്യം ചെയ്യാനുള്ള ചില ഫലങ്ങൾ ലഭിക്കുന്നതിനായി ഒരു ടോക്കൺ ക്ലാസിഫിക്കേഷൻ പൈപ്പ്‌ലൈൻ എടുക്കാം. ഡിഫോൾട്ടായി ഉപയോഗിക്കുന്ന മോഡൽ [`dbmdz/bert-large-cased-finetuned-conll03-english`](https://huggingface.co/dbmdz/bert-large-cased-finetuned-conll03-english) ആണ്; ഇത് വാക്യങ്ങളിൽ NER നടത്തുന്നു: + +```py +from transformers import pipeline + +token_classifier = pipeline("token-classification") +token_classifier("My name is Sylvain and I work at Hugging Face in Brooklyn.") +``` + +```python out +[{'entity': 'I-PER', 'score': 0.9993828, 'index': 4, 'word': 'S', 'start': 11, 'end': 12}, + {'entity': 'I-PER', 'score': 0.99815476, 'index': 5, 'word': '##yl', 'start': 12, 'end': 14}, + {'entity': 'I-PER', 'score': 0.99590725, 'index': 6, 'word': '##va', 'start': 14, 'end': 16}, + {'entity': 'I-PER', 'score': 0.9992327, 'index': 7, 'word': '##in', 'start': 16, 'end': 18}, + {'entity': 'I-ORG', 'score': 0.97389334, 'index': 12, 'word': 'Hu', 'start': 33, 'end': 35}, + {'entity': 'I-ORG', 'score': 0.976115, 'index': 13, 'word': '##gging', 'start': 35, 'end': 40}, + {'entity': 'I-ORG', 'score': 0.98879766, 'index': 14, 'word': 'Face', 'start': 41, 'end': 45}, + {'entity': 'I-LOC', 'score': 0.99321055, 'index': 16, 'word': 'Brooklyn', 'start': 49, 'end': 57}] +``` + +"Sylvain" സൃഷ്ടിച്ച ഓരോ ടോക്കണിനെയും ഒരു വ്യക്തിയായും, "Hugging Face" സൃഷ്ടിച്ച ഓരോ ടോക്കണിനെയും ഒരു സംഘടനയായും, "Brooklyn" എന്ന ടോക്കണിനെ ഒരു സ്ഥലമായും മോഡൽ ശരിയായി തിരിച്ചറിഞ്ഞു. ഒരേ എന്റിറ്റിയുമായി പൊരുത്തപ്പെടുന്ന ടോക്കണുകളെ ഒരുമിച്ച് ഗ്രൂപ്പ് ചെയ്യാനും നമുക്ക് പൈപ്പ്‌ലൈനിനോട് ആവശ്യപ്പെടാം: + +```py +from transformers import pipeline + +token_classifier = pipeline("token-classification", aggregation_strategy="simple") +token_classifier("My name is Sylvain and I work at Hugging Face in Brooklyn.") +``` + +```python out +[{'entity_group': 'PER', 'score': 0.9981694, 'word': 'Sylvain', 'start': 11, 'end': 18}, + {'entity_group': 'ORG', 'score': 0.97960204, 'word': 'Hugging Face', 'start': 33, 'end': 45}, + {'entity_group': 'LOC', 'score': 0.99321055, 'word': 'Brooklyn', 'start': 49, 'end': 57}] +``` + +തിരഞ്ഞെടുക്കുന്ന `aggregation_strategy`, ഗ്രൂപ്പ് ചെയ്ത ഓരോ എന്റിറ്റിക്കും കണക്കാക്കുന്ന സ്‌കോറുകളെ മാറ്റും. `"simple"` ഉപയോഗിക്കുമ്പോൾ, തന്നിരിക്കുന്ന എന്റിറ്റിയിലെ ഓരോ ടോക്കണിന്റെയും സ്‌കോറുകളുടെ ശരാശരി (mean) മാത്രമാണ് സ്‌കോർ: ഉദാഹരണത്തിന്, "Sylvain"-ന്റെ സ്‌കോർ, മുൻ ഉദാഹരണത്തിൽ `S`, `##yl`, `##va`, `##in` എന്നീ ടോക്കണുകൾക്ക് നമ്മൾ കണ്ട സ്‌കോറുകളുടെ ശരാശരിയാണ്. ലഭ്യമായ മറ്റ് സ്‌ട്രാറ്റജികൾ ഇവയാണ്: + +- `"first"`: ഇവിടെ ഓരോ എന്റിറ്റിയുടെയും സ്‌കോർ ആ എന്റിറ്റിയുടെ ആദ്യ ടോക്കണിന്റെ സ്‌കോറാണ് (അതിനാൽ "Sylvain"-ന് അത് `S` എന്ന ടോക്കണിന്റെ സ്‌കോറായ 0.993828 ആയിരിക്കും) +- `"max"`: ഇവിടെ ഓരോ എന്റിറ്റിയുടെയും സ്‌കോർ ആ എന്റിറ്റിയിലെ ടോക്കണുകളുടെ പരമാവധി സ്‌കോറാണ് (അതിനാൽ "Hugging Face"-ന് അത് "Face"-ന്റെ സ്‌കോറായ 0.98879766 ആയിരിക്കും) +- `"average"`: ഇവിടെ ഓരോ എന്റിറ്റിയുടെയും സ്‌കോർ ആ എന്റിറ്റി രൂപപ്പെടുത്തുന്ന വാക്കുകളുടെ സ്‌കോറുകളുടെ ശരാശരിയാണ് (അതിനാൽ "Sylvain"-ന് `"simple"` സ്‌ട്രാറ്റജിയിൽ നിന്ന് വ്യത്യാസമുണ്ടാകില്ല, എന്നാൽ "Hugging Face"-ന് "Hugging"-ന്റെ സ്‌കോറായ 0.975-ന്റെയും "Face"-ന്റെ സ്‌കോറായ 0.98879-ന്റെയും ശരാശരിയായ 0.9819 എന്ന സ്‌കോർ ലഭിക്കും) + +ഇനി `pipeline()` ഫംഗ്‌ഷൻ ഉപയോഗിക്കാതെ ഈ ഫലങ്ങൾ എങ്ങനെ നേടാമെന്ന് നോക്കാം! + +### ഇൻപുട്ടുകളിൽ നിന്ന് പ്രവചനങ്ങളിലേക്ക്[[from-inputs-to-predictions]] + +{#if fw === 'pt'} + +ആദ്യം നമ്മുടെ ഇൻപുട്ട് ടോക്കണൈസ് ചെയ്ത് മോഡലിലൂടെ കടത്തിവിടണം. [അധ്യായം 2](/course/chapter2)-ൽ ചെയ്തതുപോലെ തന്നെയാണ് ഇത് ചെയ്യുന്നത്; `AutoXxx` ക്ലാസുകൾ ഉപയോഗിച്ച് ടോക്കണൈസറും മോഡലും ഇൻസ്‌റ്റാൻഷിയേറ്റ് ചെയ്ത ശേഷം നമ്മുടെ ഉദാഹരണത്തിൽ അവ ഉപയോഗിക്കുന്നു: + +```py +from transformers import AutoTokenizer, AutoModelForTokenClassification + +model_checkpoint = "dbmdz/bert-large-cased-finetuned-conll03-english" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) +model = AutoModelForTokenClassification.from_pretrained(model_checkpoint) + +example = "My name is Sylvain and I work at Hugging Face in Brooklyn." +inputs = tokenizer(example, return_tensors="pt") +outputs = model(**inputs) +``` + +ഇവിടെ നമ്മൾ `AutoModelForTokenClassification` ഉപയോഗിക്കുന്നതിനാൽ, ഇൻപുട്ട് സീക്വൻസിലെ ഓരോ ടോക്കണിനും ഒരു സെറ്റ് ലോജിറ്റുകൾ (logits) നമുക്ക് ലഭിക്കുന്നു: + +```py +print(inputs["input_ids"].shape) +print(outputs.logits.shape) +``` + +```python out +torch.Size([1, 19]) +torch.Size([1, 19, 9]) +``` + +{:else} + +ആദ്യം നമ്മുടെ ഇൻപുട്ട് ടോക്കണൈസ് ചെയ്ത് മോഡലിലൂടെ കടത്തിവിടണം. [അധ്യായം 2](/course/chapter2)-ൽ ചെയ്തതുപോലെ തന്നെയാണ് ഇത് ചെയ്യുന്നത്; `TFAutoXxx` ക്ലാസുകൾ ഉപയോഗിച്ച് ടോക്കണൈസറും മോഡലും ഇൻസ്‌റ്റാൻഷിയേറ്റ് ചെയ്ത ശേഷം നമ്മുടെ ഉദാഹരണത്തിൽ അവ ഉപയോഗിക്കുന്നു: + +```py +from transformers import AutoTokenizer, TFAutoModelForTokenClassification + +model_checkpoint = "dbmdz/bert-large-cased-finetuned-conll03-english" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) +model = TFAutoModelForTokenClassification.from_pretrained(model_checkpoint) + +example = "My name is Sylvain and I work at Hugging Face in Brooklyn." +inputs = tokenizer(example, return_tensors="tf") +outputs = model(**inputs) +``` + +ഇവിടെ നമ്മൾ `TFAutoModelForTokenClassification` ഉപയോഗിക്കുന്നതിനാൽ, ഇൻപുട്ട് സീക്വൻസിലെ ഓരോ ടോക്കണിനും ഒരു സെറ്റ് ലോജിറ്റുകൾ (logits) നമുക്ക് ലഭിക്കുന്നു: + +```py +print(inputs["input_ids"].shape) +print(outputs.logits.shape) +``` + +```python out +(1, 19) +(1, 19, 9) +``` + +{/if} + +19 ടോക്കണുകളുള്ള 1 സീക്വൻസ് അടങ്ങിയ ഒരു ബാച്ചാണ് നമുക്കുള്ളത്, മോഡലിന് 9 വ്യത്യസ്ത ലേബലുകളുമുണ്ട്; അതിനാൽ മോഡലിന്റെ ഔട്ട്‌പുട്ടിന്റെ ഷേപ്പ് 1 x 19 x 9 ആണ്. ടെക്‌സ്‌റ്റ് ക്ലാസിഫിക്കേഷൻ പൈപ്പ്‌ലൈനിലേതുപോലെ, ആ ലോജിറ്റുകളെ പ്രോബബിലിറ്റികളാക്കി മാറ്റാൻ ഒരു softmax ഫംഗ്‌ഷൻ നമ്മൾ ഉപയോഗിക്കുന്നു, പ്രവചനങ്ങൾ ലഭിക്കാൻ argmax എടുക്കുന്നു (softmax ക്രമം മാറ്റാത്തതിനാൽ ലോജിറ്റുകളിൽ തന്നെ argmax എടുക്കാം എന്നത് ശ്രദ്ധിക്കുക): + +{#if fw === 'pt'} + +```py +import torch + +probabilities = torch.nn.functional.softmax(outputs.logits, dim=-1)[0].tolist() +predictions = outputs.logits.argmax(dim=-1)[0].tolist() +print(predictions) +``` + +{:else} + +```py +import tensorflow as tf + +probabilities = tf.math.softmax(outputs.logits, axis=-1)[0] +probabilities = probabilities.numpy().tolist() +predictions = tf.math.argmax(outputs.logits, axis=-1)[0] +predictions = predictions.numpy().tolist() +print(predictions) +``` + +{/if} + +```python out +[0, 0, 0, 0, 4, 4, 4, 4, 0, 0, 0, 0, 6, 6, 6, 0, 8, 0, 0] +``` + +പ്രവചനങ്ങൾ മനസ്സിലാക്കാൻ നമുക്ക് ഉപയോഗിക്കാവുന്ന, ഇൻഡെക്‌സുകളെ ലേബലുകളുമായി ബന്ധിപ്പിക്കുന്ന മാപ്പിംഗ് `model.config.id2label` ആട്രിബ്യൂട്ടിൽ അടങ്ങിയിരിക്കുന്നു: + +```py +model.config.id2label +``` + +```python out +{0: 'O', + 1: 'B-MISC', + 2: 'I-MISC', + 3: 'B-PER', + 4: 'I-PER', + 5: 'B-ORG', + 6: 'I-ORG', + 7: 'B-LOC', + 8: 'I-LOC'} +``` + +നമ്മൾ മുമ്പ് കണ്ടതുപോലെ, 9 ലേബലുകളുണ്ട്: ഒരു നെയിംഡ് എന്റിറ്റിയിലും ഉൾപ്പെടാത്ത ടോക്കണുകളുടെ ലേബലാണ് `O` (ഇത് "outside" എന്നതിനെ സൂചിപ്പിക്കുന്നു); പിന്നെ ഓരോ തരം എന്റിറ്റിക്കും (മിസലേനിയസ് അഥവാ മറ്റുള്ളവ, വ്യക്തി, സംഘടന, സ്ഥലം) രണ്ട് ലേബലുകൾ വീതമുണ്ട്. `B-XXX` എന്ന ലേബൽ, ടോക്കൺ ഒരു `XXX` എന്റിറ്റിയുടെ തുടക്കത്തിലാണെന്ന് സൂചിപ്പിക്കുന്നു; `I-XXX` എന്ന ലേബൽ, ടോക്കൺ `XXX` എന്റിറ്റിയുടെ ഉള്ളിലാണെന്ന് സൂചിപ്പിക്കുന്നു. ഉദാഹരണത്തിന്, ഇപ്പോഴത്തെ ഉദാഹരണത്തിൽ, നമ്മുടെ മോഡൽ `S` എന്ന ടോക്കണിനെ `B-PER` (ഒരു വ്യക്തി എന്റിറ്റിയുടെ തുടക്കം) എന്നും `##yl`, `##va`, `##in` എന്നീ ടോക്കണുകളെ `I-PER` (ഒരു വ്യക്തി എന്റിറ്റിയുടെ ഉള്ളിൽ) എന്നും വർഗ്ഗീകരിക്കുമെന്ന് നമ്മൾ പ്രതീക്ഷിക്കും. + +ഈ നാല് ടോക്കണുകൾക്കും മോഡൽ `I-PER` എന്ന ലേബൽ നൽകിയതിനാൽ ഇവിടെ മോഡലിന് തെറ്റുപറ്റി എന്ന് നിങ്ങൾ ചിന്തിച്ചേക്കാം, എന്നാൽ അത് പൂർണ്ണമായും ശരിയല്ല. ആ `B-`, `I-` ലേബലുകൾക്ക് യഥാർത്ഥത്തിൽ രണ്ട് ഫോർമാറ്റുകളുണ്ട്: *IOB1*, *IOB2*. നമ്മൾ പരിചയപ്പെടുത്തിയത് IOB2 ഫോർമാറ്റാണ് (താഴെ പിങ്ക് നിറത്തിൽ); അതേസമയം IOB1 ഫോർമാറ്റിൽ (നീല നിറത്തിൽ), ഒരേ തരത്തിലുള്ള അടുത്തടുത്ത രണ്ട് എന്റിറ്റികളെ വേർതിരിക്കാൻ മാത്രമാണ് `B-` എന്ന് തുടങ്ങുന്ന ലേബലുകൾ ഉപയോഗിക്കുന്നത്. നമ്മൾ ഉപയോഗിക്കുന്ന മോഡൽ ആ ഫോർമാറ്റ് ഉപയോഗിക്കുന്ന ഒരു ഡേറ്റാസെറ്റിലാണ് ഫൈൻ-ട്യൂൻ ചെയ്തിരിക്കുന്നത്; അതുകൊണ്ടാണ് അത് `S` എന്ന ടോക്കണിന് `I-PER` എന്ന ലേബൽ നൽകുന്നത്. + +
+IOB1 vs IOB2 ഫോർമാറ്റ് + +
+ +ഈ മാപ്പ് ഉപയോഗിച്ച്, ആദ്യ പൈപ്പ്‌ലൈനിന്റെ ഫലങ്ങൾ (ഏകദേശം പൂർണ്ണമായി) പുനഃസൃഷ്ടിക്കാൻ നമ്മൾ തയ്യാറാണ് -- `O` എന്ന് വർഗ്ഗീകരിക്കപ്പെടാത്ത ഓരോ ടോക്കണിന്റെയും സ്‌കോറും ലേബലും എടുത്താൽ മാത്രം മതി: + +```py +results = [] +tokens = inputs.tokens() + +for idx, pred in enumerate(predictions): + label = model.config.id2label[pred] + if label != "O": + results.append( + {"entity": label, "score": probabilities[idx][pred], "word": tokens[idx]} + ) + +print(results) +``` + +```python out +[{'entity': 'I-PER', 'score': 0.9993828, 'index': 4, 'word': 'S'}, + {'entity': 'I-PER', 'score': 0.99815476, 'index': 5, 'word': '##yl'}, + {'entity': 'I-PER', 'score': 0.99590725, 'index': 6, 'word': '##va'}, + {'entity': 'I-PER', 'score': 0.9992327, 'index': 7, 'word': '##in'}, + {'entity': 'I-ORG', 'score': 0.97389334, 'index': 12, 'word': 'Hu'}, + {'entity': 'I-ORG', 'score': 0.976115, 'index': 13, 'word': '##gging'}, + {'entity': 'I-ORG', 'score': 0.98879766, 'index': 14, 'word': 'Face'}, + {'entity': 'I-LOC', 'score': 0.99321055, 'index': 16, 'word': 'Brooklyn'}] +``` + +ഇത് നമുക്ക് മുമ്പ് ലഭിച്ചതിനോട് വളരെ സാമ്യമുള്ളതാണ്, ഒരു വ്യത്യാസം മാത്രം: യഥാർത്ഥ വാക്യത്തിലെ ഓരോ എന്റിറ്റിയുടെയും `start`, `end` എന്നിവയെക്കുറിച്ചുള്ള വിവരവും പൈപ്പ്‌ലൈൻ നമുക്ക് നൽകിയിരുന്നു. ഇവിടെയാണ് നമ്മുടെ ഓഫ്‌സെറ്റ് മാപ്പിംഗ് രംഗത്തെത്തുന്നത്. ഓഫ്‌സെറ്റുകൾ ലഭിക്കാൻ, ടോക്കണൈസർ നമ്മുടെ ഇൻപുട്ടുകളിൽ പ്രയോഗിക്കുമ്പോൾ `return_offsets_mapping=True` എന്ന് സെറ്റ് ചെയ്താൽ മാത്രം മതി: + +```py +inputs_with_offsets = tokenizer(example, return_offsets_mapping=True) +inputs_with_offsets["offset_mapping"] +``` + +```python out +[(0, 0), (0, 2), (3, 7), (8, 10), (11, 12), (12, 14), (14, 16), (16, 18), (19, 22), (23, 24), (25, 29), (30, 32), + (33, 35), (35, 40), (41, 45), (46, 48), (49, 57), (57, 58), (0, 0)] +``` + +ഓരോ ട്യൂപ്പിളും (tuple) ഓരോ ടോക്കണുമായി പൊരുത്തപ്പെടുന്ന ടെക്‌സ്‌റ്റ് സ്‌പാനാണ്; `(0, 0)` സ്‌പെഷ്യൽ ടോക്കണുകൾക്കായി മാറ്റിവച്ചിരിക്കുന്നു. ഇൻഡെക്‌സ് 5-ലെ ടോക്കൺ `##yl` ആണെന്ന് നമ്മൾ മുമ്പ് കണ്ടു; ഇവിടെ അതിന്റെ ഓഫ്‌സെറ്റുകൾ `(12, 14)` ആണ്. നമ്മുടെ ഉദാഹരണത്തിലെ അതിനു യോജിച്ച സ്ലൈസ് (slice) എടുത്താൽ: + + +```py +example[12:14] +``` + +`##` ഇല്ലാതെ ശരിയായ ടെക്‌സ്‌റ്റ് സ്‌പാൻ നമുക്ക് ലഭിക്കുന്നു: + +```python out +yl +``` + +ഇത് ഉപയോഗിച്ച്, മുൻപത്തെ ഫലങ്ങൾ ഇപ്പോൾ നമുക്ക് പൂർത്തിയാക്കാം: + +```py +results = [] +inputs_with_offsets = tokenizer(example, return_offsets_mapping=True) +tokens = inputs_with_offsets.tokens() +offsets = inputs_with_offsets["offset_mapping"] + +for idx, pred in enumerate(predictions): + label = model.config.id2label[pred] + if label != "O": + start, end = offsets[idx] + results.append( + { + "entity": label, + "score": probabilities[idx][pred], + "word": tokens[idx], + "start": start, + "end": end, + } + ) + +print(results) +``` + +```python out +[{'entity': 'I-PER', 'score': 0.9993828, 'index': 4, 'word': 'S', 'start': 11, 'end': 12}, + {'entity': 'I-PER', 'score': 0.99815476, 'index': 5, 'word': '##yl', 'start': 12, 'end': 14}, + {'entity': 'I-PER', 'score': 0.99590725, 'index': 6, 'word': '##va', 'start': 14, 'end': 16}, + {'entity': 'I-PER', 'score': 0.9992327, 'index': 7, 'word': '##in', 'start': 16, 'end': 18}, + {'entity': 'I-ORG', 'score': 0.97389334, 'index': 12, 'word': 'Hu', 'start': 33, 'end': 35}, + {'entity': 'I-ORG', 'score': 0.976115, 'index': 13, 'word': '##gging', 'start': 35, 'end': 40}, + {'entity': 'I-ORG', 'score': 0.98879766, 'index': 14, 'word': 'Face', 'start': 41, 'end': 45}, + {'entity': 'I-LOC', 'score': 0.99321055, 'index': 16, 'word': 'Brooklyn', 'start': 49, 'end': 57}] +``` + +ആദ്യ പൈപ്പ്‌ലൈനിൽ നിന്ന് നമുക്ക് ലഭിച്ചതിന് തുല്യമാണ് ഇത്! + +### എന്റിറ്റികളെ ഗ്രൂപ്പ് ചെയ്യുന്നു[[grouping-entities]] + +ഓരോ എന്റിറ്റിയുടെയും start, end കീകൾ നിർണ്ണയിക്കാൻ ഓഫ്‌സെറ്റുകൾ ഉപയോഗിക്കുന്നത് സൗകര്യപ്രദമാണ്, എന്നാൽ ആ വിവരം കർശനമായി ആവശ്യമുള്ളതല്ല. എന്നിരുന്നാലും, എന്റിറ്റികളെ ഒരുമിച്ച് ഗ്രൂപ്പ് ചെയ്യാൻ ആഗ്രഹിക്കുമ്പോൾ, കുഴഞ്ഞുമറിഞ്ഞ ഒരുപാട് കോഡ് ഓഫ്‌സെറ്റുകൾ നമുക്ക് ഒഴിവാക്കിത്തരും. ഉദാഹരണത്തിന്, `Hu`, `##gging`, `Face` എന്നീ ടോക്കണുകളെ ഒരുമിച്ച് ഗ്രൂപ്പ് ചെയ്യണമെങ്കിൽ, ആദ്യത്തെ രണ്ടെണ്ണം `##` നീക്കം ചെയ്ത് കൂട്ടിച്ചേർക്കണമെന്നും, `Face` `##`-ൽ തുടങ്ങാത്തതിനാൽ ഒരു സ്‌പേസ് സഹിതം ചേർക്കണമെന്നും പറയുന്ന പ്രത്യേക നിയമങ്ങൾ നമുക്ക് ഉണ്ടാക്കാം -- എന്നാൽ അത് ഈ പ്രത്യേക തരം ടോക്കണൈസറിന് മാത്രമേ പ്രവർത്തിക്കൂ. ഒരു SentencePiece അല്ലെങ്കിൽ Byte-Pair-Encoding ടോക്കണൈസറിന് (ഈ അധ്യായത്തിൽ പിന്നീട് ചർച്ച ചെയ്യുന്നു) മറ്റൊരു കൂട്ടം നിയമങ്ങൾ നമുക്ക് എഴുതേണ്ടിവരും. + +ഓഫ്‌സെറ്റുകൾ ഉള്ളപ്പോൾ, ആ കസ്‌റ്റം കോഡെല്ലാം ഒഴിവാകുന്നു: ആദ്യ ടോക്കണിൽ തുടങ്ങി അവസാന ടോക്കണിൽ അവസാനിക്കുന്ന, യഥാർത്ഥ ടെക്‌സ്‌റ്റിലെ സ്‌പാൻ എടുത്താൽ മാത്രം മതി. അതിനാൽ, `Hu`, `##gging`, `Face` എന്നീ ടോക്കണുകളുടെ കാര്യത്തിൽ, ക്യാരക്റ്റർ 33-ൽ (`Hu`-ന്റെ തുടക്കം) തുടങ്ങി ക്യാരക്റ്റർ 45-ന് (`Face`-ന്റെ അവസാനം) മുമ്പ് അവസാനിപ്പിക്കണം: + +```py +example[33:45] +``` + +```python out +Hugging Face +``` + +എന്റിറ്റികളെ ഗ്രൂപ്പ് ചെയ്യുന്നതിനൊപ്പം പ്രവചനങ്ങളെ പോസ്‌റ്റ്-പ്രോസസ്സ് ചെയ്യുന്ന കോഡ് എഴുതാൻ, തുടർച്ചയായി വരുന്നതും `I-XXX` എന്ന് ലേബൽ ചെയ്തതുമായ എന്റിറ്റികളെ നമ്മൾ ഒരുമിച്ച് ഗ്രൂപ്പ് ചെയ്യും; ആദ്യത്തേത് മാത്രം ഇതിന് അപവാദമാണ്, അതിന് `B-XXX` അല്ലെങ്കിൽ `I-XXX` എന്ന ലേബൽ ആകാം (അതായത്, ഒരു `O`, ഒരു പുതിയ തരം എന്റിറ്റി, അല്ലെങ്കിൽ ഒരേ തരത്തിലുള്ള ഒരു എന്റിറ്റി തുടങ്ങുന്നു എന്ന് പറയുന്ന ഒരു `B-XXX` എന്നിവ ലഭിക്കുമ്പോൾ ഒരു എന്റിറ്റിയുടെ ഗ്രൂപ്പിംഗ് നമ്മൾ നിർത്തുന്നു): + +```py +import numpy as np + +results = [] +inputs_with_offsets = tokenizer(example, return_offsets_mapping=True) +tokens = inputs_with_offsets.tokens() +offsets = inputs_with_offsets["offset_mapping"] + +idx = 0 +while idx < len(predictions): + pred = predictions[idx] + label = model.config.id2label[pred] + if label != "O": + # Remove the B- or I- + label = label[2:] + start, _ = offsets[idx] + + # Grab all the tokens labeled with I-label + all_scores = [] + while ( + idx < len(predictions) + and model.config.id2label[predictions[idx]] == f"I-{label}" + ): + all_scores.append(probabilities[idx][pred]) + _, end = offsets[idx] + idx += 1 + + # The score is the mean of all the scores of the tokens in that grouped entity + score = np.mean(all_scores).item() + word = example[start:end] + results.append( + { + "entity_group": label, + "score": score, + "word": word, + "start": start, + "end": end, + } + ) + idx += 1 + +print(results) +``` + +നമ്മുടെ രണ്ടാമത്തെ പൈപ്പ്‌ലൈനിൽ ലഭിച്ച അതേ ഫലങ്ങൾ തന്നെ നമുക്ക് ലഭിക്കുന്നു! + +```python out +[{'entity_group': 'PER', 'score': 0.9981694, 'word': 'Sylvain', 'start': 11, 'end': 18}, + {'entity_group': 'ORG', 'score': 0.97960204, 'word': 'Hugging Face', 'start': 33, 'end': 45}, + {'entity_group': 'LOC', 'score': 0.99321055, 'word': 'Brooklyn', 'start': 49, 'end': 57}] +``` + +ഈ ഓഫ്‌സെറ്റുകൾ അത്യധികം ഉപകാരപ്രദമാകുന്ന മറ്റൊരു ടാസ്‌ക്കിന്റെ ഉദാഹരണമാണ് ചോദ്യോത്തരം (question answering). അടുത്ത ഭാഗത്തിൽ നമ്മൾ ചെയ്യാൻ പോകുന്ന, ആ പൈപ്പ്‌ലൈനിലേക്കുള്ള ആഴത്തിലുള്ള പരിശോധന, 🤗 Transformers ലൈബ്രറിയിലെ ടോക്കണൈസറുകളുടെ അവസാനത്തെ ഒരു ഫീച്ചർ കൂടി പരിചയപ്പെടാനും നമ്മെ സഹായിക്കും: ഒരു ഇൻപുട്ടിനെ നിശ്ചിത നീളത്തിലേക്ക് ട്രങ്കേറ്റ് ചെയ്യുമ്പോൾ (truncate) കവിഞ്ഞുപോകുന്ന (overflowing) ടോക്കണുകൾ കൈകാര്യം ചെയ്യൽ. diff --git a/chapters/ml/chapter6/3b.mdx b/chapters/ml/chapter6/3b.mdx new file mode 100644 index 000000000..2269f2375 --- /dev/null +++ b/chapters/ml/chapter6/3b.mdx @@ -0,0 +1,630 @@ + + +# QA പൈപ്പ്‌ലൈനിലെ ഫാസ്‌റ്റ് ടോക്കണൈസറുകൾ[[fast-tokenizers-in-the-qa-pipeline]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +ഇനി നമ്മൾ `question-answering` പൈപ്പ്‌ലൈനിലേക്ക് ആഴത്തിൽ കടക്കുകയും, മുൻ ഭാഗത്തിൽ ഗ്രൂപ്പ് ചെയ്ത എന്റിറ്റികൾക്കായി (grouped entities) ചെയ്തതുപോലെ, ഓഫ്‌സെറ്റുകൾ (offsets) ഉപയോഗപ്പെടുത്തി കോൺടെക്‌സ്‌റ്റിൽ (context) നിന്ന് ചോദ്യത്തിന്റെ ഉത്തരം എങ്ങനെ എടുക്കാമെന്ന് കാണുകയും ചെയ്യും. തുടർന്ന്, ട്രങ്കേറ്റ് ചെയ്യപ്പെടുന്ന (truncated) വളരെ നീണ്ട കോൺടെക്‌സ്‌റ്റുകളെ എങ്ങനെ കൈകാര്യം ചെയ്യാമെന്ന് നമ്മൾ നോക്കും. ചോദ്യോത്തര (question answering) ടാസ്‌കിൽ നിങ്ങൾക്ക് താൽപ്പര്യമില്ലെങ്കിൽ ഈ ഭാഗം നിങ്ങൾക്ക് ഒഴിവാക്കാം. + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +## `question-answering` പൈപ്പ്‌ലൈൻ ഉപയോഗിക്കുന്നു[[using-the-question-answering-pipeline]] + +[അധ്യായം 1](/course/chapter1)-ൽ നമ്മൾ കണ്ടതുപോലെ, ഒരു ചോദ്യത്തിന്റെ ഉത്തരം ലഭിക്കാൻ `question-answering` പൈപ്പ്‌ലൈൻ ഇങ്ങനെ ഉപയോഗിക്കാം: + +```py +from transformers import pipeline + +question_answerer = pipeline("question-answering") +context = """ +🤗 Transformers is backed by the three most popular deep learning libraries — Jax, PyTorch, and TensorFlow — with a seamless integration +between them. It's straightforward to train your models with one before loading them for inference with the other. +""" +question = "Which deep learning libraries back 🤗 Transformers?" +question_answerer(question=question, context=context) +``` + +```python out +{'score': 0.97773, + 'start': 78, + 'end': 105, + 'answer': 'Jax, PyTorch and TensorFlow'} +``` + +മോഡൽ സ്വീകരിക്കുന്ന പരമാവധി ദൈർഘ്യത്തേക്കാൾ നീളമുള്ള ടെക്‌സ്‌റ്റുകളെ ട്രങ്കേറ്റ് ചെയ്യാനും വിഭജിക്കാനും കഴിയാത്ത (അതിനാൽ ഒരു ഡോക്യുമെന്റിന്റെ അവസാനത്തെ വിവരങ്ങൾ നഷ്ടപ്പെടുത്താൻ സാധ്യതയുള്ള) മറ്റ് പൈപ്പ്‌ലൈനുകളിൽ നിന്ന് വ്യത്യസ്തമായി, ഈ പൈപ്പ്‌ലൈനിന് വളരെ നീണ്ട കോൺടെക്‌സ്‌റ്റുകൾ കൈകാര്യം ചെയ്യാൻ കഴിയും, ഉത്തരം അവസാനഭാഗത്താണെങ്കിൽ പോലും ചോദ്യത്തിന്റെ ഉത്തരം അത് റിട്ടേൺ ചെയ്യും: + +```py +long_context = """ +🤗 Transformers: State of the Art NLP + +🤗 Transformers provides thousands of pretrained models to perform tasks on texts such as classification, information extraction, +question answering, summarization, translation, text generation and more in over 100 languages. +Its aim is to make cutting-edge NLP easier to use for everyone. + +🤗 Transformers provides APIs to quickly download and use those pretrained models on a given text, fine-tune them on your own datasets and +then share them with the community on our model hub. At the same time, each python module defining an architecture is fully standalone and +can be modified to enable quick research experiments. + +Why should I use transformers? + +1. Easy-to-use state-of-the-art models: + - High performance on NLU and NLG tasks. + - Low barrier to entry for educators and practitioners. + - Few user-facing abstractions with just three classes to learn. + - A unified API for using all our pretrained models. + - Lower compute costs, smaller carbon footprint: + +2. Researchers can share trained models instead of always retraining. + - Practitioners can reduce compute time and production costs. + - Dozens of architectures with over 10,000 pretrained models, some in more than 100 languages. + +3. Choose the right framework for every part of a model's lifetime: + - Train state-of-the-art models in 3 lines of code. + - Move a single model between TF2.0/PyTorch frameworks at will. + - Seamlessly pick the right framework for training, evaluation and production. + +4. Easily customize a model or an example to your needs: + - We provide examples for each architecture to reproduce the results published by its original authors. + - Model internals are exposed as consistently as possible. + - Model files can be used independently of the library for quick experiments. + +🤗 Transformers is backed by the three most popular deep learning libraries — Jax, PyTorch and TensorFlow — with a seamless integration +between them. It's straightforward to train your models with one before loading them for inference with the other. +""" +question_answerer(question=question, context=long_context) +``` + +```python out +{'score': 0.97149, + 'start': 1892, + 'end': 1919, + 'answer': 'Jax, PyTorch and TensorFlow'} +``` + +ഇതെല്ലാം അത് എങ്ങനെ ചെയ്യുന്നു എന്ന് നോക്കാം! + +## ചോദ്യോത്തരത്തിനായി ഒരു മോഡൽ ഉപയോഗിക്കുന്നു[[using-a-model-for-question-answering]] + +മറ്റേതൊരു പൈപ്പ്‌ലൈനിലെയും പോലെ, നമ്മുടെ ഇൻപുട്ട് ടോക്കണൈസ് ചെയ്തുകൊണ്ട് നമ്മൾ തുടങ്ങുന്നു, തുടർന്ന് അത് മോഡലിലൂടെ കടത്തിവിടുന്നു. `question-answering` പൈപ്പ്‌ലൈനിൽ ഡിഫോൾട്ടായി ഉപയോഗിക്കുന്ന ചെക്ക്‌പോയിന്റ് [`distilbert-base-cased-distilled-squad`](https://huggingface.co/distilbert-base-cased-distilled-squad) ആണ് (പേരിലെ "squad" വന്നത് മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യപ്പെട്ട ഡേറ്റാസെറ്റിൽ നിന്നാണ്; SQuAD ഡേറ്റാസെറ്റിനെക്കുറിച്ച് [അധ്യായം 7](/course/chapter7/7)-ൽ നമ്മൾ കൂടുതൽ സംസാരിക്കും): + +{#if fw === 'pt'} + +```py +from transformers import AutoTokenizer, AutoModelForQuestionAnswering + +model_checkpoint = "distilbert-base-cased-distilled-squad" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) +model = AutoModelForQuestionAnswering.from_pretrained(model_checkpoint) + +inputs = tokenizer(question, context, return_tensors="pt") +outputs = model(**inputs) +``` + +{:else} + +```py +from transformers import AutoTokenizer, TFAutoModelForQuestionAnswering + +model_checkpoint = "distilbert-base-cased-distilled-squad" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) +model = TFAutoModelForQuestionAnswering.from_pretrained(model_checkpoint) + +inputs = tokenizer(question, context, return_tensors="tf") +outputs = model(**inputs) +``` + +{/if} + +ചോദ്യവും കോൺടെക്‌സ്‌റ്റും ഒരു ജോഡിയായി, ചോദ്യം ആദ്യം വരുന്ന രീതിയിൽ, നമ്മൾ ടോക്കണൈസ് ചെയ്യുന്നു എന്നത് ശ്രദ്ധിക്കുക. + +
+ചോദ്യത്തിന്റെയും കോൺടെക്‌സ്‌റ്റിന്റെയും ടോക്കണൈസേഷന്റെ ഒരു ഉദാഹരണം + +
+ +ചോദ്യോത്തരത്തിനുള്ള മോഡലുകൾ, നമ്മൾ ഇതുവരെ കണ്ട മോഡലുകളിൽ നിന്ന് അൽപ്പം വ്യത്യസ്തമായാണ് പ്രവർത്തിക്കുന്നത്. മുകളിലെ ചിത്രം ഉദാഹരണമായി എടുത്താൽ, ഉത്തരം ആരംഭിക്കുന്ന ടോക്കണിന്റെ ഇൻഡെക്‌സും (ഇവിടെ 21) ഉത്തരം അവസാനിക്കുന്ന ടോക്കണിന്റെ ഇൻഡെക്‌സും (ഇവിടെ 24) പ്രവചിക്കാനാണ് മോഡൽ ട്രെയിൻ ചെയ്യപ്പെട്ടിരിക്കുന്നത്. അതുകൊണ്ടാണ് ഈ മോഡലുകൾ ലോജിറ്റുകളുടെ (logits) ഒരു ടെൻസറല്ല, രണ്ടെണ്ണം റിട്ടേൺ ചെയ്യുന്നത്: ഒന്ന് ഉത്തരത്തിന്റെ ആരംഭ ടോക്കണിനോട് (start token) ബന്ധപ്പെട്ട ലോജിറ്റുകൾക്കും, മറ്റൊന്ന് ഉത്തരത്തിന്റെ അവസാന ടോക്കണിനോട് (end token) ബന്ധപ്പെട്ട ലോജിറ്റുകൾക്കും. ഈ സാഹചര്യത്തിൽ 66 ടോക്കണുകൾ അടങ്ങിയ ഒരേയൊരു ഇൻപുട്ട് മാത്രമേ നമുക്കുള്ളതിനാൽ, നമുക്ക് ലഭിക്കുന്നത്: + +```py +start_logits = outputs.start_logits +end_logits = outputs.end_logits +print(start_logits.shape, end_logits.shape) +``` + +{#if fw === 'pt'} + +```python out +torch.Size([1, 66]) torch.Size([1, 66]) +``` + +{:else} + +```python out +(1, 66) (1, 66) +``` + +{/if} + +ഈ ലോജിറ്റുകളെ പ്രോബബിലിറ്റികളാക്കി മാറ്റാൻ, നമ്മൾ ഒരു സോഫ്‌റ്റ്‌മാക്‌സ് (softmax) ഫംഗ്‌ഷൻ പ്രയോഗിക്കും -- എന്നാൽ അതിനുമുമ്പ്, കോൺടെക്‌സ്‌റ്റിന്റെ ഭാഗമല്ലാത്ത ഇൻഡെക്‌സുകൾ മാസ്‌ക് ചെയ്യുന്നുണ്ടെന്ന് നമ്മൾ ഉറപ്പാക്കണം. നമ്മുടെ ഇൻപുട്ട് `[CLS] question [SEP] context [SEP]` എന്നതാണ്, അതിനാൽ ചോദ്യത്തിന്റെ ടോക്കണുകളും `[SEP]` ടോക്കണും നമ്മൾ മാസ്‌ക് ചെയ്യണം. എന്നാൽ `[CLS]` ടോക്കൺ നമ്മൾ നിലനിർത്തും, കാരണം ഉത്തരം കോൺടെക്‌സ്‌റ്റിൽ ഇല്ല എന്ന് സൂചിപ്പിക്കാൻ ചില മോഡലുകൾ അത് ഉപയോഗിക്കുന്നു. + +പിന്നീട് നമ്മൾ ഒരു സോഫ്‌റ്റ്‌മാക്‌സ് പ്രയോഗിക്കുന്നതിനാൽ, മാസ്‌ക് ചെയ്യേണ്ട ലോജിറ്റുകളെ ഒരു വലിയ നെഗറ്റീവ് സംഖ്യ കൊണ്ട് മാറ്റിവയ്ക്കുകയേ വേണ്ടൂ. ഇവിടെ നമ്മൾ `-10000` ഉപയോഗിക്കുന്നു: + +{#if fw === 'pt'} + +```py +import torch + +sequence_ids = inputs.sequence_ids() +# Mask everything apart from the tokens of the context +mask = [i != 1 for i in sequence_ids] +# Unmask the [CLS] token +mask[0] = False +mask = torch.tensor(mask)[None] + +start_logits[mask] = -10000 +end_logits[mask] = -10000 +``` + +{:else} + +```py +import tensorflow as tf + +sequence_ids = inputs.sequence_ids() +# Mask everything apart from the tokens of the context +mask = [i != 1 for i in sequence_ids] +# Unmask the [CLS] token +mask[0] = False +mask = tf.constant(mask)[None] + +start_logits = tf.where(mask, -10000, start_logits) +end_logits = tf.where(mask, -10000, end_logits) +``` + +{/if} + +പ്രവചിക്കാൻ നമ്മൾ ആഗ്രഹിക്കാത്ത സ്ഥാനങ്ങളോട് ബന്ധപ്പെട്ട ലോജിറ്റുകൾ ശരിയായി മാസ്‌ക് ചെയ്തുകഴിഞ്ഞതിനാൽ, ഇപ്പോൾ നമുക്ക് സോഫ്‌റ്റ്‌മാക്‌സ് പ്രയോഗിക്കാം: + +{#if fw === 'pt'} + +```py +start_probabilities = torch.nn.functional.softmax(start_logits, dim=-1)[0] +end_probabilities = torch.nn.functional.softmax(end_logits, dim=-1)[0] +``` + +{:else} + +```py +start_probabilities = tf.math.softmax(start_logits, axis=-1)[0].numpy() +end_probabilities = tf.math.softmax(end_logits, axis=-1)[0].numpy() +``` + +{/if} + +ഈ ഘട്ടത്തിൽ, ആരംഭ, അവസാന പ്രോബബിലിറ്റികളുടെ argmax നമുക്ക് എടുക്കാമായിരുന്നു -- എന്നാൽ അവസാന ഇൻഡെക്‌സിനേക്കാൾ വലിയ ഒരു ആരംഭ ഇൻഡെക്‌സ് നമുക്ക് ലഭിച്ചേക്കാം, അതിനാൽ കുറച്ചുകൂടി മുൻകരുതലുകൾ നമ്മൾ എടുക്കണം. `start_index <= end_index` ആയ, സാധ്യമായ ഓരോ `start_index`-ന്റെയും `end_index`-ന്റെയും പ്രോബബിലിറ്റികൾ നമ്മൾ കണക്കാക്കും, തുടർന്ന് ഏറ്റവും ഉയർന്ന പ്രോബബിലിറ്റിയുള്ള `(start_index, end_index)` എന്ന ട്യൂപ്പിൾ (tuple) എടുക്കും. + +"ഉത്തരം `start_index`-ൽ ആരംഭിക്കുന്നു" എന്നതും "ഉത്തരം `end_index`-ൽ അവസാനിക്കുന്നു" എന്നതും പരസ്പരം സ്വതന്ത്രമായ (independent) സംഭവങ്ങളാണെന്ന് അനുമാനിച്ചാൽ, ഉത്തരം `start_index`-ൽ ആരംഭിച്ച് `end_index`-ൽ അവസാനിക്കാനുള്ള പ്രോബബിലിറ്റി ഇതാണ്: + +$$\mathrm{start\_probabilities}[\mathrm{start\_index}] \times \mathrm{end\_probabilities}[\mathrm{end\_index}]$$ + +അതിനാൽ, എല്ലാ സ്‌കോറുകളും കണക്കാക്കാൻ, `start_index <= end_index` ആയ എല്ലാ \\(\mathrm{start\_probabilities}[\mathrm{start\_index}] \times \mathrm{end\_probabilities}[\mathrm{end\_index}]\\) ഗുണനഫലങ്ങളും (products) നമ്മൾ കണക്കാക്കിയാൽ മതി. + +ആദ്യം സാധ്യമായ എല്ലാ ഗുണനഫലങ്ങളും കണക്കാക്കാം: + +```py +scores = start_probabilities[:, None] * end_probabilities[None, :] +``` + +{#if fw === 'pt'} + +തുടർന്ന്, `start_index > end_index` ആയ മൂല്യങ്ങളെ `0` ആയി സെറ്റ് ചെയ്തുകൊണ്ട് നമ്മൾ അവയെ മാസ്‌ക് ചെയ്യും (മറ്റ് പ്രോബബിലിറ്റികളെല്ലാം പോസിറ്റീവ് സംഖ്യകളാണ്). ആർഗ്യുമെന്റായി നൽകുന്ന 2D ടെൻസറിന്റെ മുകളിലെ ത്രികോണഭാഗം (upper triangular part) `torch.triu()` ഫംഗ്‌ഷൻ റിട്ടേൺ ചെയ്യുന്നു, അതിനാൽ ആ മാസ്‌കിംഗ് അത് നമുക്കായി ചെയ്യും: + +```py +scores = torch.triu(scores) +``` + +{:else} + +തുടർന്ന്, `start_index > end_index` ആയ മൂല്യങ്ങളെ `0` ആയി സെറ്റ് ചെയ്തുകൊണ്ട് നമ്മൾ അവയെ മാസ്‌ക് ചെയ്യും (മറ്റ് പ്രോബബിലിറ്റികളെല്ലാം പോസിറ്റീവ് സംഖ്യകളാണ്). ആർഗ്യുമെന്റായി നൽകുന്ന 2D ടെൻസറിന്റെ മുകളിലെ ത്രികോണഭാഗം (upper triangular part) `np.triu()` ഫംഗ്‌ഷൻ റിട്ടേൺ ചെയ്യുന്നു, അതിനാൽ ആ മാസ്‌കിംഗ് അത് നമുക്കായി ചെയ്യും: + +```py +import numpy as np + +scores = np.triu(scores) +``` + +{/if} + +ഇനി പരമാവധി മൂല്യത്തിന്റെ ഇൻഡെക്‌സ് എടുക്കുകയേ വേണ്ടൂ. ഫ്ലാറ്റൻ ചെയ്ത (flattened) ടെൻസറിലെ ഇൻഡെക്‌സാണ് PyTorch റിട്ടേൺ ചെയ്യുന്നത് എന്നതിനാൽ, `start_index`-ഉം `end_index`-ഉം ലഭിക്കാൻ ഫ്ലോർ ഡിവിഷൻ `//`, മോഡുലസ് `%` എന്നീ ഓപ്പറേഷനുകൾ നമ്മൾ ഉപയോഗിക്കണം: + +```py +max_index = scores.argmax().item() +start_index = max_index // scores.shape[1] +end_index = max_index % scores.shape[1] +print(scores[start_index, end_index]) +``` + +നമ്മൾ ഇതുവരെ പൂർണ്ണമായി തീർന്നിട്ടില്ല, എന്നാൽ ഉത്തരത്തിനുള്ള ശരിയായ സ്‌കോർ ഇപ്പോൾ തന്നെ നമുക്ക് ലഭിച്ചിട്ടുണ്ട് (മുൻ ഭാഗത്തിലെ ആദ്യ ഫലവുമായി താരതമ്യം ചെയ്ത് നിങ്ങൾക്ക് ഇത് പരിശോധിക്കാം): + +```python out +0.97773 +``` + +> [!TIP] +> ✏️ **പരീക്ഷിച്ചു നോക്കൂ!** ഏറ്റവും സാധ്യതയുള്ള അഞ്ച് ഉത്തരങ്ങളുടെ ആരംഭ, അവസാന ഇൻഡെക്‌സുകൾ കണക്കാക്കുക. + +ടോക്കണുകളുടെ അടിസ്ഥാനത്തിൽ ഉത്തരത്തിന്റെ `start_index`-ഉം `end_index`-ഉം നമുക്ക് ലഭിച്ചു, അതിനാൽ ഇനി കോൺടെക്‌സ്‌റ്റിലെ അക്ഷര ഇൻഡെക്‌സുകളിലേക്ക് (character indices) മാറ്റുകയേ വേണ്ടൂ. ഇവിടെയാണ് ഓഫ്‌സെറ്റുകൾ വളരെ ഉപകാരപ്രദമാകുന്നത്. ടോക്കൺ ക്ലാസിഫിക്കേഷൻ ടാസ്‌കിൽ ചെയ്തതുപോലെ അവ എടുത്ത് ഉപയോഗിക്കാം: + +```py +inputs_with_offsets = tokenizer(question, context, return_offsets_mapping=True) +offsets = inputs_with_offsets["offset_mapping"] + +start_char, _ = offsets[start_index] +_, end_char = offsets[end_index] +answer = context[start_char:end_char] +``` + +ഇനി നമ്മുടെ ഫലം ലഭിക്കാൻ എല്ലാം ഫോർമാറ്റ് ചെയ്യുകയേ വേണ്ടൂ: + +```py +result = { + "answer": answer, + "start": start_char, + "end": end_char, + "score": scores[start_index, end_index], +} +print(result) +``` + +```python out +{'answer': 'Jax, PyTorch and TensorFlow', + 'start': 78, + 'end': 105, + 'score': 0.97773} +``` + +കൊള്ളാം! ഇത് നമ്മുടെ ആദ്യ ഉദാഹരണത്തിലേതിന് തുല്യമാണ്! + +> [!TIP] +> ✏️ **പരീക്ഷിച്ചു നോക്കൂ!** ഏറ്റവും സാധ്യതയുള്ള അഞ്ച് ഉത്തരങ്ങൾ കാണിക്കാൻ നിങ്ങൾ മുമ്പ് കണക്കാക്കിയ മികച്ച സ്‌കോറുകൾ ഉപയോഗിക്കുക. നിങ്ങളുടെ ഫലങ്ങൾ പരിശോധിക്കാൻ, ആദ്യത്തെ പൈപ്പ്‌ലൈനിലേക്ക് തിരിച്ചുപോയി അത് വിളിക്കുമ്പോൾ `top_k=5` നൽകുക. + +## നീണ്ട കോൺടെക്‌സ്‌റ്റുകൾ കൈകാര്യം ചെയ്യുന്നു[[handling-long-contexts]] + +മുമ്പ് ഉദാഹരണമായി ഉപയോഗിച്ച ചോദ്യവും നീണ്ട കോൺടെക്‌സ്‌റ്റും ടോക്കണൈസ് ചെയ്യാൻ ശ്രമിച്ചാൽ, `question-answering` പൈപ്പ്‌ലൈനിൽ ഉപയോഗിക്കുന്ന പരമാവധി ദൈർഘ്യത്തേക്കാൾ (അത് 384 ആണ്) കൂടുതൽ ടോക്കണുകൾ നമുക്ക് ലഭിക്കും: + +```py +inputs = tokenizer(question, long_context) +print(len(inputs["input_ids"])) +``` + +```python out +461 +``` + +അതിനാൽ, ആ പരമാവധി ദൈർഘ്യത്തിൽ നമ്മുടെ ഇൻപുട്ടുകൾ ട്രങ്കേറ്റ് ചെയ്യേണ്ടിവരും. ഇത് ചെയ്യാൻ പല വഴികളുണ്ട്, എന്നാൽ ചോദ്യം ട്രങ്കേറ്റ് ചെയ്യാൻ നമ്മൾ ആഗ്രഹിക്കുന്നില്ല, കോൺടെക്‌സ്‌റ്റ് മാത്രം. കോൺടെക്‌സ്‌റ്റ് രണ്ടാമത്തെ വാക്യമായതിനാൽ, `"only_second"` എന്ന ട്രങ്കേഷൻ സ്‌ട്രാറ്റജി നമ്മൾ ഉപയോഗിക്കും. അപ്പോൾ ഉയരുന്ന പ്രശ്‌നം, ചോദ്യത്തിന്റെ ഉത്തരം ട്രങ്കേറ്റ് ചെയ്ത കോൺടെക്‌സ്‌റ്റിൽ ഉണ്ടാകണമെന്നില്ല എന്നതാണ്. ഉദാഹരണത്തിന്, ഇവിടെ ഉത്തരം കോൺടെക്‌സ്‌റ്റിന്റെ അവസാനഭാഗത്തുള്ള ഒരു ചോദ്യമാണ് നമ്മൾ തിരഞ്ഞെടുത്തത്, അത് ട്രങ്കേറ്റ് ചെയ്യുമ്പോൾ ആ ഉത്തരം അതിൽ ഉണ്ടാകില്ല: + +```py +inputs = tokenizer(question, long_context, max_length=384, truncation="only_second") +print(tokenizer.decode(inputs["input_ids"])) +``` + +```python out +""" +[CLS] Which deep learning libraries back [UNK] Transformers? [SEP] [UNK] Transformers : State of the Art NLP + +[UNK] Transformers provides thousands of pretrained models to perform tasks on texts such as classification, information extraction, +question answering, summarization, translation, text generation and more in over 100 languages. +Its aim is to make cutting-edge NLP easier to use for everyone. + +[UNK] Transformers provides APIs to quickly download and use those pretrained models on a given text, fine-tune them on your own datasets and +then share them with the community on our model hub. At the same time, each python module defining an architecture is fully standalone and +can be modified to enable quick research experiments. + +Why should I use transformers? + +1. Easy-to-use state-of-the-art models: + - High performance on NLU and NLG tasks. + - Low barrier to entry for educators and practitioners. + - Few user-facing abstractions with just three classes to learn. + - A unified API for using all our pretrained models. + - Lower compute costs, smaller carbon footprint: + +2. Researchers can share trained models instead of always retraining. + - Practitioners can reduce compute time and production costs. + - Dozens of architectures with over 10,000 pretrained models, some in more than 100 languages. + +3. Choose the right framework for every part of a model's lifetime: + - Train state-of-the-art models in 3 lines of code. + - Move a single model between TF2.0/PyTorch frameworks at will. + - Seamlessly pick the right framework for training, evaluation and production. + +4. Easily customize a model or an example to your needs: + - We provide examples for each architecture to reproduce the results published by its original authors. + - Model internal [SEP] +""" +``` + +ഇതിനർത്ഥം, ശരിയായ ഉത്തരം തിരഞ്ഞെടുക്കാൻ മോഡലിന് ബുദ്ധിമുട്ടാകും എന്നാണ്. ഇത് പരിഹരിക്കാൻ, പരമാവധി ദൈർഘ്യം വ്യക്തമാക്കിക്കൊണ്ട് കോൺടെക്‌സ്‌റ്റിനെ ചെറിയ ചങ്കുകളായി (chunks) വിഭജിക്കാൻ `question-answering` പൈപ്പ്‌ലൈൻ നമ്മെ അനുവദിക്കുന്നു. ഉത്തരം കണ്ടെത്താൻ കഴിയാത്ത തരത്തിൽ കൃത്യമായി തെറ്റായ സ്ഥലത്ത് കോൺടെക്‌സ്‌റ്റ് വിഭജിക്കപ്പെടുന്നില്ല എന്ന് ഉറപ്പാക്കാൻ, ചങ്കുകൾക്കിടയിൽ കുറച്ച് ഓവർലാപ്പും (overlap) അത് ഉൾപ്പെടുത്തുന്നു. + +`return_overflowing_tokens=True` ചേർത്തുകൊണ്ട് ടോക്കണൈസറിനെ (ഫാസ്‌റ്റോ സ്ലോയോ) ഇത് നമുക്കായി ചെയ്യിക്കാം, കൂടാതെ നമുക്ക് വേണ്ട ഓവർലാപ്പ് `stride` ആർഗ്യുമെന്റ് ഉപയോഗിച്ച് വ്യക്തമാക്കാം. ഒരു ചെറിയ വാക്യം ഉപയോഗിച്ചുള്ള ഒരു ഉദാഹരണം ഇതാ: + +```py +sentence = "This sentence is not too long but we are going to split it anyway." +inputs = tokenizer( + sentence, truncation=True, return_overflowing_tokens=True, max_length=6, stride=2 +) + +for ids in inputs["input_ids"]: + print(tokenizer.decode(ids)) +``` + +```python out +'[CLS] This sentence is not [SEP]' +'[CLS] is not too long [SEP]' +'[CLS] too long but we [SEP]' +'[CLS] but we are going [SEP]' +'[CLS] are going to split [SEP]' +'[CLS] to split it anyway [SEP]' +'[CLS] it anyway. [SEP]' +``` + +നമുക്ക് കാണാവുന്നതുപോലെ, `inputs["input_ids"]`-ലെ ഓരോ എൻട്രിയിലും പരമാവധി 6 ടോക്കണുകൾ മാത്രമുള്ള രീതിയിൽ വാക്യം ചങ്കുകളായി വിഭജിക്കപ്പെട്ടിരിക്കുന്നു (അവസാനത്തെ എൻട്രി മറ്റുള്ളവയുടെ അതേ വലുപ്പത്തിലാകാൻ നമ്മൾ പാഡിംഗ് ചേർക്കേണ്ടിവരും), കൂടാതെ ഓരോ എൻട്രിക്കുമിടയിൽ 2 ടോക്കണുകളുടെ ഓവർലാപ്പുമുണ്ട്. + +ടോക്കണൈസേഷന്റെ ഫലം കുറച്ചുകൂടി അടുത്ത് പരിശോധിക്കാം: + +```py +print(inputs.keys()) +``` + +```python out +dict_keys(['input_ids', 'attention_mask', 'overflow_to_sample_mapping']) +``` + +പ്രതീക്ഷിച്ചതുപോലെ, ഇൻപുട്ട് ID-കളും ഒരു അറ്റൻഷൻ മാസ്‌കും നമുക്ക് ലഭിക്കുന്നു. അവസാനത്തെ കീ, `overflow_to_sample_mapping`, ഓരോ ഫലവും ഏത് വാക്യത്തിനോട് ബന്ധപ്പെട്ടതാണെന്ന് നമ്മോട് പറയുന്ന ഒരു മാപ്പാണ് -- ഇവിടെ നമുക്ക് 7 ഫലങ്ങളുണ്ട്, അവയെല്ലാം ടോക്കണൈസറിന് നമ്മൾ നൽകിയ (ഒരേയൊരു) വാക്യത്തിൽ നിന്നാണ് വരുന്നത്: + +```py +print(inputs["overflow_to_sample_mapping"]) +``` + +```python out +[0, 0, 0, 0, 0, 0, 0] +``` + +നിരവധി വാക്യങ്ങൾ ഒരുമിച്ച് ടോക്കണൈസ് ചെയ്യുമ്പോഴാണ് ഇത് കൂടുതൽ ഉപകാരപ്രദമാകുന്നത്. ഉദാഹരണത്തിന്, ഇത്: + +```py +sentences = [ + "This sentence is not too long but we are going to split it anyway.", + "This sentence is shorter but will still get split.", +] +inputs = tokenizer( + sentences, truncation=True, return_overflowing_tokens=True, max_length=6, stride=2 +) + +print(inputs["overflow_to_sample_mapping"]) +``` + +നമുക്ക് നൽകുന്നത്: + +```python out +[0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1] +``` + +ഇതിനർത്ഥം, ആദ്യത്തെ വാക്യം മുമ്പത്തെപ്പോലെ 7 ചങ്കുകളായി വിഭജിക്കപ്പെട്ടിരിക്കുന്നു, അടുത്ത 4 ചങ്കുകൾ രണ്ടാമത്തെ വാക്യത്തിൽ നിന്നാണ് വരുന്നത് എന്നാണ്. + +ഇനി നമ്മുടെ നീണ്ട കോൺടെക്‌സ്‌റ്റിലേക്ക് തിരിച്ചുപോകാം. മുമ്പ് സൂചിപ്പിച്ചതുപോലെ, `question-answering` പൈപ്പ്‌ലൈൻ ഡിഫോൾട്ടായി 384 എന്ന പരമാവധി ദൈർഘ്യവും 128 എന്ന സ്‌ട്രൈഡും (stride) ഉപയോഗിക്കുന്നു; മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യപ്പെട്ട രീതിയോട് യോജിക്കുന്നവയാണ് ഇവ (പൈപ്പ്‌ലൈൻ വിളിക്കുമ്പോൾ `max_seq_len`, `stride` എന്നീ ആർഗ്യുമെന്റുകൾ നൽകിക്കൊണ്ട് ആ പാരാമീറ്ററുകൾ നിങ്ങൾക്ക് ക്രമീകരിക്കാം). അതിനാൽ ടോക്കണൈസ് ചെയ്യുമ്പോൾ ആ പാരാമീറ്ററുകൾ നമ്മൾ ഉപയോഗിക്കും. പാഡിംഗ് ചേർക്കുകയും (ഒരേ ദൈർഘ്യമുള്ള സാമ്പിളുകൾ ലഭിക്കാൻ, അങ്ങനെ നമുക്ക് ടെൻസറുകൾ നിർമ്മിക്കാം) ഓഫ്‌സെറ്റുകൾ ആവശ്യപ്പെടുകയും നമ്മൾ ചെയ്യും: + +```py +inputs = tokenizer( + question, + long_context, + stride=128, + max_length=384, + padding="longest", + truncation="only_second", + return_overflowing_tokens=True, + return_offsets_mapping=True, +) +``` + +ആ `inputs`-ൽ, മോഡൽ പ്രതീക്ഷിക്കുന്ന ഇൻപുട്ട് ID-കളും അറ്റൻഷൻ മാസ്‌കുകളും, കൂടാതെ ഓഫ്‌സെറ്റുകളും നമ്മൾ ഇപ്പോൾ സംസാരിച്ച `overflow_to_sample_mapping`-ഉം ഉണ്ടാകും. ഈ രണ്ടെണ്ണം മോഡൽ ഉപയോഗിക്കുന്ന പാരാമീറ്ററുകളല്ലാത്തതിനാൽ, ടെൻസറാക്കി മാറ്റുന്നതിനുമുമ്പ് അവയെ `inputs`-ൽ നിന്ന് നമ്മൾ pop ചെയ്ത് പുറത്തെടുക്കും (ഇവിടെ ഉപകാരപ്രദമല്ലാത്തതിനാൽ മാപ്പ് നമ്മൾ സൂക്ഷിച്ചുവയ്ക്കുകയില്ല): + +{#if fw === 'pt'} + +```py +_ = inputs.pop("overflow_to_sample_mapping") +offsets = inputs.pop("offset_mapping") + +inputs = inputs.convert_to_tensors("pt") +print(inputs["input_ids"].shape) +``` + +```python out +torch.Size([2, 384]) +``` + +{:else} + +```py +_ = inputs.pop("overflow_to_sample_mapping") +offsets = inputs.pop("offset_mapping") + +inputs = inputs.convert_to_tensors("tf") +print(inputs["input_ids"].shape) +``` + +```python out +(2, 384) +``` + +{/if} + +നമ്മുടെ നീണ്ട കോൺടെക്‌സ്‌റ്റ് രണ്ടായി വിഭജിക്കപ്പെട്ടു, അതിനർത്ഥം അത് നമ്മുടെ മോഡലിലൂടെ കടന്നുപോയ ശേഷം, ആരംഭ, അവസാന ലോജിറ്റുകളുടെ രണ്ട് സെറ്റുകൾ നമുക്ക് ഉണ്ടാകും എന്നാണ്: + +```py +outputs = model(**inputs) + +start_logits = outputs.start_logits +end_logits = outputs.end_logits +print(start_logits.shape, end_logits.shape) +``` + +{#if fw === 'pt'} + +```python out +torch.Size([2, 384]) torch.Size([2, 384]) +``` + +{:else} + +```python out +(2, 384) (2, 384) +``` + +{/if} + +മുമ്പത്തെപ്പോലെ, സോഫ്‌റ്റ്‌മാക്‌സ് എടുക്കുന്നതിനുമുമ്പ് കോൺടെക്‌സ്‌റ്റിന്റെ ഭാഗമല്ലാത്ത ടോക്കണുകൾ നമ്മൾ ആദ്യം മാസ്‌ക് ചെയ്യുന്നു. എല്ലാ പാഡിംഗ് ടോക്കണുകളും (അറ്റൻഷൻ മാസ്‌ക് അടയാളപ്പെടുത്തിയിരിക്കുന്നതനുസരിച്ച്) നമ്മൾ മാസ്‌ക് ചെയ്യുന്നു: + +{#if fw === 'pt'} + +```py +sequence_ids = inputs.sequence_ids() +# Mask everything apart from the tokens of the context +mask = [i != 1 for i in sequence_ids] +# Unmask the [CLS] token +mask[0] = False +# Mask all the [PAD] tokens +mask = torch.logical_or(torch.tensor(mask)[None], (inputs["attention_mask"] == 0)) + +start_logits[mask] = -10000 +end_logits[mask] = -10000 +``` + +{:else} + +```py +sequence_ids = inputs.sequence_ids() +# Mask everything apart from the tokens of the context +mask = [i != 1 for i in sequence_ids] +# Unmask the [CLS] token +mask[0] = False +# Mask all the [PAD] tokens +mask = tf.math.logical_or(tf.constant(mask)[None], inputs["attention_mask"] == 0) + +start_logits = tf.where(mask, -10000, start_logits) +end_logits = tf.where(mask, -10000, end_logits) +``` + +{/if} + +തുടർന്ന്, നമ്മുടെ ലോജിറ്റുകളെ പ്രോബബിലിറ്റികളാക്കി മാറ്റാൻ സോഫ്‌റ്റ്‌മാക്‌സ് ഉപയോഗിക്കാം: + +{#if fw === 'pt'} + +```py +start_probabilities = torch.nn.functional.softmax(start_logits, dim=-1) +end_probabilities = torch.nn.functional.softmax(end_logits, dim=-1) +``` + +{:else} + +```py +start_probabilities = tf.math.softmax(start_logits, axis=-1).numpy() +end_probabilities = tf.math.softmax(end_logits, axis=-1).numpy() +``` + +{/if} + +അടുത്ത ഘട്ടം ചെറിയ കോൺടെക്‌സ്‌റ്റിനായി നമ്മൾ ചെയ്തതിന് സമാനമാണ്, എന്നാൽ നമ്മുടെ രണ്ട് ചങ്കുകളിൽ ഓരോന്നിനും അത് ആവർത്തിക്കുന്നു. ഉത്തരത്തിന്റെ സാധ്യമായ എല്ലാ സ്‌പാനുകൾക്കും (spans) നമ്മൾ ഒരു സ്‌കോർ നൽകുന്നു, തുടർന്ന് ഏറ്റവും മികച്ച സ്‌കോറുള്ള സ്‌പാൻ എടുക്കുന്നു: + +{#if fw === 'pt'} + +```py +candidates = [] +for start_probs, end_probs in zip(start_probabilities, end_probabilities): + scores = start_probs[:, None] * end_probs[None, :] + idx = torch.triu(scores).argmax().item() + + start_idx = idx // scores.shape[1] + end_idx = idx % scores.shape[1] + score = scores[start_idx, end_idx].item() + candidates.append((start_idx, end_idx, score)) + +print(candidates) +``` + +{:else} + +```py +candidates = [] +for start_probs, end_probs in zip(start_probabilities, end_probabilities): + scores = start_probs[:, None] * end_probs[None, :] + idx = np.triu(scores).argmax().item() + + start_idx = idx // scores.shape[1] + end_idx = idx % scores.shape[1] + score = scores[start_idx, end_idx].item() + candidates.append((start_idx, end_idx, score)) + +print(candidates) +``` + +{/if} + +```python out +[(0, 18, 0.33867), (173, 184, 0.97149)] +``` + +ഓരോ ചങ്കിലും മോഡലിന് കണ്ടെത്താൻ കഴിഞ്ഞ മികച്ച ഉത്തരങ്ങളാണ് ആ രണ്ട് കാൻഡിഡേറ്റുകൾ. ശരിയായ ഉത്തരം രണ്ടാം ഭാഗത്തിലാണെന്ന് മോഡലിന് വളരെയധികം ആത്മവിശ്വാസമുണ്ട് (അത് ഒരു നല്ല സൂചനയാണ്!). ഇനി ആ രണ്ട് ടോക്കൺ സ്‌പാനുകളെ കോൺടെക്‌സ്‌റ്റിലെ അക്ഷര സ്‌പാനുകളിലേക്ക് മാപ്പ് ചെയ്യുകയേ വേണ്ടൂ (നമ്മുടെ ഉത്തരം ലഭിക്കാൻ രണ്ടാമത്തേത് മാത്രം മാപ്പ് ചെയ്താൽ മതി, എന്നാൽ ആദ്യ ചങ്കിൽ മോഡൽ എന്താണ് തിരഞ്ഞെടുത്തത് എന്ന് കാണുന്നത് രസകരമാണ്). + +> [!TIP] +> ✏️ **പരീക്ഷിച്ചു നോക്കൂ!** ഏറ്റവും സാധ്യതയുള്ള അഞ്ച് ഉത്തരങ്ങളുടെ (ഓരോ ചങ്കിലും അല്ല, മൊത്തത്തിൽ) സ്‌കോറുകളും സ്‌പാനുകളും റിട്ടേൺ ചെയ്യാൻ മുകളിലെ കോഡ് അനുയോജ്യമായി മാറ്റുക. + +നമ്മൾ മുമ്പ് എടുത്ത `offsets` യഥാർത്ഥത്തിൽ ഓഫ്‌സെറ്റുകളുടെ ഒരു ലിസ്‌റ്റാണ്; ടെക്‌സ്‌റ്റിന്റെ ഓരോ ചങ്കിനും ഒരു ലിസ്‌റ്റ് വീതം: + +```py +for candidate, offset in zip(candidates, offsets): + start_token, end_token, score = candidate + start_char, _ = offset[start_token] + _, end_char = offset[end_token] + answer = long_context[start_char:end_char] + result = {"answer": answer, "start": start_char, "end": end_char, "score": score} + print(result) +``` + +```python out +{'answer': '\n🤗 Transformers: State of the Art NLP', 'start': 0, 'end': 37, 'score': 0.33867} +{'answer': 'Jax, PyTorch and TensorFlow', 'start': 1892, 'end': 1919, 'score': 0.97149} +``` + +ആദ്യ ഫലം അവഗണിച്ചാൽ, ഈ നീണ്ട കോൺടെക്‌സ്‌റ്റിന് നമ്മുടെ പൈപ്പ്‌ലൈൻ നൽകിയ അതേ ഫലം നമുക്ക് ലഭിക്കുന്നു -- ഹുറേ! + +> [!TIP] +> ✏️ **പരീക്ഷിച്ചു നോക്കൂ!** ഏറ്റവും സാധ്യതയുള്ള അഞ്ച് ഉത്തരങ്ങൾ (ഓരോ ചങ്കിനുമല്ല, മുഴുവൻ കോൺടെക്‌സ്‌റ്റിനും) കാണിക്കാൻ നിങ്ങൾ മുമ്പ് കണക്കാക്കിയ മികച്ച സ്‌കോറുകൾ ഉപയോഗിക്കുക. നിങ്ങളുടെ ഫലങ്ങൾ പരിശോധിക്കാൻ, ആദ്യത്തെ പൈപ്പ്‌ലൈനിലേക്ക് തിരിച്ചുപോയി അത് വിളിക്കുമ്പോൾ `top_k=5` നൽകുക. + +ടോക്കണൈസറിന്റെ കഴിവുകളിലേക്കുള്ള നമ്മുടെ ആഴത്തിലുള്ള അന്വേഷണം ഇവിടെ അവസാനിക്കുന്നു. സാധാരണമായ വിവിധ NLP ടാസ്‌കുകളിൽ ഒരു മോഡൽ എങ്ങനെ ഫൈൻ-ട്യൂൻ ചെയ്യാമെന്ന് കാണിച്ചുതരുന്ന അടുത്ത അധ്യായത്തിൽ, ഇതെല്ലാം നമ്മൾ വീണ്ടും പ്രായോഗികമായി ഉപയോഗിക്കും. diff --git a/chapters/ml/chapter6/4.mdx b/chapters/ml/chapter6/4.mdx new file mode 100644 index 000000000..6552bd16c --- /dev/null +++ b/chapters/ml/chapter6/4.mdx @@ -0,0 +1,120 @@ +# നോർമലൈസേഷനും പ്രീ-ടോക്കണൈസേഷനും[[normalization-and-pre-tokenization]] + + + +Transformer മോഡലുകളിൽ ഉപയോഗിക്കുന്ന ഏറ്റവും സാധാരണമായ മൂന്ന് സബ്‌വേഡ് ടോക്കണൈസേഷൻ അൽഗോരിതങ്ങളിലേക്ക് (Byte-Pair Encoding [BPE], WordPiece, Unigram എന്നിവ) കൂടുതൽ ആഴത്തിൽ കടക്കുന്നതിന് മുമ്പ്, ഓരോ ടോക്കണൈസറും ടെക്‌സ്‌റ്റിൽ പ്രയോഗിക്കുന്ന പ്രീപ്രോസസ്സിംഗ് (preprocessing) നമുക്ക് ആദ്യം ഒന്ന് നോക്കാം. ടോക്കണൈസേഷൻ പൈപ്പ്‌ലൈനിലെ ഘട്ടങ്ങളുടെ ഒരു ഉയർന്ന തലത്തിലുള്ള അവലോകനം ഇതാ: + +
+ടോക്കണൈസേഷൻ പൈപ്പ്‌ലൈൻ. + +
+ +ഒരു ടെക്‌സ്‌റ്റിനെ (അതിന്റെ മോഡലിന് അനുസരിച്ച്) സബ്‌ടോക്കണുകളായി വിഭജിക്കുന്നതിന് മുമ്പ്, ടോക്കണൈസർ രണ്ട് ഘട്ടങ്ങൾ നിർവഹിക്കുന്നു: _നോർമലൈസേഷൻ_ (normalization), _പ്രീ-ടോക്കണൈസേഷൻ_ (pre-tokenization). + +## നോർമലൈസേഷൻ[[normalization]] + + + +അനാവശ്യമായ വൈറ്റ്‌സ്‌പേസ് (whitespace) നീക്കം ചെയ്യുക, അക്ഷരങ്ങളെ ചെറിയക്ഷരങ്ങളാക്കുക (lowercasing), ആക്‌സന്റുകൾ (accents) നീക്കം ചെയ്യുക തുടങ്ങിയ പൊതുവായ ചില ശുദ്ധീകരണ ജോലികളാണ് നോർമലൈസേഷൻ ഘട്ടത്തിൽ ഉൾപ്പെടുന്നത്. [Unicode നോർമലൈസേഷൻ](http://www.unicode.org/reports/tr15/) (NFC അല്ലെങ്കിൽ NFKC പോലുള്ളവ) നിങ്ങൾക്ക് പരിചിതമാണെങ്കിൽ, അതും ടോക്കണൈസർ പ്രയോഗിക്കാൻ സാധ്യതയുള്ള ഒരു കാര്യമാണ്. + +🤗 Transformers-ലെ `tokenizer`-ന് `backend_tokenizer` എന്ന ഒരു ആട്രിബ്യൂട്ട് ഉണ്ട്; 🤗 Tokenizers ലൈബ്രറിയിൽ നിന്നുള്ള അടിസ്ഥാന ടോക്കണൈസറിലേക്ക് ഇത് ആക്‌സസ് നൽകുന്നു: + +```py +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-uncased") +print(type(tokenizer.backend_tokenizer)) +``` + +```python out + +``` + +`tokenizer` ഒബ്‌ജക്റ്റിന്റെ `normalizer` ആട്രിബ്യൂട്ടിന് ഒരു `normalize_str()` മെത്തേഡ് ഉണ്ട്; നോർമലൈസേഷൻ എങ്ങനെയാണ് നടക്കുന്നത് എന്ന് കാണാൻ നമുക്ക് ഇത് ഉപയോഗിക്കാം: + +```py +print(tokenizer.backend_tokenizer.normalizer.normalize_str("Héllò hôw are ü?")) +``` + +```python out +'hello how are u?' +``` + +ഈ ഉദാഹരണത്തിൽ, നമ്മൾ `bert-base-uncased` ചെക്ക്‌പോയിന്റ് തിരഞ്ഞെടുത്തതിനാൽ, നോർമലൈസേഷൻ അക്ഷരങ്ങളെ ചെറിയക്ഷരങ്ങളാക്കുകയും ആക്‌സന്റുകൾ നീക്കം ചെയ്യുകയും ചെയ്തു. + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** `bert-base-cased` ചെക്ക്‌പോയിന്റിൽ നിന്ന് ഒരു ടോക്കണൈസർ ലോഡ് ചെയ്ത്, അതേ ഉദാഹരണം അതിന് നൽകുക. ടോക്കണൈസറിന്റെ cased, uncased പതിപ്പുകൾക്കിടയിൽ നിങ്ങൾക്ക് കാണാൻ കഴിയുന്ന പ്രധാന വ്യത്യാസങ്ങൾ എന്തൊക്കെയാണ്? + +## പ്രീ-ടോക്കണൈസേഷൻ[[pre-tokenization]] + + + +അടുത്ത ഭാഗങ്ങളിൽ നമ്മൾ കാണാൻ പോകുന്നതുപോലെ, ഒരു ടോക്കണൈസറിനെ റോ ടെക്‌സ്‌റ്റിൽ (raw text) മാത്രം ട്രെയിൻ ചെയ്യാൻ കഴിയില്ല. പകരം, ടെക്‌സ്‌റ്റുകളെ വാക്കുകൾ പോലുള്ള ചെറിയ ഘടകങ്ങളായി നമ്മൾ ആദ്യം വിഭജിക്കേണ്ടതുണ്ട്. അവിടെയാണ് പ്രീ-ടോക്കണൈസേഷൻ ഘട്ടം കടന്നുവരുന്നത്. [അധ്യായം 2](/course/chapter2)-ൽ നമ്മൾ കണ്ടതുപോലെ, ഒരു വേഡ്-ബേസ്ഡ് ടോക്കണൈസറിന് (word-based tokenizer) റോ ടെക്‌സ്‌റ്റിനെ വൈറ്റ്‌സ്‌പേസും ചിഹ്നങ്ങളും (punctuation) അടിസ്ഥാനമാക്കി ലളിതമായി വാക്കുകളായി വിഭജിക്കാൻ കഴിയും. ട്രെയിനിംഗ് സമയത്ത് ടോക്കണൈസറിന് പഠിക്കാൻ കഴിയുന്ന സബ്‌ടോക്കണുകളുടെ അതിരുകളായിരിക്കും ആ വാക്കുകൾ. + +ഒരു ഫാസ്‌റ്റ് ടോക്കണൈസർ പ്രീ-ടോക്കണൈസേഷൻ എങ്ങനെ നടത്തുന്നു എന്ന് കാണാൻ, `tokenizer` ഒബ്‌ജക്റ്റിന്റെ `pre_tokenizer` ആട്രിബ്യൂട്ടിന്റെ `pre_tokenize_str()` മെത്തേഡ് നമുക്ക് ഉപയോഗിക്കാം: + +```py +tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, how are you?") +``` + +```python out +[('Hello', (0, 5)), (',', (5, 6)), ('how', (7, 10)), ('are', (11, 14)), ('you', (16, 19)), ('?', (19, 20))] +``` + +ടോക്കണൈസർ ഇപ്പോൾത്തന്നെ ഓഫ്‌സെറ്റുകൾ (offsets) ട്രാക്ക് ചെയ്യുന്നത് ശ്രദ്ധിക്കുക; മുൻ ഭാഗത്തിൽ നമ്മൾ ഉപയോഗിച്ച ഓഫ്‌സെറ്റ് മാപ്പിംഗ് നമുക്ക് നൽകാൻ അതിന് കഴിയുന്നത് ഇങ്ങനെയാണ്. ഇവിടെ ടോക്കണൈസർ രണ്ട് സ്‌പേസുകളെ അവഗണിച്ച് അവയെ ഒരെണ്ണം കൊണ്ട് മാറ്റുന്നു, എന്നാൽ അത് കണക്കിലെടുക്കാൻ `are`-നും `you`-വിനും ഇടയിൽ ഓഫ്‌സെറ്റ് ചാടുന്നു. + +നമ്മൾ ഒരു BERT ടോക്കണൈസർ ഉപയോഗിക്കുന്നതിനാൽ, വൈറ്റ്‌സ്‌പേസും ചിഹ്നങ്ങളും അടിസ്ഥാനമാക്കി വിഭജിക്കുന്നതാണ് പ്രീ-ടോക്കണൈസേഷനിൽ ഉൾപ്പെടുന്നത്. മറ്റ് ടോക്കണൈസറുകൾക്ക് ഈ ഘട്ടത്തിന് വ്യത്യസ്ത നിയമങ്ങളുണ്ടാകാം. ഉദാഹരണത്തിന്, GPT-2 ടോക്കണൈസർ ഉപയോഗിച്ചാൽ: + +```py +tokenizer = AutoTokenizer.from_pretrained("gpt2") +tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, how are you?") +``` + +അതും വൈറ്റ്‌സ്‌പേസും ചിഹ്നങ്ങളും അടിസ്ഥാനമാക്കി വിഭജിക്കും, എന്നാൽ അത് സ്‌പേസുകളെ നിലനിർത്തി അവയെ ഒരു `Ġ` ചിഹ്നം കൊണ്ട് മാറ്റും; ടോക്കണുകൾ ഡീകോഡ് ചെയ്യുമ്പോൾ യഥാർത്ഥ സ്‌പേസുകൾ വീണ്ടെടുക്കാൻ ഇത് അതിനെ പ്രാപ്‌തമാക്കുന്നു: + +```python out +[('Hello', (0, 5)), (',', (5, 6)), ('Ġhow', (6, 10)), ('Ġare', (10, 14)), ('Ġ', (14, 15)), ('Ġyou', (15, 19)), + ('?', (19, 20))] +``` + +BERT ടോക്കണൈസറിൽ നിന്ന് വ്യത്യസ്തമായി, ഈ ടോക്കണൈസർ ഇരട്ട സ്‌പേസിനെ അവഗണിക്കുന്നില്ല എന്നതും ശ്രദ്ധിക്കുക. + +അവസാന ഉദാഹരണമായി, SentencePiece അൽഗോരിതം അടിസ്ഥാനമാക്കിയുള്ള T5 ടോക്കണൈസർ നമുക്ക് ഒന്ന് നോക്കാം: + +```py +tokenizer = AutoTokenizer.from_pretrained("t5-small") +tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str("Hello, how are you?") +``` + +```python out +[('▁Hello,', (0, 6)), ('▁how', (7, 10)), ('▁are', (11, 14)), ('▁you?', (16, 20))] +``` + +GPT-2 ടോക്കണൈസർ പോലെ, ഇതും സ്‌പേസുകളെ നിലനിർത്തി അവയെ ഒരു പ്രത്യേക ടോക്കൺ (`_`) കൊണ്ട് മാറ്റുന്നു, എന്നാൽ T5 ടോക്കണൈസർ വൈറ്റ്‌സ്‌പേസ് അടിസ്ഥാനമാക്കി മാത്രമേ വിഭജിക്കുന്നുള്ളൂ, ചിഹ്നങ്ങൾ അടിസ്ഥാനമാക്കിയല്ല. വാക്യത്തിന്റെ തുടക്കത്തിൽ (`Hello`-യുടെ മുമ്പ്) അത് ഡിഫോൾട്ടായി ഒരു സ്‌പേസ് ചേർത്തു എന്നതും `are`-നും `you`-വിനും ഇടയിലുള്ള ഇരട്ട സ്‌പേസിനെ അവഗണിച്ചു എന്നതും ശ്രദ്ധിക്കുക. + +വ്യത്യസ്ത ടോക്കണൈസറുകൾ ടെക്‌സ്‌റ്റ് എങ്ങനെ പ്രോസസ്സ് ചെയ്യുന്നു എന്ന് കുറച്ചൊക്കെ കണ്ടുകഴിഞ്ഞ സ്ഥിതിക്ക്, അടിസ്ഥാന അൽഗോരിതങ്ങളെത്തന്നെ പരിശോധിക്കാൻ നമുക്ക് തുടങ്ങാം. വ്യാപകമായി ഉപയോഗിക്കാവുന്ന SentencePiece-നെ വേഗത്തിൽ ഒന്ന് നോക്കിക്കൊണ്ടാണ് നമ്മൾ ആരംഭിക്കുന്നത്; പിന്നീട്, അടുത്ത മൂന്ന് ഭാഗങ്ങളിലായി, സബ്‌വേഡ് ടോക്കണൈസേഷന് ഉപയോഗിക്കുന്ന മൂന്ന് പ്രധാന അൽഗോരിതങ്ങൾ എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് നമ്മൾ പരിശോധിക്കും. + +## SentencePiece[[sentencepiece]] + +[SentencePiece](https://github.com/google/sentencepiece) എന്നത് ടെക്‌സ്‌റ്റിന്റെ പ്രീപ്രോസസ്സിംഗിനുള്ള ഒരു ടോക്കണൈസേഷൻ അൽഗോരിതമാണ്; അടുത്ത മൂന്ന് ഭാഗങ്ങളിൽ നമ്മൾ കാണാൻ പോകുന്ന ഏത് മോഡലിനോടൊപ്പവും നിങ്ങൾക്ക് ഇത് ഉപയോഗിക്കാം. ഇത് ടെക്‌സ്‌റ്റിനെ Unicode അക്ഷരങ്ങളുടെ (characters) ഒരു ശ്രേണിയായി പരിഗണിക്കുകയും, സ്‌പേസുകളെ `▁` എന്ന ഒരു പ്രത്യേക അക്ഷരം കൊണ്ട് മാറ്റുകയും ചെയ്യുന്നു. Unigram അൽഗോരിതത്തോടൊപ്പം ഉപയോഗിക്കുമ്പോൾ ([ഭാഗം 7](/course/chapter6/7) കാണുക), ഇതിന് ഒരു പ്രീ-ടോക്കണൈസേഷൻ ഘട്ടം പോലും ആവശ്യമില്ല; സ്‌പേസ് അക്ഷരം ഉപയോഗിക്കാത്ത ഭാഷകൾക്ക് (ചൈനീസ് അല്ലെങ്കിൽ ജാപ്പനീസ് പോലുള്ളവ) ഇത് വളരെ ഉപകാരപ്രദമാണ്. + +SentencePiece-ന്റെ മറ്റൊരു പ്രധാന സവിശേഷത *റിവേഴ്‌സിബിൾ ടോക്കണൈസേഷൻ* (reversible tokenization) ആണ്: സ്‌പേസുകൾക്ക് പ്രത്യേക പരിഗണനയൊന്നും ഇല്ലാത്തതിനാൽ, ടോക്കണുകളെ കൂട്ടിച്ചേർത്ത് `_`-കളെ സ്‌പേസുകൾ കൊണ്ട് മാറ്റുന്നതിലൂടെ മാത്രം ടോക്കണുകളുടെ ഡീകോഡിംഗ് നടക്കുന്നു -- ഇത് നോർമലൈസ് ചെയ്ത ടെക്‌സ്‌റ്റിലേക്ക് നയിക്കുന്നു. നമ്മൾ മുമ്പ് കണ്ടതുപോലെ, BERT ടോക്കണൈസർ ആവർത്തിക്കുന്ന സ്‌പേസുകളെ നീക്കം ചെയ്യുന്നു, അതിനാൽ അതിന്റെ ടോക്കണൈസേഷൻ റിവേഴ്‌സിബിൾ അല്ല. + +## അൽഗോരിതങ്ങളുടെ അവലോകനം[[algorithm-overview]] + +തുടർന്നുള്ള ഭാഗങ്ങളിൽ, മൂന്ന് പ്രധാന സബ്‌വേഡ് ടോക്കണൈസേഷൻ അൽഗോരിതങ്ങളിലേക്ക് നമ്മൾ ആഴത്തിൽ കടക്കും: BPE (GPT-2-ഉം മറ്റുള്ളവയും ഉപയോഗിക്കുന്നത്), WordPiece (ഉദാഹരണത്തിന് BERT ഉപയോഗിക്കുന്നത്), Unigram (T5-ഉം മറ്റുള്ളവയും ഉപയോഗിക്കുന്നത്). തുടങ്ങുന്നതിന് മുമ്പ്, ഇവ ഓരോന്നും എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്നതിന്റെ ഒരു ഹ്രസ്വ അവലോകനം ഇതാ. ഇത് നിങ്ങൾക്ക് ഇപ്പോൾ മനസ്സിലാകുന്നില്ലെങ്കിൽ, അടുത്ത ഓരോ ഭാഗവും വായിച്ചതിന് ശേഷം ഈ ടേബിളിലേക്ക് തിരിച്ചുവരാൻ മടിക്കേണ്ട. + + +മോഡൽ | BPE | WordPiece | Unigram +:----:|:---:|:---------:|:------: +ട്രെയിനിംഗ് | ഒരു ചെറിയ വൊക്കാബുലറിയിൽ നിന്ന് ആരംഭിച്ച്, ടോക്കണുകളെ മെർജ് ചെയ്യാനുള്ള (merge) നിയമങ്ങൾ പഠിക്കുന്നു | ഒരു ചെറിയ വൊക്കാബുലറിയിൽ നിന്ന് ആരംഭിച്ച്, ടോക്കണുകളെ മെർജ് ചെയ്യാനുള്ള നിയമങ്ങൾ പഠിക്കുന്നു | ഒരു വലിയ വൊക്കാബുലറിയിൽ നിന്ന് ആരംഭിച്ച്, ടോക്കണുകളെ നീക്കം ചെയ്യാനുള്ള നിയമങ്ങൾ പഠിക്കുന്നു +ട്രെയിനിംഗ് ഘട്ടം | ഏറ്റവും സാധാരണമായ ജോഡിക്ക് (pair) അനുയോജ്യമായ ടോക്കണുകളെ മെർജ് ചെയ്യുന്നു | ജോഡിയുടെ ആവൃത്തി (frequency) അടിസ്ഥാനമാക്കി ഏറ്റവും മികച്ച സ്‌കോർ ഉള്ള ജോഡിക്ക് അനുയോജ്യമായ ടോക്കണുകളെ മെർജ് ചെയ്യുന്നു; ഓരോ വ്യക്തിഗത ടോക്കണും കുറവ് ആവൃത്തിയുള്ള ജോഡികൾക്ക് മുൻഗണന നൽകുന്നു | മുഴുവൻ കോർപ്പസിലും കണക്കാക്കുന്ന ലോസ് ഏറ്റവും കുറയ്ക്കുന്ന തരത്തിൽ, വൊക്കാബുലറിയിലെ എല്ലാ ടോക്കണുകളെയും നീക്കം ചെയ്യുന്നു +പഠിക്കുന്നത് | മെർജ് നിയമങ്ങളും ഒരു വൊക്കാബുലറിയും | ഒരു വൊക്കാബുലറി മാത്രം | ഓരോ ടോക്കണിനും ഒരു സ്‌കോർ ഉള്ള ഒരു വൊക്കാബുലറി +എൻകോഡിംഗ് | ഒരു വാക്കിനെ അക്ഷരങ്ങളായി വിഭജിച്ച്, ട്രെയിനിംഗ് സമയത്ത് പഠിച്ച മെർജുകൾ പ്രയോഗിക്കുന്നു | വാക്കിന്റെ തുടക്കത്തിൽ നിന്ന് ആരംഭിക്കുന്ന, വൊക്കാബുലറിയിൽ ഉള്ള ഏറ്റവും നീളമുള്ള സബ്‌വേഡ് കണ്ടെത്തുന്നു, പിന്നീട് വാക്കിന്റെ ബാക്കി ഭാഗത്തിനും ഇതേ കാര്യം ചെയ്യുന്നു | ട്രെയിനിംഗ് സമയത്ത് പഠിച്ച സ്‌കോറുകൾ ഉപയോഗിച്ച്, ടോക്കണുകളിലേക്കുള്ള ഏറ്റവും സാധ്യതയുള്ള വിഭജനം കണ്ടെത്തുന്നു + +ഇനി നമുക്ക് BPE-യിലേക്ക് കടക്കാം! diff --git a/chapters/ml/chapter6/5.mdx b/chapters/ml/chapter6/5.mdx new file mode 100644 index 000000000..4b4170363 --- /dev/null +++ b/chapters/ml/chapter6/5.mdx @@ -0,0 +1,342 @@ +# Byte-Pair Encoding ടോക്കണൈസേഷൻ[[byte-pair-encoding-tokenization]] + + + +Byte-Pair Encoding (BPE) തുടക്കത്തിൽ ടെക്‌സ്‌റ്റുകൾ കംപ്രസ് ചെയ്യാനുള്ള ഒരു അൽഗോരിതമായാണ് വികസിപ്പിച്ചത്; പിന്നീട് GPT മോഡൽ പ്രീട്രെയിൻ ചെയ്യുമ്പോൾ ടോക്കണൈസേഷനായി OpenAI ഇത് ഉപയോഗിച്ചു. GPT, GPT-2, RoBERTa, BART, DeBERTa എന്നിവയുൾപ്പെടെ ധാരാളം Transformer മോഡലുകൾ ഇത് ഉപയോഗിക്കുന്നു. + + + +> [!TIP] +> 💡 ഒരു പൂർണ്ണമായ ഇംപ്ലിമെന്റേഷൻ (implementation) കാണിക്കുന്നത് വരെ പോകുന്ന തരത്തിൽ, ഈ ഭാഗം BPE-യെ ആഴത്തിൽ പരിശോധിക്കുന്നു. ടോക്കണൈസേഷൻ അൽഗോരിതത്തിന്റെ ഒരു പൊതുവായ അവലോകനം മാത്രമാണ് നിങ്ങൾക്ക് വേണ്ടതെങ്കിൽ, നിങ്ങൾക്ക് നേരെ അവസാനത്തേക്ക് പോകാം. + +## ട്രെയിനിംഗ് അൽഗോരിതം[[training-algorithm]] + +കോർപ്പസിൽ (corpus) ഉപയോഗിച്ചിരിക്കുന്ന വാക്കുകളുടെ അനന്യമായ (unique) ഗണം കണക്കാക്കിക്കൊണ്ടാണ് BPE ട്രെയിനിംഗ് ആരംഭിക്കുന്നത് (നോർമലൈസേഷൻ, പ്രീ-ടോക്കണൈസേഷൻ ഘട്ടങ്ങൾ പൂർത്തിയായതിന് ശേഷം); പിന്നീട് ആ വാക്കുകൾ എഴുതാൻ ഉപയോഗിച്ചിരിക്കുന്ന എല്ലാ അക്ഷരങ്ങളും (symbols) എടുത്ത് വൊക്കാബുലറി (vocabulary) നിർമ്മിക്കുന്നു. വളരെ ലളിതമായ ഒരു ഉദാഹരണമായി, നമ്മുടെ കോർപ്പസ് ഈ അഞ്ച് വാക്കുകൾ ഉപയോഗിക്കുന്നു എന്ന് കരുതുക: + +``` +"hug", "pug", "pun", "bun", "hugs" +``` + +അപ്പോൾ അടിസ്ഥാന വൊക്കാബുലറി `["b", "g", "h", "n", "p", "s", "u"]` ആയിരിക്കും. യഥാർത്ഥ ലോകത്തിലെ സാഹചര്യങ്ങളിൽ, ആ അടിസ്ഥാന വൊക്കാബുലറിയിൽ ഏറ്റവും കുറഞ്ഞത് എല്ലാ ASCII അക്ഷരങ്ങളും, ഒരുപക്ഷേ ചില Unicode അക്ഷരങ്ങളും ഉണ്ടായിരിക്കും. നിങ്ങൾ ടോക്കണൈസ് ചെയ്യുന്ന ഒരു ഉദാഹരണത്തിൽ ട്രെയിനിംഗ് കോർപ്പസിൽ ഇല്ലാത്ത ഒരു അക്ഷരം ഉപയോഗിച്ചിട്ടുണ്ടെങ്കിൽ, ആ അക്ഷരം unknown ടോക്കണിലേക്ക് മാറ്റപ്പെടും. ഉദാഹരണത്തിന്, ഇമോജികൾ ഉള്ള ഉള്ളടക്കം വിശകലനം ചെയ്യുന്നതിൽ ധാരാളം NLP മോഡലുകൾ വളരെ മോശമായിരിക്കുന്നതിന്റെ ഒരു കാരണം ഇതാണ്. + +> [!TIP] +> GPT-2, RoBERTa ടോക്കണൈസറുകൾക്ക് (ഇവ ഏറെക്കുറെ സമാനമാണ്) ഇത് കൈകാര്യം ചെയ്യാൻ ഒരു ബുദ്ധിപൂർവ്വമായ മാർഗമുണ്ട്: വാക്കുകളെ Unicode അക്ഷരങ്ങൾ കൊണ്ട് എഴുതിയവയായല്ല, ബൈറ്റുകൾ (bytes) കൊണ്ട് എഴുതിയവയായാണ് അവ കാണുന്നത്. ഇങ്ങനെ അടിസ്ഥാന വൊക്കാബുലറിക്ക് ചെറിയ വലുപ്പമാണ് (256) ഉള്ളത്, എന്നാൽ നിങ്ങൾക്ക് ചിന്തിക്കാൻ കഴിയുന്ന ഏത് അക്ഷരവും അതിൽ ഉൾപ്പെട്ടിരിക്കും, unknown ടോക്കണിലേക്ക് മാറ്റപ്പെടുകയുമില്ല. ഈ തന്ത്രത്തെ *byte-level BPE* എന്ന് വിളിക്കുന്നു. + +ഈ അടിസ്ഥാന വൊക്കാബുലറി ലഭിച്ചതിന് ശേഷം, *മെർജുകൾ* (merges) പഠിച്ചുകൊണ്ട്, ആവശ്യമുള്ള വൊക്കാബുലറി വലുപ്പം എത്തുന്നത് വരെ നമ്മൾ പുതിയ ടോക്കണുകൾ ചേർക്കുന്നു; നിലവിലുള്ള വൊക്കാബുലറിയിലെ രണ്ട് ഘടകങ്ങളെ ഒന്നിച്ചുചേർത്ത് ഒരു പുതിയ ഘടകമാക്കാനുള്ള നിയമങ്ങളാണ് മെർജുകൾ. അതിനാൽ, തുടക്കത്തിൽ ഈ മെർജുകൾ രണ്ട് അക്ഷരങ്ങളുള്ള ടോക്കണുകൾ സൃഷ്ടിക്കും; പിന്നീട്, ട്രെയിനിംഗ് പുരോഗമിക്കുമ്പോൾ, കൂടുതൽ നീളമുള്ള സബ്‌വേഡുകളും. + +ടോക്കണൈസർ ട്രെയിനിംഗിലെ ഏത് ഘട്ടത്തിലും, നിലവിലുള്ള ടോക്കണുകളുടെ ഏറ്റവും കൂടുതൽ തവണ വരുന്ന (most frequent) ജോഡിക്കായി BPE അൽഗോരിതം തിരയും ("ജോഡി" എന്നതുകൊണ്ട് ഇവിടെ നമ്മൾ അർത്ഥമാക്കുന്നത് ഒരു വാക്കിലെ തുടർച്ചയായ രണ്ട് ടോക്കണുകളാണ്). ഏറ്റവും കൂടുതൽ തവണ വരുന്ന ആ ജോഡിയാണ് മെർജ് ചെയ്യപ്പെടുന്നത്; അടുത്ത ഘട്ടത്തിനായി നമ്മൾ ഇത് വീണ്ടും ആവർത്തിക്കുന്നു. + +നമ്മുടെ മുൻ ഉദാഹരണത്തിലേക്ക് തിരിച്ചുപോയാൽ, വാക്കുകൾക്ക് താഴെ പറയുന്ന ആവൃത്തികൾ (frequencies) ഉണ്ടായിരുന്നു എന്ന് കരുതുക: + +``` +("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5) +``` + +അതായത് `"hug"` കോർപ്പസിൽ 10 തവണയും, `"pug"` 5 തവണയും, `"pun"` 12 തവണയും, `"bun"` 4 തവണയും, `"hugs"` 5 തവണയും ഉണ്ടായിരുന്നു. ഓരോ വാക്കിനെയും അക്ഷരങ്ങളായി (നമ്മുടെ പ്രാരംഭ വൊക്കാബുലറി രൂപപ്പെടുത്തുന്നവ) വിഭജിച്ചുകൊണ്ടാണ് നമ്മൾ ട്രെയിനിംഗ് ആരംഭിക്കുന്നത്; അങ്ങനെ ഓരോ വാക്കിനെയും ടോക്കണുകളുടെ ഒരു ലിസ്‌റ്റായി നമുക്ക് കാണാൻ കഴിയും: + +``` +("h" "u" "g", 10), ("p" "u" "g", 5), ("p" "u" "n", 12), ("b" "u" "n", 4), ("h" "u" "g" "s", 5) +``` + +പിന്നീട് നമ്മൾ ജോഡികളെ നോക്കുന്നു. `("h", "u")` എന്ന ജോഡി `"hug"`, `"hugs"` എന്ന വാക്കുകളിൽ ഉണ്ട്, അതായത് കോർപ്പസിൽ മൊത്തം 15 തവണ. എന്നാൽ, ഇത് ഏറ്റവും കൂടുതൽ തവണ വരുന്ന ജോഡിയല്ല: ആ ബഹുമതി `("u", "g")`-ന് അവകാശപ്പെട്ടതാണ്; ഇത് `"hug"`, `"pug"`, `"hugs"` എന്നിവയിൽ ഉണ്ട്, വൊക്കാബുലറിയിൽ ആകെ 20 തവണ. + +അതിനാൽ, ടോക്കണൈസർ പഠിക്കുന്ന ആദ്യ മെർജ് നിയമം `("u", "g") -> "ug"` ആണ്; അതായത് `"ug"` വൊക്കാബുലറിയിലേക്ക് ചേർക്കപ്പെടും, കൂടാതെ കോർപ്പസിലെ എല്ലാ വാക്കുകളിലും ഈ ജോഡി മെർജ് ചെയ്യപ്പെടണം. ഈ ഘട്ടത്തിന്റെ അവസാനം, വൊക്കാബുലറിയും കോർപ്പസും ഇങ്ങനെയായിരിക്കും: + +``` +Vocabulary: ["b", "g", "h", "n", "p", "s", "u", "ug"] +Corpus: ("h" "ug", 10), ("p" "ug", 5), ("p" "u" "n", 12), ("b" "u" "n", 4), ("h" "ug" "s", 5) +``` + +ഇപ്പോൾ രണ്ട് അക്ഷരങ്ങളിൽ കൂടുതൽ നീളമുള്ള ഒരു ടോക്കണിൽ കലാശിക്കുന്ന ചില ജോഡികൾ നമുക്കുണ്ട്: ഉദാഹരണത്തിന്, `("h", "ug")` എന്ന ജോഡി (കോർപ്പസിൽ 15 തവണ ഉണ്ട്). എന്നാൽ, ഈ ഘട്ടത്തിൽ ഏറ്റവും കൂടുതൽ തവണ വരുന്ന ജോഡി `("u", "n")` ആണ്, കോർപ്പസിൽ 16 തവണ ഉണ്ട്; അതിനാൽ പഠിക്കുന്ന രണ്ടാമത്തെ മെർജ് നിയമം `("u", "n") -> "un"` ആണ്. അത് വൊക്കാബുലറിയിലേക്ക് ചേർക്കുകയും നിലവിലുള്ള എല്ലാ സന്ദർഭങ്ങളും (occurrences) മെർജ് ചെയ്യുകയും ചെയ്യുമ്പോൾ നമുക്ക് ലഭിക്കുന്നത്: + +``` +Vocabulary: ["b", "g", "h", "n", "p", "s", "u", "ug", "un"] +Corpus: ("h" "ug", 10), ("p" "ug", 5), ("p" "un", 12), ("b" "un", 4), ("h" "ug" "s", 5) +``` + +ഇപ്പോൾ ഏറ്റവും കൂടുതൽ തവണ വരുന്ന ജോഡി `("h", "ug")` ആണ്, അതിനാൽ `("h", "ug") -> "hug"` എന്ന മെർജ് നിയമം നമ്മൾ പഠിക്കുന്നു; ഇത് നമുക്ക് നമ്മുടെ ആദ്യത്തെ മൂന്നക്ഷര ടോക്കൺ നൽകുന്നു. മെർജിന് ശേഷം, കോർപ്പസ് ഇങ്ങനെയായിരിക്കും: + +``` +Vocabulary: ["b", "g", "h", "n", "p", "s", "u", "ug", "un", "hug"] +Corpus: ("hug", 10), ("p" "ug", 5), ("p" "un", 12), ("b" "un", 4), ("hug" "s", 5) +``` + +ആവശ്യമുള്ള വൊക്കാബുലറി വലുപ്പത്തിൽ എത്തുന്നത് വരെ നമ്മൾ ഇങ്ങനെ തുടരുന്നു. + +> [!TIP] +> ✏️ **ഇനി നിങ്ങളുടെ ഊഴം!** അടുത്ത മെർജ് നിയമം എന്തായിരിക്കും എന്നാണ് നിങ്ങൾ കരുതുന്നത്? + +## ടോക്കണൈസേഷൻ അൽഗോരിതം[[tokenization-algorithm]] + +ടോക്കണൈസേഷൻ ട്രെയിനിംഗ് പ്രക്രിയയെ അടുത്ത് പിന്തുടരുന്നു; അതായത്, താഴെ പറയുന്ന ഘട്ടങ്ങൾ പ്രയോഗിച്ചുകൊണ്ടാണ് പുതിയ ഇൻപുട്ടുകൾ ടോക്കണൈസ് ചെയ്യപ്പെടുന്നത്: + +1. നോർമലൈസേഷൻ +2. പ്രീ-ടോക്കണൈസേഷൻ +3. വാക്കുകളെ ഓരോ അക്ഷരങ്ങളായി വിഭജിക്കുക +4. പഠിച്ച മെർജ് നിയമങ്ങൾ ക്രമത്തിൽ ആ വിഭജനങ്ങളിൽ (splits) പ്രയോഗിക്കുക + +ട്രെയിനിംഗ് സമയത്ത് നമ്മൾ ഉപയോഗിച്ച ഉദാഹരണം, പഠിച്ച മൂന്ന് മെർജ് നിയമങ്ങളോടൊപ്പം എടുക്കാം: + +``` +("u", "g") -> "ug" +("u", "n") -> "un" +("h", "ug") -> "hug" +``` + +`"bug"` എന്ന വാക്ക് `["b", "ug"]` എന്ന് ടോക്കണൈസ് ചെയ്യപ്പെടും. എന്നാൽ, `"m"` എന്ന അക്ഷരം അടിസ്ഥാന വൊക്കാബുലറിയിൽ ഇല്ലാതിരുന്നതിനാൽ `"mug"` എന്നത് `["[UNK]", "ug"]` എന്ന് ടോക്കണൈസ് ചെയ്യപ്പെടും. അതുപോലെ, `"thug"` എന്ന വാക്ക് `["[UNK]", "hug"]` എന്ന് ടോക്കണൈസ് ചെയ്യപ്പെടും: `"t"` എന്ന അക്ഷരം അടിസ്ഥാന വൊക്കാബുലറിയിൽ ഇല്ല, കൂടാതെ മെർജ് നിയമങ്ങൾ പ്രയോഗിക്കുമ്പോൾ ആദ്യം `"u"`-ഉം `"g"`-ഉം മെർജ് ചെയ്യപ്പെടുകയും പിന്നീട് `"h"`-ഉം `"ug"`-ഉം മെർജ് ചെയ്യപ്പെടുകയും ചെയ്യുന്നു. + +> [!TIP] +> ✏️ **ഇനി നിങ്ങളുടെ ഊഴം!** `"unhug"` എന്ന വാക്ക് എങ്ങനെ ടോക്കണൈസ് ചെയ്യപ്പെടും എന്നാണ് നിങ്ങൾ കരുതുന്നത്? + +## BPE ഇംപ്ലിമെന്റ് ചെയ്യുന്നു[[implementing-bpe]] + +ഇനി BPE അൽഗോരിതത്തിന്റെ ഒരു ഇംപ്ലിമെന്റേഷൻ നമുക്ക് ഒന്ന് നോക്കാം. ഒരു വലിയ കോർപ്പസിൽ നിങ്ങൾക്ക് യഥാർത്ഥത്തിൽ ഉപയോഗിക്കാൻ കഴിയുന്ന ഒരു ഒപ്‌റ്റിമൈസ് ചെയ്ത പതിപ്പായിരിക്കില്ല ഇത്; അൽഗോരിതം കുറച്ചുകൂടി നന്നായി മനസ്സിലാക്കാൻ നിങ്ങളെ സഹായിക്കുന്നതിനായി കോഡ് കാണിച്ചുതരാൻ മാത്രമാണ് ഞങ്ങൾ ഉദ്ദേശിക്കുന്നത്. + +ആദ്യം നമുക്ക് ഒരു കോർപ്പസ് ആവശ്യമാണ്, അതിനാൽ ഏതാനും വാക്യങ്ങളുള്ള ലളിതമായ ഒന്ന് നമുക്ക് സൃഷ്ടിക്കാം: + +```python +corpus = [ + "This is the Hugging Face Course.", + "This chapter is about tokenization.", + "This section shows several tokenizer algorithms.", + "Hopefully, you will be able to understand how they are trained and generate tokens.", +] +``` + +അടുത്തതായി, ആ കോർപ്പസിനെ വാക്കുകളായി പ്രീ-ടോക്കണൈസ് ചെയ്യേണ്ടതുണ്ട്. നമ്മൾ ഒരു BPE ടോക്കണൈസറിനെ (GPT-2 പോലുള്ളത്) പുനഃസൃഷ്ടിക്കുന്നതിനാൽ, പ്രീ-ടോക്കണൈസേഷനായി `gpt2` ടോക്കണൈസർ നമ്മൾ ഉപയോഗിക്കും: + +```python +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("gpt2") +``` + +പിന്നീട്, പ്രീ-ടോക്കണൈസേഷൻ ചെയ്യുന്നതിനോടൊപ്പം കോർപ്പസിലെ ഓരോ വാക്കിന്റെയും ആവൃത്തി നമ്മൾ കണക്കാക്കുന്നു: + +```python +from collections import defaultdict + +word_freqs = defaultdict(int) + +for text in corpus: + words_with_offsets = tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str(text) + new_words = [word for word, offset in words_with_offsets] + for word in new_words: + word_freqs[word] += 1 + +print(word_freqs) +``` + +```python out +defaultdict(int, {'This': 3, 'Ġis': 2, 'Ġthe': 1, 'ĠHugging': 1, 'ĠFace': 1, 'ĠCourse': 1, '.': 4, 'Ġchapter': 1, + 'Ġabout': 1, 'Ġtokenization': 1, 'Ġsection': 1, 'Ġshows': 1, 'Ġseveral': 1, 'Ġtokenizer': 1, 'Ġalgorithms': 1, + 'Hopefully': 1, ',': 1, 'Ġyou': 1, 'Ġwill': 1, 'Ġbe': 1, 'Ġable': 1, 'Ġto': 1, 'Ġunderstand': 1, 'Ġhow': 1, + 'Ġthey': 1, 'Ġare': 1, 'Ġtrained': 1, 'Ġand': 1, 'Ġgenerate': 1, 'Ġtokens': 1}) +``` + +അടുത്ത ഘട്ടം, കോർപ്പസിൽ ഉപയോഗിച്ചിരിക്കുന്ന എല്ലാ അക്ഷരങ്ങളും ചേർന്ന് രൂപപ്പെടുന്ന അടിസ്ഥാന വൊക്കാബുലറി കണക്കാക്കുകയാണ്: + +```python +alphabet = [] + +for word in word_freqs.keys(): + for letter in word: + if letter not in alphabet: + alphabet.append(letter) +alphabet.sort() + +print(alphabet) +``` + +```python out +[ ',', '.', 'C', 'F', 'H', 'T', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k', 'l', 'm', 'n', 'o', 'p', 'r', 's', + 't', 'u', 'v', 'w', 'y', 'z', 'Ġ'] +``` + +മോഡൽ ഉപയോഗിക്കുന്ന പ്രത്യേക ടോക്കണുകളും (special tokens) ആ വൊക്കാബുലറിയുടെ തുടക്കത്തിൽ നമ്മൾ ചേർക്കുന്നു. GPT-2-ന്റെ കാര്യത്തിൽ, ഒരേയൊരു പ്രത്യേക ടോക്കൺ `"<|endoftext|>"` ആണ്: + +```python +vocab = ["<|endoftext|>"] + alphabet.copy() +``` + +ട്രെയിനിംഗ് ആരംഭിക്കാൻ കഴിയുന്നതിനായി, ഇപ്പോൾ ഓരോ വാക്കിനെയും ഓരോ അക്ഷരങ്ങളായി നമ്മൾ വിഭജിക്കേണ്ടതുണ്ട്: + +```python +splits = {word: [c for c in word] for word in word_freqs.keys()} +``` + +ഇപ്പോൾ നമ്മൾ ട്രെയിനിംഗിന് തയ്യാറായ സ്ഥിതിക്ക്, ഓരോ ജോഡിയുടെയും ആവൃത്തി കണക്കാക്കുന്ന ഒരു ഫംഗ്‌ഷൻ എഴുതാം. ട്രെയിനിംഗിന്റെ ഓരോ ഘട്ടത്തിലും നമുക്ക് ഇത് ഉപയോഗിക്കേണ്ടിവരും: + +```python +def compute_pair_freqs(splits): + pair_freqs = defaultdict(int) + for word, freq in word_freqs.items(): + split = splits[word] + if len(split) == 1: + continue + for i in range(len(split) - 1): + pair = (split[i], split[i + 1]) + pair_freqs[pair] += freq + return pair_freqs +``` + +പ്രാരംഭ വിഭജനങ്ങൾക്ക് ശേഷം ഈ ഡിക്‌ഷണറിയുടെ ഒരു ഭാഗം നമുക്ക് ഒന്ന് നോക്കാം: + +```python +pair_freqs = compute_pair_freqs(splits) + +for i, key in enumerate(pair_freqs.keys()): + print(f"{key}: {pair_freqs[key]}") + if i >= 5: + break +``` + +```python out +('T', 'h'): 3 +('h', 'i'): 3 +('i', 's'): 5 +('Ġ', 'i'): 2 +('Ġ', 't'): 7 +('t', 'h'): 3 +``` + +ഇപ്പോൾ, ഏറ്റവും കൂടുതൽ തവണ വരുന്ന ജോഡി കണ്ടെത്താൻ ഒരു ചെറിയ ലൂപ്പ് മാത്രം മതി: + +```python +best_pair = "" +max_freq = None + +for pair, freq in pair_freqs.items(): + if max_freq is None or max_freq < freq: + best_pair = pair + max_freq = freq + +print(best_pair, max_freq) +``` + +```python out +('Ġ', 't') 7 +``` + +അതിനാൽ പഠിക്കേണ്ട ആദ്യ മെർജ് `('Ġ', 't') -> 'Ġt'` ആണ്, കൂടാതെ `'Ġt'` നമ്മൾ വൊക്കാബുലറിയിലേക്ക് ചേർക്കുന്നു: + +```python +merges = {("Ġ", "t"): "Ġt"} +vocab.append("Ġt") +``` + +തുടരാൻ, ആ മെർജ് നമ്മുടെ `splits` ഡിക്‌ഷണറിയിൽ പ്രയോഗിക്കേണ്ടതുണ്ട്. ഇതിനായി മറ്റൊരു ഫംഗ്‌ഷൻ എഴുതാം: + +```python +def merge_pair(a, b, splits): + for word in word_freqs: + split = splits[word] + if len(split) == 1: + continue + + i = 0 + while i < len(split) - 1: + if split[i] == a and split[i + 1] == b: + split = split[:i] + [a + b] + split[i + 2 :] + else: + i += 1 + splits[word] = split + return splits +``` + +ആദ്യ മെർജിന്റെ ഫലം നമുക്ക് ഒന്ന് നോക്കാം: + +```py +splits = merge_pair("Ġ", "t", splits) +print(splits["Ġtrained"]) +``` + +```python out +['Ġt', 'r', 'a', 'i', 'n', 'e', 'd'] +``` + +നമുക്ക് ആവശ്യമുള്ള എല്ലാ മെർജുകളും പഠിക്കുന്നത് വരെ ലൂപ്പ് ചെയ്യാൻ ആവശ്യമായതെല്ലാം ഇപ്പോൾ നമ്മുടെ പക്കലുണ്ട്. 50 എന്ന വൊക്കാബുലറി വലുപ്പം നമുക്ക് ലക്ഷ്യമിടാം: + +```python +vocab_size = 50 + +while len(vocab) < vocab_size: + pair_freqs = compute_pair_freqs(splits) + best_pair = "" + max_freq = None + for pair, freq in pair_freqs.items(): + if max_freq is None or max_freq < freq: + best_pair = pair + max_freq = freq + splits = merge_pair(*best_pair, splits) + merges[best_pair] = best_pair[0] + best_pair[1] + vocab.append(best_pair[0] + best_pair[1]) +``` + +ഫലമായി, നമ്മൾ 19 മെർജ് നിയമങ്ങൾ പഠിച്ചു (പ്രാരംഭ വൊക്കാബുലറിയുടെ വലുപ്പം 31 ആയിരുന്നു -- ആൽഫബെറ്റിലെ 30 അക്ഷരങ്ങളും, കൂടെ പ്രത്യേക ടോക്കണും): + +```py +print(merges) +``` + +```python out +{('Ġ', 't'): 'Ġt', ('i', 's'): 'is', ('e', 'r'): 'er', ('Ġ', 'a'): 'Ġa', ('Ġt', 'o'): 'Ġto', ('e', 'n'): 'en', + ('T', 'h'): 'Th', ('Th', 'is'): 'This', ('o', 'u'): 'ou', ('s', 'e'): 'se', ('Ġto', 'k'): 'Ġtok', + ('Ġtok', 'en'): 'Ġtoken', ('n', 'd'): 'nd', ('Ġ', 'is'): 'Ġis', ('Ġt', 'h'): 'Ġth', ('Ġth', 'e'): 'Ġthe', + ('i', 'n'): 'in', ('Ġa', 'b'): 'Ġab', ('Ġtoken', 'i'): 'Ġtokeni'} +``` + +കൂടാതെ, പ്രത്യേക ടോക്കൺ, പ്രാരംഭ ആൽഫബെറ്റ്, മെർജുകളുടെ എല്ലാ ഫലങ്ങളും ചേർന്നതാണ് വൊക്കാബുലറി: + +```py +print(vocab) +``` + +```python out +['<|endoftext|>', ',', '.', 'C', 'F', 'H', 'T', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k', 'l', 'm', 'n', 'o', + 'p', 'r', 's', 't', 'u', 'v', 'w', 'y', 'z', 'Ġ', 'Ġt', 'is', 'er', 'Ġa', 'Ġto', 'en', 'Th', 'This', 'ou', 'se', + 'Ġtok', 'Ġtoken', 'nd', 'Ġis', 'Ġth', 'Ġthe', 'in', 'Ġab', 'Ġtokeni'] +``` + +> [!TIP] +> 💡 അതേ കോർപ്പസിൽ `train_new_from_iterator()` ഉപയോഗിച്ചാൽ കൃത്യമായി ഇതേ വൊക്കാബുലറി ലഭിക്കില്ല. ഏറ്റവും കൂടുതൽ തവണ വരുന്ന ജോഡി തിരഞ്ഞെടുക്കാൻ ഒന്നിലധികം സാധ്യതകൾ ഉള്ളപ്പോൾ, നമ്മൾ ആദ്യം കണ്ടുമുട്ടിയതിനെ തിരഞ്ഞെടുത്തു, അതേസമയം 🤗 Tokenizers ലൈബ്രറി അതിന്റെ ആന്തരിക ID-കൾ അടിസ്ഥാനമാക്കി ആദ്യത്തേതിനെ തിരഞ്ഞെടുക്കുന്നു എന്നതാണ് ഇതിന് കാരണം. + +ഒരു പുതിയ ടെക്‌സ്‌റ്റ് ടോക്കണൈസ് ചെയ്യാൻ, നമ്മൾ അതിനെ പ്രീ-ടോക്കണൈസ് ചെയ്യുകയും, വിഭജിക്കുകയും, പിന്നീട് പഠിച്ച എല്ലാ മെർജ് നിയമങ്ങളും പ്രയോഗിക്കുകയും ചെയ്യുന്നു: + +```python +def tokenize(text): + pre_tokenize_result = tokenizer._tokenizer.pre_tokenizer.pre_tokenize_str(text) + pre_tokenized_text = [word for word, offset in pre_tokenize_result] + splits = [[l for l in word] for word in pre_tokenized_text] + for pair, merge in merges.items(): + for idx, split in enumerate(splits): + i = 0 + while i < len(split) - 1: + if split[i] == pair[0] and split[i + 1] == pair[1]: + split = split[:i] + [merge] + split[i + 2 :] + else: + i += 1 + splits[idx] = split + + return sum(splits, []) +``` + +ആൽഫബെറ്റിലെ അക്ഷരങ്ങൾ കൊണ്ട് രചിച്ച ഏത് ടെക്‌സ്‌റ്റിലും നമുക്ക് ഇത് പരീക്ഷിക്കാം: + +```py +tokenize("This is not a token.") +``` + +```python out +['This', 'Ġis', 'Ġ', 'n', 'o', 't', 'Ġa', 'Ġtoken', '.'] +``` + +> [!WARNING] +> ⚠️ അജ്ഞാതമായ (unknown) ഒരു അക്ഷരം ഉണ്ടെങ്കിൽ നമ്മുടെ ഇംപ്ലിമെന്റേഷൻ ഒരു എറർ ത്രോ ചെയ്യും, കാരണം അവ കൈകാര്യം ചെയ്യാൻ നമ്മൾ ഒന്നും ചെയ്തിട്ടില്ല. GPT-2-ന് യഥാർത്ഥത്തിൽ ഒരു unknown ടോക്കൺ ഇല്ല (byte-level BPE ഉപയോഗിക്കുമ്പോൾ ഒരു unknown അക്ഷരം ലഭിക്കുക അസാധ്യമാണ്), എന്നാൽ സാധ്യമായ എല്ലാ ബൈറ്റുകളും പ്രാരംഭ വൊക്കാബുലറിയിൽ നമ്മൾ ഉൾപ്പെടുത്താത്തതിനാൽ ഇവിടെ ഇത് സംഭവിക്കാം. BPE-യുടെ ഈ വശം ഈ ഭാഗത്തിന്റെ പരിധിക്ക് പുറത്താണ്, അതിനാൽ വിശദാംശങ്ങൾ ഞങ്ങൾ ഒഴിവാക്കിയിരിക്കുന്നു. + +BPE അൽഗോരിതത്തെക്കുറിച്ച് ഇത്രമാത്രം! അടുത്തതായി, WordPiece നമ്മൾ ഒന്ന് നോക്കും. diff --git a/chapters/ml/chapter6/6.mdx b/chapters/ml/chapter6/6.mdx new file mode 100644 index 000000000..30034d48c --- /dev/null +++ b/chapters/ml/chapter6/6.mdx @@ -0,0 +1,359 @@ +# WordPiece ടോക്കണൈസേഷൻ[[wordpiece-tokenization]] + + + +BERT പ്രീട്രെയിൻ ചെയ്യാൻ Google വികസിപ്പിച്ച ടോക്കണൈസേഷൻ അൽഗോരിതമാണ് WordPiece. അതിനുശേഷം, DistilBERT, MobileBERT, Funnel Transformers, MPNET തുടങ്ങിയ, BERT അടിസ്ഥാനമാക്കിയുള്ള നിരവധി Transformer മോഡലുകളിൽ ഇത് വീണ്ടും ഉപയോഗിക്കപ്പെട്ടിട്ടുണ്ട്. ട്രെയിനിംഗിന്റെ കാര്യത്തിൽ ഇത് BPE-യോട് വളരെ സാമ്യമുള്ളതാണ്, എന്നാൽ യഥാർത്ഥ ടോക്കണൈസേഷൻ വ്യത്യസ്തമായ രീതിയിലാണ് ചെയ്യുന്നത്. + + + +> [!TIP] +> 💡 ഈ ഭാഗം WordPiece-നെ ആഴത്തിൽ വിശദീകരിക്കുന്നു; ഒരു പൂർണ്ണമായ ഇംപ്ലിമെന്റേഷൻ കാണിക്കുന്നതുവരെ അത് പോകുന്നു. ടോക്കണൈസേഷൻ അൽഗോരിതത്തിന്റെ ഒരു പൊതുവായ അവലോകനം മാത്രമാണ് നിങ്ങൾക്ക് വേണ്ടതെങ്കിൽ, നിങ്ങൾക്ക് നേരെ അവസാനഭാഗത്തേക്ക് പോകാം. + +## ട്രെയിനിംഗ് അൽഗോരിതം[[training-algorithm]] + +> [!WARNING] +> ⚠️ WordPiece-ന്റെ ട്രെയിനിംഗ് അൽഗോരിതത്തിന്റെ ഇംപ്ലിമെന്റേഷൻ Google ഒരിക്കലും ഓപ്പൻ-സോഴ്‌സ് ചെയ്തിട്ടില്ല, അതിനാൽ താഴെ പറയുന്നത് പ്രസിദ്ധീകരിക്കപ്പെട്ട ഗവേഷണ പ്രബന്ധങ്ങളെ അടിസ്ഥാനമാക്കിയുള്ള ഞങ്ങളുടെ ഏറ്റവും മികച്ച ഊഹമാണ്. ഇത് 100% കൃത്യമായിരിക്കണമെന്നില്ല. + +BPE പോലെ, മോഡൽ ഉപയോഗിക്കുന്ന സ്‌പെഷ്യൽ ടോക്കണുകളും പ്രാരംഭ അക്ഷരമാലയും (alphabet) ഉൾപ്പെടുന്ന ഒരു ചെറിയ വൊക്കാബുലറിയിൽ നിന്നാണ് WordPiece ആരംഭിക്കുന്നത്. ഒരു പ്രിഫിക്‌സ് (BERT-ന്റെ കാര്യത്തിൽ `##` പോലെ) ചേർത്താണ് ഇത് സബ്‌വേഡുകളെ തിരിച്ചറിയുന്നത് എന്നതിനാൽ, വാക്കിനുള്ളിലെ എല്ലാ ക്യാരക്‌ടറുകൾക്കും ആ പ്രിഫിക്‌സ് ചേർത്താണ് ഓരോ വാക്കും തുടക്കത്തിൽ വിഭജിക്കപ്പെടുന്നത്. അതിനാൽ, ഉദാഹരണത്തിന്, `"word"` ഇങ്ങനെ വിഭജിക്കപ്പെടുന്നു: + +``` +w ##o ##r ##d +``` + +അങ്ങനെ, ഒരു വാക്കിന്റെ തുടക്കത്തിൽ വരുന്ന എല്ലാ ക്യാരക്‌ടറുകളും, WordPiece പ്രിഫിക്‌സ് മുന്നിൽ ചേർത്ത നിലയിൽ വാക്കിനുള്ളിൽ വരുന്ന ക്യാരക്‌ടറുകളും പ്രാരംഭ അക്ഷരമാലയിൽ അടങ്ങിയിരിക്കുന്നു. + +തുടർന്ന്, വീണ്ടും BPE പോലെ, WordPiece മെർജ് നിയമങ്ങൾ (merge rules) പഠിക്കുന്നു. മെർജ് ചെയ്യേണ്ട ജോഡി തിരഞ്ഞെടുക്കുന്ന രീതിയാണ് പ്രധാന വ്യത്യാസം. ഏറ്റവും കൂടുതൽ തവണ വരുന്ന ജോഡി തിരഞ്ഞെടുക്കുന്നതിന് പകരം, താഴെ പറയുന്ന ഫോർമുല ഉപയോഗിച്ച് WordPiece ഓരോ ജോഡിക്കും ഒരു സ്‌കോർ കണക്കാക്കുന്നു: + +$$\mathrm{score} = (\mathrm{freq\_of\_pair}) / (\mathrm{freq\_of\_first\_element} \times \mathrm{freq\_of\_second\_element})$$ + +ജോഡിയുടെ ഫ്രീക്വൻസിയെ (frequency) അതിന്റെ ഓരോ ഭാഗത്തിന്റെയും ഫ്രീക്വൻസികളുടെ ഗുണനഫലം കൊണ്ട് ഹരിക്കുന്നതിലൂടെ, ഒറ്റയ്ക്കുള്ള ഭാഗങ്ങൾ വൊക്കാബുലറിയിൽ കുറവ് തവണ വരുന്ന ജോഡികളെ മെർജ് ചെയ്യുന്നതിന് അൽഗോരിതം മുൻഗണന നൽകുന്നു. ഉദാഹരണത്തിന്, `("un", "##able")` എന്ന ജോഡി വൊക്കാബുലറിയിൽ വളരെ കൂടുതൽ തവണ വന്നാലും അത് നിർബന്ധമായും മെർജ് ചെയ്യപ്പെടണമെന്നില്ല, കാരണം `"un"`, `"##able"` എന്നീ രണ്ട് ഭാഗങ്ങളും വേറെ ധാരാളം വാക്കുകളിൽ പ്രത്യക്ഷപ്പെടാനും ഉയർന്ന ഫ്രീക്വൻസി ഉണ്ടാകാനും സാധ്യതയുണ്ട്. അതിന് വിപരീതമായി, `("hu", "##gging")` പോലുള്ള ഒരു ജോഡി ഒരുപക്ഷേ വേഗത്തിൽ മെർജ് ചെയ്യപ്പെടും ("hugging" എന്ന വാക്ക് വൊക്കാബുലറിയിൽ പതിവായി വരുന്നു എന്ന് കരുതിയാൽ), കാരണം `"hu"`, `"##gging"` എന്നിവ ഒറ്റയ്ക്ക് കുറവ് തവണയേ വരാൻ സാധ്യതയുള്ളൂ. + +BPE ട്രെയിനിംഗ് ഉദാഹരണത്തിൽ നമ്മൾ ഉപയോഗിച്ച അതേ വൊക്കാബുലറി നോക്കാം: + +``` +("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5) +``` + +ഇവിടെ വിഭജനങ്ങൾ (splits) ഇങ്ങനെയായിരിക്കും: + +``` +("h" "##u" "##g", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("h" "##u" "##g" "##s", 5) +``` + +അതിനാൽ പ്രാരംഭ വൊക്കാബുലറി `["b", "h", "p", "##g", "##n", "##s", "##u"]` ആയിരിക്കും (സ്‌പെഷ്യൽ ടോക്കണുകളെ തൽക്കാലം മറന്നാൽ). ഏറ്റവും കൂടുതൽ തവണ വരുന്ന ജോഡി `("##u", "##g")` ആണ് (20 തവണ വരുന്നു), എന്നാൽ `"##u"`-ന്റെ ഒറ്റയ്ക്കുള്ള ഫ്രീക്വൻസി വളരെ ഉയർന്നതാണ്, അതിനാൽ അതിന്റെ സ്‌കോർ ഏറ്റവും ഉയർന്നതല്ല (അത് 1 / 36 ആണ്). `"##u"` ഉള്ള എല്ലാ ജോഡികൾക്കും യഥാർത്ഥത്തിൽ അതേ സ്‌കോർ (1 / 36) ആണ്, അതിനാൽ ഏറ്റവും മികച്ച സ്‌കോർ `("##g", "##s")` എന്ന ജോഡിക്ക് ലഭിക്കുന്നു -- `"##u"` ഇല്ലാത്ത ഒരേയൊരു ജോഡി -- 1 / 20 എന്ന സ്‌കോറോടെ; പഠിക്കപ്പെടുന്ന ആദ്യത്തെ മെർജ് `("##g", "##s") -> ("##gs")` ആണ്. + +മെർജ് ചെയ്യുമ്പോൾ, രണ്ട് ടോക്കണുകൾക്കിടയിലുള്ള `##` നമ്മൾ നീക്കം ചെയ്യുന്നു എന്നത് ശ്രദ്ധിക്കുക; അതിനാൽ `"##gs"` വൊക്കാബുലറിയിൽ ചേർത്ത്, കോർപ്പസിലെ വാക്കുകളിൽ ആ മെർജ് പ്രയോഗിക്കുന്നു: + +``` +Vocabulary: ["b", "h", "p", "##g", "##n", "##s", "##u", "##gs"] +Corpus: ("h" "##u" "##g", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("h" "##u" "##gs", 5) +``` + +ഈ ഘട്ടത്തിൽ, സാധ്യമായ എല്ലാ ജോഡികളിലും `"##u"` ഉണ്ട്, അതിനാൽ അവയ്‌ക്കെല്ലാം ഒരേ സ്‌കോർ ലഭിക്കുന്നു. ഈ സാഹചര്യത്തിൽ ആദ്യത്തെ ജോഡി മെർജ് ചെയ്യപ്പെടുന്നു എന്ന് കരുതാം, അതായത് `("h", "##u") -> "hu"`. ഇത് നമ്മളെ ഇവിടേക്ക് എത്തിക്കുന്നു: + +``` +Vocabulary: ["b", "h", "p", "##g", "##n", "##s", "##u", "##gs", "hu"] +Corpus: ("hu" "##g", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("hu" "##gs", 5) +``` + +തുടർന്ന്, അടുത്ത മികച്ച സ്‌കോർ `("hu", "##g")`, `("hu", "##gs")` എന്നിവ പങ്കിടുന്നു (മറ്റെല്ലാ ജോഡികൾക്കും 1/21 ആയിരിക്കുമ്പോൾ ഇവയ്ക്ക് 1/15), അതിനാൽ ഏറ്റവും വലിയ സ്‌കോറുള്ള ആദ്യത്തെ ജോഡി മെർജ് ചെയ്യപ്പെടുന്നു: + +``` +Vocabulary: ["b", "h", "p", "##g", "##n", "##s", "##u", "##gs", "hu", "hug"] +Corpus: ("hug", 10), ("p" "##u" "##g", 5), ("p" "##u" "##n", 12), ("b" "##u" "##n", 4), ("hu" "##gs", 5) +``` + +ആവശ്യമുള്ള വൊക്കാബുലറി വലിപ്പത്തിൽ എത്തുന്നതുവരെ നമ്മൾ ഇങ്ങനെ തുടരുന്നു. + +> [!TIP] +> ✏️ **ഇനി നിങ്ങളുടെ ഊഴം!** അടുത്ത മെർജ് നിയമം എന്തായിരിക്കും? + +## ടോക്കണൈസേഷൻ അൽഗോരിതം[[tokenization-algorithm]] + +പഠിച്ച മെർജ് നിയമങ്ങളല്ല, അന്തിമ വൊക്കാബുലറി മാത്രമാണ് WordPiece സേവ് ചെയ്യുന്നത് എന്നതിലാണ് WordPiece-ലെയും BPE-യിലെയും ടോക്കണൈസേഷൻ വ്യത്യാസപ്പെടുന്നത്. ടോക്കണൈസ് ചെയ്യേണ്ട വാക്കിൽ നിന്ന് ആരംഭിച്ച്, വൊക്കാബുലറിയിലുള്ള ഏറ്റവും നീളമുള്ള സബ്‌വേഡ് WordPiece കണ്ടെത്തുന്നു, തുടർന്ന് അവിടെ വിഭജിക്കുന്നു. ഉദാഹരണത്തിന്, മുകളിലെ ഉദാഹരണത്തിൽ പഠിച്ച വൊക്കാബുലറി ഉപയോഗിക്കുകയാണെങ്കിൽ, `"hugs"` എന്ന വാക്കിന്, തുടക്കത്തിൽ നിന്ന് ആരംഭിക്കുന്ന, വൊക്കാബുലറിയിലുള്ള ഏറ്റവും നീളമുള്ള സബ്‌വേഡ് `"hug"` ആണ്; അതിനാൽ നമ്മൾ അവിടെ വിഭജിച്ച് `["hug", "##s"]` നേടുന്നു. തുടർന്ന് നമ്മൾ `"##s"`-ഉമായി മുന്നോട്ട് പോകുന്നു; അത് വൊക്കാബുലറിയിലുണ്ട്, അതിനാൽ `"hugs"`-ന്റെ ടോക്കണൈസേഷൻ `["hug", "##s"]` ആണ്. + +BPE ഉപയോഗിച്ചായിരുന്നെങ്കിൽ, പഠിച്ച മെർജുകൾ ക്രമത്തിൽ പ്രയോഗിച്ച് ഇതിനെ `["hu", "##gs"]` എന്ന് ടോക്കണൈസ് ചെയ്യുമായിരുന്നു, അതിനാൽ എൻകോഡിംഗ് വ്യത്യസ്തമാണ്. + +മറ്റൊരു ഉദാഹരണമായി, `"bugs"` എന്ന വാക്ക് എങ്ങനെ ടോക്കണൈസ് ചെയ്യപ്പെടും എന്ന് നോക്കാം. വാക്കിന്റെ തുടക്കത്തിൽ നിന്ന് ആരംഭിക്കുന്ന, വൊക്കാബുലറിയിലുള്ള ഏറ്റവും നീളമുള്ള സബ്‌വേഡ് `"b"` ആണ്, അതിനാൽ നമ്മൾ അവിടെ വിഭജിച്ച് `["b", "##ugs"]` നേടുന്നു. തുടർന്ന്, `"##ugs"`-ന്റെ തുടക്കത്തിൽ നിന്ന് ആരംഭിക്കുന്ന, വൊക്കാബുലറിയിലുള്ള ഏറ്റവും നീളമുള്ള സബ്‌വേഡ് `"##u"` ആണ്, അതിനാൽ നമ്മൾ അവിടെ വിഭജിച്ച് `["b", "##u, "##gs"]` നേടുന്നു. അവസാനമായി, `"##gs"` വൊക്കാബുലറിയിലുണ്ട്, അതിനാൽ ഈ അവസാന ലിസ്‌റ്റാണ് `"bugs"`-ന്റെ ടോക്കണൈസേഷൻ. + +വൊക്കാബുലറിയിൽ ഒരു സബ്‌വേഡ് കണ്ടെത്താൻ കഴിയാത്ത ഒരു ഘട്ടത്തിൽ ടോക്കണൈസേഷൻ എത്തുമ്പോൾ, വാക്ക് മുഴുവനും അജ്ഞാതം (unknown) എന്ന് ടോക്കണൈസ് ചെയ്യപ്പെടുന്നു -- അതിനാൽ, ഉദാഹരണത്തിന്, `"mug"` `["[UNK]"]` എന്ന് ടോക്കണൈസ് ചെയ്യപ്പെടും, `"bum"`-ഉം അങ്ങനെതന്നെ (`"b"`, `"##u"` എന്നിവയോടെ നമുക്ക് തുടങ്ങാൻ കഴിയുമെങ്കിലും, `"##m"` വൊക്കാബുലറിയിലില്ല, അതിനാൽ ഫലമായുള്ള ടോക്കണൈസേഷൻ `["b", "##u", "[UNK]"]` അല്ല, വെറും `["[UNK]"]` ആയിരിക്കും). BPE-യിൽ നിന്നുള്ള മറ്റൊരു വ്യത്യാസമാണിത്; BPE വൊക്കാബുലറിയിലില്ലാത്ത ഒറ്റയ്ക്കുള്ള ക്യാരക്‌ടറുകളെ മാത്രമേ അജ്ഞാതമായി തരംതിരിക്കുകയുള്ളൂ. + +> [!TIP] +> ✏️ **ഇനി നിങ്ങളുടെ ഊഴം!** `"pugs"` എന്ന വാക്ക് എങ്ങനെ ടോക്കണൈസ് ചെയ്യപ്പെടും? + +## WordPiece ഇംപ്ലിമെന്റ് ചെയ്യുന്നു[[implementing-wordpiece]] + +ഇനി WordPiece അൽഗോരിതത്തിന്റെ ഒരു ഇംപ്ലിമെന്റേഷൻ നോക്കാം. BPE-യുടെ കാര്യത്തിലേതുപോലെ, ഇത് പഠനാവശ്യത്തിന് മാത്രമുള്ളതാണ്; ഒരു വലിയ കോർപ്പസിൽ ഇത് ഉപയോഗിക്കാൻ നിങ്ങൾക്ക് കഴിയില്ല. + +BPE ഉദാഹരണത്തിലെ അതേ കോർപ്പസ് നമ്മൾ ഉപയോഗിക്കും: + +```python +corpus = [ + "This is the Hugging Face Course.", + "This chapter is about tokenization.", + "This section shows several tokenizer algorithms.", + "Hopefully, you will be able to understand how they are trained and generate tokens.", +] +``` + +ആദ്യം, കോർപ്പസിനെ വാക്കുകളായി പ്രീ-ടോക്കണൈസ് ചെയ്യേണ്ടതുണ്ട്. നമ്മൾ ഒരു WordPiece ടോക്കണൈസർ (BERT പോലെ) പുനഃസൃഷ്ടിക്കുകയാണ് എന്നതിനാൽ, പ്രീ-ടോക്കണൈസേഷന് `bert-base-cased` ടോക്കണൈസർ ഉപയോഗിക്കും: + +```python +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("bert-base-cased") +``` + +തുടർന്ന്, പ്രീ-ടോക്കണൈസേഷൻ ചെയ്യുന്നതോടൊപ്പം കോർപ്പസിലെ ഓരോ വാക്കിന്റെയും ഫ്രീക്വൻസികൾ നമ്മൾ കണക്കാക്കുന്നു: + +```python +from collections import defaultdict + +word_freqs = defaultdict(int) +for text in corpus: + words_with_offsets = tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str(text) + new_words = [word for word, offset in words_with_offsets] + for word in new_words: + word_freqs[word] += 1 + +word_freqs +``` + +```python out +defaultdict( + int, {'This': 3, 'is': 2, 'the': 1, 'Hugging': 1, 'Face': 1, 'Course': 1, '.': 4, 'chapter': 1, 'about': 1, + 'tokenization': 1, 'section': 1, 'shows': 1, 'several': 1, 'tokenizer': 1, 'algorithms': 1, 'Hopefully': 1, + ',': 1, 'you': 1, 'will': 1, 'be': 1, 'able': 1, 'to': 1, 'understand': 1, 'how': 1, 'they': 1, 'are': 1, + 'trained': 1, 'and': 1, 'generate': 1, 'tokens': 1}) +``` + +നമ്മൾ മുമ്പ് കണ്ടതുപോലെ, വാക്കുകളുടെ എല്ലാ ആദ്യാക്ഷരങ്ങളും, `##` പ്രിഫിക്‌സോടെ വാക്കുകളിൽ വരുന്ന മറ്റെല്ലാ അക്ഷരങ്ങളും ചേർന്ന, ആവർത്തനമില്ലാത്ത (unique) ഗണമാണ് അക്ഷരമാല: + +```python +alphabet = [] +for word in word_freqs.keys(): + if word[0] not in alphabet: + alphabet.append(word[0]) + for letter in word[1:]: + if f"##{letter}" not in alphabet: + alphabet.append(f"##{letter}") + +alphabet.sort() +alphabet + +print(alphabet) +``` + +```python out +['##a', '##b', '##c', '##d', '##e', '##f', '##g', '##h', '##i', '##k', '##l', '##m', '##n', '##o', '##p', '##r', '##s', + '##t', '##u', '##v', '##w', '##y', '##z', ',', '.', 'C', 'F', 'H', 'T', 'a', 'b', 'c', 'g', 'h', 'i', 's', 't', 'u', + 'w', 'y'] +``` + +മോഡൽ ഉപയോഗിക്കുന്ന സ്‌പെഷ്യൽ ടോക്കണുകളും ആ വൊക്കാബുലറിയുടെ തുടക്കത്തിൽ നമ്മൾ ചേർക്കുന്നു. BERT-ന്റെ കാര്യത്തിൽ, അത് `["[PAD]", "[UNK]", "[CLS]", "[SEP]", "[MASK]"]` എന്ന ലിസ്‌റ്റാണ്: + +```python +vocab = ["[PAD]", "[UNK]", "[CLS]", "[SEP]", "[MASK]"] + alphabet.copy() +``` + +അടുത്തതായി, ആദ്യത്തേതല്ലാത്ത എല്ലാ അക്ഷരങ്ങൾക്കും `##` പ്രിഫിക്‌സ് ചേർത്ത്, ഓരോ വാക്കും നമ്മൾ വിഭജിക്കേണ്ടതുണ്ട്: + +```python +splits = { + word: [c if i == 0 else f"##{c}" for i, c in enumerate(word)] + for word in word_freqs.keys() +} +``` + +ഇപ്പോൾ ട്രെയിനിംഗിന് നമ്മൾ തയ്യാറായതിനാൽ, ഓരോ ജോഡിയുടെയും സ്‌കോർ കണക്കാക്കുന്ന ഒരു ഫംഗ്‌ഷൻ എഴുതാം. ട്രെയിനിംഗിന്റെ ഓരോ ഘട്ടത്തിലും ഇത് നമുക്ക് ഉപയോഗിക്കേണ്ടിവരും: + +```python +def compute_pair_scores(splits): + letter_freqs = defaultdict(int) + pair_freqs = defaultdict(int) + for word, freq in word_freqs.items(): + split = splits[word] + if len(split) == 1: + letter_freqs[split[0]] += freq + continue + for i in range(len(split) - 1): + pair = (split[i], split[i + 1]) + letter_freqs[split[i]] += freq + pair_freqs[pair] += freq + letter_freqs[split[-1]] += freq + + scores = { + pair: freq / (letter_freqs[pair[0]] * letter_freqs[pair[1]]) + for pair, freq in pair_freqs.items() + } + return scores +``` + +പ്രാരംഭ വിഭജനങ്ങൾക്ക് ശേഷമുള്ള ഈ ഡിക്‌ഷണറിയുടെ ഒരു ഭാഗം നോക്കാം: + +```python +pair_scores = compute_pair_scores(splits) +for i, key in enumerate(pair_scores.keys()): + print(f"{key}: {pair_scores[key]}") + if i >= 5: + break +``` + +```python out +('T', '##h'): 0.125 +('##h', '##i'): 0.03409090909090909 +('##i', '##s'): 0.02727272727272727 +('i', '##s'): 0.1 +('t', '##h'): 0.03571428571428571 +('##h', '##e'): 0.011904761904761904 +``` + +ഇപ്പോൾ, ഏറ്റവും മികച്ച സ്‌കോറുള്ള ജോഡി കണ്ടെത്താൻ ഒരു ചെറിയ ലൂപ്പ് മാത്രം മതി: + +```python +best_pair = "" +max_score = None +for pair, score in pair_scores.items(): + if max_score is None or max_score < score: + best_pair = pair + max_score = score + +print(best_pair, max_score) +``` + +```python out +('a', '##b') 0.2 +``` + +അതിനാൽ പഠിക്കേണ്ട ആദ്യത്തെ മെർജ് `('a', '##b') -> 'ab'` ആണ്, നമ്മൾ `'ab'` വൊക്കാബുലറിയിൽ ചേർക്കുന്നു: + +```python +vocab.append("ab") +``` + +തുടരാൻ, നമ്മുടെ `splits` ഡിക്‌ഷണറിയിൽ ആ മെർജ് പ്രയോഗിക്കേണ്ടതുണ്ട്. ഇതിനായി മറ്റൊരു ഫംഗ്‌ഷൻ എഴുതാം: + +```python +def merge_pair(a, b, splits): + for word in word_freqs: + split = splits[word] + if len(split) == 1: + continue + i = 0 + while i < len(split) - 1: + if split[i] == a and split[i + 1] == b: + merge = a + b[2:] if b.startswith("##") else a + b + split = split[:i] + [merge] + split[i + 2 :] + else: + i += 1 + splits[word] = split + return splits +``` + +ആദ്യത്തെ മെർജിന്റെ ഫലം നമുക്ക് നോക്കാം: + +```py +splits = merge_pair("a", "##b", splits) +splits["about"] +``` + +```python out +['ab', '##o', '##u', '##t'] +``` + +നമുക്ക് വേണ്ട എല്ലാ മെർജുകളും പഠിക്കുന്നതുവരെ ലൂപ്പ് ചെയ്യാൻ ആവശ്യമായതെല്ലാം ഇപ്പോൾ നമ്മുടെ പക്കലുണ്ട്. 70 എന്ന വൊക്കാബുലറി വലിപ്പം ലക്ഷ്യമാക്കാം: + +```python +vocab_size = 70 +while len(vocab) < vocab_size: + scores = compute_pair_scores(splits) + best_pair, max_score = "", None + for pair, score in scores.items(): + if max_score is None or max_score < score: + best_pair = pair + max_score = score + splits = merge_pair(*best_pair, splits) + new_token = ( + best_pair[0] + best_pair[1][2:] + if best_pair[1].startswith("##") + else best_pair[0] + best_pair[1] + ) + vocab.append(new_token) +``` + +തുടർന്ന്, ജനറേറ്റ് ചെയ്ത വൊക്കാബുലറി നമുക്ക് നോക്കാം: + +```py +print(vocab) +``` + +```python out +['[PAD]', '[UNK]', '[CLS]', '[SEP]', '[MASK]', '##a', '##b', '##c', '##d', '##e', '##f', '##g', '##h', '##i', '##k', + '##l', '##m', '##n', '##o', '##p', '##r', '##s', '##t', '##u', '##v', '##w', '##y', '##z', ',', '.', 'C', 'F', 'H', + 'T', 'a', 'b', 'c', 'g', 'h', 'i', 's', 't', 'u', 'w', 'y', 'ab', '##fu', 'Fa', 'Fac', '##ct', '##ful', '##full', '##fully', + 'Th', 'ch', '##hm', 'cha', 'chap', 'chapt', '##thm', 'Hu', 'Hug', 'Hugg', 'sh', 'th', 'is', '##thms', '##za', '##zat', + '##ut'] +``` + +നമുക്ക് കാണാവുന്നതുപോലെ, BPE-യുമായി താരതമ്യം ചെയ്യുമ്പോൾ, ഈ ടോക്കണൈസർ വാക്കുകളുടെ ഭാഗങ്ങളെ ടോക്കണുകളായി കുറച്ചുകൂടി വേഗത്തിൽ പഠിക്കുന്നു. + +> [!TIP] +> 💡 അതേ കോർപ്പസിൽ `train_new_from_iterator()` ഉപയോഗിച്ചാൽ കൃത്യമായി ഇതേ വൊക്കാബുലറി ലഭിക്കില്ല. 🤗 Tokenizers ലൈബ്രറി ട്രെയിനിംഗിനായി WordPiece ഇംപ്ലിമെന്റ് ചെയ്യുന്നില്ല (അതിന്റെ ആന്തരിക പ്രവർത്തനങ്ങളെക്കുറിച്ച് നമുക്ക് പൂർണ്ണമായി ഉറപ്പില്ലാത്തതിനാൽ), പകരം BPE ഉപയോഗിക്കുന്നു എന്നതാണ് ഇതിന് കാരണം. + +ഒരു പുതിയ ടെക്‌സ്‌റ്റ് ടോക്കണൈസ് ചെയ്യാൻ, നമ്മൾ അതിനെ പ്രീ-ടോക്കണൈസ് ചെയ്യുന്നു, വിഭജിക്കുന്നു, തുടർന്ന് ഓരോ വാക്കിലും ടോക്കണൈസേഷൻ അൽഗോരിതം പ്രയോഗിക്കുന്നു. അതായത്, ആദ്യ വാക്കിന്റെ തുടക്കത്തിൽ നിന്ന് ആരംഭിക്കുന്ന ഏറ്റവും വലിയ സബ്‌വേഡ് നമ്മൾ തിരഞ്ഞ് അതിനെ വിഭജിക്കുന്നു, തുടർന്ന് രണ്ടാമത്തെ ഭാഗത്തിൽ ഈ പ്രക്രിയ ആവർത്തിക്കുന്നു; അങ്ങനെ ആ വാക്കിന്റെ ബാക്കി ഭാഗത്തിനും ടെക്‌സ്‌റ്റിലെ തുടർന്നുള്ള വാക്കുകൾക്കും ഇത് തുടരുന്നു: + +```python +def encode_word(word): + tokens = [] + while len(word) > 0: + i = len(word) + while i > 0 and word[:i] not in vocab: + i -= 1 + if i == 0: + return ["[UNK]"] + tokens.append(word[:i]) + word = word[i:] + if len(word) > 0: + word = f"##{word}" + return tokens +``` + +വൊക്കാബുലറിയിലുള്ള ഒരു വാക്കിലും അതിൽ ഇല്ലാത്ത മറ്റൊന്നിലും ഇത് പരീക്ഷിച്ചുനോക്കാം: + +```python +print(encode_word("Hugging")) +print(encode_word("HOgging")) +``` + +```python out +['Hugg', '##i', '##n', '##g'] +['[UNK]'] +``` + +ഇനി, ഒരു ടെക്‌സ്‌റ്റ് ടോക്കണൈസ് ചെയ്യുന്ന ഒരു ഫംഗ്‌ഷൻ എഴുതാം: + +```python +def tokenize(text): + pre_tokenize_result = tokenizer._tokenizer.pre_tokenizer.pre_tokenize_str(text) + pre_tokenized_text = [word for word, offset in pre_tokenize_result] + encoded_words = [encode_word(word) for word in pre_tokenized_text] + return sum(encoded_words, []) +``` + +ഏത് ടെക്‌സ്‌റ്റിലും നമുക്ക് ഇത് പരീക്ഷിക്കാം: + +```python +tokenize("This is the Hugging Face course!") +``` + +```python out +['Th', '##i', '##s', 'is', 'th', '##e', 'Hugg', '##i', '##n', '##g', 'Fac', '##e', 'c', '##o', '##u', '##r', '##s', + '##e', '[UNK]'] +``` + +WordPiece അൽഗോരിതത്തെക്കുറിച്ച് ഇത്രയേ ഉള്ളൂ! ഇനി Unigram നോക്കാം. diff --git a/chapters/ml/chapter6/7.mdx b/chapters/ml/chapter6/7.mdx new file mode 100644 index 000000000..f27a2b0b5 --- /dev/null +++ b/chapters/ml/chapter6/7.mdx @@ -0,0 +1,371 @@ +# Unigram ടോക്കണൈസേഷൻ[[unigram-tokenization]] + + + +Unigram അൽഗോരിതം [SentencePiece](https://huggingface.co/papers/1808.06226)-നോടൊപ്പം ചേർത്താണ് ഉപയോഗിക്കുന്നത്; AlBERT, T5, mBART, Big Bird, XLNet തുടങ്ങിയ മോഡലുകൾ ഉപയോഗിക്കുന്ന ടോക്കണൈസേഷൻ അൽഗോരിതമാണ് SentencePiece. + +എല്ലാ ഭാഷകളും വാക്കുകൾ വേർതിരിക്കാൻ സ്‌പേസ് ഉപയോഗിക്കുന്നില്ല എന്ന വസ്തുതയെയാണ് SentencePiece അഭിസംബോധന ചെയ്യുന്നത്. പകരം, ഉപയോഗിക്കേണ്ട ക്യാരക്‌ടറുകളുടെ കൂട്ടത്തിൽ സ്‌പേസും ഉൾപ്പെടുന്ന ഒരു അസംസ്‌കൃത ഇൻപുട്ട് സ്‌ട്രീമായി (raw input stream) SentencePiece ഇൻപുട്ടിനെ പരിഗണിക്കുന്നു. തുടർന്ന്, അനുയോജ്യമായ വൊക്കാബുലറി (vocabulary) നിർമ്മിക്കാൻ ഇതിന് Unigram അൽഗോരിതം ഉപയോഗിക്കാം. + + + +> [!TIP] +> 💡 ഈ ഭാഗം Unigram-നെ ആഴത്തിൽ പരിശോധിക്കുന്നു, ഒരു പൂർണ്ണ ഇംപ്ലിമെന്റേഷൻ കാണിക്കുന്നതുവരെ പോകുന്നു. ടോക്കണൈസേഷൻ അൽഗോരിതത്തിന്റെ ഒരു പൊതുവായ അവലോകനം മാത്രമാണ് നിങ്ങൾക്ക് വേണ്ടതെങ്കിൽ, നിങ്ങൾക്ക് നേരെ അവസാനത്തിലേക്ക് പോകാം. + +## ട്രെയിനിംഗ് അൽഗോരിതം[[training-algorithm]] + +BPE, WordPiece എന്നിവയുമായി താരതമ്യം ചെയ്യുമ്പോൾ, Unigram മറുദിശയിലാണ് പ്രവർത്തിക്കുന്നത്: ഇത് ഒരു വലിയ വൊക്കാബുലറിയിൽ നിന്ന് തുടങ്ങി, ആവശ്യമുള്ള വൊക്കാബുലറി വലുപ്പത്തിൽ എത്തുന്നതുവരെ അതിൽ നിന്ന് ടോക്കണുകൾ നീക്കം ചെയ്യുന്നു. ആ അടിസ്ഥാന വൊക്കാബുലറി നിർമ്മിക്കാൻ പല മാർഗങ്ങളുണ്ട്: ഉദാഹരണത്തിന്, പ്രീ-ടോക്കണൈസ് ചെയ്ത വാക്കുകളിലെ ഏറ്റവും സാധാരണമായ സബ്‌സ്‌ട്രിംഗുകൾ (substrings) നമുക്ക് എടുക്കാം, അല്ലെങ്കിൽ ഒരു വലിയ വൊക്കാബുലറി വലുപ്പത്തോടെ പ്രാരംഭ കോർപ്പസിൽ (corpus) BPE പ്രയോഗിക്കാം. + +ട്രെയിനിംഗിന്റെ ഓരോ ഘട്ടത്തിലും, നിലവിലെ വൊക്കാബുലറി അടിസ്ഥാനമാക്കി കോർപ്പസിന് മേൽ ഒരു ലോസ് (loss) Unigram അൽഗോരിതം കണക്കാക്കുന്നു. തുടർന്ന്, വൊക്കാബുലറിയിലെ ഓരോ ചിഹ്നത്തിനും (symbol), ആ ചിഹ്നം നീക്കം ചെയ്താൽ മൊത്തത്തിലുള്ള ലോസ് എത്രമാത്രം കൂടുമെന്ന് അൽഗോരിതം കണക്കാക്കുകയും, അതിനെ ഏറ്റവും കുറച്ച് മാത്രം കൂട്ടുന്ന ചിഹ്നങ്ങൾ തിരയുകയും ചെയ്യുന്നു. കോർപ്പസിന് മേലുള്ള മൊത്തം ലോസിൽ ആ ചിഹ്നങ്ങൾക്ക് സ്വാധീനം കുറവാണ്, അതിനാൽ ഒരർത്ഥത്തിൽ അവ "അത്ര ആവശ്യമില്ലാത്തവ" ആണ്, നീക്കം ചെയ്യാനുള്ള ഏറ്റവും മികച്ച സ്ഥാനാർത്ഥികളും അവയാണ്. + +ഇതെല്ലാം വളരെ ചെലവേറിയ ഒരു പ്രവർത്തനമാണ്, അതിനാൽ ഏറ്റവും കുറഞ്ഞ ലോസ് വർദ്ധനവുമായി ബന്ധപ്പെട്ട ഒരൊറ്റ ചിഹ്നം മാത്രമല്ല നമ്മൾ നീക്കം ചെയ്യുന്നത്, മറിച്ച് ഏറ്റവും കുറഞ്ഞ ലോസ് വർദ്ധനവുമായി ബന്ധപ്പെട്ട ചിഹ്നങ്ങളുടെ \\(p\\) ശതമാനമാണ് (\\(p\\) എന്നത് നിങ്ങൾക്ക് നിയന്ത്രിക്കാവുന്ന ഒരു ഹൈപ്പർപാരാമീറ്ററാണ്, സാധാരണയായി 10 അല്ലെങ്കിൽ 20). വൊക്കാബുലറി ആവശ്യമുള്ള വലുപ്പത്തിൽ എത്തുന്നതുവരെ ഈ പ്രക്രിയ ആവർത്തിക്കുന്നു. + +ഏത് വാക്കും ടോക്കണൈസ് ചെയ്യാൻ കഴിയുമെന്ന് ഉറപ്പാക്കാൻ, അടിസ്ഥാന ക്യാരക്‌ടറുകൾ നമ്മൾ ഒരിക്കലും നീക്കം ചെയ്യുന്നില്ല എന്നത് ശ്രദ്ധിക്കുക. + +ഇപ്പോഴും ഇത് അൽപ്പം അവ്യക്തമാണ്: കോർപ്പസിന് മേൽ ഒരു ലോസ് കണക്കാക്കുകയും, വൊക്കാബുലറിയിൽ നിന്ന് ചില ടോക്കണുകൾ നീക്കം ചെയ്യുമ്പോൾ അത് എങ്ങനെ മാറുന്നു എന്ന് നോക്കുകയും ചെയ്യുന്നതാണ് അൽഗോരിതത്തിന്റെ പ്രധാന ഭാഗം, എന്നാൽ ഇത് എങ്ങനെ ചെയ്യണമെന്ന് നമ്മൾ ഇതുവരെ വിശദീകരിച്ചിട്ടില്ല. ഈ ഘട്ടം ഒരു Unigram മോഡലിന്റെ ടോക്കണൈസേഷൻ അൽഗോരിതത്തെ ആശ്രയിച്ചിരിക്കുന്നു, അതിനാൽ അടുത്തതായി നമ്മൾ അതിലേക്ക് കടക്കും. + +മുൻ ഉദാഹരണങ്ങളിലെ കോർപ്പസ് നമ്മൾ വീണ്ടും ഉപയോഗിക്കും: + +``` +("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5) +``` + +കൂടാതെ, ഈ ഉദാഹരണത്തിനായി, പ്രാരംഭ വൊക്കാബുലറിക്ക് വേണ്ടി എല്ലാ സ്‌ട്രിക്‌ട് സബ്‌സ്‌ട്രിംഗുകളും (strict substrings) നമ്മൾ എടുക്കും: + +``` +["h", "u", "g", "hu", "ug", "p", "pu", "n", "un", "b", "bu", "s", "hug", "gs", "ugs"] +``` + +## ടോക്കണൈസേഷൻ അൽഗോരിതം[[tokenization-algorithm]] + +ഓരോ ടോക്കണും അതിന് മുമ്പുള്ള ടോക്കണുകളിൽ നിന്ന് സ്വതന്ത്രമാണെന്ന് കരുതുന്ന ഒരു തരം ഭാഷാ മോഡലാണ് (language model) Unigram മോഡൽ. ഇത് ഏറ്റവും ലളിതമായ ഭാഷാ മോഡലാണ്; അതായത്, മുൻ സന്ദർഭം (context) നൽകിയാൽ ടോക്കൺ X-ന്റെ പ്രോബബിലിറ്റി എന്നത് ടോക്കൺ X-ന്റെ പ്രോബബിലിറ്റി തന്നെയാണ്. അതിനാൽ, ടെക്‌സ്‌റ്റ് ജനറേറ്റ് ചെയ്യാൻ ഒരു Unigram ഭാഷാ മോഡൽ ഉപയോഗിച്ചാൽ, നമ്മൾ എപ്പോഴും ഏറ്റവും സാധാരണമായ ടോക്കൺ തന്നെ പ്രവചിക്കും. + +ഒരു ടോക്കണിന്റെ പ്രോബബിലിറ്റി എന്നത്, യഥാർത്ഥ കോർപ്പസിലെ അതിന്റെ ഫ്രീക്വൻസിയെ (frequency — അത് എത്ര തവണ കാണപ്പെടുന്നു എന്നത്) വൊക്കാബുലറിയിലെ എല്ലാ ടോക്കണുകളുടെയും എല്ലാ ഫ്രീക്വൻസികളുടെയും ആകെത്തുകയാൽ ഹരിച്ചതാണ് (പ്രോബബിലിറ്റികളുടെ ആകെത്തുക 1 ആണെന്ന് ഉറപ്പാക്കാൻ). ഉദാഹരണത്തിന്, `"ug"` എന്നത് `"hug"`, `"pug"`, `"hugs"` എന്നിവയിൽ ഉണ്ട്, അതിനാൽ നമ്മുടെ കോർപ്പസിൽ അതിന്റെ ഫ്രീക്വൻസി 20 ആണ്. + +വൊക്കാബുലറിയിലെ സാധ്യമായ എല്ലാ സബ്‌വേഡുകളുടെയും ഫ്രീക്വൻസികൾ ഇതാ: + +``` +("h", 15) ("u", 36) ("g", 20) ("hu", 15) ("ug", 20) ("p", 17) ("pu", 17) ("n", 16) +("un", 16) ("b", 4) ("bu", 4) ("s", 5) ("hug", 15) ("gs", 5) ("ugs", 5) +``` + +അതിനാൽ, എല്ലാ ഫ്രീക്വൻസികളുടെയും ആകെത്തുക 210 ആണ്, അങ്ങനെ `"ug"` എന്ന സബ്‌വേഡിന്റെ പ്രോബബിലിറ്റി 20/210 ആണ്. + +> [!TIP] +> ✏️ **ഇനി നിങ്ങളുടെ ഊഴം!** മുകളിലുള്ള ഫ്രീക്വൻസികൾ കണക്കാക്കാനുള്ള കോഡ് എഴുതുകയും, കാണിച്ചിരിക്കുന്ന ഫലങ്ങളും മൊത്തം തുകയും ശരിയാണെന്ന് ഒന്നുകൂടി ഉറപ്പുവരുത്തുകയും ചെയ്യുക. + +ഇനി, ഒരു വാക്ക് ടോക്കണൈസ് ചെയ്യാൻ, അതിനെ ടോക്കണുകളായി വിഭജിക്കാവുന്ന സാധ്യമായ എല്ലാ സെഗ്‌മെന്റേഷനുകളും (segmentations) നമ്മൾ നോക്കുകയും, Unigram മോഡൽ അനുസരിച്ച് ഓരോന്നിന്റെയും പ്രോബബിലിറ്റി കണക്കാക്കുകയും ചെയ്യുന്നു. എല്ലാ ടോക്കണുകളും സ്വതന്ത്രമായി പരിഗണിക്കപ്പെടുന്നതിനാൽ, ഈ പ്രോബബിലിറ്റി ഓരോ ടോക്കണിന്റെയും പ്രോബബിലിറ്റികളുടെ ഗുണനഫലം മാത്രമാണ്. ഉദാഹരണത്തിന്, `"pug"`-ന്റെ `["p", "u", "g"]` എന്ന ടോക്കണൈസേഷന്റെ പ്രോബബിലിറ്റി ഇതാണ്: + +$$P([``p", ``u", ``g"]) = P(``p") \times P(``u") \times P(``g") = \frac{5}{210} \times \frac{36}{210} \times \frac{20}{210} = 0.000389$$ + +താരതമ്യേന, `["pu", "g"]` എന്ന ടോക്കണൈസേഷന്റെ പ്രോബബിലിറ്റി ഇതാണ്: + +$$P([``pu", ``g"]) = P(``pu") \times P(``g") = \frac{5}{210} \times \frac{20}{210} = 0.0022676$$ + +അതിനാൽ അതിനാണ് വളരെ കൂടുതൽ സാധ്യത. പൊതുവേ, സാധ്യമായ ഏറ്റവും കുറച്ച് ടോക്കണുകളുള്ള ടോക്കണൈസേഷനുകൾക്കായിരിക്കും ഏറ്റവും ഉയർന്ന പ്രോബബിലിറ്റി (ഓരോ ടോക്കണിനും 210 കൊണ്ടുള്ള ആ ഹരണം ആവർത്തിക്കുന്നതുകൊണ്ടാണ് ഇത്), ഇത് നമ്മൾ അവബോധപരമായി ആഗ്രഹിക്കുന്നതിനോട് യോജിക്കുന്നു: ഒരു വാക്കിനെ സാധ്യമായ ഏറ്റവും കുറഞ്ഞ എണ്ണം ടോക്കണുകളായി വിഭജിക്കുക. + +അങ്ങനെ, Unigram മോഡൽ ഉപയോഗിച്ചുള്ള ഒരു വാക്കിന്റെ ടോക്കണൈസേഷൻ എന്നത് ഏറ്റവും ഉയർന്ന പ്രോബബിലിറ്റിയുള്ള ടോക്കണൈസേഷനാണ്. `"pug"`-ന്റെ ഉദാഹരണത്തിൽ, സാധ്യമായ ഓരോ സെഗ്‌മെന്റേഷനും നമുക്ക് ലഭിക്കുന്ന പ്രോബബിലിറ്റികൾ ഇതാ: + +``` +["p", "u", "g"] : 0.000389 +["p", "ug"] : 0.0022676 +["pu", "g"] : 0.0022676 +``` + +അതിനാൽ, ആ സെഗ്‌മെന്റേഷനുകളിൽ ഏതാണ് ആദ്യം കണ്ടുമുട്ടുന്നത് എന്നതിനെ ആശ്രയിച്ച്, `"pug"` എന്നത് `["p", "ug"]` ആയോ `["pu", "g"]` ആയോ ടോക്കണൈസ് ചെയ്യപ്പെടും (ഒരു വലിയ കോർപ്പസിൽ ഇതുപോലുള്ള തുല്യതാ സാഹചര്യങ്ങൾ അപൂർവമായിരിക്കും എന്നത് ശ്രദ്ധിക്കുക). + +ഈ സാഹചര്യത്തിൽ, സാധ്യമായ എല്ലാ സെഗ്‌മെന്റേഷനുകളും കണ്ടെത്തി അവയുടെ പ്രോബബിലിറ്റികൾ കണക്കാക്കുന്നത് എളുപ്പമായിരുന്നു, എന്നാൽ പൊതുവേ ഇത് കുറച്ചുകൂടി ബുദ്ധിമുട്ടുള്ളതായിരിക്കും. ഇതിനായി ഉപയോഗിക്കുന്ന ഒരു ക്ലാസിക് അൽഗോരിതമുണ്ട്, *Viterbi അൽഗോരിതം* എന്നാണ് ഇതിന്റെ പേര്. അടിസ്ഥാനപരമായി, _a_ മുതൽ _b_ വരെയുള്ള സബ്‌വേഡ് വൊക്കാബുലറിയിലുണ്ടെങ്കിൽ ക്യാരക്‌ടർ _a_-യിൽ നിന്ന് ക്യാരക്‌ടർ _b_-യിലേക്ക് ഒരു ശാഖ (branch) ഉണ്ട് എന്ന് പറഞ്ഞുകൊണ്ട്, ഒരു വാക്കിന്റെ സാധ്യമായ സെഗ്‌മെന്റേഷനുകൾ കണ്ടെത്താൻ നമുക്ക് ഒരു ഗ്രാഫ് നിർമ്മിക്കാം, ആ ശാഖയ്ക്ക് സബ്‌വേഡിന്റെ പ്രോബബിലിറ്റി നൽകുകയും ചെയ്യാം. + +ആ ഗ്രാഫിൽ ഏറ്റവും മികച്ച സ്‌കോർ ലഭിക്കുന്ന പാത കണ്ടെത്താൻ, വാക്കിലെ ഓരോ സ്ഥാനത്തിനും (position), ആ സ്ഥാനത്ത് അവസാനിക്കുന്ന ഏറ്റവും മികച്ച സ്‌കോറുള്ള സെഗ്‌മെന്റേഷൻ Viterbi അൽഗോരിതം നിർണ്ണയിക്കുന്നു. നമ്മൾ തുടക്കത്തിൽ നിന്ന് അവസാനത്തിലേക്കാണ് പോകുന്നതിനാൽ, നിലവിലെ സ്ഥാനത്ത് അവസാനിക്കുന്ന എല്ലാ സബ്‌വേഡുകളിലൂടെയും ലൂപ്പ് ചെയ്ത്, ആ സബ്‌വേഡ് തുടങ്ങുന്ന സ്ഥാനത്തെ ഏറ്റവും മികച്ച ടോക്കണൈസേഷൻ സ്‌കോർ ഉപയോഗിച്ച് ആ മികച്ച സ്‌കോർ കണ്ടെത്താം. തുടർന്ന്, അവസാനത്തിൽ എത്താൻ സ്വീകരിച്ച പാത നമ്മൾ പിന്നോട്ട് നിവർത്തിയെടുത്താൽ (unroll) മാത്രം മതി. + +നമ്മുടെ വൊക്കാബുലറിയും `"unhug"` എന്ന വാക്കും ഉപയോഗിച്ചുള്ള ഒരു ഉദാഹരണം നോക്കാം. ഓരോ സ്ഥാനത്തിനും, അവിടെ അവസാനിക്കുന്ന ഏറ്റവും മികച്ച സ്‌കോറുകളുള്ള സബ്‌വേഡുകൾ ഇവയാണ്: + +``` +Character 0 (u): "u" (score 0.171429) +Character 1 (n): "un" (score 0.076191) +Character 2 (h): "un" "h" (score 0.005442) +Character 3 (u): "un" "hu" (score 0.005442) +Character 4 (g): "un" "hug" (score 0.005442) +``` + +അങ്ങനെ `"unhug"` എന്നത് `["un", "hug"]` ആയി ടോക്കണൈസ് ചെയ്യപ്പെടും. + +> [!TIP] +> ✏️ **ഇനി നിങ്ങളുടെ ഊഴം!** `"huggun"` എന്ന വാക്കിന്റെ ടോക്കണൈസേഷനും അതിന്റെ സ്‌കോറും നിർണ്ണയിക്കുക. + +## വീണ്ടും ട്രെയിനിംഗിലേക്ക്[[back-to-training]] + +ടോക്കണൈസേഷൻ എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് ഇപ്പോൾ നമ്മൾ കണ്ടതിനാൽ, ട്രെയിനിംഗ് സമയത്ത് ഉപയോഗിക്കുന്ന ലോസിലേക്ക് നമുക്ക് കുറച്ചുകൂടി ആഴത്തിൽ കടക്കാം. ഏതൊരു ഘട്ടത്തിലും, നിലവിലെ വൊക്കാബുലറിയും കോർപ്പസിലെ ഓരോ ടോക്കണിന്റെയും ഫ്രീക്വൻസികൾ നിർണ്ണയിക്കുന്ന Unigram മോഡലും ഉപയോഗിച്ച് (മുമ്പ് കണ്ടതുപോലെ), കോർപ്പസിലെ ഓരോ വാക്കും ടോക്കണൈസ് ചെയ്താണ് ഈ ലോസ് കണക്കാക്കുന്നത്. + +കോർപ്പസിലെ ഓരോ വാക്കിനും ഒരു സ്‌കോർ ഉണ്ട്, ആ സ്‌കോറുകളുടെ നെഗറ്റീവ് ലോഗ് ലൈക്‌ലിഹുഡ് (negative log likelihood) ആണ് ലോസ് -- അതായത്, കോർപ്പസിലെ എല്ലാ വാക്കുകളുടെയും `-log(P(word))`-കളുടെ ആകെത്തുക. + +താഴെ പറയുന്ന കോർപ്പസുള്ള നമ്മുടെ ഉദാഹരണത്തിലേക്ക് തിരിച്ചുപോകാം: + +``` +("hug", 10), ("pug", 5), ("pun", 12), ("bun", 4), ("hugs", 5) +``` + +ഓരോ വാക്കിന്റെയും ടോക്കണൈസേഷനും അവയുടെ സ്‌കോറുകളും ഇതാ: + +``` +"hug": ["hug"] (score 0.071428) +"pug": ["pu", "g"] (score 0.007710) +"pun": ["pu", "n"] (score 0.006168) +"bun": ["bu", "n"] (score 0.001451) +"hugs": ["hug", "s"] (score 0.001701) +``` + +അതിനാൽ ലോസ് ഇതാണ്: + +``` +10 * (-log(0.071428)) + 5 * (-log(0.007710)) + 12 * (-log(0.006168)) + 4 * (-log(0.001451)) + 5 * (-log(0.001701)) = 169.8 +``` + +ഇനി, ഓരോ ടോക്കണും നീക്കം ചെയ്യുന്നത് ലോസിനെ എങ്ങനെ ബാധിക്കുന്നു എന്ന് നമ്മൾ കണക്കാക്കണം. ഇത് കുറച്ച് മടുപ്പിക്കുന്ന ജോലിയാണ്, അതിനാൽ ഇവിടെ രണ്ട് ടോക്കണുകൾക്ക് മാത്രം നമ്മൾ ഇത് ചെയ്യും; മുഴുവൻ പ്രക്രിയയും, നമ്മെ സഹായിക്കാൻ കോഡ് ഉള്ളപ്പോഴേക്ക് മാറ്റിവയ്ക്കും. ഈ (വളരെ) പ്രത്യേക സാഹചര്യത്തിൽ, എല്ലാ വാക്കുകൾക്കും തുല്യമായ രണ്ട് ടോക്കണൈസേഷനുകൾ നമുക്കുണ്ടായിരുന്നു: ഉദാഹരണത്തിന്, നേരത്തെ കണ്ടതുപോലെ, `"pug"` എന്നത് അതേ സ്‌കോറോടെ `["p", "ug"]` ആയി ടോക്കണൈസ് ചെയ്യാമായിരുന്നു. അതിനാൽ, വൊക്കാബുലറിയിൽ നിന്ന് `"pu"` ടോക്കൺ നീക്കം ചെയ്താൽ കൃത്യമായി അതേ ലോസ് തന്നെ ലഭിക്കും. + +മറുവശത്ത്, `"hug"` നീക്കം ചെയ്യുന്നത് ലോസ് കൂടുതൽ മോശമാക്കും, കാരണം `"hug"`-ന്റെയും `"hugs"`-ന്റെയും ടോക്കണൈസേഷൻ ഇങ്ങനെയാകും: + +``` +"hug": ["hu", "g"] (score 0.006802) +"hugs": ["hu", "gs"] (score 0.001701) +``` + +ഈ മാറ്റങ്ങൾ ലോസ് ഇത്രയും ഉയരാൻ കാരണമാകും: + +``` +- 10 * (-log(0.071428)) + 10 * (-log(0.006802)) = 23.5 +``` + +അതിനാൽ, `"pu"` എന്ന ടോക്കൺ ഒരുപക്ഷേ വൊക്കാബുലറിയിൽ നിന്ന് നീക്കം ചെയ്യപ്പെടും, എന്നാൽ `"hug"` നീക്കം ചെയ്യപ്പെടില്ല. + +## Unigram ഇംപ്ലിമെന്റ് ചെയ്യുന്നു[[implementing-unigram]] + +ഇനി ഇതുവരെ നമ്മൾ കണ്ടതെല്ലാം കോഡിൽ ഇംപ്ലിമെന്റ് ചെയ്യാം. BPE-യുടെയും WordPiece-ന്റെയും കാര്യത്തിലേതുപോലെ, ഇത് Unigram അൽഗോരിതത്തിന്റെ കാര്യക്ഷമമായ ഒരു ഇംപ്ലിമെന്റേഷനല്ല (നേരെ മറിച്ചാണ്), എന്നാൽ അത് കുറച്ചുകൂടി നന്നായി മനസ്സിലാക്കാൻ ഇത് നിങ്ങളെ സഹായിക്കും. + +മുമ്പത്തെ അതേ കോർപ്പസ് തന്നെ നമ്മൾ ഉദാഹരണമായി ഉപയോഗിക്കും: + +```python +corpus = [ + "This is the Hugging Face Course.", + "This chapter is about tokenization.", + "This section shows several tokenizer algorithms.", + "Hopefully, you will be able to understand how they are trained and generate tokens.", +] +``` + +ഇത്തവണ, `xlnet-base-cased` ആണ് നമ്മൾ മോഡലായി ഉപയോഗിക്കുന്നത്: + +```python +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained("xlnet-base-cased") +``` + +BPE-യുടെയും WordPiece-ന്റെയും കാര്യത്തിലേതുപോലെ, കോർപ്പസിലെ ഓരോ വാക്കും എത്ര തവണ വരുന്നു എന്ന് എണ്ണിക്കൊണ്ടാണ് നമ്മൾ തുടങ്ങുന്നത്: + +```python +from collections import defaultdict + +word_freqs = defaultdict(int) +for text in corpus: + words_with_offsets = tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str(text) + new_words = [word for word, offset in words_with_offsets] + for word in new_words: + word_freqs[word] += 1 + +word_freqs +``` + +തുടർന്ന്, അവസാനം നമുക്ക് വേണ്ട വൊക്കാബുലറി വലുപ്പത്തെക്കാൾ വലുതായ ഒന്നിലേക്ക് നമ്മുടെ വൊക്കാബുലറി ഇനിഷ്യലൈസ് ചെയ്യണം. എല്ലാ അടിസ്ഥാന ക്യാരക്‌ടറുകളും നമ്മൾ ഉൾപ്പെടുത്തണം (അല്ലാത്തപക്ഷം എല്ലാ വാക്കുകളും ടോക്കണൈസ് ചെയ്യാൻ നമുക്ക് കഴിയില്ല), എന്നാൽ വലിയ സബ്‌സ്‌ട്രിംഗുകളുടെ കാര്യത്തിൽ ഏറ്റവും സാധാരണമായവ മാത്രമേ നമ്മൾ നിലനിർത്തൂ, അതിനാൽ അവയെ ഫ്രീക്വൻസി അനുസരിച്ച് ക്രമീകരിക്കുന്നു: + +```python +char_freqs = defaultdict(int) +subwords_freqs = defaultdict(int) +for word, freq in word_freqs.items(): + for i in range(len(word)): + char_freqs[word[i]] += freq + # Loop through the subwords of length at least 2 + for j in range(i + 2, len(word) + 1): + subwords_freqs[word[i:j]] += freq + +# Sort subwords by frequency +sorted_subwords = sorted(subwords_freqs.items(), key=lambda x: x[1], reverse=True) +sorted_subwords[:10] +``` + +```python out +[('▁t', 7), ('is', 5), ('er', 5), ('▁a', 5), ('▁to', 4), ('to', 4), ('en', 4), ('▁T', 3), ('▁Th', 3), ('▁Thi', 3)] +``` + +300 വലുപ്പമുള്ള ഒരു പ്രാരംഭ വൊക്കാബുലറിയിൽ എത്താൻ, ക്യാരക്‌ടറുകളെ ഏറ്റവും മികച്ച സബ്‌വേഡുകളുമായി നമ്മൾ കൂട്ടിച്ചേർക്കുന്നു: + +```python +token_freqs = list(char_freqs.items()) + sorted_subwords[: 300 - len(char_freqs)] +token_freqs = {token: freq for token, freq in token_freqs} +``` + +> [!TIP] +> 💡 പ്രാരംഭ വൊക്കാബുലറി നിർമ്മിക്കാൻ SentencePiece, Enhanced Suffix Array (ESA) എന്ന കൂടുതൽ കാര്യക്ഷമമായ ഒരു അൽഗോരിതം ഉപയോഗിക്കുന്നു. + +അടുത്തതായി, ഫ്രീക്വൻസികളെ പ്രോബബിലിറ്റികളാക്കി മാറ്റാൻ, എല്ലാ ഫ്രീക്വൻസികളുടെയും ആകെത്തുക നമ്മൾ കണക്കാക്കുന്നു. നമ്മുടെ മോഡലിനായി പ്രോബബിലിറ്റികളുടെ ലോഗരിതങ്ങളാണ് (logarithms) നമ്മൾ സ്‌റ്റോർ ചെയ്യുന്നത്, കാരണം ചെറിയ സംഖ്യകൾ ഗുണിക്കുന്നതിനെക്കാൾ ലോഗരിതങ്ങൾ കൂട്ടുന്നത് സംഖ്യാപരമായി കൂടുതൽ സ്ഥിരതയുള്ളതാണ് (numerically stable), കൂടാതെ ഇത് മോഡലിന്റെ ലോസ് കണക്കാക്കുന്നത് ലളിതമാക്കുകയും ചെയ്യും: + +```python +from math import log + +total_sum = sum([freq for token, freq in token_freqs.items()]) +model = {token: -log(freq / total_sum) for token, freq in token_freqs.items()} +``` + +ഇനി, Viterbi അൽഗോരിതം ഉപയോഗിച്ച് വാക്കുകൾ ടോക്കണൈസ് ചെയ്യുന്ന ഫംഗ്‌ഷനാണ് പ്രധാന ഫംഗ്‌ഷൻ. മുമ്പ് കണ്ടതുപോലെ, ആ അൽഗോരിതം വാക്കിന്റെ ഓരോ സബ്‌സ്‌ട്രിംഗിന്റെയും ഏറ്റവും മികച്ച സെഗ്‌മെന്റേഷൻ കണക്കാക്കുന്നു, അത് നമ്മൾ `best_segmentations` എന്ന വേരിയബിളിൽ സ്‌റ്റോർ ചെയ്യും. വാക്കിലെ ഓരോ സ്ഥാനത്തിനും (0 മുതൽ അതിന്റെ മൊത്തം നീളം വരെ) രണ്ട് കീകളുള്ള ഒരു ഡിക്‌ഷണറി വീതം നമ്മൾ സ്‌റ്റോർ ചെയ്യും: ഏറ്റവും മികച്ച സെഗ്‌മെന്റേഷനിലെ അവസാന ടോക്കണിന്റെ തുടക്കത്തിന്റെ ഇൻഡെക്‌സ്, ഏറ്റവും മികച്ച സെഗ്‌മെന്റേഷന്റെ സ്‌കോർ എന്നിവയാണ് ആ കീകൾ. അവസാന ടോക്കണിന്റെ തുടക്കത്തിന്റെ ഇൻഡെക്‌സ് ഉപയോഗിച്ച്, ലിസ്‌റ്റ് പൂർണ്ണമായി പൂരിപ്പിച്ചു കഴിഞ്ഞാൽ മുഴുവൻ സെഗ്‌മെന്റേഷനും നമുക്ക് വീണ്ടെടുക്കാൻ കഴിയും. + +വെറും രണ്ട് ലൂപ്പുകൾ ഉപയോഗിച്ചാണ് ലിസ്‌റ്റ് പൂരിപ്പിക്കുന്നത്: പ്രധാന ലൂപ്പ് ഓരോ തുടക്ക സ്ഥാനത്തിലൂടെയും കടന്നുപോകുന്നു, രണ്ടാമത്തെ ലൂപ്പ് ആ തുടക്ക സ്ഥാനത്ത് ആരംഭിക്കുന്ന എല്ലാ സബ്‌സ്‌ട്രിംഗുകളും പരീക്ഷിക്കുന്നു. സബ്‌സ്‌ട്രിംഗ് വൊക്കാബുലറിയിലുണ്ടെങ്കിൽ, ആ അവസാന സ്ഥാനം വരെയുള്ള വാക്കിന്റെ ഒരു പുതിയ സെഗ്‌മെന്റേഷൻ നമുക്ക് ലഭിക്കുന്നു, അതിനെ `best_segmentations`-ൽ ഉള്ളതുമായി നമ്മൾ താരതമ്യം ചെയ്യുന്നു. + +പ്രധാന ലൂപ്പ് പൂർത്തിയായിക്കഴിഞ്ഞാൽ, നമ്മൾ അവസാനത്തിൽ നിന്ന് തുടങ്ങി, വാക്കിന്റെ തുടക്കത്തിൽ എത്തുന്നതുവരെ ഒരു തുടക്ക സ്ഥാനത്തിൽ നിന്ന് അടുത്തതിലേക്ക് ചാടിക്കൊണ്ട്, പോകുന്ന വഴിയിൽ ടോക്കണുകൾ രേഖപ്പെടുത്തുന്നു: + +```python +def encode_word(word, model): + best_segmentations = [{"start": 0, "score": 1}] + [ + {"start": None, "score": None} for _ in range(len(word)) + ] + for start_idx in range(len(word)): + # This should be properly filled by the previous steps of the loop + best_score_at_start = best_segmentations[start_idx]["score"] + for end_idx in range(start_idx + 1, len(word) + 1): + token = word[start_idx:end_idx] + if token in model and best_score_at_start is not None: + score = model[token] + best_score_at_start + # If we have found a better segmentation ending at end_idx, we update + if ( + best_segmentations[end_idx]["score"] is None + or best_segmentations[end_idx]["score"] > score + ): + best_segmentations[end_idx] = {"start": start_idx, "score": score} + + segmentation = best_segmentations[-1] + if segmentation["score"] is None: + # We did not find a tokenization of the word -> unknown + return [""], None + + score = segmentation["score"] + start = segmentation["start"] + end = len(word) + tokens = [] + while start != 0: + tokens.insert(0, word[start:end]) + next_start = best_segmentations[start]["start"] + end = start + start = next_start + tokens.insert(0, word[start:end]) + return tokens, score +``` + +നമ്മുടെ പ്രാരംഭ മോഡൽ ചില വാക്കുകളിൽ ഇപ്പോൾ തന്നെ നമുക്ക് പരീക്ഷിക്കാം: + +```python +print(encode_word("Hopefully", model)) +print(encode_word("This", model)) +``` + +```python out +(['H', 'o', 'p', 'e', 'f', 'u', 'll', 'y'], 41.5157494601402) +(['This'], 6.288267030694535) +``` + +ഇനി കോർപ്പസിൽ മോഡലിന്റെ ലോസ് കണക്കാക്കുന്നത് എളുപ്പമാണ്! + +```python +def compute_loss(model): + loss = 0 + for word, freq in word_freqs.items(): + _, word_loss = encode_word(word, model) + loss += freq * word_loss + return loss +``` + +നമ്മുടെ കൈയിലുള്ള മോഡലിൽ ഇത് പ്രവർത്തിക്കുന്നുണ്ടോ എന്ന് നമുക്ക് പരിശോധിക്കാം: + +```python +compute_loss(model) +``` + +```python out +413.10377642940875 +``` + +ഓരോ ടോക്കണിന്റെയും സ്‌കോറുകൾ കണക്കാക്കുന്നതും അത്ര ബുദ്ധിമുട്ടുള്ള കാര്യമല്ല; ഓരോ ടോക്കണും ഒഴിവാക്കി ലഭിക്കുന്ന മോഡലുകളുടെ ലോസ് നമ്മൾ കണക്കാക്കിയാൽ മാത്രം മതി: + +```python +import copy + + +def compute_scores(model): + scores = {} + model_loss = compute_loss(model) + for token, score in model.items(): + # We always keep tokens of length 1 + if len(token) == 1: + continue + model_without_token = copy.deepcopy(model) + _ = model_without_token.pop(token) + scores[token] = compute_loss(model_without_token) - model_loss + return scores +``` + +ഒരു നിശ്ചിത ടോക്കണിൽ നമുക്ക് ഇത് പരീക്ഷിക്കാം: + +```python +scores = compute_scores(model) +print(scores["ll"]) +print(scores["his"]) +``` + +`"Hopefully"`-യുടെ ടോക്കണൈസേഷനിൽ `"ll"` ഉപയോഗിക്കുന്നതിനാലും, അത് നീക്കം ചെയ്താൽ പകരം `"l"` എന്ന ടോക്കൺ രണ്ട് തവണ ഉപയോഗിക്കേണ്ടി വരാൻ സാധ്യതയുള്ളതിനാലും, അതിന് ഒരു പോസിറ്റീവ് ലോസ് ഉണ്ടാകുമെന്ന് നമ്മൾ പ്രതീക്ഷിക്കുന്നു. `"his"` എന്നത് `"This"` എന്ന വാക്കിനുള്ളിൽ മാത്രമേ ഉപയോഗിക്കുന്നുള്ളൂ, ആ വാക്ക് അതേപടിയാണ് ടോക്കണൈസ് ചെയ്യപ്പെടുന്നത്, അതിനാൽ അതിന് പൂജ്യം ലോസ് ആയിരിക്കുമെന്ന് നമ്മൾ പ്രതീക്ഷിക്കുന്നു. ഫലങ്ങൾ ഇതാ: + +```python out +6.376412403623874 +0.0 +``` + +> [!TIP] +> 💡 ഈ സമീപനം വളരെ കാര്യക്ഷമത കുറഞ്ഞതാണ്, അതിനാൽ ടോക്കൺ X ഇല്ലാത്ത മോഡലിന്റെ ലോസിന്റെ ഒരു ഏകദേശ കണക്ക് (approximation) SentencePiece ഉപയോഗിക്കുന്നു: തുടക്കം മുതൽ വീണ്ടും ആരംഭിക്കുന്നതിന് പകരം, ബാക്കിയുള്ള വൊക്കാബുലറിയിലെ അതിന്റെ സെഗ്‌മെന്റേഷൻ കൊണ്ട് ടോക്കൺ X-നെ അത് പകരം വയ്ക്കുന്നു. ഇങ്ങനെ, മോഡൽ ലോസിനൊപ്പം തന്നെ എല്ലാ സ്‌കോറുകളും ഒറ്റയടിക്ക് കണക്കാക്കാൻ കഴിയും. + +ഇതെല്ലാം തയ്യാറായിക്കഴിഞ്ഞാൽ, മോഡൽ ഉപയോഗിക്കുന്ന സ്‌പെഷ്യൽ ടോക്കണുകൾ വൊക്കാബുലറിയിലേക്ക് ചേർക്കുകയും, തുടർന്ന് നമുക്ക് വേണ്ട വലുപ്പത്തിൽ എത്താൻ വൊക്കാബുലറിയിൽ നിന്ന് ആവശ്യത്തിന് ടോക്കണുകൾ വെട്ടിമാറ്റുന്നതുവരെ (prune) ലൂപ്പ് ചെയ്യുകയുമാണ് നമ്മൾ ചെയ്യേണ്ട അവസാന കാര്യം: + +```python +percent_to_remove = 0.1 +while len(model) > 100: + scores = compute_scores(model) + sorted_scores = sorted(scores.items(), key=lambda x: x[1]) + # Remove percent_to_remove tokens with the lowest scores. + for i in range(int(len(model) * percent_to_remove)): + _ = token_freqs.pop(sorted_scores[i][0]) + + total_sum = sum([freq for token, freq in token_freqs.items()]) + model = {token: -log(freq / total_sum) for token, freq in token_freqs.items()} +``` + +തുടർന്ന്, ഏതെങ്കിലും ടെക്‌സ്‌റ്റ് ടോക്കണൈസ് ചെയ്യാൻ, പ്രീ-ടോക്കണൈസേഷൻ പ്രയോഗിച്ചതിന് ശേഷം നമ്മുടെ `encode_word()` ഫംഗ്‌ഷൻ ഉപയോഗിച്ചാൽ മാത്രം മതി: + +```python +def tokenize(text, model): + words_with_offsets = tokenizer.backend_tokenizer.pre_tokenizer.pre_tokenize_str(text) + pre_tokenized_text = [word for word, offset in words_with_offsets] + encoded_words = [encode_word(word, model)[0] for word in pre_tokenized_text] + return sum(encoded_words, []) + + +tokenize("This is the Hugging Face course.", model) +``` + +```python out +['▁This', '▁is', '▁the', '▁Hugging', '▁Face', '▁', 'c', 'ou', 'r', 's', 'e', '.'] +``` + +> [!TIP] +> XLNetTokenizer SentencePiece ഉപയോഗിക്കുന്നു, അതുകൊണ്ടാണ് `"_"` എന്ന ക്യാരക്‌ടർ ഉൾപ്പെട്ടിരിക്കുന്നത്. SentencePiece ഉപയോഗിച്ച് ഡീകോഡ് ചെയ്യാൻ, എല്ലാ ടോക്കണുകളും കൂട്ടിച്ചേർത്ത് (concatenate) `"_"`-നെ ഒരു സ്‌പേസ് കൊണ്ട് പകരം വയ്ക്കുക. + +Unigram-നെക്കുറിച്ച് ഇത്രയേയുള്ളൂ! ടോക്കണൈസറുമായി ബന്ധപ്പെട്ട എല്ലാ കാര്യങ്ങളിലും നിങ്ങൾ ഇപ്പോൾ ഒരു എക്‌സ്‌പെർട്ട് ആയതുപോലെ തോന്നുന്നുണ്ടാകുമെന്ന് കരുതുന്നു. അടുത്ത ഭാഗത്തിൽ, 🤗 Tokenizers ലൈബ്രറിയുടെ അടിസ്ഥാന ഘടകങ്ങളിലേക്ക് (building blocks) നമ്മൾ കടക്കുകയും, നിങ്ങളുടെ സ്വന്തം ടോക്കണൈസർ നിർമ്മിക്കാൻ അവ എങ്ങനെ ഉപയോഗിക്കാമെന്ന് കാണിച്ചുതരികയും ചെയ്യും. diff --git a/chapters/ml/chapter6/8.mdx b/chapters/ml/chapter6/8.mdx new file mode 100644 index 000000000..9d6591e91 --- /dev/null +++ b/chapters/ml/chapter6/8.mdx @@ -0,0 +1,562 @@ +# ഒരു ടോക്കണൈസർ ബ്ലോക്ക് ബ്ലോക്കായി നിർമ്മിക്കുന്നു[[building-a-tokenizer-block-by-block]] + + + +മുൻ ഭാഗങ്ങളിൽ നമ്മൾ കണ്ടതുപോലെ, ടോക്കണൈസേഷനിൽ പല ഘട്ടങ്ങൾ ഉൾപ്പെടുന്നു: + +- നോർമലൈസേഷൻ (Normalization) (ടെക്‌സ്‌റ്റിൽ ആവശ്യമെന്ന് കരുതുന്ന ഏത് ശുദ്ധീകരണവും — സ്‌പേസുകളോ ആക്‌സന്റുകളോ (accents) നീക്കം ചെയ്യുക, യൂണികോഡ് നോർമലൈസേഷൻ തുടങ്ങിയവ) +- പ്രീ-ടോക്കണൈസേഷൻ (Pre-tokenization) (ഇൻപുട്ടിനെ വാക്കുകളായി വിഭജിക്കുക) +- ഇൻപുട്ട് മോഡലിലൂടെ കടത്തിവിടുക (പ്രീ-ടോക്കണൈസ് ചെയ്ത വാക്കുകൾ ഉപയോഗിച്ച് ടോക്കണുകളുടെ ഒരു സീക്വൻസ് ഉണ്ടാക്കുക) +- പോസ്‌റ്റ്-പ്രോസസ്സിംഗ് (Post-processing) (ടോക്കണൈസറിന്റെ പ്രത്യേക ടോക്കണുകൾ ചേർക്കുക, അറ്റൻഷൻ മാസ്‌കും ടോക്കൺ ടൈപ്പ് ID-കളും ജനറേറ്റ് ചെയ്യുക) + +ഓർമ്മപ്പെടുത്തലായി, മൊത്തത്തിലുള്ള പ്രക്രിയ ഒരിക്കൽ കൂടി ഇതാ: + +
+ടോക്കണൈസേഷൻ പൈപ്പ്‌ലൈൻ. + +
+ +ഈ ഓരോ ഘട്ടത്തിനും പല ഓപ്‌ഷനുകൾ നൽകുന്ന തരത്തിലാണ് 🤗 Tokenizers ലൈബ്രറി നിർമ്മിച്ചിരിക്കുന്നത്; അവ നിങ്ങൾക്ക് ഇഷ്ടാനുസരണം കൂട്ടിച്ചേർത്ത് ഉപയോഗിക്കാം. [ഭാഗം 2](/course/chapter6/2)-ൽ നമ്മൾ ചെയ്തതുപോലെ പഴയൊരു ടോക്കണൈസറിൽ നിന്ന് പുതിയൊരു ടോക്കണൈസർ ട്രെയിൻ ചെയ്യുന്നതിന് പകരം, ഒരു ടോക്കണൈസർ പൂജ്യത്തിൽ നിന്ന് (from scratch) എങ്ങനെ നിർമ്മിക്കാമെന്ന് ഈ ഭാഗത്തിൽ നമ്മൾ കാണും. അതിനുശേഷം, നിങ്ങൾക്ക് ചിന്തിക്കാവുന്ന ഏതുതരം ടോക്കണൈസറും നിർമ്മിക്കാൻ നിങ്ങൾക്ക് കഴിയും! + + + +കൂടുതൽ കൃത്യമായി പറഞ്ഞാൽ, ഒരു കേന്ദ്ര `Tokenizer` ക്ലാസിനെ ചുറ്റിപ്പറ്റിയാണ് ഈ ലൈബ്രറി നിർമ്മിച്ചിരിക്കുന്നത്; ബിൽഡിംഗ് ബ്ലോക്കുകൾ (building blocks) സബ്‌മൊഡ്യൂളുകളായി തരംതിരിച്ചിരിക്കുന്നു: + +- `normalizers`-ൽ, നിങ്ങൾക്ക് ഉപയോഗിക്കാവുന്ന എല്ലാത്തരം `Normalizer`-ഉം അടങ്ങിയിരിക്കുന്നു (പൂർണ്ണമായ ലിസ്‌റ്റ് [ഇവിടെ](https://huggingface.co/docs/tokenizers/api/normalizers)). +- `pre_tokenizers`-ൽ, നിങ്ങൾക്ക് ഉപയോഗിക്കാവുന്ന എല്ലാത്തരം `PreTokenizer`-ഉം അടങ്ങിയിരിക്കുന്നു (പൂർണ്ണമായ ലിസ്‌റ്റ് [ഇവിടെ](https://huggingface.co/docs/tokenizers/api/pre-tokenizers)). +- `models`-ൽ, `BPE`, `WordPiece`, `Unigram` തുടങ്ങി നിങ്ങൾക്ക് ഉപയോഗിക്കാവുന്ന വിവിധതരം `Model`-കൾ അടങ്ങിയിരിക്കുന്നു (പൂർണ്ണമായ ലിസ്‌റ്റ് [ഇവിടെ](https://huggingface.co/docs/tokenizers/api/models)). +- `trainers`-ൽ, ഒരു കോർപ്പസിൽ (corpus) നിങ്ങളുടെ മോഡൽ ട്രെയിൻ ചെയ്യാൻ ഉപയോഗിക്കാവുന്ന വിവിധതരം `Trainer`-കൾ അടങ്ങിയിരിക്കുന്നു (ഓരോ തരം മോഡലിനും ഒന്ന്; പൂർണ്ണമായ ലിസ്‌റ്റ് [ഇവിടെ](https://huggingface.co/docs/tokenizers/api/trainers)). +- `post_processors`-ൽ, നിങ്ങൾക്ക് ഉപയോഗിക്കാവുന്ന വിവിധതരം `PostProcessor`-കൾ അടങ്ങിയിരിക്കുന്നു (പൂർണ്ണമായ ലിസ്‌റ്റ് [ഇവിടെ](https://huggingface.co/docs/tokenizers/api/post-processors)). +- `decoders`-ൽ, ടോക്കണൈസേഷന്റെ ഔട്ട്‌പുട്ടുകൾ ഡീകോഡ് ചെയ്യാൻ നിങ്ങൾക്ക് ഉപയോഗിക്കാവുന്ന വിവിധതരം `Decoder`-കൾ അടങ്ങിയിരിക്കുന്നു (പൂർണ്ണമായ ലിസ്‌റ്റ് [ഇവിടെ](https://huggingface.co/docs/tokenizers/components#decoders)). + +ബിൽഡിംഗ് ബ്ലോക്കുകളുടെ മുഴുവൻ ലിസ്‌റ്റും [ഇവിടെ](https://huggingface.co/docs/tokenizers/components) നിങ്ങൾക്ക് കാണാം. + +## ഒരു കോർപ്പസ് സ്വന്തമാക്കുന്നു[[acquiring-a-corpus]] + +നമ്മുടെ പുതിയ ടോക്കണൈസർ ട്രെയിൻ ചെയ്യാൻ, ഒരു ചെറിയ ടെക്‌സ്‌റ്റ് കോർപ്പസ് നമ്മൾ ഉപയോഗിക്കും (അങ്ങനെ ഉദാഹരണങ്ങൾ വേഗത്തിൽ റൺ ചെയ്യും). കോർപ്പസ് സ്വന്തമാക്കാനുള്ള ഘട്ടങ്ങൾ [ഈ അധ്യായത്തിന്റെ തുടക്കത്തിൽ](/course/chapter6/2) നമ്മൾ ചെയ്തതിന് സമാനമാണ്, എന്നാൽ ഇത്തവണ നമ്മൾ [WikiText-2](https://huggingface.co/datasets/wikitext) ഡേറ്റാസെറ്റ് ഉപയോഗിക്കും: + +```python +from datasets import load_dataset + +dataset = load_dataset("wikitext", name="wikitext-2-raw-v1", split="train") + + +def get_training_corpus(): + for i in range(0, len(dataset), 1000): + yield dataset[i : i + 1000]["text"] +``` + +`get_training_corpus()` എന്ന ഫംഗ്‌ഷൻ 1,000 ടെക്‌സ്‌റ്റുകൾ വീതമുള്ള ബാച്ചുകൾ യീൽഡ് ചെയ്യുന്ന (yield) ഒരു ജനറേറ്ററാണ് (generator); ടോക്കണൈസർ ട്രെയിൻ ചെയ്യാൻ നമ്മൾ ഇത് ഉപയോഗിക്കും. + +🤗 Tokenizers-ന് ടെക്‌സ്‌റ്റ് ഫയലുകളിൽ നേരിട്ടും ട്രെയിൻ ചെയ്യാൻ കഴിയും. WikiText-2-ലെ എല്ലാ ടെക്‌സ്‌റ്റുകളും/ഇൻപുട്ടുകളും അടങ്ങിയ, നമുക്ക് ലോക്കലായി ഉപയോഗിക്കാവുന്ന ഒരു ടെക്‌സ്‌റ്റ് ഫയൽ എങ്ങനെ ജനറേറ്റ് ചെയ്യാമെന്ന് ഇതാ: + +```python +with open("wikitext-2.txt", "w", encoding="utf-8") as f: + for i in range(len(dataset)): + f.write(dataset[i]["text"] + "\n") +``` + +അടുത്തതായി, നിങ്ങളുടെ സ്വന്തം BERT, GPT-2, XLNet ടോക്കണൈസറുകൾ ബ്ലോക്ക് ബ്ലോക്കായി എങ്ങനെ നിർമ്മിക്കാമെന്ന് ഞങ്ങൾ കാണിച്ചുതരും. അത് മൂന്ന് പ്രധാന ടോക്കണൈസേഷൻ അൽഗോരിതങ്ങളുടെയും — WordPiece, BPE, Unigram — ഓരോ ഉദാഹരണം നമുക്ക് നൽകും. BERT-ൽ നിന്ന് തുടങ്ങാം! + +## ഒരു WordPiece ടോക്കണൈസർ പൂജ്യത്തിൽ നിന്ന് നിർമ്മിക്കുന്നു[[building-a-wordpiece-tokenizer-from-scratch]] + +🤗 Tokenizers ലൈബ്രറി ഉപയോഗിച്ച് ഒരു ടോക്കണൈസർ നിർമ്മിക്കാൻ, ഒരു `model`-ഓടെ ഒരു `Tokenizer` ഒബ്‌ജക്റ്റ് ഇൻസ്‌റ്റാൻഷിയേറ്റ് ചെയ്യുന്നതിൽ നിന്ന് നമ്മൾ തുടങ്ങുന്നു; തുടർന്ന് അതിന്റെ `normalizer`, `pre_tokenizer`, `post_processor`, `decoder` ആട്രിബ്യൂട്ടുകൾ നമുക്ക് വേണ്ട മൂല്യങ്ങളായി സെറ്റ് ചെയ്യുന്നു. + +ഈ ഉദാഹരണത്തിനായി, ഒരു WordPiece മോഡലോടുകൂടിയ ഒരു `Tokenizer` നമ്മൾ സൃഷ്ടിക്കും: + +```python +from tokenizers import ( + decoders, + models, + normalizers, + pre_tokenizers, + processors, + trainers, + Tokenizer, +) + +tokenizer = Tokenizer(models.WordPiece(unk_token="[UNK]")) +``` + +മുമ്പ് കണ്ടിട്ടില്ലാത്ത അക്ഷരങ്ങൾ (characters) കണ്ടുമുട്ടുമ്പോൾ എന്ത് റിട്ടേൺ ചെയ്യണമെന്ന് മോഡലിന് അറിയാൻ നമ്മൾ `unk_token` നിർദ്ദേശിക്കണം. ഇവിടെ നമുക്ക് സെറ്റ് ചെയ്യാവുന്ന മറ്റ് ആർഗ്യുമെന്റുകളിൽ നമ്മുടെ മോഡലിന്റെ `vocab`-ഉം (നമ്മൾ മോഡൽ ട്രെയിൻ ചെയ്യാൻ പോകുന്നതിനാൽ ഇത് സെറ്റ് ചെയ്യേണ്ടതില്ല), ഓരോ വാക്കിന്റെയും പരമാവധി ദൈർഘ്യം നിർദ്ദേശിക്കുന്ന `max_input_chars_per_word`-ഉം ഉൾപ്പെടുന്നു (നൽകിയ മൂല്യത്തെക്കാൾ നീളമുള്ള വാക്കുകൾ വിഭജിക്കപ്പെടും). + +ടോക്കണൈസേഷന്റെ ആദ്യ ഘട്ടം നോർമലൈസേഷനാണ്, അതിനാൽ അതിൽ നിന്ന് തുടങ്ങാം. BERT വ്യാപകമായി ഉപയോഗിക്കപ്പെടുന്നതിനാൽ, BERT-നായി നമുക്ക് സെറ്റ് ചെയ്യാവുന്ന ക്ലാസിക് ഓപ്‌ഷനുകളോടുകൂടിയ ഒരു `BertNormalizer` ലഭ്യമാണ്: പേരിൽ നിന്നുതന്നെ അർത്ഥം വ്യക്തമാകുന്ന `lowercase`, `strip_accents`; എല്ലാ കൺട്രോൾ കാരക്ടറുകളും നീക്കം ചെയ്യാനും ആവർത്തിക്കുന്ന സ്‌പേസുകളെ ഒറ്റ സ്‌പേസാക്കി മാറ്റാനുമുള്ള `clean_text`; ചൈനീസ് അക്ഷരങ്ങൾക്ക് ചുറ്റും സ്‌പേസുകൾ ഇടുന്ന `handle_chinese_chars`. `bert-base-uncased` ടോക്കണൈസർ പുനഃസൃഷ്ടിക്കാൻ, ഈ നോർമലൈസർ സെറ്റ് ചെയ്താൽ മാത്രം മതി: + +```python +tokenizer.normalizer = normalizers.BertNormalizer(lowercase=True) +``` + +എന്നാൽ പൊതുവേ പറഞ്ഞാൽ, ഒരു പുതിയ ടോക്കണൈസർ നിർമ്മിക്കുമ്പോൾ ഇത്രയും സൗകര്യപ്രദമായ, 🤗 Tokenizers ലൈബ്രറിയിൽ ഇതിനകം ഇംപ്ലിമെന്റ് ചെയ്തിട്ടുള്ള ഒരു നോർമലൈസർ നിങ്ങൾക്ക് ലഭ്യമാകണമെന്നില്ല -- അതിനാൽ BERT നോർമലൈസർ സ്വന്തമായി (by hand) എങ്ങനെ സൃഷ്ടിക്കാമെന്ന് നോക്കാം. ലൈബ്രറി ഒരു `Lowercase` നോർമലൈസറും ഒരു `StripAccents` നോർമലൈസറും നൽകുന്നു, കൂടാതെ ഒരു `Sequence` ഉപയോഗിച്ച് പല നോർമലൈസറുകൾ നിങ്ങൾക്ക് കൂട്ടിച്ചേർക്കാം (compose): + +```python +tokenizer.normalizer = normalizers.Sequence( + [normalizers.NFD(), normalizers.Lowercase(), normalizers.StripAccents()] +) +``` + +ഒരു `NFD` യൂണികോഡ് നോർമലൈസറും നമ്മൾ ഉപയോഗിക്കുന്നുണ്ട്; അല്ലാത്തപക്ഷം `StripAccents` നോർമലൈസർ ആക്‌സന്റുള്ള അക്ഷരങ്ങളെ ശരിയായി തിരിച്ചറിയില്ല, അതിനാൽ അവയെ നീക്കം ചെയ്യുകയുമില്ല. + +നമ്മൾ മുമ്പ് കണ്ടതുപോലെ, നൽകിയ ഒരു ടെക്‌സ്‌റ്റിൽ അത് ഉണ്ടാക്കുന്ന മാറ്റങ്ങൾ പരിശോധിക്കാൻ `normalizer`-ന്റെ `normalize_str()` മെത്തേഡ് നമുക്ക് ഉപയോഗിക്കാം: + +```python +print(tokenizer.normalizer.normalize_str("Héllò hôw are ü?")) +``` + +```python out +hello how are u? +``` + +> [!TIP] +> **കൂടുതൽ മുന്നോട്ട് പോകാൻ** യൂണികോഡ് കാരക്ടർ `u"\u0085"` അടങ്ങിയ ഒരു സ്‌ട്രിംഗിൽ മുൻപറഞ്ഞ നോർമലൈസറുകളുടെ രണ്ട് പതിപ്പുകളും നിങ്ങൾ പരീക്ഷിച്ചാൽ, ഈ രണ്ട് നോർമലൈസറുകളും കൃത്യമായി തുല്യമല്ലെന്ന് നിങ്ങൾ തീർച്ചയായും ശ്രദ്ധിക്കും. +> `normalizers.Sequence` ഉപയോഗിച്ചുള്ള പതിപ്പ് അമിതമായി സങ്കീർണ്ണമാക്കാതിരിക്കാൻ, `clean_text` ആർഗ്യുമെന്റ് `True` ആയി സെറ്റ് ചെയ്യുമ്പോൾ `BertNormalizer`-ന് ആവശ്യമായ Regex റീപ്ലേസ്‌മെന്റുകൾ നമ്മൾ ഉൾപ്പെടുത്തിയിട്ടില്ല - അതാണ് ഡിഫോൾട്ട് സ്വഭാവം. എന്നാൽ വിഷമിക്കേണ്ട: നോർമലൈസർ സീക്വൻസിലേക്ക് രണ്ട് `normalizers.Replace`-കൾ ചേർത്തുകൊണ്ട്, സൗകര്യപ്രദമായ `BertNormalizer` ഉപയോഗിക്കാതെതന്നെ കൃത്യമായി അതേ നോർമലൈസേഷൻ നേടാൻ സാധിക്കും. + +അടുത്തത് പ്രീ-ടോക്കണൈസേഷൻ ഘട്ടമാണ്. ഇവിടെയും, നമുക്ക് ഉപയോഗിക്കാവുന്ന ഒരു മുൻകൂട്ടി നിർമ്മിച്ച `BertPreTokenizer` ഉണ്ട്: + +```python +tokenizer.pre_tokenizer = pre_tokenizers.BertPreTokenizer() +``` + +അല്ലെങ്കിൽ നമുക്ക് അത് പൂജ്യത്തിൽ നിന്ന് നിർമ്മിക്കാം: + +```python +tokenizer.pre_tokenizer = pre_tokenizers.Whitespace() +``` + +`Whitespace` പ്രീ-ടോക്കണൈസർ വൈറ്റ്‌സ്‌പേസിലും, അക്ഷരങ്ങളോ അക്കങ്ങളോ അണ്ടർസ്‌കോർ കാരക്ടറോ അല്ലാത്ത എല്ലാ കാരക്ടറുകളിലും വിഭജിക്കുന്നു എന്നത് ശ്രദ്ധിക്കുക; അതിനാൽ സാങ്കേതികമായി അത് വൈറ്റ്‌സ്‌പേസിലും ചിഹ്നങ്ങളിലും (punctuation) വിഭജിക്കുന്നു: + +```python +tokenizer.pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") +``` + +```python out +[('Let', (0, 3)), ("'", (3, 4)), ('s', (4, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre', (14, 17)), + ('-', (17, 18)), ('tokenizer', (18, 27)), ('.', (27, 28))] +``` + +നിങ്ങൾക്ക് വൈറ്റ്‌സ്‌പേസിൽ മാത്രം വിഭജിക്കണമെങ്കിൽ, പകരം `WhitespaceSplit` പ്രീ-ടോക്കണൈസർ ഉപയോഗിക്കണം: + +```python +pre_tokenizer = pre_tokenizers.WhitespaceSplit() +pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") +``` + +```python out +[("Let's", (0, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre-tokenizer.', (14, 28))] +``` + +നോർമലൈസറുകളുടെ കാര്യത്തിലെന്നപോലെ, പല പ്രീ-ടോക്കണൈസറുകൾ കൂട്ടിച്ചേർക്കാൻ നിങ്ങൾക്ക് ഒരു `Sequence` ഉപയോഗിക്കാം: + +```python +pre_tokenizer = pre_tokenizers.Sequence( + [pre_tokenizers.WhitespaceSplit(), pre_tokenizers.Punctuation()] +) +pre_tokenizer.pre_tokenize_str("Let's test my pre-tokenizer.") +``` + +```python out +[('Let', (0, 3)), ("'", (3, 4)), ('s', (4, 5)), ('test', (6, 10)), ('my', (11, 13)), ('pre', (14, 17)), + ('-', (17, 18)), ('tokenizer', (18, 27)), ('.', (27, 28))] +``` + +ടോക്കണൈസേഷൻ പൈപ്പ്‌ലൈനിലെ അടുത്ത ഘട്ടം ഇൻപുട്ടുകൾ മോഡലിലൂടെ കടത്തിവിടുകയാണ്. ഇനിഷ്യലൈസേഷനിൽ നമ്മുടെ മോഡൽ നമ്മൾ ഇതിനകം നിർദ്ദേശിച്ചിട്ടുണ്ട്, എന്നാൽ അത് ഇനിയും ട്രെയിൻ ചെയ്യേണ്ടതുണ്ട്; അതിന് ഒരു `WordPieceTrainer` ആവശ്യമാണ്. 🤗 Tokenizers-ൽ ഒരു ട്രെയിനർ ഇൻസ്‌റ്റാൻഷിയേറ്റ് ചെയ്യുമ്പോൾ ഓർക്കേണ്ട പ്രധാന കാര്യം, നിങ്ങൾ ഉപയോഗിക്കാൻ ഉദ്ദേശിക്കുന്ന എല്ലാ പ്രത്യേക ടോക്കണുകളും അതിന് നൽകണം എന്നതാണ് -- അല്ലാത്തപക്ഷം, അവ ട്രെയിനിംഗ് കോർപ്പസിൽ ഇല്ലാത്തതിനാൽ അത് അവയെ വൊക്കാബുലറിയിൽ ചേർക്കില്ല: + +```python +special_tokens = ["[UNK]", "[PAD]", "[CLS]", "[SEP]", "[MASK]"] +trainer = trainers.WordPieceTrainer(vocab_size=25000, special_tokens=special_tokens) +``` + +`vocab_size`-ഉം `special_tokens`-ഉം നിർദ്ദേശിക്കുന്നതിനൊപ്പം, `min_frequency` (വൊക്കാബുലറിയിൽ ഉൾപ്പെടാൻ ഒരു ടോക്കൺ എത്ര തവണ പ്രത്യക്ഷപ്പെടണം എന്നത്) സെറ്റ് ചെയ്യാനോ `continuing_subword_prefix` മാറ്റാനോ (`##`-ൽ നിന്ന് വ്യത്യസ്തമായ എന്തെങ്കിലും ഉപയോഗിക്കണമെങ്കിൽ) നമുക്ക് കഴിയും. + +നമ്മൾ മുമ്പ് നിർവചിച്ച ഇറ്ററേറ്റർ ഉപയോഗിച്ച് നമ്മുടെ മോഡൽ ട്രെയിൻ ചെയ്യാൻ, ഈ കമാൻഡ് എക്‌സിക്യൂട്ട് ചെയ്താൽ മാത്രം മതി: + +```python +tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer) +``` + +നമ്മുടെ ടോക്കണൈസർ ട്രെയിൻ ചെയ്യാൻ ടെക്‌സ്‌റ്റ് ഫയലുകളും നമുക്ക് ഉപയോഗിക്കാം; അത് ഇങ്ങനെയായിരിക്കും (അതിനുമുമ്പ് ഒരു ശൂന്യമായ `WordPiece` ഉപയോഗിച്ച് മോഡൽ നമ്മൾ വീണ്ടും ഇനിഷ്യലൈസ് ചെയ്യുന്നു): + +```python +tokenizer.model = models.WordPiece(unk_token="[UNK]") +tokenizer.train(["wikitext-2.txt"], trainer=trainer) +``` + +രണ്ട് സാഹചര്യങ്ങളിലും, തുടർന്ന് `encode()` മെത്തേഡ് വിളിച്ചുകൊണ്ട് ഒരു ടെക്‌സ്‌റ്റിൽ ടോക്കണൈസർ നമുക്ക് പരീക്ഷിക്കാം: + +```python +encoding = tokenizer.encode("Let's test this tokenizer.") +print(encoding.tokens) +``` + +```python out +['let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '.'] +``` + +ലഭിച്ച `encoding` ഒരു `Encoding` ആണ്; ടോക്കണൈസറിന്റെ ആവശ്യമായ എല്ലാ ഔട്ട്‌പുട്ടുകളും അതിന്റെ വിവിധ ആട്രിബ്യൂട്ടുകളിൽ ഇത് ഉൾക്കൊള്ളുന്നു: `ids`, `type_ids`, `tokens`, `offsets`, `attention_mask`, `special_tokens_mask`, `overflowing`. + +ടോക്കണൈസേഷൻ പൈപ്പ്‌ലൈനിലെ അവസാന ഘട്ടം പോസ്‌റ്റ്-പ്രോസസ്സിംഗ് ആണ്. തുടക്കത്തിൽ `[CLS]` ടോക്കണും അവസാനത്തിൽ (അല്ലെങ്കിൽ ഒരു വാക്യജോഡിയാണെങ്കിൽ ഓരോ വാക്യത്തിനും ശേഷം) `[SEP]` ടോക്കണും നമ്മൾ ചേർക്കണം. ഇതിനായി ഒരു `TemplateProcessor` നമ്മൾ ഉപയോഗിക്കും, എന്നാൽ ആദ്യം വൊക്കാബുലറിയിലെ `[CLS]`, `[SEP]` ടോക്കണുകളുടെ ID-കൾ നമുക്ക് അറിയേണ്ടതുണ്ട്: + +```python +cls_token_id = tokenizer.token_to_id("[CLS]") +sep_token_id = tokenizer.token_to_id("[SEP]") +print(cls_token_id, sep_token_id) +``` + +```python out +(2, 3) +``` + +`TemplateProcessor`-നുള്ള ടെംപ്ലേറ്റ് എഴുതാൻ, ഒരൊറ്റ വാക്യത്തെയും ഒരു വാക്യജോഡിയെയും എങ്ങനെ കൈകാര്യം ചെയ്യണമെന്ന് നമ്മൾ നിർദ്ദേശിക്കണം. രണ്ടിനും, നമ്മൾ ഉപയോഗിക്കാൻ ആഗ്രഹിക്കുന്ന പ്രത്യേക ടോക്കണുകൾ എഴുതുന്നു; ആദ്യത്തെ (അല്ലെങ്കിൽ ഒറ്റ) വാക്യത്തെ `$A` പ്രതിനിധീകരിക്കുന്നു, രണ്ടാമത്തെ വാക്യത്തെ (ഒരു ജോഡി എൻകോഡ് ചെയ്യുകയാണെങ്കിൽ) `$B` പ്രതിനിധീകരിക്കുന്നു. ഇവയിൽ ഓരോന്നിനും (പ്രത്യേക ടോക്കണുകൾക്കും വാക്യങ്ങൾക്കും), ഒരു കോളനുശേഷം (colon) അനുബന്ധ ടോക്കൺ ടൈപ്പ് ID-യും നമ്മൾ നിർദ്ദേശിക്കുന്നു. + +അങ്ങനെ, ക്ലാസിക് BERT ടെംപ്ലേറ്റ് ഇനിപ്പറയുന്ന രീതിയിൽ നിർവചിക്കപ്പെടുന്നു: + +```python +tokenizer.post_processor = processors.TemplateProcessing( + single=f"[CLS]:0 $A:0 [SEP]:0", + pair=f"[CLS]:0 $A:0 [SEP]:0 $B:1 [SEP]:1", + special_tokens=[("[CLS]", cls_token_id), ("[SEP]", sep_token_id)], +) +``` + +പ്രത്യേക ടോക്കണുകളുടെ ID-കൾ നമ്മൾ കൈമാറേണ്ടതുണ്ട് എന്നത് ശ്രദ്ധിക്കുക; അങ്ങനെയാണ് ടോക്കണൈസറിന് അവയെ ശരിയായി അവയുടെ ID-കളാക്കി മാറ്റാൻ കഴിയുന്നത്. + +ഇത് ചേർത്തുകഴിഞ്ഞാൽ, നമ്മുടെ മുൻ ഉദാഹരണത്തിലേക്ക് തിരികെ പോയാൽ ഇതായിരിക്കും ഫലം: + +```python +encoding = tokenizer.encode("Let's test this tokenizer.") +print(encoding.tokens) +``` + +```python out +['[CLS]', 'let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '.', '[SEP]'] +``` + +ഒരു വാക്യജോഡിയിലും നമുക്ക് ശരിയായ ഫലം ലഭിക്കുന്നു: + +```python +encoding = tokenizer.encode("Let's test this tokenizer...", "on a pair of sentences.") +print(encoding.tokens) +print(encoding.type_ids) +``` + +```python out +['[CLS]', 'let', "'", 's', 'test', 'this', 'tok', '##eni', '##zer', '...', '[SEP]', 'on', 'a', 'pair', 'of', 'sentences', '.', '[SEP]'] +[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1] +``` + +ഈ ടോക്കണൈസർ പൂജ്യത്തിൽ നിന്ന് നിർമ്മിക്കുന്നത് നമ്മൾ ഏതാണ്ട് പൂർത്തിയാക്കി -- അവസാന ഘട്ടം ഒരു ഡീകോഡർ ഉൾപ്പെടുത്തുകയാണ്: + +```python +tokenizer.decoder = decoders.WordPiece(prefix="##") +``` + +നമ്മുടെ മുൻ `encoding`-ൽ ഇത് പരീക്ഷിക്കാം: + +```python +tokenizer.decode(encoding.ids) +``` + +```python out +"let's test this tokenizer... on a pair of sentences." +``` + +കൊള്ളാം! നമ്മുടെ ടോക്കണൈസർ ഒരൊറ്റ JSON ഫയലിൽ ഇങ്ങനെ സേവ് ചെയ്യാം: + +```python +tokenizer.save("tokenizer.json") +``` + +തുടർന്ന്, `from_file()` മെത്തേഡ് ഉപയോഗിച്ച് ആ ഫയൽ ഒരു `Tokenizer` ഒബ്‌ജക്റ്റിലേക്ക് നമുക്ക് വീണ്ടും ലോഡ് ചെയ്യാം: + +```python +new_tokenizer = Tokenizer.from_file("tokenizer.json") +``` + +ഈ ടോക്കണൈസർ 🤗 Transformers-ൽ ഉപയോഗിക്കാൻ, അതിനെ ഒരു `PreTrainedTokenizerFast`-ൽ പൊതിയേണ്ടതുണ്ട് (wrap). നമുക്ക് ഒന്നുകിൽ ജനറിക് ക്ലാസ് ഉപയോഗിക്കാം, അല്ലെങ്കിൽ നമ്മുടെ ടോക്കണൈസർ നിലവിലുള്ള ഒരു മോഡലിനോട് യോജിക്കുന്നതാണെങ്കിൽ ആ ക്ലാസ് ഉപയോഗിക്കാം (ഇവിടെ, `BertTokenizerFast`). തീർത്തും പുതിയൊരു ടോക്കണൈസർ നിർമ്മിക്കാൻ നിങ്ങൾ ഈ പാഠം പ്രയോഗിക്കുകയാണെങ്കിൽ, ആദ്യത്തെ ഓപ്‌ഷൻ നിങ്ങൾ ഉപയോഗിക്കേണ്ടിവരും. + +ടോക്കണൈസറിനെ ഒരു `PreTrainedTokenizerFast`-ൽ പൊതിയാൻ, നമ്മൾ നിർമ്മിച്ച ടോക്കണൈസർ `tokenizer_object` ആയി നൽകുകയോ, നമ്മൾ സേവ് ചെയ്ത ടോക്കണൈസർ ഫയൽ `tokenizer_file` ആയി നൽകുകയോ ചെയ്യാം. ഓർക്കേണ്ട പ്രധാന കാര്യം, എല്ലാ പ്രത്യേക ടോക്കണുകളും നമ്മൾ സ്വയം (manually) സെറ്റ് ചെയ്യണം എന്നതാണ്; കാരണം ഏത് ടോക്കണാണ് മാസ്‌ക് ടോക്കൺ, ഏതാണ് `[CLS]` ടോക്കൺ എന്നിങ്ങനെയുള്ള കാര്യങ്ങൾ `tokenizer` ഒബ്‌ജക്റ്റിൽ നിന്ന് ഊഹിച്ചെടുക്കാൻ ആ ക്ലാസിന് കഴിയില്ല: + +```python +from transformers import PreTrainedTokenizerFast + +wrapped_tokenizer = PreTrainedTokenizerFast( + tokenizer_object=tokenizer, + # tokenizer_file="tokenizer.json", # You can load from the tokenizer file, alternatively + unk_token="[UNK]", + pad_token="[PAD]", + cls_token="[CLS]", + sep_token="[SEP]", + mask_token="[MASK]", +) +``` + +നിങ്ങൾ ഒരു നിശ്ചിത ടോക്കണൈസർ ക്ലാസ് (`BertTokenizerFast` പോലെ) ഉപയോഗിക്കുകയാണെങ്കിൽ, ഡിഫോൾട്ടുകളിൽ നിന്ന് വ്യത്യസ്തമായ പ്രത്യേക ടോക്കണുകൾ മാത്രം നിർദ്ദേശിച്ചാൽ മതി (ഇവിടെ, ഒന്നുമില്ല): + +```python +from transformers import BertTokenizerFast + +wrapped_tokenizer = BertTokenizerFast(tokenizer_object=tokenizer) +``` + +തുടർന്ന് മറ്റേതൊരു 🤗 Transformers ടോക്കണൈസറിനെയും പോലെ ഈ ടോക്കണൈസർ നിങ്ങൾക്ക് ഉപയോഗിക്കാം. `save_pretrained()` മെത്തേഡ് ഉപയോഗിച്ച് ഇത് സേവ് ചെയ്യാം, അല്ലെങ്കിൽ `push_to_hub()` മെത്തേഡ് ഉപയോഗിച്ച് Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യാം. + +ഒരു WordPiece ടോക്കണൈസർ എങ്ങനെ നിർമ്മിക്കാമെന്ന് നമ്മൾ കണ്ടുകഴിഞ്ഞു; ഇനി ഒരു BPE ടോക്കണൈസറിനും അതുതന്നെ ചെയ്യാം. എല്ലാ ഘട്ടങ്ങളും നിങ്ങൾക്ക് അറിയാവുന്നതിനാൽ നമ്മൾ കുറച്ചുകൂടി വേഗത്തിൽ പോകും, വ്യത്യാസങ്ങൾ മാത്രം എടുത്തുകാണിക്കും. + +## ഒരു BPE ടോക്കണൈസർ പൂജ്യത്തിൽ നിന്ന് നിർമ്മിക്കുന്നു[[building-a-bpe-tokenizer-from-scratch]] + +ഇനി നമുക്ക് ഒരു GPT-2 ടോക്കണൈസർ നിർമ്മിക്കാം. BERT ടോക്കണൈസറിന്റെ കാര്യത്തിലെന്നപോലെ, ഒരു BPE മോഡലോടെ ഒരു `Tokenizer` ഇനിഷ്യലൈസ് ചെയ്യുന്നതിൽ നിന്ന് നമ്മൾ തുടങ്ങുന്നു: + +```python +tokenizer = Tokenizer(models.BPE()) +``` + +BERT-ന്റെ കാര്യത്തിലെന്നപോലെ, നമ്മുടെ കൈയിൽ ഒരു വൊക്കാബുലറി ഉണ്ടായിരുന്നെങ്കിൽ അതുപയോഗിച്ച് ഈ മോഡൽ ഇനിഷ്യലൈസ് ചെയ്യാമായിരുന്നു (ആ സാഹചര്യത്തിൽ `vocab`-ഉം `merges`-ഉം നമ്മൾ നൽകേണ്ടിവരും), എന്നാൽ നമ്മൾ പൂജ്യത്തിൽ നിന്ന് ട്രെയിൻ ചെയ്യാൻ പോകുന്നതിനാൽ അത് ചെയ്യേണ്ടതില്ല. ഒരു `unk_token` നിർദ്ദേശിക്കേണ്ട ആവശ്യവുമില്ല, കാരണം GPT-2 ബൈറ്റ്-ലെവൽ BPE ഉപയോഗിക്കുന്നു, അതിന് അത് ആവശ്യമില്ല. + +GPT-2 ഒരു നോർമലൈസർ ഉപയോഗിക്കുന്നില്ല, അതിനാൽ ആ ഘട്ടം ഒഴിവാക്കി നേരിട്ട് പ്രീ-ടോക്കണൈസേഷനിലേക്ക് പോകാം: + +```python +tokenizer.pre_tokenizer = pre_tokenizers.ByteLevel(add_prefix_space=False) +``` + +ഇവിടെ `ByteLevel`-ന് നമ്മൾ ചേർത്ത ഓപ്‌ഷൻ, ഒരു വാക്യത്തിന്റെ തുടക്കത്തിൽ സ്‌പേസ് ചേർക്കാതിരിക്കാനുള്ളതാണ് (അല്ലാത്തപക്ഷം അതാണ് ഡിഫോൾട്ട്). മുമ്പത്തെപ്പോലെ ഒരു ഉദാഹരണ ടെക്‌സ്‌റ്റിന്റെ പ്രീ-ടോക്കണൈസേഷൻ നമുക്ക് നോക്കാം: + +```python +tokenizer.pre_tokenizer.pre_tokenize_str("Let's test pre-tokenization!") +``` + +```python out +[('Let', (0, 3)), ("'s", (3, 5)), ('Ġtest', (5, 10)), ('Ġpre', (10, 14)), ('-', (14, 15)), + ('tokenization', (15, 27)), ('!', (27, 28))] +``` + +അടുത്തത് മോഡലാണ്, അതിന് ട്രെയിനിംഗ് ആവശ്യമാണ്. GPT-2-ന്, ഒരേയൊരു പ്രത്യേക ടോക്കൺ end-of-text ടോക്കണാണ്: + +```python +trainer = trainers.BpeTrainer(vocab_size=25000, special_tokens=["<|endoftext|>"]) +tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer) +``` + +`WordPieceTrainer`-ന്റെ കാര്യത്തിലെന്നപോലെ, `vocab_size`-ഉം `special_tokens`-ഉം കൂടാതെ, വേണമെങ്കിൽ `min_frequency` നമുക്ക് നിർദ്ദേശിക്കാം; അല്ലെങ്കിൽ ഒരു end-of-word സഫിക്‌സ് (`` പോലെ) ഉണ്ടെങ്കിൽ, അത് `end_of_word_suffix` ഉപയോഗിച്ച് സെറ്റ് ചെയ്യാം. + +ഈ ടോക്കണൈസറും ടെക്‌സ്‌റ്റ് ഫയലുകളിൽ ട്രെയിൻ ചെയ്യാം: + +```python +tokenizer.model = models.BPE() +tokenizer.train(["wikitext-2.txt"], trainer=trainer) +``` + +ഒരു സാമ്പിൾ ടെക്‌സ്‌റ്റിന്റെ ടോക്കണൈസേഷൻ നമുക്ക് നോക്കാം: + +```python +encoding = tokenizer.encode("Let's test this tokenizer.") +print(encoding.tokens) +``` + +```python out +['L', 'et', "'", 's', 'Ġtest', 'Ġthis', 'Ġto', 'ken', 'izer', '.'] +``` + +GPT-2 ടോക്കണൈസറിനുള്ള ബൈറ്റ്-ലെവൽ പോസ്‌റ്റ്-പ്രോസസ്സിംഗ് നമ്മൾ ഇനിപ്പറയുന്ന രീതിയിൽ പ്രയോഗിക്കുന്നു: + +```python +tokenizer.post_processor = processors.ByteLevel(trim_offsets=False) +``` + +`trim_offsets = False` ഓപ്‌ഷൻ, 'Ġ'-യിൽ തുടങ്ങുന്ന ടോക്കണുകളുടെ ഓഫ്‌സെറ്റുകൾ (offsets) അതേപടി വിടണമെന്ന് പോസ്‌റ്റ്-പ്രോസസറിനോട് പറയുന്നു: ഇങ്ങനെ ചെയ്യുമ്പോൾ ഓഫ്‌സെറ്റുകളുടെ തുടക്കം വാക്കിന്റെ ആദ്യ അക്ഷരത്തിലേക്കല്ല, വാക്കിന് മുമ്പുള്ള സ്‌പേസിലേക്കാണ് ചൂണ്ടുന്നത് (കാരണം സാങ്കേതികമായി സ്‌പേസ് ടോക്കണിന്റെ ഭാഗമാണ്). നമ്മൾ ഇപ്പോൾ എൻകോഡ് ചെയ്ത ടെക്‌സ്‌റ്റ് ഉപയോഗിച്ച് ഫലം നോക്കാം; ഇവിടെ `'Ġtest'` എന്നത് ഇൻഡെക്‌സ് 4-ലെ ടോക്കണാണ്: + +```python +sentence = "Let's test this tokenizer." +encoding = tokenizer.encode(sentence) +start, end = encoding.offsets[4] +sentence[start:end] +``` + +```python out +' test' +``` + +അവസാനമായി, ഒരു ബൈറ്റ്-ലെവൽ ഡീകോഡർ നമ്മൾ ചേർക്കുന്നു: + +```python +tokenizer.decoder = decoders.ByteLevel() +``` + +അത് ശരിയായി പ്രവർത്തിക്കുന്നുണ്ടെന്ന് നമുക്ക് ഒന്നുകൂടി ഉറപ്പുവരുത്താം: + +```python +tokenizer.decode(encoding.ids) +``` + +```python out +"Let's test this tokenizer." +``` + +കൊള്ളാം! ഇപ്പോൾ പൂർത്തിയായതിനാൽ, മുമ്പത്തെപ്പോലെ ടോക്കണൈസർ സേവ് ചെയ്യാം, കൂടാതെ 🤗 Transformers-ൽ ഉപയോഗിക്കണമെങ്കിൽ ഒരു `PreTrainedTokenizerFast`-ലോ `GPT2TokenizerFast`-ലോ പൊതിയാം: + +```python +from transformers import PreTrainedTokenizerFast + +wrapped_tokenizer = PreTrainedTokenizerFast( + tokenizer_object=tokenizer, + bos_token="<|endoftext|>", + eos_token="<|endoftext|>", +) +``` + +അല്ലെങ്കിൽ: + +```python +from transformers import GPT2TokenizerFast + +wrapped_tokenizer = GPT2TokenizerFast(tokenizer_object=tokenizer) +``` + +അവസാന ഉദാഹരണമായി, ഒരു Unigram ടോക്കണൈസർ പൂജ്യത്തിൽ നിന്ന് എങ്ങനെ നിർമ്മിക്കാമെന്ന് ഞങ്ങൾ കാണിച്ചുതരും. + +## ഒരു Unigram ടോക്കണൈസർ പൂജ്യത്തിൽ നിന്ന് നിർമ്മിക്കുന്നു[[building-a-unigram-tokenizer-from-scratch]] + +ഇനി നമുക്ക് ഒരു XLNet ടോക്കണൈസർ നിർമ്മിക്കാം. മുൻ ടോക്കണൈസറുകളുടെ കാര്യത്തിലെന്നപോലെ, ഒരു Unigram മോഡലോടെ ഒരു `Tokenizer` ഇനിഷ്യലൈസ് ചെയ്യുന്നതിൽ നിന്ന് നമ്മൾ തുടങ്ങുന്നു: + +```python +tokenizer = Tokenizer(models.Unigram()) +``` + +ഇവിടെയും, നമ്മുടെ കൈയിൽ ഒരു വൊക്കാബുലറി ഉണ്ടായിരുന്നെങ്കിൽ അതുപയോഗിച്ച് ഈ മോഡൽ ഇനിഷ്യലൈസ് ചെയ്യാമായിരുന്നു. + +നോർമലൈസേഷനായി, XLNet ഏതാനും റീപ്ലേസ്‌മെന്റുകൾ ഉപയോഗിക്കുന്നു (ഇവ SentencePiece-ൽ നിന്ന് വരുന്നവയാണ്): + +```python +from tokenizers import Regex + +tokenizer.normalizer = normalizers.Sequence( + [ + normalizers.Replace("``", '"'), + normalizers.Replace("''", '"'), + normalizers.NFKD(), + normalizers.StripAccents(), + normalizers.Replace(Regex(" {2,}"), " "), + ] +) +``` + +ഇത് ``, '' എന്നിവയെ " ആക്കിയും, രണ്ടോ അതിലധികമോ സ്‌പേസുകളുടെ ഏത് സീക്വൻസിനെയും ഒറ്റ സ്‌പേസാക്കിയും മാറ്റുന്നു; കൂടാതെ ടോക്കണൈസ് ചെയ്യേണ്ട ടെക്‌സ്‌റ്റുകളിലെ ആക്‌സന്റുകൾ നീക്കം ചെയ്യുകയും ചെയ്യുന്നു. + +ഏതൊരു SentencePiece ടോക്കണൈസറിനും ഉപയോഗിക്കേണ്ട പ്രീ-ടോക്കണൈസർ `Metaspace` ആണ്: + +```python +tokenizer.pre_tokenizer = pre_tokenizers.Metaspace() +``` + +മുമ്പത്തെപ്പോലെ ഒരു ഉദാഹരണ ടെക്‌സ്‌റ്റിന്റെ പ്രീ-ടോക്കണൈസേഷൻ നമുക്ക് നോക്കാം: + +```python +tokenizer.pre_tokenizer.pre_tokenize_str("Let's test the pre-tokenizer!") +``` + +```python out +[("▁Let's", (0, 5)), ('▁test', (5, 10)), ('▁the', (10, 14)), ('▁pre-tokenizer!', (14, 29))] +``` + +അടുത്തത് മോഡലാണ്, അതിന് ട്രെയിനിംഗ് ആവശ്യമാണ്. XLNet-ന് കുറച്ചധികം പ്രത്യേക ടോക്കണുകളുണ്ട്: + +```python +special_tokens = ["", "", "", "", "", "", ""] +trainer = trainers.UnigramTrainer( + vocab_size=25000, special_tokens=special_tokens, unk_token="" +) +tokenizer.train_from_iterator(get_training_corpus(), trainer=trainer) +``` + +`UnigramTrainer`-ന് മറക്കാൻ പാടില്ലാത്ത വളരെ പ്രധാനപ്പെട്ട ഒരു ആർഗ്യുമെന്റാണ് `unk_token`. Unigram അൽഗോരിതത്തിന് പ്രത്യേകമായ മറ്റ് ആർഗ്യുമെന്റുകളും നമുക്ക് നൽകാം; ഉദാഹരണത്തിന്, ടോക്കണുകൾ നീക്കം ചെയ്യുന്ന ഓരോ ഘട്ടത്തിനുമുള്ള `shrinking_factor` (ഡിഫോൾട്ട് 0.75) അല്ലെങ്കിൽ ഒരു ടോക്കണിന്റെ പരമാവധി ദൈർഘ്യം നിർദ്ദേശിക്കാനുള്ള `max_piece_length` (ഡിഫോൾട്ട് 16). + +ഈ ടോക്കണൈസറും ടെക്‌സ്‌റ്റ് ഫയലുകളിൽ ട്രെയിൻ ചെയ്യാം: + +```python +tokenizer.model = models.Unigram() +tokenizer.train(["wikitext-2.txt"], trainer=trainer) +``` + +ഒരു സാമ്പിൾ ടെക്‌സ്‌റ്റിന്റെ ടോക്കണൈസേഷൻ നമുക്ക് നോക്കാം: + +```python +encoding = tokenizer.encode("Let's test this tokenizer.") +print(encoding.tokens) +``` + +```python out +['▁Let', "'", 's', '▁test', '▁this', '▁to', 'ken', 'izer', '.'] +``` + +XLNet-ന്റെ ഒരു സവിശേഷത, അത് `` ടോക്കൺ വാക്യത്തിന്റെ അവസാനത്തിൽ, 2 എന്ന ടൈപ്പ് ID-യോടെ (മറ്റ് ടോക്കണുകളിൽ നിന്ന് വേർതിരിക്കാൻ) വയ്ക്കുന്നു എന്നതാണ്. അതിന്റെ ഫലമായി, പാഡിംഗ് ഇടതുവശത്താണ്. BERT-ന്റെ കാര്യത്തിലെന്നപോലെ, എല്ലാ പ്രത്യേക ടോക്കണുകളും ടോക്കൺ ടൈപ്പ് ID-കളും ഒരു ടെംപ്ലേറ്റ് ഉപയോഗിച്ച് നമുക്ക് കൈകാര്യം ചെയ്യാം, എന്നാൽ ആദ്യം ``, `` ടോക്കണുകളുടെ ID-കൾ നമ്മൾ നേടണം: + +```python +cls_token_id = tokenizer.token_to_id("") +sep_token_id = tokenizer.token_to_id("") +print(cls_token_id, sep_token_id) +``` + +```python out +0 1 +``` + +ടെംപ്ലേറ്റ് ഇങ്ങനെയാണ്: + +```python +tokenizer.post_processor = processors.TemplateProcessing( + single="$A:0 :0 :2", + pair="$A:0 :0 $B:1 :1 :2", + special_tokens=[("", sep_token_id), ("", cls_token_id)], +) +``` + +ഒരു വാക്യജോഡി എൻകോഡ് ചെയ്തുകൊണ്ട് അത് പ്രവർത്തിക്കുന്നുണ്ടെന്ന് നമുക്ക് പരീക്ഷിക്കാം: + +```python +encoding = tokenizer.encode("Let's test this tokenizer...", "on a pair of sentences!") +print(encoding.tokens) +print(encoding.type_ids) +``` + +```python out +['▁Let', "'", 's', '▁test', '▁this', '▁to', 'ken', 'izer', '.', '.', '.', '', '▁', 'on', '▁', 'a', '▁pair', + '▁of', '▁sentence', 's', '!', '', ''] +[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2] +``` + +അവസാനമായി, ഒരു `Metaspace` ഡീകോഡർ നമ്മൾ ചേർക്കുന്നു: + +```python +tokenizer.decoder = decoders.Metaspace() +``` + +അതോടെ ഈ ടോക്കണൈസർ പൂർത്തിയായി! മുമ്പത്തെപ്പോലെ ടോക്കണൈസർ സേവ് ചെയ്യാം, കൂടാതെ 🤗 Transformers-ൽ ഉപയോഗിക്കണമെങ്കിൽ ഒരു `PreTrainedTokenizerFast`-ലോ `XLNetTokenizerFast`-ലോ പൊതിയാം. `PreTrainedTokenizerFast` ഉപയോഗിക്കുമ്പോൾ ശ്രദ്ധിക്കേണ്ട ഒരു കാര്യം, പ്രത്യേക ടോക്കണുകൾക്ക് പുറമേ, ഇടതുവശത്ത് പാഡ് ചെയ്യാൻ 🤗 Transformers ലൈബ്രറിയോട് നമ്മൾ പറയേണ്ടതുണ്ട് എന്നതാണ്: + +```python +from transformers import PreTrainedTokenizerFast + +wrapped_tokenizer = PreTrainedTokenizerFast( + tokenizer_object=tokenizer, + bos_token="", + eos_token="", + unk_token="", + pad_token="", + cls_token="", + sep_token="", + mask_token="", + padding_side="left", +) +``` + +അല്ലെങ്കിൽ പകരമായി: + +```python +from transformers import XLNetTokenizerFast + +wrapped_tokenizer = XLNetTokenizerFast(tokenizer_object=tokenizer) +``` + +നിലവിലുള്ള ടോക്കണൈസറുകൾ നിർമ്മിക്കാൻ വിവിധ ബിൽഡിംഗ് ബ്ലോക്കുകൾ എങ്ങനെ ഉപയോഗിക്കുന്നു എന്ന് നിങ്ങൾ ഇപ്പോൾ കണ്ടുകഴിഞ്ഞു; ഇനി 🤗 Tokenizers ലൈബ്രറി ഉപയോഗിച്ച് നിങ്ങൾക്ക് വേണ്ട ഏത് ടോക്കണൈസറും എഴുതാനും അത് 🤗 Transformers-ൽ ഉപയോഗിക്കാനും നിങ്ങൾക്ക് കഴിയേണ്ടതാണ്. diff --git a/chapters/ml/chapter6/9.mdx b/chapters/ml/chapter6/9.mdx new file mode 100644 index 000000000..6e81dd520 --- /dev/null +++ b/chapters/ml/chapter6/9.mdx @@ -0,0 +1,16 @@ +# Tokenizers, പൂർത്തിയായി![[tokenizers-check]] + + + +ഈ അധ്യായം പൂർത്തിയാക്കിയതിന് അഭിനന്ദനങ്ങൾ! + +ടോക്കണൈസറുകളിലേക്കുള്ള ഈ ആഴത്തിലുള്ള പഠനത്തിനുശേഷം, നിങ്ങൾക്ക്: + +- ഒരു പഴയ ടോക്കണൈസർ ടെംപ്ലേറ്റായി ഉപയോഗിച്ച് ഒരു പുതിയ ടോക്കണൈസർ ട്രെയിൻ ചെയ്യാൻ കഴിയണം +- ടോക്കണുകളുടെ സ്ഥാനങ്ങളെ അവയുടെ യഥാർത്ഥ ടെക്‌സ്‌റ്റ് ഭാഗവുമായി (span) ബന്ധിപ്പിക്കാൻ ഓഫ്‌സെറ്റുകൾ (offsets) എങ്ങനെ ഉപയോഗിക്കാമെന്ന് മനസ്സിലായിരിക്കണം +- BPE, WordPiece, Unigram എന്നിവ തമ്മിലുള്ള വ്യത്യാസങ്ങളെക്കുറിച്ച് അറിവുണ്ടായിരിക്കണം +- 🤗 Tokenizers ലൈബ്രറി നൽകുന്ന ബ്ലോക്കുകൾ ഇഷ്ടാനുസരണം കൂട്ടിച്ചേർത്ത് നിങ്ങളുടെ സ്വന്തം ടോക്കണൈസർ നിർമ്മിക്കാൻ കഴിയണം +- ആ ടോക്കണൈസർ 🤗 Transformers ലൈബ്രറിക്കുള്ളിൽ ഉപയോഗിക്കാൻ കഴിയണം diff --git a/chapters/ml/chapter7/1.mdx b/chapters/ml/chapter7/1.mdx new file mode 100644 index 000000000..e78591e0c --- /dev/null +++ b/chapters/ml/chapter7/1.mdx @@ -0,0 +1,37 @@ + + +# ആമുഖം[[introduction]] + + + +[അധ്യായം 3](/course/chapter3)-ൽ, ടെക്‌സ്‌റ്റ് ക്ലാസിഫിക്കേഷനായി ഒരു മോഡൽ എങ്ങനെ ഫൈൻ-ട്യൂൻ ചെയ്യാമെന്ന് നിങ്ങൾ കണ്ടു. ഈ അധ്യായത്തിൽ, പരമ്പരാഗത NLP മോഡലുകളുമായും ആധുനിക LLM-കളുമായും പ്രവർത്തിക്കാൻ അത്യാവശ്യമായ, താഴെ പറയുന്ന സാധാരണ ഭാഷാ ടാസ്‌ക്കുകൾ നമ്മൾ കൈകാര്യം ചെയ്യും: + +- ടോക്കൺ ക്ലാസിഫിക്കേഷൻ (Token classification) +- മാസ്‌ക്ഡ് ലാംഗ്വേജ് മോഡലിംഗ് (BERT പോലെ) +- സമ്മറൈസേഷൻ (Summarization) +- വിവർത്തനം (Translation) +- കോസൽ ലാംഗ്വേജ് മോഡലിംഗ് പ്രീട്രെയിനിംഗ് (GPT-2 പോലെ) +- ചോദ്യോത്തരം (Question answering) + +ലാർജ് ലാംഗ്വേജ് മോഡലുകൾ (LLM-കൾ) എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്നതിന്റെ അടിത്തറയാണ് ഈ അടിസ്ഥാന ടാസ്‌ക്കുകൾ; ഇന്നത്തെ ഏറ്റവും നൂതനമായ ലാംഗ്വേജ് മോഡലുകളുമായി ഫലപ്രദമായി പ്രവർത്തിക്കാൻ ഇവ മനസ്സിലാക്കുന്നത് നിർണ്ണായകമാണ്. + +{#if fw === 'pt'} + +ഇതിനായി, [അധ്യായം 3](/course/chapter3)-ൽ `Trainer` API-യെയും 🤗 Accelerate ലൈബ്രറിയെയും കുറിച്ചും, [അധ്യായം 5](/course/chapter5)-ൽ 🤗 Datasets ലൈബ്രറിയെക്കുറിച്ചും, [അധ്യായം 6](/course/chapter6)-ൽ 🤗 Tokenizers ലൈബ്രറിയെക്കുറിച്ചും നിങ്ങൾ പഠിച്ചതെല്ലാം പ്രയോജനപ്പെടുത്തേണ്ടതുണ്ട്. [അധ്യായം 4](/course/chapter4)-ൽ ചെയ്തതുപോലെ, നമ്മുടെ ഫലങ്ങൾ Model Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യുകയും ചെയ്യും; അതിനാൽ എല്ലാം ഒരുമിച്ചു ചേരുന്ന അധ്യായമാണ് യഥാർത്ഥത്തിൽ ഇത്! + +ഓരോ ഭാഗവും സ്വതന്ത്രമായി വായിക്കാവുന്നതാണ്; `Trainer` API ഉപയോഗിച്ചോ, 🤗 Accelerate ഉപയോഗിച്ചുള്ള നിങ്ങളുടെ സ്വന്തം ട്രെയിനിംഗ് ലൂപ്പ് ഉപയോഗിച്ചോ ഒരു മോഡൽ എങ്ങനെ ട്രെയിൻ ചെയ്യാമെന്ന് അവ നിങ്ങൾക്ക് കാണിച്ചുതരും. ഇവയിൽ ഏതെങ്കിലും ഒരു ഭാഗം ഒഴിവാക്കി, നിങ്ങൾക്ക് ഏറ്റവും താൽപ്പര്യമുള്ളതിൽ ശ്രദ്ധ കേന്ദ്രീകരിക്കാൻ മടിക്കേണ്ട: തിരശ്ശീലയ്ക്ക് പിന്നിൽ എന്താണ് നടക്കുന്നത് എന്ന് ആശങ്കപ്പെടാതെ നിങ്ങളുടെ മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യാനോ ട്രെയിൻ ചെയ്യാനോ `Trainer` API വളരെ മികച്ചതാണ്; അതേസമയം `Accelerate` ഉപയോഗിച്ചുള്ള ട്രെയിനിംഗ് ലൂപ്പ്, നിങ്ങൾക്ക് ആവശ്യമുള്ള ഏത് ഭാഗവും കൂടുതൽ എളുപ്പത്തിൽ ഇഷ്ടാനുസൃതമാക്കാൻ അനുവദിക്കും. + +{:else} + +ഇതിനായി, [അധ്യായം 3](/course/chapter3)-ൽ Keras API ഉപയോഗിച്ച് മോഡലുകൾ ട്രെയിൻ ചെയ്യുന്നതിനെക്കുറിച്ചും, [അധ്യായം 5](/course/chapter5)-ൽ 🤗 Datasets ലൈബ്രറിയെക്കുറിച്ചും, [അധ്യായം 6](/course/chapter6)-ൽ 🤗 Tokenizers ലൈബ്രറിയെക്കുറിച്ചും നിങ്ങൾ പഠിച്ചതെല്ലാം പ്രയോജനപ്പെടുത്തേണ്ടതുണ്ട്. [അധ്യായം 4](/course/chapter4)-ൽ ചെയ്തതുപോലെ, നമ്മുടെ ഫലങ്ങൾ Model Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യുകയും ചെയ്യും; അതിനാൽ എല്ലാം ഒരുമിച്ചു ചേരുന്ന അധ്യായമാണ് യഥാർത്ഥത്തിൽ ഇത്! + +ഓരോ ഭാഗവും സ്വതന്ത്രമായി വായിക്കാവുന്നതാണ്. + +{/if} + + +> [!TIP] +> ഈ ഭാഗങ്ങൾ ക്രമത്തിൽ വായിക്കുകയാണെങ്കിൽ, അവയിൽ കോഡും വിവരണവും ഒരുപാട് പൊതുവായി ഉണ്ടെന്ന് നിങ്ങൾ ശ്രദ്ധിക്കും. ഈ ആവർത്തനം മനഃപൂർവ്വമാണ് — നിങ്ങൾക്ക് താൽപ്പര്യമുള്ള ഏത് ടാസ്‌ക്കിലേക്കും നേരിട്ട് കടന്നുചെന്ന് (അല്ലെങ്കിൽ പിന്നീട് തിരികെ വന്ന്) പൂർണ്ണമായി പ്രവർത്തിക്കുന്ന ഒരു ഉദാഹരണം കണ്ടെത്താൻ നിങ്ങളെ അനുവദിക്കാനാണ് ഇത്. diff --git a/chapters/ml/chapter7/2.mdx b/chapters/ml/chapter7/2.mdx new file mode 100644 index 000000000..62d6e0761 --- /dev/null +++ b/chapters/ml/chapter7/2.mdx @@ -0,0 +1,957 @@ + + +# ടോക്കൺ ക്ലാസിഫിക്കേഷൻ[[token-classification]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +നമ്മൾ ആദ്യം പരിശോധിക്കുന്ന ആപ്ലിക്കേഷൻ ടോക്കൺ ക്ലാസിഫിക്കേഷൻ (token classification) ആണ്. "ഒരു വാക്യത്തിലെ ഓരോ ടോക്കണിനും ഒരു ലേബൽ നൽകുക" എന്ന രീതിയിൽ രൂപപ്പെടുത്താവുന്ന ഏത് പ്രശ്നവും ഈ പൊതുവായ ടാസ്‌കിൽ ഉൾപ്പെടുന്നു, ഉദാഹരണത്തിന്: + +- **നെയിംഡ് എന്റിറ്റി റെക്കഗ്നിഷൻ (Named entity recognition, NER)**: ഒരു വാക്യത്തിലെ എന്റിറ്റികൾ (വ്യക്തികൾ, സ്ഥലങ്ങൾ, സംഘടനകൾ എന്നിവ പോലുള്ളവ) കണ്ടെത്തുക. ഓരോ എന്റിറ്റിക്കും ഒരു ക്ലാസ്സും "എന്റിറ്റി ഇല്ല" എന്നതിന് ഒരു ക്ലാസ്സും വച്ച്, ഓരോ ടോക്കണിനും ഒരു ലേബൽ നൽകുന്ന രീതിയിൽ ഇത് രൂപപ്പെടുത്താം. +- **പാർട്ട്-ഓഫ്-സ്പീച്ച് ടാഗിംഗ് (Part-of-speech tagging, POS)**: ഒരു വാക്യത്തിലെ ഓരോ വാക്കും ഒരു പ്രത്യേക പദവിഭാഗത്തിൽ (നാമം, ക്രിയ, വിശേഷണം എന്നിങ്ങനെ) പെടുന്നതായി അടയാളപ്പെടുത്തുക. +- **ചങ്കിംഗ് (Chunking)**: ഒരേ എന്റിറ്റിയിൽ പെടുന്ന ടോക്കണുകൾ കണ്ടെത്തുക. ഈ ടാസ്‌ക് (POS-മായോ NER-മായോ ഇത് സംയോജിപ്പിക്കാം) ഇങ്ങനെ രൂപപ്പെടുത്താം: ഒരു ചങ്കിന്റെ തുടക്കത്തിലുള്ള ടോക്കണുകൾക്ക് ഒരു ലേബൽ (സാധാരണയായി `B-`), ഒരു ചങ്കിന്റെ ഉള്ളിലുള്ള ടോക്കണുകൾക്ക് മറ്റൊരു ലേബൽ (സാധാരണയായി `I-`), ഒരു ചങ്കിലും പെടാത്ത ടോക്കണുകൾക്ക് മൂന്നാമതൊരു ലേബൽ (സാധാരണയായി `O`) എന്നിങ്ങനെ നൽകുക. + + + +തീർച്ചയായും, ടോക്കൺ ക്ലാസിഫിക്കേഷൻ പ്രശ്നങ്ങൾ വേറെയും പല തരത്തിലുണ്ട്; ഇവ പ്രതിനിധാനപരമായ ഏതാനും ഉദാഹരണങ്ങൾ മാത്രമാണ്. ഈ ഭാഗത്തിൽ, ഒരു NER ടാസ്‌കിൽ നമ്മൾ ഒരു മോഡൽ (BERT) ഫൈൻ-ട്യൂൻ ചെയ്യും; അതിനുശേഷം ഇതുപോലുള്ള പ്രവചനങ്ങൾ (predictions) കണക്കാക്കാൻ അതിന് കഴിയും: + + + + +ചോദ്യോത്തരത്തിനായുള്ള വൺ-ഹോട്ട് എൻകോഡ് ചെയ്ത ലേബലുകൾ. + + + +നമ്മൾ ട്രെയിൻ ചെയ്ത് Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യുന്ന മോഡൽ [ഇവിടെ](https://huggingface.co/huggingface-course/bert-finetuned-ner?text=My+name+is+Sylvain+and+I+work+at+Hugging+Face+in+Brooklyn) കാണാനും അതിന്റെ പ്രവചനങ്ങൾ ഒന്നുകൂടി പരിശോധിക്കാനും നിങ്ങൾക്ക് കഴിയും. + +## ഡേറ്റ തയ്യാറാക്കുന്നു[[preparing-the-data]] + +ആദ്യം വേണ്ടത്, ടോക്കൺ ക്ലാസിഫിക്കേഷന് അനുയോജ്യമായ ഒരു ഡേറ്റാസെറ്റാണ്. ഈ ഭാഗത്തിൽ, Reuters-ൽ നിന്നുള്ള വാർത്തകൾ ഉൾക്കൊള്ളുന്ന [CoNLL-2003 ഡേറ്റാസെറ്റ്](https://huggingface.co/datasets/conll2003) നമ്മൾ ഉപയോഗിക്കും. + +> [!TIP] +> 💡 നിങ്ങളുടെ ഡേറ്റാസെറ്റിൽ വാക്കുകളായി വിഭജിച്ച ടെക്‌സ്‌റ്റുകളും അവയോട് ബന്ധപ്പെട്ട ലേബലുകളും ഉള്ളിടത്തോളം, ഇവിടെ വിവരിക്കുന്ന ഡേറ്റാ പ്രോസസ്സിംഗ് രീതികൾ നിങ്ങളുടെ സ്വന്തം ഡേറ്റാസെറ്റിന് അനുയോജ്യമായി മാറ്റാൻ നിങ്ങൾക്ക് കഴിയും. നിങ്ങളുടെ സ്വന്തം കസ്‌റ്റം ഡേറ്റ ഒരു `Dataset`-ൽ എങ്ങനെ ലോഡ് ചെയ്യാമെന്ന് ഓർമ്മ പുതുക്കണമെങ്കിൽ [അധ്യായം 5](/course/chapter5) വീണ്ടും നോക്കുക. + +### CoNLL-2003 ഡേറ്റാസെറ്റ്[[the-conll-2003-dataset]] + +CoNLL-2003 ഡേറ്റാസെറ്റ് ലോഡ് ചെയ്യാൻ, 🤗 Datasets ലൈബ്രറിയിലെ `load_dataset()` മെത്തേഡ് നമ്മൾ ഉപയോഗിക്കുന്നു: + +```py +from datasets import load_dataset + +raw_datasets = load_dataset("conll2003") +``` + +[അധ്യായം 3](/course/chapter3)-ൽ GLUE MRPC ഡേറ്റാസെറ്റിന്റെ കാര്യത്തിൽ കണ്ടതുപോലെ, ഇത് ഡേറ്റാസെറ്റ് ഡൗൺലോഡ് ചെയ്ത് കാഷ് ചെയ്യും. ഈ ഒബ്‌ജക്റ്റ് പരിശോധിച്ചാൽ, അതിലുള്ള കോളങ്ങളും ട്രെയിനിംഗ്, വാലിഡേഷൻ, ടെസ്‌റ്റ് സെറ്റുകൾ തമ്മിലുള്ള വിഭജനവും നമുക്ക് കാണാം: + +```py +raw_datasets +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['chunk_tags', 'id', 'ner_tags', 'pos_tags', 'tokens'], + num_rows: 14041 + }) + validation: Dataset({ + features: ['chunk_tags', 'id', 'ner_tags', 'pos_tags', 'tokens'], + num_rows: 3250 + }) + test: Dataset({ + features: ['chunk_tags', 'id', 'ner_tags', 'pos_tags', 'tokens'], + num_rows: 3453 + }) +}) +``` + +പ്രത്യേകിച്ച്, നമ്മൾ മുമ്പ് പറഞ്ഞ മൂന്ന് ടാസ്‌കുകൾക്കുമുള്ള — NER, POS, ചങ്കിംഗ് — ലേബലുകൾ ഈ ഡേറ്റാസെറ്റിൽ ഉണ്ടെന്ന് കാണാം. മറ്റ് ഡേറ്റാസെറ്റുകളിൽ നിന്നുള്ള ഒരു വലിയ വ്യത്യാസം, ഇൻപുട്ട് ടെക്‌സ്‌റ്റുകൾ വാക്യങ്ങളായോ ഡോക്യുമെന്റുകളായോ അല്ല, വാക്കുകളുടെ ലിസ്‌റ്റുകളായാണ് നൽകിയിരിക്കുന്നത് എന്നതാണ് (അവസാനത്തെ കോളത്തിന്റെ പേര് `tokens` എന്നാണെങ്കിലും, അതിൽ ഉള്ളത് വാക്കുകളാണ് — അതായത്, സബ്‌വേഡ് ടോക്കണൈസേഷനായി ഇനിയും ടോക്കണൈസറിലൂടെ കടന്നുപോകേണ്ട, മുൻകൂട്ടി ടോക്കണൈസ് ചെയ്ത (pre-tokenized) ഇൻപുട്ടുകളാണ് ഇവ). + +ട്രെയിനിംഗ് സെറ്റിലെ ആദ്യത്തെ എലമെന്റ് നോക്കാം: + +```py +raw_datasets["train"][0]["tokens"] +``` + +```python out +['EU', 'rejects', 'German', 'call', 'to', 'boycott', 'British', 'lamb', '.'] +``` + +നമുക്ക് നെയിംഡ് എന്റിറ്റി റെക്കഗ്നിഷൻ ചെയ്യണം എന്നതിനാൽ, NER ടാഗുകൾ നമ്മൾ നോക്കും: + +```py +raw_datasets["train"][0]["ner_tags"] +``` + +```python out +[3, 0, 7, 0, 0, 0, 7, 0, 0] +``` + +ട്രെയിനിംഗിന് തയ്യാറായ, ഇന്റിജറുകളായുള്ള (integers) ലേബലുകളാണ് ഇവ; എന്നാൽ ഡേറ്റ പരിശോധിക്കാൻ ആഗ്രഹിക്കുമ്പോൾ ഇവ അത്ര ഉപകാരപ്രദമാകണമെന്നില്ല. ടെക്‌സ്‌റ്റ് ക്ലാസിഫിക്കേഷന്റെ കാര്യത്തിലേതുപോലെ, നമ്മുടെ ഡേറ്റാസെറ്റിന്റെ `features` ആട്രിബ്യൂട്ട് നോക്കിയാൽ ഈ ഇന്റിജറുകളും ലേബൽ പേരുകളും തമ്മിലുള്ള ബന്ധം നമുക്ക് കാണാം: + +```py +ner_feature = raw_datasets["train"].features["ner_tags"] +ner_feature +``` + +```python out +Sequence(feature=ClassLabel(num_classes=9, names=['O', 'B-PER', 'I-PER', 'B-ORG', 'I-ORG', 'B-LOC', 'I-LOC', 'B-MISC', 'I-MISC'], names_file=None, id=None), length=-1, id=None) +``` + +അതായത്, ഈ കോളത്തിലെ എലമെന്റുകൾ `ClassLabel`-ന്റെ സീക്വൻസുകളാണ്. സീക്വൻസിലെ എലമെന്റുകളുടെ ടൈപ്പ് ഈ `ner_feature`-ന്റെ `feature` ആട്രിബ്യൂട്ടിലാണ് ഉള്ളത്; ആ `feature`-ന്റെ `names` ആട്രിബ്യൂട്ട് നോക്കിയാൽ പേരുകളുടെ ലിസ്‌റ്റ് നമുക്ക് ലഭിക്കും: + +```py +label_names = ner_feature.feature.names +label_names +``` + +```python out +['O', 'B-PER', 'I-PER', 'B-ORG', 'I-ORG', 'B-LOC', 'I-LOC', 'B-MISC', 'I-MISC'] +``` + +[അധ്യായം 6](/course/chapter6/3)-ൽ `token-classification` പൈപ്പ്‌ലൈനിലേക്ക് ആഴത്തിൽ ഇറങ്ങിയപ്പോൾ ഈ ലേബലുകൾ നമ്മൾ ഇതിനകം കണ്ടിട്ടുണ്ട്, എങ്കിലും പെട്ടെന്ന് ഒന്ന് ഓർമ്മ പുതുക്കാൻ: + +- `O` എന്നാൽ ആ വാക്ക് ഒരു എന്റിറ്റിയുമായും ബന്ധപ്പെട്ടതല്ല എന്നാണ്. +- `B-PER`/`I-PER` എന്നാൽ ആ വാക്ക് ഒരു *വ്യക്തി* (person) എന്റിറ്റിയുടെ തുടക്കമാണ്/ഉള്ളിലാണ് എന്നാണ്. +- `B-ORG`/`I-ORG` എന്നാൽ ആ വാക്ക് ഒരു *സംഘടന* (organization) എന്റിറ്റിയുടെ തുടക്കമാണ്/ഉള്ളിലാണ് എന്നാണ്. +- `B-LOC`/`I-LOC` എന്നാൽ ആ വാക്ക് ഒരു *സ്ഥലം* (location) എന്റിറ്റിയുടെ തുടക്കമാണ്/ഉള്ളിലാണ് എന്നാണ്. +- `B-MISC`/`I-MISC` എന്നാൽ ആ വാക്ക് ഒരു *മറ്റ് വിഭാഗത്തിലുള്ള* (miscellaneous) എന്റിറ്റിയുടെ തുടക്കമാണ്/ഉള്ളിലാണ് എന്നാണ്. + +ഇപ്പോൾ, നമ്മൾ മുമ്പ് കണ്ട ലേബലുകൾ ഡീകോഡ് ചെയ്താൽ ഇതാണ് ലഭിക്കുന്നത്: + +```python +words = raw_datasets["train"][0]["tokens"] +labels = raw_datasets["train"][0]["ner_tags"] +line1 = "" +line2 = "" +for word, label in zip(words, labels): + full_label = label_names[label] + max_length = max(len(word), len(full_label)) + line1 += word + " " * (max_length - len(word) + 1) + line2 += full_label + " " * (max_length - len(full_label) + 1) + +print(line1) +print(line2) +``` + +```python out +'EU rejects German call to boycott British lamb .' +'B-ORG O B-MISC O O O B-MISC O O' +``` + +`B-`, `I-` ലേബലുകൾ ഇടകലർന്നു വരുന്ന ഒരു ഉദാഹരണത്തിനായി, ട്രെയിനിംഗ് സെറ്റിലെ ഇൻഡെക്‌സ് 4-ലുള്ള എലമെന്റിൽ അതേ കോഡ് നൽകുന്ന ഫലം ഇതാ: + +```python out +'Germany \'s representative to the European Union \'s veterinary committee Werner Zwingmann said on Wednesday consumers should buy sheepmeat from countries other than Britain until the scientific advice was clearer .' +'B-LOC O O O O B-ORG I-ORG O O O B-PER I-PER O O O O O O O O O O O B-LOC O O O O O O O' +``` + +നമുക്ക് കാണാവുന്നതുപോലെ, "European Union", "Werner Zwingmann" എന്നിവ പോലെ രണ്ട് വാക്കുകളിലായി വ്യാപിക്കുന്ന എന്റിറ്റികൾക്ക്, ആദ്യത്തെ വാക്കിന് ഒരു `B-` ലേബലും രണ്ടാമത്തേതിന് ഒരു `I-` ലേബലുമാണ് നൽകിയിരിക്കുന്നത്. + +> [!TIP] +> ✏️ **നിങ്ങളുടെ ഊഴം!** അതേ രണ്ട് വാക്യങ്ങൾ അവയുടെ POS അല്ലെങ്കിൽ ചങ്കിംഗ് ലേബലുകളോടെ പ്രിന്റ് ചെയ്യുക. + +### ഡേറ്റ പ്രോസസ്സ് ചെയ്യുന്നു[[processing-the-data]] + + + +പതിവുപോലെ, മോഡലിന് മനസ്സിലാക്കാൻ കഴിയുന്നതിന് മുമ്പ് നമ്മുടെ ടെക്‌സ്‌റ്റുകൾ ടോക്കൺ ID-കളാക്കി മാറ്റേണ്ടതുണ്ട്. [അധ്യായം 6](/course/chapter6/)-ൽ കണ്ടതുപോലെ, ടോക്കൺ ക്ലാസിഫിക്കേഷൻ ടാസ്‌കുകളുടെ കാര്യത്തിലെ ഒരു വലിയ വ്യത്യാസം, നമ്മുടെ ഇൻപുട്ടുകൾ മുൻകൂട്ടി ടോക്കണൈസ് ചെയ്തവയാണ് എന്നതാണ്. ഭാഗ്യവശാൽ, ടോക്കണൈസർ API-ക്ക് ഇത് വളരെ എളുപ്പത്തിൽ കൈകാര്യം ചെയ്യാൻ കഴിയും; ഒരു പ്രത്യേക ഫ്ലാഗ് ഉപയോഗിച്ച് `tokenizer`-നെ അറിയിച്ചാൽ മാത്രം മതി. + +തുടങ്ങാൻ, നമ്മുടെ `tokenizer` ഒബ്‌ജക്റ്റ് ഉണ്ടാക്കാം. മുമ്പ് പറഞ്ഞതുപോലെ, ഒരു BERT പ്രീട്രെയിൻഡ് മോഡലാണ് നമ്മൾ ഉപയോഗിക്കുന്നത്; അതിനാൽ അതിനോട് ബന്ധപ്പെട്ട ടോക്കണൈസർ ഡൗൺലോഡ് ചെയ്ത് കാഷ് ചെയ്യുന്നതിലൂടെ നമ്മൾ ആരംഭിക്കും: + +```python +from transformers import AutoTokenizer + +model_checkpoint = "bert-base-cased" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) +``` + +`model_checkpoint`-ന് പകരം [Hub](https://huggingface.co/models)-ൽ നിന്ന് നിങ്ങൾക്ക് ഇഷ്ടമുള്ള മറ്റേതെങ്കിലും മോഡലോ, ഒരു പ്രീട്രെയിൻഡ് മോഡലും ടോക്കണൈസറും നിങ്ങൾ സേവ് ചെയ്തിട്ടുള്ള ഒരു ലോക്കൽ ഫോൾഡറോ നിങ്ങൾക്ക് ഉപയോഗിക്കാം. ഒരേയൊരു നിബന്ധന, ടോക്കണൈസർ 🤗 Tokenizers ലൈബ്രറിയെ അടിസ്ഥാനമാക്കിയുള്ളതായിരിക്കണം, അതായത് അതിന്റെ ഒരു "ഫാസ്‌റ്റ്" (fast) പതിപ്പ് ലഭ്യമായിരിക്കണം എന്നതാണ്. ഫാസ്‌റ്റ് പതിപ്പുള്ള എല്ലാ ആർക്കിടെക്‌ചറുകളും [ഈ വലിയ പട്ടികയിൽ](https://huggingface.co/transformers/#supported-frameworks) നിങ്ങൾക്ക് കാണാം; നിങ്ങൾ ഉപയോഗിക്കുന്ന `tokenizer` ഒബ്‌ജക്റ്റ് ശരിക്കും 🤗 Tokenizers-നെ അടിസ്ഥാനമാക്കിയുള്ളതാണോ എന്ന് പരിശോധിക്കാൻ അതിന്റെ `is_fast` ആട്രിബ്യൂട്ട് നോക്കാം: + +```py +tokenizer.is_fast +``` + +```python out +True +``` + +മുൻകൂട്ടി ടോക്കണൈസ് ചെയ്ത ഒരു ഇൻപുട്ട് ടോക്കണൈസ് ചെയ്യാൻ, നമ്മുടെ `tokenizer` പതിവുപോലെ ഉപയോഗിച്ച്, `is_split_into_words=True` എന്നത് കൂടി ചേർത്താൽ മതി: + +```py +inputs = tokenizer(raw_datasets["train"][0]["tokens"], is_split_into_words=True) +inputs.tokens() +``` + +```python out +['[CLS]', 'EU', 'rejects', 'German', 'call', 'to', 'boycott', 'British', 'la', '##mb', '.', '[SEP]'] +``` + +നമുക്ക് കാണാവുന്നതുപോലെ, മോഡൽ ഉപയോഗിക്കുന്ന സ്‌പെഷ്യൽ ടോക്കണുകൾ (തുടക്കത്തിൽ `[CLS]`, അവസാനം `[SEP]`) ടോക്കണൈസർ ചേർത്തു, മിക്ക വാക്കുകളെയും അതേപടി വിട്ടു. എന്നാൽ `lamb` എന്ന വാക്ക് `la`, `##mb` എന്നീ രണ്ട് സബ്‌വേഡുകളായി ടോക്കണൈസ് ചെയ്യപ്പെട്ടു. ഇത് നമ്മുടെ ഇൻപുട്ടുകളും ലേബലുകളും തമ്മിൽ ഒരു പൊരുത്തക്കേട് ഉണ്ടാക്കുന്നു: ലേബലുകളുടെ ലിസ്‌റ്റിൽ 9 എലമെന്റുകൾ മാത്രമേയുള്ളൂ, എന്നാൽ നമ്മുടെ ഇൻപുട്ടിൽ ഇപ്പോൾ 12 ടോക്കണുകളുണ്ട്. സ്‌പെഷ്യൽ ടോക്കണുകളുടെ കാര്യം കണക്കിലെടുക്കുന്നത് എളുപ്പമാണ് (അവ തുടക്കത്തിലും അവസാനത്തിലുമാണെന്ന് നമുക്കറിയാം), എന്നാൽ എല്ലാ ലേബലുകളും ശരിയായ വാക്കുകളുമായി വിന്യസിക്കുന്നു (align) എന്ന് ഉറപ്പാക്കുകയും വേണം. + +ഭാഗ്യവശാൽ, നമ്മൾ ഒരു ഫാസ്‌റ്റ് ടോക്കണൈസർ ഉപയോഗിക്കുന്നതിനാൽ 🤗 Tokenizers-ന്റെ അസാമാന്യ ശേഷികൾ നമുക്ക് ലഭ്യമാണ്; അതായത്, ഓരോ ടോക്കണും അതിനോട് ബന്ധപ്പെട്ട വാക്കുമായി എളുപ്പത്തിൽ മാപ്പ് ചെയ്യാൻ നമുക്ക് കഴിയും ([അധ്യായം 6](/course/chapter6/3)-ൽ കണ്ടതുപോലെ): + +```py +inputs.word_ids() +``` + +```python out +[None, 0, 1, 2, 3, 4, 5, 6, 7, 7, 8, None] +``` + +ചെറിയൊരു പണിയിലൂടെ, ടോക്കണുകളുമായി പൊരുത്തപ്പെടുന്ന തരത്തിൽ നമ്മുടെ ലേബൽ ലിസ്‌റ്റ് വികസിപ്പിക്കാം. നമ്മൾ പ്രയോഗിക്കുന്ന ആദ്യത്തെ നിയമം, സ്‌പെഷ്യൽ ടോക്കണുകൾക്ക് `-100` എന്ന ലേബൽ ലഭിക്കും എന്നതാണ്. കാരണം, നമ്മൾ ഉപയോഗിക്കാൻ പോകുന്ന ലോസ് ഫംഗ്‌ഷനിൽ (ക്രോസ് എൻട്രോപ്പി) ഡിഫോൾട്ടായി അവഗണിക്കപ്പെടുന്ന ഒരു ഇൻഡെക്‌സാണ് `-100`. പിന്നീട്, ഓരോ ടോക്കണിനും അത് ഉള്ളിലുള്ള വാക്ക് ആരംഭിച്ച ടോക്കണിന്റെ അതേ ലേബൽ ലഭിക്കും, കാരണം അവ ഒരേ എന്റിറ്റിയുടെ ഭാഗമാണ്. ഒരു വാക്കിന്റെ ഉള്ളിലുള്ള, എന്നാൽ തുടക്കത്തിലല്ലാത്ത ടോക്കണുകൾക്ക്, `B-` എന്നത് `I-` എന്നാക്കി മാറ്റുന്നു (ആ ടോക്കൺ എന്റിറ്റി ആരംഭിക്കുന്നില്ല എന്നതിനാൽ): + +```python +def align_labels_with_tokens(labels, word_ids): + new_labels = [] + current_word = None + for word_id in word_ids: + if word_id != current_word: + # Start of a new word! + current_word = word_id + label = -100 if word_id is None else labels[word_id] + new_labels.append(label) + elif word_id is None: + # Special token + new_labels.append(-100) + else: + # Same word as previous token + label = labels[word_id] + # If the label is B-XXX we change it to I-XXX + if label % 2 == 1: + label += 1 + new_labels.append(label) + + return new_labels +``` + +നമ്മുടെ ആദ്യത്തെ വാക്യത്തിൽ ഇത് പരീക്ഷിച്ചുനോക്കാം: + +```py +labels = raw_datasets["train"][0]["ner_tags"] +word_ids = inputs.word_ids() +print(labels) +print(align_labels_with_tokens(labels, word_ids)) +``` + +```python out +[3, 0, 7, 0, 0, 0, 7, 0, 0] +[-100, 3, 0, 7, 0, 0, 0, 7, 0, 0, 0, -100] +``` + +നമുക്ക് കാണാവുന്നതുപോലെ, തുടക്കത്തിലെയും അവസാനത്തെയും രണ്ട് സ്‌പെഷ്യൽ ടോക്കണുകൾക്ക് `-100`-ഉം, രണ്ട് ടോക്കണുകളായി വിഭജിക്കപ്പെട്ട നമ്മുടെ വാക്കിന് ഒരു പുതിയ `0`-ഉം നമ്മുടെ ഫംഗ്‌ഷൻ ചേർത്തു. + +> [!TIP] +> ✏️ **നിങ്ങളുടെ ഊഴം!** ചില ഗവേഷകർ ഒരു വാക്കിന് ഒരു ലേബൽ മാത്രം നൽകാനും, ആ വാക്കിലെ മറ്റ് സബ്‌ടോക്കണുകൾക്ക് `-100` നൽകാനുമാണ് ഇഷ്ടപ്പെടുന്നത്. ധാരാളം സബ്‌ടോക്കണുകളായി വിഭജിക്കപ്പെടുന്ന നീണ്ട വാക്കുകൾ ലോസിൽ വലിയ സ്വാധീനം ചെലുത്തുന്നത് ഒഴിവാക്കാനാണ് ഇത്. ഈ നിയമം പിന്തുടർന്ന് ലേബലുകളെ ഇൻപുട്ട് ID-കളുമായി വിന്യസിക്കാൻ മുമ്പത്തെ ഫംഗ്‌ഷൻ മാറ്റുക. + +നമ്മുടെ മുഴുവൻ ഡേറ്റാസെറ്റും പ്രീപ്രോസസ്സ് ചെയ്യാൻ, എല്ലാ ഇൻപുട്ടുകളും ടോക്കണൈസ് ചെയ്യുകയും എല്ലാ ലേബലുകളിലും `align_labels_with_tokens()` പ്രയോഗിക്കുകയും വേണം. നമ്മുടെ ഫാസ്‌റ്റ് ടോക്കണൈസറിന്റെ വേഗത പ്രയോജനപ്പെടുത്താൻ, ധാരാളം ടെക്‌സ്‌റ്റുകൾ ഒരേസമയം ടോക്കണൈസ് ചെയ്യുന്നതാണ് ഏറ്റവും നല്ലത്; അതിനാൽ ഉദാഹരണങ്ങളുടെ ഒരു ലിസ്‌റ്റ് പ്രോസസ്സ് ചെയ്യുന്ന ഒരു ഫംഗ്‌ഷൻ എഴുതി, `batched=True` എന്ന ഓപ്‌ഷനോടെ `Dataset.map()` മെത്തേഡ് നമ്മൾ ഉപയോഗിക്കും. നമ്മുടെ മുൻ ഉദാഹരണത്തിൽ നിന്നുള്ള ഒരേയൊരു വ്യത്യാസം, ടോക്കണൈസറിലേക്കുള്ള ഇൻപുട്ടുകൾ ടെക്‌സ്‌റ്റുകളുടെ ലിസ്‌റ്റുകളായിരിക്കുമ്പോൾ (അല്ലെങ്കിൽ നമ്മുടെ കാര്യത്തിൽ, വാക്കുകളുടെ ലിസ്‌റ്റുകളുടെ ലിസ്‌റ്റ്), ഏത് ഉദാഹരണത്തിന്റെ വേഡ് ID-കളാണ് വേണ്ടത് എന്നതിന്റെ ഇൻഡെക്‌സ് `word_ids()` ഫംഗ്‌ഷന് നൽകേണ്ടതുണ്ട് എന്നതാണ്; അതിനാൽ അതും നമ്മൾ ചേർക്കുന്നു: + +```py +def tokenize_and_align_labels(examples): + tokenized_inputs = tokenizer( + examples["tokens"], truncation=True, is_split_into_words=True + ) + all_labels = examples["ner_tags"] + new_labels = [] + for i, labels in enumerate(all_labels): + word_ids = tokenized_inputs.word_ids(i) + new_labels.append(align_labels_with_tokens(labels, word_ids)) + + tokenized_inputs["labels"] = new_labels + return tokenized_inputs +``` + +നമ്മുടെ ഇൻപുട്ടുകൾ ഇതുവരെ പാഡ് ചെയ്തിട്ടില്ല എന്നത് ശ്രദ്ധിക്കുക; ഒരു ഡേറ്റാ കൊളേറ്റർ (data collator) ഉപയോഗിച്ച് ബാച്ചുകൾ ഉണ്ടാക്കുമ്പോൾ, പിന്നീട് നമ്മൾ അത് ചെയ്യും. + +ഇപ്പോൾ ആ പ്രീപ്രോസസ്സിംഗ് മുഴുവൻ ഒറ്റയടിക്ക് നമ്മുടെ ഡേറ്റാസെറ്റിന്റെ മറ്റ് സ്‌പ്ലിറ്റുകളിലും പ്രയോഗിക്കാം: + +```py +tokenized_datasets = raw_datasets.map( + tokenize_and_align_labels, + batched=True, + remove_columns=raw_datasets["train"].column_names, +) +``` + +ഏറ്റവും ബുദ്ധിമുട്ടുള്ള ഭാഗം നമ്മൾ പൂർത്തിയാക്കി! ഡേറ്റ പ്രീപ്രോസസ്സ് ചെയ്തുകഴിഞ്ഞ സ്ഥിതിക്ക്, യഥാർത്ഥ ട്രെയിനിംഗ് [അധ്യായം 3](/course/chapter3)-ൽ നമ്മൾ ചെയ്തതിനോട് വളരെ സാമ്യമുള്ളതായിരിക്കും. + +{#if fw === 'pt'} + +## `Trainer` API ഉപയോഗിച്ച് മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യുന്നു[[fine-tuning-the-model-with-the-trainer-api]] + +`Trainer` ഉപയോഗിക്കുന്ന യഥാർത്ഥ കോഡ് മുമ്പത്തേതുപോലെ തന്നെയായിരിക്കും; ഡേറ്റ ഒരു ബാച്ചായി കൊളേറ്റ് ചെയ്യുന്ന രീതിയും മെട്രിക് കണക്കുകൂട്ടൽ ഫംഗ്‌ഷനും മാത്രമാണ് മാറ്റങ്ങൾ. + +{:else} + +## Keras ഉപയോഗിച്ച് മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യുന്നു[[fine-tuning-the-model-with-keras]] + +Keras ഉപയോഗിക്കുന്ന യഥാർത്ഥ കോഡ് മുമ്പത്തേതിനോട് വളരെ സാമ്യമുള്ളതായിരിക്കും; ഡേറ്റ ഒരു ബാച്ചായി കൊളേറ്റ് ചെയ്യുന്ന രീതിയും മെട്രിക് കണക്കുകൂട്ടൽ ഫംഗ്‌ഷനും മാത്രമാണ് മാറ്റങ്ങൾ. + +{/if} + + +### ഡേറ്റാ കൊളേഷൻ[[data-collation]] + +[അധ്യായം 3](/course/chapter3)-ലേതുപോലെ ഒരു `DataCollatorWithPadding` അതേപടി ഉപയോഗിക്കാൻ നമുക്ക് കഴിയില്ല, കാരണം അത് ഇൻപുട്ടുകൾ (ഇൻപുട്ട് ID-കൾ, അറ്റൻഷൻ മാസ്‌ക്, ടോക്കൺ ടൈപ്പ് ID-കൾ) മാത്രമേ പാഡ് ചെയ്യുന്നുള്ളൂ. ഇവിടെ നമ്മുടെ ലേബലുകളും ഇൻപുട്ടുകളുടെ അതേ രീതിയിൽ തന്നെ പാഡ് ചെയ്യണം, അങ്ങനെ അവ ഒരേ വലിപ്പത്തിൽ തുടരും; ലോസ് കണക്കുകൂട്ടലിൽ അതിനോട് ബന്ധപ്പെട്ട പ്രവചനങ്ങൾ അവഗണിക്കപ്പെടാൻ വേണ്ടി `-100` ആണ് മൂല്യമായി ഉപയോഗിക്കുന്നത്. + +ഇതെല്ലാം ഒരു [`DataCollatorForTokenClassification`](https://huggingface.co/transformers/main_classes/data_collator.html#datacollatorfortokenclassification) ചെയ്യുന്നു. `DataCollatorWithPadding` പോലെ, ഇൻപുട്ടുകൾ പ്രീപ്രോസസ്സ് ചെയ്യാൻ ഉപയോഗിച്ച `tokenizer` ഇത് സ്വീകരിക്കുന്നു: + +{#if fw === 'pt'} + +```py +from transformers import DataCollatorForTokenClassification + +data_collator = DataCollatorForTokenClassification(tokenizer=tokenizer) +``` + +{:else} + +```py +from transformers import DataCollatorForTokenClassification + +data_collator = DataCollatorForTokenClassification( + tokenizer=tokenizer, return_tensors="tf" +) +``` + +{/if} + +ഏതാനും സാമ്പിളുകളിൽ ഇത് പരീക്ഷിക്കാൻ, നമ്മുടെ ടോക്കണൈസ് ചെയ്ത ട്രെയിനിംഗ് സെറ്റിലെ ഉദാഹരണങ്ങളുടെ ഒരു ലിസ്‌റ്റിൽ ഇത് വിളിച്ചാൽ മതി: + +```py +batch = data_collator([tokenized_datasets["train"][i] for i in range(2)]) +batch["labels"] +``` + +```python out +tensor([[-100, 3, 0, 7, 0, 0, 0, 7, 0, 0, 0, -100], + [-100, 1, 2, -100, -100, -100, -100, -100, -100, -100, -100, -100]]) +``` + +നമ്മുടെ ഡേറ്റാസെറ്റിലെ ഒന്നാമത്തെയും രണ്ടാമത്തെയും എലമെന്റുകളുടെ ലേബലുകളുമായി ഇത് താരതമ്യം ചെയ്യാം: + +```py +for i in range(2): + print(tokenized_datasets["train"][i]["labels"]) +``` + +```python out +[-100, 3, 0, 7, 0, 0, 0, 7, 0, 0, 0, -100] +[-100, 1, 2, -100] +``` + +{#if fw === 'pt'} + +നമുക്ക് കാണാവുന്നതുപോലെ, രണ്ടാമത്തെ ലേബൽ സെറ്റ് `-100`-കൾ ഉപയോഗിച്ച് ആദ്യത്തേതിന്റെ നീളത്തിലേക്ക് പാഡ് ചെയ്യപ്പെട്ടിരിക്കുന്നു. + +{:else} + +നമ്മുടെ ഡേറ്റാ കൊളേറ്റർ തയ്യാറായി! ഇപ്പോൾ `to_tf_dataset()` മെത്തേഡ് ഉപയോഗിച്ച് ഒരു `tf.data.Dataset` ഉണ്ടാക്കാൻ ഇത് ഉപയോഗിക്കാം. കുറച്ചുകൂടി കുറഞ്ഞ ബോയിലർപ്ലേറ്റ് കോഡിൽ ഇത് ചെയ്യാൻ `model.prepare_tf_dataset()` ഉപയോഗിക്കുകയും ചെയ്യാം — ഈ അധ്യായത്തിലെ മറ്റ് ചില ഭാഗങ്ങളിൽ ഇത് നിങ്ങൾ കാണും. + +```py +tf_train_dataset = tokenized_datasets["train"].to_tf_dataset( + columns=["attention_mask", "input_ids", "labels", "token_type_ids"], + collate_fn=data_collator, + shuffle=True, + batch_size=16, +) + +tf_eval_dataset = tokenized_datasets["validation"].to_tf_dataset( + columns=["attention_mask", "input_ids", "labels", "token_type_ids"], + collate_fn=data_collator, + shuffle=False, + batch_size=16, +) +``` + + + അടുത്ത ഘട്ടം: മോഡൽ തന്നെ. + +{/if} + +{#if fw === 'tf'} + +### മോഡൽ നിർവചിക്കുന്നു[[defining-the-model]] + +നമ്മൾ ഒരു ടോക്കൺ ക്ലാസിഫിക്കേഷൻ പ്രശ്നത്തിലാണ് പ്രവർത്തിക്കുന്നത് എന്നതിനാൽ, `TFAutoModelForTokenClassification` ക്ലാസ് നമ്മൾ ഉപയോഗിക്കും. ഈ മോഡൽ നിർവചിക്കുമ്പോൾ ഓർമ്മിക്കേണ്ട പ്രധാന കാര്യം, നമുക്കുള്ള ലേബലുകളുടെ എണ്ണത്തെക്കുറിച്ചുള്ള വിവരം കൈമാറുക എന്നതാണ്. ഇത് ചെയ്യാനുള്ള ഏറ്റവും എളുപ്പ വഴി `num_labels` ആർഗ്യുമെന്റ് ഉപയോഗിച്ച് ആ എണ്ണം നൽകുകയാണ്; എന്നാൽ ഈ ഭാഗത്തിന്റെ തുടക്കത്തിൽ കണ്ടതുപോലെ നന്നായി പ്രവർത്തിക്കുന്ന ഒരു ഇൻഫറൻസ് വിഡ്‌ജറ്റ് വേണമെങ്കിൽ, പകരം ശരിയായ ലേബൽ ബന്ധങ്ങൾ (label correspondences) സെറ്റ് ചെയ്യുന്നതാണ് നല്ലത്. + +ID-യിൽ നിന്ന് ലേബലിലേക്കും തിരിച്ചുമുള്ള മാപ്പിംഗ് ഉൾക്കൊള്ളുന്ന `id2label`, `label2id` എന്നീ രണ്ട് ഡിക്‌ഷണറികൾ ഉപയോഗിച്ചാണ് അവ സെറ്റ് ചെയ്യേണ്ടത്: + +```py +id2label = {i: label for i, label in enumerate(label_names)} +label2id = {v: k for k, v in id2label.items()} +``` + +ഇപ്പോൾ അവ `TFAutoModelForTokenClassification.from_pretrained()` മെത്തേഡിന് നൽകിയാൽ മതി; അവ മോഡലിന്റെ കോൺഫിഗറേഷനിൽ സെറ്റ് ചെയ്യപ്പെടുകയും, പിന്നീട് ശരിയായി സേവ് ചെയ്ത് Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യപ്പെടുകയും ചെയ്യും: + +```py +from transformers import TFAutoModelForTokenClassification + +model = TFAutoModelForTokenClassification.from_pretrained( + model_checkpoint, + id2label=id2label, + label2id=label2id, +) +``` + +[അധ്യായം 3](/course/chapter3)-ൽ നമ്മുടെ `TFAutoModelForSequenceClassification` നിർവചിച്ചപ്പോഴത്തേതുപോലെ, മോഡൽ ഉണ്ടാക്കുമ്പോൾ ചില വെയ്‌റ്റുകൾ ഉപയോഗിച്ചിട്ടില്ലെന്നും (പ്രീട്രെയിനിംഗ് ഹെഡിന്റേത്) മറ്റു ചില വെയ്‌റ്റുകൾ ക്രമരഹിതമായി ഇനിഷ്യലൈസ് ചെയ്യപ്പെട്ടിരിക്കുന്നു എന്നും (പുതിയ ടോക്കൺ ക്ലാസിഫിക്കേഷൻ ഹെഡിന്റേത്), ഈ മോഡൽ ട്രെയിൻ ചെയ്യണം എന്നും ഒരു മുന്നറിയിപ്പ് ലഭിക്കും. അത് നമ്മൾ ഉടൻ ചെയ്യും, എന്നാൽ ആദ്യം നമ്മുടെ മോഡലിന് ശരിയായ എണ്ണം ലേബലുകൾ ഉണ്ടെന്ന് ഒന്നുകൂടി ഉറപ്പാക്കാം: + +```python +model.config.num_labels +``` + +```python out +9 +``` + +> [!WARNING] +> ⚠️ തെറ്റായ എണ്ണം ലേബലുകളുള്ള ഒരു മോഡലാണ് നിങ്ങളുടേതെങ്കിൽ, പിന്നീട് `model.fit()` വിളിക്കുമ്പോൾ അവ്യക്തമായ ഒരു എറർ നിങ്ങൾക്ക് ലഭിക്കും. ഇത് ഡീബഗ് ചെയ്യാൻ ബുദ്ധിമുട്ടായിരിക്കാം; അതിനാൽ പ്രതീക്ഷിക്കുന്ന എണ്ണം ലേബലുകൾ ഉണ്ടെന്ന് സ്ഥിരീകരിക്കാൻ ഈ പരിശോധന നിങ്ങൾ തീർച്ചയായും ചെയ്യുക. + +### മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യുന്നു[[fine-tuning-the-model]] + +ഇപ്പോൾ നമ്മുടെ മോഡൽ ട്രെയിൻ ചെയ്യാൻ നമ്മൾ തയ്യാറാണ്! എന്നാൽ ആദ്യം ചെറിയ ചില ഒരുക്കങ്ങൾ കൂടി ബാക്കിയുണ്ട്: Hugging Face-ൽ ലോഗിൻ ചെയ്യുകയും നമ്മുടെ ട്രെയിനിംഗ് ഹൈപ്പർപാരാമീറ്ററുകൾ നിർവചിക്കുകയും വേണം. നിങ്ങൾ ഒരു നോട്ട്‌ബുക്കിലാണ് പ്രവർത്തിക്കുന്നതെങ്കിൽ, ഇതിന് നിങ്ങളെ സഹായിക്കുന്ന സൗകര്യപ്രദമായ ഒരു ഫംഗ്‌ഷൻ ഉണ്ട്: + +```python +from huggingface_hub import notebook_login + +notebook_login() +``` + +നിങ്ങളുടെ Hugging Face ലോഗിൻ വിവരങ്ങൾ (credentials) നൽകാവുന്ന ഒരു വിഡ്‌ജറ്റ് ഇത് കാണിക്കും. + +നിങ്ങൾ ഒരു നോട്ട്‌ബുക്കിലല്ല പ്രവർത്തിക്കുന്നതെങ്കിൽ, നിങ്ങളുടെ ടെർമിനലിൽ താഴെയുള്ള വരി ടൈപ്പ് ചെയ്താൽ മതി: + +```bash +huggingface-cli login +``` + +ലോഗിൻ ചെയ്ത ശേഷം, നമ്മുടെ മോഡൽ കംപൈൽ ചെയ്യാൻ ആവശ്യമായതെല്ലാം തയ്യാറാക്കാം. വെയ്‌റ്റ് ഡികേയ്‌ക്കും (weight decay) ലേണിംഗ് റേറ്റ് ഡികേയ്‌ക്കും അനുയോജ്യമായ സെറ്റിംഗുകളോടെ ഒരു `AdamW` ഒപ്‌റ്റിമൈസർ നിങ്ങൾക്ക് നൽകുന്ന സൗകര്യപ്രദമായ ഒരു `create_optimizer()` ഫംഗ്‌ഷൻ 🤗 Transformers നൽകുന്നു; ബിൽറ്റ്-ഇൻ `Adam` ഒപ്‌റ്റിമൈസറിനെ അപേക്ഷിച്ച് ഇവ രണ്ടും നിങ്ങളുടെ മോഡലിന്റെ പ്രകടനം മെച്ചപ്പെടുത്തും: + +```python +from transformers import create_optimizer +import tensorflow as tf + +# Train in mixed-precision float16 +# Comment this line out if you're using a GPU that will not benefit from this +tf.keras.mixed_precision.set_global_policy("mixed_float16") + +# The number of training steps is the number of samples in the dataset, divided by the batch size then multiplied +# by the total number of epochs. Note that the tf_train_dataset here is a batched tf.data.Dataset, +# not the original Hugging Face Dataset, so its len() is already num_samples // batch_size. +num_epochs = 3 +num_train_steps = len(tf_train_dataset) * num_epochs + +optimizer, schedule = create_optimizer( + init_lr=2e-5, + num_warmup_steps=0, + num_train_steps=num_train_steps, + weight_decay_rate=0.01, +) +model.compile(optimizer=optimizer) +``` + +`compile()`-ന് ഒരു `loss` ആർഗ്യുമെന്റ് നമ്മൾ നൽകുന്നില്ല എന്നതും ശ്രദ്ധിക്കുക. കാരണം, മോഡലുകൾക്ക് ആന്തരികമായി ലോസ് കണക്കാക്കാൻ കഴിയും — ലോസ് ഇല്ലാതെ കംപൈൽ ചെയ്യുകയും നിങ്ങളുടെ ലേബലുകൾ ഇൻപുട്ട് ഡിക്‌ഷണറിയിൽ നൽകുകയും ചെയ്താൽ (നമ്മുടെ ഡേറ്റാസെറ്റുകളിൽ നമ്മൾ ചെയ്യുന്നതുപോലെ), മോഡൽ ആ ആന്തരിക ലോസ് ഉപയോഗിച്ച് ട്രെയിൻ ചെയ്യും; നിങ്ങൾ തിരഞ്ഞെടുത്ത ടാസ്‌കിനും മോഡൽ ടൈപ്പിനും അനുയോജ്യമായതായിരിക്കും അത്. + +അടുത്തതായി, ട്രെയിനിംഗ് സമയത്ത് നമ്മുടെ മോഡൽ Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യാൻ ഒരു `PushToHubCallback` നിർവചിച്ച്, ആ കോൾബാക്കോടെ മോഡൽ ഫിറ്റ് ചെയ്യുന്നു: + +```python +from transformers.keras_callbacks import PushToHubCallback + +callback = PushToHubCallback(output_dir="bert-finetuned-ner", tokenizer=tokenizer) + +model.fit( + tf_train_dataset, + validation_data=tf_eval_dataset, + callbacks=[callback], + epochs=num_epochs, +) +``` + +നിങ്ങൾ പുഷ് ചെയ്യാൻ ആഗ്രഹിക്കുന്ന റിപ്പോസിറ്ററിയുടെ പൂർണ്ണമായ പേര് `hub_model_id` ആർഗ്യുമെന്റ് ഉപയോഗിച്ച് നിങ്ങൾക്ക് വ്യക്തമാക്കാം (പ്രത്യേകിച്ച്, ഒരു ഓർഗനൈസേഷനിലേക്ക് പുഷ് ചെയ്യാൻ ഈ ആർഗ്യുമെന്റ് നിങ്ങൾ ഉപയോഗിക്കേണ്ടിവരും). ഉദാഹരണത്തിന്, [`huggingface-course` ഓർഗനൈസേഷനിലേക്ക്](https://huggingface.co/huggingface-course) മോഡൽ പുഷ് ചെയ്തപ്പോൾ, ഞങ്ങൾ `hub_model_id="huggingface-course/bert-finetuned-ner"` ചേർത്തു. ഡിഫോൾട്ടായി, ഉപയോഗിക്കുന്ന റിപ്പോസിറ്ററി നിങ്ങളുടെ നെയിംസ്‌പേസിലായിരിക്കും, നിങ്ങൾ സെറ്റ് ചെയ്ത ഔട്ട്‌പുട്ട് ഡയറക്ടറിയുടെ പേരിലായിരിക്കും അത്; ഉദാഹരണത്തിന് `"cool_huggingface_user/bert-finetuned-ner"`. + +> [!TIP] +> 💡 നിങ്ങൾ ഉപയോഗിക്കുന്ന ഔട്ട്‌പുട്ട് ഡയറക്ടറി ഇതിനകം നിലവിലുണ്ടെങ്കിൽ, അത് നിങ്ങൾ പുഷ് ചെയ്യാൻ ആഗ്രഹിക്കുന്ന റിപ്പോസിറ്ററിയുടെ ഒരു ലോക്കൽ ക്ലോൺ ആയിരിക്കണം. അല്ലെങ്കിൽ, `model.fit()` വിളിക്കുമ്പോൾ ഒരു എറർ ലഭിക്കും, പുതിയ ഒരു പേര് സെറ്റ് ചെയ്യേണ്ടിവരും. + +ട്രെയിനിംഗ് നടക്കുമ്പോൾ, ഓരോ തവണ മോഡൽ സേവ് ചെയ്യപ്പെടുമ്പോഴും (ഇവിടെ, ഓരോ എപ്പോക്കിലും) അത് പശ്ചാത്തലത്തിൽ Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യപ്പെടുന്നു എന്നത് ശ്രദ്ധിക്കുക. ഇങ്ങനെ, ആവശ്യമെങ്കിൽ മറ്റൊരു മെഷീനിൽ നിങ്ങളുടെ ട്രെയിനിംഗ് പുനരാരംഭിക്കാൻ നിങ്ങൾക്ക് കഴിയും. + +ഈ ഘട്ടത്തിൽ, Model Hub-ലെ ഇൻഫറൻസ് വിഡ്‌ജറ്റ് ഉപയോഗിച്ച് നിങ്ങളുടെ മോഡൽ പരീക്ഷിക്കാനും സുഹൃത്തുക്കളുമായി പങ്കുവയ്ക്കാനും കഴിയും. ഒരു ടോക്കൺ ക്ലാസിഫിക്കേഷൻ ടാസ്‌കിൽ നിങ്ങൾ വിജയകരമായി ഒരു മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്തു — അഭിനന്ദനങ്ങൾ! എന്നാൽ നമ്മുടെ മോഡൽ ശരിക്കും എത്ര മികച്ചതാണ്? അത് അറിയാൻ ചില മെട്രിക്കുകൾ നമ്മൾ ഇവാല്യുവേറ്റ് ചെയ്യണം. + +{/if} + + +### മെട്രിക്കുകൾ[[metrics]] + +{#if fw === 'pt'} + +ഓരോ എപ്പോക്കിലും `Trainer` ഒരു മെട്രിക് കണക്കാക്കണമെങ്കിൽ, പ്രവചനങ്ങളുടെയും ലേബലുകളുടെയും അറേകൾ സ്വീകരിച്ച്, മെട്രിക്കുകളുടെ പേരുകളും മൂല്യങ്ങളുമുള്ള ഒരു ഡിക്‌ഷണറി റിട്ടേൺ ചെയ്യുന്ന ഒരു `compute_metrics()` ഫംഗ്‌ഷൻ നമ്മൾ നിർവചിക്കേണ്ടതുണ്ട്. + +ടോക്കൺ ക്ലാസിഫിക്കേഷൻ പ്രവചനങ്ങൾ ഇവാല്യുവേറ്റ് ചെയ്യാൻ പരമ്പരാഗതമായി ഉപയോഗിക്കുന്ന ഫ്രെയിംവർക്ക് [*seqeval*](https://github.com/chakki-works/seqeval) ആണ്. ഈ മെട്രിക് ഉപയോഗിക്കാൻ, ആദ്യം *seqeval* ലൈബ്രറി നമ്മൾ ഇൻസ്‌റ്റാൾ ചെയ്യണം: + +```py +!pip install seqeval +``` + +പിന്നീട് [അധ്യായം 3](/course/chapter3)-ൽ ചെയ്തതുപോലെ `evaluate.load()` ഫംഗ്‌ഷൻ വഴി ഇത് ലോഡ് ചെയ്യാം: + +{:else} + +ടോക്കൺ ക്ലാസിഫിക്കേഷൻ പ്രവചനങ്ങൾ ഇവാല്യുവേറ്റ് ചെയ്യാൻ പരമ്പരാഗതമായി ഉപയോഗിക്കുന്ന ഫ്രെയിംവർക്ക് [*seqeval*](https://github.com/chakki-works/seqeval) ആണ്. ഈ മെട്രിക് ഉപയോഗിക്കാൻ, ആദ്യം *seqeval* ലൈബ്രറി നമ്മൾ ഇൻസ്‌റ്റാൾ ചെയ്യണം: + +```py +!pip install seqeval +``` + +പിന്നീട് [അധ്യായം 3](/course/chapter3)-ൽ ചെയ്തതുപോലെ `evaluate.load()` ഫംഗ്‌ഷൻ വഴി ഇത് ലോഡ് ചെയ്യാം: + +{/if} + +```py +import evaluate + +metric = evaluate.load("seqeval") +``` + +ഈ മെട്രിക് സാധാരണ അക്യുറസി (accuracy) പോലെയല്ല പ്രവർത്തിക്കുന്നത്: ഇത് ലേബലുകളുടെ ലിസ്‌റ്റുകൾ ഇന്റിജറുകളായല്ല, സ്‌ട്രിംഗുകളായാണ് സ്വീകരിക്കുന്നത്; അതിനാൽ മെട്രിക്കിന് നൽകുന്നതിന് മുമ്പ് പ്രവചനങ്ങളും ലേബലുകളും നമ്മൾ പൂർണ്ണമായി ഡീകോഡ് ചെയ്യേണ്ടതുണ്ട്. ഇത് എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് നോക്കാം. ആദ്യം, നമ്മുടെ ആദ്യത്തെ ട്രെയിനിംഗ് ഉദാഹരണത്തിന്റെ ലേബലുകൾ എടുക്കാം: + +```py +labels = raw_datasets["train"][0]["ner_tags"] +labels = [label_names[i] for i in labels] +labels +``` + +```python out +['B-ORG', 'O', 'B-MISC', 'O', 'O', 'O', 'B-MISC', 'O', 'O'] +``` + +പിന്നീട് ഇൻഡെക്‌സ് 2-ലെ മൂല്യം മാത്രം മാറ്റിക്കൊണ്ട് അവയ്ക്കായി വ്യാജ പ്രവചനങ്ങൾ ഉണ്ടാക്കാം: + +```py +predictions = labels.copy() +predictions[2] = "O" +metric.compute(predictions=[predictions], references=[labels]) +``` + +മെട്രിക് പ്രവചനങ്ങളുടെ ഒരു ലിസ്‌റ്റും (ഒന്ന് മാത്രമല്ല) ലേബലുകളുടെ ഒരു ലിസ്‌റ്റുമാണ് സ്വീകരിക്കുന്നത് എന്നത് ശ്രദ്ധിക്കുക. ഔട്ട്‌പുട്ട് ഇതാ: + +```python out +{'MISC': {'precision': 1.0, 'recall': 0.5, 'f1': 0.67, 'number': 2}, + 'ORG': {'precision': 1.0, 'recall': 1.0, 'f1': 1.0, 'number': 1}, + 'overall_precision': 1.0, + 'overall_recall': 0.67, + 'overall_f1': 0.8, + 'overall_accuracy': 0.89} +``` + +{#if fw === 'pt'} + +ഇത് ധാരാളം വിവരങ്ങൾ തിരികെ നൽകുന്നു! ഓരോ എന്റിറ്റിക്കും വെവ്വേറെയും, മൊത്തത്തിലുമുള്ള പ്രിസിഷൻ (precision), റീകോൾ (recall), F1 സ്‌കോർ എന്നിവ നമുക്ക് ലഭിക്കുന്നു. നമ്മുടെ മെട്രിക് കണക്കുകൂട്ടലിനായി മൊത്തത്തിലുള്ള സ്‌കോർ മാത്രമേ നമ്മൾ നിലനിർത്തുകയുള്ളൂ; എന്നാൽ നിങ്ങൾക്ക് റിപ്പോർട്ട് ചെയ്യണമെന്നുള്ള എല്ലാ മെട്രിക്കുകളും റിട്ടേൺ ചെയ്യുന്ന തരത്തിൽ `compute_metrics()` ഫംഗ്‌ഷൻ മാറ്റാൻ മടിക്കേണ്ടതില്ല. + +ഈ `compute_metrics()` ഫംഗ്‌ഷൻ ആദ്യം ലോജിറ്റുകളുടെ argmax എടുത്ത് അവയെ പ്രവചനങ്ങളാക്കി മാറ്റുന്നു (പതിവുപോലെ, ലോജിറ്റുകളും പ്രോബബിലിറ്റികളും ഒരേ ക്രമത്തിലാണ്, അതിനാൽ softmax പ്രയോഗിക്കേണ്ട ആവശ്യമില്ല). പിന്നീട് ലേബലുകളെയും പ്രവചനങ്ങളെയും ഇന്റിജറുകളിൽ നിന്ന് സ്‌ട്രിംഗുകളാക്കി മാറ്റണം. ലേബൽ `-100` ആയിട്ടുള്ള എല്ലാ മൂല്യങ്ങളും നമ്മൾ നീക്കം ചെയ്യുന്നു, പിന്നീട് ഫലങ്ങൾ `metric.compute()` മെത്തേഡിന് നൽകുന്നു: + +```py +import numpy as np + + +def compute_metrics(eval_preds): + logits, labels = eval_preds + predictions = np.argmax(logits, axis=-1) + + # Remove ignored index (special tokens) and convert to labels + true_labels = [[label_names[l] for l in label if l != -100] for label in labels] + true_predictions = [ + [label_names[p] for (p, l) in zip(prediction, label) if l != -100] + for prediction, label in zip(predictions, labels) + ] + all_metrics = metric.compute(predictions=true_predictions, references=true_labels) + return { + "precision": all_metrics["overall_precision"], + "recall": all_metrics["overall_recall"], + "f1": all_metrics["overall_f1"], + "accuracy": all_metrics["overall_accuracy"], + } +``` + +ഇത് പൂർത്തിയായ സ്ഥിതിക്ക്, നമ്മുടെ `Trainer` നിർവചിക്കാൻ നമ്മൾ ഏറെക്കുറെ തയ്യാറാണ്. ഫൈൻ-ട്യൂൻ ചെയ്യാൻ ഒരു `model` മാത്രമേ ഇനി വേണ്ടത്! + +{:else} + +ഇത് ധാരാളം വിവരങ്ങൾ തിരികെ നൽകുന്നു! ഓരോ എന്റിറ്റിക്കും വെവ്വേറെയും, മൊത്തത്തിലുമുള്ള പ്രിസിഷൻ (precision), റീകോൾ (recall), F1 സ്‌കോർ എന്നിവ നമുക്ക് ലഭിക്കുന്നു. ഇപ്പോൾ, നമ്മുടെ യഥാർത്ഥ മോഡൽ പ്രവചനങ്ങൾ ഉപയോഗിച്ച് ചില യഥാർത്ഥ സ്‌കോറുകൾ കണക്കാക്കാൻ ശ്രമിച്ചാൽ എന്ത് സംഭവിക്കുമെന്ന് നോക്കാം. + +നമ്മുടെ പ്രവചനങ്ങൾക്ക് വ്യത്യസ്ത സീക്വൻസ് നീളങ്ങൾ ഉള്ളതിനാൽ, അവയെ ഒന്നിച്ച് കൂട്ടിച്ചേർക്കുന്നത് (concatenate) TensorFlow-ന് ഇഷ്ടമല്ല. അതായത്, `model.predict()` അതേപടി ഉപയോഗിക്കാൻ നമുക്ക് കഴിയില്ല — എന്നാൽ അത് നമ്മളെ തടയാൻ പോകുന്നില്ല. ഓരോ തവണയും ഒരു ബാച്ച് വീതം പ്രവചനങ്ങൾ എടുത്ത്, മാസ്‌കിംഗ്/പാഡിംഗ് സൂചിപ്പിക്കുന്ന `-100` ടോക്കണുകൾ ഒഴിവാക്കിക്കൊണ്ട്, അവയെ ഒരു വലിയ നീണ്ട ലിസ്‌റ്റായി കൂട്ടിച്ചേർത്തുകൊണ്ടുപോകും; അവസാനം ആ ലിസ്‌റ്റിൽ മെട്രിക്കുകൾ കണക്കാക്കും: + +```py +import numpy as np + +all_predictions = [] +all_labels = [] +for batch in tf_eval_dataset: + logits = model.predict_on_batch(batch)["logits"] + labels = batch["labels"] + predictions = np.argmax(logits, axis=-1) + for prediction, label in zip(predictions, labels): + for predicted_idx, label_idx in zip(prediction, label): + if label_idx == -100: + continue + all_predictions.append(label_names[predicted_idx]) + all_labels.append(label_names[label_idx]) +metric.compute(predictions=[all_predictions], references=[all_labels]) +``` + + +```python out +{'LOC': {'precision': 0.91, 'recall': 0.92, 'f1': 0.91, 'number': 1668}, + 'MISC': {'precision': 0.70, 'recall': 0.79, 'f1': 0.74, 'number': 702}, + 'ORG': {'precision': 0.85, 'recall': 0.90, 'f1': 0.88, 'number': 1661}, + 'PER': {'precision': 0.95, 'recall': 0.95, 'f1': 0.95, 'number': 1617}, + 'overall_precision': 0.87, + 'overall_recall': 0.91, + 'overall_f1': 0.89, + 'overall_accuracy': 0.97} +``` + +ഞങ്ങളുടേതുമായി താരതമ്യം ചെയ്യുമ്പോൾ നിങ്ങളുടെ മോഡൽ എങ്ങനെ പ്രവർത്തിച്ചു? സമാനമായ സംഖ്യകളാണ് നിങ്ങൾക്ക് ലഭിച്ചതെങ്കിൽ, നിങ്ങളുടെ ട്രെയിനിംഗ് വിജയമായിരുന്നു! + +{/if} + +{#if fw === 'pt'} + +### മോഡൽ നിർവചിക്കുന്നു[[defining-the-model]] + +നമ്മൾ ഒരു ടോക്കൺ ക്ലാസിഫിക്കേഷൻ പ്രശ്നത്തിലാണ് പ്രവർത്തിക്കുന്നത് എന്നതിനാൽ, `AutoModelForTokenClassification` ക്ലാസ് നമ്മൾ ഉപയോഗിക്കും. ഈ മോഡൽ നിർവചിക്കുമ്പോൾ ഓർമ്മിക്കേണ്ട പ്രധാന കാര്യം, നമുക്കുള്ള ലേബലുകളുടെ എണ്ണത്തെക്കുറിച്ചുള്ള വിവരം കൈമാറുക എന്നതാണ്. ഇത് ചെയ്യാനുള്ള ഏറ്റവും എളുപ്പ വഴി `num_labels` ആർഗ്യുമെന്റ് ഉപയോഗിച്ച് ആ എണ്ണം നൽകുകയാണ്; എന്നാൽ ഈ ഭാഗത്തിന്റെ തുടക്കത്തിൽ കണ്ടതുപോലെ നന്നായി പ്രവർത്തിക്കുന്ന ഒരു ഇൻഫറൻസ് വിഡ്‌ജറ്റ് വേണമെങ്കിൽ, പകരം ശരിയായ ലേബൽ ബന്ധങ്ങൾ (label correspondences) സെറ്റ് ചെയ്യുന്നതാണ് നല്ലത്. + +ID-യിൽ നിന്ന് ലേബലിലേക്കും തിരിച്ചുമുള്ള മാപ്പിംഗുകൾ ഉൾക്കൊള്ളുന്ന `id2label`, `label2id` എന്നീ രണ്ട് ഡിക്‌ഷണറികൾ ഉപയോഗിച്ചാണ് അവ സെറ്റ് ചെയ്യേണ്ടത്: + +```py +id2label = {i: label for i, label in enumerate(label_names)} +label2id = {v: k for k, v in id2label.items()} +``` + +ഇപ്പോൾ അവ `AutoModelForTokenClassification.from_pretrained()` മെത്തേഡിന് നൽകിയാൽ മതി; അവ മോഡലിന്റെ കോൺഫിഗറേഷനിൽ സെറ്റ് ചെയ്യപ്പെടുകയും, പിന്നീട് ശരിയായി സേവ് ചെയ്ത് Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യപ്പെടുകയും ചെയ്യും: + +```py +from transformers import AutoModelForTokenClassification + +model = AutoModelForTokenClassification.from_pretrained( + model_checkpoint, + id2label=id2label, + label2id=label2id, +) +``` + +[അധ്യായം 3](/course/chapter3)-ൽ നമ്മുടെ `AutoModelForSequenceClassification` നിർവചിച്ചപ്പോഴത്തേതുപോലെ, മോഡൽ ഉണ്ടാക്കുമ്പോൾ ചില വെയ്‌റ്റുകൾ ഉപയോഗിച്ചിട്ടില്ലെന്നും (പ്രീട്രെയിനിംഗ് ഹെഡിന്റേത്) മറ്റു ചില വെയ്‌റ്റുകൾ ക്രമരഹിതമായി ഇനിഷ്യലൈസ് ചെയ്യപ്പെട്ടിരിക്കുന്നു എന്നും (പുതിയ ടോക്കൺ ക്ലാസിഫിക്കേഷൻ ഹെഡിന്റേത്), ഈ മോഡൽ ട്രെയിൻ ചെയ്യണം എന്നും ഒരു മുന്നറിയിപ്പ് ലഭിക്കും. അത് നമ്മൾ ഉടൻ ചെയ്യും, എന്നാൽ ആദ്യം നമ്മുടെ മോഡലിന് ശരിയായ എണ്ണം ലേബലുകൾ ഉണ്ടെന്ന് ഒന്നുകൂടി ഉറപ്പാക്കാം: + +```python +model.config.num_labels +``` + +```python out +9 +``` + +> [!WARNING] +> ⚠️ തെറ്റായ എണ്ണം ലേബലുകളുള്ള ഒരു മോഡലാണ് നിങ്ങളുടേതെങ്കിൽ, പിന്നീട് `Trainer.train()` മെത്തേഡ് വിളിക്കുമ്പോൾ അവ്യക്തമായ ഒരു എറർ നിങ്ങൾക്ക് ലഭിക്കും ("CUDA error: device-side assert triggered" എന്നതുപോലെ എന്തെങ്കിലും). ഇത്തരം എററുകൾക്ക് ഉപയോക്താക്കൾ റിപ്പോർട്ട് ചെയ്യുന്ന ബഗുകളുടെ ഒന്നാമത്തെ കാരണം ഇതാണ്; അതിനാൽ പ്രതീക്ഷിക്കുന്ന എണ്ണം ലേബലുകൾ ഉണ്ടെന്ന് സ്ഥിരീകരിക്കാൻ ഈ പരിശോധന നിങ്ങൾ തീർച്ചയായും ചെയ്യുക. + +### മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യുന്നു[[fine-tuning-the-model]] + +ഇപ്പോൾ നമ്മുടെ മോഡൽ ട്രെയിൻ ചെയ്യാൻ നമ്മൾ തയ്യാറാണ്! നമ്മുടെ `Trainer` നിർവചിക്കുന്നതിന് മുമ്പ് അവസാനത്തെ രണ്ട് കാര്യങ്ങൾ മാത്രം ചെയ്യാനുണ്ട്: Hugging Face-ൽ ലോഗിൻ ചെയ്യുക, നമ്മുടെ ട്രെയിനിംഗ് ആർഗ്യുമെന്റുകൾ നിർവചിക്കുക. നിങ്ങൾ ഒരു നോട്ട്‌ബുക്കിലാണ് പ്രവർത്തിക്കുന്നതെങ്കിൽ, ഇതിന് നിങ്ങളെ സഹായിക്കുന്ന സൗകര്യപ്രദമായ ഒരു ഫംഗ്‌ഷൻ ഉണ്ട്: + +```python +from huggingface_hub import notebook_login + +notebook_login() +``` + +നിങ്ങളുടെ Hugging Face ലോഗിൻ വിവരങ്ങൾ (credentials) നൽകാവുന്ന ഒരു വിഡ്‌ജറ്റ് ഇത് കാണിക്കും. + +നിങ്ങൾ ഒരു നോട്ട്‌ബുക്കിലല്ല പ്രവർത്തിക്കുന്നതെങ്കിൽ, നിങ്ങളുടെ ടെർമിനലിൽ താഴെയുള്ള വരി ടൈപ്പ് ചെയ്താൽ മതി: + +```bash +huggingface-cli login +``` + +ഇത് പൂർത്തിയായാൽ, നമ്മുടെ `TrainingArguments` നിർവചിക്കാം: + +```python +from transformers import TrainingArguments + +args = TrainingArguments( + "bert-finetuned-ner", + evaluation_strategy="epoch", + save_strategy="epoch", + learning_rate=2e-5, + num_train_epochs=3, + weight_decay=0.01, + push_to_hub=True, +) +``` + +ഇവയിൽ മിക്കതും നിങ്ങൾ മുമ്പ് കണ്ടിട്ടുണ്ട്: ചില ഹൈപ്പർപാരാമീറ്ററുകൾ (ലേണിംഗ് റേറ്റ്, ട്രെയിൻ ചെയ്യേണ്ട എപ്പോക്കുകളുടെ എണ്ണം, വെയ്‌റ്റ് ഡികേ എന്നിവ പോലുള്ളവ) നമ്മൾ സെറ്റ് ചെയ്യുന്നു; കൂടാതെ ഓരോ എപ്പോക്കിന്റെയും അവസാനം മോഡൽ സേവ് ചെയ്ത് ഇവാല്യുവേറ്റ് ചെയ്യണമെന്നും നമ്മുടെ ഫലങ്ങൾ Model Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യണമെന്നും സൂചിപ്പിക്കാൻ `push_to_hub=True` എന്ന് വ്യക്തമാക്കുന്നു. നിങ്ങൾ പുഷ് ചെയ്യാൻ ആഗ്രഹിക്കുന്ന റിപ്പോസിറ്ററിയുടെ പേര് `hub_model_id` ആർഗ്യുമെന്റ് ഉപയോഗിച്ച് വ്യക്തമാക്കാം എന്നത് ശ്രദ്ധിക്കുക (പ്രത്യേകിച്ച്, ഒരു ഓർഗനൈസേഷനിലേക്ക് പുഷ് ചെയ്യാൻ ഈ ആർഗ്യുമെന്റ് നിങ്ങൾ ഉപയോഗിക്കേണ്ടിവരും). ഉദാഹരണത്തിന്, [`huggingface-course` ഓർഗനൈസേഷനിലേക്ക്](https://huggingface.co/huggingface-course) മോഡൽ പുഷ് ചെയ്തപ്പോൾ, ഞങ്ങൾ `TrainingArguments`-ൽ `hub_model_id="huggingface-course/bert-finetuned-ner"` ചേർത്തു. ഡിഫോൾട്ടായി, ഉപയോഗിക്കുന്ന റിപ്പോസിറ്ററി നിങ്ങളുടെ നെയിംസ്‌പേസിലായിരിക്കും, നിങ്ങൾ സെറ്റ് ചെയ്ത ഔട്ട്‌പുട്ട് ഡയറക്ടറിയുടെ പേരിലായിരിക്കും അത്; അതിനാൽ നമ്മുടെ കാര്യത്തിൽ അത് `"sgugger/bert-finetuned-ner"` ആയിരിക്കും. + +> [!TIP] +> 💡 നിങ്ങൾ ഉപയോഗിക്കുന്ന ഔട്ട്‌പുട്ട് ഡയറക്ടറി ഇതിനകം നിലവിലുണ്ടെങ്കിൽ, അത് നിങ്ങൾ പുഷ് ചെയ്യാൻ ആഗ്രഹിക്കുന്ന റിപ്പോസിറ്ററിയുടെ ഒരു ലോക്കൽ ക്ലോൺ ആയിരിക്കണം. അല്ലെങ്കിൽ, നിങ്ങളുടെ `Trainer` നിർവചിക്കുമ്പോൾ ഒരു എറർ ലഭിക്കും, പുതിയ ഒരു പേര് സെറ്റ് ചെയ്യേണ്ടിവരും. + +അവസാനമായി, എല്ലാം `Trainer`-ന് നൽകി ട്രെയിനിംഗ് ആരംഭിക്കുന്നു: + +```python +from transformers import Trainer + +trainer = Trainer( + model=model, + args=args, + train_dataset=tokenized_datasets["train"], + eval_dataset=tokenized_datasets["validation"], + data_collator=data_collator, + compute_metrics=compute_metrics, + processing_class=tokenizer, +) +trainer.train() +``` + +ട്രെയിനിംഗ് നടക്കുമ്പോൾ, ഓരോ തവണ മോഡൽ സേവ് ചെയ്യപ്പെടുമ്പോഴും (ഇവിടെ, ഓരോ എപ്പോക്കിലും) അത് പശ്ചാത്തലത്തിൽ Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യപ്പെടുന്നു എന്നത് ശ്രദ്ധിക്കുക. ഇങ്ങനെ, ആവശ്യമെങ്കിൽ മറ്റൊരു മെഷീനിൽ നിങ്ങളുടെ ട്രെയിനിംഗ് പുനരാരംഭിക്കാൻ നിങ്ങൾക്ക് കഴിയും. + +ട്രെയിനിംഗ് പൂർത്തിയായിക്കഴിഞ്ഞാൽ, മോഡലിന്റെ ഏറ്റവും പുതിയ പതിപ്പ് അപ്‌ലോഡ് ചെയ്യുന്നു എന്ന് ഉറപ്പാക്കാൻ `push_to_hub()` മെത്തേഡ് നമ്മൾ ഉപയോഗിക്കുന്നു: + +```py +trainer.push_to_hub(commit_message="Training complete") +``` + +ഈ കമാൻഡ് അത് ഇപ്പോൾ ചെയ്ത കമ്മിറ്റിന്റെ URL റിട്ടേൺ ചെയ്യുന്നു; നിങ്ങൾക്ക് അത് പരിശോധിക്കണമെങ്കിൽ ഉപയോഗിക്കാം: + +```python out +'https://huggingface.co/sgugger/bert-finetuned-ner/commit/26ab21e5b1568f9afeccdaed2d8715f571d786ed' +``` + +എല്ലാ ഇവാല്യുവേഷൻ ഫലങ്ങളോടും കൂടിയ ഒരു മോഡൽ കാർഡ് `Trainer` തയ്യാറാക്കി അപ്‌ലോഡ് ചെയ്യുകയും ചെയ്യുന്നു. ഈ ഘട്ടത്തിൽ, Model Hub-ലെ ഇൻഫറൻസ് വിഡ്‌ജറ്റ് ഉപയോഗിച്ച് നിങ്ങളുടെ മോഡൽ പരീക്ഷിക്കാനും സുഹൃത്തുക്കളുമായി പങ്കുവയ്ക്കാനും കഴിയും. ഒരു ടോക്കൺ ക്ലാസിഫിക്കേഷൻ ടാസ്‌കിൽ നിങ്ങൾ വിജയകരമായി ഒരു മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്തു — അഭിനന്ദനങ്ങൾ! + +ട്രെയിനിംഗ് ലൂപ്പിലേക്ക് കുറച്ചുകൂടി ആഴത്തിൽ ഇറങ്ങണമെങ്കിൽ, 🤗 Accelerate ഉപയോഗിച്ച് ഇതേ കാര്യം എങ്ങനെ ചെയ്യാമെന്ന് ഇപ്പോൾ ഞങ്ങൾ കാണിച്ചുതരാം. + +## ഒരു കസ്‌റ്റം ട്രെയിനിംഗ് ലൂപ്പ്[[a-custom-training-loop]] + +ഇപ്പോൾ പൂർണ്ണമായ ട്രെയിനിംഗ് ലൂപ്പ് നോക്കാം, അങ്ങനെ നിങ്ങൾക്ക് ആവശ്യമുള്ള ഭാഗങ്ങൾ എളുപ്പത്തിൽ ഇഷ്ടാനുസൃതമാക്കാം. ഇവാല്യുവേഷനുള്ള ഏതാനും മാറ്റങ്ങളൊഴിച്ചാൽ, [അധ്യായം 3](/course/chapter3/4)-ൽ നമ്മൾ ചെയ്തതിനോട് ഇത് വളരെ സാമ്യമുള്ളതായിരിക്കും. + +### ട്രെയിനിംഗിനായി എല്ലാം തയ്യാറാക്കുന്നു[[preparing-everything-for-training]] + +ആദ്യം നമ്മുടെ ഡേറ്റാസെറ്റുകളിൽ നിന്ന് `DataLoader`-കൾ നിർമ്മിക്കണം. നമ്മുടെ `data_collator` ഒരു `collate_fn` ആയി വീണ്ടും ഉപയോഗിക്കുകയും ട്രെയിനിംഗ് സെറ്റ് ഷഫിൾ ചെയ്യുകയും ചെയ്യും, എന്നാൽ വാലിഡേഷൻ സെറ്റ് ഷഫിൾ ചെയ്യില്ല: + +```py +from torch.utils.data import DataLoader + +train_dataloader = DataLoader( + tokenized_datasets["train"], + shuffle=True, + collate_fn=data_collator, + batch_size=8, +) +eval_dataloader = DataLoader( + tokenized_datasets["validation"], collate_fn=data_collator, batch_size=8 +) +``` + +അടുത്തതായി, മുമ്പത്തെ ഫൈൻ-ട്യൂണിംഗ് തുടരുകയല്ല, BERT പ്രീട്രെയിൻഡ് മോഡലിൽ നിന്ന് വീണ്ടും ആരംഭിക്കുകയാണ് എന്ന് ഉറപ്പാക്കാൻ, നമ്മുടെ മോഡൽ വീണ്ടും ഇൻസ്‌റ്റാൻഷിയേറ്റ് ചെയ്യുന്നു: + +```py +model = AutoModelForTokenClassification.from_pretrained( + model_checkpoint, + id2label=id2label, + label2id=label2id, +) +``` + +പിന്നീട് നമുക്ക് ഒരു ഒപ്‌റ്റിമൈസർ വേണം. ക്ലാസിക് `AdamW` നമ്മൾ ഉപയോഗിക്കും; ഇത് `Adam` പോലെയാണ്, എന്നാൽ വെയ്‌റ്റ് ഡികേ പ്രയോഗിക്കുന്ന രീതിയിൽ ഒരു തിരുത്തലുണ്ട്: + +```py +from torch.optim import AdamW + +optimizer = AdamW(model.parameters(), lr=2e-5) +``` + +ആ ഒബ്‌ജക്റ്റുകളെല്ലാം ലഭിച്ചുകഴിഞ്ഞാൽ, അവയെ `accelerator.prepare()` മെത്തേഡിലേക്ക് അയയ്ക്കാം: + +```py +from accelerate import Accelerator + +accelerator = Accelerator() +model, optimizer, train_dataloader, eval_dataloader = accelerator.prepare( + model, optimizer, train_dataloader, eval_dataloader +) +``` + +> [!TIP] +> 🚨 നിങ്ങൾ ഒരു TPU-വിലാണ് ട്രെയിൻ ചെയ്യുന്നതെങ്കിൽ, മുകളിലെ സെല്ലിൽ നിന്ന് തുടങ്ങുന്ന എല്ലാ കോഡും ഒരു പ്രത്യേക ട്രെയിനിംഗ് ഫംഗ്‌ഷനിലേക്ക് മാറ്റേണ്ടിവരും. കൂടുതൽ വിവരങ്ങൾക്ക് [അധ്യായം 3](/course/chapter3) കാണുക. + +നമ്മുടെ `train_dataloader` `accelerator.prepare()`-ലേക്ക് അയച്ചുകഴിഞ്ഞ സ്ഥിതിക്ക്, ട്രെയിനിംഗ് സ്‌റ്റെപ്പുകളുടെ എണ്ണം കണക്കാക്കാൻ അതിന്റെ നീളം ഉപയോഗിക്കാം. ഡേറ്റാലോഡർ പ്രിപ്പയർ ചെയ്ത ശേഷം മാത്രമേ ഇത് എപ്പോഴും ചെയ്യാവൂ എന്ന് ഓർക്കുക, കാരണം ആ മെത്തേഡ് അതിന്റെ നീളം മാറ്റും. ലേണിംഗ് റേറ്റിൽ നിന്ന് 0-ലേക്കുള്ള ക്ലാസിക് ലീനിയർ ഷെഡ്യൂൾ നമ്മൾ ഉപയോഗിക്കുന്നു: + +```py +from transformers import get_scheduler + +num_train_epochs = 3 +num_update_steps_per_epoch = len(train_dataloader) +num_training_steps = num_train_epochs * num_update_steps_per_epoch + +lr_scheduler = get_scheduler( + "linear", + optimizer=optimizer, + num_warmup_steps=0, + num_training_steps=num_training_steps, +) +``` + +അവസാനമായി, നമ്മുടെ മോഡൽ Hub-ലേക്ക് പുഷ് ചെയ്യാൻ, ഒരു വർക്കിംഗ് ഫോൾഡറിൽ ഒരു `Repository` ഒബ്‌ജക്റ്റ് ഉണ്ടാക്കേണ്ടതുണ്ട്. ഇതിനകം ലോഗിൻ ചെയ്തിട്ടില്ലെങ്കിൽ, ആദ്യം Hugging Face-ൽ ലോഗിൻ ചെയ്യുക. നമ്മുടെ മോഡലിന് നൽകാൻ ആഗ്രഹിക്കുന്ന മോഡൽ ID-യിൽ നിന്ന് റിപ്പോസിറ്ററിയുടെ പേര് നമ്മൾ നിർണ്ണയിക്കും (`repo_name` നിങ്ങളുടെ ഇഷ്ടപ്രകാരം മാറ്റാൻ മടിക്കേണ്ടതില്ല; അതിൽ നിങ്ങളുടെ യൂസർനെയിം ഉണ്ടായിരിക്കണം എന്ന് മാത്രം, `get_full_repo_name()` എന്ന ഫംഗ്‌ഷൻ ചെയ്യുന്നത് അതാണ്): + +```py +from huggingface_hub import Repository, get_full_repo_name + +model_name = "bert-finetuned-ner-accelerate" +repo_name = get_full_repo_name(model_name) +repo_name +``` + +```python out +'sgugger/bert-finetuned-ner-accelerate' +``` + +പിന്നീട് ആ റിപ്പോസിറ്ററി ഒരു ലോക്കൽ ഫോൾഡറിലേക്ക് ക്ലോൺ ചെയ്യാം. അത് ഇതിനകം നിലവിലുണ്ടെങ്കിൽ, ഈ ലോക്കൽ ഫോൾഡർ നമ്മൾ പ്രവർത്തിക്കുന്ന റിപ്പോസിറ്ററിയുടെ നിലവിലുള്ള ഒരു ക്ലോൺ ആയിരിക്കണം: + +```py +output_dir = "bert-finetuned-ner-accelerate" +repo = Repository(output_dir, clone_from=repo_name) +``` + +`repo.push_to_hub()` മെത്തേഡ് വിളിച്ചുകൊണ്ട്, `output_dir`-ൽ നമ്മൾ സേവ് ചെയ്യുന്ന എന്തും ഇപ്പോൾ അപ്‌ലോഡ് ചെയ്യാം. ഓരോ എപ്പോക്കിന്റെയും അവസാനം ഇടക്കാല മോഡലുകൾ അപ്‌ലോഡ് ചെയ്യാൻ ഇത് നമ്മളെ സഹായിക്കും. + +### ട്രെയിനിംഗ് ലൂപ്പ്[[training-loop]] + +ഇപ്പോൾ പൂർണ്ണമായ ട്രെയിനിംഗ് ലൂപ്പ് എഴുതാൻ നമ്മൾ തയ്യാറാണ്. അതിന്റെ ഇവാല്യുവേഷൻ ഭാഗം ലളിതമാക്കാൻ, പ്രവചനങ്ങളും ലേബലുകളും സ്വീകരിച്ച്, നമ്മുടെ `metric` ഒബ്‌ജക്റ്റ് പ്രതീക്ഷിക്കുന്നതുപോലെ അവയെ സ്‌ട്രിംഗുകളുടെ ലിസ്‌റ്റുകളാക്കി മാറ്റുന്ന ഈ `postprocess()` ഫംഗ്‌ഷൻ നമ്മൾ നിർവചിക്കുന്നു: + +```py +def postprocess(predictions, labels): + predictions = predictions.detach().cpu().clone().numpy() + labels = labels.detach().cpu().clone().numpy() + + # Remove ignored index (special tokens) and convert to labels + true_labels = [[label_names[l] for l in label if l != -100] for label in labels] + true_predictions = [ + [label_names[p] for (p, l) in zip(prediction, label) if l != -100] + for prediction, label in zip(predictions, labels) + ] + return true_labels, true_predictions +``` + +പിന്നീട് ട്രെയിനിംഗ് ലൂപ്പ് എഴുതാം. ട്രെയിനിംഗ് എങ്ങനെ പുരോഗമിക്കുന്നു എന്ന് പിന്തുടരാൻ ഒരു പ്രോഗ്രസ് ബാർ നിർവചിച്ച ശേഷം, ലൂപ്പിന് മൂന്ന് ഭാഗങ്ങളുണ്ട്: + +- ട്രെയിനിംഗ് തന്നെ; ഇത് `train_dataloader`-ലൂടെയുള്ള ക്ലാസിക് ഇറ്ററേഷനാണ്: മോഡലിലൂടെയുള്ള ഫോർവേഡ് പാസ്, പിന്നീട് ബാക്ക്‌വേഡ് പാസും ഒപ്‌റ്റിമൈസർ സ്‌റ്റെപ്പും. +- ഇവാല്യുവേഷൻ; ഇതിൽ ഒരു ബാച്ചിലെ നമ്മുടെ മോഡലിന്റെ ഔട്ട്‌പുട്ടുകൾ ലഭിച്ച ശേഷം ഒരു പുതുമയുണ്ട്: രണ്ട് പ്രോസസ്സുകൾ ഇൻപുട്ടുകളും ലേബലുകളും വ്യത്യസ്ത ഷേപ്പുകളിലേക്ക് പാഡ് ചെയ്തിരിക്കാം എന്നതിനാൽ, `gather()` മെത്തേഡ് വിളിക്കുന്നതിന് മുമ്പ് പ്രവചനങ്ങളെയും ലേബലുകളെയും ഒരേ ഷേപ്പിലാക്കാൻ `accelerator.pad_across_processes()` നമ്മൾ ഉപയോഗിക്കണം. ഇത് ചെയ്തില്ലെങ്കിൽ, ഇവാല്യുവേഷൻ ഒന്നുകിൽ എറർ നൽകും, അല്ലെങ്കിൽ എന്നെന്നേക്കുമായി തടഞ്ഞുനിൽക്കും (hang). പിന്നീട് ഫലങ്ങൾ `metric.add_batch()`-ലേക്ക് അയയ്ക്കുകയും, ഇവാല്യുവേഷൻ ലൂപ്പ് കഴിഞ്ഞാൽ `metric.compute()` വിളിക്കുകയും ചെയ്യുന്നു. +- സേവ് ചെയ്യലും അപ്‌ലോഡ് ചെയ്യലും; ഇവിടെ ആദ്യം മോഡലും ടോക്കണൈസറും സേവ് ചെയ്ത്, പിന്നീട് `repo.push_to_hub()` വിളിക്കുന്നു. ഒരു അസിൻക്രണസ് (asynchronous) പ്രോസസ്സിൽ പുഷ് ചെയ്യാൻ 🤗 Hub ലൈബ്രറിയോട് പറയാൻ `blocking=False` എന്ന ആർഗ്യുമെന്റ് നമ്മൾ ഉപയോഗിക്കുന്നത് ശ്രദ്ധിക്കുക. ഇങ്ങനെ, ട്രെയിനിംഗ് സാധാരണപോലെ തുടരുകയും ഈ (ദൈർഘ്യമേറിയ) നിർദ്ദേശം പശ്ചാത്തലത്തിൽ എക്‌സിക്യൂട്ട് ചെയ്യപ്പെടുകയും ചെയ്യുന്നു. + +ട്രെയിനിംഗ് ലൂപ്പിന്റെ പൂർണ്ണമായ കോഡ് ഇതാ: + +```py +from tqdm.auto import tqdm +import torch + +progress_bar = tqdm(range(num_training_steps)) + +for epoch in range(num_train_epochs): + # Training + model.train() + for batch in train_dataloader: + outputs = model(**batch) + loss = outputs.loss + accelerator.backward(loss) + + optimizer.step() + lr_scheduler.step() + optimizer.zero_grad() + progress_bar.update(1) + + # Evaluation + model.eval() + for batch in eval_dataloader: + with torch.no_grad(): + outputs = model(**batch) + + predictions = outputs.logits.argmax(dim=-1) + labels = batch["labels"] + + # Necessary to pad predictions and labels for being gathered + predictions = accelerator.pad_across_processes(predictions, dim=1, pad_index=-100) + labels = accelerator.pad_across_processes(labels, dim=1, pad_index=-100) + + predictions_gathered = accelerator.gather(predictions) + labels_gathered = accelerator.gather(labels) + + true_predictions, true_labels = postprocess(predictions_gathered, labels_gathered) + metric.add_batch(predictions=true_predictions, references=true_labels) + + results = metric.compute() + print( + f"epoch {epoch}:", + { + key: results[f"overall_{key}"] + for key in ["precision", "recall", "f1", "accuracy"] + }, + ) + + # Save and upload + accelerator.wait_for_everyone() + unwrapped_model = accelerator.unwrap_model(model) + unwrapped_model.save_pretrained(output_dir, save_function=accelerator.save) + if accelerator.is_main_process: + tokenizer.save_pretrained(output_dir) + repo.push_to_hub( + commit_message=f"Training in progress epoch {epoch}", blocking=False + ) +``` + +🤗 Accelerate ഉപയോഗിച്ച് സേവ് ചെയ്ത ഒരു മോഡൽ നിങ്ങൾ ആദ്യമായി കാണുന്നതാണെങ്കിൽ, അതിനോടൊപ്പമുള്ള മൂന്ന് വരി കോഡ് ഒരു നിമിഷം പരിശോധിക്കാം: + +```py +accelerator.wait_for_everyone() +unwrapped_model = accelerator.unwrap_model(model) +unwrapped_model.save_pretrained(output_dir, save_function=accelerator.save) +``` + +ആദ്യത്തെ വരി സ്വയം വ്യക്തമാണ്: തുടരുന്നതിന് മുമ്പ് എല്ലാവരും ആ ഘട്ടത്തിൽ എത്തുന്നതുവരെ കാത്തിരിക്കാൻ ഇത് എല്ലാ പ്രോസസ്സുകളോടും പറയുന്നു. സേവ് ചെയ്യുന്നതിന് മുമ്പ് എല്ലാ പ്രോസസ്സിലും ഒരേ മോഡൽ ഉണ്ടെന്ന് ഉറപ്പാക്കാനാണ് ഇത്. പിന്നീട് നമ്മൾ നിർവചിച്ച ബേസ് മോഡലായ `unwrapped_model` നമ്മൾ എടുക്കുന്നു. `accelerator.prepare()` മെത്തേഡ് ഡിസ്‌ട്രിബ്യൂട്ടഡ് ട്രെയിനിംഗിൽ പ്രവർത്തിക്കാൻ മോഡലിനെ മാറ്റുന്നു, അതിനാൽ അതിന് ഇനി `save_pretrained()` മെത്തേഡ് ഉണ്ടാകില്ല; `accelerator.unwrap_model()` മെത്തേഡ് ആ ഘട്ടം പഴയപടിയാക്കുന്നു. അവസാനമായി, നമ്മൾ `save_pretrained()` വിളിക്കുന്നു, എന്നാൽ `torch.save()`-ന് പകരം `accelerator.save()` ഉപയോഗിക്കാൻ ആ മെത്തേഡിനോട് പറയുന്നു. + +ഇത് പൂർത്തിയായാൽ, `Trainer` ഉപയോഗിച്ച് ട്രെയിൻ ചെയ്തതിനോട് ഏറെക്കുറെ സമാനമായ ഫലങ്ങൾ നൽകുന്ന ഒരു മോഡൽ നിങ്ങൾക്ക് ഉണ്ടായിരിക്കണം. ഈ കോഡ് ഉപയോഗിച്ച് ഞങ്ങൾ ട്രെയിൻ ചെയ്ത മോഡൽ [*huggingface-course/bert-finetuned-ner-accelerate*](https://huggingface.co/huggingface-course/bert-finetuned-ner-accelerate)-ൽ നിങ്ങൾക്ക് പരിശോധിക്കാം. ട്രെയിനിംഗ് ലൂപ്പിൽ എന്തെങ്കിലും മാറ്റങ്ങൾ പരീക്ഷിക്കണമെങ്കിൽ, മുകളിൽ കാണിച്ച കോഡ് എഡിറ്റ് ചെയ്ത് നേരിട്ട് അവ നടപ്പിലാക്കാം! + +{/if} + +## ഫൈൻ-ട്യൂൻ ചെയ്ത മോഡൽ ഉപയോഗിക്കുന്നു[[using-the-fine-tuned-model]] + +നമ്മൾ ഫൈൻ-ട്യൂൻ ചെയ്ത മോഡൽ Model Hub-ലെ ഇൻഫറൻസ് വിഡ്‌ജറ്റ് ഉപയോഗിച്ച് എങ്ങനെ ഉപയോഗിക്കാമെന്ന് ഞങ്ങൾ ഇതിനകം കാണിച്ചുതന്നിട്ടുണ്ട്. ഒരു `pipeline`-ൽ ഇത് ലോക്കലായി ഉപയോഗിക്കാൻ, ശരിയായ മോഡൽ ഐഡന്റിഫയർ വ്യക്തമാക്കിയാൽ മാത്രം മതി: + +```py +from transformers import pipeline + +# Replace this with your own checkpoint +model_checkpoint = "huggingface-course/bert-finetuned-ner" +token_classifier = pipeline( + "token-classification", model=model_checkpoint, aggregation_strategy="simple" +) +token_classifier("My name is Sylvain and I work at Hugging Face in Brooklyn.") +``` + +```python out +[{'entity_group': 'PER', 'score': 0.9988506, 'word': 'Sylvain', 'start': 11, 'end': 18}, + {'entity_group': 'ORG', 'score': 0.9647625, 'word': 'Hugging Face', 'start': 33, 'end': 45}, + {'entity_group': 'LOC', 'score': 0.9986118, 'word': 'Brooklyn', 'start': 49, 'end': 57}] +``` + +കൊള്ളാം! ഈ പൈപ്പ്‌ലൈനിന്റെ ഡിഫോൾട്ട് മോഡൽ പോലെ തന്നെ നന്നായി നമ്മുടെ മോഡൽ പ്രവർത്തിക്കുന്നു! diff --git a/chapters/ml/chapter7/3.mdx b/chapters/ml/chapter7/3.mdx new file mode 100644 index 000000000..44fd1b4ed --- /dev/null +++ b/chapters/ml/chapter7/3.mdx @@ -0,0 +1,1020 @@ + + +# ഒരു മാസ്‌ക്‌ഡ് ലാംഗ്വേജ് മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യുന്നു[[fine-tuning-a-masked-language-model]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +Transformer മോഡലുകൾ ഉൾപ്പെടുന്ന പല NLP ആപ്ലിക്കേഷനുകൾക്കും, Hugging Face Hub-ൽ നിന്ന് ഒരു പ്രീട്രെയിൻഡ് മോഡൽ എടുത്ത്, നിങ്ങളുടെ ടാസ്‌ക്കിനായി നിങ്ങളുടെ ഡേറ്റയിൽ അത് നേരിട്ട് ഫൈൻ-ട്യൂൻ ചെയ്താൽ മതി. പ്രീട്രെയിനിംഗിന് ഉപയോഗിച്ച കോർപ്പസ് (corpus) ഫൈൻ-ട്യൂണിംഗിന് ഉപയോഗിക്കുന്ന കോർപ്പസിൽ നിന്ന് വളരെ വ്യത്യസ്തമല്ലെങ്കിൽ, ട്രാൻസ്ഫർ ലേണിംഗ് (transfer learning) സാധാരണയായി നല്ല ഫലങ്ങൾ നൽകും. + +എന്നാൽ, ടാസ്‌ക്-നിർദ്ദിഷ്ടമായ ഒരു ഹെഡ് (task-specific head) ട്രെയിൻ ചെയ്യുന്നതിന് മുമ്പ്, ലാംഗ്വേജ് മോഡലുകളെ ആദ്യം നിങ്ങളുടെ ഡേറ്റയിൽ ഫൈൻ-ട്യൂൻ ചെയ്യേണ്ടി വരുന്ന ചില സാഹചര്യങ്ങളുണ്ട്. ഉദാഹരണത്തിന്, നിങ്ങളുടെ ഡേറ്റാസെറ്റിൽ നിയമപരമായ കരാറുകളോ ശാസ്ത്രലേഖനങ്ങളോ ആണുള്ളതെങ്കിൽ, BERT പോലുള്ള ഒരു സാധാരണ Transformer മോഡൽ നിങ്ങളുടെ കോർപ്പസിലെ ഡൊമെയ്ൻ-നിർദ്ദിഷ്ട വാക്കുകളെ സാധാരണയായി അപൂർവ ടോക്കണുകളായി (rare tokens) പരിഗണിക്കും, അതിന്റെ ഫലമായി ലഭിക്കുന്ന പ്രകടനം അത്ര തൃപ്തികരമായിരിക്കില്ല. ഇൻ-ഡൊമെയ്ൻ ഡേറ്റയിൽ ലാംഗ്വേജ് മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യുന്നതിലൂടെ പല ഡൗൺസ്ട്രീം ടാസ്‌ക്കുകളുടെയും പ്രകടനം നിങ്ങൾക്ക് മെച്ചപ്പെടുത്താം; അതായത്, ഈ ഘട്ടം സാധാരണയായി ഒരിക്കൽ മാത്രം ചെയ്താൽ മതി! + +ഒരു പ്രീട്രെയിൻഡ് ലാംഗ്വേജ് മോഡൽ ഇൻ-ഡൊമെയ്ൻ ഡേറ്റയിൽ ഫൈൻ-ട്യൂൻ ചെയ്യുന്ന ഈ പ്രക്രിയയെ സാധാരണയായി _ഡൊമെയ്ൻ അഡാപ്‌റ്റേഷൻ_ (domain adaptation) എന്ന് വിളിക്കുന്നു. NLP-യിൽ ട്രാൻസ്ഫർ ലേണിംഗ് യഥാർത്ഥത്തിൽ പ്രവർത്തിക്കുന്നതാക്കിയ ആദ്യകാല ന്യൂറൽ ആർക്കിടെക്ചറുകളിൽ ഒന്നായ (LSTM-കളെ അടിസ്ഥാനമാക്കിയുള്ള) [ULMFiT](https://arxiv.org/abs/1801.06146) ആണ് 2018-ൽ ഇത് ജനപ്രിയമാക്കിയത്. ULMFiT ഉപയോഗിച്ചുള്ള ഡൊമെയ്ൻ അഡാപ്‌റ്റേഷന്റെ ഒരു ഉദാഹരണം താഴെയുള്ള ചിത്രത്തിൽ കാണിച്ചിരിക്കുന്നു; ഈ ഭാഗത്തിൽ നമ്മൾ സമാനമായ ഒന്ന് ചെയ്യും, എന്നാൽ LSTM-ന് പകരം ഒരു Transformer ഉപയോഗിച്ച്! + +
+ULMFiT. + +
+ +ഈ ഭാഗത്തിന്റെ അവസാനത്തോടെ, താഴെ കാണിച്ചിരിക്കുന്നതുപോലെ വാക്യങ്ങൾ ഓട്ടോകംപ്ലീറ്റ് ചെയ്യാൻ കഴിയുന്ന ഒരു [മാസ്‌ക്‌ഡ് ലാംഗ്വേജ് മോഡൽ](https://huggingface.co/huggingface-course/distilbert-base-uncased-finetuned-imdb?text=This+is+a+great+%5BMASK%5D.) Hub-ൽ നിങ്ങൾക്ക് ഉണ്ടായിരിക്കും: + + + +നമുക്ക് തുടങ്ങാം! + + + +> [!TIP] +> 🙋 "മാസ്‌ക്‌ഡ് ലാംഗ്വേജ് മോഡലിംഗ്", "പ്രീട്രെയിൻഡ് മോഡൽ" എന്നീ പദങ്ങൾ നിങ്ങൾക്ക് അപരിചിതമായി തോന്നുന്നുവെങ്കിൽ, [അധ്യായം 1](/course/chapter1) പരിശോധിക്കുക; അവിടെ ഈ അടിസ്ഥാന ആശയങ്ങളെല്ലാം വീഡിയോകളോടെ നമ്മൾ വിശദീകരിക്കുന്നുണ്ട്! + +## മാസ്‌ക്‌ഡ് ലാംഗ്വേജ് മോഡലിംഗിനായി ഒരു പ്രീട്രെയിൻഡ് മോഡൽ തിരഞ്ഞെടുക്കുന്നു[[picking-a-pretrained-model-for-masked-language-modeling]] + +തുടങ്ങാനായി, മാസ്‌ക്‌ഡ് ലാംഗ്വേജ് മോഡലിംഗിന് അനുയോജ്യമായ ഒരു പ്രീട്രെയിൻഡ് മോഡൽ തിരഞ്ഞെടുക്കാം. താഴെയുള്ള സ്‌ക്രീൻഷോട്ടിൽ കാണിച്ചിരിക്കുന്നതുപോലെ, [Hugging Face Hub](https://huggingface.co/models?pipeline_tag=fill-mask&sort=downloads)-ൽ "Fill-Mask" ഫിൽറ്റർ പ്രയോഗിച്ചാൽ സാധ്യതയുള്ള മോഡലുകളുടെ ഒരു ലിസ്‌റ്റ് നിങ്ങൾക്ക് കാണാം: + +
+Hub മോഡലുകൾ. +
+ +BERT, RoBERTa കുടുംബത്തിലെ മോഡലുകളാണ് ഏറ്റവുമധികം ഡൗൺലോഡ് ചെയ്യപ്പെടുന്നവയെങ്കിലും, [DistilBERT](https://huggingface.co/distilbert-base-uncased) എന്ന ഒരു മോഡലാണ് നമ്മൾ ഉപയോഗിക്കുക — +ഡൗൺസ്ട്രീം പ്രകടനത്തിൽ കാര്യമായ നഷ്ടമൊന്നുമില്ലാതെ, വളരെ വേഗത്തിൽ ട്രെയിൻ ചെയ്യാൻ കഴിയുന്ന ഒരു മോഡലാണിത്. [_നോളജ് ഡിസ്‌റ്റിലേഷൻ_](https://en.wikipedia.org/wiki/Knowledge_distillation) (knowledge distillation) എന്ന ഒരു പ്രത്യേക ടെക്‌നിക് ഉപയോഗിച്ചാണ് ഈ മോഡൽ ട്രെയിൻ ചെയ്തത്; ഇതിൽ BERT പോലുള്ള ഒരു വലിയ "ടീച്ചർ മോഡൽ" (teacher model), വളരെ കുറച്ച് പാരാമീറ്ററുകൾ മാത്രമുള്ള ഒരു "സ്‌റ്റുഡന്റ് മോഡലിന്റെ" (student model) ട്രെയിനിംഗിനെ നയിക്കാൻ ഉപയോഗിക്കുന്നു. നോളജ് ഡിസ്‌റ്റിലേഷന്റെ വിശദാംശങ്ങൾ വിവരിക്കുന്നത് ഈ ഭാഗത്തിന്റെ പരിധിക്ക് പുറത്താണ്, എന്നാൽ താൽപ്പര്യമുണ്ടെങ്കിൽ [_Natural Language Processing with Transformers_](https://www.oreilly.com/library/view/natural-language-processing/9781098136789/) (Transformers ടെക്‌സ്‌റ്റ്ബുക്ക് എന്ന് സാധാരണയായി അറിയപ്പെടുന്ന പുസ്തകം) എന്ന പുസ്തകത്തിൽ അതേക്കുറിച്ച് എല്ലാം നിങ്ങൾക്ക് വായിക്കാം. + +{#if fw === 'pt'} + +`AutoModelForMaskedLM` ക്ലാസ് ഉപയോഗിച്ച് DistilBERT ഡൗൺലോഡ് ചെയ്യാം: + +```python +from transformers import AutoModelForMaskedLM + +model_checkpoint = "distilbert-base-uncased" +model = AutoModelForMaskedLM.from_pretrained(model_checkpoint) +``` + +`num_parameters()` മെത്തേഡ് വിളിച്ചുകൊണ്ട് ഈ മോഡലിന് എത്ര പാരാമീറ്ററുകൾ ഉണ്ടെന്ന് നമുക്ക് കാണാം: + +```python +distilbert_num_parameters = model.num_parameters() / 1_000_000 +print(f"'>>> DistilBERT number of parameters: {round(distilbert_num_parameters)}M'") +print(f"'>>> BERT number of parameters: 110M'") +``` + +```python out +'>>> DistilBERT number of parameters: 67M' +'>>> BERT number of parameters: 110M' +``` + +{:else} + +`AutoModelForMaskedLM` ക്ലാസ് ഉപയോഗിച്ച് DistilBERT ഡൗൺലോഡ് ചെയ്യാം: + +```python +from transformers import TFAutoModelForMaskedLM + +model_checkpoint = "distilbert-base-uncased" +model = TFAutoModelForMaskedLM.from_pretrained(model_checkpoint) +``` + +`summary()` മെത്തേഡ് വിളിച്ചുകൊണ്ട് ഈ മോഡലിന് എത്ര പാരാമീറ്ററുകൾ ഉണ്ടെന്ന് നമുക്ക് കാണാം: + +```python +model.summary() +``` + +```python out +Model: "tf_distil_bert_for_masked_lm" +_________________________________________________________________ +Layer (type) Output Shape Param # +================================================================= +distilbert (TFDistilBertMain multiple 66362880 +_________________________________________________________________ +vocab_transform (Dense) multiple 590592 +_________________________________________________________________ +vocab_layer_norm (LayerNorma multiple 1536 +_________________________________________________________________ +vocab_projector (TFDistilBer multiple 23866170 +================================================================= +Total params: 66,985,530 +Trainable params: 66,985,530 +Non-trainable params: 0 +_________________________________________________________________ +``` + +{/if} + +ഏകദേശം 67 ദശലക്ഷം പാരാമീറ്ററുകളുള്ള DistilBERT, BERT ബേസ് മോഡലിനെക്കാൾ ഏകദേശം രണ്ട് മടങ്ങ് ചെറുതാണ്; അതായത് ട്രെയിനിംഗിൽ ഏതാണ്ട് ഇരട്ടി വേഗത -- കൊള്ളാം! ഒരു ചെറിയ സാമ്പിൾ ടെക്‌സ്‌റ്റിന്റെ ഏറ്റവും സാധ്യതയുള്ള പൂരണങ്ങളായി (completions) ഈ മോഡൽ ഏതുതരം ടോക്കണുകളാണ് പ്രവചിക്കുന്നത് എന്ന് ഇപ്പോൾ നോക്കാം: + +```python +text = "This is a great [MASK]." +``` + +മനുഷ്യരായ നമുക്ക് `[MASK]` ടോക്കണിന് "day", "ride", "painting" എന്നിങ്ങനെ പല സാധ്യതകളും സങ്കൽപ്പിക്കാൻ കഴിയും. പ്രീട്രെയിൻഡ് മോഡലുകളുടെ കാര്യത്തിൽ, പ്രവചനങ്ങൾ മോഡൽ ട്രെയിൻ ചെയ്ത കോർപ്പസിനെ ആശ്രയിച്ചിരിക്കും, കാരണം ഡേറ്റയിലുള്ള സ്ഥിതിവിവര പാറ്റേണുകൾ (statistical patterns) തിരിച്ചറിയാനാണ് അത് പഠിക്കുന്നത്. BERT പോലെ, DistilBERT-ഉം [English Wikipedia](https://huggingface.co/datasets/wikipedia), [BookCorpus](https://huggingface.co/datasets/bookcorpus) ഡേറ്റാസെറ്റുകളിലാണ് പ്രീട്രെയിൻ ചെയ്തത്, അതിനാൽ `[MASK]`-നുള്ള പ്രവചനങ്ങൾ ഈ ഡൊമെയ്‌നുകളെ പ്രതിഫലിപ്പിക്കുമെന്ന് നമ്മൾ പ്രതീക്ഷിക്കുന്നു. മാസ്‌ക് പ്രവചിക്കാൻ, മോഡലിനുള്ള ഇൻപുട്ടുകൾ നിർമ്മിക്കാൻ DistilBERT-ന്റെ ടോക്കണൈസർ നമുക്ക് ആവശ്യമാണ്, അതിനാൽ അതും Hub-ൽ നിന്ന് ഡൗൺലോഡ് ചെയ്യാം: + +```python +from transformers import AutoTokenizer + +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) +``` + +ഒരു ടോക്കണൈസറും ഒരു മോഡലും കൈയിലുള്ളതിനാൽ, ഇപ്പോൾ നമ്മുടെ ടെക്‌സ്‌റ്റ് ഉദാഹരണം മോഡലിന് നൽകി, ലോജിറ്റുകൾ (logits) വേർതിരിച്ചെടുത്ത്, മികച്ച 5 സാധ്യതകൾ പ്രിന്റ് ചെയ്യാം: + +{#if fw === 'pt'} + +```python +import torch + +inputs = tokenizer(text, return_tensors="pt") +token_logits = model(**inputs).logits +# Find the location of [MASK] and extract its logits +mask_token_index = torch.where(inputs["input_ids"] == tokenizer.mask_token_id)[1] +mask_token_logits = token_logits[0, mask_token_index, :] +# Pick the [MASK] candidates with the highest logits +top_5_tokens = torch.topk(mask_token_logits, 5, dim=1).indices[0].tolist() + +for token in top_5_tokens: + print(f"'>>> {text.replace(tokenizer.mask_token, tokenizer.decode([token]))}'") +``` + +{:else} + +```python +import numpy as np +import tensorflow as tf + +inputs = tokenizer(text, return_tensors="np") +token_logits = model(**inputs).logits +# Find the location of [MASK] and extract its logits +mask_token_index = np.argwhere(inputs["input_ids"] == tokenizer.mask_token_id)[0, 1] +mask_token_logits = token_logits[0, mask_token_index, :] +# Pick the [MASK] candidates with the highest logits +# We negate the array before argsort to get the largest, not the smallest, logits +top_5_tokens = np.argsort(-mask_token_logits)[:5].tolist() + +for token in top_5_tokens: + print(f">>> {text.replace(tokenizer.mask_token, tokenizer.decode([token]))}") +``` + +{/if} + +```python out +'>>> This is a great deal.' +'>>> This is a great success.' +'>>> This is a great adventure.' +'>>> This is a great idea.' +'>>> This is a great feat.' +``` + +മോഡലിന്റെ പ്രവചനങ്ങൾ ദൈനംദിന പദങ്ങളെയാണ് സൂചിപ്പിക്കുന്നത് എന്ന് ഔട്ട്‌പുട്ടുകളിൽ നിന്ന് കാണാം; English Wikipedia ആണ് അടിത്തറ എന്നതിനാൽ അതിൽ ഒരുപക്ഷേ അത്ഭുതമില്ല. ഈ ഡൊമെയ്ൻ കുറച്ചുകൂടി സവിശേഷമായ (niche) ഒന്നിലേക്ക് -- തീവ്രമായി ധ്രുവീകരിക്കപ്പെട്ട സിനിമാ റിവ്യൂകളിലേക്ക് -- എങ്ങനെ മാറ്റാമെന്ന് നോക്കാം! + + +## ഡേറ്റാസെറ്റ്[[the-dataset]] + +ഡൊമെയ്ൻ അഡാപ്‌റ്റേഷൻ പ്രദർശിപ്പിക്കാൻ, പ്രശസ്തമായ [Large Movie Review Dataset](https://huggingface.co/datasets/imdb) (ചുരുക്കത്തിൽ IMDb) നമ്മൾ ഉപയോഗിക്കും; സെന്റിമെന്റ് അനാലിസിസ് മോഡലുകളെ ബെഞ്ച്‌മാർക്ക് ചെയ്യാൻ പലപ്പോഴും ഉപയോഗിക്കുന്ന സിനിമാ റിവ്യൂകളുടെ ഒരു കോർപ്പസാണിത്. ഈ കോർപ്പസിൽ DistilBERT ഫൈൻ-ട്യൂൻ ചെയ്യുന്നതിലൂടെ, പ്രീട്രെയിൻ ചെയ്ത Wikipedia-യിലെ വസ്തുതാപരമായ ഡേറ്റയിൽ നിന്ന് സിനിമാ റിവ്യൂകളിലെ കൂടുതൽ ആത്മനിഷ്ഠമായ ഘടകങ്ങളിലേക്ക് ലാംഗ്വേജ് മോഡൽ അതിന്റെ പദസമ്പത്ത് (vocabulary) പൊരുത്തപ്പെടുത്തുമെന്ന് നമ്മൾ പ്രതീക്ഷിക്കുന്നു. 🤗 Datasets-ലെ `load_dataset()` ഫംഗ്‌ഷൻ ഉപയോഗിച്ച് Hugging Face Hub-ൽ നിന്ന് നമുക്ക് ഡേറ്റ ലഭിക്കും: + +```python +from datasets import load_dataset + +imdb_dataset = load_dataset("imdb") +imdb_dataset +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['text', 'label'], + num_rows: 25000 + }) + test: Dataset({ + features: ['text', 'label'], + num_rows: 25000 + }) + unsupervised: Dataset({ + features: ['text', 'label'], + num_rows: 50000 + }) +}) +``` + +`train`, `test` സ്‌പ്ലിറ്റുകളിൽ ഓരോന്നിലും 25,000 റിവ്യൂകൾ വീതം ഉണ്ടെന്നും, 50,000 റിവ്യൂകൾ ഉൾക്കൊള്ളുന്ന `unsupervised` എന്ന ലേബൽ ചെയ്യാത്ത ഒരു സ്‌പ്ലിറ്റ് ഉണ്ടെന്നും നമുക്ക് കാണാം. നമ്മൾ കൈകാര്യം ചെയ്യുന്നത് ഏതുതരം ടെക്‌സ്‌റ്റാണ് എന്ന് ഒരു ധാരണ കിട്ടാൻ ഏതാനും സാമ്പിളുകൾ നോക്കാം. കോഴ്‌സിന്റെ മുൻ അധ്യായങ്ങളിൽ ചെയ്തതുപോലെ, ഒരു റാൻഡം സാമ്പിൾ ഉണ്ടാക്കാൻ `Dataset.shuffle()`, `Dataset.select()` ഫംഗ്‌ഷനുകൾ നമ്മൾ ചെയിൻ ചെയ്യും: + +```python +sample = imdb_dataset["train"].shuffle(seed=42).select(range(3)) + +for row in sample: + print(f"\n'>>> Review: {row['text']}'") + print(f"'>>> Label: {row['label']}'") +``` + +```python out + +'>>> Review: This is your typical Priyadarshan movie--a bunch of loony characters out on some silly mission. His signature climax has the entire cast of the film coming together and fighting each other in some crazy moshpit over hidden money. Whether it is a winning lottery ticket in Malamaal Weekly, black money in Hera Pheri, "kodokoo" in Phir Hera Pheri, etc., etc., the director is becoming ridiculously predictable. Don\'t get me wrong; as clichéd and preposterous his movies may be, I usually end up enjoying the comedy. However, in most his previous movies there has actually been some good humor, (Hungama and Hera Pheri being noteworthy ones). Now, the hilarity of his films is fading as he is using the same formula over and over again.

Songs are good. Tanushree Datta looks awesome. Rajpal Yadav is irritating, and Tusshar is not a whole lot better. Kunal Khemu is OK, and Sharman Joshi is the best.' +'>>> Label: 0' + +'>>> Review: Okay, the story makes no sense, the characters lack any dimensionally, the best dialogue is ad-libs about the low quality of movie, the cinematography is dismal, and only editing saves a bit of the muddle, but Sam" Peckinpah directed the film. Somehow, his direction is not enough. For those who appreciate Peckinpah and his great work, this movie is a disappointment. Even a great cast cannot redeem the time the viewer wastes with this minimal effort.

The proper response to the movie is the contempt that the director San Peckinpah, James Caan, Robert Duvall, Burt Young, Bo Hopkins, Arthur Hill, and even Gig Young bring to their work. Watch the great Peckinpah films. Skip this mess.' +'>>> Label: 0' + +'>>> Review: I saw this movie at the theaters when I was about 6 or 7 years old. I loved it then, and have recently come to own a VHS version.

My 4 and 6 year old children love this movie and have been asking again and again to watch it.

I have enjoyed watching it again too. Though I have to admit it is not as good on a little TV.

I do not have older children so I do not know what they would think of it.

The songs are very cute. My daughter keeps singing them over and over.

Hope this helps.' +'>>> Label: 1' +``` + +അതെ, ഇവ തീർച്ചയായും സിനിമാ റിവ്യൂകളാണ്; നിങ്ങൾക്ക് മതിയായ പ്രായമുണ്ടെങ്കിൽ, VHS പതിപ്പ് സ്വന്തമായുള്ളതിനെക്കുറിച്ച് അവസാന റിവ്യൂവിലുള്ള പരാമർശം പോലും നിങ്ങൾക്ക് മനസ്സിലാകും 😜! ലാംഗ്വേജ് മോഡലിംഗിന് ലേബലുകൾ ആവശ്യമില്ലെങ്കിലും, `0` ഒരു നെഗറ്റീവ് റിവ്യൂവിനെയും `1` ഒരു പോസിറ്റീവ് റിവ്യൂവിനെയും സൂചിപ്പിക്കുന്നു എന്ന് നമുക്ക് ഇപ്പോഴേ കാണാം. + +> [!TIP] +> ✏️ **പരീക്ഷിച്ചു നോക്കൂ!** `unsupervised` സ്‌പ്ലിറ്റിന്റെ ഒരു റാൻഡം സാമ്പിൾ ഉണ്ടാക്കി, ലേബലുകൾ `0`-ഉം `1`-ഉം അല്ല എന്ന് ഉറപ്പുവരുത്തുക. അതോടൊപ്പം, `train`, `test` സ്‌പ്ലിറ്റുകളിലെ ലേബലുകൾ തീർച്ചയായും `0` അല്ലെങ്കിൽ `1` ആണെന്നും നിങ്ങൾക്ക് പരിശോധിക്കാം -- ഒരു പുതിയ പ്രോജക്റ്റിന്റെ തുടക്കത്തിൽ ഓരോ NLP പ്രാക്റ്റീഷണറും ചെയ്യേണ്ട ഉപകാരപ്രദമായ ഒരു സാനിറ്റി ചെക്ക് (sanity check) ആണിത്! + +ഡേറ്റ ഒന്ന് വേഗത്തിൽ നോക്കിക്കഴിഞ്ഞ സ്ഥിതിക്ക്, മാസ്‌ക്‌ഡ് ലാംഗ്വേജ് മോഡലിംഗിനായി അത് തയ്യാറാക്കുന്നതിലേക്ക് കടക്കാം. നമ്മൾ കാണാൻ പോകുന്നതുപോലെ, [അധ്യായം 3](/course/chapter3)-ൽ കണ്ട സീക്വൻസ് ക്ലാസിഫിക്കേഷൻ ടാസ്‌ക്കുകളെ അപേക്ഷിച്ച് ഇവിടെ ചില അധിക ഘട്ടങ്ങൾ ചെയ്യേണ്ടതുണ്ട്. തുടങ്ങാം! + +## ഡേറ്റ പ്രീപ്രോസസ്സ് ചെയ്യുന്നു[[preprocessing-the-data]] + + + +ഓട്ടോ-റിഗ്രസ്സീവ് (auto-regressive) ലാംഗ്വേജ് മോഡലിംഗിനും മാസ്‌ക്‌ഡ് ലാംഗ്വേജ് മോഡലിംഗിനും പൊതുവായുള്ള ഒരു പ്രീപ്രോസസ്സിംഗ് ഘട്ടം, എല്ലാ ഉദാഹരണങ്ങളും കൂട്ടിച്ചേർത്ത (concatenate) ശേഷം മുഴുവൻ കോർപ്പസും തുല്യ വലുപ്പമുള്ള ചങ്കുകളായി (chunks) വിഭജിക്കുകയാണ്. ഓരോ ഉദാഹരണവും വെറുതെ ടോക്കണൈസ് ചെയ്യുന്ന നമ്മുടെ സാധാരണ രീതിയിൽ നിന്ന് ഇത് തികച്ചും വ്യത്യസ്തമാണ്. എന്തിനാണ് എല്ലാം ഒരുമിച്ച് കൂട്ടിച്ചേർക്കുന്നത്? ഓരോ ഉദാഹരണവും വളരെ നീണ്ടതാണെങ്കിൽ അവ ട്രങ്കേറ്റ് (truncate) ചെയ്യപ്പെട്ടേക്കാം, അത് ലാംഗ്വേജ് മോഡലിംഗ് ടാസ്‌ക്കിന് ഉപകാരപ്രദമായേക്കാവുന്ന വിവരങ്ങൾ നഷ്ടപ്പെടുന്നതിന് കാരണമാകും എന്നതാണ് കാരണം! + +അതിനാൽ തുടങ്ങാനായി, നമ്മുടെ കോർപ്പസ് പതിവുപോലെ ആദ്യം ടോക്കണൈസ് ചെയ്യും, എന്നാൽ ടോക്കണൈസറിൽ `truncation=True` ഓപ്‌ഷൻ _സെറ്റ് ചെയ്യാതെ_. വേഡ് ID-കൾ ലഭ്യമാണെങ്കിൽ അവയും നമ്മൾ എടുക്കും ([അധ്യായം 6](/course/chapter6/3)-ൽ വിവരിച്ചതുപോലെ, ഒരു ഫാസ്‌റ്റ് ടോക്കണൈസർ ഉപയോഗിക്കുകയാണെങ്കിൽ അവ ലഭ്യമായിരിക്കും), കാരണം ഹോൾ വേഡ് മാസ്‌കിംഗ് (whole word masking) ചെയ്യാൻ പിന്നീട് അവ നമുക്ക് ആവശ്യമായി വരും. ഇത് ഒരു ലളിതമായ ഫംഗ്‌ഷനിൽ നമ്മൾ പൊതിയും, അതോടൊപ്പം ഇനി ആവശ്യമില്ലാത്തതിനാൽ `text`, `label` കോളങ്ങളും നീക്കം ചെയ്യും: + +```python +def tokenize_function(examples): + result = tokenizer(examples["text"]) + if tokenizer.is_fast: + result["word_ids"] = [result.word_ids(i) for i in range(len(result["input_ids"]))] + return result + + +# Use batched=True to activate fast multithreading! +tokenized_datasets = imdb_dataset.map( + tokenize_function, batched=True, remove_columns=["text", "label"] +) +tokenized_datasets +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['attention_mask', 'input_ids', 'word_ids'], + num_rows: 25000 + }) + test: Dataset({ + features: ['attention_mask', 'input_ids', 'word_ids'], + num_rows: 25000 + }) + unsupervised: Dataset({ + features: ['attention_mask', 'input_ids', 'word_ids'], + num_rows: 50000 + }) +}) +``` + +DistilBERT ഒരു BERT-സമാന മോഡൽ ആയതിനാൽ, എൻകോഡ് ചെയ്ത ടെക്‌സ്‌റ്റുകളിൽ മറ്റ് അധ്യായങ്ങളിൽ നമ്മൾ കണ്ട `input_ids`, `attention_mask` എന്നിവയും, നമ്മൾ ചേർത്ത `word_ids`-ഉം ഉണ്ടെന്ന് കാണാം. + +സിനിമാ റിവ്യൂകൾ ടോക്കണൈസ് ചെയ്തുകഴിഞ്ഞ സ്ഥിതിക്ക്, അടുത്ത ഘട്ടം അവയെല്ലാം ഒരുമിച്ച് കൂട്ടിച്ചേർത്ത് ഫലം ചങ്കുകളായി വിഭജിക്കുകയാണ്. എന്നാൽ ഈ ചങ്കുകൾ എത്ര വലുതായിരിക്കണം? ഇത് ആത്യന്തികമായി നിങ്ങൾക്ക് ലഭ്യമായ GPU മെമ്മറിയുടെ അളവനുസരിച്ച് നിർണ്ണയിക്കപ്പെടും, എന്നാൽ മോഡലിന്റെ പരമാവധി കോൺടെക്‌സ്‌റ്റ് സൈസ് (maximum context size) എത്രയാണെന്ന് നോക്കുന്നത് ഒരു നല്ല തുടക്കമാണ്. ടോക്കണൈസറിന്റെ `model_max_length` ആട്രിബ്യൂട്ട് പരിശോധിച്ച് ഇത് കണ്ടെത്താം: + +```python +tokenizer.model_max_length +``` + +```python out +512 +``` + +ഒരു ചെക്ക്‌പോയിന്റുമായി ബന്ധപ്പെട്ട *tokenizer_config.json* ഫയലിൽ നിന്നാണ് ഈ മൂല്യം ലഭിക്കുന്നത്; ഈ സാഹചര്യത്തിൽ, BERT-ലേതുപോലെ തന്നെ, കോൺടെക്‌സ്‌റ്റ് സൈസ് 512 ടോക്കണുകളാണെന്ന് നമുക്ക് കാണാം. + +> [!TIP] +> ✏️ **പരീക്ഷിച്ചു നോക്കൂ!** [BigBird](https://huggingface.co/google/bigbird-roberta-base), [Longformer](hf.co/allenai/longformer-base-4096) പോലുള്ള ചില Transformer മോഡലുകൾക്ക് BERT-നെയും മറ്റ് ആദ്യകാല Transformer മോഡലുകളെയും അപേക്ഷിച്ച് വളരെ നീണ്ട കോൺടെക്‌സ്‌റ്റ് ലെങ്ത് ഉണ്ട്. ഈ ചെക്ക്‌പോയിന്റുകളിൽ ഒന്നിനായി ടോക്കണൈസർ ഇൻസ്‌റ്റാൻഷിയേറ്റ് ചെയ്ത്, `model_max_length` അതിന്റെ മോഡൽ കാർഡിൽ പറഞ്ഞിരിക്കുന്നതുമായി യോജിക്കുന്നുണ്ടോ എന്ന് പരിശോധിക്കുക. + +അതിനാൽ, Google Colab-ൽ കാണുന്നതുപോലുള്ള GPU-കളിൽ നമ്മുടെ പരീക്ഷണങ്ങൾ റൺ ചെയ്യാൻ, മെമ്മറിയിൽ ഒതുങ്ങുന്ന അൽപ്പം ചെറിയ ഒരു വലുപ്പം നമ്മൾ തിരഞ്ഞെടുക്കും: + +```python +chunk_size = 128 +``` + +> [!WARNING] +> യഥാർത്ഥ സാഹചര്യങ്ങളിൽ ചെറിയ ചങ്ക് സൈസ് ഉപയോഗിക്കുന്നത് ദോഷകരമാകാം എന്നത് ശ്രദ്ധിക്കുക; അതിനാൽ നിങ്ങളുടെ മോഡൽ പ്രയോഗിക്കാൻ പോകുന്ന ഉപയോഗ സാഹചര്യത്തിന് (use case) അനുയോജ്യമായ ഒരു വലുപ്പം നിങ്ങൾ ഉപയോഗിക്കണം. + +ഇനിയാണ് രസകരമായ ഭാഗം. കൂട്ടിച്ചേർക്കൽ എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് കാണിക്കാൻ, ടോക്കണൈസ് ചെയ്ത നമ്മുടെ ട്രെയിനിംഗ് സെറ്റിൽ നിന്ന് ഏതാനും റിവ്യൂകൾ എടുത്ത്, ഓരോ റിവ്യൂവിലെയും ടോക്കണുകളുടെ എണ്ണം പ്രിന്റ് ചെയ്യാം: + +```python +# Slicing produces a list of lists for each feature +tokenized_samples = tokenized_datasets["train"][:3] + +for idx, sample in enumerate(tokenized_samples["input_ids"]): + print(f"'>>> Review {idx} length: {len(sample)}'") +``` + +```python out +'>>> Review 0 length: 200' +'>>> Review 1 length: 559' +'>>> Review 2 length: 192' +``` + +തുടർന്ന് ഒരു ലളിതമായ ഡിക്‌ഷണറി കോംപ്രിഹെൻഷൻ (dictionary comprehension) ഉപയോഗിച്ച് ഈ ഉദാഹരണങ്ങളെല്ലാം താഴെ കാണുന്നതുപോലെ കൂട്ടിച്ചേർക്കാം: + +```python +concatenated_examples = { + k: sum(tokenized_samples[k], []) for k in tokenized_samples.keys() +} +total_length = len(concatenated_examples["input_ids"]) +print(f"'>>> Concatenated reviews length: {total_length}'") +``` + +```python out +'>>> Concatenated reviews length: 951' +``` + +കൊള്ളാം, മൊത്തം ദൈർഘ്യം ശരിയാണ് -- ഇനി കൂട്ടിച്ചേർത്ത റിവ്യൂകളെ `chunk_size` നൽകുന്ന വലുപ്പമുള്ള ചങ്കുകളായി വിഭജിക്കാം. അതിനായി, `concatenated_examples`-ലെ ഫീച്ചറുകളിലൂടെ ഇറ്ററേറ്റ് ചെയ്ത്, ഓരോ ഫീച്ചറിന്റെയും സ്ലൈസുകൾ ഉണ്ടാക്കാൻ ഒരു ലിസ്‌റ്റ് കോംപ്രിഹെൻഷൻ ഉപയോഗിക്കുന്നു. ഫലം, ഓരോ ഫീച്ചറിനുമുള്ള ചങ്കുകളുടെ ഒരു ഡിക്‌ഷണറിയാണ്: + +```python +chunks = { + k: [t[i : i + chunk_size] for i in range(0, total_length, chunk_size)] + for k, t in concatenated_examples.items() +} + +for chunk in chunks["input_ids"]: + print(f"'>>> Chunk length: {len(chunk)}'") +``` + +```python out +'>>> Chunk length: 128' +'>>> Chunk length: 128' +'>>> Chunk length: 128' +'>>> Chunk length: 128' +'>>> Chunk length: 128' +'>>> Chunk length: 128' +'>>> Chunk length: 128' +'>>> Chunk length: 55' +``` + +ഈ ഉദാഹരണത്തിൽ കാണാവുന്നതുപോലെ, അവസാന ചങ്ക് സാധാരണയായി പരമാവധി ചങ്ക് സൈസിനെക്കാൾ ചെറുതായിരിക്കും. ഇത് കൈകാര്യം ചെയ്യാൻ രണ്ട് പ്രധാന തന്ത്രങ്ങളുണ്ട്: + +* അവസാന ചങ്ക് `chunk_size`-നെക്കാൾ ചെറുതാണെങ്കിൽ അത് ഒഴിവാക്കുക. +* അവസാന ചങ്കിന്റെ ദൈർഘ്യം `chunk_size`-ന് തുല്യമാകുന്നതുവരെ അതിൽ പാഡിംഗ് ചേർക്കുക. + +ഇവിടെ നമ്മൾ ആദ്യത്തെ രീതി സ്വീകരിക്കും; അതിനാൽ മുകളിലുള്ള ലോജിക് മുഴുവൻ, ടോക്കണൈസ് ചെയ്ത നമ്മുടെ ഡേറ്റാസെറ്റുകളിൽ പ്രയോഗിക്കാവുന്ന ഒരൊറ്റ ഫംഗ്‌ഷനിൽ പൊതിയാം: + +```python +def group_texts(examples): + # Concatenate all texts + concatenated_examples = {k: sum(examples[k], []) for k in examples.keys()} + # Compute length of concatenated texts + total_length = len(concatenated_examples[list(examples.keys())[0]]) + # We drop the last chunk if it's smaller than chunk_size + total_length = (total_length // chunk_size) * chunk_size + # Split by chunks of max_len + result = { + k: [t[i : i + chunk_size] for i in range(0, total_length, chunk_size)] + for k, t in concatenated_examples.items() + } + # Create a new labels column + result["labels"] = result["input_ids"].copy() + return result +``` + +`group_texts()`-ന്റെ അവസാന ഘട്ടത്തിൽ, `input_ids` കോളത്തിന്റെ ഒരു പകർപ്പായ `labels` എന്ന പുതിയ കോളം നമ്മൾ ഉണ്ടാക്കുന്നു എന്നത് ശ്രദ്ധിക്കുക. ഉടൻ കാണാൻ പോകുന്നതുപോലെ, മാസ്‌ക്‌ഡ് ലാംഗ്വേജ് മോഡലിംഗിൽ ഇൻപുട്ട് ബാച്ചിലെ ക്രമരഹിതമായി മാസ്‌ക് ചെയ്ത ടോക്കണുകൾ പ്രവചിക്കുകയാണ് ലക്ഷ്യം എന്നതാണ് ഇതിന് കാരണം; ഒരു `labels` കോളം ഉണ്ടാക്കുന്നതിലൂടെ, നമ്മുടെ ലാംഗ്വേജ് മോഡലിന് പഠിക്കാനുള്ള ഗ്രൗണ്ട് ട്രൂത്ത് (ground truth) നമ്മൾ നൽകുന്നു. + +ഇനി, നമ്മുടെ വിശ്വസ്തമായ `Dataset.map()` ഫംഗ്‌ഷൻ ഉപയോഗിച്ച്, ടോക്കണൈസ് ചെയ്ത ഡേറ്റാസെറ്റുകളിൽ `group_texts()` പ്രയോഗിക്കാം: + +```python +lm_datasets = tokenized_datasets.map(group_texts, batched=True) +lm_datasets +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['attention_mask', 'input_ids', 'labels', 'word_ids'], + num_rows: 61289 + }) + test: Dataset({ + features: ['attention_mask', 'input_ids', 'labels', 'word_ids'], + num_rows: 59905 + }) + unsupervised: Dataset({ + features: ['attention_mask', 'input_ids', 'labels', 'word_ids'], + num_rows: 122963 + }) +}) +``` + +ടെക്‌സ്‌റ്റുകൾ ഗ്രൂപ്പ് ചെയ്ത് ചങ്കുകളാക്കിയത്, `train`, `test` സ്‌പ്ലിറ്റുകൾക്ക് നമ്മുടെ യഥാർത്ഥ 25,000-നെക്കാൾ വളരെയധികം ഉദാഹരണങ്ങൾ ഉണ്ടാക്കിയതായി നിങ്ങൾക്ക് കാണാം. യഥാർത്ഥ കോർപ്പസിലെ ഒന്നിലധികം ഉദാഹരണങ്ങളിലായി വ്യാപിച്ചുകിടക്കുന്ന _തുടർച്ചയായ ടോക്കണുകൾ_ (contiguous tokens) ഉൾപ്പെടുന്ന ഉദാഹരണങ്ങൾ ഇപ്പോൾ നമുക്കുള്ളതുകൊണ്ടാണ് അത്. ചങ്കുകളിൽ ഒന്നിലെ പ്രത്യേക `[SEP]`, `[CLS]` ടോക്കണുകൾ നോക്കിയാൽ ഇത് വ്യക്തമായി കാണാം: + +```python +tokenizer.decode(lm_datasets["train"][1]["input_ids"]) +``` + +```python out +".... at.......... high. a classic line : inspector : i'm here to sack one of your teachers. student : welcome to bromwell high. i expect that many adults of my age think that bromwell high is far fetched. what a pity that it isn't! [SEP] [CLS] homelessness ( or houselessness as george carlin stated ) has been an issue for years but never a plan to help those on the street that were once considered human who did everything from going to school, work, or vote for the matter. most people think of the homeless" +``` + +ഈ ഉദാഹരണത്തിൽ, പരസ്പരം ഓവർലാപ്പ് ചെയ്യുന്ന രണ്ട് സിനിമാ റിവ്യൂകൾ നിങ്ങൾക്ക് കാണാം: ഒന്ന് ഒരു ഹൈസ്‌കൂൾ സിനിമയെക്കുറിച്ചും മറ്റേത് ഭവനരഹിതരെക്കുറിച്ചും. മാസ്‌ക്‌ഡ് ലാംഗ്വേജ് മോഡലിംഗിനുള്ള ലേബലുകൾ എങ്ങനെയിരിക്കുന്നു എന്നും നോക്കാം: + +```python out +tokenizer.decode(lm_datasets["train"][1]["labels"]) +``` + +```python out +".... at.......... high. a classic line : inspector : i'm here to sack one of your teachers. student : welcome to bromwell high. i expect that many adults of my age think that bromwell high is far fetched. what a pity that it isn't! [SEP] [CLS] homelessness ( or houselessness as george carlin stated ) has been an issue for years but never a plan to help those on the street that were once considered human who did everything from going to school, work, or vote for the matter. most people think of the homeless" +``` + +മുകളിലുള്ള നമ്മുടെ `group_texts()` ഫംഗ്‌ഷനിൽ നിന്ന് പ്രതീക്ഷിക്കുന്നതുപോലെ, ഇത് ഡീകോഡ് ചെയ്ത `input_ids`-ന് സമാനമായി കാണപ്പെടുന്നു -- എന്നാൽ പിന്നെ നമ്മുടെ മോഡലിന് എങ്ങനെ എന്തെങ്കിലും പഠിക്കാൻ കഴിയും? ഒരു പ്രധാന ഘട്ടം നമുക്ക് നഷ്ടമായിരിക്കുന്നു: ഇൻപുട്ടുകളിൽ ക്രമരഹിതമായ സ്ഥാനങ്ങളിൽ `[MASK]` ടോക്കണുകൾ ചേർക്കുക! ഒരു പ്രത്യേക ഡേറ്റാ കൊളേറ്റർ (data collator) ഉപയോഗിച്ച് ഫൈൻ-ട്യൂണിംഗ് സമയത്ത് തത്സമയം ഇത് എങ്ങനെ ചെയ്യാമെന്ന് നോക്കാം. + +## `Trainer` API ഉപയോഗിച്ച് DistilBERT ഫൈൻ-ട്യൂൻ ചെയ്യുന്നു[[fine-tuning-distilbert-with-the-trainer-api]] + +ഒരു മാസ്‌ക്‌ഡ് ലാംഗ്വേജ് മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യുന്നത്, [അധ്യായം 3](/course/chapter3)-ൽ നമ്മൾ ചെയ്തതുപോലെ ഒരു സീക്വൻസ് ക്ലാസിഫിക്കേഷൻ മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യുന്നതിന് ഏതാണ്ട് സമാനമാണ്. ഓരോ ടെക്‌സ്‌റ്റ് ബാച്ചിലെയും ചില ടോക്കണുകൾ ക്രമരഹിതമായി മാസ്‌ക് ചെയ്യാൻ കഴിയുന്ന ഒരു പ്രത്യേക ഡേറ്റാ കൊളേറ്റർ നമുക്ക് ആവശ്യമാണ് എന്നതാണ് ഒരേയൊരു വ്യത്യാസം. ഭാഗ്യവശാൽ, ഈ ടാസ്‌ക്കിനായി മാത്രമുള്ള ഒരു `DataCollatorForLanguageModeling` 🤗 Transformers-ൽ തയ്യാറായി ഉണ്ട്. ടോക്കണൈസറും, ടോക്കണുകളുടെ എത്ര ഭാഗം മാസ്‌ക് ചെയ്യണം എന്ന് വ്യക്തമാക്കുന്ന ഒരു `mlm_probability` ആർഗ്യുമെന്റും അതിന് നൽകിയാൽ മാത്രം മതി. BERT-ന് ഉപയോഗിച്ചതും ഗവേഷണ സാഹിത്യത്തിൽ സാധാരണമായ ഒരു തിരഞ്ഞെടുപ്പുമായ 15% നമ്മൾ തിരഞ്ഞെടുക്കും: + +```python +from transformers import DataCollatorForLanguageModeling + +data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm_probability=0.15) +``` + +ക്രമരഹിത മാസ്‌കിംഗ് എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് കാണാൻ, ഡേറ്റാ കൊളേറ്ററിന് ഏതാനും ഉദാഹരണങ്ങൾ നൽകാം. ഓരോ `dict`-ഉം തുടർച്ചയായ ടെക്‌സ്‌റ്റിന്റെ ഒരൊറ്റ ചങ്കിനെ പ്രതിനിധീകരിക്കുന്ന, `dict`-കളുടെ ഒരു ലിസ്‌റ്റാണ് അത് പ്രതീക്ഷിക്കുന്നത് എന്നതിനാൽ, ബാച്ച് കൊളേറ്ററിന് നൽകുന്നതിന് മുമ്പ് നമ്മൾ ആദ്യം ഡേറ്റാസെറ്റിലൂടെ ഇറ്ററേറ്റ് ചെയ്യുന്നു. ഈ ഡേറ്റാ കൊളേറ്റർ `"word_ids"` കീ പ്രതീക്ഷിക്കുന്നില്ല എന്നതിനാൽ അത് നമ്മൾ നീക്കം ചെയ്യുന്നു: + +```python +samples = [lm_datasets["train"][i] for i in range(2)] +for sample in samples: + _ = sample.pop("word_ids") + +for chunk in data_collator(samples)["input_ids"]: + print(f"\n'>>> {tokenizer.decode(chunk)}'") +``` + +```python output +'>>> [CLS] bromwell [MASK] is a cartoon comedy. it ran at the same [MASK] as some other [MASK] about school life, [MASK] as " teachers ". [MASK] [MASK] [MASK] in the teaching [MASK] lead [MASK] to believe that bromwell high\'[MASK] satire is much closer to reality than is " teachers ". the scramble [MASK] [MASK] financially, the [MASK]ful students whogn [MASK] right through [MASK] pathetic teachers\'pomp, the pettiness of the whole situation, distinction remind me of the schools i knew and their students. when i saw [MASK] episode in [MASK] a student repeatedly tried to burn down the school, [MASK] immediately recalled. [MASK]...' + +'>>> .... at.. [MASK]... [MASK]... high. a classic line plucked inspector : i\'[MASK] here to [MASK] one of your [MASK]. student : welcome to bromwell [MASK]. i expect that many adults of my age think that [MASK]mwell [MASK] is [MASK] fetched. what a pity that it isn\'t! [SEP] [CLS] [MASK]ness ( or [MASK]lessness as george 宇in stated )公 been an issue for years but never [MASK] plan to help those on the street that were once considered human [MASK] did everything from going to school, [MASK], [MASK] vote for the matter. most people think [MASK] the homeless' +``` + +കൊള്ളാം, അത് പ്രവർത്തിച്ചു! നമ്മുടെ ടെക്‌സ്‌റ്റിലെ വിവിധ സ്ഥാനങ്ങളിൽ `[MASK]` ടോക്കൺ ക്രമരഹിതമായി ചേർക്കപ്പെട്ടിരിക്കുന്നത് കാണാം. ട്രെയിനിംഗ് സമയത്ത് നമ്മുടെ മോഡൽ പ്രവചിക്കേണ്ടി വരുന്ന ടോക്കണുകൾ ഇവയായിരിക്കും -- ഓരോ ബാച്ചിലും `[MASK]` ചേർക്കുന്നത് ക്രമരഹിതമാക്കും എന്നതാണ് ഡേറ്റാ കൊളേറ്ററിന്റെ ഭംഗി! + +> [!TIP] +> ✏️ **പരീക്ഷിച്ചു നോക്കൂ!** ക്രമരഹിത മാസ്‌കിംഗ് നിങ്ങളുടെ കണ്മുന്നിൽ സംഭവിക്കുന്നത് കാണാൻ മുകളിലുള്ള കോഡ് സ്‌നിപ്പെറ്റ് പല തവണ റൺ ചെയ്യുക! കൂടാതെ, ഒരു വാക്കിലെ ഒരൊറ്റ ടോക്കൺ മാത്രം ചിലപ്പോൾ മാസ്‌ക് ചെയ്യപ്പെടുകയും മറ്റുള്ളവ ചെയ്യപ്പെടാതിരിക്കുകയും ചെയ്യുന്നത് കാണാൻ, `tokenizer.decode()` മെത്തേഡിന് പകരം `tokenizer.convert_ids_to_tokens()` ഉപയോഗിക്കുക. + +{#if fw === 'pt'} + +ക്രമരഹിത മാസ്‌കിംഗിന്റെ ഒരു പാർശ്വഫലം, `Trainer` ഉപയോഗിക്കുമ്പോൾ നമ്മുടെ ഇവാല്യുവേഷൻ മെട്രിക്കുകൾ ഡിറ്റർമിനിസ്‌റ്റിക് (deterministic) ആയിരിക്കില്ല എന്നതാണ്, കാരണം ട്രെയിനിംഗ്, ടെസ്‌റ്റ് സെറ്റുകൾക്ക് ഒരേ ഡേറ്റാ കൊളേറ്ററാണ് നമ്മൾ ഉപയോഗിക്കുന്നത്. 🤗 Accelerate ഉപയോഗിച്ചുള്ള ഫൈൻ-ട്യൂണിംഗ് പരിശോധിക്കുമ്പോൾ, ഒരു കസ്‌റ്റം ഇവാല്യുവേഷൻ ലൂപ്പിന്റെ വഴക്കം ഉപയോഗിച്ച് ഈ ക്രമരഹിതത എങ്ങനെ ഉറപ്പിച്ചു നിർത്താം (freeze) എന്ന് പിന്നീട് നമ്മൾ കാണും. + +{/if} + +മാസ്‌ക്‌ഡ് ലാംഗ്വേജ് മോഡലിംഗിനായി മോഡലുകൾ ട്രെയിൻ ചെയ്യുമ്പോൾ ഉപയോഗിക്കാവുന്ന ഒരു ടെക്‌നിക്, ഒറ്റയ്‌ക്കൊറ്റയ്ക്കുള്ള ടോക്കണുകൾ മാത്രമല്ല, മുഴുവൻ വാക്കുകളും ഒരുമിച്ച് മാസ്‌ക് ചെയ്യുകയാണ്. ഈ രീതിയെ _ഹോൾ വേഡ് മാസ്‌കിംഗ്_ (whole word masking) എന്ന് വിളിക്കുന്നു. ഹോൾ വേഡ് മാസ്‌കിംഗ് ഉപയോഗിക്കണമെങ്കിൽ, ഒരു ഡേറ്റാ കൊളേറ്റർ നമ്മൾ സ്വയം നിർമ്മിക്കേണ്ടി വരും. സാമ്പിളുകളുടെ ഒരു ലിസ്‌റ്റ് എടുത്ത് അവയെ ഒരു ബാച്ചാക്കി മാറ്റുന്ന ഒരു ഫംഗ്‌ഷൻ മാത്രമാണ് ഡേറ്റാ കൊളേറ്റർ, അതിനാൽ അത് ഇപ്പോൾ തന്നെ ചെയ്യാം! വേഡ് ഇൻഡെക്‌സുകളും അവയുമായി ബന്ധപ്പെട്ട ടോക്കണുകളും തമ്മിൽ ഒരു മാപ്പ് ഉണ്ടാക്കാൻ നേരത്തെ കണക്കാക്കിയ വേഡ് ID-കൾ നമ്മൾ ഉപയോഗിക്കും, തുടർന്ന് ഏതൊക്കെ വാക്കുകൾ മാസ്‌ക് ചെയ്യണമെന്ന് ക്രമരഹിതമായി തീരുമാനിച്ച് ആ മാസ്‌ക് ഇൻപുട്ടുകളിൽ പ്രയോഗിക്കും. മാസ്‌ക് ചെയ്ത വാക്കുകളുമായി ബന്ധപ്പെട്ടവ ഒഴികെ ലേബലുകൾ എല്ലാം `-100` ആണെന്നത് ശ്രദ്ധിക്കുക. + +{#if fw === 'pt'} + +```py +import collections +import numpy as np + +from transformers import default_data_collator + +wwm_probability = 0.2 + + +def whole_word_masking_data_collator(features): + for feature in features: + word_ids = feature.pop("word_ids") + + # Create a map between words and corresponding token indices + mapping = collections.defaultdict(list) + current_word_index = -1 + current_word = None + for idx, word_id in enumerate(word_ids): + if word_id is not None: + if word_id != current_word: + current_word = word_id + current_word_index += 1 + mapping[current_word_index].append(idx) + + # Randomly mask words + mask = np.random.binomial(1, wwm_probability, (len(mapping),)) + input_ids = feature["input_ids"] + labels = feature["labels"] + new_labels = [-100] * len(labels) + for word_id in np.where(mask)[0]: + word_id = word_id.item() + for idx in mapping[word_id]: + new_labels[idx] = labels[idx] + input_ids[idx] = tokenizer.mask_token_id + feature["labels"] = new_labels + + return default_data_collator(features) +``` + +{:else} + +```py +import collections +import numpy as np + +from transformers.data.data_collator import tf_default_data_collator + +wwm_probability = 0.2 + + +def whole_word_masking_data_collator(features): + for feature in features: + word_ids = feature.pop("word_ids") + + # Create a map between words and corresponding token indices + mapping = collections.defaultdict(list) + current_word_index = -1 + current_word = None + for idx, word_id in enumerate(word_ids): + if word_id is not None: + if word_id != current_word: + current_word = word_id + current_word_index += 1 + mapping[current_word_index].append(idx) + + # Randomly mask words + mask = np.random.binomial(1, wwm_probability, (len(mapping),)) + input_ids = feature["input_ids"] + labels = feature["labels"] + new_labels = [-100] * len(labels) + for word_id in np.where(mask)[0]: + word_id = word_id.item() + for idx in mapping[word_id]: + new_labels[idx] = labels[idx] + input_ids[idx] = tokenizer.mask_token_id + feature["labels"] = new_labels + + return tf_default_data_collator(features) +``` + +{/if} + +അടുത്തതായി, മുമ്പത്തെ അതേ സാമ്പിളുകളിൽ ഇത് പരീക്ഷിക്കാം: + +```py +samples = [lm_datasets["train"][i] for i in range(2)] +batch = whole_word_masking_data_collator(samples) + +for chunk in batch["input_ids"]: + print(f"\n'>>> {tokenizer.decode(chunk)}'") +``` + +```python out +'>>> [CLS] bromwell high is a cartoon comedy [MASK] it ran at the same time as some other programs about school life, such as " teachers ". my 35 years in the teaching profession lead me to believe that bromwell high\'s satire is much closer to reality than is " teachers ". the scramble to survive financially, the insightful students who can see right through their pathetic teachers\'pomp, the pettiness of the whole situation, all remind me of the schools i knew and their students. when i saw the episode in which a student repeatedly tried to burn down the school, i immediately recalled.....' + +'>>> .... [MASK] [MASK] [MASK] [MASK]....... high. a classic line : inspector : i\'m here to sack one of your teachers. student : welcome to bromwell high. i expect that many adults of my age think that bromwell high is far fetched. what a pity that it isn\'t! [SEP] [CLS] homelessness ( or houselessness as george carlin stated ) has been an issue for years but never a plan to help those on the street that were once considered human who did everything from going to school, work, or vote for the matter. most people think of the homeless' +``` + +> [!TIP] +> ✏️ **പരീക്ഷിച്ചു നോക്കൂ!** ക്രമരഹിത മാസ്‌കിംഗ് നിങ്ങളുടെ കണ്മുന്നിൽ സംഭവിക്കുന്നത് കാണാൻ മുകളിലുള്ള കോഡ് സ്‌നിപ്പെറ്റ് പല തവണ റൺ ചെയ്യുക! കൂടാതെ, ഒരു വാക്കിലെ ടോക്കണുകൾ എപ്പോഴും ഒരുമിച്ചാണ് മാസ്‌ക് ചെയ്യപ്പെടുന്നത് എന്ന് കാണാൻ, `tokenizer.decode()` മെത്തേഡിന് പകരം `tokenizer.convert_ids_to_tokens()` ഉപയോഗിക്കുക. + +ഇപ്പോൾ നമുക്ക് രണ്ട് ഡേറ്റാ കൊളേറ്ററുകൾ ഉള്ളതിനാൽ, ഫൈൻ-ട്യൂണിംഗിന്റെ ബാക്കി ഘട്ടങ്ങൾ സാധാരണ രീതിയിലുള്ളവയാണ്. ഐതിഹാസികമായ ഒരു P100 GPU കിട്ടാനുള്ള ഭാഗ്യം നിങ്ങൾക്കില്ലെങ്കിൽ Google Colab-ൽ ട്രെയിനിംഗിന് കുറച്ച് സമയമെടുക്കാം 😭, അതിനാൽ ട്രെയിനിംഗ് സെറ്റിന്റെ വലുപ്പം ആദ്യം ഏതാനും ആയിരം ഉദാഹരണങ്ങളിലേക്ക് നമ്മൾ കുറയ്ക്കും (downsample). വിഷമിക്കേണ്ട, അപ്പോഴും തരക്കേടില്ലാത്ത ഒരു ലാംഗ്വേജ് മോഡൽ നമുക്ക് ലഭിക്കും! [അധ്യായം 5](/course/chapter5)-ൽ നമ്മൾ കണ്ട `Dataset.train_test_split()` ഫംഗ്‌ഷൻ ആണ് 🤗 Datasets-ൽ ഒരു ഡേറ്റാസെറ്റ് ഡൗൺസാമ്പിൾ ചെയ്യാനുള്ള ഒരു വേഗമേറിയ മാർഗം: + +```python +train_size = 10_000 +test_size = int(0.1 * train_size) + +downsampled_dataset = lm_datasets["train"].train_test_split( + train_size=train_size, test_size=test_size, seed=42 +) +downsampled_dataset +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['attention_mask', 'input_ids', 'labels', 'word_ids'], + num_rows: 10000 + }) + test: Dataset({ + features: ['attention_mask', 'input_ids', 'labels', 'word_ids'], + num_rows: 1000 + }) +}) +``` + +ഇത് പുതിയ `train`, `test` സ്‌പ്ലിറ്റുകൾ സ്വയമേവ ഉണ്ടാക്കിയിരിക്കുന്നു; ട്രെയിനിംഗ് സെറ്റിന്റെ വലുപ്പം 10,000 ഉദാഹരണങ്ങളും വാലിഡേഷൻ സെറ്റ് അതിന്റെ 10%-ഉം ആയി സെറ്റ് ചെയ്തിരിക്കുന്നു -- നിങ്ങൾക്ക് ഒരു ശക്തമായ GPU ഉണ്ടെങ്കിൽ ഇത് ധൈര്യമായി കൂട്ടാം! അടുത്തതായി നമ്മൾ ചെയ്യേണ്ടത് Hugging Face Hub-ൽ ലോഗിൻ ചെയ്യുകയാണ്. ഈ കോഡ് ഒരു നോട്ട്‌ബുക്കിലാണ് നിങ്ങൾ റൺ ചെയ്യുന്നതെങ്കിൽ, താഴെയുള്ള യൂട്ടിലിറ്റി ഫംഗ്‌ഷൻ ഉപയോഗിച്ച് അത് ചെയ്യാം: + +```python +from huggingface_hub import notebook_login + +notebook_login() +``` + +ഇത് നിങ്ങളുടെ ക്രെഡൻഷ്യലുകൾ നൽകാവുന്ന ഒരു വിജറ്റ് പ്രദർശിപ്പിക്കും. അല്ലെങ്കിൽ, താഴെയുള്ള കമാൻഡ്: + +``` +huggingface-cli login +``` + +നിങ്ങളുടെ ഇഷ്ടപ്പെട്ട ടെർമിനലിൽ റൺ ചെയ്ത് അവിടെ ലോഗിൻ ചെയ്യാം. + +{#if fw === 'tf'} + +ലോഗിൻ ചെയ്തുകഴിഞ്ഞാൽ, നമ്മുടെ `tf.data` ഡേറ്റാസെറ്റുകൾ ഉണ്ടാക്കാം. അതിനായി, ഏതൊക്കെ കോളങ്ങൾ ഡേറ്റാസെറ്റിൽ ഉൾപ്പെടണം എന്ന് നമ്മുടെ മോഡൽ ഉപയോഗിച്ച് സ്വയമേവ അനുമാനിക്കുന്ന `prepare_tf_dataset()` മെത്തേഡ് നമ്മൾ ഉപയോഗിക്കും. ഏതൊക്കെ കോളങ്ങൾ ഉപയോഗിക്കണം എന്ന് കൃത്യമായി നിയന്ത്രിക്കണമെങ്കിൽ, പകരം `Dataset.to_tf_dataset()` മെത്തേഡ് നിങ്ങൾക്ക് ഉപയോഗിക്കാം. കാര്യങ്ങൾ ലളിതമാക്കാൻ, ഇവിടെ നമ്മൾ സാധാരണ ഡേറ്റാ കൊളേറ്റർ മാത്രം ഉപയോഗിക്കും, എന്നാൽ ഒരു അഭ്യാസമായി ഹോൾ വേഡ് മാസ്‌കിംഗ് കൊളേറ്ററും പരീക്ഷിച്ച് ഫലങ്ങൾ താരതമ്യം ചെയ്യാം: + +```python +tf_train_dataset = model.prepare_tf_dataset( + downsampled_dataset["train"], + collate_fn=data_collator, + shuffle=True, + batch_size=32, +) + +tf_eval_dataset = model.prepare_tf_dataset( + downsampled_dataset["test"], + collate_fn=data_collator, + shuffle=False, + batch_size=32, +) +``` + +അടുത്തതായി, നമ്മുടെ ട്രെയിനിംഗ് ഹൈപ്പർപാരാമീറ്ററുകൾ സെറ്റപ്പ് ചെയ്ത് മോഡൽ കംപൈൽ ചെയ്യുന്നു. ലീനിയർ ലേണിംഗ് റേറ്റ് ഡികേയോടെ (linear learning rate decay) ഒരു `AdamW` ഒപ്‌റ്റിമൈസർ നൽകുന്ന, 🤗 Transformers ലൈബ്രറിയിലെ `create_optimizer()` ഫംഗ്‌ഷൻ നമ്മൾ ഉപയോഗിക്കുന്നു. `compile()`-ന് ആർഗ്യുമെന്റായി ലോസ് ഒന്നും വ്യക്തമാക്കാത്തപ്പോൾ ഡിഫോൾട്ടായ, മോഡലിന്റെ ബിൽറ്റ്-ഇൻ ലോസും നമ്മൾ ഉപയോഗിക്കുന്നു, കൂടാതെ ട്രെയിനിംഗ് പ്രിസിഷൻ `"mixed_float16"` എന്ന് സെറ്റ് ചെയ്യുന്നു. ആക്‌സിലറേറ്റഡ് float16 പിന്തുണയില്ലാത്ത ഒരു Colab GPU-വോ മറ്റ് GPU-വോ ആണ് നിങ്ങൾ ഉപയോഗിക്കുന്നതെങ്കിൽ, ആ വരി കമന്റ് ഔട്ട് ചെയ്യുന്നതായിരിക്കും നല്ലത് എന്നത് ശ്രദ്ധിക്കുക. + +കൂടാതെ, ഓരോ എപ്പോക്കിന് ശേഷവും മോഡൽ Hub-ലേക്ക് സേവ് ചെയ്യുന്ന ഒരു `PushToHubCallback` നമ്മൾ സെറ്റപ്പ് ചെയ്യുന്നു. നിങ്ങൾ പുഷ് ചെയ്യാൻ ആഗ്രഹിക്കുന്ന റിപ്പോസിറ്ററിയുടെ പേര് `hub_model_id` ആർഗ്യുമെന്റ് ഉപയോഗിച്ച് വ്യക്തമാക്കാം (പ്രത്യേകിച്ച്, ഒരു ഓർഗനൈസേഷനിലേക്ക് പുഷ് ചെയ്യാൻ ഈ ആർഗ്യുമെന്റ് നിങ്ങൾ ഉപയോഗിക്കേണ്ടി വരും). ഉദാഹരണത്തിന്, [`huggingface-course` ഓർഗനൈസേഷനിലേക്ക്](https://huggingface.co/huggingface-course) മോഡൽ പുഷ് ചെയ്യാൻ, ഞങ്ങൾ `hub_model_id="huggingface-course/distilbert-finetuned-imdb"` ചേർത്തു. ഡിഫോൾട്ടായി, ഉപയോഗിക്കുന്ന റിപ്പോസിറ്ററി നിങ്ങളുടെ നെയിംസ്‌പേസിലായിരിക്കും, നിങ്ങൾ സെറ്റ് ചെയ്ത ഔട്ട്‌പുട്ട് ഡയറക്ടറിയുടെ പേരിലായിരിക്കും അത്; അതിനാൽ നമ്മുടെ കാര്യത്തിൽ അത് `"lewtun/distilbert-finetuned-imdb"` ആയിരിക്കും. + +```python +from transformers import create_optimizer +from transformers.keras_callbacks import PushToHubCallback +import tensorflow as tf + +num_train_steps = len(tf_train_dataset) +optimizer, schedule = create_optimizer( + init_lr=2e-5, + num_warmup_steps=1_000, + num_train_steps=num_train_steps, + weight_decay_rate=0.01, +) +model.compile(optimizer=optimizer) + +# Train in mixed-precision float16 +tf.keras.mixed_precision.set_global_policy("mixed_float16") + +model_name = model_checkpoint.split("/")[-1] +callback = PushToHubCallback( + output_dir=f"{model_name}-finetuned-imdb", tokenizer=tokenizer +) +``` + +ഇപ്പോൾ `model.fit()` റൺ ചെയ്യാൻ നമ്മൾ തയ്യാറാണ് -- എന്നാൽ അതിന് മുമ്പ്, ലാംഗ്വേജ് മോഡലുകളുടെ പ്രകടനം ഇവാല്യുവേറ്റ് ചെയ്യാനുള്ള ഒരു സാധാരണ മെട്രിക്കായ _പെർപ്ലെക്‌സിറ്റി_ (perplexity) എന്താണെന്ന് ചുരുക്കത്തിൽ നോക്കാം. + +{:else} + +ലോഗിൻ ചെയ്തുകഴിഞ്ഞാൽ, `Trainer`-നുള്ള ആർഗ്യുമെന്റുകൾ നമുക്ക് വ്യക്തമാക്കാം: + +```python +from transformers import TrainingArguments + +batch_size = 64 +# Show the training loss with every epoch +logging_steps = len(downsampled_dataset["train"]) // batch_size +model_name = model_checkpoint.split("/")[-1] + +training_args = TrainingArguments( + output_dir=f"{model_name}-finetuned-imdb", + overwrite_output_dir=True, + evaluation_strategy="epoch", + learning_rate=2e-5, + weight_decay=0.01, + per_device_train_batch_size=batch_size, + per_device_eval_batch_size=batch_size, + push_to_hub=True, + fp16=True, + logging_steps=logging_steps, +) +``` + +ഓരോ എപ്പോക്കിലും ട്രെയിനിംഗ് ലോസ് ട്രാക്ക് ചെയ്യുന്നു എന്ന് ഉറപ്പാക്കാനുള്ള `logging_steps` ഉൾപ്പെടെ, ഡിഫോൾട്ട് ഓപ്‌ഷനുകളിൽ ചിലത് ഇവിടെ നമ്മൾ മാറ്റിയിട്ടുണ്ട്. മിക്‌സഡ്-പ്രിസിഷൻ ട്രെയിനിംഗ് പ്രവർത്തനക്ഷമമാക്കാൻ `fp16=True`-ഉം നമ്മൾ ഉപയോഗിച്ചിട്ടുണ്ട്; ഇത് വേഗതയിൽ മറ്റൊരു കുതിപ്പ് നൽകുന്നു. ഡിഫോൾട്ടായി, മോഡലിന്റെ `forward()` മെത്തേഡിന്റെ ഭാഗമല്ലാത്ത എല്ലാ കോളങ്ങളും `Trainer` നീക്കം ചെയ്യും. അതായത്, ഹോൾ വേഡ് മാസ്‌കിംഗ് കൊളേറ്ററാണ് നിങ്ങൾ ഉപയോഗിക്കുന്നതെങ്കിൽ, ട്രെയിനിംഗ് സമയത്ത് `word_ids` കോളം നഷ്ടപ്പെടാതിരിക്കാൻ `remove_unused_columns=False` എന്നും നിങ്ങൾ സെറ്റ് ചെയ്യേണ്ടി വരും. + +നിങ്ങൾ പുഷ് ചെയ്യാൻ ആഗ്രഹിക്കുന്ന റിപ്പോസിറ്ററിയുടെ പേര് `hub_model_id` ആർഗ്യുമെന്റ് ഉപയോഗിച്ച് വ്യക്തമാക്കാം എന്നത് ശ്രദ്ധിക്കുക (പ്രത്യേകിച്ച്, ഒരു ഓർഗനൈസേഷനിലേക്ക് പുഷ് ചെയ്യാൻ ഈ ആർഗ്യുമെന്റ് നിങ്ങൾ ഉപയോഗിക്കേണ്ടി വരും). ഉദാഹരണത്തിന്, [`huggingface-course` ഓർഗനൈസേഷനിലേക്ക്](https://huggingface.co/huggingface-course) മോഡൽ പുഷ് ചെയ്തപ്പോൾ, ഞങ്ങൾ `TrainingArguments`-ൽ `hub_model_id="huggingface-course/distilbert-finetuned-imdb"` ചേർത്തു. ഡിഫോൾട്ടായി, ഉപയോഗിക്കുന്ന റിപ്പോസിറ്ററി നിങ്ങളുടെ നെയിംസ്‌പേസിലായിരിക്കും, നിങ്ങൾ സെറ്റ് ചെയ്ത ഔട്ട്‌പുട്ട് ഡയറക്ടറിയുടെ പേരിലായിരിക്കും അത്; അതിനാൽ നമ്മുടെ കാര്യത്തിൽ അത് `"lewtun/distilbert-finetuned-imdb"` ആയിരിക്കും. + +`Trainer` ഇൻസ്‌റ്റാൻഷിയേറ്റ് ചെയ്യാനുള്ള എല്ലാ ചേരുവകളും ഇപ്പോൾ നമുക്കുണ്ട്. ഇവിടെ നമ്മൾ സാധാരണ `data_collator` മാത്രമേ ഉപയോഗിക്കുന്നുള്ളൂ, എന്നാൽ ഒരു അഭ്യാസമായി ഹോൾ വേഡ് മാസ്‌കിംഗ് കൊളേറ്റർ പരീക്ഷിച്ച് ഫലങ്ങൾ താരതമ്യം ചെയ്യാം: + +```python +from transformers import Trainer + +trainer = Trainer( + model=model, + args=training_args, + train_dataset=downsampled_dataset["train"], + eval_dataset=downsampled_dataset["test"], + data_collator=data_collator, + tokenizer=tokenizer, +) +``` + +ഇപ്പോൾ `trainer.train()` റൺ ചെയ്യാൻ നമ്മൾ തയ്യാറാണ് -- എന്നാൽ അതിന് മുമ്പ്, ലാംഗ്വേജ് മോഡലുകളുടെ പ്രകടനം ഇവാല്യുവേറ്റ് ചെയ്യാനുള്ള ഒരു സാധാരണ മെട്രിക്കായ _പെർപ്ലെക്‌സിറ്റി_ (perplexity) എന്താണെന്ന് ചുരുക്കത്തിൽ നോക്കാം. + +{/if} + +### ലാംഗ്വേജ് മോഡലുകൾക്കുള്ള പെർപ്ലെക്‌സിറ്റി[[perplexity-for-language-models]] + + + +ട്രെയിൻ ചെയ്യാൻ ലേബൽ ചെയ്ത ഒരു കോർപ്പസ് നമുക്ക് നൽകപ്പെടുന്ന ടെക്‌സ്‌റ്റ് ക്ലാസിഫിക്കേഷൻ, ക്വസ്‌റ്റ്യൻ ആൻസറിംഗ് പോലുള്ള മറ്റ് ടാസ്‌ക്കുകളിൽ നിന്ന് വ്യത്യസ്തമായി, ലാംഗ്വേജ് മോഡലിംഗിൽ നമുക്ക് വ്യക്തമായ ലേബലുകളൊന്നുമില്ല. അപ്പോൾ ഒരു ലാംഗ്വേജ് മോഡലിനെ നല്ലതാക്കുന്നത് എന്താണെന്ന് നമ്മൾ എങ്ങനെ നിർണ്ണയിക്കും? നിങ്ങളുടെ ഫോണിലെ ഓട്ടോകറക്റ്റ് സവിശേഷത പോലെ, വ്യാകരണപരമായി ശരിയായ വാക്യങ്ങൾക്ക് ഉയർന്ന പ്രോബബിലിറ്റികളും അർത്ഥമില്ലാത്ത വാക്യങ്ങൾക്ക് കുറഞ്ഞ പ്രോബബിലിറ്റികളും നൽകുന്ന ഒന്നാണ് ഒരു നല്ല ലാംഗ്വേജ് മോഡൽ. ഇത് എങ്ങനെയിരിക്കും എന്നതിനെക്കുറിച്ച് ഒരു മികച്ച ധാരണ ലഭിക്കാൻ, ഒരാളുടെ ഫോണിലെ മോഡൽ തമാശ നിറഞ്ഞ (പലപ്പോഴും അനുചിതമായ) പൂരണങ്ങൾ ഉണ്ടാക്കിയിട്ടുള്ള "ഓട്ടോകറക്റ്റ് പരാജയങ്ങളുടെ" (autocorrect fails) മുഴുവൻ ശേഖരങ്ങളും നിങ്ങൾക്ക് ഓൺലൈനിൽ കാണാം! + +{#if fw === 'pt'} + +നമ്മുടെ ടെസ്‌റ്റ് സെറ്റിൽ ഭൂരിഭാഗവും വ്യാകരണപരമായി ശരിയായ വാക്യങ്ങളാണ് എന്ന് അനുമാനിച്ചാൽ, ടെസ്‌റ്റ് സെറ്റിലെ എല്ലാ വാക്യങ്ങളിലെയും അടുത്ത വാക്കിന് മോഡൽ നൽകുന്ന പ്രോബബിലിറ്റികൾ കണക്കാക്കുകയാണ് നമ്മുടെ ലാംഗ്വേജ് മോഡലിന്റെ ഗുണനിലവാരം അളക്കാനുള്ള ഒരു മാർഗം. ഉയർന്ന പ്രോബബിലിറ്റികൾ, കാണാത്ത ഉദാഹരണങ്ങൾ കണ്ട് മോഡൽ "അത്ഭുതപ്പെടുന്നില്ല" അല്ലെങ്കിൽ "കുഴങ്ങുന്നില്ല" (perplexed) എന്ന് സൂചിപ്പിക്കുന്നു, കൂടാതെ ഭാഷയിലെ വ്യാകരണത്തിന്റെ അടിസ്ഥാന പാറ്റേണുകൾ അത് പഠിച്ചിട്ടുണ്ട് എന്നും സൂചിപ്പിക്കുന്നു. പെർപ്ലെക്‌സിറ്റിക്ക് വിവിധ ഗണിതശാസ്ത്ര നിർവചനങ്ങളുണ്ട്, എന്നാൽ നമ്മൾ ഉപയോഗിക്കുന്ന നിർവചനം അതിനെ ക്രോസ്-എൻട്രോപ്പി ലോസിന്റെ എക്‌സ്‌പോണൻഷ്യൽ ആയി നിർവചിക്കുന്നു. അതിനാൽ, ടെസ്‌റ്റ് സെറ്റിലെ ക്രോസ്-എൻട്രോപ്പി ലോസ് കണക്കാക്കാൻ `Trainer.evaluate()` ഫംഗ്‌ഷൻ ഉപയോഗിച്ച്, തുടർന്ന് ഫലത്തിന്റെ എക്‌സ്‌പോണൻഷ്യൽ എടുത്ത്, നമ്മുടെ പ്രീട്രെയിൻഡ് മോഡലിന്റെ പെർപ്ലെക്‌സിറ്റി നമുക്ക് കണക്കാക്കാം: + +```python +import math + +eval_results = trainer.evaluate() +print(f">>> Perplexity: {math.exp(eval_results['eval_loss']):.2f}") +``` + +{:else} + +നമ്മുടെ ടെസ്‌റ്റ് സെറ്റിൽ ഭൂരിഭാഗവും വ്യാകരണപരമായി ശരിയായ വാക്യങ്ങളാണ് എന്ന് അനുമാനിച്ചാൽ, ടെസ്‌റ്റ് സെറ്റിലെ എല്ലാ വാക്യങ്ങളിലെയും അടുത്ത വാക്കിന് മോഡൽ നൽകുന്ന പ്രോബബിലിറ്റികൾ കണക്കാക്കുകയാണ് നമ്മുടെ ലാംഗ്വേജ് മോഡലിന്റെ ഗുണനിലവാരം അളക്കാനുള്ള ഒരു മാർഗം. ഉയർന്ന പ്രോബബിലിറ്റികൾ, കാണാത്ത ഉദാഹരണങ്ങൾ കണ്ട് മോഡൽ "അത്ഭുതപ്പെടുന്നില്ല" അല്ലെങ്കിൽ "കുഴങ്ങുന്നില്ല" (perplexed) എന്ന് സൂചിപ്പിക്കുന്നു, കൂടാതെ ഭാഷയിലെ വ്യാകരണത്തിന്റെ അടിസ്ഥാന പാറ്റേണുകൾ അത് പഠിച്ചിട്ടുണ്ട് എന്നും സൂചിപ്പിക്കുന്നു. പെർപ്ലെക്‌സിറ്റിക്ക് വിവിധ ഗണിതശാസ്ത്ര നിർവചനങ്ങളുണ്ട്, എന്നാൽ നമ്മൾ ഉപയോഗിക്കുന്ന നിർവചനം അതിനെ ക്രോസ്-എൻട്രോപ്പി ലോസിന്റെ എക്‌സ്‌പോണൻഷ്യൽ ആയി നിർവചിക്കുന്നു. അതിനാൽ, ടെസ്‌റ്റ് സെറ്റിലെ ക്രോസ്-എൻട്രോപ്പി ലോസ് കണക്കാക്കാൻ `model.evaluate()` മെത്തേഡ് ഉപയോഗിച്ച്, തുടർന്ന് ഫലത്തിന്റെ എക്‌സ്‌പോണൻഷ്യൽ എടുത്ത്, നമ്മുടെ പ്രീട്രെയിൻഡ് മോഡലിന്റെ പെർപ്ലെക്‌സിറ്റി നമുക്ക് കണക്കാക്കാം: + +```python +import math + +eval_loss = model.evaluate(tf_eval_dataset) +print(f"Perplexity: {math.exp(eval_loss):.2f}") +``` + +{/if} + +```python out +>>> Perplexity: 21.75 +``` + +കുറഞ്ഞ പെർപ്ലെക്‌സിറ്റി സ്‌കോർ എന്നാൽ മികച്ച ലാംഗ്വേജ് മോഡൽ എന്നാണ് അർത്ഥം; നമ്മുടെ തുടക്ക മോഡലിന് അൽപ്പം വലിയ മൂല്യമാണുള്ളതെന്ന് ഇവിടെ കാണാം. ഫൈൻ-ട്യൂണിംഗ് വഴി ഇത് കുറയ്ക്കാൻ കഴിയുമോ എന്ന് നോക്കാം! അതിനായി, നമ്മൾ ആദ്യം ട്രെയിനിംഗ് ലൂപ്പ് റൺ ചെയ്യുന്നു: + +{#if fw === 'pt'} + +```python +trainer.train() +``` + +{:else} + +```python +model.fit(tf_train_dataset, validation_data=tf_eval_dataset, callbacks=[callback]) +``` + +{/if} + +തുടർന്ന്, മുമ്പത്തെപ്പോലെ ടെസ്‌റ്റ് സെറ്റിലെ പെർപ്ലെക്‌സിറ്റി കണക്കാക്കുന്നു: + +{#if fw === 'pt'} + +```python +eval_results = trainer.evaluate() +print(f">>> Perplexity: {math.exp(eval_results['eval_loss']):.2f}") +``` + +{:else} + +```python +eval_loss = model.evaluate(tf_eval_dataset) +print(f"Perplexity: {math.exp(eval_loss):.2f}") +``` + +{/if} + +```python out +>>> Perplexity: 11.32 +``` + +കൊള്ളാം -- പെർപ്ലെക്‌സിറ്റിയിൽ ഇത് ഗണ്യമായ ഒരു കുറവാണ്; സിനിമാ റിവ്യൂകളുടെ ഡൊമെയ്‌നെക്കുറിച്ച് മോഡൽ എന്തെങ്കിലും പഠിച്ചിട്ടുണ്ട് എന്ന് ഇത് നമ്മോട് പറയുന്നു! + +{#if fw === 'pt'} + +ട്രെയിനിംഗ് പൂർത്തിയായിക്കഴിഞ്ഞാൽ, ട്രെയിനിംഗ് വിവരങ്ങളോടു കൂടിയ മോഡൽ കാർഡ് Hub-ലേക്ക് പുഷ് ചെയ്യാം (ചെക്ക്‌പോയിന്റുകൾ ട്രെയിനിംഗ് സമയത്ത് തന്നെ സേവ് ചെയ്യപ്പെടുന്നു): + +```python +trainer.push_to_hub() +``` + +{/if} + +> [!TIP] +> ✏️ **ഇനി നിങ്ങളുടെ ഊഴം!** ഡേറ്റാ കൊളേറ്റർ ഹോൾ വേഡ് മാസ്‌കിംഗ് കൊളേറ്ററിലേക്ക് മാറ്റിയ ശേഷം മുകളിലുള്ള ട്രെയിനിംഗ് റൺ ചെയ്യുക. നിങ്ങൾക്ക് മികച്ച ഫലങ്ങൾ ലഭിക്കുന്നുണ്ടോ? + +{#if fw === 'pt'} + +നമ്മുടെ ഉപയോഗ സാഹചര്യത്തിൽ ട്രെയിനിംഗ് ലൂപ്പിൽ പ്രത്യേകിച്ച് ഒന്നും ചെയ്യേണ്ടി വന്നില്ല, എന്നാൽ ചില സാഹചര്യങ്ങളിൽ കസ്‌റ്റം ലോജിക് നിങ്ങൾക്ക് ഇംപ്ലിമെന്റ് ചെയ്യേണ്ടി വന്നേക്കാം. അത്തരം ആപ്ലിക്കേഷനുകൾക്ക് 🤗 Accelerate ഉപയോഗിക്കാം -- നമുക്ക് ഒന്ന് നോക്കാം! + +## 🤗 Accelerate ഉപയോഗിച്ച് DistilBERT ഫൈൻ-ട്യൂൻ ചെയ്യുന്നു[[fine-tuning-distilbert-with-accelerate]] + +`Trainer`-ന്റെ കാര്യത്തിൽ കണ്ടതുപോലെ, ഒരു മാസ്‌ക്‌ഡ് ലാംഗ്വേജ് മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യുന്നത് [അധ്യായം 3](/course/chapter3)-ലെ ടെക്‌സ്‌റ്റ് ക്ലാസിഫിക്കേഷൻ ഉദാഹരണത്തിന് വളരെ സമാനമാണ്. വാസ്തവത്തിൽ, ഒരു പ്രത്യേക ഡേറ്റാ കൊളേറ്ററിന്റെ ഉപയോഗം മാത്രമാണ് ഇവിടത്തെ ഒരേയൊരു സൂക്ഷ്മവ്യത്യാസം, അത് ഈ ഭാഗത്തിൽ നേരത്തെ തന്നെ നമ്മൾ പരിശോധിച്ചു കഴിഞ്ഞു! + +എന്നാൽ, `DataCollatorForLanguageModeling` ഓരോ ഇവാല്യുവേഷനിലും ക്രമരഹിത മാസ്‌കിംഗ് പ്രയോഗിക്കുന്നു എന്ന് നമ്മൾ കണ്ടു, അതിനാൽ ഓരോ ട്രെയിനിംഗ് റണ്ണിലും നമ്മുടെ പെർപ്ലെക്‌സിറ്റി സ്‌കോറുകളിൽ ചില ചാഞ്ചാട്ടങ്ങൾ കാണാം. ക്രമരഹിതതയുടെ ഈ ഉറവിടം ഇല്ലാതാക്കാനുള്ള ഒരു മാർഗം, മുഴുവൻ ടെസ്‌റ്റ് സെറ്റിലും മാസ്‌കിംഗ് _ഒരിക്കൽ മാത്രം_ പ്രയോഗിച്ച ശേഷം, ഇവാല്യുവേഷൻ സമയത്ത് ബാച്ചുകൾ ശേഖരിക്കാൻ 🤗 Transformers-ലെ ഡിഫോൾട്ട് ഡേറ്റാ കൊളേറ്റർ ഉപയോഗിക്കുകയാണ്. ഇത് എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് കാണാൻ, `DataCollatorForLanguageModeling`-മായുള്ള നമ്മുടെ ആദ്യ പരിചയത്തിന് സമാനമായി, ഒരു ബാച്ചിൽ മാസ്‌കിംഗ് പ്രയോഗിക്കുന്ന ഒരു ലളിതമായ ഫംഗ്‌ഷൻ ഇംപ്ലിമെന്റ് ചെയ്യാം: + +```python +def insert_random_mask(batch): + features = [dict(zip(batch, t)) for t in zip(*batch.values())] + masked_inputs = data_collator(features) + # Create a new "masked" column for each column in the dataset + return {"masked_" + k: v.numpy() for k, v in masked_inputs.items()} +``` + +അടുത്തതായി, ഈ ഫംഗ്‌ഷൻ നമ്മുടെ ടെസ്‌റ്റ് സെറ്റിൽ പ്രയോഗിച്ച്, മാസ്‌ക് ചെയ്യാത്ത കോളങ്ങൾ ഒഴിവാക്കും, അങ്ങനെ അവയ്ക്ക് പകരം മാസ്‌ക് ചെയ്ത കോളങ്ങൾ വയ്ക്കാം. മുകളിലുള്ള `data_collator`-ന് പകരം അനുയോജ്യമായത് ഉപയോഗിച്ചുകൊണ്ട് ഹോൾ വേഡ് മാസ്‌കിംഗ് നിങ്ങൾക്ക് ഉപയോഗിക്കാം; ആ സാഹചര്യത്തിൽ ഇവിടത്തെ ആദ്യത്തെ വരി നിങ്ങൾ നീക്കം ചെയ്യണം: + +```py +downsampled_dataset = downsampled_dataset.remove_columns(["word_ids"]) +eval_dataset = downsampled_dataset["test"].map( + insert_random_mask, + batched=True, + remove_columns=downsampled_dataset["test"].column_names, +) +eval_dataset = eval_dataset.rename_columns( + { + "masked_input_ids": "input_ids", + "masked_attention_mask": "attention_mask", + "masked_labels": "labels", + } +) +``` + +തുടർന്ന് പതിവുപോലെ ഡേറ്റാലോഡറുകൾ സെറ്റപ്പ് ചെയ്യാം, എന്നാൽ ഇവാല്യുവേഷൻ സെറ്റിനായി 🤗 Transformers-ലെ `default_data_collator` നമ്മൾ ഉപയോഗിക്കും: + +```python +from torch.utils.data import DataLoader +from transformers import default_data_collator + +batch_size = 64 +train_dataloader = DataLoader( + downsampled_dataset["train"], + shuffle=True, + batch_size=batch_size, + collate_fn=data_collator, +) +eval_dataloader = DataLoader( + eval_dataset, batch_size=batch_size, collate_fn=default_data_collator +) +``` + +ഇവിടെ നിന്ന്, 🤗 Accelerate-ന്റെ സാധാരണ ഘട്ടങ്ങൾ നമ്മൾ പിന്തുടരുന്നു. ആദ്യം ചെയ്യേണ്ടത് പ്രീട്രെയിൻഡ് മോഡലിന്റെ ഒരു പുതിയ പതിപ്പ് ലോഡ് ചെയ്യുകയാണ്: + +``` +model = AutoModelForMaskedLM.from_pretrained(model_checkpoint) +``` + +തുടർന്ന് ഒപ്‌റ്റിമൈസർ വ്യക്തമാക്കണം; സാധാരണ `AdamW` നമ്മൾ ഉപയോഗിക്കും: + +```python +from torch.optim import AdamW + +optimizer = AdamW(model.parameters(), lr=5e-5) +``` + +ഈ ഒബ്‌ജക്റ്റുകൾ ഉപയോഗിച്ച്, `Accelerator` ഒബ്‌ജക്റ്റ് വഴി ട്രെയിനിംഗിനായി എല്ലാം ഇപ്പോൾ തയ്യാറാക്കാം: + +```python +from accelerate import Accelerator + +accelerator = Accelerator() +model, optimizer, train_dataloader, eval_dataloader = accelerator.prepare( + model, optimizer, train_dataloader, eval_dataloader +) +``` + +നമ്മുടെ മോഡലും ഒപ്‌റ്റിമൈസറും ഡേറ്റാലോഡറുകളും കോൺഫിഗർ ചെയ്തുകഴിഞ്ഞ സ്ഥിതിക്ക്, ലേണിംഗ് റേറ്റ് ഷെഡ്യൂളർ താഴെ കാണുന്നതുപോലെ വ്യക്തമാക്കാം: + +```python +from transformers import get_scheduler + +num_train_epochs = 3 +num_update_steps_per_epoch = len(train_dataloader) +num_training_steps = num_train_epochs * num_update_steps_per_epoch + +lr_scheduler = get_scheduler( + "linear", + optimizer=optimizer, + num_warmup_steps=0, + num_training_steps=num_training_steps, +) +``` + +ട്രെയിനിംഗിന് മുമ്പ് ചെയ്യാൻ ഇനി ഒരു കാര്യം മാത്രം ബാക്കിയുണ്ട്: Hugging Face Hub-ൽ ഒരു മോഡൽ റിപ്പോസിറ്ററി ഉണ്ടാക്കുക! നമ്മുടെ റിപ്പോയുടെ പൂർണ്ണമായ പേര് ആദ്യം ജനറേറ്റ് ചെയ്യാൻ 🤗 Hub ലൈബ്രറി ഉപയോഗിക്കാം: + +```python +from huggingface_hub import get_full_repo_name + +model_name = "distilbert-base-uncased-finetuned-imdb-accelerate" +repo_name = get_full_repo_name(model_name) +repo_name +``` + +```python out +'lewtun/distilbert-base-uncased-finetuned-imdb-accelerate' +``` + +തുടർന്ന് 🤗 Hub-ലെ `Repository` ക്ലാസ് ഉപയോഗിച്ച് റിപ്പോസിറ്ററി ഉണ്ടാക്കി ക്ലോൺ ചെയ്യുക: + +```python +from huggingface_hub import Repository + +output_dir = model_name +repo = Repository(output_dir, clone_from=repo_name) +``` + +അത് കഴിഞ്ഞാൽ, പൂർണ്ണമായ ട്രെയിനിംഗ്, ഇവാല്യുവേഷൻ ലൂപ്പ് എഴുതുക എന്ന ലളിതമായ കാര്യം മാത്രമേ ബാക്കിയുള്ളൂ: + +```python +from tqdm.auto import tqdm +import torch +import math + +progress_bar = tqdm(range(num_training_steps)) + +for epoch in range(num_train_epochs): + # Training + model.train() + for batch in train_dataloader: + outputs = model(**batch) + loss = outputs.loss + accelerator.backward(loss) + + optimizer.step() + lr_scheduler.step() + optimizer.zero_grad() + progress_bar.update(1) + + # Evaluation + model.eval() + losses = [] + for step, batch in enumerate(eval_dataloader): + with torch.no_grad(): + outputs = model(**batch) + + loss = outputs.loss + losses.append(accelerator.gather(loss.repeat(batch_size))) + + losses = torch.cat(losses) + losses = losses[: len(eval_dataset)] + try: + perplexity = math.exp(torch.mean(losses)) + except OverflowError: + perplexity = float("inf") + + print(f">>> Epoch {epoch}: Perplexity: {perplexity}") + + # Save and upload + accelerator.wait_for_everyone() + unwrapped_model = accelerator.unwrap_model(model) + unwrapped_model.save_pretrained(output_dir, save_function=accelerator.save) + if accelerator.is_main_process: + tokenizer.save_pretrained(output_dir) + repo.push_to_hub( + commit_message=f"Training in progress epoch {epoch}", blocking=False + ) +``` + +```python out +>>> Epoch 0: Perplexity: 11.397545307900472 +>>> Epoch 1: Perplexity: 10.904909330983092 +>>> Epoch 2: Perplexity: 10.729503505340409 +``` + +കൊള്ളാം, ഓരോ എപ്പോക്കിലും പെർപ്ലെക്‌സിറ്റി ഇവാല്യുവേറ്റ് ചെയ്യാനും, ഒന്നിലധികം ട്രെയിനിംഗ് റണ്ണുകൾ പുനരുൽപ്പാദിപ്പിക്കാവുന്നവയാണ് (reproducible) എന്ന് ഉറപ്പാക്കാനും നമുക്ക് കഴിഞ്ഞു! + +{/if} + +## ഫൈൻ-ട്യൂൻ ചെയ്ത നമ്മുടെ മോഡൽ ഉപയോഗിക്കുന്നു[[using-our-fine-tuned-model]] + +Hub-ലെ അതിന്റെ വിജറ്റ് ഉപയോഗിച്ചോ, അല്ലെങ്കിൽ ലോക്കലായി 🤗 Transformers-ലെ `pipeline` ഉപയോഗിച്ചോ, ഫൈൻ-ട്യൂൻ ചെയ്ത നിങ്ങളുടെ മോഡലുമായി നിങ്ങൾക്ക് സംവദിക്കാം. `fill-mask` പൈപ്പ്‌ലൈൻ ഉപയോഗിച്ച് നമ്മുടെ മോഡൽ ഡൗൺലോഡ് ചെയ്യാൻ രണ്ടാമത്തെ രീതി ഉപയോഗിക്കാം: + +```python +from transformers import pipeline + +mask_filler = pipeline( + "fill-mask", model="huggingface-course/distilbert-base-uncased-finetuned-imdb" +) +``` + +തുടർന്ന് "This is a great [MASK]" എന്ന നമ്മുടെ സാമ്പിൾ ടെക്‌സ്‌റ്റ് പൈപ്പ്‌ലൈനിന് നൽകി, മികച്ച 5 പ്രവചനങ്ങൾ എന്തൊക്കെയാണെന്ന് നോക്കാം: + +```python +preds = mask_filler(text) + +for pred in preds: + print(f">>> {pred['sequence']}") +``` + +```python out +'>>> this is a great movie.' +'>>> this is a great film.' +'>>> this is a great story.' +'>>> this is a great movies.' +'>>> this is a great character.' +``` + +കൊള്ളാം -- സിനിമകളുമായി കൂടുതൽ ശക്തമായി ബന്ധപ്പെട്ട വാക്കുകൾ പ്രവചിക്കാൻ നമ്മുടെ മോഡൽ അതിന്റെ വെയ്‌റ്റുകൾ വ്യക്തമായി പൊരുത്തപ്പെടുത്തിയിരിക്കുന്നു! + + + +ഒരു ലാംഗ്വേജ് മോഡൽ ട്രെയിൻ ചെയ്യുന്ന നമ്മുടെ ആദ്യ പരീക്ഷണം ഇവിടെ അവസാനിക്കുന്നു. [ഭാഗം 6](/course/en/chapter7/6)-ൽ GPT-2 പോലുള്ള ഒരു ഓട്ടോ-റിഗ്രസ്സീവ് മോഡൽ പൂജ്യത്തിൽ നിന്ന് (from scratch) എങ്ങനെ ട്രെയിൻ ചെയ്യാമെന്ന് നിങ്ങൾ പഠിക്കും; നിങ്ങളുടെ സ്വന്തം Transformer മോഡൽ എങ്ങനെ പ്രീട്രെയിൻ ചെയ്യാമെന്ന് കാണണമെങ്കിൽ അവിടേക്ക് പോകുക! + +> [!TIP] +> ✏️ **പരീക്ഷിച്ചു നോക്കൂ!** ഡൊമെയ്ൻ അഡാപ്‌റ്റേഷന്റെ പ്രയോജനങ്ങൾ അളക്കാൻ, പ്രീട്രെയിൻഡ്, ഫൈൻ-ട്യൂൻ ചെയ്ത DistilBERT ചെക്ക്‌പോയിന്റുകൾ രണ്ടിലും IMDb ലേബലുകളിൽ ഒരു ക്ലാസിഫയർ ഫൈൻ-ട്യൂൻ ചെയ്യുക. ടെക്‌സ്‌റ്റ് ക്ലാസിഫിക്കേഷനെക്കുറിച്ച് ഒരു ഓർമ്മപ്പുതുക്കൽ വേണമെങ്കിൽ, [അധ്യായം 3](/course/chapter3) പരിശോധിക്കുക. diff --git a/chapters/ml/chapter7/4.mdx b/chapters/ml/chapter7/4.mdx new file mode 100644 index 000000000..c3e48313f --- /dev/null +++ b/chapters/ml/chapter7/4.mdx @@ -0,0 +1,981 @@ + + +# വിവർത്തനം[[translation]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +ഇനി നമുക്ക് വിവർത്തനത്തിലേക്ക് (translation) കടക്കാം. ഇത് മറ്റൊരു [സീക്വൻസ്-ടു-സീക്വൻസ് ടാസ്‌ക്](/course/chapter1/7) ആണ്; അതായത്, ഒരു സീക്വൻസിൽ നിന്ന് മറ്റൊരു സീക്വൻസിലേക്ക് പോകുന്നതായി രൂപപ്പെടുത്താവുന്ന ഒരു പ്രശ്‌നമാണിത്. ആ അർത്ഥത്തിൽ ഈ പ്രശ്‌നം [സംഗ്രഹത്തോട് (summarization)](/course/chapter7/6) ഏറെ അടുത്തുനിൽക്കുന്നു, കൂടാതെ ഇവിടെ നമ്മൾ കാണുന്ന കാര്യങ്ങൾ താഴെപ്പറയുന്നതുപോലുള്ള മറ്റ് സീക്വൻസ്-ടു-സീക്വൻസ് പ്രശ്‌നങ്ങൾക്കും നിങ്ങൾക്ക് അനുയോജ്യമാക്കി ഉപയോഗിക്കാം: + +- **സ്‌റ്റൈൽ ട്രാൻസ്‌ഫർ (Style transfer)**: ഒരു പ്രത്യേക ശൈലിയിൽ എഴുതിയ ടെക്‌സ്‌റ്റുകളെ മറ്റൊരു ശൈലിയിലേക്ക് *വിവർത്തനം ചെയ്യുന്ന* ഒരു മോഡൽ നിർമ്മിക്കുക (ഉദാ., ഔപചാരികമായതിൽ നിന്ന് അനൗപചാരികമായതിലേക്ക്, അല്ലെങ്കിൽ ഷേക്‌സ്‌പിയർ കാലത്തെ ഇംഗ്ലീഷിൽ നിന്ന് ആധുനിക ഇംഗ്ലീഷിലേക്ക്) +- **ജനറേറ്റീവ് ക്വസ്‌റ്റ്യൻ ആൻസറിംഗ് (Generative question answering)**: ഒരു കോൺടെക്‌സ്‌റ്റ് നൽകിയാൽ ചോദ്യങ്ങൾക്ക് ഉത്തരങ്ങൾ ജനറേറ്റ് ചെയ്യുന്ന ഒരു മോഡൽ നിർമ്മിക്കുക + + + +രണ്ടോ (അതിലധികമോ) ഭാഷകളിലുള്ള ടെക്‌സ്‌റ്റുകളുടെ മതിയായ വലിപ്പമുള്ള ഒരു കോർപ്പസ് (corpus) നിങ്ങളുടെ കൈവശമുണ്ടെങ്കിൽ, [കോസൽ ലാംഗ്വേജ് മോഡലിംഗ്](/course/chapter7/6)-നെക്കുറിച്ചുള്ള ഭാഗത്തിൽ നമ്മൾ ചെയ്യുന്നതുപോലെ ഒരു പുതിയ വിവർത്തന മോഡൽ പൂജ്യത്തിൽ നിന്ന് ട്രെയിൻ ചെയ്യാം. എന്നാൽ, നിലവിലുള്ള ഒരു വിവർത്തന മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യുന്നതായിരിക്കും കൂടുതൽ വേഗത്തിലുള്ളത് — അത് ഒരു പ്രത്യേക ഭാഷാജോഡിയിലേക്ക് ഫൈൻ-ട്യൂൻ ചെയ്യാൻ നിങ്ങൾ ആഗ്രഹിക്കുന്ന mT5 അല്ലെങ്കിൽ mBART പോലുള്ള ഒരു ബഹുഭാഷാ (multilingual) മോഡലായാലും, അല്ലെങ്കിൽ നിങ്ങളുടെ പ്രത്യേക കോർപ്പസിലേക്ക് ഫൈൻ-ട്യൂൻ ചെയ്യാൻ ആഗ്രഹിക്കുന്ന, ഒരു ഭാഷയിൽ നിന്ന് മറ്റൊന്നിലേക്കുള്ള വിവർത്തനത്തിനായി പ്രത്യേകം തയ്യാറാക്കിയ ഒരു മോഡലായാലും. + +ഈ ഭാഗത്തിൽ, ഇംഗ്ലീഷിൽ നിന്ന് ഫ്രഞ്ചിലേക്ക് വിവർത്തനം ചെയ്യാൻ പ്രീട്രെയിൻ ചെയ്ത ഒരു Marian മോഡൽ (Hugging Face-ലെ ധാരാളം ജീവനക്കാർ ഈ രണ്ട് ഭാഷകളും സംസാരിക്കുന്നവരാണ് എന്നതിനാൽ) [KDE4 ഡേറ്റാസെറ്റിൽ](https://huggingface.co/datasets/kde4) നമ്മൾ ഫൈൻ-ട്യൂൻ ചെയ്യും; [KDE ആപ്പുകൾക്കായുള്ള](https://apps.kde.org/) ലോക്കലൈസ് ചെയ്ത ഫയലുകളുടെ ഒരു ഡേറ്റാസെറ്റാണിത്. നമ്മൾ ഉപയോഗിക്കുന്ന മോഡൽ, [Opus ഡേറ്റാസെറ്റിൽ](https://opus.nlpl.eu/) നിന്നെടുത്ത ഫ്രഞ്ച്, ഇംഗ്ലീഷ് ടെക്‌സ്‌റ്റുകളുടെ ഒരു വലിയ കോർപ്പസിലാണ് പ്രീട്രെയിൻ ചെയ്തിരിക്കുന്നത്; അതിൽ യഥാർത്ഥത്തിൽ KDE4 ഡേറ്റാസെറ്റും ഉൾപ്പെടുന്നു. എന്നാൽ നമ്മൾ ഉപയോഗിക്കുന്ന പ്രീട്രെയിൻഡ് മോഡൽ പ്രീട്രെയിനിംഗ് സമയത്ത് ആ ഡേറ്റ കണ്ടിട്ടുണ്ടെങ്കിലും, ഫൈൻ-ട്യൂണിംഗിന് ശേഷം അതിന്റെ കൂടുതൽ മെച്ചപ്പെട്ട ഒരു പതിപ്പ് നമുക്ക് ലഭിക്കുമെന്ന് നമ്മൾ കാണും. + +പൂർത്തിയാകുമ്പോൾ, ഇതുപോലുള്ള പ്രവചനങ്ങൾ (predictions) നടത്താൻ കഴിവുള്ള ഒരു മോഡൽ നമുക്കുണ്ടാകും: + + + + +ക്വസ്‌റ്റ്യൻ ആൻസറിംഗിനുള്ള വൺ-ഹോട്ട് എൻകോഡ് ചെയ്ത ലേബലുകൾ. + + + +മുൻ ഭാഗങ്ങളിലേതുപോലെ, താഴെയുള്ള കോഡ് ഉപയോഗിച്ച് നമ്മൾ ട്രെയിൻ ചെയ്ത് Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യുന്ന യഥാർത്ഥ മോഡൽ [ഇവിടെ](https://huggingface.co/huggingface-course/marian-finetuned-kde4-en-to-fr?text=This+plugin+allows+you+to+automatically+translate+web+pages+between+several+languages.) കണ്ടെത്താനും അതിന്റെ പ്രവചനങ്ങൾ ഒന്നുകൂടി പരിശോധിക്കാനും നിങ്ങൾക്ക് കഴിയും. + +## ഡേറ്റ തയ്യാറാക്കുന്നു[[preparing-the-data]] + +ഒരു വിവർത്തന മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യാനോ പൂജ്യത്തിൽ നിന്ന് ട്രെയിൻ ചെയ്യാനോ, ആ ടാസ്‌ക്കിന് അനുയോജ്യമായ ഒരു ഡേറ്റാസെറ്റ് നമുക്ക് ആവശ്യമാണ്. മുമ്പ് സൂചിപ്പിച്ചതുപോലെ, ഈ ഭാഗത്തിൽ നമ്മൾ [KDE4 ഡേറ്റാസെറ്റ്](https://huggingface.co/datasets/kde4) ഉപയോഗിക്കും, എന്നാൽ നിങ്ങൾ ഏതൊക്കെ ഭാഷകളിൽ നിന്നും ഏതിലേക്കും വിവർത്തനം ചെയ്യാൻ ആഗ്രഹിക്കുന്നുവോ ആ രണ്ട് ഭാഷകളിലെയും വാക്യജോഡികൾ നിങ്ങളുടെ കൈവശമുണ്ടെങ്കിൽ, നിങ്ങളുടെ സ്വന്തം ഡേറ്റ ഉപയോഗിക്കാൻ ഈ കോഡ് വളരെ എളുപ്പത്തിൽ അനുയോജ്യമാക്കാം. നിങ്ങളുടെ ഇഷ്ടാനുസൃത ഡേറ്റ ഒരു `Dataset`-ൽ എങ്ങനെ ലോഡ് ചെയ്യാമെന്ന് ഓർമ്മിക്കേണ്ടതുണ്ടെങ്കിൽ [അധ്യായം 5](/course/chapter5) വീണ്ടും പരിശോധിക്കുക. + +### KDE4 ഡേറ്റാസെറ്റ്[[the-kde4-dataset]] + +പതിവുപോലെ, `load_dataset()` ഫംഗ്‌ഷൻ ഉപയോഗിച്ച് നമ്മുടെ ഡേറ്റാസെറ്റ് ഡൗൺലോഡ് ചെയ്യുന്നു: + +```py +from datasets import load_dataset + +raw_datasets = load_dataset("kde4", lang1="en", lang2="fr") +``` + +മറ്റൊരു ഭാഷാജോഡിയുമായി പ്രവർത്തിക്കണമെങ്കിൽ, അവയുടെ കോഡുകൾ ഉപയോഗിച്ച് നിങ്ങൾക്ക് അവ വ്യക്തമാക്കാം. ഈ ഡേറ്റാസെറ്റിനായി മൊത്തം 92 ഭാഷകൾ ലഭ്യമാണ്; അതിന്റെ [ഡേറ്റാസെറ്റ് കാർഡിലെ](https://huggingface.co/datasets/kde4) ലാംഗ്വേജ് ടാഗുകൾ വികസിപ്പിച്ചാൽ അവയെല്ലാം നിങ്ങൾക്ക് കാണാം. + +KDE4 ഡേറ്റാസെറ്റിനായി ലഭ്യമായ ഭാഷകൾ. + +ഡേറ്റാസെറ്റ് ഒന്ന് നോക്കാം: + +```py +raw_datasets +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['id', 'translation'], + num_rows: 210173 + }) +}) +``` + +നമുക്ക് 210,173 വാക്യജോഡികളുണ്ട്, എന്നാൽ അവ ഒരൊറ്റ സ്‌പ്ലിറ്റിലാണ്; അതിനാൽ നമ്മുടെ സ്വന്തം വാലിഡേഷൻ സെറ്റ് നമ്മൾ ഉണ്ടാക്കേണ്ടിവരും. [അധ്യായം 5](/course/chapter5)-ൽ കണ്ടതുപോലെ, ഒരു `Dataset`-ന് ഇതിന് നമ്മെ സഹായിക്കുന്ന `train_test_split()` എന്ന മെത്തേഡ് ഉണ്ട്. ഫലങ്ങൾ പുനഃസൃഷ്ടിക്കാൻ (reproducibility) കഴിയുന്നതിനായി നമ്മൾ ഒരു സീഡ് നൽകും: + +```py +split_datasets = raw_datasets["train"].train_test_split(train_size=0.9, seed=20) +split_datasets +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['id', 'translation'], + num_rows: 189155 + }) + test: Dataset({ + features: ['id', 'translation'], + num_rows: 21018 + }) +}) +``` + +`"test"` എന്ന കീ ഇങ്ങനെ `"validation"` എന്ന് പുനർനാമകരണം ചെയ്യാം: + +```py +split_datasets["validation"] = split_datasets.pop("test") +``` + +ഇനി ഡേറ്റാസെറ്റിലെ ഒരു എലമെന്റ് നോക്കാം: + +```py +split_datasets["train"][1]["translation"] +``` + +```python out +{'en': 'Default to expanded threads', + 'fr': 'Par défaut, développer les fils de discussion'} +``` + +നമ്മൾ ആവശ്യപ്പെട്ട ഭാഷാജോഡിയിലെ രണ്ട് വാക്യങ്ങളുള്ള ഒരു ഡിക്‌ഷണറി നമുക്ക് ലഭിക്കുന്നു. സാങ്കേതിക കമ്പ്യൂട്ടർ സയൻസ് പദങ്ങൾ നിറഞ്ഞ ഈ ഡേറ്റാസെറ്റിന്റെ ഒരു പ്രത്യേകത, അവയെല്ലാം പൂർണ്ണമായും ഫ്രഞ്ചിലേക്ക് വിവർത്തനം ചെയ്തിരിക്കുന്നു എന്നതാണ്. എന്നാൽ, ഫ്രഞ്ച് എൻജിനീയർമാർ സംസാരിക്കുമ്പോൾ കമ്പ്യൂട്ടർ സയൻസുമായി ബന്ധപ്പെട്ട മിക്ക വാക്കുകളും ഇംഗ്ലീഷിൽ തന്നെ വിടുകയാണ് പതിവ്. ഉദാഹരണത്തിന്, ഇവിടെ "threads" എന്ന വാക്ക് ഒരു ഫ്രഞ്ച് വാക്യത്തിൽ, വിശേഷിച്ചും ഒരു സാങ്കേതിക സംഭാഷണത്തിൽ, അതേപടി വരാൻ നല്ല സാധ്യതയുണ്ട്; എന്നാൽ ഈ ഡേറ്റാസെറ്റിൽ അത് കൂടുതൽ ശരിയായ "fils de discussion" എന്നതിലേക്ക് വിവർത്തനം ചെയ്തിരിക്കുന്നു. ഫ്രഞ്ച്, ഇംഗ്ലീഷ് വാക്യങ്ങളുടെ കൂടുതൽ വലിയ ഒരു കോർപ്പസിൽ പ്രീട്രെയിൻ ചെയ്ത, നമ്മൾ ഉപയോഗിക്കുന്ന പ്രീട്രെയിൻഡ് മോഡൽ, ആ വാക്ക് അതേപടി വിടുക എന്ന എളുപ്പവഴിയാണ് സ്വീകരിക്കുന്നത്: + +```py +from transformers import pipeline + +model_checkpoint = "Helsinki-NLP/opus-mt-en-fr" +translator = pipeline("translation", model=model_checkpoint) +translator("Default to expanded threads") +``` + +```python out +[{'translation_text': 'Par défaut pour les threads élargis'}] +``` + +ഈ സ്വഭാവത്തിന്റെ മറ്റൊരു ഉദാഹരണം "plugin" എന്ന വാക്കിൽ കാണാം; ഇത് ഔദ്യോഗികമായി ഒരു ഫ്രഞ്ച് വാക്കല്ല, എന്നാൽ മിക്ക മാതൃഭാഷക്കാർക്കും അത് മനസ്സിലാകും, അവർ അത് വിവർത്തനം ചെയ്യാൻ മിനക്കെടാറുമില്ല. +KDE4 ഡേറ്റാസെറ്റിൽ ഈ വാക്ക് ഫ്രഞ്ചിൽ കൂടുതൽ ഔദ്യോഗികമായ "module d'extension" എന്നതിലേക്ക് വിവർത്തനം ചെയ്തിരിക്കുന്നു: + +```py +split_datasets["train"][172]["translation"] +``` + +```python out +{'en': 'Unable to import %1 using the OFX importer plugin. This file is not the correct format.', + 'fr': "Impossible d'importer %1 en utilisant le module d'extension d'importation OFX. Ce fichier n'a pas un format correct."} +``` + +എന്നാൽ, നമ്മുടെ പ്രീട്രെയിൻഡ് മോഡൽ ഹ്രസ്വവും പരിചിതവുമായ ഇംഗ്ലീഷ് വാക്കിൽ തന്നെ ഉറച്ചുനിൽക്കുന്നു: + +```py +translator( + "Unable to import %1 using the OFX importer plugin. This file is not the correct format." +) +``` + +```python out +[{'translation_text': "Impossible d'importer %1 en utilisant le plugin d'importateur OFX. Ce fichier n'est pas le bon format."}] +``` + +നമ്മുടെ ഫൈൻ-ട്യൂൻ ചെയ്ത മോഡൽ ഡേറ്റാസെറ്റിന്റെ ഈ പ്രത്യേകതകൾ പഠിച്ചെടുക്കുമോ എന്ന് കാണുന്നത് രസകരമായിരിക്കും (സ്‌പോയിലർ അലർട്ട്: പഠിച്ചെടുക്കും). + + + +> [!TIP] +> ✏️ **നിങ്ങളുടെ ഊഴം!** ഫ്രഞ്ചിൽ പതിവായി ഉപയോഗിക്കുന്ന മറ്റൊരു ഇംഗ്ലീഷ് വാക്കാണ് "email." ഈ വാക്ക് ഉപയോഗിക്കുന്ന ആദ്യത്തെ സാമ്പിൾ ട്രെയിനിംഗ് ഡേറ്റാസെറ്റിൽ കണ്ടെത്തുക. അത് എങ്ങനെയാണ് വിവർത്തനം ചെയ്തിരിക്കുന്നത്? അതേ ഇംഗ്ലീഷ് വാക്യം പ്രീട്രെയിൻഡ് മോഡൽ എങ്ങനെ വിവർത്തനം ചെയ്യുന്നു? + +### ഡേറ്റ പ്രോസസ്സ് ചെയ്യുന്നു[[processing-the-data]] + + + +ഇപ്പോൾ നിങ്ങൾക്ക് ഈ രീതി പരിചിതമായിരിക്കണം: മോഡലിന് മനസ്സിലാക്കാൻ കഴിയുന്നതിനായി ടെക്‌സ്‌റ്റുകളെല്ലാം ടോക്കൺ ID-കളുടെ സെറ്റുകളായി മാറ്റേണ്ടതുണ്ട്. ഈ ടാസ്‌ക്കിനായി, ഇൻപുട്ടുകളും ടാർഗെറ്റുകളും രണ്ടും നമ്മൾ ടോക്കണൈസ് ചെയ്യേണ്ടതുണ്ട്. നമ്മുടെ ആദ്യ ജോലി നമ്മുടെ `tokenizer` ഒബ്‌ജക്റ്റ് ഉണ്ടാക്കുകയാണ്. മുമ്പ് സൂചിപ്പിച്ചതുപോലെ, ഇംഗ്ലീഷിൽ നിന്ന് ഫ്രഞ്ചിലേക്കുള്ള ഒരു Marian പ്രീട്രെയിൻഡ് മോഡലാണ് നമ്മൾ ഉപയോഗിക്കുന്നത്. മറ്റൊരു ഭാഷാജോഡിയുമായി ഈ കോഡ് പരീക്ഷിക്കുകയാണെങ്കിൽ, മോഡൽ ചെക്ക്‌പോയിന്റ് അതിനനുസരിച്ച് മാറ്റാൻ മറക്കരുത്. [Helsinki-NLP](https://huggingface.co/Helsinki-NLP) ഓർഗനൈസേഷൻ ഒന്നിലധികം ഭാഷകളിലായി ആയിരത്തിലേറെ മോഡലുകൾ നൽകുന്നു. + +```python +from transformers import AutoTokenizer + +model_checkpoint = "Helsinki-NLP/opus-mt-en-fr" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint, return_tensors="pt") +``` + +[Hub](https://huggingface.co/models)-ൽ നിന്ന് നിങ്ങൾക്ക് ഇഷ്ടമുള്ള മറ്റേതെങ്കിലും മോഡൽ ഉപയോഗിച്ചോ, അല്ലെങ്കിൽ ഒരു പ്രീട്രെയിൻഡ് മോഡലും ടോക്കണൈസറും നിങ്ങൾ സേവ് ചെയ്തിട്ടുള്ള ഒരു ലോക്കൽ ഫോൾഡർ ഉപയോഗിച്ചോ `model_checkpoint` മാറ്റാനും നിങ്ങൾക്ക് കഴിയും. + +> [!TIP] +> 💡 mBART, mBART-50, അല്ലെങ്കിൽ M2M100 പോലുള്ള ഒരു ബഹുഭാഷാ ടോക്കണൈസർ നിങ്ങൾ ഉപയോഗിക്കുന്നുണ്ടെങ്കിൽ, `tokenizer.src_lang`, `tokenizer.tgt_lang` എന്നിവ ശരിയായ മൂല്യങ്ങളിലേക്ക് സെറ്റ് ചെയ്തുകൊണ്ട് നിങ്ങളുടെ ഇൻപുട്ടുകളുടെയും ടാർഗെറ്റുകളുടെയും ഭാഷാ കോഡുകൾ ടോക്കണൈസറിൽ നിങ്ങൾ സെറ്റ് ചെയ്യേണ്ടതുണ്ട്. + +നമ്മുടെ ഡേറ്റ തയ്യാറാക്കുന്നത് വളരെ ലളിതമാണ്. ഓർമ്മിക്കേണ്ട ഒരേയൊരു കാര്യം ഇതാണ്: ടോക്കണൈസർ ടാർഗെറ്റുകളെ ഔട്ട്‌പുട്ട് ഭാഷയിൽ (ഇവിടെ, ഫ്രഞ്ച്) പ്രോസസ്സ് ചെയ്യുന്നുണ്ടെന്ന് നിങ്ങൾ ഉറപ്പാക്കണം. ടോക്കണൈസറിന്റെ `__call__` മെത്തേഡിന്റെ `text_targets` ആർഗ്യുമെന്റിലേക്ക് ടാർഗെറ്റുകൾ നൽകിക്കൊണ്ട് നിങ്ങൾക്ക് ഇത് ചെയ്യാം. + +ഇത് എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് കാണാൻ, ട്രെയിനിംഗ് സെറ്റിലെ ഓരോ ഭാഷയുടെയും ഒരു സാമ്പിൾ വീതം പ്രോസസ്സ് ചെയ്യാം: + +```python +en_sentence = split_datasets["train"][1]["translation"]["en"] +fr_sentence = split_datasets["train"][1]["translation"]["fr"] + +inputs = tokenizer(en_sentence, text_target=fr_sentence) +inputs +``` + +```python out +{'input_ids': [47591, 12, 9842, 19634, 9, 0], 'attention_mask': [1, 1, 1, 1, 1, 1], 'labels': [577, 5891, 2, 3184, 16, 2542, 5, 1710, 0]} +``` + +നമുക്ക് കാണാവുന്നതുപോലെ, ഇംഗ്ലീഷ് വാക്യവുമായി ബന്ധപ്പെട്ട ഇൻപുട്ട് ID-കൾ ഔട്ട്‌പുട്ടിൽ ഉണ്ട്, അതേസമയം ഫ്രഞ്ച് വാക്യവുമായി ബന്ധപ്പെട്ട ID-കൾ `labels` ഫീൽഡിലാണ് സൂക്ഷിച്ചിരിക്കുന്നത്. ലേബലുകളാണ് ടോക്കണൈസ് ചെയ്യുന്നത് എന്ന് സൂചിപ്പിക്കാൻ നിങ്ങൾ മറന്നാൽ, അവ ഇൻപുട്ട് ടോക്കണൈസർ ഉപയോഗിച്ചാകും ടോക്കണൈസ് ചെയ്യപ്പെടുക; ഒരു Marian മോഡലിന്റെ കാര്യത്തിൽ അത് ഒട്ടും നന്നായി വരില്ല: + +```python +wrong_targets = tokenizer(fr_sentence) +print(tokenizer.convert_ids_to_tokens(wrong_targets["input_ids"])) +print(tokenizer.convert_ids_to_tokens(inputs["labels"])) +``` + +```python out +['▁Par', '▁dé', 'f', 'aut', ',', '▁dé', 've', 'lop', 'per', '▁les', '▁fil', 's', '▁de', '▁discussion', ''] +['▁Par', '▁défaut', ',', '▁développer', '▁les', '▁fils', '▁de', '▁discussion', ''] +``` + +നമുക്ക് കാണാവുന്നതുപോലെ, ഒരു ഫ്രഞ്ച് വാക്യം പ്രീപ്രോസസ്സ് ചെയ്യാൻ ഇംഗ്ലീഷ് ടോക്കണൈസർ ഉപയോഗിക്കുമ്പോൾ വളരെയധികം ടോക്കണുകൾ ഉണ്ടാകുന്നു, കാരണം ടോക്കണൈസറിന് ഫ്രഞ്ച് വാക്കുകളൊന്നും അറിയില്ല ("discussion" പോലെ ഇംഗ്ലീഷ് ഭാഷയിലും വരുന്നവ ഒഴികെ). + +`inputs` നമ്മുടെ പതിവ് കീകളുള്ള (ഇൻപുട്ട് ID-കൾ, അറ്റൻഷൻ മാസ്‌ക് മുതലായവ) ഒരു ഡിക്‌ഷണറിയാണെന്നതിനാൽ, ഡേറ്റാസെറ്റുകളിൽ നമ്മൾ പ്രയോഗിക്കുന്ന പ്രീപ്രോസസ്സിംഗ് ഫംഗ്‌ഷൻ നിർവചിക്കുകയാണ് അവസാന ഘട്ടം: + +```python +max_length = 128 + + +def preprocess_function(examples): + inputs = [ex["en"] for ex in examples["translation"]] + targets = [ex["fr"] for ex in examples["translation"]] + model_inputs = tokenizer( + inputs, text_target=targets, max_length=max_length, truncation=True + ) + return model_inputs +``` + +നമ്മുടെ ഇൻപുട്ടുകൾക്കും ഔട്ട്‌പുട്ടുകൾക്കും ഒരേ പരമാവധി ദൈർഘ്യമാണ് നമ്മൾ സെറ്റ് ചെയ്യുന്നത് എന്ന് ശ്രദ്ധിക്കുക. നമ്മൾ കൈകാര്യം ചെയ്യുന്ന ടെക്‌സ്‌റ്റുകൾ വളരെ ചെറുതായി തോന്നുന്നതിനാൽ, നമ്മൾ 128 ഉപയോഗിക്കുന്നു. + +> [!TIP] +> 💡 നിങ്ങൾ ഒരു T5 മോഡൽ ഉപയോഗിക്കുന്നുണ്ടെങ്കിൽ (കൂടുതൽ കൃത്യമായി പറഞ്ഞാൽ, `t5-xxx` ചെക്ക്‌പോയിന്റുകളിൽ ഒന്ന്), ടെക്‌സ്‌റ്റ് ഇൻപുട്ടുകൾക്ക് `translate: English to French:` പോലെ, ചെയ്യേണ്ട ടാസ്‌ക് സൂചിപ്പിക്കുന്ന ഒരു പ്രിഫിക്‌സ് ഉണ്ടാകണമെന്ന് മോഡൽ പ്രതീക്ഷിക്കും. + +> [!WARNING] +> ⚠️ ടാർഗെറ്റുകളുടെ അറ്റൻഷൻ മാസ്‌കിനെ നമ്മൾ ശ്രദ്ധിക്കുന്നില്ല, കാരണം മോഡൽ അത് പ്രതീക്ഷിക്കുന്നില്ല. പകരം, ഒരു പാഡിംഗ് ടോക്കണിന് അനുയോജ്യമായ ലേബലുകൾ `-100` എന്ന് സെറ്റ് ചെയ്യണം, അങ്ങനെ ലോസ് കണക്കുകൂട്ടലിൽ അവ അവഗണിക്കപ്പെടും. നമ്മൾ ഡൈനാമിക് പാഡിംഗ് പ്രയോഗിക്കുന്നതിനാൽ ഇത് പിന്നീട് നമ്മുടെ ഡേറ്റാ കൊളേറ്റർ (data collator) ചെയ്യും, എന്നാൽ നിങ്ങൾ ഇവിടെ പാഡിംഗ് ഉപയോഗിക്കുന്നുണ്ടെങ്കിൽ, പാഡിംഗ് ടോക്കണിന് അനുയോജ്യമായ എല്ലാ ലേബലുകളും `-100` എന്ന് സെറ്റ് ചെയ്യുന്ന തരത്തിൽ പ്രീപ്രോസസ്സിംഗ് ഫംഗ്‌ഷൻ നിങ്ങൾ മാറ്റണം. + +ഇപ്പോൾ ആ പ്രീപ്രോസസ്സിംഗ് നമ്മുടെ ഡേറ്റാസെറ്റിന്റെ എല്ലാ സ്‌പ്ലിറ്റുകളിലും ഒറ്റയടിക്ക് പ്രയോഗിക്കാം: + +```py +tokenized_datasets = split_datasets.map( + preprocess_function, + batched=True, + remove_columns=split_datasets["train"].column_names, +) +``` + +ഡേറ്റ പ്രീപ്രോസസ്സ് ചെയ്തുകഴിഞ്ഞതിനാൽ, നമ്മുടെ പ്രീട്രെയിൻഡ് മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യാൻ നമ്മൾ തയ്യാറാണ്! + +{#if fw === 'pt'} + +## `Trainer` API ഉപയോഗിച്ച് മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യുന്നു[[fine-tuning-the-model-with-the-trainer-api]] + +`Trainer` ഉപയോഗിക്കുന്ന യഥാർത്ഥ കോഡ് മുമ്പത്തേതുപോലെ തന്നെയായിരിക്കും, ഒരു ചെറിയ മാറ്റം മാത്രം: ഇവിടെ നമ്മൾ ഒരു [`Seq2SeqTrainer`](https://huggingface.co/transformers/main_classes/trainer.html#seq2seqtrainer) ഉപയോഗിക്കുന്നു; `Trainer`-ന്റെ ഒരു സബ്‌ക്ലാസായ ഇത്, ഇൻപുട്ടുകളിൽ നിന്ന് ഔട്ട്‌പുട്ടുകൾ പ്രവചിക്കാൻ `generate()` മെത്തേഡ് ഉപയോഗിച്ചുകൊണ്ട് ഇവാല്യുവേഷൻ ശരിയായി കൈകാര്യം ചെയ്യാൻ നമ്മെ അനുവദിക്കും. മെട്രിക് കണക്കുകൂട്ടലിനെക്കുറിച്ച് സംസാരിക്കുമ്പോൾ അതിലേക്ക് നമ്മൾ കൂടുതൽ വിശദമായി കടക്കും. + +ആദ്യം ആദ്യത്തെ കാര്യം: ഫൈൻ-ട്യൂൻ ചെയ്യാൻ നമുക്ക് ഒരു യഥാർത്ഥ മോഡൽ ആവശ്യമാണ്. പതിവ് `AutoModel` API നമ്മൾ ഉപയോഗിക്കും: + +```py +from transformers import AutoModelForSeq2SeqLM + +model = AutoModelForSeq2SeqLM.from_pretrained(model_checkpoint) +``` + +{:else} + +## Keras ഉപയോഗിച്ച് മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യുന്നു[[fine-tuning-the-model-with-keras]] + +ആദ്യം ആദ്യത്തെ കാര്യം: ഫൈൻ-ട്യൂൻ ചെയ്യാൻ നമുക്ക് ഒരു യഥാർത്ഥ മോഡൽ ആവശ്യമാണ്. പതിവ് `AutoModel` API നമ്മൾ ഉപയോഗിക്കും: + +```py +from transformers import TFAutoModelForSeq2SeqLM + +model = TFAutoModelForSeq2SeqLM.from_pretrained(model_checkpoint, from_pt=True) +``` + + + +💡 `Helsinki-NLP/opus-mt-en-fr` ചെക്ക്‌പോയിന്റിന് PyTorch വെയ്‌റ്റുകൾ മാത്രമേ ഉള്ളൂ, അതിനാൽ +`from_pretrained()` മെത്തേഡിൽ `from_pt=True` ആർഗ്യുമെന്റ് ഉപയോഗിക്കാതെ മോഡൽ ലോഡ് ചെയ്യാൻ +ശ്രമിച്ചാൽ നിങ്ങൾക്ക് ഒരു എറർ ലഭിക്കും. `from_pt=True` എന്ന് നിങ്ങൾ വ്യക്തമാക്കുമ്പോൾ, +ലൈബ്രറി PyTorch വെയ്‌റ്റുകൾ സ്വയമേവ ഡൗൺലോഡ് ചെയ്ത് നിങ്ങൾക്കായി കൺവേർട്ട് +ചെയ്യും. നിങ്ങൾക്ക് കാണാവുന്നതുപോലെ, 🤗 Transformers-ൽ ഫ്രെയിംവർക്കുകൾക്കിടയിൽ +മാറുന്നത് വളരെ ലളിതമാണ്! + + + +{/if} + +ഇത്തവണ ഒരു വിവർത്തന ടാസ്‌ക്കിൽ ട്രെയിൻ ചെയ്തതും ഇപ്പോൾ തന്നെ യഥാർത്ഥത്തിൽ ഉപയോഗിക്കാവുന്നതുമായ ഒരു മോഡലാണ് നമ്മൾ ഉപയോഗിക്കുന്നത് എന്ന് ശ്രദ്ധിക്കുക; അതിനാൽ നഷ്ടപ്പെട്ട വെയ്‌റ്റുകളെക്കുറിച്ചോ പുതുതായി ഇനിഷ്യലൈസ് ചെയ്തവയെക്കുറിച്ചോ ഒരു മുന്നറിയിപ്പും ഇല്ല. + +### ഡേറ്റാ കൊളേഷൻ[[data-collation]] + +ഡൈനാമിക് ബാച്ചിംഗിനുള്ള പാഡിംഗ് കൈകാര്യം ചെയ്യാൻ നമുക്ക് ഒരു ഡേറ്റാ കൊളേറ്റർ ആവശ്യമാണ്. ഈ സാഹചര്യത്തിൽ [അധ്യായം 3](/course/chapter3)-ലേതുപോലെ ഒരു `DataCollatorWithPadding` അതേപടി ഉപയോഗിക്കാൻ കഴിയില്ല, കാരണം അത് ഇൻപുട്ടുകൾ (ഇൻപുട്ട് ID-കൾ, അറ്റൻഷൻ മാസ്‌ക്, ടോക്കൺ ടൈപ്പ് ID-കൾ) മാത്രമേ പാഡ് ചെയ്യുന്നുള്ളൂ. നമ്മുടെ ലേബലുകളും ലേബലുകളിൽ കാണുന്ന പരമാവധി ദൈർഘ്യത്തിലേക്ക് പാഡ് ചെയ്യണം. കൂടാതെ, മുമ്പ് സൂചിപ്പിച്ചതുപോലെ, ലേബലുകൾ പാഡ് ചെയ്യാൻ ഉപയോഗിക്കുന്ന പാഡിംഗ് മൂല്യം ടോക്കണൈസറിന്റെ പാഡിംഗ് ടോക്കണല്ല, `-100` ആയിരിക്കണം; അങ്ങനെ പാഡ് ചെയ്ത ആ മൂല്യങ്ങൾ ലോസ് കണക്കുകൂട്ടലിൽ അവഗണിക്കപ്പെടുമെന്ന് ഉറപ്പാക്കാം. + +ഇതെല്ലാം ഒരു [`DataCollatorForSeq2Seq`](https://huggingface.co/transformers/main_classes/data_collator.html#datacollatorforseq2seq) ചെയ്യുന്നു. `DataCollatorWithPadding` പോലെ, ഇൻപുട്ടുകൾ പ്രീപ്രോസസ്സ് ചെയ്യാൻ ഉപയോഗിച്ച `tokenizer` ഇത് സ്വീകരിക്കുന്നു, എന്നാൽ `model`-ഉം ഇത് സ്വീകരിക്കുന്നു. ഡീകോഡർ ഇൻപുട്ട് ID-കൾ തയ്യാറാക്കാനുള്ള ഉത്തരവാദിത്തവും ഈ ഡേറ്റാ കൊളേറ്ററിനായിരിക്കും എന്നതാണ് ഇതിന് കാരണം; തുടക്കത്തിൽ ഒരു സ്‌പെഷ്യൽ ടോക്കണോടെ ലേബലുകളെ ഷിഫ്‌റ്റ് ചെയ്ത പതിപ്പുകളാണ് ഇവ. ഈ ഷിഫ്‌റ്റ് വ്യത്യസ്ത ആർക്കിടെക്ചറുകൾക്ക് അൽപ്പം വ്യത്യസ്തമായാണ് ചെയ്യുന്നത് എന്നതിനാൽ, `DataCollatorForSeq2Seq`-ന് `model` ഒബ്‌ജക്റ്റ് അറിയേണ്ടതുണ്ട്: + +{#if fw === 'pt'} + +```py +from transformers import DataCollatorForSeq2Seq + +data_collator = DataCollatorForSeq2Seq(tokenizer, model=model) +``` + +{:else} + +```py +from transformers import DataCollatorForSeq2Seq + +data_collator = DataCollatorForSeq2Seq(tokenizer, model=model, return_tensors="tf") +``` + +{/if} + +ഏതാനും സാമ്പിളുകളിൽ ഇത് പരീക്ഷിക്കാൻ, നമ്മുടെ ടോക്കണൈസ് ചെയ്ത ട്രെയിനിംഗ് സെറ്റിലെ ഉദാഹരണങ്ങളുടെ ഒരു ലിസ്‌റ്റിൽ ഇത് വിളിച്ചാൽ മാത്രം മതി: + +```py +batch = data_collator([tokenized_datasets["train"][i] for i in range(1, 3)]) +batch.keys() +``` + +```python out +dict_keys(['attention_mask', 'input_ids', 'labels', 'decoder_input_ids']) +``` + +നമ്മുടെ ലേബലുകൾ `-100` ഉപയോഗിച്ച് ബാച്ചിന്റെ പരമാവധി ദൈർഘ്യത്തിലേക്ക് പാഡ് ചെയ്തിട്ടുണ്ടെന്ന് നമുക്ക് പരിശോധിക്കാം: + +```py +batch["labels"] +``` + +```python out +tensor([[ 577, 5891, 2, 3184, 16, 2542, 5, 1710, 0, -100, + -100, -100, -100, -100, -100, -100], + [ 1211, 3, 49, 9409, 1211, 3, 29140, 817, 3124, 817, + 550, 7032, 5821, 7907, 12649, 0]]) +``` + +കൂടാതെ, ഡീകോഡർ ഇൻപുട്ട് ID-കൾ ലേബലുകളുടെ ഷിഫ്‌റ്റ് ചെയ്ത പതിപ്പുകളാണെന്ന് കാണാൻ, അവയും നമുക്ക് ഒന്ന് നോക്കാം: + +```py +batch["decoder_input_ids"] +``` + +```python out +tensor([[59513, 577, 5891, 2, 3184, 16, 2542, 5, 1710, 0, + 59513, 59513, 59513, 59513, 59513, 59513], + [59513, 1211, 3, 49, 9409, 1211, 3, 29140, 817, 3124, + 817, 550, 7032, 5821, 7907, 12649]]) +``` + +നമ്മുടെ ഡേറ്റാസെറ്റിലെ ഒന്നാമത്തെയും രണ്ടാമത്തെയും എലമെന്റുകളുടെ ലേബലുകൾ ഇതാ: + +```py +for i in range(1, 3): + print(tokenized_datasets["train"][i]["labels"]) +``` + +```python out +[577, 5891, 2, 3184, 16, 2542, 5, 1710, 0] +[1211, 3, 49, 9409, 1211, 3, 29140, 817, 3124, 817, 550, 7032, 5821, 7907, 12649, 0] +``` + +{#if fw === 'pt'} + +ഈ `data_collator` നമ്മൾ `Seq2SeqTrainer`-ന് കൈമാറും. അടുത്തതായി, മെട്രിക് ഒന്ന് നോക്കാം. + +{:else} + +ഇപ്പോൾ ഈ `data_collator` ഉപയോഗിച്ച് നമ്മുടെ ഓരോ ഡേറ്റാസെറ്റും ട്രെയിനിംഗിന് തയ്യാറായ ഒരു `tf.data.Dataset`-ലേക്ക് മാറ്റാം: + +```python +tf_train_dataset = model.prepare_tf_dataset( + tokenized_datasets["train"], + collate_fn=data_collator, + shuffle=True, + batch_size=32, +) +tf_eval_dataset = model.prepare_tf_dataset( + tokenized_datasets["validation"], + collate_fn=data_collator, + shuffle=False, + batch_size=16, +) +``` + +{/if} + + +### മെട്രിക്കുകൾ[[metrics]] + + + +{#if fw === 'pt'} + +`Seq2SeqTrainer` അതിന്റെ സൂപ്പർക്ലാസായ `Trainer`-ലേക്ക് ചേർക്കുന്ന സവിശേഷത, ഇവാല്യുവേഷൻ അല്ലെങ്കിൽ പ്രവചന സമയത്ത് `generate()` മെത്തേഡ് ഉപയോഗിക്കാനുള്ള കഴിവാണ്. ട്രെയിനിംഗ് സമയത്ത്, ട്രെയിനിംഗ് വേഗത്തിലാക്കാൻ, പ്രവചിക്കാൻ ശ്രമിക്കുന്ന ടോക്കണിന് ശേഷമുള്ള ടോക്കണുകൾ ഉപയോഗിക്കുന്നില്ലെന്ന് ഉറപ്പാക്കുന്ന ഒരു അറ്റൻഷൻ മാസ്‌കോടൊപ്പം മോഡൽ `decoder_input_ids` ഉപയോഗിക്കും. ഇൻഫറൻസ് സമയത്ത് നമുക്ക് ലേബലുകൾ ഉണ്ടാകില്ല എന്നതിനാൽ അവ ഉപയോഗിക്കാൻ കഴിയില്ല; അതിനാൽ അതേ സജ്ജീകരണത്തോടെ നമ്മുടെ മോഡൽ ഇവാല്യുവേറ്റ് ചെയ്യുന്നതാണ് നല്ലത്. + +[അധ്യായം 1](/course/chapter1/6)-ൽ കണ്ടതുപോലെ, ഡീകോഡർ ടോക്കണുകൾ ഒന്നൊന്നായി പ്രവചിച്ചുകൊണ്ടാണ് ഇൻഫറൻസ് നടത്തുന്നത് — 🤗 Transformers-ൽ `generate()` മെത്തേഡ് വഴി തിരശ്ശീലയ്ക്ക് പിന്നിൽ നടപ്പിലാക്കിയിരിക്കുന്ന ഒരു കാര്യമാണിത്. `predict_with_generate=True` എന്ന് സെറ്റ് ചെയ്താൽ ഇവാല്യുവേഷനായി ആ മെത്തേഡ് ഉപയോഗിക്കാൻ `Seq2SeqTrainer` നമ്മെ അനുവദിക്കും. + +{/if} + +വിവർത്തനത്തിനായി പരമ്പരാഗതമായി ഉപയോഗിക്കുന്ന മെട്രിക് [BLEU സ്‌കോർ](https://en.wikipedia.org/wiki/BLEU) ആണ്; Kishore Papineni et al. [2002-ലെ ഒരു പ്രബന്ധത്തിൽ](https://aclanthology.org/P02-1040.pdf) അവതരിപ്പിച്ചതാണ് ഇത്. വിവർത്തനങ്ങൾ അവയുടെ ലേബലുകളോട് എത്ര അടുത്തുനിൽക്കുന്നു എന്ന് BLEU സ്‌കോർ വിലയിരുത്തുന്നു. മോഡൽ ജനറേറ്റ് ചെയ്ത ഔട്ട്‌പുട്ടുകളുടെ വ്യക്തതയോ വ്യാകരണശുദ്ധിയോ ഇത് അളക്കുന്നില്ല, പകരം ജനറേറ്റ് ചെയ്ത ഔട്ട്‌പുട്ടുകളിലെ എല്ലാ വാക്കുകളും ടാർഗെറ്റുകളിലും വരുന്നുണ്ടെന്ന് ഉറപ്പാക്കാൻ സ്ഥിതിവിവര നിയമങ്ങൾ (statistical rules) ഉപയോഗിക്കുന്നു. കൂടാതെ, ടാർഗെറ്റുകളിൽ ആവർത്തിക്കാത്ത അതേ വാക്കുകളുടെ ആവർത്തനങ്ങൾക്ക് (`"the the the the the"` പോലുള്ള വാക്യങ്ങൾ മോഡൽ ഔട്ട്‌പുട്ട് ചെയ്യുന്നത് ഒഴിവാക്കാൻ) പിഴ ചുമത്തുന്ന നിയമങ്ങളും, ടാർഗെറ്റുകളിലുള്ളതിനേക്കാൾ ചെറിയ ഔട്ട്‌പുട്ട് വാക്യങ്ങൾക്ക് (`"the"` പോലുള്ള വാക്യങ്ങൾ മോഡൽ ഔട്ട്‌പുട്ട് ചെയ്യുന്നത് ഒഴിവാക്കാൻ) പിഴ ചുമത്തുന്ന നിയമങ്ങളും ഉണ്ട്. + +BLEU-വിന്റെ ഒരു ദൗർബല്യം, ടെക്‌സ്‌റ്റ് ഇതിനകം ടോക്കണൈസ് ചെയ്തിരിക്കണമെന്ന് ഇത് പ്രതീക്ഷിക്കുന്നു എന്നതാണ്; ഇത് വ്യത്യസ്ത ടോക്കണൈസറുകൾ ഉപയോഗിക്കുന്ന മോഡലുകൾക്കിടയിൽ സ്‌കോറുകൾ താരതമ്യം ചെയ്യുന്നത് ബുദ്ധിമുട്ടാക്കുന്നു. അതിനാൽ പകരം, ഇന്ന് വിവർത്തന മോഡലുകൾ ബെഞ്ച്‌മാർക്ക് ചെയ്യാൻ ഏറ്റവും സാധാരണയായി ഉപയോഗിക്കുന്ന മെട്രിക് [SacreBLEU](https://github.com/mjpost/sacrebleu) ആണ്; ടോക്കണൈസേഷൻ ഘട്ടം സ്‌റ്റാൻഡേർഡൈസ് ചെയ്തുകൊണ്ട് ഇത് ഈ ദൗർബല്യം (മറ്റുള്ളവയും) പരിഹരിക്കുന്നു. ഈ മെട്രിക് ഉപയോഗിക്കാൻ, ആദ്യം നമ്മൾ SacreBLEU ലൈബ്രറി ഇൻസ്‌റ്റാൾ ചെയ്യേണ്ടതുണ്ട്: + +```py +!pip install sacrebleu +``` + +തുടർന്ന്, [അധ്യായം 3](/course/chapter3)-ൽ ചെയ്തതുപോലെ `evaluate.load()` വഴി നമുക്ക് ഇത് ലോഡ് ചെയ്യാം: + +```py +import evaluate + +metric = evaluate.load("sacrebleu") +``` + +ഈ മെട്രിക് ടെക്‌സ്‌റ്റുകളെ ഇൻപുട്ടുകളായും ടാർഗെറ്റുകളായും സ്വീകരിക്കും. ഒരേ വാക്യത്തിന് പലപ്പോഴും സ്വീകാര്യമായ ഒന്നിലധികം വിവർത്തനങ്ങൾ ഉണ്ടാകാറുള്ളതിനാൽ, സ്വീകാര്യമായ പല ടാർഗെറ്റുകളും സ്വീകരിക്കാൻ കഴിയുന്ന തരത്തിലാണ് ഇത് രൂപകൽപ്പന ചെയ്തിരിക്കുന്നത് — നമ്മൾ ഉപയോഗിക്കുന്ന ഡേറ്റാസെറ്റ് ഒന്ന് മാത്രമേ നൽകുന്നുള്ളൂ, എന്നാൽ ലേബലുകളായി പല വാക്യങ്ങൾ നൽകുന്ന ഡേറ്റാസെറ്റുകൾ NLP-യിൽ കണ്ടെത്തുന്നത് അസാധാരണമല്ല. അതിനാൽ, പ്രവചനങ്ങൾ വാക്യങ്ങളുടെ ഒരു ലിസ്‌റ്റ് ആയിരിക്കണം, എന്നാൽ റഫറൻസുകൾ വാക്യങ്ങളുടെ ലിസ്‌റ്റുകളുടെ ഒരു ലിസ്‌റ്റ് ആയിരിക്കണം. + +ഒരു ഉദാഹരണം പരീക്ഷിക്കാം: + +```py +predictions = [ + "This plugin lets you translate web pages between several languages automatically." +] +references = [ + [ + "This plugin allows you to automatically translate web pages between several languages." + ] +] +metric.compute(predictions=predictions, references=references) +``` + +```python out +{'score': 46.750469682990165, + 'counts': [11, 6, 4, 3], + 'totals': [12, 11, 10, 9], + 'precisions': [91.67, 54.54, 40.0, 33.33], + 'bp': 0.9200444146293233, + 'sys_len': 12, + 'ref_len': 13} +``` + +ഇതിന് 46.75 എന്ന BLEU സ്‌കോർ ലഭിക്കുന്നു, അത് തികച്ചും നല്ലതാണ് — താരതമ്യത്തിന്, ["Attention Is All You Need" പ്രബന്ധത്തിലെ](https://arxiv.org/pdf/1706.03762.pdf) യഥാർത്ഥ Transformer മോഡൽ ഇംഗ്ലീഷിനും ഫ്രഞ്ചിനും ഇടയിലുള്ള ഇതുപോലൊരു വിവർത്തന ടാസ്‌ക്കിൽ 41.8 എന്ന BLEU സ്‌കോറാണ് നേടിയത്! (`counts`, `bp` പോലുള്ള ഓരോ മെട്രിക്കുകളെക്കുറിച്ചുള്ള കൂടുതൽ വിവരങ്ങൾക്ക്, [SacreBLEU റിപ്പോസിറ്ററി](https://github.com/mjpost/sacrebleu/blob/078c440168c6adc89ba75fe6d63f0d922d42bcfe/sacrebleu/metrics/bleu.py#L74) കാണുക.) മറുവശത്ത്, വിവർത്തന മോഡലുകളിൽ നിന്ന് പലപ്പോഴും വരുന്ന രണ്ട് തരം മോശം പ്രവചനങ്ങൾ (ധാരാളം ആവർത്തനങ്ങൾ അല്ലെങ്കിൽ വളരെ ചെറുത്) ഉപയോഗിച്ച് പരീക്ഷിച്ചാൽ, തികച്ചും മോശം BLEU സ്‌കോറുകളാണ് നമുക്ക് ലഭിക്കുക: + +```py +predictions = ["This This This This"] +references = [ + [ + "This plugin allows you to automatically translate web pages between several languages." + ] +] +metric.compute(predictions=predictions, references=references) +``` + +```python out +{'score': 1.683602693167689, + 'counts': [1, 0, 0, 0], + 'totals': [4, 3, 2, 1], + 'precisions': [25.0, 16.67, 12.5, 12.5], + 'bp': 0.10539922456186433, + 'sys_len': 4, + 'ref_len': 13} +``` + +```py +predictions = ["This plugin"] +references = [ + [ + "This plugin allows you to automatically translate web pages between several languages." + ] +] +metric.compute(predictions=predictions, references=references) +``` + +```python out +{'score': 0.0, + 'counts': [2, 1, 0, 0], + 'totals': [2, 1, 0, 0], + 'precisions': [100.0, 100.0, 0.0, 0.0], + 'bp': 0.004086771438464067, + 'sys_len': 2, + 'ref_len': 13} +``` + +സ്‌കോർ 0 മുതൽ 100 വരെ ആകാം, കൂടുതൽ ഉയർന്നതാണ് കൂടുതൽ മെച്ചം. + +{#if fw === 'tf'} + +മോഡൽ ഔട്ട്‌പുട്ടുകളിൽ നിന്ന് മെട്രിക്കിന് ഉപയോഗിക്കാൻ കഴിയുന്ന ടെക്‌സ്‌റ്റുകളിലേക്ക് എത്താൻ, നമ്മൾ `tokenizer.batch_decode()` മെത്തേഡ് ഉപയോഗിക്കും. ലേബലുകളിലെ എല്ലാ `-100`-കളും വൃത്തിയാക്കിയാൽ മാത്രം മതി; പാഡിംഗ് ടോക്കണിനായി ടോക്കണൈസർ അതേ കാര്യം സ്വയമേവ ചെയ്യും. നമ്മുടെ മോഡലും ഒരു ഡേറ്റാസെറ്റും സ്വീകരിച്ച് അതിൽ മെട്രിക്കുകൾ കണക്കുകൂട്ടുന്ന ഒരു ഫംഗ്‌ഷൻ നിർവചിക്കാം. പ്രകടനം ഗണ്യമായി വർദ്ധിപ്പിക്കുന്ന ഒരു തന്ത്രവും നമ്മൾ ഉപയോഗിക്കാൻ പോകുന്നു - TensorFlow-യുടെ ആക്‌സിലറേറ്റഡ് ലീനിയർ ആൾജിബ്ര കംപൈലറായ [XLA](https://www.tensorflow.org/xla) ഉപയോഗിച്ച് നമ്മുടെ ജനറേഷൻ കോഡ് കംപൈൽ ചെയ്യുക. മോഡലിന്റെ കമ്പ്യൂട്ടേഷൻ ഗ്രാഫിൽ XLA വിവിധ ഒപ്‌റ്റിമൈസേഷനുകൾ പ്രയോഗിക്കുന്നു, അതിന്റെ ഫലമായി വേഗതയിലും മെമ്മറി ഉപയോഗത്തിലും ഗണ്യമായ മെച്ചപ്പെടുത്തലുകൾ ഉണ്ടാകുന്നു. Hugging Face [ബ്ലോഗിൽ](https://huggingface.co/blog/tf-xla-generate) വിവരിച്ചിരിക്കുന്നതുപോലെ, നമ്മുടെ ഇൻപുട്ട് ഷേപ്പുകൾ വളരെയധികം മാറാതിരിക്കുമ്പോഴാണ് XLA ഏറ്റവും നന്നായി പ്രവർത്തിക്കുന്നത്. ഇത് കൈകാര്യം ചെയ്യാൻ, നമ്മുടെ ഇൻപുട്ടുകൾ 128-ന്റെ ഗുണിതങ്ങളിലേക്ക് പാഡ് ചെയ്യുകയും പാഡിംഗ് കൊളേറ്റർ ഉപയോഗിച്ച് ഒരു പുതിയ ഡേറ്റാസെറ്റ് ഉണ്ടാക്കുകയും ചെയ്യും, തുടർന്ന് നമ്മുടെ ജനറേഷൻ ഫംഗ്‌ഷനിൽ `@tf.function(jit_compile=True)` ഡെക്കറേറ്റർ പ്രയോഗിക്കും; ഇത് മുഴുവൻ ഫംഗ്‌ഷനെയും XLA ഉപയോഗിച്ചുള്ള കംപൈലേഷനായി അടയാളപ്പെടുത്തുന്നു. + +```py +import numpy as np +import tensorflow as tf +from tqdm import tqdm + +generation_data_collator = DataCollatorForSeq2Seq( + tokenizer, model=model, return_tensors="tf", pad_to_multiple_of=128 +) + +tf_generate_dataset = model.prepare_tf_dataset( + tokenized_datasets["validation"], + collate_fn=generation_data_collator, + shuffle=False, + batch_size=8, +) + + +@tf.function(jit_compile=True) +def generate_with_xla(batch): + return model.generate( + input_ids=batch["input_ids"], + attention_mask=batch["attention_mask"], + max_new_tokens=128, + ) + + +def compute_metrics(): + all_preds = [] + all_labels = [] + + for batch, labels in tqdm(tf_generate_dataset): + predictions = generate_with_xla(batch) + decoded_preds = tokenizer.batch_decode(predictions, skip_special_tokens=True) + labels = labels.numpy() + labels = np.where(labels != -100, labels, tokenizer.pad_token_id) + decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True) + decoded_preds = [pred.strip() for pred in decoded_preds] + decoded_labels = [[label.strip()] for label in decoded_labels] + all_preds.extend(decoded_preds) + all_labels.extend(decoded_labels) + + result = metric.compute(predictions=all_preds, references=all_labels) + return {"bleu": result["score"]} +``` + +{:else} + +മോഡൽ ഔട്ട്‌പുട്ടുകളിൽ നിന്ന് മെട്രിക്കിന് ഉപയോഗിക്കാൻ കഴിയുന്ന ടെക്‌സ്‌റ്റുകളിലേക്ക് എത്താൻ, നമ്മൾ `tokenizer.batch_decode()` മെത്തേഡ് ഉപയോഗിക്കും. ലേബലുകളിലെ എല്ലാ `-100`-കളും വൃത്തിയാക്കിയാൽ മാത്രം മതി (പാഡിംഗ് ടോക്കണിനായി ടോക്കണൈസർ അതേ കാര്യം സ്വയമേവ ചെയ്യും): + +```py +import numpy as np + + +def compute_metrics(eval_preds): + preds, labels = eval_preds + # In case the model returns more than the prediction logits + if isinstance(preds, tuple): + preds = preds[0] + + decoded_preds = tokenizer.batch_decode(preds, skip_special_tokens=True) + + # Replace -100s in the labels as we can't decode them + labels = np.where(labels != -100, labels, tokenizer.pad_token_id) + decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True) + + # Some simple post-processing + decoded_preds = [pred.strip() for pred in decoded_preds] + decoded_labels = [[label.strip()] for label in decoded_labels] + + result = metric.compute(predictions=decoded_preds, references=decoded_labels) + return {"bleu": result["score"]} +``` + +{/if} + +ഇത് പൂർത്തിയായതിനാൽ, നമ്മുടെ മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യാൻ നമ്മൾ തയ്യാറാണ്! + + +### മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യുന്നു[[fine-tuning-the-model]] + +ആദ്യ ഘട്ടം Hugging Face-ൽ ലോഗിൻ ചെയ്യുകയാണ്; അങ്ങനെ നിങ്ങളുടെ ഫലങ്ങൾ Model Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യാൻ നിങ്ങൾക്ക് കഴിയും. ഒരു നോട്ട്‌ബുക്കിൽ ഇതിന് നിങ്ങളെ സഹായിക്കാൻ സൗകര്യപ്രദമായ ഒരു ഫംഗ്‌ഷൻ ഉണ്ട്: + +```python +from huggingface_hub import notebook_login + +notebook_login() +``` + +നിങ്ങളുടെ Hugging Face ലോഗിൻ ക്രെഡൻഷ്യലുകൾ നൽകാൻ കഴിയുന്ന ഒരു വിജറ്റ് ഇത് പ്രദർശിപ്പിക്കും. + +നിങ്ങൾ ഒരു നോട്ട്‌ബുക്കിലല്ല പ്രവർത്തിക്കുന്നതെങ്കിൽ, നിങ്ങളുടെ ടെർമിനലിൽ താഴെയുള്ള വരി ടൈപ്പ് ചെയ്താൽ മതി: + +```bash +huggingface-cli login +``` + +{#if fw === 'tf'} + +തുടങ്ങുന്നതിന് മുമ്പ്, യാതൊരു ട്രെയിനിംഗും കൂടാതെ നമ്മുടെ മോഡലിൽ നിന്ന് എന്ത് തരം ഫലങ്ങളാണ് ലഭിക്കുന്നത് എന്ന് നോക്കാം: + +```py +print(compute_metrics()) +``` + +``` +{'bleu': 33.26983701454733} +``` + +ഇത് പൂർത്തിയായാൽ, നമ്മുടെ മോഡൽ കംപൈൽ ചെയ്യാനും ട്രെയിൻ ചെയ്യാനും ആവശ്യമായതെല്ലാം നമുക്ക് തയ്യാറാക്കാം. `tf.keras.mixed_precision.set_global_policy("mixed_float16")`-ന്റെ ഉപയോഗം ശ്രദ്ധിക്കുക — float16 ഉപയോഗിച്ച് ട്രെയിൻ ചെയ്യാൻ ഇത് Keras-നോട് പറയും; ഇതിനെ പിന്തുണയ്ക്കുന്ന GPU-കളിൽ (Nvidia 20xx/V100 അല്ലെങ്കിൽ അതിലും പുതിയവ) ഇത് ഗണ്യമായ വേഗവർദ്ധന നൽകും. + +```python +from transformers import create_optimizer +from transformers.keras_callbacks import PushToHubCallback +import tensorflow as tf + +# The number of training steps is the number of samples in the dataset, divided by the batch size then multiplied +# by the total number of epochs. Note that the tf_train_dataset here is a batched tf.data.Dataset, +# not the original Hugging Face Dataset, so its len() is already num_samples // batch_size. +num_epochs = 3 +num_train_steps = len(tf_train_dataset) * num_epochs + +optimizer, schedule = create_optimizer( + init_lr=5e-5, + num_warmup_steps=0, + num_train_steps=num_train_steps, + weight_decay_rate=0.01, +) +model.compile(optimizer=optimizer) + +# Train in mixed-precision float16 +tf.keras.mixed_precision.set_global_policy("mixed_float16") +``` + +അടുത്തതായി, [ഭാഗം 2]((/course/chapter7/2))-ൽ കണ്ടതുപോലെ, ട്രെയിനിംഗ് സമയത്ത് നമ്മുടെ മോഡൽ Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യാൻ ഒരു `PushToHubCallback` നമ്മൾ നിർവചിക്കുന്നു, തുടർന്ന് ആ കോൾബാക്ക് ഉപയോഗിച്ച് മോഡൽ ഫിറ്റ് ചെയ്യുകയേ വേണ്ടൂ: + +```python +from transformers.keras_callbacks import PushToHubCallback + +callback = PushToHubCallback( + output_dir="marian-finetuned-kde4-en-to-fr", tokenizer=tokenizer +) + +model.fit( + tf_train_dataset, + validation_data=tf_eval_dataset, + callbacks=[callback], + epochs=num_epochs, +) +``` + +നിങ്ങൾ പുഷ് ചെയ്യാൻ ആഗ്രഹിക്കുന്ന റിപ്പോസിറ്ററിയുടെ പേര് `hub_model_id` ആർഗ്യുമെന്റ് ഉപയോഗിച്ച് നിങ്ങൾക്ക് വ്യക്തമാക്കാം എന്ന് ശ്രദ്ധിക്കുക (വിശേഷിച്ചും, ഒരു ഓർഗനൈസേഷനിലേക്ക് പുഷ് ചെയ്യാൻ നിങ്ങൾ ഈ ആർഗ്യുമെന്റ് ഉപയോഗിക്കേണ്ടിവരും). ഉദാഹരണത്തിന്, [`huggingface-course` ഓർഗനൈസേഷനിലേക്ക്](https://huggingface.co/huggingface-course) നമ്മൾ മോഡൽ പുഷ് ചെയ്തപ്പോൾ, `Seq2SeqTrainingArguments`-ലേക്ക് `hub_model_id="huggingface-course/marian-finetuned-kde4-en-to-fr"` നമ്മൾ ചേർത്തു. ഡിഫോൾട്ടായി, ഉപയോഗിക്കുന്ന റിപ്പോസിറ്ററി നിങ്ങളുടെ നെയിംസ്‌പേസിൽ ആയിരിക്കും, നിങ്ങൾ സെറ്റ് ചെയ്ത ഔട്ട്‌പുട്ട് ഡയറക്‌ടറിയുടെ പേരിലായിരിക്കും അത്; അതിനാൽ ഇവിടെ അത് `"sgugger/marian-finetuned-kde4-en-to-fr"` ആയിരിക്കും (ഈ ഭാഗത്തിന്റെ തുടക്കത്തിൽ നമ്മൾ ലിങ്ക് ചെയ്ത മോഡലാണിത്). + +> [!TIP] +> 💡 നിങ്ങൾ ഉപയോഗിക്കുന്ന ഔട്ട്‌പുട്ട് ഡയറക്‌ടറി ഇതിനകം നിലവിലുണ്ടെങ്കിൽ, അത് നിങ്ങൾ പുഷ് ചെയ്യാൻ ആഗ്രഹിക്കുന്ന റിപ്പോസിറ്ററിയുടെ ഒരു ലോക്കൽ ക്ലോൺ ആയിരിക്കണം. അല്ലെങ്കിൽ, `model.fit()` വിളിക്കുമ്പോൾ നിങ്ങൾക്ക് ഒരു എറർ ലഭിക്കും, ഒരു പുതിയ പേര് സെറ്റ് ചെയ്യേണ്ടിവരും. + +അവസാനമായി, ട്രെയിനിംഗ് പൂർത്തിയായ സ്ഥിതിക്ക് നമ്മുടെ മെട്രിക്കുകൾ ഇപ്പോൾ എങ്ങനെയുണ്ടെന്ന് നോക്കാം: + +```py +print(compute_metrics()) +``` + +``` +{'bleu': 57.334066271545865} +``` + +ഈ ഘട്ടത്തിൽ, നിങ്ങളുടെ മോഡൽ പരീക്ഷിക്കാനും സുഹൃത്തുക്കളുമായി പങ്കുവയ്ക്കാനും Model Hub-ലെ ഇൻഫറൻസ് വിജറ്റ് നിങ്ങൾക്ക് ഉപയോഗിക്കാം. ഒരു വിവർത്തന ടാസ്‌ക്കിൽ ഒരു മോഡൽ നിങ്ങൾ വിജയകരമായി ഫൈൻ-ട്യൂൻ ചെയ്തിരിക്കുന്നു — അഭിനന്ദനങ്ങൾ! + +{:else} + +ഇത് പൂർത്തിയായാൽ, നമ്മുടെ `Seq2SeqTrainingArguments` നമുക്ക് നിർവചിക്കാം. `Trainer`-ന്റെ കാര്യത്തിലേതുപോലെ, ഏതാനും ഫീൽഡുകൾ കൂടുതലായി അടങ്ങിയ `TrainingArguments`-ന്റെ ഒരു സബ്‌ക്ലാസാണ് നമ്മൾ ഉപയോഗിക്കുന്നത്: + +```python +from transformers import Seq2SeqTrainingArguments + +args = Seq2SeqTrainingArguments( + f"marian-finetuned-kde4-en-to-fr", + evaluation_strategy="no", + save_strategy="epoch", + learning_rate=2e-5, + per_device_train_batch_size=32, + per_device_eval_batch_size=64, + weight_decay=0.01, + save_total_limit=3, + num_train_epochs=3, + predict_with_generate=True, + fp16=True, + push_to_hub=True, +) +``` + +പതിവ് ഹൈപ്പർപാരാമീറ്ററുകൾ (ലേണിംഗ് റേറ്റ്, എപ്പോക്കുകളുടെ എണ്ണം, ബാച്ച് സൈസ്, കുറച്ച് വെയ്‌റ്റ് ഡികേ പോലുള്ളവ) ഒഴികെ, മുൻ ഭാഗങ്ങളിൽ കണ്ടതുമായി താരതമ്യം ചെയ്യുമ്പോൾ ഇവിടെയുള്ള ഏതാനും മാറ്റങ്ങൾ ഇതാ: + +- ഇവാല്യുവേഷന് കുറച്ച് സമയമെടുക്കും എന്നതിനാൽ, പതിവായുള്ള ഇവാല്യുവേഷനൊന്നും നമ്മൾ സെറ്റ് ചെയ്യുന്നില്ല; ട്രെയിനിംഗിന് മുമ്പും ശേഷവും ഒരു തവണ മാത്രം നമ്മുടെ മോഡൽ ഇവാല്യുവേറ്റ് ചെയ്യും. +- `fp16=True` എന്ന് നമ്മൾ സെറ്റ് ചെയ്യുന്നു, ഇത് ആധുനിക GPU-കളിൽ ട്രെയിനിംഗ് വേഗത്തിലാക്കുന്നു. +- മുകളിൽ ചർച്ച ചെയ്തതുപോലെ, `predict_with_generate=True` എന്ന് നമ്മൾ സെറ്റ് ചെയ്യുന്നു. +- ഓരോ എപ്പോക്കിന്റെയും അവസാനം മോഡൽ Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യാൻ `push_to_hub=True` നമ്മൾ ഉപയോഗിക്കുന്നു. + +നിങ്ങൾ പുഷ് ചെയ്യാൻ ആഗ്രഹിക്കുന്ന റിപ്പോസിറ്ററിയുടെ പൂർണ്ണമായ പേര് `hub_model_id` ആർഗ്യുമെന്റ് ഉപയോഗിച്ച് നിങ്ങൾക്ക് വ്യക്തമാക്കാം എന്ന് ശ്രദ്ധിക്കുക (വിശേഷിച്ചും, ഒരു ഓർഗനൈസേഷനിലേക്ക് പുഷ് ചെയ്യാൻ നിങ്ങൾ ഈ ആർഗ്യുമെന്റ് ഉപയോഗിക്കേണ്ടിവരും). ഉദാഹരണത്തിന്, [`huggingface-course` ഓർഗനൈസേഷനിലേക്ക്](https://huggingface.co/huggingface-course) നമ്മൾ മോഡൽ പുഷ് ചെയ്തപ്പോൾ, `Seq2SeqTrainingArguments`-ലേക്ക് `hub_model_id="huggingface-course/marian-finetuned-kde4-en-to-fr"` നമ്മൾ ചേർത്തു. ഡിഫോൾട്ടായി, ഉപയോഗിക്കുന്ന റിപ്പോസിറ്ററി നിങ്ങളുടെ നെയിംസ്‌പേസിൽ ആയിരിക്കും, നിങ്ങൾ സെറ്റ് ചെയ്ത ഔട്ട്‌പുട്ട് ഡയറക്‌ടറിയുടെ പേരിലായിരിക്കും അത്; അതിനാൽ നമ്മുടെ കാര്യത്തിൽ അത് `"sgugger/marian-finetuned-kde4-en-to-fr"` ആയിരിക്കും (ഈ ഭാഗത്തിന്റെ തുടക്കത്തിൽ നമ്മൾ ലിങ്ക് ചെയ്ത മോഡലാണിത്). + +> [!TIP] +> 💡 നിങ്ങൾ ഉപയോഗിക്കുന്ന ഔട്ട്‌പുട്ട് ഡയറക്‌ടറി ഇതിനകം നിലവിലുണ്ടെങ്കിൽ, അത് നിങ്ങൾ പുഷ് ചെയ്യാൻ ആഗ്രഹിക്കുന്ന റിപ്പോസിറ്ററിയുടെ ഒരു ലോക്കൽ ക്ലോൺ ആയിരിക്കണം. അല്ലെങ്കിൽ, നിങ്ങളുടെ `Seq2SeqTrainer` നിർവചിക്കുമ്പോൾ നിങ്ങൾക്ക് ഒരു എറർ ലഭിക്കും, ഒരു പുതിയ പേര് സെറ്റ് ചെയ്യേണ്ടിവരും. + + +അവസാനമായി, എല്ലാം `Seq2SeqTrainer`-ന് കൈമാറുകയേ വേണ്ടൂ: + +```python +from transformers import Seq2SeqTrainer + +trainer = Seq2SeqTrainer( + model, + args, + train_dataset=tokenized_datasets["train"], + eval_dataset=tokenized_datasets["validation"], + data_collator=data_collator, + tokenizer=tokenizer, + compute_metrics=compute_metrics, +) +``` + +ട്രെയിനിംഗിന് മുമ്പ്, നമ്മുടെ ഫൈൻ-ട്യൂണിംഗ് കൊണ്ട് കാര്യങ്ങൾ കൂടുതൽ മോശമാക്കുന്നില്ല എന്ന് ഒന്നുകൂടി ഉറപ്പാക്കാൻ, നമ്മുടെ മോഡലിന് ലഭിക്കുന്ന സ്‌കോർ ആദ്യം നോക്കാം. ഈ കമാൻഡിന് കുറച്ച് സമയമെടുക്കും, അതിനാൽ ഇത് പ്രവർത്തിക്കുമ്പോൾ നിങ്ങൾക്ക് ഒരു കാപ്പി കുടിക്കാം: + +```python +trainer.evaluate(max_length=max_length) +``` + +```python out +{'eval_loss': 1.6964408159255981, + 'eval_bleu': 39.26865061007616, + 'eval_runtime': 965.8884, + 'eval_samples_per_second': 21.76, + 'eval_steps_per_second': 0.341} +``` + +39 എന്ന BLEU സ്‌കോർ അത്ര മോശമല്ല; ഇംഗ്ലീഷ് വാക്യങ്ങളെ ഫ്രഞ്ചിലേക്ക് വിവർത്തനം ചെയ്യുന്നതിൽ നമ്മുടെ മോഡൽ ഇതിനകം തന്നെ മികച്ചതാണ് എന്ന വസ്തുതയാണ് ഇത് പ്രതിഫലിപ്പിക്കുന്നത്. + +അടുത്തത് ട്രെയിനിംഗാണ്, അതിനും കുറച്ച് സമയമെടുക്കും: + +```python +trainer.train() +``` + +ട്രെയിനിംഗ് നടക്കുമ്പോൾ, ഓരോ തവണ മോഡൽ സേവ് ചെയ്യുമ്പോഴും (ഇവിടെ, ഓരോ എപ്പോക്കിലും) അത് പശ്ചാത്തലത്തിൽ Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യപ്പെടുന്നു എന്ന് ശ്രദ്ധിക്കുക. ഇങ്ങനെ, ആവശ്യമെങ്കിൽ മറ്റൊരു മെഷീനിൽ നിങ്ങളുടെ ട്രെയിനിംഗ് പുനരാരംഭിക്കാൻ നിങ്ങൾക്ക് കഴിയും. + +ട്രെയിനിംഗ് പൂർത്തിയായാൽ, നമ്മുടെ മോഡൽ വീണ്ടും ഇവാല്യുവേറ്റ് ചെയ്യുന്നു — BLEU സ്‌കോറിൽ കുറച്ച് മെച്ചപ്പെടുത്തൽ കാണാൻ കഴിയുമെന്ന് പ്രതീക്ഷിക്കാം! + +```py +trainer.evaluate(max_length=max_length) +``` + +```python out +{'eval_loss': 0.8558505773544312, + 'eval_bleu': 52.94161337775576, + 'eval_runtime': 714.2576, + 'eval_samples_per_second': 29.426, + 'eval_steps_per_second': 0.461, + 'epoch': 3.0} +``` + +അത് ഏകദേശം 14 പോയിന്റിന്റെ മെച്ചപ്പെടുത്തലാണ്, അത് വളരെ നല്ലതാണ്. + +അവസാനമായി, മോഡലിന്റെ ഏറ്റവും പുതിയ പതിപ്പ് അപ്‌ലോഡ് ചെയ്യുന്നുണ്ടെന്ന് ഉറപ്പാക്കാൻ `push_to_hub()` മെത്തേഡ് നമ്മൾ ഉപയോഗിക്കുന്നു. `Trainer` എല്ലാ ഇവാല്യുവേഷൻ ഫലങ്ങളോടും കൂടിയ ഒരു മോഡൽ കാർഡിന്റെ കരട് തയ്യാറാക്കി അതും അപ്‌ലോഡ് ചെയ്യുന്നു. ഇൻഫറൻസ് ഡെമോയ്ക്കുള്ള വിജറ്റ് തിരഞ്ഞെടുക്കാൻ Model Hub-നെ സഹായിക്കുന്ന മെറ്റാഡേറ്റ ഈ മോഡൽ കാർഡിൽ അടങ്ങിയിരിക്കുന്നു. സാധാരണയായി, മോഡൽ ക്ലാസിൽ നിന്ന് ശരിയായ വിജറ്റ് അതിന് ഊഹിച്ചെടുക്കാൻ കഴിയുന്നതിനാൽ ഒന്നും പറയേണ്ട ആവശ്യമില്ല, എന്നാൽ ഈ സാഹചര്യത്തിൽ, ഒരേ മോഡൽ ക്ലാസ് എല്ലാത്തരം സീക്വൻസ്-ടു-സീക്വൻസ് പ്രശ്‌നങ്ങൾക്കും ഉപയോഗിക്കാൻ കഴിയും, അതിനാൽ ഇത് ഒരു വിവർത്തന മോഡലാണ് എന്ന് നമ്മൾ വ്യക്തമാക്കുന്നു: + +```py +trainer.push_to_hub(tags="translation", commit_message="Training complete") +``` + +നിങ്ങൾക്ക് പരിശോധിക്കണമെങ്കിൽ, ഇപ്പോൾ ചെയ്ത കമ്മിറ്റിന്റെ URL ഈ കമാൻഡ് തിരികെ നൽകുന്നു: + +```python out +'https://huggingface.co/sgugger/marian-finetuned-kde4-en-to-fr/commit/3601d621e3baae2bc63d3311452535f8f58f6ef3' +``` + +ഈ ഘട്ടത്തിൽ, നിങ്ങളുടെ മോഡൽ പരീക്ഷിക്കാനും സുഹൃത്തുക്കളുമായി പങ്കുവയ്ക്കാനും Model Hub-ലെ ഇൻഫറൻസ് വിജറ്റ് നിങ്ങൾക്ക് ഉപയോഗിക്കാം. ഒരു വിവർത്തന ടാസ്‌ക്കിൽ ഒരു മോഡൽ നിങ്ങൾ വിജയകരമായി ഫൈൻ-ട്യൂൻ ചെയ്തിരിക്കുന്നു — അഭിനന്ദനങ്ങൾ! + +ട്രെയിനിംഗ് ലൂപ്പിലേക്ക് കുറച്ചുകൂടി ആഴത്തിൽ ഇറങ്ങാൻ നിങ്ങൾ ആഗ്രഹിക്കുന്നുവെങ്കിൽ, 🤗 Accelerate ഉപയോഗിച്ച് അതേ കാര്യം എങ്ങനെ ചെയ്യാമെന്ന് ഇപ്പോൾ നമ്മൾ കാണിച്ചുതരാം. + +{/if} + +{#if fw === 'pt'} + +## ഒരു ഇഷ്ടാനുസൃത ട്രെയിനിംഗ് ലൂപ്പ്[[a-custom-training-loop]] + +ഇനി പൂർണ്ണമായ ട്രെയിനിംഗ് ലൂപ്പ് ഒന്ന് നോക്കാം, അങ്ങനെ നിങ്ങൾക്ക് ആവശ്യമുള്ള ഭാഗങ്ങൾ എളുപ്പത്തിൽ ഇഷ്ടാനുസൃതമാക്കാം. [ഭാഗം 2](/course/chapter7/2)-ലും [അധ്യായം 3](/course/chapter3/4)-ലും നമ്മൾ ചെയ്തതിനോട് ഇത് ഏറെ സാമ്യമുള്ളതായിരിക്കും. + +### ട്രെയിനിംഗിനായി എല്ലാം തയ്യാറാക്കുന്നു[[preparing-everything-for-training]] + +ഇതെല്ലാം നിങ്ങൾ ഇപ്പോൾ ഏതാനും തവണ കണ്ടിട്ടുള്ളതിനാൽ, കോഡിലൂടെ നമ്മൾ വളരെ വേഗത്തിൽ കടന്നുപോകും. ആദ്യം, PyTorch ടെൻസറുകൾ ലഭിക്കുന്നതിനായി ഡേറ്റാസെറ്റുകൾ `"torch"` ഫോർമാറ്റിലേക്ക് സെറ്റ് ചെയ്തതിന് ശേഷം, നമ്മുടെ ഡേറ്റാസെറ്റുകളിൽ നിന്ന് `DataLoader`-കൾ നമ്മൾ നിർമ്മിക്കും: + +```py +from torch.utils.data import DataLoader + +tokenized_datasets.set_format("torch") +train_dataloader = DataLoader( + tokenized_datasets["train"], + shuffle=True, + collate_fn=data_collator, + batch_size=8, +) +eval_dataloader = DataLoader( + tokenized_datasets["validation"], collate_fn=data_collator, batch_size=8 +) +``` + +അടുത്തതായി, മുമ്പത്തെ ഫൈൻ-ട്യൂണിംഗ് തുടരുകയല്ല, മറിച്ച് പ്രീട്രെയിൻഡ് മോഡലിൽ നിന്ന് വീണ്ടും തുടങ്ങുകയാണ് എന്ന് ഉറപ്പാക്കാൻ, നമ്മുടെ മോഡൽ നമ്മൾ വീണ്ടും ഇൻസ്‌റ്റാൻഷിയേറ്റ് ചെയ്യുന്നു: + +```py +model = AutoModelForSeq2SeqLM.from_pretrained(model_checkpoint) +``` + +തുടർന്ന് നമുക്ക് ഒരു ഒപ്‌റ്റിമൈസർ ആവശ്യമായി വരും: + +```py +from torch.optim import AdamW + +optimizer = AdamW(model.parameters(), lr=2e-5) +``` + +ആ ഒബ്‌ജക്റ്റുകളെല്ലാം കൈവശമായാൽ, അവ `accelerator.prepare()` മെത്തേഡിലേക്ക് നമുക്ക് അയയ്ക്കാം. ഒരു Colab നോട്ട്‌ബുക്കിൽ TPU-കളിൽ ട്രെയിൻ ചെയ്യാൻ നിങ്ങൾ ആഗ്രഹിക്കുന്നുവെങ്കിൽ, ഈ കോഡ് മുഴുവൻ ഒരു ട്രെയിനിംഗ് ഫംഗ്‌ഷനിലേക്ക് മാറ്റേണ്ടിവരും, കൂടാതെ ഒരു `Accelerator` ഇൻസ്‌റ്റാൻഷിയേറ്റ് ചെയ്യുന്ന ഒരു സെല്ലും അത് എക്‌സിക്യൂട്ട് ചെയ്യരുത് എന്ന് ഓർമ്മിക്കുക. + +```py +from accelerate import Accelerator + +accelerator = Accelerator() +model, optimizer, train_dataloader, eval_dataloader = accelerator.prepare( + model, optimizer, train_dataloader, eval_dataloader +) +``` + +നമ്മുടെ `train_dataloader` `accelerator.prepare()`-ലേക്ക് അയച്ചുകഴിഞ്ഞതിനാൽ, ട്രെയിനിംഗ് സ്‌റ്റെപ്പുകളുടെ എണ്ണം കണക്കുകൂട്ടാൻ അതിന്റെ ദൈർഘ്യം നമുക്ക് ഉപയോഗിക്കാം. ആ മെത്തേഡ് `DataLoader`-ന്റെ ദൈർഘ്യം മാറ്റും എന്നതിനാൽ, ഡേറ്റാലോഡർ തയ്യാറാക്കിയതിന് ശേഷം മാത്രമേ ഇത് എപ്പോഴും ചെയ്യാവൂ എന്ന് ഓർമ്മിക്കുക. ലേണിംഗ് റേറ്റിൽ നിന്ന് 0-ലേക്കുള്ള ഒരു ക്ലാസിക് ലീനിയർ ഷെഡ്യൂൾ നമ്മൾ ഉപയോഗിക്കുന്നു: + +```py +from transformers import get_scheduler + +num_train_epochs = 3 +num_update_steps_per_epoch = len(train_dataloader) +num_training_steps = num_train_epochs * num_update_steps_per_epoch + +lr_scheduler = get_scheduler( + "linear", + optimizer=optimizer, + num_warmup_steps=0, + num_training_steps=num_training_steps, +) +``` + +അവസാനമായി, നമ്മുടെ മോഡൽ Hub-ലേക്ക് പുഷ് ചെയ്യാൻ, ഒരു വർക്കിംഗ് ഫോൾഡറിൽ ഒരു `Repository` ഒബ്‌ജക്റ്റ് നമ്മൾ ഉണ്ടാക്കേണ്ടിവരും. നിങ്ങൾ ഇതിനകം ലോഗിൻ ചെയ്തിട്ടില്ലെങ്കിൽ, ആദ്യം Hugging Face Hub-ൽ ലോഗിൻ ചെയ്യുക. നമ്മുടെ മോഡലിന് നൽകാൻ ആഗ്രഹിക്കുന്ന മോഡൽ ID-യിൽ നിന്ന് റിപ്പോസിറ്ററിയുടെ പേര് നമ്മൾ നിർണ്ണയിക്കും (`repo_name` നിങ്ങളുടെ സ്വന്തം ഇഷ്ടപ്രകാരം മാറ്റാൻ മടിക്കേണ്ട; അതിൽ നിങ്ങളുടെ യൂസർനെയിം അടങ്ങിയിരിക്കണം എന്ന് മാത്രം, `get_full_repo_name()` ഫംഗ്‌ഷൻ ചെയ്യുന്നത് അതാണ്): + +```py +from huggingface_hub import Repository, get_full_repo_name + +model_name = "marian-finetuned-kde4-en-to-fr-accelerate" +repo_name = get_full_repo_name(model_name) +repo_name +``` + +```python out +'sgugger/marian-finetuned-kde4-en-to-fr-accelerate' +``` + +തുടർന്ന് ആ റിപ്പോസിറ്ററി ഒരു ലോക്കൽ ഫോൾഡറിലേക്ക് നമുക്ക് ക്ലോൺ ചെയ്യാം. അത് ഇതിനകം നിലവിലുണ്ടെങ്കിൽ, ഈ ലോക്കൽ ഫോൾഡർ നമ്മൾ പ്രവർത്തിക്കുന്ന റിപ്പോസിറ്ററിയുടെ ഒരു ക്ലോൺ ആയിരിക്കണം: + +```py +output_dir = "marian-finetuned-kde4-en-to-fr-accelerate" +repo = Repository(output_dir, clone_from=repo_name) +``` + +`repo.push_to_hub()` മെത്തേഡ് വിളിച്ചുകൊണ്ട് `output_dir`-ൽ നമ്മൾ സേവ് ചെയ്യുന്ന എന്തും ഇപ്പോൾ നമുക്ക് അപ്‌ലോഡ് ചെയ്യാം. ഓരോ എപ്പോക്കിന്റെയും അവസാനം ഇടക്കാല മോഡലുകൾ അപ്‌ലോഡ് ചെയ്യാൻ ഇത് നമ്മെ സഹായിക്കും. + +### ട്രെയിനിംഗ് ലൂപ്പ്[[training-loop]] + +പൂർണ്ണമായ ട്രെയിനിംഗ് ലൂപ്പ് എഴുതാൻ നമ്മൾ ഇപ്പോൾ തയ്യാറാണ്. അതിന്റെ ഇവാല്യുവേഷൻ ഭാഗം ലളിതമാക്കാൻ, പ്രവചനങ്ങളും ലേബലുകളും സ്വീകരിച്ച് അവയെ നമ്മുടെ `metric` ഒബ്‌ജക്റ്റ് പ്രതീക്ഷിക്കുന്ന സ്‌ട്രിംഗുകളുടെ ലിസ്‌റ്റുകളിലേക്ക് മാറ്റുന്ന ഈ `postprocess()` ഫംഗ്‌ഷൻ നമ്മൾ നിർവചിക്കുന്നു: + +```py +def postprocess(predictions, labels): + predictions = predictions.cpu().numpy() + labels = labels.cpu().numpy() + + decoded_preds = tokenizer.batch_decode(predictions, skip_special_tokens=True) + + # Replace -100 in the labels as we can't decode them. + labels = np.where(labels != -100, labels, tokenizer.pad_token_id) + decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True) + + # Some simple post-processing + decoded_preds = [pred.strip() for pred in decoded_preds] + decoded_labels = [[label.strip()] for label in decoded_labels] + return decoded_preds, decoded_labels +``` + +ട്രെയിനിംഗ് ലൂപ്പ് [ഭാഗം 2](/course/chapter7/2)-ലെയും [അധ്യായം 3](/course/chapter3)-ലെയും ലൂപ്പുകളോട് ഏറെ സാമ്യമുള്ളതാണ്, ഇവാല്യുവേഷൻ ഭാഗത്തിൽ ഏതാനും വ്യത്യാസങ്ങളോടെ — അതിനാൽ അതിൽ നമുക്ക് ശ്രദ്ധ കേന്ദ്രീകരിക്കാം! + +ആദ്യം ശ്രദ്ധിക്കേണ്ട കാര്യം, പ്രവചനങ്ങൾ കണക്കുകൂട്ടാൻ നമ്മൾ `generate()` മെത്തേഡ് ഉപയോഗിക്കുന്നു എന്നതാണ്; എന്നാൽ ഇത് നമ്മുടെ ബേസ് മോഡലിലെ ഒരു മെത്തേഡാണ്, `prepare()` മെത്തേഡിൽ 🤗 Accelerate ഉണ്ടാക്കിയ റാപ്പ് ചെയ്ത മോഡലിലേതല്ല. അതുകൊണ്ടാണ് നമ്മൾ ആദ്യം മോഡൽ അൻറാപ്പ് (unwrap) ചെയ്ത്, പിന്നീട് ഈ മെത്തേഡ് വിളിക്കുന്നത്. + +രണ്ടാമത്തെ കാര്യം, [ടോക്കൺ ക്ലാസിഫിക്കേഷനിലേതുപോലെ](/course/chapter7/2), രണ്ട് പ്രോസസ്സുകൾ ഇൻപുട്ടുകളും ലേബലുകളും വ്യത്യസ്ത ഷേപ്പുകളിലേക്ക് പാഡ് ചെയ്തിരിക്കാം എന്നതാണ്; അതിനാൽ `gather()` മെത്തേഡ് വിളിക്കുന്നതിന് മുമ്പ് പ്രവചനങ്ങളെയും ലേബലുകളെയും ഒരേ ഷേപ്പിലാക്കാൻ `accelerator.pad_across_processes()` നമ്മൾ ഉപയോഗിക്കുന്നു. ഇത് ചെയ്തില്ലെങ്കിൽ, ഇവാല്യുവേഷൻ ഒന്നുകിൽ എറർ നൽകി നിലയ്ക്കും, അല്ലെങ്കിൽ എന്നെന്നേക്കുമായി തൂങ്ങിക്കിടക്കും (hang). + +```py +from tqdm.auto import tqdm +import torch + +progress_bar = tqdm(range(num_training_steps)) + +for epoch in range(num_train_epochs): + # Training + model.train() + for batch in train_dataloader: + outputs = model(**batch) + loss = outputs.loss + accelerator.backward(loss) + + optimizer.step() + lr_scheduler.step() + optimizer.zero_grad() + progress_bar.update(1) + + # Evaluation + model.eval() + for batch in tqdm(eval_dataloader): + with torch.no_grad(): + generated_tokens = accelerator.unwrap_model(model).generate( + batch["input_ids"], + attention_mask=batch["attention_mask"], + max_length=128, + ) + labels = batch["labels"] + + # Necessary to pad predictions and labels for being gathered + generated_tokens = accelerator.pad_across_processes( + generated_tokens, dim=1, pad_index=tokenizer.pad_token_id + ) + labels = accelerator.pad_across_processes(labels, dim=1, pad_index=-100) + + predictions_gathered = accelerator.gather(generated_tokens) + labels_gathered = accelerator.gather(labels) + + decoded_preds, decoded_labels = postprocess(predictions_gathered, labels_gathered) + metric.add_batch(predictions=decoded_preds, references=decoded_labels) + + results = metric.compute() + print(f"epoch {epoch}, BLEU score: {results['score']:.2f}") + + # Save and upload + accelerator.wait_for_everyone() + unwrapped_model = accelerator.unwrap_model(model) + unwrapped_model.save_pretrained(output_dir, save_function=accelerator.save) + if accelerator.is_main_process: + tokenizer.save_pretrained(output_dir) + repo.push_to_hub( + commit_message=f"Training in progress epoch {epoch}", blocking=False + ) +``` + +```python out +epoch 0, BLEU score: 53.47 +epoch 1, BLEU score: 54.24 +epoch 2, BLEU score: 54.44 +``` + +ഇത് പൂർത്തിയായാൽ, `Seq2SeqTrainer` ഉപയോഗിച്ച് ട്രെയിൻ ചെയ്തതിനോട് ഏറെ സമാനമായ ഫലങ്ങളുള്ള ഒരു മോഡൽ നിങ്ങൾക്കുണ്ടാകണം. ഈ കോഡ് ഉപയോഗിച്ച് നമ്മൾ ട്രെയിൻ ചെയ്തത് [*huggingface-course/marian-finetuned-kde4-en-to-fr-accelerate*](https://huggingface.co/huggingface-course/marian-finetuned-kde4-en-to-fr-accelerate)-ൽ നിങ്ങൾക്ക് പരിശോധിക്കാം. ട്രെയിനിംഗ് ലൂപ്പിൽ എന്തെങ്കിലും ചെറിയ മാറ്റങ്ങൾ പരീക്ഷിക്കാൻ നിങ്ങൾ ആഗ്രഹിക്കുന്നുവെങ്കിൽ, മുകളിൽ കാണിച്ച കോഡ് എഡിറ്റ് ചെയ്തുകൊണ്ട് അവ നേരിട്ട് നടപ്പിലാക്കാം! + +{/if} + +## ഫൈൻ-ട്യൂൻ ചെയ്ത മോഡൽ ഉപയോഗിക്കുന്നു[[using-the-fine-tuned-model]] + +നമ്മൾ ഫൈൻ-ട്യൂൻ ചെയ്ത മോഡൽ Model Hub-ൽ ഇൻഫറൻസ് വിജറ്റ് ഉപയോഗിച്ച് എങ്ങനെ ഉപയോഗിക്കാമെന്ന് നമ്മൾ ഇതിനകം നിങ്ങൾക്ക് കാണിച്ചുതന്നിട്ടുണ്ട്. ഒരു `pipeline`-ൽ അത് ലോക്കലായി ഉപയോഗിക്കാൻ, ശരിയായ മോഡൽ ഐഡന്റിഫയർ വ്യക്തമാക്കിയാൽ മാത്രം മതി: + +```py +from transformers import pipeline + +# Replace this with your own checkpoint +model_checkpoint = "huggingface-course/marian-finetuned-kde4-en-to-fr" +translator = pipeline("translation", model=model_checkpoint) +translator("Default to expanded threads") +``` + +```python out +[{'translation_text': 'Par défaut, développer les fils de discussion'}] +``` + +പ്രതീക്ഷിച്ചതുപോലെ, നമ്മുടെ പ്രീട്രെയിൻഡ് മോഡൽ അതിന്റെ അറിവ് നമ്മൾ ഫൈൻ-ട്യൂൻ ചെയ്ത കോർപ്പസിലേക്ക് അനുയോജ്യമാക്കി; "threads" എന്ന ഇംഗ്ലീഷ് വാക്ക് അതേപടി വിടുന്നതിന് പകരം, ഇപ്പോൾ അത് അതിന്റെ ഔദ്യോഗിക ഫ്രഞ്ച് പതിപ്പിലേക്ക് വിവർത്തനം ചെയ്യുന്നു. "plugin"-ന്റെ കാര്യത്തിലും ഇതുതന്നെയാണ് സ്ഥിതി: + +```py +translator( + "Unable to import %1 using the OFX importer plugin. This file is not the correct format." +) +``` + +```python out +[{'translation_text': "Impossible d'importer %1 en utilisant le module externe d'importation OFX. Ce fichier n'est pas le bon format."}] +``` + +ഡൊമെയ്ൻ അഡാപ്‌റ്റേഷന്റെ (domain adaptation) മറ്റൊരു മികച്ച ഉദാഹരണം! + +> [!TIP] +> ✏️ **നിങ്ങളുടെ ഊഴം!** നിങ്ങൾ മുമ്പ് കണ്ടെത്തിയ, "email" എന്ന വാക്കുള്ള സാമ്പിളിൽ മോഡൽ എന്താണ് തിരികെ നൽകുന്നത്? diff --git a/chapters/ml/chapter7/5.mdx b/chapters/ml/chapter7/5.mdx new file mode 100644 index 000000000..739c17d62 --- /dev/null +++ b/chapters/ml/chapter7/5.mdx @@ -0,0 +1,1048 @@ + + +# സമ്മറൈസേഷൻ[[summarization]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + + +ദൈർഘ്യമേറിയ ഡോക്യുമെന്റുകളെ സംഗ്രഹങ്ങളായി (summaries) ചുരുക്കാൻ Transformer മോഡലുകൾ എങ്ങനെ ഉപയോഗിക്കാമെന്ന് ഈ ഭാഗത്തിൽ നമ്മൾ പരിശോധിക്കും; _ടെക്‌സ്‌റ്റ് സമ്മറൈസേഷൻ_ (text summarization) എന്നാണ് ഈ ടാസ്‌ക് അറിയപ്പെടുന്നത്. നീണ്ട ഖണ്ഡികകൾ മനസ്സിലാക്കുക, ഒരു ഡോക്യുമെന്റിലെ പ്രധാന വിഷയങ്ങൾ ഉൾക്കൊള്ളുന്ന യോജിപ്പുള്ള ടെക്‌സ്‌റ്റ് ജനറേറ്റ് ചെയ്യുക തുടങ്ങിയ പലതരം കഴിവുകൾ ആവശ്യമായതിനാൽ, ഏറ്റവും വെല്ലുവിളി നിറഞ്ഞ NLP ടാസ്‌കുകളിൽ ഒന്നാണിത്. എന്നിരുന്നാലും, നന്നായി ചെയ്യുമ്പോൾ, ദൈർഘ്യമേറിയ ഡോക്യുമെന്റുകൾ വിശദമായി വായിക്കേണ്ട ഭാരത്തിൽ നിന്ന് ഡൊമെയ്ൻ വിദഗ്ധരെ മോചിപ്പിച്ചുകൊണ്ട് വിവിധ ബിസിനസ് പ്രോസസ്സുകൾ വേഗത്തിലാക്കാൻ കഴിയുന്ന ശക്തമായ ഒരു ഉപകരണമാണ് ടെക്‌സ്‌റ്റ് സമ്മറൈസേഷൻ. + + + +[Hugging Face Hub](https://huggingface.co/models?pipeline_tag=summarization&sort=downloads)-ൽ സമ്മറൈസേഷനായി ഫൈൻ-ട്യൂൻ ചെയ്ത വിവിധ മോഡലുകൾ ഇതിനകം ഉണ്ടെങ്കിലും, അവയിൽ മിക്കവാറും എല്ലാം ഇംഗ്ലീഷ് ഡോക്യുമെന്റുകൾക്ക് മാത്രം അനുയോജ്യമായവയാണ്. അതിനാൽ, ഈ ഭാഗത്തിൽ ഒരു വ്യത്യസ്തത കൊണ്ടുവരാൻ, ഇംഗ്ലീഷിനും സ്പാനിഷിനുമായി ഒരു ദ്വിഭാഷാ (bilingual) മോഡൽ നമ്മൾ ട്രെയിൻ ചെയ്യും. ഈ ഭാഗത്തിന്റെ അവസാനത്തോടെ, ഇവിടെ കാണിച്ചിരിക്കുന്നതുപോലുള്ള കസ്‌റ്റമർ റിവ്യൂകൾ സംഗ്രഹിക്കാൻ കഴിയുന്ന ഒരു [മോഡൽ](https://huggingface.co/huggingface-course/mt5-small-finetuned-amazon-en-es) നിങ്ങളുടെ കൈവശമുണ്ടാകും: + + + +നമ്മൾ കാണാൻ പോകുന്നതുപോലെ, കസ്‌റ്റമർമാർ അവരുടെ പ്രൊഡക്റ്റ് റിവ്യൂകളിൽ നൽകുന്ന തലക്കെട്ടുകളിൽ (titles) നിന്ന് പഠിച്ചെടുക്കുന്നതിനാലാണ് ഈ സംഗ്രഹങ്ങൾ ഇത്ര സംക്ഷിപ്തമായിരിക്കുന്നത്. ഈ ടാസ്‌കിന് അനുയോജ്യമായ ഒരു ദ്വിഭാഷാ കോർപ്പസ് (corpus) തയ്യാറാക്കിക്കൊണ്ട് നമുക്ക് തുടങ്ങാം. + +## ഒരു ബഹുഭാഷാ കോർപ്പസ് തയ്യാറാക്കുന്നു[[preparing-a-multilingual-corpus]] + +നമ്മുടെ ദ്വിഭാഷാ സമ്മറൈസർ നിർമ്മിക്കാൻ [Multilingual Amazon Reviews Corpus](https://huggingface.co/datasets/amazon_reviews_multi) നമ്മൾ ഉപയോഗിക്കും. ആറ് ഭാഷകളിലുള്ള Amazon പ്രൊഡക്റ്റ് റിവ്യൂകൾ അടങ്ങിയ ഈ കോർപ്പസ് സാധാരണയായി ബഹുഭാഷാ ക്ലാസിഫയറുകളെ ബെഞ്ച്‌മാർക്ക് ചെയ്യാനാണ് ഉപയോഗിക്കുന്നത്. എന്നാൽ, ഓരോ റിവ്യൂവിനോടൊപ്പവും ഒരു ചെറിയ തലക്കെട്ടും ഉള്ളതിനാൽ, നമ്മുടെ മോഡലിന് പഠിക്കാനുള്ള ടാർഗെറ്റ് സംഗ്രഹങ്ങളായി ഈ തലക്കെട്ടുകൾ നമുക്ക് ഉപയോഗിക്കാം! തുടങ്ങാനായി, ഇംഗ്ലീഷ്, സ്പാനിഷ് സബ്‌സെറ്റുകൾ Hugging Face Hub-ൽ നിന്ന് ഡൗൺലോഡ് ചെയ്യാം: + +```python +from datasets import load_dataset + +spanish_dataset = load_dataset("amazon_reviews_multi", "es") +english_dataset = load_dataset("amazon_reviews_multi", "en") +english_dataset +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['review_id', 'product_id', 'reviewer_id', 'stars', 'review_body', 'review_title', 'language', 'product_category'], + num_rows: 200000 + }) + validation: Dataset({ + features: ['review_id', 'product_id', 'reviewer_id', 'stars', 'review_body', 'review_title', 'language', 'product_category'], + num_rows: 5000 + }) + test: Dataset({ + features: ['review_id', 'product_id', 'reviewer_id', 'stars', 'review_body', 'review_title', 'language', 'product_category'], + num_rows: 5000 + }) +}) +``` + +നിങ്ങൾക്ക് കാണാവുന്നതുപോലെ, ഓരോ ഭാഷയ്ക്കും `train` സ്പ്ലിറ്റിൽ 200,000 റിവ്യൂകളും, `validation`, `test` സ്പ്ലിറ്റുകളിൽ ഓരോന്നിലും 5,000 റിവ്യൂകൾ വീതവുമുണ്ട്. നമുക്ക് താൽപ്പര്യമുള്ള റിവ്യൂ വിവരങ്ങൾ `review_body`, `review_title` എന്നീ കോളങ്ങളിലാണ് ഉള്ളത്. [അധ്യായം 5](/course/chapter5)-ൽ നമ്മൾ പഠിച്ച ടെക്‌നിക്കുകൾ ഉപയോഗിച്ച് ട്രെയിനിംഗ് സെറ്റിൽ നിന്ന് ഒരു റാൻഡം സാമ്പിൾ എടുക്കുന്ന ഒരു ലളിതമായ ഫംഗ്‌ഷൻ നിർമ്മിച്ച്, ഏതാനും ഉദാഹരണങ്ങൾ നമുക്ക് നോക്കാം: + +```python +def show_samples(dataset, num_samples=3, seed=42): + sample = dataset["train"].shuffle(seed=seed).select(range(num_samples)) + for example in sample: + print(f"\n'>> Title: {example['review_title']}'") + print(f"'>> Review: {example['review_body']}'") + + +show_samples(english_dataset) +``` + +```python out +'>> Title: Worked in front position, not rear' +'>> Review: 3 stars because these are not rear brakes as stated in the item description. At least the mount adapter only worked on the front fork of the bike that I got it for.' + +'>> Title: meh' +'>> Review: Does it’s job and it’s gorgeous but mine is falling apart, I had to basically put it together again with hot glue' + +'>> Title: Can\'t beat these for the money' +'>> Review: Bought this for handling miscellaneous aircraft parts and hanger "stuff" that I needed to organize; it really fit the bill. The unit arrived quickly, was well packaged and arrived intact (always a good sign). There are five wall mounts-- three on the top and two on the bottom. I wanted to mount it on the wall, so all I had to do was to remove the top two layers of plastic drawers, as well as the bottom corner drawers, place it when I wanted and mark it; I then used some of the new plastic screw in wall anchors (the 50 pound variety) and it easily mounted to the wall. Some have remarked that they wanted dividers for the drawers, and that they made those. Good idea. My application was that I needed something that I can see the contents at about eye level, so I wanted the fuller-sized drawers. I also like that these are the new plastic that doesn\'t get brittle and split like my older plastic drawers did. I like the all-plastic construction. It\'s heavy duty enough to hold metal parts, but being made of plastic it\'s not as heavy as a metal frame, so you can easily mount it to the wall and still load it up with heavy stuff, or light stuff. No problem there. For the money, you can\'t beat it. Best one of these I\'ve bought to date-- and I\'ve been using some version of these for over forty years.' +``` + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** കോർപ്പസിലെ മറ്റ് റിവ്യൂകൾ പരിശോധിക്കാൻ `Dataset.shuffle()` കമാൻഡിലെ റാൻഡം സീഡ് മാറ്റി നോക്കുക. നിങ്ങൾക്ക് സ്പാനിഷ് അറിയാമെങ്കിൽ, `spanish_dataset`-ലെ ചില റിവ്യൂകൾ നോക്കി, അവിടെയും തലക്കെട്ടുകൾ ന്യായമായ സംഗ്രഹങ്ങളായി തോന്നുന്നുണ്ടോ എന്ന് പരിശോധിക്കുക. + +ഓൺലൈനിൽ സാധാരണയായി കാണുന്ന റിവ്യൂകളുടെ വൈവിധ്യം — പോസിറ്റീവ് മുതൽ നെഗറ്റീവ് വരെ (അതിനിടയിലുള്ള എല്ലാം ഉൾപ്പെടെ!) — ഈ സാമ്പിൾ കാണിക്കുന്നു. "meh" എന്ന തലക്കെട്ടുള്ള ഉദാഹരണം അത്ര വിവരദായകമല്ലെങ്കിലും, മറ്റ് തലക്കെട്ടുകൾ റിവ്യൂകളുടെ തരക്കേടില്ലാത്ത സംഗ്രഹങ്ങളായി തോന്നുന്നു. 400,000 റിവ്യൂകളിലും ഒരു സമ്മറൈസേഷൻ മോഡൽ ട്രെയിൻ ചെയ്യുന്നത് ഒരൊറ്റ GPU-വിൽ വളരെയധികം സമയമെടുക്കും, അതിനാൽ പകരം ഒരൊറ്റ പ്രൊഡക്റ്റ് ഡൊമെയ്‌നിനുള്ള സംഗ്രഹങ്ങൾ ജനറേറ്റ് ചെയ്യുന്നതിലാണ് നമ്മൾ ശ്രദ്ധ കേന്ദ്രീകരിക്കുക. തിരഞ്ഞെടുക്കാൻ ഏതൊക്കെ ഡൊമെയ്‌നുകളുണ്ടെന്ന് മനസ്സിലാക്കാൻ, `english_dataset`-നെ ഒരു `pandas.DataFrame`-ലേക്ക് മാറ്റി, ഓരോ പ്രൊഡക്റ്റ് കാറ്റഗറിയിലെയും റിവ്യൂകളുടെ എണ്ണം കണക്കാക്കാം: + +```python +english_dataset.set_format("pandas") +english_df = english_dataset["train"][:] +# Show counts for top 20 products +english_df["product_category"].value_counts()[:20] +``` + +```python out +home 17679 +apparel 15951 +wireless 15717 +other 13418 +beauty 12091 +drugstore 11730 +kitchen 10382 +toy 8745 +sports 8277 +automotive 7506 +lawn_and_garden 7327 +home_improvement 7136 +pet_products 7082 +digital_ebook_purchase 6749 +pc 6401 +electronics 6186 +office_product 5521 +shoes 5197 +grocery 4730 +book 3756 +Name: product_category, dtype: int64 +``` + +ഇംഗ്ലീഷ് ഡേറ്റാസെറ്റിലെ ഏറ്റവും ജനപ്രിയമായ പ്രൊഡക്റ്റുകൾ വീട്ടുപകരണങ്ങൾ, വസ്ത്രങ്ങൾ, വയർലെസ് ഇലക്ട്രോണിക്‌സ് എന്നിവയാണ്. എന്നാൽ Amazon-ന്റെ തീമിനോട് ചേർന്നുനിൽക്കാൻ, പുസ്തക റിവ്യൂകൾ സംഗ്രഹിക്കുന്നതിൽ നമുക്ക് ശ്രദ്ധ കേന്ദ്രീകരിക്കാം — എന്തായാലും, ഇതിലാണല്ലോ ആ കമ്പനി സ്ഥാപിതമായത്! ഇതിന് യോജിക്കുന്ന രണ്ട് പ്രൊഡക്റ്റ് കാറ്റഗറികൾ നമുക്ക് കാണാം (`book`, `digital_ebook_purchase`), അതിനാൽ രണ്ട് ഭാഷകളിലെയും ഡേറ്റാസെറ്റുകൾ ഈ പ്രൊഡക്റ്റുകൾക്ക് മാത്രമായി ഫിൽറ്റർ ചെയ്യാം. [അധ്യായം 5](/course/chapter5)-ൽ നമ്മൾ കണ്ടതുപോലെ, `Dataset.filter()` ഫംഗ്‌ഷൻ ഒരു ഡേറ്റാസെറ്റിനെ വളരെ കാര്യക്ഷമമായി സ്ലൈസ് ചെയ്യാൻ അനുവദിക്കുന്നു, അതിനാൽ ഇതിനായി ഒരു ലളിതമായ ഫംഗ്‌ഷൻ നമുക്ക് നിർവചിക്കാം: + +```python +def filter_books(example): + return ( + example["product_category"] == "book" + or example["product_category"] == "digital_ebook_purchase" + ) +``` + +ഇപ്പോൾ ഈ ഫംഗ്‌ഷൻ `english_dataset`-ലും `spanish_dataset`-ലും പ്രയോഗിക്കുമ്പോൾ, പുസ്തക കാറ്റഗറികളുമായി ബന്ധപ്പെട്ട വരികൾ മാത്രമേ ഫലത്തിൽ ഉണ്ടാകൂ. ഫിൽറ്റർ പ്രയോഗിക്കുന്നതിന് മുമ്പ്, `english_dataset`-ന്റെ ഫോർമാറ്റ് `"pandas"`-ൽ നിന്ന് തിരികെ `"arrow"`-ലേക്ക് മാറ്റാം: + +```python +english_dataset.reset_format() +``` + +തുടർന്ന് നമുക്ക് ഫിൽറ്റർ ഫംഗ്‌ഷൻ പ്രയോഗിക്കാം; ഒരു ഉറപ്പുവരുത്തലിനായി (sanity check), റിവ്യൂകളുടെ ഒരു സാമ്പിൾ പരിശോധിച്ച് അവ ശരിക്കും പുസ്തകങ്ങളെക്കുറിച്ചാണോ എന്ന് നോക്കാം: + +```python +spanish_books = spanish_dataset.filter(filter_books) +english_books = english_dataset.filter(filter_books) +show_samples(english_books) +``` + +```python out +'>> Title: I\'m dissapointed.' +'>> Review: I guess I had higher expectations for this book from the reviews. I really thought I\'d at least like it. The plot idea was great. I loved Ash but, it just didnt go anywhere. Most of the book was about their radio show and talking to callers. I wanted the author to dig deeper so we could really get to know the characters. All we know about Grace is that she is attractive looking, Latino and is kind of a brat. I\'m dissapointed.' + +'>> Title: Good art, good price, poor design' +'>> Review: I had gotten the DC Vintage calendar the past two years, but it was on backorder forever this year and I saw they had shrunk the dimensions for no good reason. This one has good art choices but the design has the fold going through the picture, so it\'s less aesthetically pleasing, especially if you want to keep a picture to hang. For the price, a good calendar' + +'>> Title: Helpful' +'>> Review: Nearly all the tips useful and. I consider myself an intermediate to advanced user of OneNote. I would highly recommend.' +``` + +ശരി, റിവ്യൂകൾ കർശനമായി പുസ്തകങ്ങളെക്കുറിച്ച് മാത്രമല്ല, കലണ്ടറുകൾ, OneNote പോലുള്ള ഇലക്ട്രോണിക് ആപ്ലിക്കേഷനുകൾ തുടങ്ങിയ കാര്യങ്ങളെക്കുറിച്ചും ആകാം എന്ന് നമുക്ക് കാണാം. എന്നിരുന്നാലും, ഒരു സമ്മറൈസേഷൻ മോഡൽ ട്രെയിൻ ചെയ്യാൻ ഈ ഡൊമെയ്ൻ ഏകദേശം ശരിയാണെന്ന് തോന്നുന്നു. ഈ ടാസ്‌കിന് അനുയോജ്യമായ വിവിധ മോഡലുകൾ പരിശോധിക്കുന്നതിന് മുമ്പ്, ഡേറ്റാ തയ്യാറാക്കലിന്റെ അവസാനത്തെ ഒരു ഭാഗം കൂടി നമുക്ക് ചെയ്യാനുണ്ട്: ഇംഗ്ലീഷ്, സ്പാനിഷ് റിവ്യൂകളെ ഒരൊറ്റ `DatasetDict` ഒബ്‌ജക്റ്റായി സംയോജിപ്പിക്കുക. രണ്ട് `Dataset` ഒബ്‌ജക്റ്റുകളെ (പേര് സൂചിപ്പിക്കുന്നതുപോലെ) ഒന്നിനു മുകളിൽ ഒന്നായി അടുക്കിവയ്ക്കുന്ന ഉപകാരപ്രദമായ ഒരു `concatenate_datasets()` ഫംഗ്‌ഷൻ 🤗 Datasets നൽകുന്നു. അതിനാൽ, നമ്മുടെ ദ്വിഭാഷാ ഡേറ്റാസെറ്റ് നിർമ്മിക്കാൻ, ഓരോ സ്പ്ലിറ്റിലൂടെയും ലൂപ്പ് ചെയ്ത്, ആ സ്പ്ലിറ്റിനുള്ള ഡേറ്റാസെറ്റുകൾ കൂട്ടിച്ചേർത്ത്, നമ്മുടെ മോഡൽ ഒരൊറ്റ ഭാഷയിലേക്ക് ഓവർഫിറ്റ് ചെയ്യാതിരിക്കാൻ ഫലം ഷഫിൾ ചെയ്യും: + +```python +from datasets import concatenate_datasets, DatasetDict + +books_dataset = DatasetDict() + +for split in english_books.keys(): + books_dataset[split] = concatenate_datasets( + [english_books[split], spanish_books[split]] + ) + books_dataset[split] = books_dataset[split].shuffle(seed=42) + +# Peek at a few examples +show_samples(books_dataset) +``` + +```python out +'>> Title: Easy to follow!!!!' +'>> Review: I loved The dash diet weight loss Solution. Never hungry. I would recommend this diet. Also the menus are well rounded. Try it. Has lots of the information need thanks.' + +'>> Title: PARCIALMENTE DAÑADO' +'>> Review: Me llegó el día que tocaba, junto a otros libros que pedí, pero la caja llegó en mal estado lo cual dañó las esquinas de los libros porque venían sin protección (forro).' + +'>> Title: no lo he podido descargar' +'>> Review: igual que el anterior' +``` + +ഇത് തീർച്ചയായും ഇംഗ്ലീഷ്, സ്പാനിഷ് റിവ്യൂകളുടെ ഒരു മിശ്രിതമായി തോന്നുന്നു! ഇപ്പോൾ നമുക്ക് ഒരു ട്രെയിനിംഗ് കോർപ്പസ് ഉള്ളതിനാൽ, അവസാനമായി പരിശോധിക്കേണ്ട ഒരു കാര്യം റിവ്യൂകളിലെയും അവയുടെ തലക്കെട്ടുകളിലെയും വാക്കുകളുടെ വിതരണമാണ് (distribution). സമ്മറൈസേഷൻ ടാസ്‌കുകളിൽ ഇത് പ്രത്യേകിച്ചും പ്രധാനമാണ്, കാരണം ഡേറ്റയിലെ ചെറിയ റഫറൻസ് സംഗ്രഹങ്ങൾ, ജനറേറ്റ് ചെയ്യുന്ന സംഗ്രഹങ്ങളിൽ ഒന്നോ രണ്ടോ വാക്കുകൾ മാത്രം ഔട്ട്‌പുട്ട് ചെയ്യാൻ മോഡലിനെ പ്രേരിപ്പിച്ചേക്കാം (bias). താഴെയുള്ള പ്ലോട്ടുകൾ വാക്കുകളുടെ വിതരണം കാണിക്കുന്നു; തലക്കെട്ടുകൾ വെറും 1-2 വാക്കുകളിലേക്ക് ശക്തമായി ചായ്‌വുള്ളവയാണെന്ന് (skewed) നമുക്ക് കാണാം: + +
+റിവ്യൂ തലക്കെട്ടുകളുടെയും ടെക്‌സ്‌റ്റുകളുടെയും വാക്കുകളുടെ എണ്ണത്തിന്റെ വിതരണം. + +
+ +ഇത് കൈകാര്യം ചെയ്യാൻ, നമ്മുടെ മോഡലിന് കൂടുതൽ രസകരമായ സംഗ്രഹങ്ങൾ ഉണ്ടാക്കാൻ കഴിയുന്ന വിധത്തിൽ, വളരെ ചെറിയ തലക്കെട്ടുകളുള്ള ഉദാഹരണങ്ങൾ നമ്മൾ ഫിൽറ്റർ ചെയ്ത് ഒഴിവാക്കും. നമ്മൾ ഇംഗ്ലീഷ്, സ്പാനിഷ് ടെക്‌സ്‌റ്റുകളാണ് കൈകാര്യം ചെയ്യുന്നതിനാൽ, തലക്കെട്ടുകളെ വൈറ്റ്‌സ്‌പേസിൽ വിഭജിക്കുന്ന ഒരു ഏകദേശ ഹ്യൂറിസ്‌റ്റിക് (heuristic) ഉപയോഗിക്കാം; തുടർന്ന് നമ്മുടെ വിശ്വസ്തമായ `Dataset.filter()` മെത്തേഡ് താഴെ കാണുന്നതുപോലെ ഉപയോഗിക്കാം: + +```python +books_dataset = books_dataset.filter(lambda x: len(x["review_title"].split()) > 2) +``` + +ഇപ്പോൾ നമ്മുടെ കോർപ്പസ് തയ്യാറാക്കിക്കഴിഞ്ഞു, അതിൽ ഫൈൻ-ട്യൂൻ ചെയ്യാവുന്ന ഏതാനും Transformer മോഡലുകൾ നമുക്ക് നോക്കാം! + +## ടെക്‌സ്‌റ്റ് സമ്മറൈസേഷനുള്ള മോഡലുകൾ[[models-for-text-summarization]] + +ചിന്തിച്ചു നോക്കിയാൽ, ടെക്‌സ്‌റ്റ് സമ്മറൈസേഷൻ മെഷീൻ ട്രാൻസ്‌ലേഷനോട് സാമ്യമുള്ള ഒരു ടാസ്‌കാണ്: ഒരു റിവ്യൂ പോലുള്ള ഒരു ടെക്‌സ്‌റ്റ് നമ്മുടെ കൈയിലുണ്ട്, അതിനെ ഇൻപുട്ടിന്റെ പ്രധാന സവിശേഷതകൾ ഉൾക്കൊള്ളുന്ന ഒരു ചെറിയ പതിപ്പിലേക്ക് "വിവർത്തനം" ചെയ്യാനാണ് നമ്മൾ ആഗ്രഹിക്കുന്നത്. അതനുസരിച്ച്, സമ്മറൈസേഷനുള്ള മിക്ക Transformer മോഡലുകളും [അധ്യായം 1](/course/chapter1)-ൽ നമ്മൾ ആദ്യമായി കണ്ട എൻകോഡർ-ഡീകോഡർ ആർക്കിടെക്ചറാണ് സ്വീകരിക്കുന്നത്; എന്നാൽ few-shot സാഹചര്യങ്ങളിൽ സമ്മറൈസേഷനും ഉപയോഗിക്കാവുന്ന GPT കുടുംബത്തിലെ മോഡലുകൾ പോലുള്ള ചില അപവാദങ്ങളുമുണ്ട്. സമ്മറൈസേഷനായി ഫൈൻ-ട്യൂൻ ചെയ്യാവുന്ന ചില ജനപ്രിയ പ്രീട്രെയിൻഡ് മോഡലുകൾ താഴെയുള്ള പട്ടികയിൽ കാണാം. + +| Transformer മോഡൽ | വിവരണം | ബഹുഭാഷാ? | +| :---------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-----------: | +| [GPT-2](https://huggingface.co/gpt2-xl) | ഒരു ഓട്ടോ-റിഗ്രസ്സീവ് ലാംഗ്വേജ് മോഡലായി ട്രെയിൻ ചെയ്തതാണെങ്കിലും, ഇൻപുട്ട് ടെക്‌സ്‌റ്റിന്റെ അവസാനം "TL;DR" ചേർത്തുകൊണ്ട് GPT-2-നെ സംഗ്രഹങ്ങൾ ജനറേറ്റ് ചെയ്യിക്കാൻ നിങ്ങൾക്ക് കഴിയും. | ❌ | +| [PEGASUS](https://huggingface.co/google/pegasus-large) | ഒന്നിലധികം വാക്യങ്ങളുള്ള ടെക്‌സ്‌റ്റുകളിൽ മാസ്‌ക് ചെയ്ത വാക്യങ്ങൾ പ്രവചിക്കാനുള്ള ഒരു പ്രീട്രെയിനിംഗ് ഒബ്ജക്റ്റീവ് ഉപയോഗിക്കുന്നു. സാധാരണ ലാംഗ്വേജ് മോഡലിംഗിനെക്കാൾ സമ്മറൈസേഷനോട് അടുത്തുനിൽക്കുന്ന ഈ പ്രീട്രെയിനിംഗ് ഒബ്ജക്റ്റീവ്, ജനപ്രിയ ബെഞ്ച്‌മാർക്കുകളിൽ ഉയർന്ന സ്കോർ നേടുന്നു. | ❌ | +| [T5](https://huggingface.co/t5-base) | എല്ലാ ടാസ്‌കുകളെയും ഒരു text-to-text ഫ്രെയിംവർക്കിൽ രൂപപ്പെടുത്തുന്ന ഒരു സാർവത്രിക Transformer ആർക്കിടെക്ചർ; ഉദാ., ഒരു ഡോക്യുമെന്റ് സംഗ്രഹിക്കാൻ മോഡലിനുള്ള ഇൻപുട്ട് ഫോർമാറ്റ് `summarize: ARTICLE` എന്നതാണ്. | ❌ | +| [mT5](https://huggingface.co/google/mt5-base) | 101 ഭാഷകൾ ഉൾക്കൊള്ളുന്ന ബഹുഭാഷാ Common Crawl കോർപ്പസിൽ (mC4) പ്രീട്രെയിൻ ചെയ്ത, T5-ന്റെ ഒരു ബഹുഭാഷാ പതിപ്പ്. | ✅ | +| [BART](https://huggingface.co/facebook/bart-base) | BERT-ന്റെയും GPT-2-ന്റെയും പ്രീട്രെയിനിംഗ് രീതികൾ സംയോജിപ്പിക്കുന്ന, കേടുവരുത്തിയ (corrupted) ഇൻപുട്ട് പുനർനിർമ്മിക്കാൻ ട്രെയിൻ ചെയ്ത ഒരു എൻകോഡർ സ്‌റ്റാക്കും ഒരു ഡീകോഡർ സ്‌റ്റാക്കും ഉള്ള ഒരു നൂതന Transformer ആർക്കിടെക്ചർ. | ❌ | +| [mBART-50](https://huggingface.co/facebook/mbart-large-50) | 50 ഭാഷകളിൽ പ്രീട്രെയിൻ ചെയ്ത, BART-ന്റെ ഒരു ബഹുഭാഷാ പതിപ്പ്. | ✅ | + +ഈ പട്ടികയിൽ നിന്ന് നിങ്ങൾക്ക് കാണാവുന്നതുപോലെ, സമ്മറൈസേഷനുള്ള (തീർച്ചയായും മിക്ക NLP ടാസ്‌കുകൾക്കുമുള്ള) Transformer മോഡലുകളിൽ ഭൂരിഭാഗവും ഏകഭാഷാ (monolingual) മോഡലുകളാണ്. നിങ്ങളുടെ ടാസ്‌ക് ഇംഗ്ലീഷ് അല്ലെങ്കിൽ ജർമ്മൻ പോലുള്ള ഒരു "ഹൈ-റിസോഴ്‌സ്" ഭാഷയിലാണെങ്കിൽ ഇത് വളരെ നല്ലതാണ്, എന്നാൽ ലോകമെമ്പാടും ഉപയോഗത്തിലുള്ള ആയിരക്കണക്കിന് മറ്റ് ഭാഷകൾക്ക് അത്ര നല്ലതല്ല. ഭാഗ്യവശാൽ, mT5, mBART പോലുള്ള ബഹുഭാഷാ Transformer മോഡലുകളുടെ ഒരു വിഭാഗം രക്ഷയ്‌ക്കെത്തുന്നു. ഈ മോഡലുകൾ ലാംഗ്വേജ് മോഡലിംഗ് ഉപയോഗിച്ചാണ് പ്രീട്രെയിൻ ചെയ്യുന്നത്, എന്നാൽ ഒരു വ്യത്യാസത്തോടെ: ഒരു ഭാഷയുടെ കോർപ്പസിൽ ട്രെയിൻ ചെയ്യുന്നതിന് പകരം, 50-ലധികം ഭാഷകളിലെ ടെക്‌സ്‌റ്റുകളിൽ ഒരേസമയം സംയുക്തമായി അവ ട്രെയിൻ ചെയ്യപ്പെടുന്നു! + +text-to-text ഫ്രെയിംവർക്കിൽ പ്രീട്രെയിൻ ചെയ്ത, T5 അടിസ്ഥാനമാക്കിയുള്ള രസകരമായ ഒരു ആർക്കിടെക്ചറായ mT5-ലാണ് നമ്മൾ ശ്രദ്ധ കേന്ദ്രീകരിക്കുക. T5-ൽ, ഓരോ NLP ടാസ്‌കും `summarize:` പോലുള്ള ഒരു പ്രോംപ്‌റ്റ് പ്രിഫിക്‌സിന്റെ രൂപത്തിലാണ് രൂപപ്പെടുത്തുന്നത്; ജനറേറ്റ് ചെയ്യുന്ന ടെക്‌സ്‌റ്റിനെ പ്രോംപ്‌റ്റിന് അനുസൃതമാക്കാൻ ഇത് മോഡലിനെ കണ്ടീഷൻ ചെയ്യുന്നു. താഴെയുള്ള ചിത്രത്തിൽ കാണിച്ചിരിക്കുന്നതുപോലെ, ഇത് T5-നെ അതിവിപുലമായ ഉപയോഗക്ഷമതയുള്ളതാക്കുന്നു (versatile), കാരണം ഒരൊറ്റ മോഡൽ ഉപയോഗിച്ച് നിരവധി ടാസ്‌കുകൾ നിങ്ങൾക്ക് പരിഹരിക്കാം! + +
+T5 ആർക്കിടെക്ചർ നിർവഹിക്കുന്ന വിവിധ ടാസ്‌കുകൾ. + +
+ +mT5 പ്രിഫിക്‌സുകൾ ഉപയോഗിക്കുന്നില്ല, എന്നാൽ T5-ന്റെ ബഹുമുഖതയുടെ നല്ലൊരു പങ്ക് അതിനുമുണ്ട്, കൂടാതെ ബഹുഭാഷാ മോഡലാണെന്ന മേന്മയുമുണ്ട്. ഇപ്പോൾ ഒരു മോഡൽ തിരഞ്ഞെടുത്തുകഴിഞ്ഞു, ട്രെയിനിംഗിനായി നമ്മുടെ ഡേറ്റ തയ്യാറാക്കുന്നത് നമുക്ക് നോക്കാം. + + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** ഈ ഭാഗം പൂർത്തിയാക്കിയ ശേഷം, അതേ ടെക്‌നിക്കുകൾ ഉപയോഗിച്ച് mBART ഫൈൻ-ട്യൂൻ ചെയ്ത്, mBART-നോട് താരതമ്യപ്പെടുത്തുമ്പോൾ mT5 എത്ര മികച്ചതാണെന്ന് നോക്കുക. ബോണസ് പോയിന്റുകൾക്കായി, ഇംഗ്ലീഷ് റിവ്യൂകളിൽ മാത്രം T5 ഫൈൻ-ട്യൂൻ ചെയ്യാനും നിങ്ങൾക്ക് ശ്രമിക്കാം. T5-ന് ഒരു പ്രത്യേക പ്രിഫിക്‌സ് പ്രോംപ്‌റ്റ് ഉള്ളതിനാൽ, താഴെയുള്ള പ്രീപ്രോസസ്സിംഗ് ഘട്ടങ്ങളിൽ ഇൻപുട്ട് ഉദാഹരണങ്ങളുടെ മുന്നിൽ `summarize:` എന്ന് ചേർക്കേണ്ടിവരും. + +## ഡേറ്റ പ്രീപ്രോസസ്സ് ചെയ്യുന്നു[[preprocessing-the-data]] + + + +നമ്മുടെ റിവ്യൂകളും അവയുടെ തലക്കെട്ടുകളും ടോക്കണൈസ് ചെയ്യുകയും എൻകോഡ് ചെയ്യുകയുമാണ് നമ്മുടെ അടുത്ത ടാസ്‌ക്. പതിവുപോലെ, പ്രീട്രെയിൻഡ് മോഡൽ ചെക്ക്‌പോയിന്റുമായി ബന്ധപ്പെട്ട ടോക്കണൈസർ ലോഡ് ചെയ്തുകൊണ്ട് നമ്മൾ തുടങ്ങുന്നു. ന്യായമായ സമയത്തിനുള്ളിൽ മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യാൻ കഴിയുന്നതിനായി, `mt5-small` ആണ് നമ്മുടെ ചെക്ക്‌പോയിന്റായി ഉപയോഗിക്കുക: + +```python +from transformers import AutoTokenizer + +model_checkpoint = "google/mt5-small" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) +``` + +> [!TIP] +> 💡 നിങ്ങളുടെ NLP പ്രോജക്റ്റുകളുടെ ആദ്യഘട്ടങ്ങളിൽ, ഡേറ്റയുടെ ഒരു ചെറിയ സാമ്പിളിൽ "ചെറിയ" മോഡലുകളുടെ ഒരു വിഭാഗം ട്രെയിൻ ചെയ്യുന്നത് ഒരു നല്ല ശീലമാണ്. ഒരു എൻഡ്-ടു-എൻഡ് വർക്ക്‌ഫ്ലോയിലേക്ക് വേഗത്തിൽ ഡീബഗ് ചെയ്യാനും ആവർത്തിച്ച് മെച്ചപ്പെടുത്താനും ഇത് നിങ്ങളെ അനുവദിക്കുന്നു. ഫലങ്ങളിൽ നിങ്ങൾക്ക് ആത്മവിശ്വാസം വന്നുകഴിഞ്ഞാൽ, മോഡൽ ചെക്ക്‌പോയിന്റ് മാറ്റുന്നതിലൂടെ മാത്രം എപ്പോൾ വേണമെങ്കിലും മോഡൽ സ്കെയിൽ അപ്പ് ചെയ്യാം! + +ഒരു ചെറിയ ഉദാഹരണത്തിൽ mT5 ടോക്കണൈസർ പരീക്ഷിച്ചു നോക്കാം: + +```python +inputs = tokenizer("I loved reading the Hunger Games!") +inputs +``` + +```python out +{'input_ids': [336, 259, 28387, 11807, 287, 62893, 295, 12507, 1], 'attention_mask': [1, 1, 1, 1, 1, 1, 1, 1, 1]} +``` + +[അധ്യായം 3](/course/chapter3)-ലെ നമ്മുടെ ആദ്യ ഫൈൻ-ട്യൂണിംഗ് പരീക്ഷണങ്ങളിൽ കണ്ട പരിചിതമായ `input_ids`-ഉം `attention_mask`-ഉം ഇവിടെ നമുക്ക് കാണാം. നമ്മൾ ഏതുതരം ടോക്കണൈസറാണ് കൈകാര്യം ചെയ്യുന്നതെന്ന് അറിയാൻ, ടോക്കണൈസറിന്റെ `convert_ids_to_tokens()` ഫംഗ്‌ഷൻ ഉപയോഗിച്ച് ഈ ഇൻപുട്ട് ID-കൾ ഡീകോഡ് ചെയ്യാം: + +```python +tokenizer.convert_ids_to_tokens(inputs.input_ids) +``` + +```python out +['▁I', '▁', 'loved', '▁reading', '▁the', '▁Hung', 'er', '▁Games', ''] +``` + +പ്രത്യേക യൂണികോഡ് അക്ഷരമായ `▁`-ഉം എൻഡ്-ഓഫ്-സീക്വൻസ് ടോക്കണായ ``-ഉം സൂചിപ്പിക്കുന്നത്, [അധ്യായം 6](/course/chapter6)-ൽ ചർച്ച ചെയ്ത Unigram സെഗ്‌മെന്റേഷൻ അൽഗോരിതം അടിസ്ഥാനമാക്കിയുള്ള SentencePiece ടോക്കണൈസറാണ് നമ്മൾ കൈകാര്യം ചെയ്യുന്നത് എന്നാണ്. ആക്‌സന്റുകൾ, ചിഹ്നങ്ങൾ (punctuation), ജാപ്പനീസ് പോലുള്ള പല ഭാഷകളിലും വൈറ്റ്‌സ്‌പേസ് അക്ഷരങ്ങൾ ഇല്ല എന്ന വസ്തുത എന്നിവയെക്കുറിച്ച് ആശങ്കപ്പെടാതെ (agnostic) പ്രവർത്തിക്കാൻ SentencePiece-നെ അനുവദിക്കുന്നതിനാൽ, ബഹുഭാഷാ കോർപ്പസുകൾക്ക് Unigram പ്രത്യേകിച്ചും ഉപകാരപ്രദമാണ്. + +നമ്മുടെ കോർപ്പസ് ടോക്കണൈസ് ചെയ്യാൻ, സമ്മറൈസേഷനുമായി ബന്ധപ്പെട്ട ഒരു സൂക്ഷ്മമായ കാര്യം നമ്മൾ കൈകാര്യം ചെയ്യേണ്ടതുണ്ട്: നമ്മുടെ ലേബലുകളും ടെക്‌സ്‌റ്റായതിനാൽ, അവ മോഡലിന്റെ പരമാവധി കോൺടെക്‌സ്‌റ്റ് വലുപ്പം കവിയാൻ സാധ്യതയുണ്ട്. അതായത്, അമിതമായി നീണ്ട ഇൻപുട്ടുകൾ നമ്മുടെ മോഡലിലേക്ക് നൽകാതിരിക്കാൻ, റിവ്യൂകളിലും അവയുടെ തലക്കെട്ടുകളിലും നമ്മൾ ട്രങ്കേഷൻ (truncation) പ്രയോഗിക്കേണ്ടതുണ്ട്. ഇൻപുട്ടുകൾക്ക് സമാന്തരമായി ലേബലുകൾ ടോക്കണൈസ് ചെയ്യാൻ അനുവദിക്കുന്ന `text_target` എന്ന ഉപകാരപ്രദമായ ഒരു ആർഗ്യുമെന്റ് 🤗 Transformers-ലെ ടോക്കണൈസറുകൾ നൽകുന്നു. mT5-നായി ഇൻപുട്ടുകളും ടാർഗെറ്റുകളും എങ്ങനെ പ്രോസസ്സ് ചെയ്യുന്നു എന്നതിന്റെ ഒരു ഉദാഹരണം ഇതാ: + +```python +max_input_length = 512 +max_target_length = 30 + + +def preprocess_function(examples): + model_inputs = tokenizer( + examples["review_body"], + max_length=max_input_length, + truncation=True, + ) + labels = tokenizer( + examples["review_title"], max_length=max_target_length, truncation=True + ) + model_inputs["labels"] = labels["input_ids"] + return model_inputs +``` + +എന്താണ് സംഭവിക്കുന്നതെന്ന് മനസ്സിലാക്കാൻ ഈ കോഡിലൂടെ ഒന്ന് കടന്നുപോകാം. നമ്മൾ ആദ്യം ചെയ്തത് `max_input_length`, `max_target_length` എന്നിവയ്ക്കുള്ള മൂല്യങ്ങൾ നിർവചിക്കുകയാണ്; നമ്മുടെ റിവ്യൂകൾക്കും തലക്കെട്ടുകൾക്കും എത്ര ദൈർഘ്യമുണ്ടാകാം എന്നതിന്റെ ഉയർന്ന പരിധികൾ ഇവ നിശ്ചയിക്കുന്നു. റിവ്യൂ ബോഡി സാധാരണയായി തലക്കെട്ടിനെക്കാൾ വളരെ വലുതായതിനാൽ, ഈ മൂല്യങ്ങൾ അതനുസരിച്ച് നമ്മൾ ക്രമീകരിച്ചിട്ടുണ്ട്. + +`preprocess_function()` ഉപയോഗിച്ച്, ഈ കോഴ്‌സിലുടനീളം നമ്മൾ വ്യാപകമായി ഉപയോഗിച്ചിട്ടുള്ള ഉപകാരപ്രദമായ `Dataset.map()` ഫംഗ്‌ഷൻ വഴി മുഴുവൻ കോർപ്പസും ടോക്കണൈസ് ചെയ്യുന്നത് പിന്നെ ലളിതമായ ഒരു കാര്യമാണ്: + +```python +tokenized_datasets = books_dataset.map(preprocess_function, batched=True) +``` + +ഇപ്പോൾ കോർപ്പസ് പ്രീപ്രോസസ്സ് ചെയ്തുകഴിഞ്ഞു, സമ്മറൈസേഷനായി സാധാരണയായി ഉപയോഗിക്കുന്ന ചില മെട്രിക്കുകൾ നമുക്ക് നോക്കാം. നമ്മൾ കാണാൻ പോകുന്നതുപോലെ, മെഷീൻ ജനറേറ്റ് ചെയ്ത ടെക്‌സ്‌റ്റിന്റെ ഗുണനിലവാരം അളക്കുന്ന കാര്യത്തിൽ എല്ലാം പരിഹരിക്കുന്ന ഒരൊറ്റ മാർഗമില്ല. + +> [!TIP] +> 💡 മുകളിലെ നമ്മുടെ `Dataset.map()` ഫംഗ്‌ഷനിൽ `batched=True` ഉപയോഗിച്ചത് നിങ്ങൾ ശ്രദ്ധിച്ചിരിക്കാം. ഇത് ഉദാഹരണങ്ങളെ 1,000 വീതമുള്ള ബാച്ചുകളായി (ഡിഫോൾട്ട്) എൻകോഡ് ചെയ്യുകയും, 🤗 Transformers-ലെ ഫാസ്‌റ്റ് ടോക്കണൈസറുകളുടെ മൾട്ടിത്രെഡിംഗ് കഴിവുകൾ പ്രയോജനപ്പെടുത്താൻ നിങ്ങളെ അനുവദിക്കുകയും ചെയ്യുന്നു. സാധ്യമാകുന്നിടത്തെല്ലാം, നിങ്ങളുടെ പ്രീപ്രോസസ്സിംഗിൽ നിന്ന് പരമാവധി പ്രയോജനം നേടാൻ `batched=True` ഉപയോഗിക്കാൻ ശ്രമിക്കുക! + + +## ടെക്‌സ്‌റ്റ് സമ്മറൈസേഷനുള്ള മെട്രിക്കുകൾ[[metrics-for-text-summarization]] + + + +ഈ കോഴ്‌സിൽ നമ്മൾ കണ്ട മറ്റ് മിക്ക ടാസ്‌കുകളുമായി താരതമ്യപ്പെടുത്തുമ്പോൾ, സമ്മറൈസേഷൻ അല്ലെങ്കിൽ ട്രാൻസ്‌ലേഷൻ പോലുള്ള ടെക്‌സ്‌റ്റ് ജനറേഷൻ ടാസ്‌കുകളുടെ പ്രകടനം അളക്കുന്നത് അത്ര നേരായ കാര്യമല്ല. ഉദാഹരണത്തിന്, "I loved reading the Hunger Games" പോലുള്ള ഒരു റിവ്യൂ തന്നാൽ, "I loved the Hunger Games" അല്ലെങ്കിൽ "Hunger Games is a great read" എന്നിങ്ങനെ സാധുവായ ഒന്നിലധികം സംഗ്രഹങ്ങളുണ്ട്. ജനറേറ്റ് ചെയ്ത സംഗ്രഹത്തിനും ലേബലിനും ഇടയിൽ ഏതെങ്കിലും തരത്തിലുള്ള കൃത്യമായ പൊരുത്തം (exact match) പ്രയോഗിക്കുന്നത് ഒരു നല്ല പരിഹാരമല്ലെന്ന് വ്യക്തമാണ് — നമുക്കെല്ലാം നമ്മുടേതായ എഴുത്തുശൈലി ഉള്ളതിനാൽ, അത്തരമൊരു മെട്രിക്കിൽ മനുഷ്യർ പോലും മോശമായി പ്രവർത്തിക്കും. + +സമ്മറൈസേഷന് ഏറ്റവും സാധാരണയായി ഉപയോഗിക്കുന്ന മെട്രിക്കുകളിൽ ഒന്നാണ് [ROUGE സ്കോർ](https://en.wikipedia.org/wiki/ROUGE_(metric)) (Recall-Oriented Understudy for Gisting Evaluation എന്നതിന്റെ ചുരുക്കം). ജനറേറ്റ് ചെയ്ത ഒരു സംഗ്രഹത്തെ, സാധാരണയായി മനുഷ്യർ തയ്യാറാക്കിയ ഒരു കൂട്ടം റഫറൻസ് സംഗ്രഹങ്ങളുമായി താരതമ്യം ചെയ്യുക എന്നതാണ് ഈ മെട്രിക്കിന് പിന്നിലെ അടിസ്ഥാന ആശയം. ഇത് കൂടുതൽ കൃത്യമായി മനസ്സിലാക്കാൻ, താഴെയുള്ള രണ്ട് സംഗ്രഹങ്ങൾ താരതമ്യം ചെയ്യണമെന്ന് കരുതുക: + +```python +generated_summary = "I absolutely loved reading the Hunger Games" +reference_summary = "I loved reading the Hunger Games" +``` + +അവയെ താരതമ്യം ചെയ്യാനുള്ള ഒരു മാർഗം പൊതുവായുള്ള (overlapping) വാക്കുകളുടെ എണ്ണം കണക്കാക്കുകയാണ്, ഈ സാഹചര്യത്തിൽ അത് 6 ആയിരിക്കും. എന്നാൽ ഇത് കുറച്ച് പരുക്കനായ ഒരു രീതിയാണ്, അതിനാൽ പകരം ഈ പൊരുത്തത്തിനുള്ള _പ്രിസിഷൻ_ (precision), _റീകോൾ_ (recall) സ്കോറുകൾ കണക്കാക്കുന്നതിനെ അടിസ്ഥാനമാക്കിയാണ് ROUGE പ്രവർത്തിക്കുന്നത്. + +> [!TIP] +> 🙋 പ്രിസിഷൻ, റീകോൾ എന്നിവയെക്കുറിച്ച് നിങ്ങൾ ആദ്യമായാണ് കേൾക്കുന്നതെങ്കിൽ വിഷമിക്കേണ്ട — എല്ലാം വ്യക്തമാക്കാൻ ചില വ്യക്തമായ ഉദാഹരണങ്ങളിലൂടെ നമ്മൾ ഒരുമിച്ച് കടന്നുപോകും. ഈ മെട്രിക്കുകൾ സാധാരണയായി ക്ലാസിഫിക്കേഷൻ ടാസ്‌കുകളിലാണ് കാണുന്നത്, അതിനാൽ ആ സന്ദർഭത്തിൽ പ്രിസിഷനും റീകോളും എങ്ങനെ നിർവചിക്കപ്പെടുന്നു എന്ന് മനസ്സിലാക്കണമെങ്കിൽ, `scikit-learn` [ഗൈഡുകൾ](https://scikit-learn.org/stable/auto_examples/model_selection/plot_precision_recall.html) പരിശോധിക്കാൻ ഞങ്ങൾ ശുപാർശ ചെയ്യുന്നു. + +ROUGE-ൽ, റഫറൻസ് സംഗ്രഹത്തിന്റെ എത്ര ഭാഗം ജനറേറ്റ് ചെയ്ത സംഗ്രഹത്തിൽ ഉൾക്കൊള്ളുന്നു എന്നാണ് റീകോൾ അളക്കുന്നത്. നമ്മൾ വാക്കുകൾ മാത്രം താരതമ്യം ചെയ്യുകയാണെങ്കിൽ, താഴെയുള്ള സൂത്രവാക്യം അനുസരിച്ച് റീകോൾ കണക്കാക്കാം: + +$$ \mathrm{Recall} = \frac{\mathrm{Number\,of\,overlapping\, words}}{\mathrm{Total\, number\, of\, words\, in\, reference\, summary}} $$ + +മുകളിലെ നമ്മുടെ ലളിതമായ ഉദാഹരണത്തിന്, ഈ സൂത്രവാക്യം 6/6 = 1 എന്ന പൂർണ്ണമായ റീകോൾ നൽകുന്നു; അതായത്, റഫറൻസ് സംഗ്രഹത്തിലെ എല്ലാ വാക്കുകളും മോഡൽ ഉണ്ടാക്കിയിട്ടുണ്ട്. ഇത് മികച്ചതായി തോന്നാം, എന്നാൽ നമ്മുടെ ജനറേറ്റ് ചെയ്ത സംഗ്രഹം "I really really loved reading the Hunger Games all night" എന്നായിരുന്നെങ്കിൽ എന്ന് സങ്കൽപ്പിക്കുക. ഇതിനും പൂർണ്ണമായ റീകോൾ ഉണ്ടാകും, എന്നാൽ അത് വാചാലമായതിനാൽ (verbose) മോശമായ ഒരു സംഗ്രഹമാണെന്ന് വാദിക്കാം. ഇത്തരം സാഹചര്യങ്ങൾ കൈകാര്യം ചെയ്യാൻ നമ്മൾ പ്രിസിഷനും കണക്കാക്കുന്നു; ROUGE-ന്റെ സന്ദർഭത്തിൽ, ജനറേറ്റ് ചെയ്ത സംഗ്രഹത്തിന്റെ എത്ര ഭാഗം പ്രസക്തമായിരുന്നു എന്നാണ് ഇത് അളക്കുന്നത്: + +$$ \mathrm{Precision} = \frac{\mathrm{Number\,of\,overlapping\, words}}{\mathrm{Total\, number\, of\, words\, in\, generated\, summary}} $$ + +ഇത് നമ്മുടെ വാചാലമായ സംഗ്രഹത്തിൽ പ്രയോഗിക്കുമ്പോൾ 6/10 = 0.6 എന്ന പ്രിസിഷൻ ലഭിക്കുന്നു; നമ്മുടെ ചെറിയ സംഗ്രഹത്തിന് ലഭിച്ച 6/7 = 0.86 എന്ന പ്രിസിഷനെക്കാൾ ഇത് വളരെ മോശമാണ്. പ്രായോഗികമായി, സാധാരണയായി പ്രിസിഷനും റീകോളും രണ്ടും കണക്കാക്കുകയും, തുടർന്ന് F1-സ്കോർ (പ്രിസിഷന്റെയും റീകോളിന്റെയും ഹാർമോണിക് മീൻ) റിപ്പോർട്ട് ചെയ്യുകയും ചെയ്യുന്നു. `rouge_score` പാക്കേജ് ആദ്യം ഇൻസ്‌റ്റാൾ ചെയ്തുകൊണ്ട് 🤗 Datasets-ൽ നമുക്ക് ഇത് എളുപ്പത്തിൽ ചെയ്യാം: + +```py +!pip install rouge_score +``` + +തുടർന്ന് ROUGE മെട്രിക് താഴെ കാണുന്നതുപോലെ ലോഡ് ചെയ്യുക: + +```python +import evaluate + +rouge_score = evaluate.load("rouge") +``` + +തുടർന്ന് എല്ലാ മെട്രിക്കുകളും ഒറ്റയടിക്ക് കണക്കാക്കാൻ `rouge_score.compute()` ഫംഗ്‌ഷൻ നമുക്ക് ഉപയോഗിക്കാം: + +```python +scores = rouge_score.compute( + predictions=[generated_summary], references=[reference_summary] +) +scores +``` + +```python out +{'rouge1': AggregateScore(low=Score(precision=0.86, recall=1.0, fmeasure=0.92), mid=Score(precision=0.86, recall=1.0, fmeasure=0.92), high=Score(precision=0.86, recall=1.0, fmeasure=0.92)), + 'rouge2': AggregateScore(low=Score(precision=0.67, recall=0.8, fmeasure=0.73), mid=Score(precision=0.67, recall=0.8, fmeasure=0.73), high=Score(precision=0.67, recall=0.8, fmeasure=0.73)), + 'rougeL': AggregateScore(low=Score(precision=0.86, recall=1.0, fmeasure=0.92), mid=Score(precision=0.86, recall=1.0, fmeasure=0.92), high=Score(precision=0.86, recall=1.0, fmeasure=0.92)), + 'rougeLsum': AggregateScore(low=Score(precision=0.86, recall=1.0, fmeasure=0.92), mid=Score(precision=0.86, recall=1.0, fmeasure=0.92), high=Score(precision=0.86, recall=1.0, fmeasure=0.92))} +``` + +ഹോ, ആ ഔട്ട്‌പുട്ടിൽ ഒരുപാട് വിവരങ്ങളുണ്ട് — ഇതെല്ലാം എന്താണ് അർത്ഥമാക്കുന്നത്? ആദ്യമായി, 🤗 Datasets യഥാർത്ഥത്തിൽ പ്രിസിഷൻ, റീകോൾ, F1-സ്കോർ എന്നിവയ്ക്കുള്ള കോൺഫിഡൻസ് ഇന്റർവലുകൾ (confidence intervals) കണക്കാക്കുന്നു; ഇവിടെ നിങ്ങൾ കാണുന്ന `low`, `mid`, `high` ആട്രിബ്യൂട്ടുകൾ അവയാണ്. കൂടാതെ, ജനറേറ്റ് ചെയ്ത സംഗ്രഹങ്ങളും റഫറൻസ് സംഗ്രഹങ്ങളും താരതമ്യം ചെയ്യുമ്പോൾ വ്യത്യസ്ത തരം ടെക്‌സ്‌റ്റ് ഗ്രാനുലാരിറ്റി അടിസ്ഥാനമാക്കിയുള്ള വിവിധതരം ROUGE സ്കോറുകളും 🤗 Datasets കണക്കാക്കുന്നു. `rouge1` വേരിയന്റ് യൂണിഗ്രാമുകളുടെ പൊരുത്തമാണ് — വാക്കുകളുടെ പൊരുത്തം എന്നതിന്റെ ഒരു ആലങ്കാരികമായ പേര് മാത്രമാണിത്, മുകളിൽ നമ്മൾ ചർച്ച ചെയ്ത അതേ മെട്രിക്ക് തന്നെയാണിത്. ഇത് സ്ഥിരീകരിക്കാൻ, നമ്മുടെ സ്കോറുകളുടെ `mid` മൂല്യം പുറത്തെടുക്കാം: + +```python +scores["rouge1"].mid +``` + +```python out +Score(precision=0.86, recall=1.0, fmeasure=0.92) +``` + +കൊള്ളാം, പ്രിസിഷൻ, റീകോൾ സംഖ്യകൾ പൊരുത്തപ്പെടുന്നു! ഇനി മറ്റ് ROUGE സ്കോറുകളുടെ കാര്യമോ? `rouge2` ബൈഗ്രാമുകൾക്കിടയിലുള്ള പൊരുത്തം അളക്കുന്നു (വാക്കുകളുടെ ജോഡികളുടെ പൊരുത്തം എന്ന് കരുതുക), അതേസമയം `rougeL`-ഉം `rougeLsum`-ഉം ജനറേറ്റ് ചെയ്ത സംഗ്രഹങ്ങളിലെയും റഫറൻസ് സംഗ്രഹങ്ങളിലെയും ഏറ്റവും നീണ്ട പൊതു സബ്‌സ്‌ട്രിംഗുകൾ (longest common substrings) തിരഞ്ഞുകൊണ്ട്, പൊരുത്തപ്പെടുന്ന വാക്കുകളുടെ ഏറ്റവും നീണ്ട ശ്രേണികൾ അളക്കുന്നു. `rougeLsum`-ലെ "sum" സൂചിപ്പിക്കുന്നത്, ഈ മെട്രിക് ഒരു സംഗ്രഹത്തിന്റെ മുഴുവൻ ഭാഗത്തും കണക്കാക്കുന്നു എന്നാണ്; അതേസമയം `rougeL` ഓരോ വാക്യത്തിന്റെയും ശരാശരിയായാണ് കണക്കാക്കുന്നത്. + +> [!TIP] +> ✏️ **സ്വയം പരീക്ഷിക്കുക!** ജനറേറ്റ് ചെയ്ത സംഗ്രഹത്തിന്റെയും റഫറൻസ് സംഗ്രഹത്തിന്റെയും നിങ്ങളുടെ സ്വന്തം ഉദാഹരണം സൃഷ്ടിച്ച്, ലഭിക്കുന്ന ROUGE സ്കോറുകൾ പ്രിസിഷനും റീകോളിനുമുള്ള സൂത്രവാക്യങ്ങൾ അടിസ്ഥാനമാക്കി കൈകൊണ്ട് കണക്കാക്കിയതുമായി യോജിക്കുന്നുണ്ടോ എന്ന് നോക്കുക. ബോണസ് പോയിന്റുകൾക്കായി, ടെക്‌സ്‌റ്റിനെ ബൈഗ്രാമുകളായി വിഭജിച്ച് `rouge2` മെട്രിക്കിനുള്ള പ്രിസിഷനും റീകോളും താരതമ്യം ചെയ്യുക. + +നമ്മുടെ മോഡലിന്റെ പ്രകടനം ട്രാക്ക് ചെയ്യാൻ ഈ ROUGE സ്കോറുകൾ നമ്മൾ ഉപയോഗിക്കും, എന്നാൽ അതിനു മുമ്പ്, ഓരോ നല്ല NLP പ്രാക്ടീഷണറും ചെയ്യേണ്ട ഒരു കാര്യം ചെയ്യാം: ശക്തവും എന്നാൽ ലളിതവുമായ ഒരു ബേസ്‌ലൈൻ (baseline) സൃഷ്ടിക്കുക! + +### ശക്തമായ ഒരു ബേസ്‌ലൈൻ സൃഷ്ടിക്കുന്നു[[creating-a-strong-baseline]] + +ടെക്‌സ്‌റ്റ് സമ്മറൈസേഷനുള്ള ഒരു സാധാരണ ബേസ്‌ലൈൻ, ഒരു ലേഖനത്തിന്റെ ആദ്യത്തെ മൂന്ന് വാക്യങ്ങൾ എടുക്കുക എന്നതാണ്; ഇതിനെ പലപ്പോഴും _lead-3_ ബേസ്‌ലൈൻ എന്ന് വിളിക്കുന്നു. വാക്യങ്ങളുടെ അതിരുകൾ കണ്ടെത്താൻ പൂർണ്ണവിരാമങ്ങൾ (full stops) നമുക്ക് ഉപയോഗിക്കാമായിരുന്നു, എന്നാൽ "U.S." അല്ലെങ്കിൽ "U.N." പോലുള്ള ചുരുക്കെഴുത്തുകളിൽ ഇത് പരാജയപ്പെടും — അതിനാൽ പകരം, ഇത്തരം സാഹചര്യങ്ങൾ കൈകാര്യം ചെയ്യാൻ മികച്ച ഒരു അൽഗോരിതം ഉൾക്കൊള്ളുന്ന `nltk` ലൈബ്രറി നമ്മൾ ഉപയോഗിക്കും. `pip` ഉപയോഗിച്ച് താഴെ കാണുന്നതുപോലെ നിങ്ങൾക്ക് ഈ പാക്കേജ് ഇൻസ്‌റ്റാൾ ചെയ്യാം: + +```python +!pip install nltk +``` + +തുടർന്ന് ചിഹ്നന നിയമങ്ങൾ (punctuation rules) ഡൗൺലോഡ് ചെയ്യുക: + +```python +import nltk + +nltk.download("punkt") +``` + +അടുത്തതായി, `nltk`-ൽ നിന്ന് സെന്റൻസ് ടോക്കണൈസർ ഇംപോർട്ട് ചെയ്ത്, ഒരു റിവ്യൂവിലെ ആദ്യത്തെ മൂന്ന് വാക്യങ്ങൾ വേർതിരിച്ചെടുക്കുന്ന ഒരു ലളിതമായ ഫംഗ്‌ഷൻ നമ്മൾ നിർമ്മിക്കുന്നു. ഓരോ സംഗ്രഹത്തെയും ഒരു ന്യൂലൈൻ ഉപയോഗിച്ച് വേർതിരിക്കുക എന്നതാണ് ടെക്‌സ്‌റ്റ് സമ്മറൈസേഷനിലെ കീഴ്‌വഴക്കം, അതിനാൽ അതും ഉൾപ്പെടുത്തി ഒരു ട്രെയിനിംഗ് ഉദാഹരണത്തിൽ ഇത് പരീക്ഷിക്കാം: + +```python +from nltk.tokenize import sent_tokenize + + +def three_sentence_summary(text): + return "\n".join(sent_tokenize(text)[:3]) + + +print(three_sentence_summary(books_dataset["train"][1]["review_body"])) +``` + +```python out +'I grew up reading Koontz, and years ago, I stopped,convinced i had "outgrown" him.' +'Still,when a friend was looking for something suspenseful too read, I suggested Koontz.' +'She found Strangers.' +``` + +ഇത് പ്രവർത്തിക്കുന്നതായി തോന്നുന്നു, അതിനാൽ ഒരു ഡേറ്റാസെറ്റിൽ നിന്ന് ഈ "സംഗ്രഹങ്ങൾ" വേർതിരിച്ചെടുത്ത് ബേസ്‌ലൈനിനുള്ള ROUGE സ്കോറുകൾ കണക്കാക്കുന്ന ഒരു ഫംഗ്‌ഷൻ ഇപ്പോൾ നമുക്ക് ഇംപ്ലിമെന്റ് ചെയ്യാം: + +```python +def evaluate_baseline(dataset, metric): + summaries = [three_sentence_summary(text) for text in dataset["review_body"]] + return metric.compute(predictions=summaries, references=dataset["review_title"]) +``` + +തുടർന്ന് വാലിഡേഷൻ സെറ്റിലെ ROUGE സ്കോറുകൾ കണക്കാക്കാൻ ഈ ഫംഗ്‌ഷൻ ഉപയോഗിക്കുകയും, Pandas ഉപയോഗിച്ച് അവയെ കുറച്ച് ഭംഗിയാക്കുകയും ചെയ്യാം: + +```python +import pandas as pd + +score = evaluate_baseline(books_dataset["validation"], rouge_score) +rouge_names = ["rouge1", "rouge2", "rougeL", "rougeLsum"] +rouge_dict = dict((rn, round(score[rn].mid.fmeasure * 100, 2)) for rn in rouge_names) +rouge_dict +``` + +```python out +{'rouge1': 16.74, 'rouge2': 8.83, 'rougeL': 15.6, 'rougeLsum': 15.96} +``` + +`rouge2` സ്കോർ മറ്റുള്ളവയെക്കാൾ വളരെ കുറവാണെന്ന് നമുക്ക് കാണാം; റിവ്യൂ തലക്കെട്ടുകൾ സാധാരണയായി സംക്ഷിപ്തമായതിനാൽ lead-3 ബേസ്‌ലൈൻ വളരെ വാചാലമാണ് എന്ന വസ്തുതയാണ് ഇത് പ്രതിഫലിപ്പിക്കുന്നത്. ഇപ്പോൾ പ്രവർത്തിക്കാൻ ഒരു നല്ല ബേസ്‌ലൈൻ നമുക്കുള്ളതിനാൽ, mT5 ഫൈൻ-ട്യൂൻ ചെയ്യുന്നതിലേക്ക് നമ്മുടെ ശ്രദ്ധ തിരിക്കാം! + +{#if fw === 'pt'} + +## `Trainer` API ഉപയോഗിച്ച് mT5 ഫൈൻ-ട്യൂൻ ചെയ്യുന്നു[[fine-tuning-mt5-with-the-trainer-api]] + +സമ്മറൈസേഷനായി ഒരു മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യുന്നത് ഈ അധ്യായത്തിൽ നമ്മൾ കണ്ട മറ്റ് ടാസ്‌കുകളോട് വളരെ സാമ്യമുള്ളതാണ്. നമ്മൾ ആദ്യം ചെയ്യേണ്ടത് `mt5-small` ചെക്ക്‌പോയിന്റിൽ നിന്ന് പ്രീട്രെയിൻഡ് മോഡൽ ലോഡ് ചെയ്യുകയാണ്. സമ്മറൈസേഷൻ ഒരു സീക്വൻസ്-ടു-സീക്വൻസ് ടാസ്‌കായതിനാൽ, `AutoModelForSeq2SeqLM` ക്ലാസ് ഉപയോഗിച്ച് മോഡൽ ലോഡ് ചെയ്യാം; ഇത് വെയ്‌റ്റുകൾ സ്വയമേവ ഡൗൺലോഡ് ചെയ്ത് കാഷ് ചെയ്യും: + +```python +from transformers import AutoModelForSeq2SeqLM + +model = AutoModelForSeq2SeqLM.from_pretrained(model_checkpoint) +``` + +{:else} + +## Keras ഉപയോഗിച്ച് mT5 ഫൈൻ-ട്യൂൻ ചെയ്യുന്നു[[fine-tuning-mt5-with-keras]] + +സമ്മറൈസേഷനായി ഒരു മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യുന്നത് ഈ അധ്യായത്തിൽ നമ്മൾ കണ്ട മറ്റ് ടാസ്‌കുകളോട് വളരെ സാമ്യമുള്ളതാണ്. നമ്മൾ ആദ്യം ചെയ്യേണ്ടത് `mt5-small` ചെക്ക്‌പോയിന്റിൽ നിന്ന് പ്രീട്രെയിൻഡ് മോഡൽ ലോഡ് ചെയ്യുകയാണ്. സമ്മറൈസേഷൻ ഒരു സീക്വൻസ്-ടു-സീക്വൻസ് ടാസ്‌കായതിനാൽ, `TFAutoModelForSeq2SeqLM` ക്ലാസ് ഉപയോഗിച്ച് മോഡൽ ലോഡ് ചെയ്യാം; ഇത് വെയ്‌റ്റുകൾ സ്വയമേവ ഡൗൺലോഡ് ചെയ്ത് കാഷ് ചെയ്യും: + +```python +from transformers import TFAutoModelForSeq2SeqLM + +model = TFAutoModelForSeq2SeqLM.from_pretrained(model_checkpoint) +``` + +{/if} + +> [!TIP] +> 💡 ഒരു ഡൗൺസ്ട്രീം ടാസ്‌കിൽ മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യുന്നതിനെക്കുറിച്ചുള്ള മുന്നറിയിപ്പുകളൊന്നും എന്തുകൊണ്ട് കാണുന്നില്ല എന്ന് നിങ്ങൾ ആലോചിക്കുന്നുണ്ടെങ്കിൽ, അതിന് കാരണം സീക്വൻസ്-ടു-സീക്വൻസ് ടാസ്‌കുകൾക്ക് നെറ്റ്‌വർക്കിന്റെ എല്ലാ വെയ്‌റ്റുകളും നമ്മൾ നിലനിർത്തുന്നു എന്നതാണ്. [അധ്യായം 3](/course/chapter3)-ലെ നമ്മുടെ ടെക്‌സ്‌റ്റ് ക്ലാസിഫിക്കേഷൻ മോഡലുമായി ഇത് താരതമ്യം ചെയ്യുക; അവിടെ പ്രീട്രെയിൻഡ് മോഡലിന്റെ ഹെഡ്, ക്രമരഹിതമായി ഇനിഷ്യലൈസ് ചെയ്ത ഒരു നെറ്റ്‌വർക്ക് കൊണ്ട് മാറ്റിസ്ഥാപിക്കപ്പെട്ടിരുന്നു. + +അടുത്തതായി നമ്മൾ ചെയ്യേണ്ടത് Hugging Face Hub-ൽ ലോഗിൻ ചെയ്യുകയാണ്. നിങ്ങൾ ഈ കോഡ് ഒരു നോട്ട്‌ബുക്കിൽ റൺ ചെയ്യുന്നുണ്ടെങ്കിൽ, താഴെയുള്ള യൂട്ടിലിറ്റി ഫംഗ്‌ഷൻ ഉപയോഗിച്ച് അത് ചെയ്യാം: + +```python +from huggingface_hub import notebook_login + +notebook_login() +``` + +ഇത് നിങ്ങളുടെ ക്രെഡൻഷ്യലുകൾ നൽകാവുന്ന ഒരു വിജറ്റ് പ്രദർശിപ്പിക്കും. അല്ലെങ്കിൽ, നിങ്ങളുടെ ടെർമിനലിൽ ഈ കമാൻഡ് റൺ ചെയ്ത് അവിടെ ലോഗിൻ ചെയ്യാം: + +``` +huggingface-cli login +``` + +{#if fw === 'pt'} + +ട്രെയിനിംഗ് സമയത്ത് ROUGE സ്കോറുകൾ കണക്കാക്കാൻ നമ്മൾ സംഗ്രഹങ്ങൾ ജനറേറ്റ് ചെയ്യേണ്ടതുണ്ട്. ഭാഗ്യവശാൽ, ഇത് നമുക്കായി സ്വയമേവ ചെയ്യാൻ കഴിയുന്ന പ്രത്യേക `Seq2SeqTrainingArguments`, `Seq2SeqTrainer` ക്ലാസുകൾ 🤗 Transformers നൽകുന്നു! ഇത് എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് കാണാൻ, നമ്മുടെ പരീക്ഷണങ്ങൾക്കുള്ള ഹൈപ്പർപാരാമീറ്ററുകളും മറ്റ് ആർഗ്യുമെന്റുകളും ആദ്യം നിർവചിക്കാം: + +```python +from transformers import Seq2SeqTrainingArguments + +batch_size = 8 +num_train_epochs = 8 +# Show the training loss with every epoch +logging_steps = len(tokenized_datasets["train"]) // batch_size +model_name = model_checkpoint.split("/")[-1] + +args = Seq2SeqTrainingArguments( + output_dir=f"{model_name}-finetuned-amazon-en-es", + evaluation_strategy="epoch", + learning_rate=5.6e-5, + per_device_train_batch_size=batch_size, + per_device_eval_batch_size=batch_size, + weight_decay=0.01, + save_total_limit=3, + num_train_epochs=num_train_epochs, + predict_with_generate=True, + logging_steps=logging_steps, + push_to_hub=True, +) +``` + +ഇവിടെ, ഓരോ എപ്പോക്കിനും ROUGE സ്കോറുകൾ കണക്കാക്കാൻ കഴിയുന്നതിനായി ഇവാല്യുവേഷൻ സമയത്ത് സംഗ്രഹങ്ങൾ ജനറേറ്റ് ചെയ്യണം എന്ന് സൂചിപ്പിക്കാൻ `predict_with_generate` ആർഗ്യുമെന്റ് സെറ്റ് ചെയ്തിരിക്കുന്നു. [അധ്യായം 1](/course/chapter1)-ൽ ചർച്ച ചെയ്തതുപോലെ, ഡീകോഡർ ടോക്കണുകൾ ഒന്നൊന്നായി പ്രവചിച്ചുകൊണ്ടാണ് ഇൻഫറൻസ് നടത്തുന്നത്, മോഡലിന്റെ `generate()` മെത്തേഡിലാണ് ഇത് ഇംപ്ലിമെന്റ് ചെയ്തിരിക്കുന്നത്. `predict_with_generate=True` സെറ്റ് ചെയ്യുന്നത്, ഇവാല്യുവേഷന് ആ മെത്തേഡ് ഉപയോഗിക്കാൻ `Seq2SeqTrainer`-നോട് പറയുന്നു. ലേണിംഗ് റേറ്റ്, എപ്പോക്കുകളുടെ എണ്ണം, വെയ്‌റ്റ് ഡികേ തുടങ്ങിയ ചില ഡിഫോൾട്ട് ഹൈപ്പർപാരാമീറ്ററുകളും നമ്മൾ ക്രമീകരിച്ചിട്ടുണ്ട്, കൂടാതെ ട്രെയിനിംഗ് സമയത്ത് പരമാവധി 3 ചെക്ക്‌പോയിന്റുകൾ മാത്രം സേവ് ചെയ്യാൻ `save_total_limit` ഓപ്‌ഷൻ സെറ്റ് ചെയ്തിട്ടുണ്ട് — mT5-ന്റെ "small" പതിപ്പ് പോലും ഏകദേശം ഒരു GB ഹാർഡ് ഡ്രൈവ് സ്ഥലം ഉപയോഗിക്കുന്നു എന്നതാണ് ഇതിന് കാരണം, സേവ് ചെയ്യുന്ന കോപ്പികളുടെ എണ്ണം പരിമിതപ്പെടുത്തി കുറച്ച് സ്ഥലം നമുക്ക് ലാഭിക്കാം. + +`push_to_hub=True` ആർഗ്യുമെന്റ് ട്രെയിനിംഗിന് ശേഷം മോഡൽ Hub-ലേക്ക് പുഷ് ചെയ്യാൻ നമ്മെ അനുവദിക്കും; `output_dir` നിർവചിക്കുന്ന സ്ഥാനത്ത്, നിങ്ങളുടെ യൂസർ പ്രൊഫൈലിന് കീഴിൽ റിപ്പോസിറ്ററി നിങ്ങൾക്ക് കാണാം. `hub_model_id` ആർഗ്യുമെന്റ് ഉപയോഗിച്ച് പുഷ് ചെയ്യേണ്ട റിപ്പോസിറ്ററിയുടെ പേര് നിങ്ങൾക്ക് വ്യക്തമാക്കാം എന്നത് ശ്രദ്ധിക്കുക (പ്രത്യേകിച്ച്, ഒരു ഓർഗനൈസേഷനിലേക്ക് പുഷ് ചെയ്യാൻ ഈ ആർഗ്യുമെന്റ് നിങ്ങൾ ഉപയോഗിക്കേണ്ടിവരും). ഉദാഹരണത്തിന്, [`huggingface-course` ഓർഗനൈസേഷനിലേക്ക്](https://huggingface.co/huggingface-course) മോഡൽ പുഷ് ചെയ്തപ്പോൾ, `Seq2SeqTrainingArguments`-ൽ `hub_model_id="huggingface-course/mt5-finetuned-amazon-en-es"` ഞങ്ങൾ ചേർത്തിരുന്നു. + +അടുത്തതായി നമ്മൾ ചെയ്യേണ്ടത്, ട്രെയിനിംഗ് സമയത്ത് നമ്മുടെ മോഡൽ ഇവാല്യുവേറ്റ് ചെയ്യാൻ കഴിയുന്നതിനായി ട്രെയിനറിന് ഒരു `compute_metrics()` ഫംഗ്‌ഷൻ നൽകുകയാണ്. സമ്മറൈസേഷന് ഇത് മോഡലിന്റെ പ്രവചനങ്ങളിൽ `rouge_score.compute()` വിളിക്കുന്നതിനെക്കാൾ കുറച്ചുകൂടി സങ്കീർണ്ണമാണ്, കാരണം ROUGE സ്കോറുകൾ കണക്കാക്കുന്നതിന് മുമ്പ് ഔട്ട്‌പുട്ടുകളും ലേബലുകളും ടെക്‌സ്‌റ്റിലേക്ക് _ഡീകോഡ്_ ചെയ്യേണ്ടതുണ്ട്. താഴെയുള്ള ഫംഗ്‌ഷൻ കൃത്യമായി അതാണ് ചെയ്യുന്നത്, കൂടാതെ സംഗ്രഹത്തിലെ വാക്യങ്ങളെ ന്യൂലൈനുകൾ ഉപയോഗിച്ച് വേർതിരിക്കാൻ `nltk`-ലെ `sent_tokenize()` ഫംഗ്‌ഷനും ഇത് ഉപയോഗിക്കുന്നു: + +```python +import numpy as np + + +def compute_metrics(eval_pred): + predictions, labels = eval_pred + # Decode generated summaries into text + decoded_preds = tokenizer.batch_decode(predictions, skip_special_tokens=True) + # Replace -100 in the labels as we can't decode them + labels = np.where(labels != -100, labels, tokenizer.pad_token_id) + # Decode reference summaries into text + decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True) + # ROUGE expects a newline after each sentence + decoded_preds = ["\n".join(sent_tokenize(pred.strip())) for pred in decoded_preds] + decoded_labels = ["\n".join(sent_tokenize(label.strip())) for label in decoded_labels] + # Compute ROUGE scores + result = rouge_score.compute( + predictions=decoded_preds, references=decoded_labels, use_stemmer=True + ) + # Extract the median scores + result = {key: value.mid.fmeasure * 100 for key, value in result.items()} + return {k: round(v, 4) for k, v in result.items()} +``` + +{/if} + +അടുത്തതായി, നമ്മുടെ സീക്വൻസ്-ടു-സീക്വൻസ് ടാസ്‌കിനായി ഒരു ഡേറ്റാ കൊളേറ്റർ (data collator) നിർവചിക്കേണ്ടതുണ്ട്. mT5 ഒരു എൻകോഡർ-ഡീകോഡർ Transformer മോഡലായതിനാൽ, നമ്മുടെ ബാച്ചുകൾ തയ്യാറാക്കുന്നതിലെ ഒരു സൂക്ഷ്മമായ കാര്യം, ഡീകോഡിംഗ് സമയത്ത് ലേബലുകളെ ഒരു സ്ഥാനം വലത്തോട്ട് ഷിഫ്‌റ്റ് ചെയ്യേണ്ടതുണ്ട് എന്നതാണ്. ഡീകോഡർ മുൻപുള്ള ഗ്രൗണ്ട് ട്രൂത്ത് ലേബലുകൾ മാത്രം കാണുകയും, ഇപ്പോഴത്തേതോ ഭാവിയിലേതോ കാണാതിരിക്കുകയും ചെയ്യുന്നു എന്ന് ഉറപ്പാക്കാൻ ഇത് ആവശ്യമാണ്; അല്ലാത്തപക്ഷം മോഡലിന് അവ മനഃപാഠമാക്കാൻ എളുപ്പമായിരിക്കും. [കോസൽ ലാംഗ്വേജ് മോഡലിംഗ്](/course/chapter7/6) പോലുള്ള ഒരു ടാസ്‌കിൽ ഇൻപുട്ടുകളിൽ മാസ്‌ക്ഡ് സെൽഫ്-അറ്റൻഷൻ പ്രയോഗിക്കുന്നതിന് സമാനമാണ് ഇത്. + +ഭാഗ്യവശാൽ, ഇൻപുട്ടുകളും ലേബലുകളും നമുക്കായി ഡൈനാമിക്കായി പാഡ് ചെയ്യുന്ന ഒരു `DataCollatorForSeq2Seq` കൊളേറ്റർ 🤗 Transformers നൽകുന്നു. ഈ കൊളേറ്റർ ഇൻസ്‌റ്റാൻഷിയേറ്റ് ചെയ്യാൻ, `tokenizer`-ഉം `model`-ഉം നൽകിയാൽ മാത്രം മതി: + +{#if fw === 'pt'} + +```python +from transformers import DataCollatorForSeq2Seq + +data_collator = DataCollatorForSeq2Seq(tokenizer, model=model) +``` + +{:else} + +```python +from transformers import DataCollatorForSeq2Seq + +data_collator = DataCollatorForSeq2Seq(tokenizer, model=model, return_tensors="tf") +``` + +{/if} + +ഉദാഹരണങ്ങളുടെ ഒരു ചെറിയ ബാച്ച് നൽകുമ്പോൾ ഈ കൊളേറ്റർ എന്താണ് ഉണ്ടാക്കുന്നതെന്ന് നോക്കാം. ആദ്യം, സ്‌ട്രിംഗുകൾ അടങ്ങിയ കോളങ്ങൾ നമ്മൾ നീക്കം ചെയ്യേണ്ടതുണ്ട്, കാരണം ഈ എലമെന്റുകൾ എങ്ങനെ പാഡ് ചെയ്യണമെന്ന് കൊളേറ്ററിന് അറിയില്ല: + +```python +tokenized_datasets = tokenized_datasets.remove_columns( + books_dataset["train"].column_names +) +``` + +കൊളേറ്റർ `dict`-കളുടെ ഒരു ലിസ്‌റ്റാണ് പ്രതീക്ഷിക്കുന്നത് — ഓരോ `dict`-ഉം ഡേറ്റാസെറ്റിലെ ഒരൊറ്റ ഉദാഹരണത്തെ പ്രതിനിധീകരിക്കുന്നു — അതിനാൽ ഡേറ്റാ കൊളേറ്ററിലേക്ക് നൽകുന്നതിന് മുമ്പ് ഡേറ്റയെ പ്രതീക്ഷിക്കുന്ന ഫോർമാറ്റിലേക്ക് നമ്മൾ മാറ്റിയെടുക്കേണ്ടതുമുണ്ട്: + +```python +features = [tokenized_datasets["train"][i] for i in range(2)] +data_collator(features) +``` + +```python out +{'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]), 'input_ids': tensor([[ 1494, 259, 8622, 390, 259, 262, 2316, 3435, 955, + 772, 281, 772, 1617, 263, 305, 14701, 260, 1385, + 3031, 259, 24146, 332, 1037, 259, 43906, 305, 336, + 260, 1, 0, 0, 0, 0, 0, 0], + [ 259, 27531, 13483, 259, 7505, 260, 112240, 15192, 305, + 53198, 276, 259, 74060, 263, 260, 459, 25640, 776, + 2119, 336, 259, 2220, 259, 18896, 288, 4906, 288, + 1037, 3931, 260, 7083, 101476, 1143, 260, 1]]), 'labels': tensor([[ 7483, 259, 2364, 15695, 1, -100], + [ 259, 27531, 13483, 259, 7505, 1]]), 'decoder_input_ids': tensor([[ 0, 7483, 259, 2364, 15695, 1], + [ 0, 259, 27531, 13483, 259, 7505]])} +``` + +ഇവിടെ ശ്രദ്ധിക്കേണ്ട പ്രധാന കാര്യം, ആദ്യത്തെ ഉദാഹരണം രണ്ടാമത്തേതിനെക്കാൾ നീളമുള്ളതാണ് എന്നതാണ്; അതിനാൽ രണ്ടാമത്തെ ഉദാഹരണത്തിന്റെ `input_ids`-ഉം `attention_mask`-ഉം വലതുവശത്ത് ഒരു `[PAD]` ടോക്കൺ (ഇതിന്റെ ID `0` ആണ്) ഉപയോഗിച്ച് പാഡ് ചെയ്തിരിക്കുന്നു. അതുപോലെ, പാഡിംഗ് ടോക്കണുകളെ ലോസ് ഫംഗ്‌ഷൻ അവഗണിക്കുന്നു എന്ന് ഉറപ്പാക്കാൻ, `labels` `-100`-കൾ ഉപയോഗിച്ച് പാഡ് ചെയ്തിരിക്കുന്നതായി നമുക്ക് കാണാം. അവസാനമായി, ആദ്യത്തെ എൻട്രിയിൽ ഒരു `[PAD]` ടോക്കൺ ചേർത്തുകൊണ്ട് ലേബലുകളെ വലത്തോട്ട് ഷിഫ്‌റ്റ് ചെയ്ത ഒരു പുതിയ `decoder_input_ids` നമുക്ക് കാണാം. + +{#if fw === 'pt'} + +ട്രെയിൻ ചെയ്യാൻ ആവശ്യമായ എല്ലാ ചേരുവകളും ഒടുവിൽ നമുക്ക് ലഭിച്ചു! ഇനി സ്‌റ്റാൻഡേർഡ് ആർഗ്യുമെന്റുകളോടെ ട്രെയിനർ ഇൻസ്‌റ്റാൻഷിയേറ്റ് ചെയ്താൽ മാത്രം മതി: + +```python +from transformers import Seq2SeqTrainer + +trainer = Seq2SeqTrainer( + model, + args, + train_dataset=tokenized_datasets["train"], + eval_dataset=tokenized_datasets["validation"], + data_collator=data_collator, + tokenizer=tokenizer, + compute_metrics=compute_metrics, +) +``` + +തുടർന്ന് നമ്മുടെ ട്രെയിനിംഗ് റൺ ആരംഭിക്കുക: + +```python +trainer.train() +``` + +ട്രെയിനിംഗ് സമയത്ത്, ഓരോ എപ്പോക്കിലും ട്രെയിനിംഗ് ലോസ് കുറയുന്നതും ROUGE സ്കോറുകൾ കൂടുന്നതും നിങ്ങൾ കാണേണ്ടതാണ്. ട്രെയിനിംഗ് പൂർത്തിയായിക്കഴിഞ്ഞാൽ, `Trainer.evaluate()` റൺ ചെയ്ത് അവസാന ROUGE സ്കോറുകൾ നിങ്ങൾക്ക് കാണാം: + +```python +trainer.evaluate() +``` + +```python out +{'eval_loss': 3.028524398803711, + 'eval_rouge1': 16.9728, + 'eval_rouge2': 8.2969, + 'eval_rougeL': 16.8366, + 'eval_rougeLsum': 16.851, + 'eval_gen_len': 10.1597, + 'eval_runtime': 6.1054, + 'eval_samples_per_second': 38.982, + 'eval_steps_per_second': 4.914} +``` + +സ്കോറുകളിൽ നിന്ന്, നമ്മുടെ മോഡൽ lead-3 ബേസ്‌ലൈനിനെ അനായാസം മറികടന്നതായി നമുക്ക് കാണാം — കൊള്ളാം! അവസാനമായി ചെയ്യേണ്ടത് മോഡൽ വെയ്‌റ്റുകൾ താഴെ കാണുന്നതുപോലെ Hub-ലേക്ക് പുഷ് ചെയ്യുകയാണ്: + +``` +trainer.push_to_hub(commit_message="Training complete", tags="summarization") +``` + +```python out +'https://huggingface.co/huggingface-course/mt5-finetuned-amazon-en-es/commit/aa0536b829b28e73e1e4b94b8a5aacec420d40e0' +``` + +ഇത് എല്ലാ ഫയലുകളും Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യുന്നതിന് മുമ്പ്, ചെക്ക്‌പോയിന്റും കോൺഫിഗറേഷൻ ഫയലുകളും `output_dir`-ൽ സേവ് ചെയ്യും. `tags` ആർഗ്യുമെന്റ് വ്യക്തമാക്കുന്നതിലൂടെ, Hub-ലെ വിജറ്റ് mT5 ആർക്കിടെക്ചറുമായി ബന്ധപ്പെട്ട ഡിഫോൾട്ട് ടെക്‌സ്‌റ്റ് ജനറേഷൻ വിജറ്റിന് പകരം ഒരു സമ്മറൈസേഷൻ പൈപ്പ്‌ലൈനിനുള്ളതായിരിക്കും എന്നും നമ്മൾ ഉറപ്പാക്കുന്നു (മോഡൽ ടാഗുകളെക്കുറിച്ചുള്ള കൂടുതൽ വിവരങ്ങൾക്ക്, [🤗 Hub ഡോക്യുമെന്റേഷൻ](https://huggingface.co/docs/hub/main#how-is-a-models-type-of-inference-api-and-widget-determined) കാണുക). `trainer.push_to_hub()`-ന്റെ ഔട്ട്‌പുട്ട് Git കമ്മിറ്റ് ഹാഷിലേക്കുള്ള ഒരു URL ആണ്, അതിനാൽ മോഡൽ റിപ്പോസിറ്ററിയിൽ വരുത്തിയ മാറ്റങ്ങൾ നിങ്ങൾക്ക് എളുപ്പത്തിൽ കാണാം! + +ഈ ഭാഗം അവസാനിപ്പിക്കാൻ, 🤗 Accelerate നൽകുന്ന ലോ-ലെവൽ ഫീച്ചറുകൾ ഉപയോഗിച്ചും mT5 എങ്ങനെ ഫൈൻ-ട്യൂൻ ചെയ്യാമെന്ന് നോക്കാം. + +{:else} + +ട്രെയിൻ ചെയ്യാൻ നമ്മൾ ഏകദേശം തയ്യാറായി! മുകളിൽ നിർവചിച്ച ഡേറ്റാ കൊളേറ്റർ ഉപയോഗിച്ച് നമ്മുടെ ഡേറ്റാസെറ്റുകളെ `tf.data.Dataset`-കളായി മാറ്റുകയും, തുടർന്ന് മോഡൽ `compile()` ചെയ്യുകയും `fit()` ചെയ്യുകയും മാത്രമേ വേണ്ടൂ. ആദ്യം, ഡേറ്റാസെറ്റുകൾ: + +```python +tf_train_dataset = model.prepare_tf_dataset( + tokenized_datasets["train"], + collate_fn=data_collator, + shuffle=True, + batch_size=8, +) +tf_eval_dataset = model.prepare_tf_dataset( + tokenized_datasets["validation"], + collate_fn=data_collator, + shuffle=False, + batch_size=8, +) +``` + +ഇപ്പോൾ, നമ്മുടെ ട്രെയിനിംഗ് ഹൈപ്പർപാരാമീറ്ററുകൾ നിർവചിച്ച് കംപൈൽ ചെയ്യുന്നു: + +```python +from transformers import create_optimizer +import tensorflow as tf + +# The number of training steps is the number of samples in the dataset, divided by the batch size then multiplied +# by the total number of epochs. Note that the tf_train_dataset here is a batched tf.data.Dataset, +# not the original Hugging Face Dataset, so its len() is already num_samples // batch_size. +num_train_epochs = 8 +num_train_steps = len(tf_train_dataset) * num_train_epochs +model_name = model_checkpoint.split("/")[-1] + +optimizer, schedule = create_optimizer( + init_lr=5.6e-5, + num_warmup_steps=0, + num_train_steps=num_train_steps, + weight_decay_rate=0.01, +) + +model.compile(optimizer=optimizer) + +# Train in mixed-precision float16 +tf.keras.mixed_precision.set_global_policy("mixed_float16") +``` + +അവസാനമായി, മോഡൽ നമ്മൾ ഫിറ്റ് ചെയ്യുന്നു. ഓരോ എപ്പോക്കിനു ശേഷവും മോഡൽ Hub-ലേക്ക് സേവ് ചെയ്യാൻ ഒരു `PushToHubCallback` നമ്മൾ ഉപയോഗിക്കുന്നു; പിന്നീട് ഇൻഫറൻസിനായി ഇത് ഉപയോഗിക്കാൻ ഇത് നമ്മെ അനുവദിക്കും: + +```python +from transformers.keras_callbacks import PushToHubCallback + +callback = PushToHubCallback( + output_dir=f"{model_name}-finetuned-amazon-en-es", tokenizer=tokenizer +) + +model.fit( + tf_train_dataset, validation_data=tf_eval_dataset, callbacks=[callback], epochs=8 +) +``` + +ട്രെയിനിംഗ് സമയത്ത് നമുക്ക് ചില ലോസ് മൂല്യങ്ങൾ ലഭിച്ചു, എന്നാൽ യഥാർത്ഥത്തിൽ നമ്മൾ നേരത്തെ കണക്കാക്കിയ ROUGE മെട്രിക്കുകളാണ് നമുക്ക് കാണേണ്ടത്. ആ മെട്രിക്കുകൾ ലഭിക്കാൻ, മോഡലിൽ നിന്ന് ഔട്ട്‌പുട്ടുകൾ ജനറേറ്റ് ചെയ്ത് അവയെ സ്‌ട്രിംഗുകളാക്കി മാറ്റേണ്ടതുണ്ട്. ROUGE മെട്രിക്കിന് താരതമ്യം ചെയ്യാനായി ലേബലുകളുടെയും പ്രവചനങ്ങളുടെയും ചില ലിസ്‌റ്റുകൾ നമുക്ക് നിർമ്മിക്കാം (ഈ ഭാഗത്തിന് ഇംപോർട്ട് എററുകൾ ലഭിക്കുകയാണെങ്കിൽ, `!pip install tqdm` ചെയ്യേണ്ടി വന്നേക്കാം എന്നത് ശ്രദ്ധിക്കുക). പ്രകടനം ഗണ്യമായി വർദ്ധിപ്പിക്കുന്ന ഒരു തന്ത്രവും നമ്മൾ ഉപയോഗിക്കാൻ പോകുന്നു — TensorFlow-യുടെ ആക്‌സിലറേറ്റഡ് ലീനിയർ ആൾജിബ്ര കംപൈലറായ [XLA](https://www.tensorflow.org/xla) ഉപയോഗിച്ച് നമ്മുടെ ജനറേഷൻ കോഡ് കംപൈൽ ചെയ്യുക. XLA മോഡലിന്റെ കംപ്യൂട്ടേഷൻ ഗ്രാഫിൽ വിവിധ ഒപ്‌റ്റിമൈസേഷനുകൾ പ്രയോഗിക്കുകയും, വേഗതയിലും മെമ്മറി ഉപയോഗത്തിലും കാര്യമായ പുരോഗതി ഉണ്ടാക്കുകയും ചെയ്യുന്നു. Hugging Face [ബ്ലോഗിൽ](https://huggingface.co/blog/tf-xla-generate) വിവരിച്ചിരിക്കുന്നതുപോലെ, നമ്മുടെ ഇൻപുട്ട് ഷേപ്പുകൾ അധികം മാറാതിരിക്കുമ്പോഴാണ് XLA ഏറ്റവും നന്നായി പ്രവർത്തിക്കുന്നത്. ഇത് കൈകാര്യം ചെയ്യാൻ, നമ്മുടെ ഇൻപുട്ടുകളെ 128-ന്റെ ഗുണിതങ്ങളിലേക്ക് പാഡ് ചെയ്യുകയും, പാഡിംഗ് കൊളേറ്റർ ഉപയോഗിച്ച് ഒരു പുതിയ ഡേറ്റാസെറ്റ് ഉണ്ടാക്കുകയും ചെയ്യും; തുടർന്ന് നമ്മുടെ ജനറേഷൻ ഫംഗ്‌ഷനിൽ `@tf.function(jit_compile=True)` ഡെക്കറേറ്റർ പ്രയോഗിക്കും, ഇത് മുഴുവൻ ഫംഗ്‌ഷനെയും XLA ഉപയോഗിച്ച് കംപൈൽ ചെയ്യാൻ അടയാളപ്പെടുത്തുന്നു. + +```python +from tqdm import tqdm +import numpy as np + +generation_data_collator = DataCollatorForSeq2Seq( + tokenizer, model=model, return_tensors="tf", pad_to_multiple_of=320 +) + +tf_generate_dataset = model.prepare_tf_dataset( + tokenized_datasets["validation"], + collate_fn=generation_data_collator, + shuffle=False, + batch_size=8, + drop_remainder=True, +) + + +@tf.function(jit_compile=True) +def generate_with_xla(batch): + return model.generate( + input_ids=batch["input_ids"], + attention_mask=batch["attention_mask"], + max_new_tokens=32, + ) + + +all_preds = [] +all_labels = [] +for batch, labels in tqdm(tf_generate_dataset): + predictions = generate_with_xla(batch) + decoded_preds = tokenizer.batch_decode(predictions, skip_special_tokens=True) + labels = labels.numpy() + labels = np.where(labels != -100, labels, tokenizer.pad_token_id) + decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True) + decoded_preds = ["\n".join(sent_tokenize(pred.strip())) for pred in decoded_preds] + decoded_labels = ["\n".join(sent_tokenize(label.strip())) for label in decoded_labels] + all_preds.extend(decoded_preds) + all_labels.extend(decoded_labels) +``` + +ലേബൽ, പ്രവചന സ്‌ട്രിംഗുകളുടെ ലിസ്‌റ്റുകൾ ലഭിച്ചുകഴിഞ്ഞാൽ, ROUGE സ്കോർ കണക്കാക്കുന്നത് എളുപ്പമാണ്: + +```python +result = rouge_score.compute( + predictions=decoded_preds, references=decoded_labels, use_stemmer=True +) +result = {key: value.mid.fmeasure * 100 for key, value in result.items()} +{k: round(v, 4) for k, v in result.items()} +``` + +``` +{'rouge1': 31.4815, 'rouge2': 25.4386, 'rougeL': 31.4815, 'rougeLsum': 31.4815} +``` + + +{/if} + +{#if fw === 'pt'} + +## 🤗 Accelerate ഉപയോഗിച്ച് mT5 ഫൈൻ-ട്യൂൻ ചെയ്യുന്നു[[fine-tuning-mt5-with-accelerate]] + +🤗 Accelerate ഉപയോഗിച്ച് നമ്മുടെ മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യുന്നത് [അധ്യായം 3](/course/chapter3)-ൽ നമ്മൾ കണ്ട ടെക്‌സ്‌റ്റ് ക്ലാസിഫിക്കേഷൻ ഉദാഹരണത്തോട് വളരെ സാമ്യമുള്ളതാണ്. ട്രെയിനിംഗ് സമയത്ത് നമ്മുടെ സംഗ്രഹങ്ങൾ വ്യക്തമായി (explicitly) ജനറേറ്റ് ചെയ്യേണ്ടതും ROUGE സ്കോറുകൾ എങ്ങനെ കണക്കാക്കണമെന്ന് നിർവചിക്കേണ്ടതുമാണ് പ്രധാന വ്യത്യാസങ്ങൾ (`Seq2SeqTrainer` ജനറേഷൻ നമുക്കായി കൈകാര്യം ചെയ്തിരുന്നു എന്ന് ഓർക്കുക). ഈ രണ്ട് ആവശ്യങ്ങളും 🤗 Accelerate-നുള്ളിൽ എങ്ങനെ ഇംപ്ലിമെന്റ് ചെയ്യാമെന്ന് നോക്കാം! + +### ട്രെയിനിംഗിനായി എല്ലാം തയ്യാറാക്കുന്നു[[preparing-everything-for-training]] + +നമ്മൾ ആദ്യം ചെയ്യേണ്ടത് നമ്മുടെ ഓരോ സ്പ്ലിറ്റിനും ഒരു `DataLoader` നിർമ്മിക്കുകയാണ്. PyTorch ഡേറ്റാലോഡറുകൾ ടെൻസറുകളുടെ ബാച്ചുകളാണ് പ്രതീക്ഷിക്കുന്നതിനാൽ, നമ്മുടെ ഡേറ്റാസെറ്റുകളിൽ ഫോർമാറ്റ് `"torch"` എന്ന് സെറ്റ് ചെയ്യേണ്ടതുണ്ട്: + +```python +tokenized_datasets.set_format("torch") +``` + +ഇപ്പോൾ ടെൻസറുകൾ മാത്രം അടങ്ങിയ ഡേറ്റാസെറ്റുകൾ നമുക്ക് ലഭിച്ചു, അടുത്തതായി ചെയ്യേണ്ടത് `DataCollatorForSeq2Seq` വീണ്ടും ഇൻസ്‌റ്റാൻഷിയേറ്റ് ചെയ്യുകയാണ്. ഇതിനായി മോഡലിന്റെ ഒരു പുതിയ പതിപ്പ് നൽകേണ്ടതുണ്ട്, അതിനാൽ നമ്മുടെ കാഷിൽ നിന്ന് അത് വീണ്ടും ലോഡ് ചെയ്യാം: + +```python +model = AutoModelForSeq2SeqLM.from_pretrained(model_checkpoint) +``` + +തുടർന്ന് ഡേറ്റാ കൊളേറ്റർ ഇൻസ്‌റ്റാൻഷിയേറ്റ് ചെയ്ത്, നമ്മുടെ ഡേറ്റാലോഡറുകൾ നിർവചിക്കാൻ ഇത് ഉപയോഗിക്കാം: + +```python +from torch.utils.data import DataLoader + +batch_size = 8 +train_dataloader = DataLoader( + tokenized_datasets["train"], + shuffle=True, + collate_fn=data_collator, + batch_size=batch_size, +) +eval_dataloader = DataLoader( + tokenized_datasets["validation"], collate_fn=data_collator, batch_size=batch_size +) +``` + +അടുത്തതായി ചെയ്യേണ്ടത് നമ്മൾ ഉപയോഗിക്കാൻ ആഗ്രഹിക്കുന്ന ഒപ്‌റ്റിമൈസർ നിർവചിക്കുകയാണ്. നമ്മുടെ മറ്റ് ഉദാഹരണങ്ങളിലേതുപോലെ, മിക്ക പ്രശ്നങ്ങൾക്കും നന്നായി പ്രവർത്തിക്കുന്ന `AdamW` നമ്മൾ ഉപയോഗിക്കും: + +```python +from torch.optim import AdamW + +optimizer = AdamW(model.parameters(), lr=2e-5) +``` + +അവസാനമായി, നമ്മുടെ മോഡൽ, ഒപ്‌റ്റിമൈസർ, ഡേറ്റാലോഡറുകൾ എന്നിവ `accelerator.prepare()` മെത്തേഡിലേക്ക് നൽകുന്നു: + +```python +from accelerate import Accelerator + +accelerator = Accelerator() +model, optimizer, train_dataloader, eval_dataloader = accelerator.prepare( + model, optimizer, train_dataloader, eval_dataloader +) +``` + +> [!TIP] +> 🚨 നിങ്ങൾ ഒരു TPU-വിലാണ് ട്രെയിൻ ചെയ്യുന്നതെങ്കിൽ, മുകളിലുള്ള എല്ലാ കോഡും ഒരു പ്രത്യേക ട്രെയിനിംഗ് ഫംഗ്‌ഷനിലേക്ക് മാറ്റേണ്ടിവരും. കൂടുതൽ വിവരങ്ങൾക്ക് [അധ്യായം 3](/course/chapter3) കാണുക. + +ഇപ്പോൾ നമ്മുടെ ഒബ്‌ജക്റ്റുകൾ തയ്യാറാക്കിക്കഴിഞ്ഞു, ഇനി മൂന്ന് കാര്യങ്ങൾ ചെയ്യാൻ ബാക്കിയുണ്ട്: + +* ലേണിംഗ് റേറ്റ് ഷെഡ്യൂൾ നിർവചിക്കുക. +* ഇവാല്യുവേഷനായി സംഗ്രഹങ്ങൾ പോസ്‌റ്റ്-പ്രോസസ്സ് ചെയ്യുന്ന ഒരു ഫംഗ്‌ഷൻ ഇംപ്ലിമെന്റ് ചെയ്യുക. +* നമ്മുടെ മോഡൽ പുഷ് ചെയ്യാൻ കഴിയുന്ന ഒരു റിപ്പോസിറ്ററി Hub-ൽ സൃഷ്ടിക്കുക. + +ലേണിംഗ് റേറ്റ് ഷെഡ്യൂളിനായി, മുൻ ഭാഗങ്ങളിലെ സ്‌റ്റാൻഡേർഡ് ലീനിയർ ഷെഡ്യൂൾ നമ്മൾ ഉപയോഗിക്കും: + +```python +from transformers import get_scheduler + +num_train_epochs = 10 +num_update_steps_per_epoch = len(train_dataloader) +num_training_steps = num_train_epochs * num_update_steps_per_epoch + +lr_scheduler = get_scheduler( + "linear", + optimizer=optimizer, + num_warmup_steps=0, + num_training_steps=num_training_steps, +) +``` + +പോസ്‌റ്റ്-പ്രോസസ്സിംഗിനായി, ജനറേറ്റ് ചെയ്ത സംഗ്രഹങ്ങളെ ന്യൂലൈനുകൾ കൊണ്ട് വേർതിരിച്ച വാക്യങ്ങളായി വിഭജിക്കുന്ന ഒരു ഫംഗ്‌ഷൻ നമുക്ക് ആവശ്യമാണ്. ROUGE മെട്രിക് പ്രതീക്ഷിക്കുന്ന ഫോർമാറ്റ് ഇതാണ്, താഴെയുള്ള കോഡ് സ്‌നിപ്പെറ്റ് ഉപയോഗിച്ച് നമുക്ക് ഇത് നേടാം: + +```python +def postprocess_text(preds, labels): + preds = [pred.strip() for pred in preds] + labels = [label.strip() for label in labels] + + # ROUGE expects a newline after each sentence + preds = ["\n".join(nltk.sent_tokenize(pred)) for pred in preds] + labels = ["\n".join(nltk.sent_tokenize(label)) for label in labels] + + return preds, labels +``` + +`Seq2SeqTrainer`-ന്റെ `compute_metrics()` ഫംഗ്‌ഷൻ നമ്മൾ എങ്ങനെ നിർവചിച്ചു എന്ന് ഓർക്കുന്നുണ്ടെങ്കിൽ ഇത് നിങ്ങൾക്ക് പരിചിതമായി തോന്നണം. + +അവസാനമായി, Hugging Face Hub-ൽ ഒരു മോഡൽ റിപ്പോസിറ്ററി നമ്മൾ സൃഷ്ടിക്കേണ്ടതുണ്ട്. ഇതിനായി, അനുയോജ്യമായ പേരുള്ള 🤗 Hub ലൈബ്രറി നമുക്ക് ഉപയോഗിക്കാം. നമ്മുടെ റിപ്പോസിറ്ററിക്ക് ഒരു പേര് നിർവചിച്ചാൽ മാത്രം മതി; റിപ്പോസിറ്ററി ID-യെ യൂസർ പ്രൊഫൈലുമായി സംയോജിപ്പിക്കാൻ ലൈബ്രറിയിൽ ഒരു യൂട്ടിലിറ്റി ഫംഗ്‌ഷനുണ്ട്: + +```python +from huggingface_hub import get_full_repo_name + +model_name = "test-bert-finetuned-squad-accelerate" +repo_name = get_full_repo_name(model_name) +repo_name +``` + +```python out +'lewtun/mt5-finetuned-amazon-en-es-accelerate' +``` + +ഇപ്പോൾ ഈ റിപ്പോസിറ്ററി പേര് ഉപയോഗിച്ച്, ട്രെയിനിംഗ് ആർട്ടിഫാക്റ്റുകൾ സൂക്ഷിക്കുന്ന നമ്മുടെ റിസൾട്ട്‌സ് ഡയറക്ടറിയിലേക്ക് ഒരു ലോക്കൽ പതിപ്പ് ക്ലോൺ ചെയ്യാം: + +```python +from huggingface_hub import Repository + +output_dir = "results-mt5-finetuned-squad-accelerate" +repo = Repository(output_dir, clone_from=repo_name) +``` + +ട്രെയിനിംഗ് സമയത്ത് `repo.push_to_hub()` മെത്തേഡ് വിളിച്ചുകൊണ്ട് ആർട്ടിഫാക്റ്റുകൾ Hub-ലേക്ക് തിരികെ പുഷ് ചെയ്യാൻ ഇത് നമ്മെ അനുവദിക്കും! ഇനി ട്രെയിനിംഗ് ലൂപ്പ് എഴുതിക്കൊണ്ട് നമ്മുടെ വിശകലനം പൂർത്തിയാക്കാം. + +### ട്രെയിനിംഗ് ലൂപ്പ്[[training-loop]] + +സമ്മറൈസേഷനുള്ള ട്രെയിനിംഗ് ലൂപ്പ് നമ്മൾ കണ്ടിട്ടുള്ള മറ്റ് 🤗 Accelerate ഉദാഹരണങ്ങളോട് ഏറെക്കുറെ സാമ്യമുള്ളതാണ്, ഏകദേശം നാല് പ്രധാന ഘട്ടങ്ങളായി ഇതിനെ വിഭജിക്കാം: + +1. ഓരോ എപ്പോക്കിലും `train_dataloader`-ലെ എല്ലാ ഉദാഹരണങ്ങളിലൂടെയും ഇറ്ററേറ്റ് ചെയ്ത് മോഡൽ ട്രെയിൻ ചെയ്യുക. +2. ഓരോ എപ്പോക്കിന്റെയും അവസാനം, ആദ്യം ടോക്കണുകൾ ജനറേറ്റ് ചെയ്തും തുടർന്ന് അവയെ (റഫറൻസ് സംഗ്രഹങ്ങളെയും) ടെക്‌സ്‌റ്റിലേക്ക് ഡീകോഡ് ചെയ്തും മോഡൽ സംഗ്രഹങ്ങൾ ജനറേറ്റ് ചെയ്യുക. +3. നമ്മൾ നേരത്തെ കണ്ട അതേ ടെക്‌നിക്കുകൾ ഉപയോഗിച്ച് ROUGE സ്കോറുകൾ കണക്കാക്കുക. +4. ചെക്ക്‌പോയിന്റുകൾ സേവ് ചെയ്ത് എല്ലാം Hub-ലേക്ക് പുഷ് ചെയ്യുക. ഓരോ എപ്പോക്കിലെയും ചെക്ക്‌പോയിന്റുകൾ _അസിൻക്രണസായി_ (asynchronously) പുഷ് ചെയ്യാൻ കഴിയുന്നതിനായി, `Repository` ഒബ്‌ജക്റ്റിന്റെ ഉപകാരപ്രദമായ `blocking=False` ആർഗ്യുമെന്റിനെ ഇവിടെ നമ്മൾ ആശ്രയിക്കുന്നു. ഒരു GB വലുപ്പമുള്ള മോഡലുമായി ബന്ധപ്പെട്ട അൽപ്പം മന്ദഗതിയിലുള്ള അപ്‌ലോഡിനായി കാത്തിരിക്കാതെ ട്രെയിനിംഗ് തുടരാൻ ഇത് നമ്മെ അനുവദിക്കുന്നു! + +ഈ ഘട്ടങ്ങൾ താഴെയുള്ള കോഡ് ബ്ലോക്കിൽ കാണാം: + +```python +from tqdm.auto import tqdm +import torch +import numpy as np + +progress_bar = tqdm(range(num_training_steps)) + +for epoch in range(num_train_epochs): + # Training + model.train() + for step, batch in enumerate(train_dataloader): + outputs = model(**batch) + loss = outputs.loss + accelerator.backward(loss) + + optimizer.step() + lr_scheduler.step() + optimizer.zero_grad() + progress_bar.update(1) + + # Evaluation + model.eval() + for step, batch in enumerate(eval_dataloader): + with torch.no_grad(): + generated_tokens = accelerator.unwrap_model(model).generate( + batch["input_ids"], + attention_mask=batch["attention_mask"], + ) + + generated_tokens = accelerator.pad_across_processes( + generated_tokens, dim=1, pad_index=tokenizer.pad_token_id + ) + labels = batch["labels"] + + # If we did not pad to max length, we need to pad the labels too + labels = accelerator.pad_across_processes( + batch["labels"], dim=1, pad_index=tokenizer.pad_token_id + ) + + generated_tokens = accelerator.gather(generated_tokens).cpu().numpy() + labels = accelerator.gather(labels).cpu().numpy() + + # Replace -100 in the labels as we can't decode them + labels = np.where(labels != -100, labels, tokenizer.pad_token_id) + if isinstance(generated_tokens, tuple): + generated_tokens = generated_tokens[0] + decoded_preds = tokenizer.batch_decode( + generated_tokens, skip_special_tokens=True + ) + decoded_labels = tokenizer.batch_decode(labels, skip_special_tokens=True) + + decoded_preds, decoded_labels = postprocess_text( + decoded_preds, decoded_labels + ) + + rouge_score.add_batch(predictions=decoded_preds, references=decoded_labels) + + # Compute metrics + result = rouge_score.compute() + # Extract the median ROUGE scores + result = {key: value.mid.fmeasure * 100 for key, value in result.items()} + result = {k: round(v, 4) for k, v in result.items()} + print(f"Epoch {epoch}:", result) + + # Save and upload + accelerator.wait_for_everyone() + unwrapped_model = accelerator.unwrap_model(model) + unwrapped_model.save_pretrained(output_dir, save_function=accelerator.save) + if accelerator.is_main_process: + tokenizer.save_pretrained(output_dir) + repo.push_to_hub( + commit_message=f"Training in progress epoch {epoch}", blocking=False + ) +``` + +```python out +Epoch 0: {'rouge1': 5.6351, 'rouge2': 1.1625, 'rougeL': 5.4866, 'rougeLsum': 5.5005} +Epoch 1: {'rouge1': 9.8646, 'rouge2': 3.4106, 'rougeL': 9.9439, 'rougeLsum': 9.9306} +Epoch 2: {'rouge1': 11.0872, 'rouge2': 3.3273, 'rougeL': 11.0508, 'rougeLsum': 10.9468} +Epoch 3: {'rouge1': 11.8587, 'rouge2': 4.8167, 'rougeL': 11.7986, 'rougeLsum': 11.7518} +Epoch 4: {'rouge1': 12.9842, 'rouge2': 5.5887, 'rougeL': 12.7546, 'rougeLsum': 12.7029} +Epoch 5: {'rouge1': 13.4628, 'rouge2': 6.4598, 'rougeL': 13.312, 'rougeLsum': 13.2913} +Epoch 6: {'rouge1': 12.9131, 'rouge2': 5.8914, 'rougeL': 12.6896, 'rougeLsum': 12.5701} +Epoch 7: {'rouge1': 13.3079, 'rouge2': 6.2994, 'rougeL': 13.1536, 'rougeLsum': 13.1194} +Epoch 8: {'rouge1': 13.96, 'rouge2': 6.5998, 'rougeL': 13.9123, 'rougeLsum': 13.7744} +Epoch 9: {'rouge1': 14.1192, 'rouge2': 7.0059, 'rougeL': 14.1172, 'rougeLsum': 13.9509} +``` + +അത്രമാത്രം! ഇത് റൺ ചെയ്തുകഴിഞ്ഞാൽ, `Trainer` ഉപയോഗിച്ച് നമുക്ക് ലഭിച്ചതിനോട് ഏറെക്കുറെ സമാനമായ ഒരു മോഡലും ഫലങ്ങളും നിങ്ങൾക്ക് ലഭിക്കും. + +{/if} + +## നിങ്ങളുടെ ഫൈൻ-ട്യൂൻ ചെയ്ത മോഡൽ ഉപയോഗിക്കുന്നു[[using-your-fine-tuned-model]] + +മോഡൽ Hub-ലേക്ക് പുഷ് ചെയ്തുകഴിഞ്ഞാൽ, ഇൻഫറൻസ് വിജറ്റ് വഴിയോ ഒരു `pipeline` ഒബ്‌ജക്റ്റ് ഉപയോഗിച്ചോ താഴെ കാണുന്നതുപോലെ അത് നിങ്ങൾക്ക് പരീക്ഷിക്കാം: + +```python +from transformers import pipeline + +hub_model_id = "huggingface-course/mt5-small-finetuned-amazon-en-es" +summarizer = pipeline("summarization", model=hub_model_id) +``` + +സംഗ്രഹങ്ങളുടെ ഗുണനിലവാരം മനസ്സിലാക്കാൻ, ടെസ്‌റ്റ് സെറ്റിൽ നിന്നുള്ള (മോഡൽ കണ്ടിട്ടില്ലാത്ത) ചില ഉദാഹരണങ്ങൾ നമ്മുടെ പൈപ്പ്‌ലൈനിലേക്ക് നൽകാം. ആദ്യം, റിവ്യൂ, തലക്കെട്ട്, ജനറേറ്റ് ചെയ്ത സംഗ്രഹം എന്നിവ ഒരുമിച്ച് കാണിക്കുന്ന ഒരു ലളിതമായ ഫംഗ്‌ഷൻ ഇംപ്ലിമെന്റ് ചെയ്യാം: + +```python +def print_summary(idx): + review = books_dataset["test"][idx]["review_body"] + title = books_dataset["test"][idx]["review_title"] + summary = summarizer(books_dataset["test"][idx]["review_body"])[0]["summary_text"] + print(f"'>>> Review: {review}'") + print(f"\n'>>> Title: {title}'") + print(f"\n'>>> Summary: {summary}'") +``` + +നമുക്ക് ലഭിക്കുന്ന ഇംഗ്ലീഷ് ഉദാഹരണങ്ങളിൽ ഒന്ന് നോക്കാം: + +```python +print_summary(100) +``` + +```python out +'>>> Review: Nothing special at all about this product... the book is too small and stiff and hard to write in. The huge sticker on the back doesn’t come off and looks super tacky. I would not purchase this again. I could have just bought a journal from the dollar store and it would be basically the same thing. It’s also really expensive for what it is.' + +'>>> Title: Not impressed at all... buy something else' + +'>>> Summary: Nothing special at all about this product' +``` + +ഇത് മോശമല്ല! റിവ്യൂവിന്റെ ഭാഗങ്ങളിൽ പുതിയ വാക്കുകൾ ചേർത്തുകൊണ്ട് _അബ്‌സ്ട്രാക്റ്റീവ്_ (abstractive) സമ്മറൈസേഷൻ നടത്താൻ നമ്മുടെ മോഡലിന് യഥാർത്ഥത്തിൽ കഴിഞ്ഞിട്ടുണ്ടെന്ന് നമുക്ക് കാണാം. നമ്മുടെ മോഡലിന്റെ ഏറ്റവും രസകരമായ വശം ഒരുപക്ഷേ അത് ദ്വിഭാഷാ മോഡലാണെന്നതാണ്, അതിനാൽ സ്പാനിഷ് റിവ്യൂകളുടെ സംഗ്രഹങ്ങളും നമുക്ക് ജനറേറ്റ് ചെയ്യാം: + +```python +print_summary(0) +``` + +```python out +'>>> Review: Es una trilogia que se hace muy facil de leer. Me ha gustado, no me esperaba el final para nada' + +'>>> Title: Buena literatura para adolescentes' + +'>>> Summary: Muy facil de leer' +``` + +ഈ സംഗ്രഹം ഇംഗ്ലീഷിൽ "Very easy to read" എന്നാണ് വിവർത്തനം ചെയ്യപ്പെടുന്നത്; ഈ സാഹചര്യത്തിൽ ഇത് റിവ്യൂവിൽ നിന്ന് നേരിട്ട് എടുത്തതാണെന്ന് നമുക്ക് കാണാം. എന്നിരുന്നാലും, ഇത് mT5 മോഡലിന്റെ ബഹുമുഖത കാണിക്കുന്നു, കൂടാതെ ഒരു ബഹുഭാഷാ കോർപ്പസ് കൈകാര്യം ചെയ്യുന്നത് എങ്ങനെയിരിക്കും എന്നതിന്റെ ഒരു രുചി നിങ്ങൾക്ക് നൽകിയിട്ടുമുണ്ട്! + +അടുത്തതായി, കുറച്ചുകൂടി സങ്കീർണ്ണമായ ഒരു ടാസ്‌കിലേക്ക് നമ്മുടെ ശ്രദ്ധ തിരിക്കും: ഒരു ലാംഗ്വേജ് മോഡൽ പൂജ്യത്തിൽ നിന്ന് (from scratch) ട്രെയിൻ ചെയ്യുക. diff --git a/chapters/ml/chapter7/6.mdx b/chapters/ml/chapter7/6.mdx new file mode 100644 index 000000000..5a2e22541 --- /dev/null +++ b/chapters/ml/chapter7/6.mdx @@ -0,0 +1,890 @@ + + +# ഒരു കോസൽ ലാംഗ്വേജ് മോഡൽ പൂജ്യത്തിൽ നിന്ന് ട്രെയിൻ ചെയ്യുന്നു[[training-a-causal-language-model-from-scratch]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +ഇതുവരെ, നമ്മൾ പ്രധാനമായും പ്രീട്രെയിൻഡ് മോഡലുകൾ ഉപയോഗിക്കുകയും, പ്രീട്രെയിനിംഗിൽ നിന്നുള്ള വെയ്‌റ്റുകൾ പുനരുപയോഗിച്ച് പുതിയ ഉപയോഗ സാഹചര്യങ്ങൾക്കായി (use cases) അവയെ ഫൈൻ-ട്യൂൻ ചെയ്യുകയുമായിരുന്നു. [അധ്യായം 1](/course/chapter1)-ൽ നമ്മൾ കണ്ടതുപോലെ, ഇതിനെ സാധാരണയായി _ട്രാൻസ്ഫർ ലേണിംഗ്_ (transfer learning) എന്ന് വിളിക്കുന്നു; ലേബൽ ചെയ്ത ഡേറ്റ കുറവായ യഥാർത്ഥ ലോക ഉപയോഗ സാഹചര്യങ്ങളിൽ Transformer മോഡലുകൾ പ്രയോഗിക്കാൻ ഇത് വളരെ വിജയകരമായ ഒരു തന്ത്രമാണ്. ഈ അധ്യായത്തിൽ, നമ്മൾ വ്യത്യസ്തമായ ഒരു സമീപനം സ്വീകരിച്ച്, തീർത്തും പുതിയ ഒരു മോഡൽ പൂജ്യത്തിൽ നിന്ന് (from scratch) ട്രെയിൻ ചെയ്യും. നിങ്ങളുടെ കൈവശം ധാരാളം ഡേറ്റ ഉണ്ടെങ്കിൽ, അത് ലഭ്യമായ മോഡലുകൾക്കായി ഉപയോഗിച്ച പ്രീട്രെയിനിംഗ് ഡേറ്റയിൽ നിന്ന് വളരെ വ്യത്യസ്തവുമാണെങ്കിൽ, ഇത് സ്വീകരിക്കാൻ നല്ലൊരു സമീപനമാണ്. എന്നിരുന്നാലും, നിലവിലുള്ള ഒരു മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യുന്നതിനെക്കാൾ വളരെയധികം കമ്പ്യൂട്ട് റിസോഴ്‌സുകൾ ഒരു ലാംഗ്വേജ് മോഡൽ പ്രീട്രെയിൻ ചെയ്യാൻ ആവശ്യമാണ്. സംഗീത സ്വരങ്ങൾ (musical notes), DNA പോലുള്ള മോളിക്യുലാർ സീക്വൻസുകൾ, അല്ലെങ്കിൽ പ്രോഗ്രാമിംഗ് ഭാഷകൾ അടങ്ങിയ ഡേറ്റാസെറ്റുകൾ, ഒരു പുതിയ മോഡൽ ട്രെയിൻ ചെയ്യുന്നത് അർത്ഥവത്താകുന്ന ഉദാഹരണങ്ങളാണ്. TabNine, OpenAI-യുടെ Codex മോഡലിന്റെ പിൻബലത്തോടെ പ്രവർത്തിക്കുന്ന GitHub-ന്റെ Copilot തുടങ്ങിയ, നീണ്ട കോഡ് സീക്വൻസുകൾ ജനറേറ്റ് ചെയ്യാൻ കഴിയുന്ന ടൂളുകൾക്ക് നന്ദി, അവസാനം പറഞ്ഞവയ്ക്ക് (പ്രോഗ്രാമിംഗ് ഭാഷകൾക്ക്) അടുത്തകാലത്ത് ഏറെ ശ്രദ്ധ ലഭിച്ചിട്ടുണ്ട്. ഈ ടെക്‌സ്‌റ്റ് ജനറേഷൻ ടാസ്‌ക് ഏറ്റവും നന്നായി കൈകാര്യം ചെയ്യുന്നത് GPT-2 പോലുള്ള ഓട്ടോ-റിഗ്രസ്സീവ് (auto-regressive) അഥവാ കോസൽ ലാംഗ്വേജ് മോഡലുകളാണ്. + +ഈ ഭാഗത്തിൽ നമ്മൾ ഒരു കോഡ് ജനറേഷൻ മോഡലിന്റെ ചെറുതാക്കിയ (scaled-down) ഒരു പതിപ്പ് നിർമ്മിക്കും: Python കോഡിന്റെ ഒരു ഉപവിഭാഗം (subset) ഉപയോഗിച്ച്, പൂർണ്ണമായ ഫംഗ്‌ഷനുകൾക്കോ ക്ലാസുകൾക്കോ പകരം ഒറ്റവരി കംപ്ലീഷനുകളിലായിരിക്കും നമ്മൾ ശ്രദ്ധ കേന്ദ്രീകരിക്കുക. Python-ൽ ഡേറ്റയുമായി പ്രവർത്തിക്കുമ്പോൾ, `matplotlib`, `seaborn`, `pandas`, `scikit-learn` എന്നീ ലൈബ്രറികൾ അടങ്ങുന്ന Python ഡേറ്റാ സയൻസ് സ്‌റ്റാക്കുമായി നിങ്ങൾ നിരന്തരം ഇടപെടേണ്ടിവരും. ആ ഫ്രെയിംവർക്കുകൾ ഉപയോഗിക്കുമ്പോൾ പ്രത്യേക കമാൻഡുകൾ തിരഞ്ഞുനോക്കേണ്ടിവരുന്നത് സാധാരണമാണ്; അതിനാൽ ഈ കോളുകൾ നമുക്കായി പൂർത്തിയാക്കിത്തരാൻ ഒരു മോഡൽ ഉപയോഗിക്കാൻ കഴിഞ്ഞാൽ അത് നന്നായിരിക്കും. + + + +[അധ്യായം 6](/course/chapter6)-ൽ Python സോഴ്‌സ് കോഡ് പ്രോസസ്സ് ചെയ്യാൻ കാര്യക്ഷമമായ ഒരു ടോക്കണൈസർ നമ്മൾ നിർമ്മിച്ചു, എന്നാൽ ഒരു മോഡൽ പ്രീട്രെയിൻ ചെയ്യാൻ വലിയ തോതിലുള്ള ഒരു ഡേറ്റാസെറ്റ് ഇനിയും നമുക്ക് ആവശ്യമാണ്. ഇവിടെ, GitHub റിപ്പോസിറ്ററികളിൽ നിന്ന് ശേഖരിച്ച Python കോഡിന്റെ ഒരു കോർപ്പസിൽ (corpus) നമ്മുടെ ടോക്കണൈസർ പ്രയോഗിക്കും. തുടർന്ന് മോഡൽ ട്രെയിൻ ചെയ്യാൻ `Trainer` API-യും 🤗 Accelerate-ഉം നമ്മൾ ഉപയോഗിക്കും. നമുക്ക് തുടങ്ങാം! + + + +ഈ ഭാഗത്തിൽ കാണിച്ചിരിക്കുന്ന കോഡ് ഉപയോഗിച്ച് ട്രെയിൻ ചെയ്ത് Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്ത മോഡലാണ് യഥാർത്ഥത്തിൽ ഇവിടെ പ്രദർശിപ്പിക്കുന്നത്. അത് നിങ്ങൾക്ക് [ഇവിടെ](https://huggingface.co/huggingface-course/codeparrot-ds?text=plt.imshow%28) കാണാം. ടെക്‌സ്‌റ്റ് ജനറേഷനിൽ കുറച്ച് ക്രമരഹിതത (randomization) ഉള്ളതിനാൽ, നിങ്ങൾക്ക് ഒരുപക്ഷേ അല്പം വ്യത്യസ്തമായ ഫലം ലഭിക്കും എന്നത് ശ്രദ്ധിക്കുക. + +## ഡേറ്റ ശേഖരിക്കുന്നു[[gathering-the-data]] + +GitHub പോലുള്ള കോഡ് റിപ്പോസിറ്ററികളിൽ നിന്ന് Python കോഡ് സമൃദ്ധമായി ലഭ്യമാണ്; എല്ലാ Python റിപ്പോസിറ്ററികളും സ്‌ക്രേപ്പ് ചെയ്ത് (scraping) ഒരു ഡേറ്റാസെറ്റ് നിർമ്മിക്കാൻ ഇത് നമുക്ക് ഉപയോഗിക്കാം. ഒരു വലിയ GPT-2 മോഡൽ പ്രീട്രെയിൻ ചെയ്യാൻ [Transformers പാഠപുസ്തകത്തിൽ](https://learning.oreilly.com/library/view/natural-language-processing/9781098136789/) സ്വീകരിച്ച സമീപനം ഇതായിരുന്നു. ഏകദേശം 20 ദശലക്ഷം Python ഫയലുകൾ അടങ്ങിയ, `codeparrot` എന്ന് വിളിക്കുന്ന, ഏകദേശം 180 GB വലിപ്പമുള്ള ഒരു GitHub ഡംപ് ഉപയോഗിച്ച് രചയിതാക്കൾ ഒരു ഡേറ്റാസെറ്റ് നിർമ്മിക്കുകയും, പിന്നീട് അത് [Hugging Face Hub](https://huggingface.co/datasets/transformersbook/codeparrot)-ൽ പങ്കുവയ്ക്കുകയും ചെയ്തു. + +എന്നിരുന്നാലും, മുഴുവൻ കോർപ്പസിലും ട്രെയിൻ ചെയ്യുന്നത് സമയവും കമ്പ്യൂട്ടും ഏറെ ചെലവാക്കുന്ന കാര്യമാണ്; Python ഡേറ്റാ സയൻസ് സ്‌റ്റാക്കുമായി ബന്ധപ്പെട്ട ഡേറ്റാസെറ്റിന്റെ ഉപവിഭാഗം മാത്രമേ നമുക്ക് ആവശ്യമുള്ളൂ. അതിനാൽ, ഈ സ്‌റ്റാക്കിലെ ഏതെങ്കിലും ലൈബ്രറി ഉൾപ്പെടുന്ന എല്ലാ ഫയലുകൾക്കുമായി `codeparrot` ഡേറ്റാസെറ്റ് ഫിൽറ്റർ ചെയ്തുകൊണ്ട് നമുക്ക് തുടങ്ങാം. ഡേറ്റാസെറ്റിന്റെ വലിപ്പം കാരണം, അത് ഡൗൺലോഡ് ചെയ്യുന്നത് ഒഴിവാക്കാൻ നമ്മൾ ആഗ്രഹിക്കുന്നു; പകരം, സ്‌ട്രീമിംഗ് (streaming) സവിശേഷത ഉപയോഗിച്ച് അത് തത്സമയം (on the fly) ഫിൽറ്റർ ചെയ്യും. നേരത്തെ പറഞ്ഞ ലൈബ്രറികൾ ഉപയോഗിച്ച് കോഡ് സാമ്പിളുകൾ ഫിൽറ്റർ ചെയ്യാൻ സഹായിക്കുന്നതിന്, താഴെയുള്ള ഫംഗ്‌ഷൻ നമ്മൾ ഉപയോഗിക്കും: + +```py +def any_keyword_in_string(string, keywords): + for keyword in keywords: + if keyword in string: + return True + return False +``` + +രണ്ട് ഉദാഹരണങ്ങളിൽ ഇത് പരീക്ഷിച്ചുനോക്കാം: + +```py +filters = ["pandas", "sklearn", "matplotlib", "seaborn"] +example_1 = "import numpy as np" +example_2 = "import pandas as pd" + +print( + any_keyword_in_string(example_1, filters), any_keyword_in_string(example_2, filters) +) +``` + +```python out +False True +``` + +ഡേറ്റാസെറ്റ് സ്‌ട്രീം ചെയ്ത് നമുക്ക് ആവശ്യമുള്ള എലമെന്റുകൾ ഫിൽറ്റർ ചെയ്യുന്ന ഒരു ഫംഗ്‌ഷൻ നിർമ്മിക്കാൻ ഇത് നമുക്ക് ഉപയോഗിക്കാം: + +```py +from collections import defaultdict +from tqdm import tqdm +from datasets import Dataset + + +def filter_streaming_dataset(dataset, filters): + filtered_dict = defaultdict(list) + total = 0 + for sample in tqdm(iter(dataset)): + total += 1 + if any_keyword_in_string(sample["content"], filters): + for k, v in sample.items(): + filtered_dict[k].append(v) + print(f"{len(filtered_dict['content'])/total:.2%} of data after filtering.") + return Dataset.from_dict(filtered_dict) +``` + +തുടർന്ന് ഈ ഫംഗ്‌ഷൻ സ്‌ട്രീമിംഗ് ഡേറ്റാസെറ്റിൽ പ്രയോഗിച്ചാൽ മാത്രം മതി: + +```py +# This cell will take a very long time to execute, so you should skip it and go to +# the next one! +from datasets import load_dataset + +split = "train" # "valid" +filters = ["pandas", "sklearn", "matplotlib", "seaborn"] + +data = load_dataset(f"transformersbook/codeparrot-{split}", split=split, streaming=True) +filtered_data = filter_streaming_dataset(data, filters) +``` + +```python out +3.26% of data after filtering. +``` + +ഇത് യഥാർത്ഥ ഡേറ്റാസെറ്റിന്റെ ഏകദേശം 3% നമുക്ക് ബാക്കി വയ്ക്കുന്നു, അത് ഇപ്പോഴും വളരെ വലുതാണ് -- ലഭിക്കുന്ന ഡേറ്റാസെറ്റ് 6 GB വലിപ്പമുള്ളതും 600,000 Python സ്‌ക്രിപ്‌റ്റുകൾ അടങ്ങിയതുമാണ്! + +നിങ്ങളുടെ മെഷീനും ബാൻഡ്‌വിഡ്ത്തും അനുസരിച്ച്, മുഴുവൻ ഡേറ്റാസെറ്റും ഫിൽറ്റർ ചെയ്യാൻ 2-3 മണിക്കൂർ എടുക്കാം. ഈ ദീർഘമായ പ്രക്രിയ സ്വയം ചെയ്യാൻ നിങ്ങൾക്ക് താൽപ്പര്യമില്ലെങ്കിൽ, ഫിൽറ്റർ ചെയ്ത ഡേറ്റാസെറ്റ് നിങ്ങൾക്ക് ഡൗൺലോഡ് ചെയ്യാനായി Hub-ൽ ഞങ്ങൾ ലഭ്യമാക്കിയിട്ടുണ്ട്: + +```py +from datasets import load_dataset, DatasetDict + +ds_train = load_dataset("huggingface-course/codeparrot-ds-train", split="train") +ds_valid = load_dataset("huggingface-course/codeparrot-ds-valid", split="validation") + +raw_datasets = DatasetDict( + { + "train": ds_train, # .shuffle().select(range(50000)), + "valid": ds_valid, # .shuffle().select(range(500)) + } +) + +raw_datasets +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['repo_name', 'path', 'copies', 'size', 'content', 'license'], + num_rows: 606720 + }) + valid: Dataset({ + features: ['repo_name', 'path', 'copies', 'size', 'content', 'license'], + num_rows: 3322 + }) +}) +``` + +> [!TIP] +> ലാംഗ്വേജ് മോഡൽ പ്രീട്രെയിൻ ചെയ്യാൻ കുറച്ച് സമയമെടുക്കും. മുകളിലുള്ള രണ്ട് ഭാഗിക വരികൾ അൺകമന്റ് ചെയ്ത്, ഡേറ്റയുടെ ഒരു സാമ്പിളിൽ ആദ്യം ട്രെയിനിംഗ് ലൂപ്പ് റൺ ചെയ്ത്, ട്രെയിനിംഗ് വിജയകരമായി പൂർത്തിയാകുന്നുവെന്നും മോഡലുകൾ സേവ് ചെയ്യപ്പെടുന്നുവെന്നും ഉറപ്പാക്കാൻ ഞങ്ങൾ നിർദ്ദേശിക്കുന്നു. ഒരു ഫോൾഡർ സൃഷ്ടിക്കാൻ മറന്നതുകൊണ്ടോ ട്രെയിനിംഗ് ലൂപ്പിന്റെ അവസാനം ഒരു അക്ഷരത്തെറ്റ് ഉള്ളതുകൊണ്ടോ അവസാന ഘട്ടത്തിൽ ഒരു ട്രെയിനിംഗ് റൺ പരാജയപ്പെടുന്നതിനെക്കാൾ നിരാശാജനകമായി മറ്റൊന്നുമില്ല! + +ഡേറ്റാസെറ്റിൽ നിന്നുള്ള ഒരു ഉദാഹരണം നോക്കാം. ഓരോ ഫീൽഡിന്റെയും ആദ്യത്തെ 200 അക്ഷരങ്ങൾ (characters) മാത്രം നമ്മൾ കാണിക്കും: + +```py +for key in raw_datasets["train"][0]: + print(f"{key.upper()}: {raw_datasets['train'][0][key][:200]}") +``` + +```python out +'REPO_NAME: kmike/scikit-learn' +'PATH: sklearn/utils/__init__.py' +'COPIES: 3' +'SIZE: 10094' +'''CONTENT: """ +The :mod:`sklearn.utils` module includes various utilites. +""" + +from collections import Sequence + +import numpy as np +from scipy.sparse import issparse +import warnings + +from .murmurhash import murm +LICENSE: bsd-3-clause''' +``` + +നമ്മുടെ മോഡൽ ട്രെയിൻ ചെയ്യേണ്ട കോഡ് `content` ഫീൽഡിലാണ് ഉള്ളതെന്ന് നമുക്ക് കാണാം. ഇപ്പോൾ നമുക്ക് ഒരു ഡേറ്റാസെറ്റ് ഉള്ളതിനാൽ, പ്രീട്രെയിനിംഗിന് അനുയോജ്യമായ ഒരു ഫോർമാറ്റിലാകുന്ന വിധത്തിൽ ടെക്‌സ്‌റ്റുകൾ തയ്യാറാക്കേണ്ടതുണ്ട്. + +## ഡേറ്റാസെറ്റ് തയ്യാറാക്കുന്നു[[preparing-the-dataset]] + + + +ട്രെയിനിംഗിന് ഉപയോഗിക്കാൻ കഴിയുന്ന വിധത്തിൽ ഡേറ്റ ടോക്കണൈസ് ചെയ്യുകയാണ് ആദ്യ ഘട്ടം. ചെറിയ ഫംഗ്‌ഷൻ കോളുകൾ ഓട്ടോകംപ്ലീറ്റ് ചെയ്യുകയാണ് നമ്മുടെ പ്രധാന ലക്ഷ്യം എന്നതിനാൽ, കോൺടെക്‌സ്‌റ്റ് സൈസ് (context size) താരതമ്യേന ചെറുതായി നിലനിർത്താം. മോഡൽ വളരെ വേഗത്തിൽ ട്രെയിൻ ചെയ്യാമെന്നും ഗണ്യമായി കുറഞ്ഞ മെമ്മറി മതിയെന്നുമുള്ള ഗുണം ഇതിനുണ്ട്. നിങ്ങളുടെ ആപ്ലിക്കേഷന് കൂടുതൽ കോൺടെക്‌സ്‌റ്റ് ഉണ്ടായിരിക്കുന്നത് പ്രധാനമാണെങ്കിൽ (ഉദാഹരണത്തിന്, ഫംഗ്‌ഷൻ ഡെഫനിഷൻ അടങ്ങിയ ഒരു ഫയലിനെ അടിസ്ഥാനമാക്കി യൂണിറ്റ് ടെസ്‌റ്റുകൾ എഴുതാൻ മോഡൽ വേണമെങ്കിൽ), ആ സംഖ്യ കൂട്ടാൻ മറക്കരുത്; എന്നാൽ ഇതോടൊപ്പം GPU മെമ്മറി ഉപയോഗവും കൂടുമെന്നത് ഓർമ്മയിൽ വയ്ക്കുക. തൽക്കാലം, GPT-2-ലും GPT-3-ലും ഉപയോഗിക്കുന്ന യഥാക്രമം 1,024, 2,048 എന്നിവയ്ക്ക് പകരം, കോൺടെക്‌സ്‌റ്റ് സൈസ് 128 ടോക്കണുകളായി നമുക്ക് നിശ്ചയിക്കാം. + +മിക്ക ഡോക്യുമെന്റുകളിലും 128-ൽ വളരെ കൂടുതൽ ടോക്കണുകൾ ഉണ്ടാകും, അതിനാൽ ഇൻപുട്ടുകളെ പരമാവധി ദൈർഘ്യത്തിലേക്ക് വെറുതെ ട്രങ്കേറ്റ് ചെയ്യുന്നത് (truncate) നമ്മുടെ ഡേറ്റാസെറ്റിന്റെ വലിയൊരു ഭാഗം ഇല്ലാതാക്കും. പകരം, [അധ്യായം 6](/course/chapter6/4)-ൽ ചെയ്തതുപോലെ, മുഴുവൻ ഇൻപുട്ടും ടോക്കണൈസ് ചെയ്ത് അതിനെ പല ചങ്കുകളായി (chunks) വിഭജിക്കാൻ `return_overflowing_tokens` ഓപ്‌ഷൻ നമ്മൾ ഉപയോഗിക്കും. സൃഷ്ടിക്കപ്പെട്ട ഓരോ ചങ്കിന്റെയും ദൈർഘ്യം സ്വയമേവ റിട്ടേൺ ചെയ്യാൻ `return_length` ഓപ്‌ഷനും നമ്മൾ ഉപയോഗിക്കും. പലപ്പോഴും അവസാനത്തെ ചങ്ക് കോൺടെക്‌സ്‌റ്റ് സൈസിനെക്കാൾ ചെറുതായിരിക്കും; പാഡിംഗ് പ്രശ്നങ്ങൾ ഒഴിവാക്കാൻ ഈ കഷണങ്ങൾ നമ്മൾ ഒഴിവാക്കും. എന്തായാലും നമുക്ക് ധാരാളം ഡേറ്റ ഉള്ളതിനാൽ അവ യഥാർത്ഥത്തിൽ നമുക്ക് ആവശ്യമില്ല. + +
+ഒരു വലിയ ടെക്‌സ്‌റ്റിനെ പല കഷണങ്ങളായി മുറിക്കുന്നു. + +
+ +ആദ്യത്തെ രണ്ട് ഉദാഹരണങ്ങൾ നോക്കിക്കൊണ്ട് ഇത് കൃത്യമായി എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് കാണാം: + +```py +from transformers import AutoTokenizer + +context_length = 128 +tokenizer = AutoTokenizer.from_pretrained("huggingface-course/code-search-net-tokenizer") + +outputs = tokenizer( + raw_datasets["train"][:2]["content"], + truncation=True, + max_length=context_length, + return_overflowing_tokens=True, + return_length=True, +) + +print(f"Input IDs length: {len(outputs['input_ids'])}") +print(f"Input chunk lengths: {(outputs['length'])}") +print(f"Chunk mapping: {outputs['overflow_to_sample_mapping']}") +``` + +```python out +Input IDs length: 34 +Input chunk lengths: [128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 117, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 41] +Chunk mapping: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] +``` + +ആ രണ്ട് ഉദാഹരണങ്ങളിൽ നിന്ന് മൊത്തം 34 സെഗ്‌മെന്റുകൾ നമുക്ക് ലഭിക്കുന്നതായി കാണാം. ചങ്കുകളുടെ ദൈർഘ്യം നോക്കിയാൽ, രണ്ട് ഡോക്യുമെന്റുകളുടെയും അവസാനത്തെ ചങ്കുകളിൽ 128-ൽ കുറവ് ടോക്കണുകളാണ് ഉള്ളതെന്ന് കാണാം (യഥാക്രമം 117-ഉം 41-ഉം). നമ്മുടെ മൊത്തം ചങ്കുകളുടെ ഒരു ചെറിയ അംശം മാത്രമാണ് ഇവ, അതിനാൽ ഇവ സുരക്ഷിതമായി ഒഴിവാക്കാം. `overflow_to_sample_mapping` ഫീൽഡ് ഉപയോഗിച്ച്, ഏത് ചങ്കുകൾ ഏത് ഇൻപുട്ട് സാമ്പിളുകളുടേതായിരുന്നു എന്നും നമുക്ക് പുനർനിർമ്മിക്കാം. + +ഈ ഓപ്പറേഷനിലൂടെ 🤗 Datasets-ലെ `Dataset.map()` ഫംഗ്‌ഷന്റെ ഉപകാരപ്രദമായ ഒരു സവിശേഷത നമ്മൾ ഉപയോഗിക്കുന്നു: അതിന് ഒന്നിനൊന്ന് (one-to-one) മാപ്പുകൾ ആവശ്യമില്ല; [ഭാഗം 3](/course/chapter7/3)-ൽ നമ്മൾ കണ്ടതുപോലെ, ഇൻപുട്ട് ബാച്ചിനെക്കാൾ കൂടുതലോ കുറവോ എലമെന്റുകളുള്ള ബാച്ചുകൾ നമുക്ക് സൃഷ്ടിക്കാം. എലമെന്റുകളുടെ എണ്ണം മാറ്റുന്ന ഡേറ്റാ ഓഗ്മെന്റേഷൻ (data augmentation) അല്ലെങ്കിൽ ഡേറ്റാ ഫിൽറ്ററിംഗ് പോലുള്ള ഓപ്പറേഷനുകൾ ചെയ്യുമ്പോൾ ഇത് ഉപകാരപ്രദമാണ്. നമ്മുടെ കാര്യത്തിൽ, ഓരോ എലമെന്റും നിശ്ചിത കോൺടെക്‌സ്‌റ്റ് സൈസുള്ള ചങ്കുകളായി ടോക്കണൈസ് ചെയ്യുമ്പോൾ, ഓരോ ഡോക്യുമെന്റിൽ നിന്നും നമ്മൾ ധാരാളം സാമ്പിളുകൾ സൃഷ്ടിക്കുന്നു. നിലവിലുള്ള കോളങ്ങൾ ഡിലീറ്റ് ചെയ്യാൻ മാത്രം നമ്മൾ ഉറപ്പാക്കണം, കാരണം അവയുടെ വലിപ്പം പൊരുത്തപ്പെടുന്നില്ല. അവ നിലനിർത്തണമെങ്കിൽ, `Dataset.map()` കോളിനുള്ളിൽ അവയെ ഉചിതമായി ആവർത്തിച്ച് റിട്ടേൺ ചെയ്യാം: + +```py +def tokenize(element): + outputs = tokenizer( + element["content"], + truncation=True, + max_length=context_length, + return_overflowing_tokens=True, + return_length=True, + ) + input_batch = [] + for length, input_ids in zip(outputs["length"], outputs["input_ids"]): + if length == context_length: + input_batch.append(input_ids) + return {"input_ids": input_batch} + + +tokenized_datasets = raw_datasets.map( + tokenize, batched=True, remove_columns=raw_datasets["train"].column_names +) +tokenized_datasets +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['input_ids'], + num_rows: 16702061 + }) + valid: Dataset({ + features: ['input_ids'], + num_rows: 93164 + }) +}) +``` + +ഇപ്പോൾ നമുക്ക് 128 ടോക്കണുകൾ വീതമുള്ള 16.7 ദശലക്ഷം ഉദാഹരണങ്ങളുണ്ട്, അത് മൊത്തം ഏകദേശം 2.1 ബില്യൺ ടോക്കണുകൾക്ക് തുല്യമാണ്. താരതമ്യത്തിന്, OpenAI-യുടെ GPT-3, Codex മോഡലുകൾ യഥാക്രമം 300, 100 ബില്യൺ ടോക്കണുകളിലാണ് ട്രെയിൻ ചെയ്തിരിക്കുന്നത്; അതിൽ Codex മോഡലുകൾ GPT-3 ചെക്ക്‌പോയിന്റുകളിൽ നിന്നാണ് ഇനിഷ്യലൈസ് ചെയ്യപ്പെട്ടിരിക്കുന്നത്. നീണ്ടതും യോജിപ്പുള്ളതുമായ ടെക്‌സ്‌റ്റുകൾ ജനറേറ്റ് ചെയ്യാൻ കഴിയുന്ന ഈ മോഡലുകളോട് മത്സരിക്കുകയല്ല ഈ ഭാഗത്തിലെ നമ്മുടെ ലക്ഷ്യം, മറിച്ച് ഡേറ്റാ സയന്റിസ്‌റ്റുകൾക്ക് വേഗത്തിലുള്ള ഒരു ഓട്ടോകംപ്ലീറ്റ് സൗകര്യം നൽകുന്ന ചെറുതാക്കിയ ഒരു പതിപ്പ് നിർമ്മിക്കുകയാണ്. + +ഇപ്പോൾ ഡേറ്റാസെറ്റ് തയ്യാറായതിനാൽ, മോഡൽ സെറ്റപ്പ് ചെയ്യാം! + +> [!TIP] +> ✏️ **പരീക്ഷിച്ചുനോക്കൂ!** ചെറിയ കോൺടെക്‌സ്‌റ്റ് വിൻഡോകളാണ് നമ്മൾ ഉപയോഗിക്കുന്നത് എന്നതിനാൽ, കോൺടെക്‌സ്‌റ്റ് സൈസിനെക്കാൾ ചെറിയ എല്ലാ ചങ്കുകളും ഒഴിവാക്കുന്നത് ഇവിടെ വലിയൊരു പ്രശ്നമായിരുന്നില്ല. കോൺടെക്‌സ്‌റ്റ് സൈസ് കൂട്ടുമ്പോൾ (അല്ലെങ്കിൽ ചെറിയ ഡോക്യുമെന്റുകളുടെ ഒരു കോർപ്പസ് നിങ്ങളുടെ കൈവശമുണ്ടെങ്കിൽ), ഒഴിവാക്കപ്പെടുന്ന ചങ്കുകളുടെ അംശവും വർദ്ധിക്കും. ഡേറ്റ തയ്യാറാക്കാനുള്ള കൂടുതൽ കാര്യക്ഷമമായ ഒരു മാർഗ്ഗം, ഒരു ബാച്ചിലെ ടോക്കണൈസ് ചെയ്ത എല്ലാ സാമ്പിളുകളും ഇടയിൽ ഒരു `eos_token_id` ടോക്കൺ ചേർത്ത് കൂട്ടിച്ചേർക്കുകയും, തുടർന്ന് കൂട്ടിച്ചേർത്ത സീക്വൻസുകളിൽ ചങ്കിംഗ് നടത്തുകയും ചെയ്യുന്നതാണ്. ഒരു അഭ്യാസമായി, ആ സമീപനം ഉപയോഗപ്പെടുത്തുന്ന വിധത്തിൽ `tokenize()` ഫംഗ്‌ഷൻ പരിഷ്‌കരിക്കുക. ടോക്കൺ ID-കളുടെ പൂർണ്ണമായ സീക്വൻസ് ലഭിക്കാൻ `truncation=False` എന്ന് സെറ്റ് ചെയ്യുകയും ടോക്കണൈസറിൽ നിന്ന് മറ്റ് ആർഗ്യുമെന്റുകൾ നീക്കം ചെയ്യുകയും വേണമെന്നത് ശ്രദ്ധിക്കുക. + + +## ഒരു പുതിയ മോഡൽ ഇനിഷ്യലൈസ് ചെയ്യുന്നു[[initializing-a-new-model]] + +ഒരു GPT-2 മോഡൽ പുതുതായി ഇനിഷ്യലൈസ് ചെയ്യുകയാണ് നമ്മുടെ ആദ്യ ഘട്ടം. ചെറിയ GPT-2 മോഡലിന്റെ അതേ കോൺഫിഗറേഷൻ തന്നെ നമ്മുടെ മോഡലിനും നമ്മൾ ഉപയോഗിക്കും; അതിനാൽ പ്രീട്രെയിൻഡ് കോൺഫിഗറേഷൻ ലോഡ് ചെയ്ത്, ടോക്കണൈസറിന്റെ വലിപ്പം മോഡലിന്റെ വൊക്കാബുലറി വലിപ്പവുമായി പൊരുത്തപ്പെടുന്നുവെന്ന് ഉറപ്പാക്കി, `bos`, `eos` (സീക്വൻസിന്റെ ആരംഭവും അവസാനവും) ടോക്കൺ ID-കൾ നൽകുന്നു: + +{#if fw === 'pt'} + +```py +from transformers import AutoTokenizer, GPT2LMHeadModel, AutoConfig + +config = AutoConfig.from_pretrained( + "gpt2", + vocab_size=len(tokenizer), + n_ctx=context_length, + bos_token_id=tokenizer.bos_token_id, + eos_token_id=tokenizer.eos_token_id, +) +``` + +ആ കോൺഫിഗറേഷൻ ഉപയോഗിച്ച്, ഒരു പുതിയ മോഡൽ നമുക്ക് ലോഡ് ചെയ്യാം. `from_pretrained()` ഫംഗ്‌ഷൻ നമ്മൾ ഉപയോഗിക്കാത്ത ആദ്യ തവണയാണിത് എന്നത് ശ്രദ്ധിക്കുക, കാരണം യഥാർത്ഥത്തിൽ നമ്മൾ സ്വയം ഒരു മോഡൽ ഇനിഷ്യലൈസ് ചെയ്യുകയാണ്: + +```py +model = GPT2LMHeadModel(config) +model_size = sum(t.numel() for t in model.parameters()) +print(f"GPT-2 size: {model_size/1000**2:.1f}M parameters") +``` + +```python out +GPT-2 size: 124.2M parameters +``` + +{:else} + +```py +from transformers import AutoTokenizer, TFGPT2LMHeadModel, AutoConfig + +config = AutoConfig.from_pretrained( + "gpt2", + vocab_size=len(tokenizer), + n_ctx=context_length, + bos_token_id=tokenizer.bos_token_id, + eos_token_id=tokenizer.eos_token_id, +) +``` + +ആ കോൺഫിഗറേഷൻ ഉപയോഗിച്ച്, ഒരു പുതിയ മോഡൽ നമുക്ക് ലോഡ് ചെയ്യാം. `from_pretrained()` ഫംഗ്‌ഷൻ നമ്മൾ ഉപയോഗിക്കാത്ത ആദ്യ തവണയാണിത് എന്നത് ശ്രദ്ധിക്കുക, കാരണം യഥാർത്ഥത്തിൽ നമ്മൾ സ്വയം ഒരു മോഡൽ ഇനിഷ്യലൈസ് ചെയ്യുകയാണ്: + +```py +model = TFGPT2LMHeadModel(config) +model(model.dummy_inputs) # Builds the model +model.summary() +``` + +```python out +_________________________________________________________________ +Layer (type) Output Shape Param # +================================================================= +transformer (TFGPT2MainLayer multiple 124242432 +================================================================= +Total params: 124,242,432 +Trainable params: 124,242,432 +Non-trainable params: 0 +_________________________________________________________________ +``` + +{/if} + +നമ്മുടെ മോഡലിന് നമ്മൾ ട്യൂൻ ചെയ്യേണ്ട 124M പാരാമീറ്ററുകളുണ്ട്. ട്രെയിനിംഗ് ആരംഭിക്കുന്നതിന് മുമ്പ്, ബാച്ചുകൾ സൃഷ്ടിക്കുന്ന കാര്യം ഏറ്റെടുക്കുന്ന ഒരു ഡേറ്റാ കൊളേറ്റർ (data collator) നമ്മൾ സെറ്റപ്പ് ചെയ്യേണ്ടതുണ്ട്. ലാംഗ്വേജ് മോഡലിംഗിനായി പ്രത്യേകം രൂപകൽപ്പന ചെയ്ത `DataCollatorForLanguageModeling` കൊളേറ്റർ നമുക്ക് ഉപയോഗിക്കാം (പേര് സൂക്ഷ്മമായി സൂചിപ്പിക്കുന്നതുപോലെ). ബാച്ചുകൾ സ്‌റ്റാക്ക് ചെയ്യുകയും പാഡ് ചെയ്യുകയും ചെയ്യുന്നതിനു പുറമേ, ലാംഗ്വേജ് മോഡൽ ലേബലുകൾ സൃഷ്ടിക്കുന്ന കാര്യവും ഇത് ഏറ്റെടുക്കുന്നു -- കോസൽ ലാംഗ്വേജ് മോഡലിംഗിൽ ഇൻപുട്ടുകൾ തന്നെയാണ് ലേബലുകളായും പ്രവർത്തിക്കുന്നത് (ഒരു എലമെന്റ് മാറ്റി), ട്രെയിനിംഗ് സമയത്ത് ഈ ഡേറ്റാ കൊളേറ്റർ അവ തത്സമയം സൃഷ്ടിക്കുന്നതിനാൽ `input_ids` നമ്മൾ ഡ്യൂപ്ലിക്കേറ്റ് ചെയ്യേണ്ടതില്ല. + +`DataCollatorForLanguageModeling` മാസ്‌ക്‌ഡ് ലാംഗ്വേജ് മോഡലിംഗും (MLM) കോസൽ ലാംഗ്വേജ് മോഡലിംഗും (CLM) പിന്തുണയ്ക്കുന്നു എന്നത് ശ്രദ്ധിക്കുക. ഡിഫോൾട്ടായി ഇത് MLM-നായി ഡേറ്റ തയ്യാറാക്കുന്നു, എന്നാൽ `mlm=False` എന്ന ആർഗ്യുമെന്റ് സെറ്റ് ചെയ്തുകൊണ്ട് CLM-ലേക്ക് നമുക്ക് മാറാം: + +{#if fw === 'pt'} + +```py +from transformers import DataCollatorForLanguageModeling + +tokenizer.pad_token = tokenizer.eos_token +data_collator = DataCollatorForLanguageModeling(tokenizer, mlm=False) +``` + +{:else} + +```py +from transformers import DataCollatorForLanguageModeling + +tokenizer.pad_token = tokenizer.eos_token +data_collator = DataCollatorForLanguageModeling(tokenizer, mlm=False, return_tensors="tf") +``` + +{/if} + +ഒരു ഉദാഹരണം നോക്കാം: + +```py +out = data_collator([tokenized_datasets["train"][i] for i in range(5)]) +for key in out: + print(f"{key} shape: {out[key].shape}") +``` + +{#if fw === 'pt'} + +```python out +input_ids shape: torch.Size([5, 128]) +attention_mask shape: torch.Size([5, 128]) +labels shape: torch.Size([5, 128]) +``` + +{:else} + +```python out +input_ids shape: (5, 128) +attention_mask shape: (5, 128) +labels shape: (5, 128) +``` + +{/if} + +ഉദാഹരണങ്ങൾ സ്‌റ്റാക്ക് ചെയ്യപ്പെട്ടിരിക്കുന്നുവെന്നും എല്ലാ ടെൻസറുകൾക്കും ഒരേ ഷേപ്പ് ആണെന്നും നമുക്ക് കാണാം. + +{#if fw === 'tf'} + +ഇപ്പോൾ, മുകളിൽ നമ്മൾ സൃഷ്ടിച്ച ഡേറ്റാ കൊളേറ്റർ ഉപയോഗിച്ച് നമ്മുടെ ഡേറ്റാസെറ്റുകളെ TensorFlow ഡേറ്റാസെറ്റുകളാക്കി മാറ്റാൻ `prepare_tf_dataset()` മെത്തേഡ് നമുക്ക് ഉപയോഗിക്കാം: + +```python +tf_train_dataset = model.prepare_tf_dataset( + tokenized_datasets["train"], + collate_fn=data_collator, + shuffle=True, + batch_size=32, +) +tf_eval_dataset = model.prepare_tf_dataset( + tokenized_datasets["valid"], + collate_fn=data_collator, + shuffle=False, + batch_size=32, +) +``` + +{/if} + +> [!WARNING] +> ⚠️ ഇൻപുട്ടുകളും ലേബലുകളും വിന്യസിക്കാൻ (align) അവയെ ഷിഫ്‌റ്റ് ചെയ്യുന്നത് മോഡലിനുള്ളിലാണ് നടക്കുന്നത്, അതിനാൽ ലേബലുകൾ സൃഷ്ടിക്കാൻ ഡേറ്റാ കൊളേറ്റർ ഇൻപുട്ടുകൾ കോപ്പി ചെയ്യുക മാത്രമേ ചെയ്യുന്നുള്ളൂ. + + +ഇപ്പോൾ നമ്മുടെ മോഡൽ യഥാർത്ഥത്തിൽ ട്രെയിൻ ചെയ്യാൻ ആവശ്യമായതെല്ലാം തയ്യാറാണ് -- അത്ര വലിയ പണിയൊന്നും ആയിരുന്നില്ല അല്ലേ! ട്രെയിനിംഗ് ആരംഭിക്കുന്നതിന് മുമ്പ് നമ്മൾ Hugging Face-ൽ ലോഗിൻ ചെയ്യണം. നിങ്ങൾ ഒരു നോട്ട്‌ബുക്കിലാണ് പ്രവർത്തിക്കുന്നതെങ്കിൽ, താഴെയുള്ള യൂട്ടിലിറ്റി ഫംഗ്‌ഷൻ ഉപയോഗിച്ച് അത് ചെയ്യാം: + +```python +from huggingface_hub import notebook_login + +notebook_login() +``` + +നിങ്ങളുടെ Hugging Face ലോഗിൻ വിവരങ്ങൾ (credentials) നൽകാൻ കഴിയുന്ന ഒരു വിജറ്റ് ഇത് പ്രദർശിപ്പിക്കും. + +നിങ്ങൾ ഒരു നോട്ട്‌ബുക്കിലല്ല പ്രവർത്തിക്കുന്നതെങ്കിൽ, നിങ്ങളുടെ ടെർമിനലിൽ താഴെയുള്ള വരി ടൈപ്പ് ചെയ്താൽ മതി: + +```bash +huggingface-cli login +``` + +{#if fw === 'pt'} + +ഇനി ബാക്കിയുള്ളത് ട്രെയിനിംഗ് ആർഗ്യുമെന്റുകൾ കോൺഫിഗർ ചെയ്ത് `Trainer` സ്‌റ്റാർട്ട് ചെയ്യുക മാത്രമാണ്. കുറച്ച് വാംഅപ്പോടു (warmup) കൂടിയ ഒരു കോസൈൻ ലേണിംഗ് റേറ്റ് ഷെഡ്യൂളും 256-ന്റെ ഒരു എഫക്റ്റീവ് ബാച്ച് സൈസും (`per_device_train_batch_size` * `gradient_accumulation_steps`) നമ്മൾ ഉപയോഗിക്കും. ഒരു ബാച്ച് മെമ്മറിയിൽ ഒതുങ്ങാത്തപ്പോഴാണ് ഗ്രേഡിയന്റ് അക്യുമുലേഷൻ (gradient accumulation) ഉപയോഗിക്കുന്നത്; പല ഫോർവേഡ്/ബാക്ക്‌വേഡ് പാസ്സുകളിലൂടെ ഇത് ഗ്രേഡിയന്റ് പടിപടിയായി കൂട്ടിച്ചേർക്കുന്നു. 🤗 Accelerate ഉപയോഗിച്ച് ട്രെയിനിംഗ് ലൂപ്പ് നിർമ്മിക്കുമ്പോൾ ഇത് പ്രവർത്തിക്കുന്നത് നമ്മൾ കാണും. + +```py +from transformers import Trainer, TrainingArguments + +args = TrainingArguments( + output_dir="codeparrot-ds", + per_device_train_batch_size=32, + per_device_eval_batch_size=32, + evaluation_strategy="steps", + eval_steps=5_000, + logging_steps=5_000, + gradient_accumulation_steps=8, + num_train_epochs=1, + weight_decay=0.1, + warmup_steps=1_000, + lr_scheduler_type="cosine", + learning_rate=5e-4, + save_steps=5_000, + fp16=True, + push_to_hub=True, +) + +trainer = Trainer( + model=model, + tokenizer=tokenizer, + args=args, + data_collator=data_collator, + train_dataset=tokenized_datasets["train"], + eval_dataset=tokenized_datasets["valid"], +) +``` + +ഇപ്പോൾ `Trainer` സ്‌റ്റാർട്ട് ചെയ്ത് ട്രെയിനിംഗ് പൂർത്തിയാകാൻ കാത്തിരുന്നാൽ മതി. മുഴുവൻ ട്രെയിനിംഗ് സെറ്റിലാണോ അതോ അതിന്റെ ഒരു ഉപവിഭാഗത്തിലാണോ റൺ ചെയ്യുന്നത് എന്നതിനെ ആശ്രയിച്ച്, ഇതിന് യഥാക്രമം 20 അല്ലെങ്കിൽ 2 മണിക്കൂർ എടുക്കും; അതിനാൽ കുറച്ച് കാപ്പിയും വായിക്കാൻ ഒരു നല്ല പുസ്തകവും കരുതിക്കോളൂ! + +```py +trainer.train() +``` + +ട്രെയിനിംഗ് പൂർത്തിയായ ശേഷം, മോഡലും ടോക്കണൈസറും Hub-ലേക്ക് പുഷ് ചെയ്യാം: + +```py +trainer.push_to_hub() +``` + +{:else} + +ഇനി ബാക്കിയുള്ളത് ട്രെയിനിംഗ് ഹൈപ്പർപാരാമീറ്ററുകൾ കോൺഫിഗർ ചെയ്ത് `compile()`-ഉം `fit()`-ഉം വിളിക്കുക മാത്രമാണ്. ട്രെയിനിംഗിന്റെ സ്ഥിരത മെച്ചപ്പെടുത്താൻ കുറച്ച് വാംഅപ്പോടു (warmup) കൂടിയ ഒരു ലേണിംഗ് റേറ്റ് ഷെഡ്യൂൾ നമ്മൾ ഉപയോഗിക്കും: + +```py +from transformers import create_optimizer +import tensorflow as tf + +num_train_steps = len(tf_train_dataset) +optimizer, schedule = create_optimizer( + init_lr=5e-5, + num_warmup_steps=1_000, + num_train_steps=num_train_steps, + weight_decay_rate=0.01, +) +model.compile(optimizer=optimizer) + +# Train in mixed-precision float16 +tf.keras.mixed_precision.set_global_policy("mixed_float16") +``` + +ഇപ്പോൾ `model.fit()` വിളിച്ച് ട്രെയിനിംഗ് പൂർത്തിയാകാൻ കാത്തിരുന്നാൽ മതി. മുഴുവൻ ട്രെയിനിംഗ് സെറ്റിലാണോ അതോ അതിന്റെ ഒരു ഉപവിഭാഗത്തിലാണോ റൺ ചെയ്യുന്നത് എന്നതിനെ ആശ്രയിച്ച്, ഇതിന് യഥാക്രമം 20 അല്ലെങ്കിൽ 2 മണിക്കൂർ എടുക്കും; അതിനാൽ കുറച്ച് കാപ്പിയും വായിക്കാൻ ഒരു നല്ല പുസ്തകവും കരുതിക്കോളൂ! ട്രെയിനിംഗ് പൂർത്തിയായ ശേഷം മോഡലും ടോക്കണൈസറും Hub-ലേക്ക് പുഷ് ചെയ്യാം: + +```py +from transformers.keras_callbacks import PushToHubCallback + +callback = PushToHubCallback(output_dir="codeparrot-ds", tokenizer=tokenizer) + +model.fit(tf_train_dataset, validation_data=tf_eval_dataset, callbacks=[callback]) +``` + +{/if} + +> [!TIP] +> ✏️ **പരീക്ഷിച്ചുനോക്കൂ!** റോ ടെക്‌സ്‌റ്റുകളിൽ നിന്ന് GPT-2 ട്രെയിൻ ചെയ്യുന്നതിലേക്ക് എത്താൻ `TrainingArguments`-ന് പുറമേ ഏകദേശം 30 വരി കോഡ് മാത്രമേ നമുക്ക് വേണ്ടിവന്നുള്ളൂ. നിങ്ങളുടെ സ്വന്തം ഡേറ്റാസെറ്റിൽ ഇത് പരീക്ഷിച്ചുനോക്കി നല്ല ഫലങ്ങൾ ലഭിക്കുന്നുണ്ടോ എന്ന് കാണുക! + +> [!TIP] +> {#if fw === 'pt'} +> +> 💡 ഒന്നിലധികം GPU-കളുള്ള ഒരു മെഷീനിലേക്ക് നിങ്ങൾക്ക് ആക്‌സസ് ഉണ്ടെങ്കിൽ, കോഡ് അവിടെ റൺ ചെയ്യാൻ ശ്രമിക്കുക. `Trainer` ഒന്നിലധികം മെഷീനുകൾ സ്വയമേവ കൈകാര്യം ചെയ്യുന്നു, ഇത് ട്രെയിനിംഗ് വളരെയധികം വേഗത്തിലാക്കും. +> +> {:else} +> +> 💡 ഒന്നിലധികം GPU-കളുള്ള ഒരു മെഷീനിലേക്ക് നിങ്ങൾക്ക് ആക്‌സസ് ഉണ്ടെങ്കിൽ, ട്രെയിനിംഗ് ഗണ്യമായി വേഗത്തിലാക്കാൻ ഒരു `MirroredStrategy` കോൺടെക്‌സ്‌റ്റ് ഉപയോഗിച്ചുനോക്കാം. നിങ്ങൾ ഒരു `tf.distribute.MirroredStrategy` ഒബ്‌ജക്റ്റ് സൃഷ്ടിക്കുകയും, ഏതെങ്കിലും `to_tf_dataset()` അല്ലെങ്കിൽ `prepare_tf_dataset()` മെത്തേഡുകളും, മോഡൽ സൃഷ്ടിക്കുന്നതും, `fit()` കോളും എല്ലാം അതിന്റെ `scope()` കോൺടെക്‌സ്‌റ്റിനുള്ളിലാണ് റൺ ചെയ്യുന്നതെന്ന് ഉറപ്പാക്കുകയും വേണം. ഇതേക്കുറിച്ചുള്ള ഡോക്യുമെന്റേഷൻ നിങ്ങൾക്ക് [ഇവിടെ](https://www.tensorflow.org/guide/distributed_training#use_tfdistributestrategy_with_keras_modelfit) കാണാം. +> +> {/if} + +## ഒരു പൈപ്പ്‌ലൈൻ ഉപയോഗിച്ചുള്ള കോഡ് ജനറേഷൻ[[code-generation-with-a-pipeline]] + +ഇപ്പോഴാണ് സത്യം തെളിയുന്ന നിമിഷം: ട്രെയിൻ ചെയ്ത മോഡൽ യഥാർത്ഥത്തിൽ എത്ര നന്നായി പ്രവർത്തിക്കുന്നു എന്ന് നോക്കാം! ലോസ് ക്രമമായി കുറഞ്ഞുവന്നതായി ലോഗുകളിൽ നമുക്ക് കാണാം, എന്നാൽ മോഡലിനെ ശരിക്കും പരീക്ഷിക്കാൻ ചില പ്രോംപ്‌റ്റുകളിൽ അത് എത്ര നന്നായി പ്രവർത്തിക്കുന്നു എന്ന് നോക്കാം. അതിനായി മോഡലിനെ ഒരു ടെക്‌സ്‌റ്റ് ജനറേഷൻ `pipeline`-ൽ പൊതിയും (wrap), വേഗത്തിലുള്ള ജനറേഷനുകൾക്കായി ഒരു GPU ലഭ്യമാണെങ്കിൽ അതിനെ GPU-വിലേക്ക് മാറ്റുകയും ചെയ്യും: + +{#if fw === 'pt'} + +```py +import torch +from transformers import pipeline + +device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu") +pipe = pipeline( + "text-generation", model="huggingface-course/codeparrot-ds", device=device +) +``` + +{:else} + +```py +from transformers import pipeline + +course_model = TFGPT2LMHeadModel.from_pretrained("huggingface-course/codeparrot-ds") +course_tokenizer = AutoTokenizer.from_pretrained("huggingface-course/codeparrot-ds") +pipe = pipeline( + "text-generation", model=course_model, tokenizer=course_tokenizer, device=0 +) +``` + +{/if} + +ഒരു സ്‌കാറ്റർ പ്ലോട്ട് സൃഷ്ടിക്കുക എന്ന ലളിതമായ ടാസ്‌കിൽ നിന്ന് തുടങ്ങാം: + +```py +txt = """\ +# create some data +x = np.random.randn(100) +y = np.random.randn(100) + +# create scatter plot with x, y +""" +print(pipe(txt, num_return_sequences=1)[0]["generated_text"]) +``` + +```python out +# create some data +x = np.random.randn(100) +y = np.random.randn(100) + +# create scatter plot with x, y +plt.scatter(x, y) + +# create scatter +``` + +ഫലം ശരിയാണെന്ന് തോന്നുന്നു. ഒരു `pandas` ഓപ്പറേഷനും ഇത് പ്രവർത്തിക്കുമോ? രണ്ട് അറേകളിൽ നിന്ന് ഒരു `DataFrame` സൃഷ്ടിക്കാൻ കഴിയുമോ എന്ന് നോക്കാം: + +```py +txt = """\ +# create some data +x = np.random.randn(100) +y = np.random.randn(100) + +# create dataframe from x and y +""" +print(pipe(txt, num_return_sequences=1)[0]["generated_text"]) +``` + +```python out +# create some data +x = np.random.randn(100) +y = np.random.randn(100) + +# create dataframe from x and y +df = pd.DataFrame({'x': x, 'y': y}) +df.insert(0,'x', x) +for +``` + +കൊള്ളാം, അതാണ് ശരിയായ ഉത്തരം -- എന്നാൽ പിന്നീട് അത് `x` എന്ന കോളം വീണ്ടും ഇൻസേർട്ട് ചെയ്യുന്നു. ജനറേറ്റ് ചെയ്യുന്ന ടോക്കണുകളുടെ എണ്ണം പരിമിതമായതിനാൽ, തുടർന്നുള്ള `for` ലൂപ്പ് മുറിഞ്ഞുപോയിരിക്കുന്നു. കുറച്ചുകൂടി സങ്കീർണ്ണമായ എന്തെങ്കിലും ചെയ്യാനും `groupby` ഓപ്പറേഷൻ ഉപയോഗിക്കാൻ മോഡലിന്റെ സഹായം തേടാനും കഴിയുമോ എന്ന് നോക്കാം: + +```py +txt = """\ +# dataframe with profession, income and name +df = pd.DataFrame({'profession': x, 'income':y, 'name': z}) + +# calculate the mean income per profession +""" +print(pipe(txt, num_return_sequences=1)[0]["generated_text"]) +``` + +```python out +# dataframe with profession, income and name +df = pd.DataFrame({'profession': x, 'income':y, 'name': z}) + +# calculate the mean income per profession +profession = df.groupby(['profession']).mean() + +# compute the +``` + +മോശമല്ല; അതാണ് ഇത് ചെയ്യാനുള്ള ശരിയായ വഴി. അവസാനമായി, `scikit-learn`-നും ഇത് ഉപയോഗിക്കാനും ഒരു Random Forest മോഡൽ സെറ്റപ്പ് ചെയ്യാനും കഴിയുമോ എന്ന് നോക്കാം: + +```py +txt = """ +# import random forest regressor from scikit-learn +from sklearn.ensemble import RandomForestRegressor + +# fit random forest model with 300 estimators on X, y: +""" +print(pipe(txt, num_return_sequences=1)[0]["generated_text"]) +``` + +```python out +# import random forest regressor from scikit-learn +from sklearn.ensemble import RandomForestRegressor + +# fit random forest model with 300 estimators on X, y: +rf = RandomForestRegressor(n_estimators=300, random_state=random_state, max_depth=3) +rf.fit(X, y) +rf +``` + +{#if fw === 'tf'} + +ഈ ചുരുക്കം ഉദാഹരണങ്ങൾ നോക്കിയാൽ, Python ഡേറ്റാ സയൻസ് സ്‌റ്റാക്കിന്റെ സിന്റാക്‌സിന്റെ ഒരു ഭാഗം മോഡൽ പഠിച്ചിട്ടുണ്ടെന്ന് തോന്നുന്നു. തീർച്ചയായും, യഥാർത്ഥ ലോകത്ത് ഡിപ്ലോയ് ചെയ്യുന്നതിന് മുമ്പ് മോഡലിനെ കൂടുതൽ സമഗ്രമായി ഇവാല്യുവേറ്റ് ചെയ്യേണ്ടതുണ്ട്, എന്നാൽ ഇത് ഇപ്പോഴും ശ്രദ്ധേയമായ ഒരു പ്രോട്ടോടൈപ്പാണ്. + +{:else} + +ഈ ചുരുക്കം ഉദാഹരണങ്ങൾ നോക്കിയാൽ, Python ഡേറ്റാ സയൻസ് സ്‌റ്റാക്കിന്റെ സിന്റാക്‌സിന്റെ ഒരു ഭാഗം മോഡൽ പഠിച്ചിട്ടുണ്ടെന്ന് തോന്നുന്നു (തീർച്ചയായും, യഥാർത്ഥ ലോകത്ത് മോഡൽ ഡിപ്ലോയ് ചെയ്യുന്നതിന് മുമ്പ് അതിനെ കൂടുതൽ സമഗ്രമായി ഇവാല്യുവേറ്റ് ചെയ്യേണ്ടതുണ്ട്). എന്നിരുന്നാലും, ഒരു നിശ്ചിത ഉപയോഗ സാഹചര്യത്തിന് ആവശ്യമായ പ്രകടനം കൈവരിക്കാൻ ചിലപ്പോൾ മോഡൽ ട്രെയിനിംഗിൽ കൂടുതൽ കസ്‌റ്റമൈസേഷൻ ആവശ്യമായി വരും. ഉദാഹരണത്തിന്, ബാച്ച് സൈസ് ഡൈനാമിക്കായി അപ്‌ഡേറ്റ് ചെയ്യാനോ, മോശം ഉദാഹരണങ്ങളെ തത്സമയം ഒഴിവാക്കുന്ന ഒരു കണ്ടീഷണൽ ട്രെയിനിംഗ് ലൂപ്പ് വേണമെന്നോ നമ്മൾ ആഗ്രഹിച്ചാലോ? `Trainer`-നെ സബ്‌ക്ലാസ് ചെയ്ത് ആവശ്യമായ മാറ്റങ്ങൾ ചേർക്കുകയാണ് ഒരു വഴി, എന്നാൽ ചിലപ്പോൾ ട്രെയിനിംഗ് ലൂപ്പ് പൂജ്യത്തിൽ നിന്ന് എഴുതുന്നതാണ് കൂടുതൽ ലളിതം. അവിടെയാണ് 🤗 Accelerate കടന്നുവരുന്നത്. + +{/if} + +{#if fw === 'pt'} + +## 🤗 Accelerate ഉപയോഗിച്ചുള്ള ട്രെയിനിംഗ്[[training-with-accelerate]] + +കുറച്ച് കസ്‌റ്റമൈസേഷൻ അനുവദിക്കുന്ന `Trainer` ഉപയോഗിച്ച് ഒരു മോഡൽ എങ്ങനെ ട്രെയിൻ ചെയ്യാമെന്ന് നമ്മൾ കണ്ടു. എന്നിരുന്നാലും, ചിലപ്പോൾ ട്രെയിനിംഗ് ലൂപ്പിന്മേൽ പൂർണ്ണ നിയന്ത്രണം നമുക്ക് വേണ്ടിവരും, അല്ലെങ്കിൽ അസാധാരണമായ ചില മാറ്റങ്ങൾ വരുത്താൻ നമ്മൾ ആഗ്രഹിക്കും. ഈ സാഹചര്യത്തിൽ 🤗 Accelerate ഒരു മികച്ച തിരഞ്ഞെടുപ്പാണ്; നമ്മുടെ മോഡൽ ട്രെയിൻ ചെയ്യാൻ അത് ഉപയോഗിക്കുന്നതിനുള്ള ഘട്ടങ്ങളിലൂടെ ഈ ഭാഗത്തിൽ നമ്മൾ കടന്നുപോകും. കാര്യങ്ങൾ കൂടുതൽ രസകരമാക്കാൻ, ട്രെയിനിംഗ് ലൂപ്പിൽ ഒരു ട്വിസ്‌റ്റും നമ്മൾ ചേർക്കും. + + + +ഡേറ്റാ സയൻസ് ലൈബ്രറികൾക്കായുള്ള അർത്ഥവത്തായ ഓട്ടോകംപ്ലീഷനിലാണ് നമുക്ക് പ്രധാനമായും താൽപ്പര്യം എന്നതിനാൽ, ഈ ലൈബ്രറികൾ കൂടുതൽ ഉപയോഗിക്കുന്ന ട്രെയിനിംഗ് സാമ്പിളുകൾക്ക് കൂടുതൽ വെയ്‌റ്റ് നൽകുന്നത് അർത്ഥവത്താണ്. `plt`, `pd`, `sk`, `fit`, `predict` തുടങ്ങിയ കീവേഡുകൾ ഉപയോഗിച്ച് ഈ ഉദാഹരണങ്ങൾ നമുക്ക് എളുപ്പത്തിൽ തിരിച്ചറിയാം; `matplotlib.pyplot`, `pandas`, `sklearn` എന്നിവയ്ക്കുള്ള ഏറ്റവും സാധാരണമായ ഇംപോർട്ട് പേരുകളും, അവസാനത്തേതിന്റെ fit/predict പാറ്റേണുമാണ് ഇവ. ഇവ ഓരോന്നും ഒറ്റ ടോക്കണായി പ്രതിനിധീകരിക്കപ്പെടുന്നുവെങ്കിൽ, ഇൻപുട്ട് സീക്വൻസിൽ അവ വരുന്നുണ്ടോ എന്ന് നമുക്ക് എളുപ്പത്തിൽ പരിശോധിക്കാം. ടോക്കണുകൾക്ക് ഒരു വൈറ്റ്‌സ്‌പേസ് പ്രിഫിക്‌സ് ഉണ്ടാകാം, അതിനാൽ ടോക്കണൈസർ വൊക്കാബുലറിയിൽ ആ പതിപ്പുകളും നമ്മൾ പരിശോധിക്കും. ഇത് പ്രവർത്തിക്കുന്നുണ്ടെന്ന് ഉറപ്പാക്കാൻ, ഒന്നിലധികം ടോക്കണുകളായി വിഭജിക്കപ്പെടേണ്ട ഒരു ടെസ്‌റ്റ് ടോക്കണും നമ്മൾ ചേർക്കും: + +```py +keytoken_ids = [] +for keyword in [ + "plt", + "pd", + "sk", + "fit", + "predict", + " plt", + " pd", + " sk", + " fit", + " predict", + "testtest", +]: + ids = tokenizer([keyword]).input_ids[0] + if len(ids) == 1: + keytoken_ids.append(ids[0]) + else: + print(f"Keyword has not single token: {keyword}") +``` + +```python out +'Keyword has not single token: testtest' +``` + +കൊള്ളാം, അത് നന്നായി പ്രവർത്തിക്കുന്നതായി തോന്നുന്നു! ഇൻപുട്ട് സീക്വൻസ്, ലോജിറ്റുകൾ (logits), നമ്മൾ ഇപ്പോൾ തിരഞ്ഞെടുത്ത കീ ടോക്കണുകൾ എന്നിവ ഇൻപുട്ടുകളായി സ്വീകരിക്കുന്ന ഒരു കസ്‌റ്റം ലോസ് ഫംഗ്‌ഷൻ ഇപ്പോൾ നമുക്ക് എഴുതാം. ആദ്യം ലോജിറ്റുകളും ഇൻപുട്ടുകളും നമ്മൾ വിന്യസിക്കണം (align): ഇൻപുട്ട് സീക്വൻസ് ഒന്ന് വലത്തോട്ട് ഷിഫ്‌റ്റ് ചെയ്തതാണ് ലേബലുകൾ, കാരണം അടുത്ത ടോക്കണാണ് നിലവിലെ ടോക്കണിന്റെ ലേബൽ. ഇൻപുട്ട് സീക്വൻസിന്റെ രണ്ടാമത്തെ ടോക്കണിൽ നിന്ന് ലേബലുകൾ ആരംഭിച്ചുകൊണ്ട് ഇത് നമുക്ക് സാധിക്കാം, കാരണം ആദ്യത്തെ ടോക്കണിനായി മോഡൽ എന്തായാലും ഒരു പ്രവചനം നടത്തുന്നില്ല. തുടർന്ന് അവസാനത്തെ ലോജിറ്റ് നമ്മൾ മുറിച്ചുമാറ്റുന്നു, കാരണം മുഴുവൻ ഇൻപുട്ട് സീക്വൻസിനും ശേഷം വരുന്ന ടോക്കണിന് നമുക്ക് ലേബൽ ഇല്ല. അതോടെ ഓരോ സാമ്പിളിനുമുള്ള ലോസ് കണക്കാക്കാനും ഓരോ സാമ്പിളിലും എല്ലാ കീവേഡുകളും എത്ര തവണ വരുന്നു എന്ന് എണ്ണാനും നമുക്ക് കഴിയും. അവസാനമായി, ആ എണ്ണങ്ങളെ വെയ്‌റ്റുകളായി ഉപയോഗിച്ച് എല്ലാ സാമ്പിളുകളുടെയും വെയ്‌റ്റഡ് ആവറേജ് (weighted average) നമ്മൾ കണക്കാക്കുന്നു. കീവേഡുകളൊന്നുമില്ലാത്ത എല്ലാ സാമ്പിളുകളും ഒഴിവാക്കാൻ നമ്മൾ ആഗ്രഹിക്കാത്തതിനാൽ, വെയ്‌റ്റുകളിലേക്ക് 1 കൂട്ടിച്ചേർക്കുന്നു: + +```py +from torch.nn import CrossEntropyLoss +import torch + + +def keytoken_weighted_loss(inputs, logits, keytoken_ids, alpha=1.0): + # Shift so that tokens < n predict n + shift_labels = inputs[..., 1:].contiguous() + shift_logits = logits[..., :-1, :].contiguous() + # Calculate per-token loss + loss_fct = CrossEntropyLoss(reduce=False) + loss = loss_fct(shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1)) + # Resize and average loss per sample + loss_per_sample = loss.view(shift_logits.size(0), shift_logits.size(1)).mean(axis=1) + # Calculate and scale weighting + weights = torch.stack([(inputs == kt).float() for kt in keytoken_ids]).sum( + axis=[0, 2] + ) + weights = alpha * (1.0 + weights) + # Calculate weighted average + weighted_loss = (loss_per_sample * weights).mean() + return weighted_loss +``` + +ഈ മികച്ച പുതിയ ലോസ് ഫംഗ്‌ഷൻ ഉപയോഗിച്ച് ട്രെയിനിംഗ് ആരംഭിക്കുന്നതിന് മുമ്പ്, ചില കാര്യങ്ങൾ നമ്മൾ തയ്യാറാക്കേണ്ടതുണ്ട്: + +- ഡേറ്റ ബാച്ചുകളായി ലോഡ് ചെയ്യാൻ നമുക്ക് ഡേറ്റാലോഡറുകൾ ആവശ്യമാണ്. +- വെയ്‌റ്റ് ഡികേ (weight decay) പാരാമീറ്ററുകൾ നമ്മൾ സെറ്റപ്പ് ചെയ്യേണ്ടതുണ്ട്. +- ഇടയ്ക്കിടെ ഇവാല്യുവേറ്റ് ചെയ്യാൻ നമ്മൾ ആഗ്രഹിക്കുന്നു, അതിനാൽ ഇവാല്യുവേഷൻ കോഡ് ഒരു ഫംഗ്‌ഷനിൽ പൊതിയുന്നത് അർത്ഥവത്താണ്. + +ഡേറ്റാലോഡറുകളിൽ നിന്ന് തുടങ്ങാം. ഡേറ്റാസെറ്റിന്റെ ഫോർമാറ്റ് `"torch"` എന്ന് സെറ്റ് ചെയ്യുക മാത്രമേ നമ്മൾ ചെയ്യേണ്ടതുള്ളൂ, തുടർന്ന് ഉചിതമായ ബാച്ച് സൈസോടെ അത് ഒരു PyTorch `DataLoader`-ലേക്ക് നൽകാം: + +```py +from torch.utils.data.dataloader import DataLoader + +tokenized_datasets.set_format("torch") +train_dataloader = DataLoader(tokenized_datasets["train"], batch_size=32, shuffle=True) +eval_dataloader = DataLoader(tokenized_datasets["valid"], batch_size=32) +``` + +അടുത്തതായി, ഏതൊക്കെ പാരാമീറ്ററുകൾക്കാണ് അധിക വെയ്‌റ്റ് ഡികേ ലഭിക്കുക എന്ന് ഒപ്‌റ്റിമൈസറിന് അറിയാൻ വേണ്ടി നമ്മൾ പാരാമീറ്ററുകളെ ഗ്രൂപ്പ് ചെയ്യുന്നു. സാധാരണയായി, എല്ലാ bias, LayerNorm വെയ്‌റ്റ് ടേമുകളും ഇതിൽ നിന്ന് ഒഴിവാക്കപ്പെടുന്നു; ഇത് എങ്ങനെ ചെയ്യാമെന്ന് ഇതാ: + +```py +weight_decay = 0.1 + + +def get_grouped_params(model, no_decay=["bias", "LayerNorm.weight"]): + params_with_wd, params_without_wd = [], [] + for n, p in model.named_parameters(): + if any(nd in n for nd in no_decay): + params_without_wd.append(p) + else: + params_with_wd.append(p) + return [ + {"params": params_with_wd, "weight_decay": weight_decay}, + {"params": params_without_wd, "weight_decay": 0.0}, + ] +``` + +ട്രെയിനിംഗ് സമയത്ത് വാലിഡേഷൻ സെറ്റിൽ മോഡലിനെ ക്രമമായി ഇവാല്യുവേറ്റ് ചെയ്യാൻ നമ്മൾ ആഗ്രഹിക്കുന്നതിനാൽ, അതിനായി ഒരു ഫംഗ്‌ഷനും എഴുതാം. ഇത് ഇവാല്യുവേഷൻ ഡേറ്റാലോഡറിലൂടെ കടന്നുപോയി എല്ലാ പ്രോസസ്സുകളിലുമുള്ള ലോസുകൾ ശേഖരിക്കുക മാത്രമേ ചെയ്യുന്നുള്ളൂ: + +```py +def evaluate(): + model.eval() + losses = [] + for step, batch in enumerate(eval_dataloader): + with torch.no_grad(): + outputs = model(batch["input_ids"], labels=batch["input_ids"]) + + losses.append(accelerator.gather(outputs.loss)) + loss = torch.mean(torch.cat(losses)) + try: + perplexity = torch.exp(loss) + except OverflowError: + perplexity = float("inf") + return loss.item(), perplexity.item() +``` + +`evaluate()` ഫംഗ്‌ഷൻ ഉപയോഗിച്ച് കൃത്യമായ ഇടവേളകളിൽ ലോസും [പെർപ്ലെക്‌സിറ്റിയും](/course/chapter7/3) നമുക്ക് റിപ്പോർട്ട് ചെയ്യാം. അടുത്തതായി, വീണ്ടും പൂജ്യത്തിൽ നിന്ന് ട്രെയിൻ ചെയ്യുന്നു എന്ന് ഉറപ്പാക്കാൻ നമ്മുടെ മോഡൽ വീണ്ടും നിർവചിക്കുന്നു: + +```py +model = GPT2LMHeadModel(config) +``` + +തുടർന്ന്, വെയ്‌റ്റ് ഡികേയ്ക്കായി പാരാമീറ്ററുകളെ വിഭജിക്കാൻ മുമ്പത്തെ ഫംഗ്‌ഷൻ ഉപയോഗിച്ച്, നമ്മുടെ ഒപ്‌റ്റിമൈസർ നിർവചിക്കാം: + +```py +from torch.optim import AdamW + +optimizer = AdamW(get_grouped_params(model), lr=5e-4) +``` + +ഇപ്പോൾ ട്രെയിനിംഗ് ആരംഭിക്കാൻ കഴിയുന്ന വിധത്തിൽ മോഡൽ, ഒപ്‌റ്റിമൈസർ, ഡേറ്റാലോഡറുകൾ എന്നിവ തയ്യാറാക്കാം: + +```py +from accelerate import Accelerator + +accelerator = Accelerator(fp16=True) + +model, optimizer, train_dataloader, eval_dataloader = accelerator.prepare( + model, optimizer, train_dataloader, eval_dataloader +) +``` + +> [!TIP] +> 🚨 നിങ്ങൾ ഒരു TPU-വിലാണ് ട്രെയിൻ ചെയ്യുന്നതെങ്കിൽ, മുകളിലുള്ള സെല്ലിൽ നിന്ന് ആരംഭിക്കുന്ന എല്ലാ കോഡും ഒരു പ്രത്യേക ട്രെയിനിംഗ് ഫംഗ്‌ഷനിലേക്ക് മാറ്റേണ്ടതുണ്ട്. കൂടുതൽ വിവരങ്ങൾക്ക് [അധ്യായം 3](/course/chapter3) കാണുക. + +നമ്മുടെ `train_dataloader` ഇപ്പോൾ `accelerator.prepare()`-ലേക്ക് അയച്ചതിനാൽ, ട്രെയിനിംഗ് സ്‌റ്റെപ്പുകളുടെ എണ്ണം കണക്കാക്കാൻ അതിന്റെ ദൈർഘ്യം നമുക്ക് ഉപയോഗിക്കാം. ഡേറ്റാലോഡർ തയ്യാറാക്കിയ ശേഷം മാത്രമേ എപ്പോഴും ഇത് ചെയ്യാവൂ എന്ന് ഓർക്കുക, കാരണം ആ മെത്തേഡ് അതിന്റെ ദൈർഘ്യം മാറ്റും. ലേണിംഗ് റേറ്റിൽ നിന്ന് 0-ലേക്കുള്ള ക്ലാസിക് ലീനിയർ ഷെഡ്യൂൾ നമ്മൾ ഉപയോഗിക്കുന്നു: + +```py +from transformers import get_scheduler + +num_train_epochs = 1 +num_update_steps_per_epoch = len(train_dataloader) +num_training_steps = num_train_epochs * num_update_steps_per_epoch + +lr_scheduler = get_scheduler( + name="linear", + optimizer=optimizer, + num_warmup_steps=1_000, + num_training_steps=num_training_steps, +) +``` + +അവസാനമായി, നമ്മുടെ മോഡൽ Hub-ലേക്ക് പുഷ് ചെയ്യാൻ, ഒരു വർക്കിംഗ് ഫോൾഡറിൽ ഒരു `Repository` ഒബ്‌ജക്റ്റ് സൃഷ്ടിക്കേണ്ടതുണ്ട്. നിങ്ങൾ ഇതുവരെ ലോഗിൻ ചെയ്തിട്ടില്ലെങ്കിൽ, ആദ്യം Hugging Face Hub-ൽ ലോഗിൻ ചെയ്യുക. നമ്മുടെ മോഡലിന് നൽകാൻ ആഗ്രഹിക്കുന്ന മോഡൽ ID-യിൽ നിന്ന് റിപ്പോസിറ്ററിയുടെ പേര് നമ്മൾ നിർണ്ണയിക്കും (`repo_name` നിങ്ങളുടെ ഇഷ്ടപ്രകാരം മാറ്റാൻ മടിക്കേണ്ടതില്ല; അതിൽ നിങ്ങളുടെ യൂസർനെയിം അടങ്ങിയിരിക്കണം എന്നേയുള്ളൂ, അതാണ് `get_full_repo_name()` ഫംഗ്‌ഷൻ ചെയ്യുന്നത്): + +```py +from huggingface_hub import Repository, get_full_repo_name + +model_name = "codeparrot-ds-accelerate" +repo_name = get_full_repo_name(model_name) +repo_name +``` + +```python out +'sgugger/codeparrot-ds-accelerate' +``` + +തുടർന്ന് ആ റിപ്പോസിറ്ററി ഒരു ലോക്കൽ ഫോൾഡറിലേക്ക് ക്ലോൺ ചെയ്യാം. അത് ഇതിനകം നിലവിലുണ്ടെങ്കിൽ, ഈ ലോക്കൽ ഫോൾഡർ നമ്മൾ പ്രവർത്തിക്കുന്ന റിപ്പോസിറ്ററിയുടെ നിലവിലുള്ള ഒരു ക്ലോൺ ആയിരിക്കണം: + +```py +output_dir = "codeparrot-ds-accelerate" +repo = Repository(output_dir, clone_from=repo_name) +``` + +`repo.push_to_hub()` മെത്തേഡ് വിളിച്ചുകൊണ്ട് `output_dir`-ൽ നമ്മൾ സേവ് ചെയ്യുന്ന എന്തും ഇപ്പോൾ അപ്‌ലോഡ് ചെയ്യാം. ഓരോ എപ്പോക്കിന്റെയും അവസാനം ഇടക്കാല മോഡലുകൾ അപ്‌ലോഡ് ചെയ്യാൻ ഇത് നമ്മെ സഹായിക്കും. + +ട്രെയിൻ ചെയ്യുന്നതിന് മുമ്പ്, ഇവാല്യുവേഷൻ ഫംഗ്‌ഷൻ ശരിയായി പ്രവർത്തിക്കുന്നുണ്ടോ എന്നറിയാൻ ഒരു ചെറിയ ടെസ്‌റ്റ് റൺ ചെയ്യാം: + +```py +evaluate() +``` + +```python out +(10.934126853942871, 56057.14453125) +``` + +ലോസിനും പെർപ്ലെക്‌സിറ്റിക്കും ഇവ വളരെ ഉയർന്ന മൂല്യങ്ങളാണ്, എന്നാൽ നമ്മൾ ഇതുവരെ മോഡൽ ട്രെയിൻ ചെയ്തിട്ടില്ലാത്തതിനാൽ അതിൽ അതിശയിക്കാനില്ല. അതോടെ, ട്രെയിനിംഗ് സ്‌ക്രിപ്‌റ്റിന്റെ പ്രധാന ഭാഗമായ ട്രെയിനിംഗ് ലൂപ്പ് എഴുതാൻ ആവശ്യമായതെല്ലാം നമ്മൾ തയ്യാറാക്കിക്കഴിഞ്ഞു. ട്രെയിനിംഗ് ലൂപ്പിൽ നമ്മൾ ഡേറ്റാലോഡറിലൂടെ ഇറ്ററേറ്റ് ചെയ്ത് ബാച്ചുകൾ മോഡലിലേക്ക് നൽകുന്നു. ലോജിറ്റുകൾ ഉപയോഗിച്ച്, നമ്മുടെ കസ്‌റ്റം ലോസ് ഫംഗ്‌ഷൻ തുടർന്ന് നമുക്ക് കണക്കാക്കാം. കൂടുതൽ സ്‌റ്റെപ്പുകൾ കൂട്ടിച്ചേർക്കുമ്പോൾ വലിയ ലോസുകൾ ഉണ്ടാകാതിരിക്കാൻ, ഗ്രേഡിയന്റ് അക്യുമുലേഷൻ സ്‌റ്റെപ്പുകളുടെ എണ്ണം കൊണ്ട് ലോസ് നമ്മൾ സ്‌കെയിൽ ചെയ്യുന്നു. ഒപ്‌റ്റിമൈസ് ചെയ്യുന്നതിന് മുമ്പ്, മികച്ച കൺവെർജൻസിനായി (convergence) ഗ്രേഡിയന്റുകൾ ക്ലിപ്പ് ചെയ്യുകയും ചെയ്യുന്നു. അവസാനമായി, ഓരോ കുറച്ച് സ്‌റ്റെപ്പുകൾ കഴിയുമ്പോഴും നമ്മുടെ പുതിയ `evaluate()` ഫംഗ്‌ഷൻ ഉപയോഗിച്ച് ഇവാല്യുവേഷൻ സെറ്റിൽ മോഡലിനെ ഇവാല്യുവേറ്റ് ചെയ്യുന്നു: + +```py +from tqdm.notebook import tqdm + +gradient_accumulation_steps = 8 +eval_steps = 5_000 + +model.train() +completed_steps = 0 +for epoch in range(num_train_epochs): + for step, batch in tqdm( + enumerate(train_dataloader, start=1), total=num_training_steps + ): + logits = model(batch["input_ids"]).logits + loss = keytoken_weighted_loss(batch["input_ids"], logits, keytoken_ids) + if step % 100 == 0: + accelerator.print( + { + "samples": step * samples_per_step, + "steps": completed_steps, + "loss/train": loss.item() * gradient_accumulation_steps, + } + ) + loss = loss / gradient_accumulation_steps + accelerator.backward(loss) + if step % gradient_accumulation_steps == 0: + accelerator.clip_grad_norm_(model.parameters(), 1.0) + optimizer.step() + lr_scheduler.step() + optimizer.zero_grad() + completed_steps += 1 + if (step % (eval_steps * gradient_accumulation_steps)) == 0: + eval_loss, perplexity = evaluate() + accelerator.print({"loss/eval": eval_loss, "perplexity": perplexity}) + model.train() + accelerator.wait_for_everyone() + unwrapped_model = accelerator.unwrap_model(model) + unwrapped_model.save_pretrained(output_dir, save_function=accelerator.save) + if accelerator.is_main_process: + tokenizer.save_pretrained(output_dir) + repo.push_to_hub( + commit_message=f"Training in progress step {step}", blocking=False + ) +``` + +അത്രമാത്രം -- GPT-2 പോലുള്ള കോസൽ ലാംഗ്വേജ് മോഡലുകൾക്കായി, നിങ്ങളുടെ ആവശ്യങ്ങൾക്കനുസരിച്ച് കൂടുതൽ കസ്‌റ്റമൈസ് ചെയ്യാവുന്ന, നിങ്ങളുടെ സ്വന്തം കസ്‌റ്റം ട്രെയിനിംഗ് ലൂപ്പ് ഇപ്പോൾ നിങ്ങൾക്കുണ്ട്. + +> [!TIP] +> ✏️ **പരീക്ഷിച്ചുനോക്കൂ!** നിങ്ങളുടെ ഉപയോഗ സാഹചര്യത്തിന് അനുയോജ്യമായ സ്വന്തം കസ്‌റ്റം ലോസ് ഫംഗ്‌ഷൻ സൃഷ്ടിക്കുക, അല്ലെങ്കിൽ ട്രെയിനിംഗ് ലൂപ്പിലേക്ക് മറ്റൊരു കസ്‌റ്റം സ്‌റ്റെപ്പ് ചേർക്കുക. + +> [!TIP] +> ✏️ **പരീക്ഷിച്ചുനോക്കൂ!** ദീർഘമായ ട്രെയിനിംഗ് പരീക്ഷണങ്ങൾ റൺ ചെയ്യുമ്പോൾ, TensorBoard അല്ലെങ്കിൽ Weights & Biases പോലുള്ള ടൂളുകൾ ഉപയോഗിച്ച് പ്രധാന മെട്രിക്കുകൾ ലോഗ് ചെയ്യുന്നത് നല്ലൊരു ആശയമാണ്. ട്രെയിനിംഗ് എങ്ങനെ പോകുന്നു എന്ന് എപ്പോഴും പരിശോധിക്കാൻ കഴിയുന്ന വിധത്തിൽ ട്രെയിനിംഗ് ലൂപ്പിലേക്ക് ശരിയായ ലോഗിംഗ് ചേർക്കുക. + +{/if} diff --git a/chapters/ml/chapter7/7.mdx b/chapters/ml/chapter7/7.mdx new file mode 100644 index 000000000..b1fa4a935 --- /dev/null +++ b/chapters/ml/chapter7/7.mdx @@ -0,0 +1,1191 @@ + + +# ചോദ്യോത്തരം (Question answering)[[question-answering]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +ഇനി ചോദ്യോത്തരത്തിലേക്ക് (question answering) കടക്കാം! ഈ ടാസ്‌ക്ക് പല രൂപങ്ങളിൽ വരുന്നുണ്ട്, എന്നാൽ ഈ ഭാഗത്തിൽ നമ്മൾ ശ്രദ്ധ കേന്ദ്രീകരിക്കുന്നത് *എക്‌സ്‌ട്രാക്റ്റീവ്* (extractive) ചോദ്യോത്തരം എന്ന് വിളിക്കുന്ന തരത്തിലാണ്. ഒരു ഡോക്യുമെന്റിനെക്കുറിച്ച് ചോദ്യങ്ങൾ ചോദിക്കുകയും, ആ ഡോക്യുമെന്റിനുള്ളിലെ _ടെക്‌സ്‌റ്റ് സ്‌പാനുകളായി_ (spans of text) ഉത്തരങ്ങൾ കണ്ടെത്തുകയും ചെയ്യുന്നതാണ് ഇതിൽ ഉൾപ്പെടുന്നത്. + + + +ഒരു കൂട്ടം Wikipedia ലേഖനങ്ങളെക്കുറിച്ച് ക്രൗഡ്‌വർക്കർമാർ ചോദിച്ച ചോദ്യങ്ങൾ അടങ്ങിയ [SQuAD ഡേറ്റാസെറ്റിൽ](https://rajpurkar.github.io/SQuAD-explorer/) നമ്മൾ ഒരു BERT മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യും. ഇതുപോലുള്ള പ്രവചനങ്ങൾ (predictions) കണക്കാക്കാൻ കഴിവുള്ള ഒരു മോഡൽ ഇത് നമുക്ക് നൽകും: + + + +ഈ ഭാഗത്തിൽ കാണിച്ചിരിക്കുന്ന കോഡ് ഉപയോഗിച്ച് ട്രെയിൻ ചെയ്ത് Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്ത മോഡലാണ് ഇവിടെ യഥാർത്ഥത്തിൽ പ്രദർശിപ്പിക്കുന്നത്. അത് [ഇവിടെ](https://huggingface.co/huggingface-course/bert-finetuned-squad?context=%F0%9F%A4%97+Transformers+is+backed+by+the+three+most+popular+deep+learning+libraries+%E2%80%94+Jax%2C+PyTorch+and+TensorFlow+%E2%80%94+with+a+seamless+integration+between+them.+It%27s+straightforward+to+train+your+models+with+one+before+loading+them+for+inference+with+the+other.&question=Which+deep+learning+libraries+back+%F0%9F%A4%97+Transformers%3F) കണ്ടെത്താനും പ്രവചനങ്ങൾ ഒന്നുകൂടി പരിശോധിക്കാനും നിങ്ങൾക്ക് കഴിയും. + +> [!TIP] +> 💡 BERT പോലുള്ള എൻകോഡർ-ഒൺലി (encoder-only) മോഡലുകൾ "Who invented the Transformer architecture?" പോലുള്ള വസ്തുതാപരമായ (factoid) ചോദ്യങ്ങൾക്ക് ഉത്തരങ്ങൾ എക്‌സ്‌ട്രാക്റ്റ് ചെയ്യുന്നതിൽ മികച്ചതായിരിക്കും, എന്നാൽ "Why is the sky blue?" പോലുള്ള തുറന്ന (open-ended) ചോദ്യങ്ങൾ നൽകുമ്പോൾ മോശമായി പ്രവർത്തിക്കും. കൂടുതൽ വെല്ലുവിളി നിറഞ്ഞ ഇത്തരം സന്ദർഭങ്ങളിൽ, [ടെക്‌സ്‌റ്റ് സമ്മറൈസേഷനോട്](/course/chapter7/5) ഏറെ സാമ്യമുള്ള രീതിയിൽ വിവരങ്ങൾ സംയോജിപ്പിക്കാൻ (synthesize) T5, BART പോലുള്ള എൻകോഡർ-ഡീകോഡർ മോഡലുകളാണ് സാധാരണയായി ഉപയോഗിക്കുന്നത്. ഇത്തരം *ജനറേറ്റീവ്* (generative) ചോദ്യോത്തരത്തിൽ നിങ്ങൾക്ക് താൽപ്പര്യമുണ്ടെങ്കിൽ, ഞങ്ങളുടെ [ഡെമോ](https://yjernite.github.io/lfqa.html) പരിശോധിക്കാൻ ഞങ്ങൾ ശുപാർശ ചെയ്യുന്നു; അത് [ELI5 ഡേറ്റാസെറ്റ്](https://huggingface.co/datasets/eli5) അടിസ്ഥാനമാക്കിയുള്ളതാണ്. + +## ഡേറ്റ തയ്യാറാക്കുന്നു[[preparing-the-data]] + +എക്‌സ്‌ട്രാക്റ്റീവ് ചോദ്യോത്തരത്തിനുള്ള അക്കാദമിക് ബെഞ്ച്‌മാർക്കായി ഏറ്റവുമധികം ഉപയോഗിക്കുന്ന ഡേറ്റാസെറ്റ് [SQuAD](https://rajpurkar.github.io/SQuAD-explorer/) ആണ്, അതിനാൽ അതാണ് നമ്മൾ ഇവിടെ ഉപയോഗിക്കുന്നത്. ഉത്തരമില്ലാത്ത ചോദ്യങ്ങളും ഉൾപ്പെടുന്ന, കൂടുതൽ കഠിനമായ ഒരു [SQuAD v2](https://huggingface.co/datasets/squad_v2) ബെഞ്ച്‌മാർക്കും ഉണ്ട്. നിങ്ങളുടെ സ്വന്തം ഡേറ്റാസെറ്റിൽ കോൺടെക്‌സ്‌റ്റുകൾക്ക് (contexts) ഒരു കോളവും, ചോദ്യങ്ങൾക്ക് ഒരു കോളവും, ഉത്തരങ്ങൾക്ക് ഒരു കോളവും ഉണ്ടെങ്കിൽ, താഴെയുള്ള ഘട്ടങ്ങൾ നിങ്ങൾക്ക് അതിനനുസരിച്ച് മാറ്റിയെടുക്കാൻ കഴിയേണ്ടതാണ്. + +### SQuAD ഡേറ്റാസെറ്റ്[[the-squad-dataset]] + +പതിവുപോലെ, `load_dataset()`-ന്റെ സഹായത്തോടെ ഒരൊറ്റ ഘട്ടത്തിൽ ഡേറ്റാസെറ്റ് ഡൗൺലോഡ് ചെയ്ത് കാഷ് (cache) ചെയ്യാം: + +```py +from datasets import load_dataset + +raw_datasets = load_dataset("squad") +``` + +SQuAD ഡേറ്റാസെറ്റിനെക്കുറിച്ച് കൂടുതൽ അറിയാൻ ഈ ഒബ്‌ജക്റ്റ് നമുക്ക് ഒന്ന് നോക്കാം: + +```py +raw_datasets +``` + +```python out +DatasetDict({ + train: Dataset({ + features: ['id', 'title', 'context', 'question', 'answers'], + num_rows: 87599 + }) + validation: Dataset({ + features: ['id', 'title', 'context', 'question', 'answers'], + num_rows: 10570 + }) +}) +``` + +`context`, `question`, `answers` എന്നീ ഫീൽഡുകളോടെ നമുക്ക് ആവശ്യമുള്ളതെല്ലാം ഉണ്ടെന്ന് തോന്നുന്നു, അതിനാൽ നമ്മുടെ ട്രെയിനിംഗ് സെറ്റിലെ ആദ്യ എലമെന്റിന്റെ ആ ഫീൽഡുകൾ പ്രിന്റ് ചെയ്ത് നോക്കാം: + +```py +print("Context: ", raw_datasets["train"][0]["context"]) +print("Question: ", raw_datasets["train"][0]["question"]) +print("Answer: ", raw_datasets["train"][0]["answers"]) +``` + +```python out +Context: 'Architecturally, the school has a Catholic character. Atop the Main Building\'s gold dome is a golden statue of the Virgin Mary. Immediately in front of the Main Building and facing it, is a copper statue of Christ with arms upraised with the legend "Venite Ad Me Omnes". Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basilica is the Grotto, a Marian place of prayer and reflection. It is a replica of the grotto at Lourdes, France where the Virgin Mary reputedly appeared to Saint Bernadette Soubirous in 1858. At the end of the main drive (and in a direct line that connects through 3 statues and the Gold Dome), is a simple, modern stone statue of Mary.' +Question: 'To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France?' +Answer: {'text': ['Saint Bernadette Soubirous'], 'answer_start': [515]} +``` + +`context`, `question` എന്നീ ഫീൽഡുകൾ ഉപയോഗിക്കാൻ വളരെ എളുപ്പമാണ്. `answers` ഫീൽഡ് അൽപ്പം കൂടുതൽ സങ്കീർണ്ണമാണ്, കാരണം അതിൽ രണ്ട് ഫീൽഡുകളുള്ള ഒരു ഡിക്‌ഷണറിയാണ് ഉള്ളത്, രണ്ടും ലിസ്‌റ്റുകളാണ്. ഇവാല്യുവേഷൻ സമയത്ത് `squad` മെട്രിക് പ്രതീക്ഷിക്കുന്ന ഫോർമാറ്റാണിത്; നിങ്ങളുടെ സ്വന്തം ഡേറ്റയാണ് ഉപയോഗിക്കുന്നതെങ്കിൽ, ഉത്തരങ്ങൾ ഇതേ ഫോർമാറ്റിൽ ആക്കുന്നതിനെക്കുറിച്ച് നിങ്ങൾ വിഷമിക്കേണ്ട ആവശ്യമില്ല. `text` ഫീൽഡ് വളരെ വ്യക്തമാണ്, `answer_start` ഫീൽഡിൽ കോൺടെക്‌സ്‌റ്റിലെ ഓരോ ഉത്തരത്തിന്റെയും ആരംഭ ക്യാരക്റ്റർ ഇൻഡെക്‌സ് (starting character index) അടങ്ങിയിരിക്കുന്നു. + +ട്രെയിനിംഗ് സമയത്ത്, സാധ്യമായ ഒരേയൊരു ഉത്തരം മാത്രമേയുള്ളൂ. `Dataset.filter()` മെത്തേഡ് ഉപയോഗിച്ച് ഇത് നമുക്ക് ഒന്നുകൂടി ഉറപ്പാക്കാം: + +```py +raw_datasets["train"].filter(lambda x: len(x["answers"]["text"]) != 1) +``` + +```python out +Dataset({ + features: ['id', 'title', 'context', 'question', 'answers'], + num_rows: 0 +}) +``` + +എന്നാൽ ഇവാല്യുവേഷനായി, ഓരോ സാമ്പിളിനും സാധ്യമായ ഒന്നിലധികം ഉത്തരങ്ങളുണ്ട്; അവ ഒന്നുതന്നെയോ വ്യത്യസ്തമോ ആകാം: + +```py +print(raw_datasets["validation"][0]["answers"]) +print(raw_datasets["validation"][2]["answers"]) +``` + +```python out +{'text': ['Denver Broncos', 'Denver Broncos', 'Denver Broncos'], 'answer_start': [177, 177, 177]} +{'text': ['Santa Clara, California', "Levi's Stadium", "Levi's Stadium in the San Francisco Bay Area at Santa Clara, California."], 'answer_start': [403, 355, 355]} +``` + +ഇവാല്യുവേഷൻ സ്‌ക്രിപ്‌റ്റിലേക്ക് നമ്മൾ ആഴത്തിൽ കടക്കുന്നില്ല, കാരണം അതെല്ലാം ഒരു 🤗 Datasets മെട്രിക് നമുക്കായി കൈകാര്യം ചെയ്യും; എന്നാൽ ചുരുക്കത്തിൽ, ചില ചോദ്യങ്ങൾക്ക് സാധ്യമായ ഒന്നിലധികം ഉത്തരങ്ങളുണ്ട്, ഈ സ്‌ക്രിപ്‌റ്റ് പ്രവചിച്ച ഒരു ഉത്തരത്തെ സ്വീകാര്യമായ എല്ലാ ഉത്തരങ്ങളുമായും താരതമ്യം ചെയ്ത് ഏറ്റവും മികച്ച സ്‌കോർ എടുക്കും. ഉദാഹരണത്തിന്, ഇൻഡെക്‌സ് 2-ലെ സാമ്പിൾ നമ്മൾ നോക്കിയാൽ: + +```py +print(raw_datasets["validation"][2]["context"]) +print(raw_datasets["validation"][2]["question"]) +``` + +```python out +'Super Bowl 50 was an American football game to determine the champion of the National Football League (NFL) for the 2015 season. The American Football Conference (AFC) champion Denver Broncos defeated the National Football Conference (NFC) champion Carolina Panthers 24–10 to earn their third Super Bowl title. The game was played on February 7, 2016, at Levi\'s Stadium in the San Francisco Bay Area at Santa Clara, California. As this was the 50th Super Bowl, the league emphasized the "golden anniversary" with various gold-themed initiatives, as well as temporarily suspending the tradition of naming each Super Bowl game with Roman numerals (under which the game would have been known as "Super Bowl L"), so that the logo could prominently feature the Arabic numerals 50.' +'Where did Super Bowl 50 take place?' +``` + +നമ്മൾ മുമ്പ് കണ്ട മൂന്ന് സാധ്യതകളിൽ ഏതെങ്കിലുമൊന്ന് തീർച്ചയായും ഉത്തരമാകാം എന്ന് കാണാൻ കഴിയും. + +### ട്രെയിനിംഗ് ഡേറ്റ പ്രോസസ്സ് ചെയ്യുന്നു[[processing-the-training-data]] + + + +ട്രെയിനിംഗ് ഡേറ്റ പ്രീപ്രോസസ്സ് ചെയ്യുന്നതിൽ നിന്ന് തുടങ്ങാം. ചോദ്യത്തിന്റെ ഉത്തരത്തിനുള്ള ലേബലുകൾ ഉണ്ടാക്കുന്നതായിരിക്കും ബുദ്ധിമുട്ടുള്ള ഭാഗം; കോൺടെക്‌സ്‌റ്റിനുള്ളിൽ ഉത്തരത്തിന് അനുയോജ്യമായ ടോക്കണുകളുടെ ആരംഭ, അവസാന സ്ഥാനങ്ങളായിരിക്കും (start and end positions) ഈ ലേബലുകൾ. + +എന്നാൽ നമുക്ക് അധികം മുന്നോട്ട് ചാടേണ്ട. ആദ്യം, ഒരു ടോക്കണൈസർ ഉപയോഗിച്ച് ഇൻപുട്ടിലെ ടെക്‌സ്‌റ്റിനെ മോഡലിന് മനസ്സിലാക്കാൻ കഴിയുന്ന ID-കളാക്കി മാറ്റണം: + +```py +from transformers import AutoTokenizer + +model_checkpoint = "bert-base-cased" +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) +``` + +മുമ്പ് സൂചിപ്പിച്ചതുപോലെ, നമ്മൾ ഒരു BERT മോഡലാണ് ഫൈൻ-ട്യൂൻ ചെയ്യുന്നത്, എന്നാൽ ഒരു ഫാസ്‌റ്റ് ടോക്കണൈസർ ഇംപ്ലിമെന്റ് ചെയ്തിട്ടുള്ള മറ്റേത് തരം മോഡലും നിങ്ങൾക്ക് ഉപയോഗിക്കാം. ഫാസ്‌റ്റ് പതിപ്പുള്ള എല്ലാ ആർക്കിടെക്ചറുകളും [ഈ വലിയ പട്ടികയിൽ](https://huggingface.co/transformers/#supported-frameworks) നിങ്ങൾക്ക് കാണാം, കൂടാതെ നിങ്ങൾ ഉപയോഗിക്കുന്ന `tokenizer` ഒബ്‌ജക്റ്റ് യഥാർത്ഥത്തിൽ 🤗 Tokenizers പിന്തുണയോടെയുള്ളതാണെന്ന് ഉറപ്പാക്കാൻ അതിന്റെ `is_fast` ആട്രിബ്യൂട്ട് നോക്കാം: + +```py +tokenizer.is_fast +``` + +```python out +True +``` + +ചോദ്യവും കോൺടെക്‌സ്‌റ്റും ഒരുമിച്ച് നമ്മുടെ ടോക്കണൈസറിന് നൽകാം, അത് ഇതുപോലുള്ള ഒരു വാക്യം രൂപപ്പെടുത്താൻ സ്‌പെഷ്യൽ ടോക്കണുകൾ ശരിയായി ചേർക്കും: + +``` +[CLS] question [SEP] context [SEP] +``` + +ഒന്നുകൂടി പരിശോധിക്കാം: + +```py +context = raw_datasets["train"][0]["context"] +question = raw_datasets["train"][0]["question"] + +inputs = tokenizer(question, context) +tokenizer.decode(inputs["input_ids"]) +``` + +```python out +'[CLS] To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France? [SEP] Architecturally, ' +'the school has a Catholic character. Atop the Main Building\'s gold dome is a golden statue of the Virgin ' +'Mary. Immediately in front of the Main Building and facing it, is a copper statue of Christ with arms ' +'upraised with the legend " Venite Ad Me Omnes ". Next to the Main Building is the Basilica of the Sacred ' +'Heart. Immediately behind the basilica is the Grotto, a Marian place of prayer and reflection. It is a ' +'replica of the grotto at Lourdes, France where the Virgin Mary reputedly appeared to Saint Bernadette ' +'Soubirous in 1858. At the end of the main drive ( and in a direct line that connects through 3 statues ' +'and the Gold Dome ), is a simple, modern stone statue of Mary. [SEP]' +``` + +അപ്പോൾ ഉത്തരം ആരംഭിക്കുന്നതും അവസാനിക്കുന്നതുമായ ടോക്കണുകളുടെ ഇൻഡെക്‌സായിരിക്കും ലേബലുകൾ, ഇൻപുട്ടിലെ ഓരോ ടോക്കണിനും ഒരു ആരംഭ ലോജിറ്റും (start logit) ഒരു അവസാന ലോജിറ്റും (end logit) പ്രവചിക്കുകയാണ് മോഡലിന്റെ ചുമതല; സൈദ്ധാന്തികമായ ലേബലുകൾ താഴെ കാണുന്നതുപോലെയായിരിക്കും: + +
+ചോദ്യോത്തരത്തിനുള്ള വൺ-ഹോട്ട് എൻകോഡ് ചെയ്ത ലേബലുകൾ. + +
+ +ഈ സന്ദർഭത്തിൽ കോൺടെക്‌സ്‌റ്റ് അധികം ദൈർഘ്യമുള്ളതല്ല, എന്നാൽ ഡേറ്റാസെറ്റിലെ ചില ഉദാഹരണങ്ങൾക്ക് നമ്മൾ സെറ്റ് ചെയ്യുന്ന പരമാവധി ദൈർഘ്യം (ഇവിടെ 384) കവിയുന്ന വളരെ നീണ്ട കോൺടെക്‌സ്‌റ്റുകളുണ്ട്. `question-answering` പൈപ്പ്‌ലൈനിന്റെ ഉള്ളറകൾ പരിശോധിച്ചപ്പോൾ [അധ്യായം 6](/course/chapter6/4)-ൽ നമ്മൾ കണ്ടതുപോലെ, നമ്മുടെ ഡേറ്റാസെറ്റിലെ ഒരു സാമ്പിളിൽ നിന്ന്, അവയ്ക്കിടയിൽ ഒരു സ്ലൈഡിംഗ് വിൻഡോയോടെ (sliding window), ഒന്നിലധികം ട്രെയിനിംഗ് ഫീച്ചറുകൾ (features) ഉണ്ടാക്കിക്കൊണ്ടാണ് നീണ്ട കോൺടെക്‌സ്‌റ്റുകളെ നമ്മൾ കൈകാര്യം ചെയ്യുന്നത്. + +ഇപ്പോഴത്തെ ഉദാഹരണം ഉപയോഗിച്ച് ഇത് എങ്ങനെ പ്രവർത്തിക്കുന്നു എന്ന് കാണാൻ, ദൈർഘ്യം 100-ലേക്ക് പരിമിതപ്പെടുത്തി 50 ടോക്കണുകളുടെ ഒരു സ്ലൈഡിംഗ് വിൻഡോ ഉപയോഗിക്കാം. ഓർമ്മപ്പെടുത്തലായി, നമ്മൾ ഉപയോഗിക്കുന്നത്: + +- പരമാവധി ദൈർഘ്യം സെറ്റ് ചെയ്യാൻ `max_length` (ഇവിടെ 100) +- ചോദ്യവും അതിന്റെ കോൺടെക്‌സ്‌റ്റും ചേർന്ന് വളരെ നീണ്ടതാകുമ്പോൾ കോൺടെക്‌സ്‌റ്റ് (രണ്ടാം സ്ഥാനത്തുള്ളത്) ട്രങ്കേറ്റ് ചെയ്യാൻ `truncation="only_second"` +- തുടർച്ചയായ രണ്ട് ചങ്കുകൾക്കിടയിൽ (chunks) ഓവർലാപ്പ് ചെയ്യുന്ന ടോക്കണുകളുടെ എണ്ണം സെറ്റ് ചെയ്യാൻ `stride` (ഇവിടെ 50) +- ഓവർഫ്ലോ ചെയ്യുന്ന ടോക്കണുകൾ നമുക്ക് വേണമെന്ന് ടോക്കണൈസറിനെ അറിയിക്കാൻ `return_overflowing_tokens=True` + +```py +inputs = tokenizer( + question, + context, + max_length=100, + truncation="only_second", + stride=50, + return_overflowing_tokens=True, +) + +for ids in inputs["input_ids"]: + print(tokenizer.decode(ids)) +``` + +```python out +'[CLS] To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France? [SEP] Architecturally, the school has a Catholic character. Atop the Main Building\'s gold dome is a golden statue of the Virgin Mary. Immediately in front of the Main Building and facing it, is a copper statue of Christ with arms upraised with the legend " Venite Ad Me Omnes ". Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basi [SEP]' +'[CLS] To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France? [SEP] the Main Building and facing it, is a copper statue of Christ with arms upraised with the legend " Venite Ad Me Omnes ". Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basilica is the Grotto, a Marian place of prayer and reflection. It is a replica of the grotto at Lourdes, France where the Virgin [SEP]' +'[CLS] To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France? [SEP] Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basilica is the Grotto, a Marian place of prayer and reflection. It is a replica of the grotto at Lourdes, France where the Virgin Mary reputedly appeared to Saint Bernadette Soubirous in 1858. At the end of the main drive ( and in a direct line that connects through 3 [SEP]' +'[CLS] To whom did the Virgin Mary allegedly appear in 1858 in Lourdes France? [SEP]. It is a replica of the grotto at Lourdes, France where the Virgin Mary reputedly appeared to Saint Bernadette Soubirous in 1858. At the end of the main drive ( and in a direct line that connects through 3 statues and the Gold Dome ), is a simple, modern stone statue of Mary. [SEP]' +``` + +നമുക്ക് കാണാവുന്നതുപോലെ, നമ്മുടെ ഉദാഹരണം നാല് ഇൻപുട്ടുകളായി വിഭജിക്കപ്പെട്ടിരിക്കുന്നു, അവയിൽ ഓരോന്നിലും ചോദ്യവും കോൺടെക്‌സ്‌റ്റിന്റെ ഒരു ഭാഗവും അടങ്ങിയിരിക്കുന്നു. ചോദ്യത്തിന്റെ ഉത്തരം ("Bernadette Soubirous") മൂന്നാമത്തെയും അവസാനത്തെയും ഇൻപുട്ടുകളിൽ മാത്രമേ വരുന്നുള്ളൂ എന്നത് ശ്രദ്ധിക്കുക; അതിനാൽ നീണ്ട കോൺടെക്‌സ്‌റ്റുകളെ ഈ രീതിയിൽ കൈകാര്യം ചെയ്യുമ്പോൾ, ഉത്തരം കോൺടെക്‌സ്‌റ്റിൽ ഉൾപ്പെടാത്ത ചില ട്രെയിനിംഗ് ഉദാഹരണങ്ങൾ നമ്മൾ ഉണ്ടാക്കും. ആ ഉദാഹരണങ്ങൾക്ക്, ലേബലുകൾ `start_position = end_position = 0` ആയിരിക്കും (അതായത് നമ്മൾ `[CLS]` ടോക്കൺ പ്രവചിക്കുന്നു). ഉത്തരം ട്രങ്കേറ്റ് ചെയ്യപ്പെട്ട് അതിന്റെ ആരംഭം (അല്ലെങ്കിൽ അവസാനം) മാത്രം നമുക്ക് ലഭിക്കുന്ന നിർഭാഗ്യകരമായ സാഹചര്യത്തിലും ആ ലേബലുകൾ തന്നെ നമ്മൾ സെറ്റ് ചെയ്യും. ഉത്തരം പൂർണ്ണമായി കോൺടെക്‌സ്‌റ്റിൽ ഉള്ള ഉദാഹരണങ്ങൾക്ക്, ഉത്തരം ആരംഭിക്കുന്ന ടോക്കണിന്റെ ഇൻഡെക്‌സും ഉത്തരം അവസാനിക്കുന്ന ടോക്കണിന്റെ ഇൻഡെക്‌സുമായിരിക്കും ലേബലുകൾ. + +കോൺടെക്‌സ്‌റ്റിലെ ഉത്തരത്തിന്റെ ആരംഭ ക്യാരക്റ്റർ ഡേറ്റാസെറ്റ് നമുക്ക് നൽകുന്നു, ഉത്തരത്തിന്റെ ദൈർഘ്യം അതിനോട് കൂട്ടിയാൽ കോൺടെക്‌സ്‌റ്റിലെ അവസാന ക്യാരക്റ്റർ കണ്ടെത്താം. ഇവയെ ടോക്കൺ ഇൻഡെക്‌സുകളിലേക്ക് മാപ്പ് ചെയ്യാൻ, [അധ്യായം 6](/course/chapter6/4)-ൽ നമ്മൾ പഠിച്ച ഓഫ്‌സെറ്റ് മാപ്പിംഗുകൾ (offset mappings) ഉപയോഗിക്കേണ്ടിവരും. `return_offsets_mapping=True` നൽകിക്കൊണ്ട് നമ്മുടെ ടോക്കണൈസർ ഇവ റിട്ടേൺ ചെയ്യുന്നതാക്കാം: + +```py +inputs = tokenizer( + question, + context, + max_length=100, + truncation="only_second", + stride=50, + return_overflowing_tokens=True, + return_offsets_mapping=True, +) +inputs.keys() +``` + +```python out +dict_keys(['input_ids', 'token_type_ids', 'attention_mask', 'offset_mapping', 'overflow_to_sample_mapping']) +``` + +നമുക്ക് കാണാവുന്നതുപോലെ, പതിവുള്ള ഇൻപുട്ട് ID-കൾ, ടോക്കൺ ടൈപ്പ് ID-കൾ, അറ്റൻഷൻ മാസ്‌ക് എന്നിവയ്‌ക്കൊപ്പം നമ്മൾ ആവശ്യപ്പെട്ട ഓഫ്‌സെറ്റ് മാപ്പിംഗും `overflow_to_sample_mapping` എന്ന ഒരു അധിക കീയും നമുക്ക് തിരികെ ലഭിക്കുന്നു. ഒന്നിലധികം ടെക്‌സ്‌റ്റുകൾ ഒരേ സമയം ടോക്കണൈസ് ചെയ്യുമ്പോൾ ഇതിന്റെ മൂല്യം നമുക്ക് ഉപകാരപ്പെടും (നമ്മുടെ ടോക്കണൈസർ Rust പിന്തുണയോടെയുള്ളതാണ് എന്നതിന്റെ പ്രയോജനം ലഭിക്കാൻ അങ്ങനെയാണ് നമ്മൾ ചെയ്യേണ്ടത്). ഒരു സാമ്പിളിൽ നിന്ന് ഒന്നിലധികം ഫീച്ചറുകൾ ലഭിക്കാം എന്നതിനാൽ, ഇത് ഓരോ ഫീച്ചറിനെയും അത് ഉത്ഭവിച്ച ഉദാഹരണത്തിലേക്ക് മാപ്പ് ചെയ്യുന്നു. ഇവിടെ നമ്മൾ ഒരു ഉദാഹരണം മാത്രമേ ടോക്കണൈസ് ചെയ്തിട്ടുള്ളൂ എന്നതിനാൽ, `0`-കളുടെ ഒരു ലിസ്‌റ്റ് ലഭിക്കുന്നു: + +```py +inputs["overflow_to_sample_mapping"] +``` + +```python out +[0, 0, 0, 0] +``` + +എന്നാൽ കൂടുതൽ ഉദാഹരണങ്ങൾ ടോക്കണൈസ് ചെയ്താൽ, ഇത് കൂടുതൽ ഉപകാരപ്രദമാകും: + +```py +inputs = tokenizer( + raw_datasets["train"][2:6]["question"], + raw_datasets["train"][2:6]["context"], + max_length=100, + truncation="only_second", + stride=50, + return_overflowing_tokens=True, + return_offsets_mapping=True, +) + +print(f"The 4 examples gave {len(inputs['input_ids'])} features.") +print(f"Here is where each comes from: {inputs['overflow_to_sample_mapping']}.") +``` + +```python out +'The 4 examples gave 19 features.' +'Here is where each comes from: [0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3].' +``` + +നമുക്ക് കാണാവുന്നതുപോലെ, ആദ്യത്തെ മൂന്ന് ഉദാഹരണങ്ങൾ (ട്രെയിനിംഗ് സെറ്റിലെ ഇൻഡെക്‌സ് 2, 3, 4 എന്നിവയിലുള്ളവ) ഓരോന്നും നാല് ഫീച്ചറുകൾ വീതം നൽകി, അവസാനത്തെ ഉദാഹരണം (ട്രെയിനിംഗ് സെറ്റിലെ ഇൻഡെക്‌സ് 5-ലുള്ളത്) 7 ഫീച്ചറുകൾ നൽകി. + +നമുക്ക് ലഭിക്കുന്ന ഓരോ ഫീച്ചറിനെയും അതിന്റെ ലേബലുമായി ബന്ധിപ്പിക്കാൻ ഈ വിവരം ഉപകാരപ്പെടും. മുമ്പ് സൂചിപ്പിച്ചതുപോലെ, ആ ലേബലുകൾ ഇവയാണ്: + +- കോൺടെക്‌സ്‌റ്റിന്റെ അനുബന്ധ സ്‌പാനിൽ ഉത്തരം ഇല്ലെങ്കിൽ `(0, 0)` +- കോൺടെക്‌സ്‌റ്റിന്റെ അനുബന്ധ സ്‌പാനിൽ ഉത്തരം ഉണ്ടെങ്കിൽ `(start_position, end_position)`; ഇവിടെ `start_position` എന്നത് ഉത്തരത്തിന്റെ ആരംഭത്തിലുള്ള ടോക്കണിന്റെ (ഇൻപുട്ട് ID-കളിലെ) ഇൻഡെക്‌സും `end_position` എന്നത് ഉത്തരം അവസാനിക്കുന്ന ടോക്കണിന്റെ (ഇൻപുട്ട് ID-കളിലെ) ഇൻഡെക്‌സുമാണ് + +ഇവയിൽ ഏതാണ് ബാധകമെന്നും, ബാധകമെങ്കിൽ ടോക്കണുകളുടെ സ്ഥാനങ്ങളും നിർണ്ണയിക്കാൻ, ഇൻപുട്ട് ID-കളിൽ കോൺടെക്‌സ്‌റ്റ് ആരംഭിക്കുന്നതും അവസാനിക്കുന്നതുമായ ഇൻഡെക്‌സുകൾ നമ്മൾ ആദ്യം കണ്ടെത്തുന്നു. ഇതിനായി ടോക്കൺ ടൈപ്പ് ID-കൾ ഉപയോഗിക്കാമായിരുന്നു, എന്നാൽ അവ എല്ലാ മോഡലുകൾക്കും ഉണ്ടാകണമെന്നില്ല എന്നതിനാൽ (ഉദാഹരണത്തിന്, DistilBERT-ന് അവ ആവശ്യമില്ല), പകരം നമ്മുടെ ടോക്കണൈസർ റിട്ടേൺ ചെയ്യുന്ന `BatchEncoding`-ന്റെ `sequence_ids()` മെത്തേഡ് നമ്മൾ ഉപയോഗിക്കും. + +ആ ടോക്കൺ ഇൻഡെക്‌സുകൾ ലഭിച്ചുകഴിഞ്ഞാൽ, അവയ്ക്ക് അനുബന്ധമായ ഓഫ്‌സെറ്റുകൾ നമ്മൾ നോക്കുന്നു; യഥാർത്ഥ കോൺടെക്‌സ്‌റ്റിനുള്ളിലെ ക്യാരക്റ്ററുകളുടെ സ്‌പാൻ സൂചിപ്പിക്കുന്ന രണ്ട് ഇന്റിജറുകളുടെ ട്യൂപ്പിളുകളാണ് ഇവ. അങ്ങനെ, ഈ ഫീച്ചറിലെ കോൺടെക്‌സ്‌റ്റിന്റെ ചങ്ക് ഉത്തരത്തിന് ശേഷമാണോ ആരംഭിക്കുന്നത്, അല്ലെങ്കിൽ ഉത്തരം തുടങ്ങുന്നതിന് മുമ്പാണോ അവസാനിക്കുന്നത് എന്ന് നമുക്ക് കണ്ടെത്താം (അങ്ങനെയാണെങ്കിൽ ലേബൽ `(0, 0)` ആണ്). അങ്ങനെയല്ലെങ്കിൽ, ഉത്തരത്തിന്റെ ആദ്യത്തെയും അവസാനത്തെയും ടോക്കൺ കണ്ടെത്താൻ നമ്മൾ ലൂപ്പ് ചെയ്യുന്നു: + +```py +answers = raw_datasets["train"][2:6]["answers"] +start_positions = [] +end_positions = [] + +for i, offset in enumerate(inputs["offset_mapping"]): + sample_idx = inputs["overflow_to_sample_mapping"][i] + answer = answers[sample_idx] + start_char = answer["answer_start"][0] + end_char = answer["answer_start"][0] + len(answer["text"][0]) + sequence_ids = inputs.sequence_ids(i) + + # Find the start and end of the context + idx = 0 + while sequence_ids[idx] != 1: + idx += 1 + context_start = idx + while sequence_ids[idx] == 1: + idx += 1 + context_end = idx - 1 + + # If the answer is not fully inside the context, label is (0, 0) + if offset[context_start][0] > start_char or offset[context_end][1] < end_char: + start_positions.append(0) + end_positions.append(0) + else: + # Otherwise it's the start and end token positions + idx = context_start + while idx <= context_end and offset[idx][0] <= start_char: + idx += 1 + start_positions.append(idx - 1) + + idx = context_end + while idx >= context_start and offset[idx][1] >= end_char: + idx -= 1 + end_positions.append(idx + 1) + +start_positions, end_positions +``` + +```python out +([83, 51, 19, 0, 0, 64, 27, 0, 34, 0, 0, 0, 67, 34, 0, 0, 0, 0, 0], + [85, 53, 21, 0, 0, 70, 33, 0, 40, 0, 0, 0, 68, 35, 0, 0, 0, 0, 0]) +``` + +നമ്മുടെ സമീപനം ശരിയാണെന്ന് ഉറപ്പാക്കാൻ ഏതാനും ഫലങ്ങൾ നോക്കാം. ആദ്യത്തെ ഫീച്ചറിന് ലേബലുകളായി `(83, 85)` ആണ് നമുക്ക് ലഭിക്കുന്നത്, അതിനാൽ സൈദ്ധാന്തിക ഉത്തരത്തെ 83 മുതൽ 85 വരെയുള്ള (85 ഉൾപ്പെടെ) ടോക്കണുകളുടെ ഡീകോഡ് ചെയ്ത സ്‌പാനുമായി താരതമ്യം ചെയ്യാം: + +```py +idx = 0 +sample_idx = inputs["overflow_to_sample_mapping"][idx] +answer = answers[sample_idx]["text"][0] + +start = start_positions[idx] +end = end_positions[idx] +labeled_answer = tokenizer.decode(inputs["input_ids"][idx][start : end + 1]) + +print(f"Theoretical answer: {answer}, labels give: {labeled_answer}") +``` + +```python out +'Theoretical answer: the Main Building, labels give: the Main Building' +``` + +അതായത് അത് ഒത്തുവരുന്നു! ഇനി ഇൻഡെക്‌സ് 4 പരിശോധിക്കാം; അവിടെ നമ്മൾ ലേബലുകൾ `(0, 0)` എന്ന് സെറ്റ് ചെയ്തിരുന്നു, അതിനർത്ഥം ആ ഫീച്ചറിന്റെ കോൺടെക്‌സ്‌റ്റ് ചങ്കിൽ ഉത്തരം ഇല്ല എന്നാണ്: + +```py +idx = 4 +sample_idx = inputs["overflow_to_sample_mapping"][idx] +answer = answers[sample_idx]["text"][0] + +decoded_example = tokenizer.decode(inputs["input_ids"][idx]) +print(f"Theoretical answer: {answer}, decoded example: {decoded_example}") +``` + +```python out +'Theoretical answer: a Marian place of prayer and reflection, decoded example: [CLS] What is the Grotto at Notre Dame? [SEP] Architecturally, the school has a Catholic character. Atop the Main Building\'s gold dome is a golden statue of the Virgin Mary. Immediately in front of the Main Building and facing it, is a copper statue of Christ with arms upraised with the legend " Venite Ad Me Omnes ". Next to the Main Building is the Basilica of the Sacred Heart. Immediately behind the basilica is the Grot [SEP]' +``` + +തീർച്ചയായും, കോൺടെക്‌സ്‌റ്റിനുള്ളിൽ ഉത്തരം നമ്മൾ കാണുന്നില്ല. + +> [!TIP] +> ✏️ **നിങ്ങളുടെ ഊഴം!** XLNet ആർക്കിടെക്ചർ ഉപയോഗിക്കുമ്പോൾ, പാഡിംഗ് ഇടതുവശത്താണ് പ്രയോഗിക്കുന്നത്, കൂടാതെ ചോദ്യവും കോൺടെക്‌സ്‌റ്റും പരസ്പരം സ്ഥാനം മാറുന്നു. നമ്മൾ ഇപ്പോൾ കണ്ട എല്ലാ കോഡും XLNet ആർക്കിടെക്ചറിന് അനുയോജ്യമായി മാറ്റുക (`padding=True` കൂടി ചേർക്കുക). പാഡിംഗ് പ്രയോഗിക്കുമ്പോൾ `[CLS]` ടോക്കൺ 0 എന്ന സ്ഥാനത്തായിരിക്കണമെന്നില്ല എന്നത് ഓർമ്മിക്കുക. + +നമ്മുടെ ട്രെയിനിംഗ് ഡേറ്റ എങ്ങനെ പ്രീപ്രോസസ്സ് ചെയ്യാമെന്ന് ഘട്ടം ഘട്ടമായി കണ്ടുകഴിഞ്ഞതിനാൽ, മുഴുവൻ ട്രെയിനിംഗ് ഡേറ്റാസെറ്റിലും പ്രയോഗിക്കാവുന്ന ഒരു ഫംഗ്‌ഷനിൽ ഇത് ഒരുമിച്ച് ചേർക്കാം. ഓരോ ഫീച്ചറും നമ്മൾ സെറ്റ് ചെയ്ത പരമാവധി ദൈർഘ്യത്തിലേക്ക് പാഡ് ചെയ്യും, കാരണം മിക്ക കോൺടെക്‌സ്‌റ്റുകളും നീണ്ടതായിരിക്കും (അവയ്ക്ക് അനുബന്ധമായ സാമ്പിളുകൾ ഒന്നിലധികം ഫീച്ചറുകളായി വിഭജിക്കപ്പെടും), അതിനാൽ ഇവിടെ ഡൈനാമിക് പാഡിംഗ് പ്രയോഗിക്കുന്നതിൽ യഥാർത്ഥ പ്രയോജനമൊന്നുമില്ല: + +```py +max_length = 384 +stride = 128 + + +def preprocess_training_examples(examples): + questions = [q.strip() for q in examples["question"]] + inputs = tokenizer( + questions, + examples["context"], + max_length=max_length, + truncation="only_second", + stride=stride, + return_overflowing_tokens=True, + return_offsets_mapping=True, + padding="max_length", + ) + + offset_mapping = inputs.pop("offset_mapping") + sample_map = inputs.pop("overflow_to_sample_mapping") + answers = examples["answers"] + start_positions = [] + end_positions = [] + + for i, offset in enumerate(offset_mapping): + sample_idx = sample_map[i] + answer = answers[sample_idx] + start_char = answer["answer_start"][0] + end_char = answer["answer_start"][0] + len(answer["text"][0]) + sequence_ids = inputs.sequence_ids(i) + + # Find the start and end of the context + idx = 0 + while sequence_ids[idx] != 1: + idx += 1 + context_start = idx + while sequence_ids[idx] == 1: + idx += 1 + context_end = idx - 1 + + # If the answer is not fully inside the context, label is (0, 0) + if offset[context_start][0] > start_char or offset[context_end][1] < end_char: + start_positions.append(0) + end_positions.append(0) + else: + # Otherwise it's the start and end token positions + idx = context_start + while idx <= context_end and offset[idx][0] <= start_char: + idx += 1 + start_positions.append(idx - 1) + + idx = context_end + while idx >= context_start and offset[idx][1] >= end_char: + idx -= 1 + end_positions.append(idx + 1) + + inputs["start_positions"] = start_positions + inputs["end_positions"] = end_positions + return inputs +``` + +ഉപയോഗിക്കുന്ന പരമാവധി ദൈർഘ്യവും സ്ലൈഡിംഗ് വിൻഡോയുടെ ദൈർഘ്യവും നിർണ്ണയിക്കാൻ നമ്മൾ രണ്ട് കോൺസ്‌റ്റന്റുകൾ നിർവചിച്ചെന്നും, ടോക്കണൈസ് ചെയ്യുന്നതിന് മുമ്പ് ഒരു ചെറിയ ക്ലീനപ്പ് ചേർത്തെന്നും ശ്രദ്ധിക്കുക: SQuAD ഡേറ്റാസെറ്റിലെ ചില ചോദ്യങ്ങളുടെ തുടക്കത്തിലും അവസാനത്തിലും ഒന്നും കൂട്ടിച്ചേർക്കാത്ത അധിക സ്‌പേസുകളുണ്ട് (RoBERTa പോലുള്ള ഒരു മോഡൽ ഉപയോഗിക്കുകയാണെങ്കിൽ ടോക്കണൈസ് ചെയ്യുമ്പോൾ അവ സ്ഥലം അപഹരിക്കുകയും ചെയ്യും), അതിനാൽ ആ അധിക സ്‌പേസുകൾ നമ്മൾ നീക്കം ചെയ്തു. + +ഈ ഫംഗ്‌ഷൻ മുഴുവൻ ട്രെയിനിംഗ് സെറ്റിലും പ്രയോഗിക്കാൻ, `batched=True` ഫ്ലാഗോടെ `Dataset.map()` മെത്തേഡ് നമ്മൾ ഉപയോഗിക്കുന്നു. ഡേറ്റാസെറ്റിന്റെ ദൈർഘ്യം നമ്മൾ മാറ്റുന്നതിനാൽ (ഒരു ഉദാഹരണത്തിൽ നിന്ന് ഒന്നിലധികം ട്രെയിനിംഗ് ഫീച്ചറുകൾ ലഭിക്കാം എന്നതിനാൽ) ഇത് ഇവിടെ അത്യാവശ്യമാണ്: + +```py +train_dataset = raw_datasets["train"].map( + preprocess_training_examples, + batched=True, + remove_columns=raw_datasets["train"].column_names, +) +len(raw_datasets["train"]), len(train_dataset) +``` + +```python out +(87599, 88729) +``` + +നമുക്ക് കാണാവുന്നതുപോലെ, പ്രീപ്രോസസ്സിംഗ് ഏകദേശം 1,000 ഫീച്ചറുകൾ കൂട്ടിച്ചേർത്തു. നമ്മുടെ ട്രെയിനിംഗ് സെറ്റ് ഇപ്പോൾ ഉപയോഗിക്കാൻ തയ്യാറാണ് -- ഇനി വാലിഡേഷൻ സെറ്റിന്റെ പ്രീപ്രോസസ്സിംഗിലേക്ക് കടക്കാം! + +### വാലിഡേഷൻ ഡേറ്റ പ്രോസസ്സ് ചെയ്യുന്നു[[processing-the-validation-data]] + +വാലിഡേഷൻ ഡേറ്റ പ്രീപ്രോസസ്സ് ചെയ്യുന്നത് അൽപ്പം കൂടുതൽ എളുപ്പമായിരിക്കും, കാരണം നമുക്ക് ലേബലുകൾ ഉണ്ടാക്കേണ്ട ആവശ്യമില്ല (ഒരു വാലിഡേഷൻ ലോസ് കണക്കാക്കണമെങ്കിൽ ഒഴികെ, എന്നാൽ മോഡൽ എത്ര നല്ലതാണെന്ന് മനസ്സിലാക്കാൻ ആ സംഖ്യ നമ്മെ കാര്യമായി സഹായിക്കില്ല). മോഡലിന്റെ പ്രവചനങ്ങളെ യഥാർത്ഥ കോൺടെക്‌സ്‌റ്റിന്റെ സ്‌പാനുകളായി വ്യാഖ്യാനിക്കുന്നതായിരിക്കും യഥാർത്ഥ രസം. ഇതിനായി, ഓഫ്‌സെറ്റ് മാപ്പിംഗുകളും, ഉണ്ടാക്കിയ ഓരോ ഫീച്ചറിനെയും അത് ഉത്ഭവിച്ച യഥാർത്ഥ ഉദാഹരണവുമായി ബന്ധിപ്പിക്കാനുള്ള ഏതെങ്കിലും ഒരു മാർഗ്ഗവും നമ്മൾ സ്‌റ്റോർ ചെയ്താൽ മതി. യഥാർത്ഥ ഡേറ്റാസെറ്റിൽ ഒരു ID കോളം ഉള്ളതിനാൽ, ആ ID നമ്മൾ ഉപയോഗിക്കും. + +ഇവിടെ നമ്മൾ കൂട്ടിച്ചേർക്കുന്ന ഒരേയൊരു കാര്യം ഓഫ്‌സെറ്റ് മാപ്പിംഗുകളുടെ ഒരു ചെറിയ ക്ലീനപ്പാണ്. അവയിൽ ചോദ്യത്തിന്റെയും കോൺടെക്‌സ്‌റ്റിന്റെയും ഓഫ്‌സെറ്റുകൾ അടങ്ങിയിരിക്കും, എന്നാൽ പോസ്‌റ്റ്-പ്രോസസ്സിംഗ് ഘട്ടത്തിൽ എത്തിക്കഴിഞ്ഞാൽ ഇൻപുട്ട് ID-കളുടെ ഏത് ഭാഗമാണ് കോൺടെക്‌സ്‌റ്റിനോട് ബന്ധപ്പെട്ടത്, ഏത് ഭാഗമാണ് ചോദ്യം എന്ന് അറിയാൻ നമുക്ക് ഒരു മാർഗ്ഗവുമുണ്ടാകില്ല (നമ്മൾ ഉപയോഗിച്ച `sequence_ids()` മെത്തേഡ് ടോക്കണൈസറിന്റെ ഔട്ട്‌പുട്ടിന് മാത്രമേ ലഭ്യമാകൂ). അതിനാൽ, ചോദ്യത്തിന് അനുബന്ധമായ ഓഫ്‌സെറ്റുകൾ നമ്മൾ `None` എന്ന് സെറ്റ് ചെയ്യും: + +```py +def preprocess_validation_examples(examples): + questions = [q.strip() for q in examples["question"]] + inputs = tokenizer( + questions, + examples["context"], + max_length=max_length, + truncation="only_second", + stride=stride, + return_overflowing_tokens=True, + return_offsets_mapping=True, + padding="max_length", + ) + + sample_map = inputs.pop("overflow_to_sample_mapping") + example_ids = [] + + for i in range(len(inputs["input_ids"])): + sample_idx = sample_map[i] + example_ids.append(examples["id"][sample_idx]) + + sequence_ids = inputs.sequence_ids(i) + offset = inputs["offset_mapping"][i] + inputs["offset_mapping"][i] = [ + o if sequence_ids[k] == 1 else None for k, o in enumerate(offset) + ] + + inputs["example_id"] = example_ids + return inputs +``` + +മുമ്പത്തെപ്പോലെ ഈ ഫംഗ്‌ഷൻ മുഴുവൻ വാലിഡേഷൻ ഡേറ്റാസെറ്റിലും പ്രയോഗിക്കാം: + +```py +validation_dataset = raw_datasets["validation"].map( + preprocess_validation_examples, + batched=True, + remove_columns=raw_datasets["validation"].column_names, +) +len(raw_datasets["validation"]), len(validation_dataset) +``` + +```python out +(10570, 10822) +``` + +ഈ സന്ദർഭത്തിൽ നമ്മൾ ഏതാനും നൂറ് സാമ്പിളുകൾ മാത്രമേ കൂട്ടിച്ചേർത്തിട്ടുള്ളൂ, അതിനാൽ വാലിഡേഷൻ ഡേറ്റാസെറ്റിലെ കോൺടെക്‌സ്‌റ്റുകൾ അൽപ്പം ചെറുതാണെന്ന് തോന്നുന്നു. + +എല്ലാ ഡേറ്റയും പ്രീപ്രോസസ്സ് ചെയ്തുകഴിഞ്ഞതിനാൽ, ഇനി ട്രെയിനിംഗിലേക്ക് കടക്കാം. + +{#if fw === 'pt'} + +## `Trainer` API ഉപയോഗിച്ച് മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യുന്നു[[fine-tuning-the-model-with-the-trainer-api]] + +ഈ ഉദാഹരണത്തിനുള്ള ട്രെയിനിംഗ് കോഡ് മുൻ ഭാഗങ്ങളിലെ കോഡിനോട് ഏറെ സാമ്യമുള്ളതായിരിക്കും -- `compute_metrics()` ഫംഗ്‌ഷൻ എഴുതുന്നതായിരിക്കും ഏറ്റവും ബുദ്ധിമുട്ടുള്ള കാര്യം. എല്ലാ സാമ്പിളുകളും നമ്മൾ സെറ്റ് ചെയ്ത പരമാവധി ദൈർഘ്യത്തിലേക്ക് പാഡ് ചെയ്തതിനാൽ, നിർവചിക്കാൻ ഒരു ഡേറ്റാ കൊളേറ്ററും ഇല്ല; അതിനാൽ ഈ മെട്രിക് കണക്കുകൂട്ടൽ മാത്രമാണ് നമ്മൾ ശ്രദ്ധിക്കേണ്ട ഒരേയൊരു കാര്യം. മോഡലിന്റെ പ്രവചനങ്ങളെ യഥാർത്ഥ ഉദാഹരണങ്ങളിലെ ടെക്‌സ്‌റ്റ് സ്‌പാനുകളായി പോസ്‌റ്റ്-പ്രോസസ്സ് ചെയ്യുന്നതായിരിക്കും ബുദ്ധിമുട്ടുള്ള ഭാഗം; അത് ചെയ്തുകഴിഞ്ഞാൽ, 🤗 Datasets ലൈബ്രറിയിലെ മെട്രിക് ബാക്കി ജോലിയുടെ ഭൂരിഭാഗവും നമുക്കായി ചെയ്യും. + +{:else} + +## Keras ഉപയോഗിച്ച് മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യുന്നു[[fine-tuning-the-model-with-keras]] + +ഈ ഉദാഹരണത്തിനുള്ള ട്രെയിനിംഗ് കോഡ് മുൻ ഭാഗങ്ങളിലെ കോഡിനോട് ഏറെ സാമ്യമുള്ളതായിരിക്കും, എന്നാൽ മെട്രിക്കുകൾ കണക്കാക്കുന്നത് സവിശേഷമായ ഒരു വെല്ലുവിളിയായിരിക്കും. എല്ലാ സാമ്പിളുകളും നമ്മൾ സെറ്റ് ചെയ്ത പരമാവധി ദൈർഘ്യത്തിലേക്ക് പാഡ് ചെയ്തതിനാൽ, നിർവചിക്കാൻ ഒരു ഡേറ്റാ കൊളേറ്ററും ഇല്ല; അതിനാൽ ഈ മെട്രിക് കണക്കുകൂട്ടൽ മാത്രമാണ് നമ്മൾ ശ്രദ്ധിക്കേണ്ട ഒരേയൊരു കാര്യം. മോഡലിന്റെ പ്രവചനങ്ങളെ യഥാർത്ഥ ഉദാഹരണങ്ങളിലെ ടെക്‌സ്‌റ്റ് സ്‌പാനുകളായി പോസ്‌റ്റ്-പ്രോസസ്സ് ചെയ്യുന്നതായിരിക്കും ബുദ്ധിമുട്ടുള്ള ഭാഗം; അത് ചെയ്തുകഴിഞ്ഞാൽ, 🤗 Datasets ലൈബ്രറിയിലെ മെട്രിക് ബാക്കി ജോലിയുടെ ഭൂരിഭാഗവും നമുക്കായി ചെയ്യും. + +{/if} + +### പോസ്‌റ്റ്-പ്രോസസ്സിംഗ്[[post-processing]] + +{#if fw === 'pt'} + + + +{:else} + + + +{/if} + +[`question-answering` പൈപ്പ്‌ലൈൻ](/course/chapter6/3b) പരിശോധിച്ചപ്പോൾ നമ്മൾ കണ്ടതുപോലെ, ഇൻപുട്ട് ID-കളിലെ ഉത്തരത്തിന്റെ ആരംഭ, അവസാന സ്ഥാനങ്ങൾക്കുള്ള ലോജിറ്റുകൾ മോഡൽ ഔട്ട്‌പുട്ട് ചെയ്യും. പോസ്‌റ്റ്-പ്രോസസ്സിംഗ് ഘട്ടം അവിടെ നമ്മൾ ചെയ്തതിന് സമാനമായിരിക്കും, അതിനാൽ നമ്മൾ സ്വീകരിച്ച നടപടികളുടെ ഒരു ചെറിയ ഓർമ്മപ്പെടുത്തൽ ഇതാ: + +- കോൺടെക്‌സ്‌റ്റിന് പുറത്തുള്ള ടോക്കണുകൾക്ക് അനുബന്ധമായ ആരംഭ, അവസാന ലോജിറ്റുകൾ നമ്മൾ മാസ്‌ക് ചെയ്തു. +- തുടർന്ന് ഒരു സോഫ്‌റ്റ്‌മാക്‌സ് ഉപയോഗിച്ച് ആരംഭ, അവസാന ലോജിറ്റുകളെ പ്രോബബിലിറ്റികളാക്കി മാറ്റി. +- അനുബന്ധമായ രണ്ട് പ്രോബബിലിറ്റികളുടെ ഗുണനഫലം എടുത്ത് ഓരോ `(start_token, end_token)` ജോഡിക്കും ഒരു സ്‌കോർ നൽകി. +- സാധുവായ ഒരു ഉത്തരം നൽകുന്ന (ഉദാഹരണത്തിന്, `end_token`-നേക്കാൾ ചെറിയ ഒരു `start_token`) പരമാവധി സ്‌കോറുള്ള ജോഡി നമ്മൾ തിരഞ്ഞു. + +ഇവിടെ ഈ പ്രക്രിയ നമ്മൾ അൽപ്പം മാറ്റും, കാരണം യഥാർത്ഥ സ്‌കോറുകൾ കണക്കാക്കേണ്ട ആവശ്യമില്ല (പ്രവചിച്ച ഉത്തരം മാത്രം മതി). അതിനർത്ഥം സോഫ്‌റ്റ്‌മാക്‌സ് ഘട്ടം നമുക്ക് ഒഴിവാക്കാം എന്നാണ്. വേഗത കൂട്ടാൻ, സാധ്യമായ എല്ലാ `(start_token, end_token)` ജോഡികൾക്കും നമ്മൾ സ്‌കോർ നൽകില്ല, പകരം ഏറ്റവും ഉയർന്ന `n_best` ലോജിറ്റുകൾക്ക് അനുബന്ധമായവയ്ക്ക് മാത്രം (`n_best=20` ഉപയോഗിച്ച്). സോഫ്‌റ്റ്‌മാക്‌സ് ഒഴിവാക്കുന്നതിനാൽ, ആ സ്‌കോറുകൾ ലോജിറ്റ് സ്‌കോറുകളായിരിക്കും, ആരംഭ, അവസാന ലോജിറ്റുകളുടെ തുക എടുത്താണ് അവ ലഭിക്കുന്നത് (ഗുണനഫലത്തിന് പകരം, \\(\log(ab) = \log(a) + \log(b)\\) എന്ന നിയമം കാരണം). + +ഇതെല്ലാം കാണിച്ചുതരാൻ, ഏതെങ്കിലും തരത്തിലുള്ള പ്രവചനങ്ങൾ നമുക്ക് ആവശ്യമാണ്. നമ്മുടെ മോഡൽ ഇതുവരെ ട്രെയിൻ ചെയ്തിട്ടില്ലാത്തതിനാൽ, വാലിഡേഷൻ സെറ്റിന്റെ ഒരു ചെറിയ ഭാഗത്തിൽ ചില പ്രവചനങ്ങൾ ഉണ്ടാക്കാൻ QA പൈപ്പ്‌ലൈനിന്റെ ഡിഫോൾട്ട് മോഡൽ നമ്മൾ ഉപയോഗിക്കാൻ പോകുന്നു. മുമ്പത്തെ അതേ പ്രോസസ്സിംഗ് ഫംഗ്‌ഷൻ നമുക്ക് ഉപയോഗിക്കാം; അത് `tokenizer` എന്ന ഗ്ലോബൽ കോൺസ്‌റ്റന്റിനെ ആശ്രയിക്കുന്നതിനാൽ, ആ ഒബ്‌ജക്റ്റിനെ താൽക്കാലികമായി ഉപയോഗിക്കാൻ ആഗ്രഹിക്കുന്ന മോഡലിന്റെ ടോക്കണൈസറാക്കി മാറ്റിയാൽ മാത്രം മതി: + +```python +small_eval_set = raw_datasets["validation"].select(range(100)) +trained_checkpoint = "distilbert-base-cased-distilled-squad" + +tokenizer = AutoTokenizer.from_pretrained(trained_checkpoint) +eval_set = small_eval_set.map( + preprocess_validation_examples, + batched=True, + remove_columns=raw_datasets["validation"].column_names, +) +``` + +പ്രീപ്രോസസ്സിംഗ് പൂർത്തിയായതിനാൽ, ടോക്കണൈസറിനെ നമ്മൾ ആദ്യം തിരഞ്ഞെടുത്തതിലേക്ക് തിരികെ മാറ്റുന്നു: + +```python +tokenizer = AutoTokenizer.from_pretrained(model_checkpoint) +``` + +തുടർന്ന് നമ്മുടെ `eval_set`-ലെ, മോഡൽ പ്രതീക്ഷിക്കാത്ത കോളങ്ങൾ നീക്കം ചെയ്യുകയും, ആ ചെറിയ വാലിഡേഷൻ സെറ്റ് മുഴുവനും ഉപയോഗിച്ച് ഒരു ബാച്ച് ഉണ്ടാക്കുകയും, അത് മോഡലിലൂടെ കടത്തിവിടുകയും ചെയ്യുന്നു. ഒരു GPU ലഭ്യമാണെങ്കിൽ, വേഗത കൂട്ടാൻ അത് ഉപയോഗിക്കുന്നു: + +{#if fw === 'pt'} + +```python +import torch +from transformers import AutoModelForQuestionAnswering + +eval_set_for_model = eval_set.remove_columns(["example_id", "offset_mapping"]) +eval_set_for_model.set_format("torch") + +device = torch.device("cuda") if torch.cuda.is_available() else torch.device("cpu") +batch = {k: eval_set_for_model[k].to(device) for k in eval_set_for_model.column_names} +trained_model = AutoModelForQuestionAnswering.from_pretrained(trained_checkpoint).to( + device +) + +with torch.no_grad(): + outputs = trained_model(**batch) +``` + +`Trainer` നമുക്ക് പ്രവചനങ്ങൾ NumPy അറേകളായി നൽകുന്നതിനാൽ, ആരംഭ, അവസാന ലോജിറ്റുകൾ എടുത്ത് ആ ഫോർമാറ്റിലേക്ക് മാറ്റുന്നു: + +```python +start_logits = outputs.start_logits.cpu().numpy() +end_logits = outputs.end_logits.cpu().numpy() +``` + +{:else} + +```python +import tensorflow as tf +from transformers import TFAutoModelForQuestionAnswering + +eval_set_for_model = eval_set.remove_columns(["example_id", "offset_mapping"]) +eval_set_for_model.set_format("numpy") + +batch = {k: eval_set_for_model[k] for k in eval_set_for_model.column_names} +trained_model = TFAutoModelForQuestionAnswering.from_pretrained(trained_checkpoint) + +outputs = trained_model(**batch) +``` + +പരീക്ഷണങ്ങൾ എളുപ്പമാക്കാൻ, ഈ ഔട്ട്‌പുട്ടുകളെ NumPy അറേകളാക്കി മാറ്റാം: + +```python +start_logits = outputs.start_logits.numpy() +end_logits = outputs.end_logits.numpy() +``` + +{/if} + +ഇപ്പോൾ, നമ്മുടെ `small_eval_set`-ലെ ഓരോ ഉദാഹരണത്തിനും പ്രവചിച്ച ഉത്തരം കണ്ടെത്തണം. ഒരു ഉദാഹരണം `eval_set`-ൽ ഒന്നിലധികം ഫീച്ചറുകളായി വിഭജിക്കപ്പെട്ടിരിക്കാം, അതിനാൽ `small_eval_set`-ലെ ഓരോ ഉദാഹരണത്തെയും `eval_set`-ലെ അനുബന്ധ ഫീച്ചറുകളുമായി മാപ്പ് ചെയ്യുകയാണ് ആദ്യ ഘട്ടം: + +```python +import collections + +example_to_features = collections.defaultdict(list) +for idx, feature in enumerate(eval_set): + example_to_features[feature["example_id"]].append(idx) +``` + +ഇത് കൈയിലുള്ളപ്പോൾ, എല്ലാ ഉദാഹരണങ്ങളിലൂടെയും, ഓരോ ഉദാഹരണത്തിനും അതുമായി ബന്ധപ്പെട്ട എല്ലാ ഫീച്ചറുകളിലൂടെയും ലൂപ്പ് ചെയ്തുകൊണ്ട് നമുക്ക് ശരിക്കും ജോലി തുടങ്ങാം. മുമ്പ് പറഞ്ഞതുപോലെ, `n_best` ആരംഭ ലോജിറ്റുകളുടെയും അവസാന ലോജിറ്റുകളുടെയും ലോജിറ്റ് സ്‌കോറുകൾ നമ്മൾ നോക്കും; താഴെപ്പറയുന്നവ നൽകുന്ന സ്ഥാനങ്ങൾ ഒഴിവാക്കിക്കൊണ്ട്: + +- കോൺടെക്‌സ്‌റ്റിനുള്ളിൽ അല്ലാത്ത ഒരു ഉത്തരം +- നെഗറ്റീവ് ദൈർഘ്യമുള്ള ഒരു ഉത്തരം +- വളരെ നീണ്ട ഒരു ഉത്തരം (സാധ്യതകളെ നമ്മൾ `max_answer_length=30`-ൽ പരിമിതപ്പെടുത്തുന്നു) + +ഒരു ഉദാഹരണത്തിന് സ്‌കോർ നൽകിയ സാധ്യമായ എല്ലാ ഉത്തരങ്ങളും ലഭിച്ചുകഴിഞ്ഞാൽ, ഏറ്റവും മികച്ച ലോജിറ്റ് സ്‌കോറുള്ളത് നമ്മൾ തിരഞ്ഞെടുക്കുന്നു: + +```python +import numpy as np + +n_best = 20 +max_answer_length = 30 +predicted_answers = [] + +for example in small_eval_set: + example_id = example["id"] + context = example["context"] + answers = [] + + for feature_index in example_to_features[example_id]: + start_logit = start_logits[feature_index] + end_logit = end_logits[feature_index] + offsets = eval_set["offset_mapping"][feature_index] + + start_indexes = np.argsort(start_logit)[-1 : -n_best - 1 : -1].tolist() + end_indexes = np.argsort(end_logit)[-1 : -n_best - 1 : -1].tolist() + for start_index in start_indexes: + for end_index in end_indexes: + # Skip answers that are not fully in the context + if offsets[start_index] is None or offsets[end_index] is None: + continue + # Skip answers with a length that is either < 0 or > max_answer_length. + if ( + end_index < start_index + or end_index - start_index + 1 > max_answer_length + ): + continue + + answers.append( + { + "text": context[offsets[start_index][0] : offsets[end_index][1]], + "logit_score": start_logit[start_index] + end_logit[end_index], + } + ) + + best_answer = max(answers, key=lambda x: x["logit_score"]) + predicted_answers.append({"id": example_id, "prediction_text": best_answer["text"]}) +``` + +പ്രവചിച്ച ഉത്തരങ്ങളുടെ അന്തിമ ഫോർമാറ്റ്, നമ്മൾ ഉപയോഗിക്കാൻ പോകുന്ന മെട്രിക് പ്രതീക്ഷിക്കുന്ന ഫോർമാറ്റാണ്. പതിവുപോലെ, 🤗 Evaluate ലൈബ്രറിയുടെ സഹായത്തോടെ അത് ലോഡ് ചെയ്യാം: + +```python +import evaluate + +metric = evaluate.load("squad") +``` + +ഈ മെട്രിക് പ്രവചിച്ച ഉത്തരങ്ങൾ മുകളിൽ നമ്മൾ കണ്ട ഫോർമാറ്റിലും (ഉദാഹരണത്തിന്റെ ID-ക്ക് ഒരു കീയും പ്രവചിച്ച ടെക്‌സ്‌റ്റിന് ഒരു കീയുമുള്ള ഡിക്‌ഷണറികളുടെ ഒരു ലിസ്‌റ്റ്), സൈദ്ധാന്തിക ഉത്തരങ്ങൾ താഴെയുള്ള ഫോർമാറ്റിലും (ഉദാഹരണത്തിന്റെ ID-ക്ക് ഒരു കീയും സാധ്യമായ ഉത്തരങ്ങൾക്ക് ഒരു കീയുമുള്ള ഡിക്‌ഷണറികളുടെ ഒരു ലിസ്‌റ്റ്) പ്രതീക്ഷിക്കുന്നു: + +```python +theoretical_answers = [ + {"id": ex["id"], "answers": ex["answers"]} for ex in small_eval_set +] +``` + +രണ്ട് ലിസ്‌റ്റുകളുടെയും ആദ്യ എലമെന്റ് നോക്കി യുക്തിസഹമായ ഫലങ്ങളാണ് ലഭിക്കുന്നതെന്ന് ഇപ്പോൾ നമുക്ക് പരിശോധിക്കാം: + +```python +print(predicted_answers[0]) +print(theoretical_answers[0]) +``` + +```python out +{'id': '56be4db0acb8001400a502ec', 'prediction_text': 'Denver Broncos'} +{'id': '56be4db0acb8001400a502ec', 'answers': {'text': ['Denver Broncos', 'Denver Broncos', 'Denver Broncos'], 'answer_start': [177, 177, 177]}} +``` + +മോശമില്ല! ഇനി മെട്രിക് നമുക്ക് നൽകുന്ന സ്‌കോർ ഒന്ന് നോക്കാം: + +```python +metric.compute(predictions=predicted_answers, references=theoretical_answers) +``` + +```python out +{'exact_match': 83.0, 'f1': 88.25} +``` + +[അതിന്റെ പ്രബന്ധം](https://arxiv.org/abs/1910.01108v2) അനുസരിച്ച്, SQuAD-ൽ ഫൈൻ-ട്യൂൻ ചെയ്ത DistilBERT മുഴുവൻ ഡേറ്റാസെറ്റിലും ആ സ്‌കോറുകൾക്ക് 79.1-ഉം 86.9-ഉം ആണ് നേടുന്നത് എന്നത് കണക്കിലെടുക്കുമ്പോൾ, ഇത് വീണ്ടും വളരെ മികച്ചതാണ്. + +{#if fw === 'pt'} + +ഇനി നമ്മൾ ഇപ്പോൾ ചെയ്തതെല്ലാം `Trainer`-ൽ ഉപയോഗിക്കാനുള്ള ഒരു `compute_metrics()` ഫംഗ്‌ഷനിൽ ഒരുമിച്ച് ചേർക്കാം. സാധാരണയായി, ആ `compute_metrics()` ഫംഗ്‌ഷന് ലോജിറ്റുകളും ലേബലുകളുമുള്ള `eval_preds` എന്ന ഒരു ട്യൂപ്പിൾ മാത്രമേ ലഭിക്കൂ. ഇവിടെ നമുക്ക് അൽപ്പം കൂടുതൽ ആവശ്യമാണ്, കാരണം ഓഫ്‌സെറ്റിനായി ഫീച്ചറുകളുടെ ഡേറ്റാസെറ്റിലും യഥാർത്ഥ കോൺടെക്‌സ്‌റ്റുകൾക്കായി ഉദാഹരണങ്ങളുടെ ഡേറ്റാസെറ്റിലും നമ്മൾ നോക്കേണ്ടതുണ്ട്; അതിനാൽ ട്രെയിനിംഗ് സമയത്ത് പതിവായ ഇവാല്യുവേഷൻ ഫലങ്ങൾ ലഭിക്കാൻ ഈ ഫംഗ്‌ഷൻ നമുക്ക് ഉപയോഗിക്കാൻ കഴിയില്ല. ഫലങ്ങൾ പരിശോധിക്കാൻ ട്രെയിനിംഗിന്റെ അവസാനം മാത്രമേ നമ്മൾ ഇത് ഉപയോഗിക്കൂ. + +`compute_metrics()` ഫംഗ്‌ഷൻ മുമ്പത്തെ അതേ ഘട്ടങ്ങളാണ് ഒരുമിച്ച് ചേർക്കുന്നത്; സാധുവായ ഉത്തരങ്ങളൊന്നും ലഭിക്കാത്ത സാഹചര്യത്തിനായി (അപ്പോൾ നമ്മൾ ഒരു ശൂന്യ സ്‌ട്രിംഗ് പ്രവചിക്കുന്നു) ഒരു ചെറിയ പരിശോധന മാത്രം കൂട്ടിച്ചേർക്കുന്നു. + +{:else} + +ഇനി നമ്മൾ ഇപ്പോൾ ചെയ്തതെല്ലാം, മോഡൽ ട്രെയിൻ ചെയ്ത ശേഷം ഉപയോഗിക്കാനുള്ള ഒരു `compute_metrics()` ഫംഗ്‌ഷനിൽ ഒരുമിച്ച് ചേർക്കാം. ഔട്ട്‌പുട്ട് ലോജിറ്റുകൾ മാത്രമല്ല, അൽപ്പം കൂടുതൽ കാര്യങ്ങൾ നമുക്ക് നൽകേണ്ടിവരും, കാരണം ഓഫ്‌സെറ്റിനായി ഫീച്ചറുകളുടെ ഡേറ്റാസെറ്റിലും യഥാർത്ഥ കോൺടെക്‌സ്‌റ്റുകൾക്കായി ഉദാഹരണങ്ങളുടെ ഡേറ്റാസെറ്റിലും നമ്മൾ നോക്കേണ്ടതുണ്ട്: + +{/if} + +```python +from tqdm.auto import tqdm + + +def compute_metrics(start_logits, end_logits, features, examples): + example_to_features = collections.defaultdict(list) + for idx, feature in enumerate(features): + example_to_features[feature["example_id"]].append(idx) + + predicted_answers = [] + for example in tqdm(examples): + example_id = example["id"] + context = example["context"] + answers = [] + + # Loop through all features associated with that example + for feature_index in example_to_features[example_id]: + start_logit = start_logits[feature_index] + end_logit = end_logits[feature_index] + offsets = features[feature_index]["offset_mapping"] + + start_indexes = np.argsort(start_logit)[-1 : -n_best - 1 : -1].tolist() + end_indexes = np.argsort(end_logit)[-1 : -n_best - 1 : -1].tolist() + for start_index in start_indexes: + for end_index in end_indexes: + # Skip answers that are not fully in the context + if offsets[start_index] is None or offsets[end_index] is None: + continue + # Skip answers with a length that is either < 0 or > max_answer_length + if ( + end_index < start_index + or end_index - start_index + 1 > max_answer_length + ): + continue + + answer = { + "text": context[offsets[start_index][0] : offsets[end_index][1]], + "logit_score": start_logit[start_index] + end_logit[end_index], + } + answers.append(answer) + + # Select the answer with the best score + if len(answers) > 0: + best_answer = max(answers, key=lambda x: x["logit_score"]) + predicted_answers.append( + {"id": example_id, "prediction_text": best_answer["text"]} + ) + else: + predicted_answers.append({"id": example_id, "prediction_text": ""}) + + theoretical_answers = [{"id": ex["id"], "answers": ex["answers"]} for ex in examples] + return metric.compute(predictions=predicted_answers, references=theoretical_answers) +``` + +നമ്മുടെ പ്രവചനങ്ങളിൽ ഇത് പ്രവർത്തിക്കുന്നുണ്ടോ എന്ന് പരിശോധിക്കാം: + +```python +compute_metrics(start_logits, end_logits, eval_set, small_eval_set) +``` + +```python out +{'exact_match': 83.0, 'f1': 88.25} +``` + +നന്നായി കാണപ്പെടുന്നു! ഇനി നമ്മുടെ മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യാൻ ഇത് ഉപയോഗിക്കാം. + +### മോഡൽ ഫൈൻ-ട്യൂൻ ചെയ്യുന്നു[[fine-tuning-the-model]] + +{#if fw === 'pt'} + +ഇപ്പോൾ നമ്മുടെ മോഡൽ ട്രെയിൻ ചെയ്യാൻ നമ്മൾ തയ്യാറാണ്. മുമ്പത്തെപ്പോലെ `AutoModelForQuestionAnswering` ക്ലാസ് ഉപയോഗിച്ച് ആദ്യം അത് ഉണ്ടാക്കാം: + +```python +model = AutoModelForQuestionAnswering.from_pretrained(model_checkpoint) +``` + +{:else} + +ഇപ്പോൾ നമ്മുടെ മോഡൽ ട്രെയിൻ ചെയ്യാൻ നമ്മൾ തയ്യാറാണ്. മുമ്പത്തെപ്പോലെ `TFAutoModelForQuestionAnswering` ക്ലാസ് ഉപയോഗിച്ച് ആദ്യം അത് ഉണ്ടാക്കാം: + +```python +model = TFAutoModelForQuestionAnswering.from_pretrained(model_checkpoint) +``` + +{/if} + +പതിവുപോലെ, ചില വെയ്‌റ്റുകൾ ഉപയോഗിച്ചിട്ടില്ലെന്നും (പ്രീട്രെയിനിംഗ് ഹെഡിന്റേത്) മറ്റു ചിലത് ക്രമരഹിതമായി ഇനിഷ്യലൈസ് ചെയ്യപ്പെട്ടിരിക്കുന്നു എന്നും (ചോദ്യോത്തര ഹെഡിന്റേത്) ഒരു മുന്നറിയിപ്പ് നമുക്ക് ലഭിക്കുന്നു. ഇപ്പോൾ നിങ്ങൾക്ക് ഇത് പരിചിതമായിരിക്കണം, എന്നാൽ ഈ മോഡൽ ഇപ്പോൾത്തന്നെ ഉപയോഗിക്കാൻ തയ്യാറല്ലെന്നും ഫൈൻ-ട്യൂണിംഗ് ആവശ്യമാണെന്നുമാണ് അതിനർത്ഥം -- നമ്മൾ അത് ചെയ്യാൻ പോകുന്നു എന്നത് നല്ല കാര്യം! + +നമ്മുടെ മോഡൽ Hub-ലേക്ക് പുഷ് ചെയ്യാൻ കഴിയണമെങ്കിൽ, Hugging Face-ൽ ലോഗിൻ ചെയ്യേണ്ടതുണ്ട്. ഈ കോഡ് ഒരു നോട്ട്‌ബുക്കിലാണ് നിങ്ങൾ റൺ ചെയ്യുന്നതെങ്കിൽ, താഴെയുള്ള യൂട്ടിലിറ്റി ഫംഗ്‌ഷൻ ഉപയോഗിച്ച് അത് ചെയ്യാം; നിങ്ങളുടെ ലോഗിൻ വിവരങ്ങൾ നൽകാവുന്ന ഒരു വിഡ്‌ജെറ്റ് ഇത് കാണിക്കും: + +```python +from huggingface_hub import notebook_login + +notebook_login() +``` + +നിങ്ങൾ ഒരു നോട്ട്‌ബുക്കിലല്ല പ്രവർത്തിക്കുന്നതെങ്കിൽ, നിങ്ങളുടെ ടെർമിനലിൽ താഴെയുള്ള വരി ടൈപ്പ് ചെയ്താൽ മതി: + +```bash +huggingface-cli login +``` + +{#if fw === 'pt'} + +ഇത് ചെയ്തുകഴിഞ്ഞാൽ, നമ്മുടെ `TrainingArguments` നിർവചിക്കാം. മെട്രിക് കണക്കാക്കാനുള്ള ഫംഗ്‌ഷൻ നിർവചിച്ചപ്പോൾ പറഞ്ഞതുപോലെ, `compute_metrics()` ഫംഗ്‌ഷന്റെ സിഗ്നേച്ചർ കാരണം ഒരു പതിവായ ഇവാല്യുവേഷൻ ലൂപ്പ് നമുക്ക് സാധ്യമാകില്ല. ഇത് ചെയ്യാൻ `Trainer`-ന്റെ നമ്മുടെ സ്വന്തം സബ്‌ക്ലാസ് എഴുതാമായിരുന്നു ([ചോദ്യോത്തര ഉദാഹരണ സ്‌ക്രിപ്‌റ്റിൽ](https://github.com/huggingface/transformers/blob/master/examples/pytorch/question-answering/trainer_qa.py) നിങ്ങൾക്ക് കാണാവുന്ന ഒരു സമീപനം), എന്നാൽ ഈ ഭാഗത്തിന് അത് അൽപ്പം ദൈർഘ്യമേറിയതാണ്. പകരം, ഇവിടെ ട്രെയിനിംഗിന്റെ അവസാനം മാത്രം മോഡൽ ഇവാല്യുവേറ്റ് ചെയ്യുകയും, താഴെ "ഒരു ഇഷ്ടാനുസൃത ട്രെയിനിംഗ് ലൂപ്പ്" എന്ന ഭാഗത്തിൽ പതിവായ ഇവാല്യുവേഷൻ എങ്ങനെ ചെയ്യാമെന്ന് കാണിച്ചുതരികയും ചെയ്യും. + +`Trainer` API-യുടെ പരിമിതികൾ വെളിപ്പെടുന്നതും 🤗 Accelerate ലൈബ്രറി തിളങ്ങുന്നതും ശരിക്കും ഇവിടെയാണ്: ഒരു പ്രത്യേക ഉപയോഗ സാഹചര്യത്തിനായി ക്ലാസ് ഇഷ്ടാനുസൃതമാക്കുന്നത് ബുദ്ധിമുട്ടേറിയതാകാം, എന്നാൽ പൂർണ്ണമായി തുറന്നുകിടക്കുന്ന ഒരു ട്രെയിനിംഗ് ലൂപ്പിൽ മാറ്റങ്ങൾ വരുത്തുന്നത് എളുപ്പമാണ്. + +നമ്മുടെ `TrainingArguments` ഒന്ന് നോക്കാം: + +```python +from transformers import TrainingArguments + +args = TrainingArguments( + "bert-finetuned-squad", + evaluation_strategy="no", + save_strategy="epoch", + learning_rate=2e-5, + num_train_epochs=3, + weight_decay=0.01, + fp16=True, + push_to_hub=True, +) +``` + +ഇവയിൽ മിക്കതും നമ്മൾ മുമ്പ് കണ്ടിട്ടുണ്ട്: ചില ഹൈപ്പർപാരാമീറ്ററുകൾ (ലേണിംഗ് റേറ്റ്, നമ്മൾ ട്രെയിൻ ചെയ്യുന്ന എപ്പോക്കുകളുടെ എണ്ണം, കുറച്ച് വെയ്‌റ്റ് ഡികേ എന്നിവ പോലെ) നമ്മൾ സെറ്റ് ചെയ്യുന്നു, കൂടാതെ ഓരോ എപ്പോക്കിന്റെയും അവസാനം മോഡൽ സേവ് ചെയ്യണമെന്നും, ഇവാല്യുവേഷൻ ഒഴിവാക്കണമെന്നും, നമ്മുടെ ഫലങ്ങൾ Model Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യണമെന്നും സൂചിപ്പിക്കുന്നു. `fp16=True` ഉപയോഗിച്ച് മിക്‌സഡ്-പ്രിസിഷൻ ട്രെയിനിംഗും നമ്മൾ പ്രവർത്തനക്ഷമമാക്കുന്നു, കാരണം ഒരു പുതിയ GPU-വിൽ അത് ട്രെയിനിംഗിന്റെ വേഗത നന്നായി കൂട്ടും. + +{:else} + +അത് ചെയ്തുകഴിഞ്ഞതിനാൽ, നമ്മുടെ TF Datasets ഉണ്ടാക്കാം. ഇത്തവണ ലളിതമായ ഡിഫോൾട്ട് ഡേറ്റാ കൊളേറ്റർ നമുക്ക് ഉപയോഗിക്കാം: + +```python +from transformers import DefaultDataCollator + +data_collator = DefaultDataCollator(return_tensors="tf") +``` + +ഇപ്പോൾ പതിവുപോലെ ഡേറ്റാസെറ്റുകൾ ഉണ്ടാക്കുന്നു. + +```python +tf_train_dataset = model.prepare_tf_dataset( + train_dataset, + collate_fn=data_collator, + shuffle=True, + batch_size=16, +) +tf_eval_dataset = model.prepare_tf_dataset( + validation_dataset, + collate_fn=data_collator, + shuffle=False, + batch_size=16, +) +``` + +അടുത്തതായി, നമ്മുടെ ട്രെയിനിംഗ് ഹൈപ്പർപാരാമീറ്ററുകൾ സെറ്റപ്പ് ചെയ്ത് മോഡൽ കംപൈൽ ചെയ്യുന്നു: + +```python +from transformers import create_optimizer +from transformers.keras_callbacks import PushToHubCallback +import tensorflow as tf + +# The number of training steps is the number of samples in the dataset, divided by the batch size then multiplied +# by the total number of epochs. Note that the tf_train_dataset here is a batched tf.data.Dataset, +# not the original Hugging Face Dataset, so its len() is already num_samples // batch_size. +num_train_epochs = 3 +num_train_steps = len(tf_train_dataset) * num_train_epochs +optimizer, schedule = create_optimizer( + init_lr=2e-5, + num_warmup_steps=0, + num_train_steps=num_train_steps, + weight_decay_rate=0.01, +) +model.compile(optimizer=optimizer) + +# Train in mixed-precision float16 +tf.keras.mixed_precision.set_global_policy("mixed_float16") +``` + +അവസാനമായി, `model.fit()` ഉപയോഗിച്ച് ട്രെയിൻ ചെയ്യാൻ നമ്മൾ തയ്യാറാണ്. ഓരോ എപ്പോക്കിന് ശേഷവും മോഡൽ Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യാൻ ഒരു `PushToHubCallback` നമ്മൾ ഉപയോഗിക്കുന്നു. + +{/if} + +ഡിഫോൾട്ടായി, ഉപയോഗിക്കുന്ന റിപ്പോസിറ്ററി നിങ്ങളുടെ നെയിംസ്‌പേസിൽ ആയിരിക്കും, നിങ്ങൾ സെറ്റ് ചെയ്ത ഔട്ട്‌പുട്ട് ഡയറക്ടറിയുടെ പേരിലായിരിക്കും അത്; അതിനാൽ നമ്മുടെ കാര്യത്തിൽ അത് `"sgugger/bert-finetuned-squad"`-ൽ ആയിരിക്കും. ഒരു `hub_model_id` നൽകിക്കൊണ്ട് ഇത് നമുക്ക് മാറ്റാം; ഉദാഹരണത്തിന്, `huggingface_course` ഓർഗനൈസേഷനിലേക്ക് മോഡൽ പുഷ് ചെയ്യാൻ നമ്മൾ `hub_model_id="huggingface_course/bert-finetuned-squad"` ഉപയോഗിച്ചു (ഈ ഭാഗത്തിന്റെ തുടക്കത്തിൽ നമ്മൾ ലിങ്ക് ചെയ്ത മോഡലാണിത്). + +{#if fw === 'pt'} + +> [!TIP] +> 💡 നിങ്ങൾ ഉപയോഗിക്കുന്ന ഔട്ട്‌പുട്ട് ഡയറക്ടറി നിലവിലുണ്ടെങ്കിൽ, അത് നിങ്ങൾ പുഷ് ചെയ്യാൻ ആഗ്രഹിക്കുന്ന റിപ്പോസിറ്ററിയുടെ ഒരു ലോക്കൽ ക്ലോൺ ആയിരിക്കണം (അതിനാൽ നിങ്ങളുടെ `Trainer` നിർവചിക്കുമ്പോൾ ഒരു എറർ ലഭിച്ചാൽ ഒരു പുതിയ പേര് സെറ്റ് ചെയ്യുക). + +അവസാനമായി, എല്ലാം `Trainer` ക്ലാസിന് നൽകി ട്രെയിനിംഗ് ആരംഭിക്കുന്നു: + +```python +from transformers import Trainer + +trainer = Trainer( + model=model, + args=args, + train_dataset=train_dataset, + eval_dataset=validation_dataset, + tokenizer=tokenizer, +) +trainer.train() +``` + +{:else} + +```python +from transformers.keras_callbacks import PushToHubCallback + +callback = PushToHubCallback(output_dir="bert-finetuned-squad", tokenizer=tokenizer) + +# We're going to do validation afterwards, so no validation mid-training +model.fit(tf_train_dataset, callbacks=[callback], epochs=num_train_epochs) +``` + +{/if} + +ട്രെയിനിംഗ് നടക്കുമ്പോൾ, മോഡൽ സേവ് ചെയ്യപ്പെടുന്ന ഓരോ തവണയും (ഇവിടെ, ഓരോ എപ്പോക്കിലും) അത് പശ്ചാത്തലത്തിൽ Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യപ്പെടുന്നു എന്നത് ശ്രദ്ധിക്കുക. ഇങ്ങനെ, ആവശ്യമെങ്കിൽ മറ്റൊരു മെഷീനിൽ നിങ്ങളുടെ ട്രെയിനിംഗ് പുനരാരംഭിക്കാൻ നിങ്ങൾക്ക് കഴിയും. മുഴുവൻ ട്രെയിനിംഗിനും കുറച്ച് സമയമെടുക്കും (ഒരു Titan RTX-ൽ ഒരു മണിക്കൂറിൽ കുറച്ചധികം), അതിനാൽ അത് പുരോഗമിക്കുമ്പോൾ നിങ്ങൾക്ക് ഒരു കാപ്പി കുടിക്കാം, അല്ലെങ്കിൽ കോഴ്‌സിൽ കൂടുതൽ വെല്ലുവിളിയായി തോന്നിയ ഭാഗങ്ങൾ വീണ്ടും വായിക്കാം. ആദ്യത്തെ എപ്പോക്ക് പൂർത്തിയായ ഉടൻ, ചില വെയ്‌റ്റുകൾ Hub-ലേക്ക് അപ്‌ലോഡ് ചെയ്യപ്പെട്ടതായി നിങ്ങൾ കാണും, അതിന്റെ പേജിൽ നിങ്ങളുടെ മോഡലുമായി കളിച്ചുതുടങ്ങാം എന്നതും ശ്രദ്ധിക്കുക. + +{#if fw === 'pt'} + +ട്രെയിനിംഗ് പൂർത്തിയായിക്കഴിഞ്ഞാൽ, ഒടുവിൽ നമ്മുടെ മോഡൽ ഇവാല്യുവേറ്റ് ചെയ്യാം (ആ കമ്പ്യൂട്ട് സമയമെല്ലാം വെറുതെയായില്ലെന്ന് പ്രാർത്ഥിക്കുകയും ചെയ്യാം). `Trainer`-ന്റെ `predict()` മെത്തേഡ് ഒരു ട്യൂപ്പിൾ റിട്ടേൺ ചെയ്യും; അതിലെ ആദ്യ എലമെന്റുകൾ മോഡലിന്റെ പ്രവചനങ്ങളായിരിക്കും (ഇവിടെ ആരംഭ, അവസാന ലോജിറ്റുകളുള്ള ഒരു ജോഡി). ഇത് നമ്മുടെ `compute_metrics()` ഫംഗ്‌ഷന് നൽകുന്നു: + +```python +predictions, _, _ = trainer.predict(validation_dataset) +start_logits, end_logits = predictions +compute_metrics(start_logits, end_logits, validation_dataset, raw_datasets["validation"]) +``` + +{:else} + +ട്രെയിനിംഗ് പൂർത്തിയായിക്കഴിഞ്ഞാൽ, ഒടുവിൽ നമ്മുടെ മോഡൽ ഇവാല്യുവേറ്റ് ചെയ്യാം (ആ കമ്പ്യൂട്ട് സമയമെല്ലാം വെറുതെയായില്ലെന്ന് പ്രാർത്ഥിക്കുകയും ചെയ്യാം). നമ്മുടെ `model`-ന്റെ `predict()` മെത്തേഡ് പ്രവചനങ്ങൾ നേടുന്ന കാര്യം ഏറ്റെടുക്കും, കൂടാതെ ഒരു `compute_metrics()` ഫംഗ്‌ഷൻ നിർവചിക്കുന്ന കഠിനമായ ജോലിയെല്ലാം നമ്മൾ മുമ്പേ ചെയ്തതിനാൽ, ഒരൊറ്റ വരിയിൽ നമുക്ക് ഫലങ്ങൾ ലഭിക്കും: + +```python +predictions = model.predict(tf_eval_dataset) +compute_metrics( + predictions["start_logits"], + predictions["end_logits"], + validation_dataset, + raw_datasets["validation"], +) +``` + +{/if} + +```python out +{'exact_match': 81.18259224219489, 'f1': 88.67381321905516} +``` + +വളരെ നന്നായി! താരതമ്യത്തിനായി, ഈ മോഡലിന് BERT ലേഖനത്തിൽ റിപ്പോർട്ട് ചെയ്തിരിക്കുന്ന ബേസ്‌ലൈൻ സ്‌കോറുകൾ 80.8-ഉം 88.5-ഉം ആണ്, അതിനാൽ നമ്മൾ എത്തേണ്ടിടത്ത് തന്നെയാണ് നമ്മൾ. + +{#if fw === 'pt'} + +അവസാനമായി, മോഡലിന്റെ ഏറ്റവും പുതിയ പതിപ്പ് അപ്‌ലോഡ് ചെയ്യുന്നു എന്ന് ഉറപ്പാക്കാൻ `push_to_hub()` മെത്തേഡ് നമ്മൾ ഉപയോഗിക്കുന്നു: + +```py +trainer.push_to_hub(commit_message="Training complete") +``` + +ഇത് ഇപ്പോൾ ചെയ്ത കമ്മിറ്റിന്റെ URL റിട്ടേൺ ചെയ്യുന്നു, നിങ്ങൾക്ക് അത് പരിശോധിക്കണമെങ്കിൽ: + +```python out +'https://huggingface.co/sgugger/bert-finetuned-squad/commit/9dcee1fbc25946a6ed4bb32efb1bd71d5fa90b68' +``` + +എല്ലാ ഇവാല്യുവേഷൻ ഫലങ്ങളോടും കൂടിയ ഒരു മോഡൽ കാർഡ് കൂടി `Trainer` തയ്യാറാക്കി അപ്‌ലോഡ് ചെയ്യുന്നു. + +{/if} + +ഈ ഘട്ടത്തിൽ, Model Hub-ലെ ഇൻഫറൻസ് വിഡ്‌ജെറ്റ് ഉപയോഗിച്ച് മോഡൽ പരീക്ഷിക്കാനും നിങ്ങളുടെ സുഹൃത്തുക്കൾ, കുടുംബം, പ്രിയപ്പെട്ട വളർത്തുമൃഗങ്ങൾ എന്നിവരുമായി പങ്കുവയ്ക്കാനും നിങ്ങൾക്ക് കഴിയും. ഒരു ചോദ്യോത്തര ടാസ്‌ക്കിൽ ഒരു മോഡൽ നിങ്ങൾ വിജയകരമായി ഫൈൻ-ട്യൂൻ ചെയ്തിരിക്കുന്നു -- അഭിനന്ദനങ്ങൾ! + +> [!TIP] +> ✏️ **നിങ്ങളുടെ ഊഴം!** ഈ ടാസ്‌ക്കിൽ മെച്ചപ്പെട്ട പ്രകടനം നടത്തുന്നുണ്ടോ എന്ന് കാണാൻ മറ്റൊരു മോഡൽ ആർക്കിടെക്ചർ പരീക്ഷിക്കുക! + +{#if fw === 'pt'} + +ട്രെയിനിംഗ് ലൂപ്പിലേക്ക് അൽപ്പം കൂടി ആഴത്തിൽ കടക്കാൻ നിങ്ങൾ ആഗ്രഹിക്കുന്നെങ്കിൽ, 🤗 Accelerate ഉപയോഗിച്ച് ഇതേ കാര്യം എങ്ങനെ ചെയ്യാമെന്ന് ഇപ്പോൾ ഞങ്ങൾ കാണിച്ചുതരാം. + +## ഒരു ഇഷ്ടാനുസൃത ട്രെയിനിംഗ് ലൂപ്പ്[[a-custom-training-loop]] + +ഇനി മുഴുവൻ ട്രെയിനിംഗ് ലൂപ്പും ഒന്ന് നോക്കാം, അങ്ങനെ നിങ്ങൾക്ക് ആവശ്യമുള്ള ഭാഗങ്ങൾ എളുപ്പത്തിൽ ഇഷ്ടാനുസൃതമാക്കാം. ഇവാല്യുവേഷൻ ലൂപ്പ് ഒഴികെ, [അധ്യായം 3](/course/chapter3/4)-ലെ ട്രെയിനിംഗ് ലൂപ്പിനോട് ഇത് ഏറെ സാമ്യമുള്ളതായിരിക്കും. `Trainer` ക്ലാസിന്റെ പരിമിതികൾ ഇനി നമുക്കില്ലാത്തതിനാൽ, മോഡൽ പതിവായി ഇവാല്യുവേറ്റ് ചെയ്യാൻ നമുക്ക് കഴിയും. + +### ട്രെയിനിംഗിനായി എല്ലാം തയ്യാറാക്കുന്നു[[preparing-everything-for-training]] + +ആദ്യം നമ്മുടെ ഡേറ്റാസെറ്റുകളിൽ നിന്ന് `DataLoader`-കൾ നിർമ്മിക്കണം. ആ ഡേറ്റാസെറ്റുകളുടെ ഫോർമാറ്റ് `"torch"` എന്ന് സെറ്റ് ചെയ്യുകയും, വാലിഡേഷൻ സെറ്റിലെ, മോഡൽ ഉപയോഗിക്കാത്ത കോളങ്ങൾ നീക്കം ചെയ്യുകയും ചെയ്യുന്നു. തുടർന്ന്, Transformers നൽകുന്ന `default_data_collator` ഒരു `collate_fn` ആയി ഉപയോഗിക്കാം, കൂടാതെ ട്രെയിനിംഗ് സെറ്റ് ഷഫിൾ ചെയ്യാം, എന്നാൽ വാലിഡേഷൻ സെറ്റ് ഷഫിൾ ചെയ്യരുത്: + +```py +from torch.utils.data import DataLoader +from transformers import default_data_collator + +train_dataset.set_format("torch") +validation_set = validation_dataset.remove_columns(["example_id", "offset_mapping"]) +validation_set.set_format("torch") + +train_dataloader = DataLoader( + train_dataset, + shuffle=True, + collate_fn=default_data_collator, + batch_size=8, +) +eval_dataloader = DataLoader( + validation_set, collate_fn=default_data_collator, batch_size=8 +) +``` + +അടുത്തതായി നമ്മുടെ മോഡൽ വീണ്ടും ഇൻസ്‌റ്റാൻഷിയേറ്റ് ചെയ്യുന്നു; മുമ്പത്തെ ഫൈൻ-ട്യൂണിംഗ് തുടരുകയല്ല, മറിച്ച് BERT പ്രീട്രെയിൻഡ് മോഡലിൽ നിന്ന് വീണ്ടും ആരംഭിക്കുകയാണ് എന്ന് ഉറപ്പാക്കാനാണിത്: + +```py +model = AutoModelForQuestionAnswering.from_pretrained(model_checkpoint) +``` + +പിന്നീട് നമുക്ക് ഒരു ഒപ്‌റ്റിമൈസർ ആവശ്യമാണ്. പതിവുപോലെ ക്ലാസിക് `AdamW` നമ്മൾ ഉപയോഗിക്കുന്നു; ഇത് Adam പോലെയാണ്, എന്നാൽ വെയ്‌റ്റ് ഡികേ പ്രയോഗിക്കുന്ന രീതിയിൽ ഒരു തിരുത്തലോടെ: + +```py +from torch.optim import AdamW + +optimizer = AdamW(model.parameters(), lr=2e-5) +``` + +ആ ഒബ്‌ജക്റ്റുകളെല്ലാം ലഭിച്ചുകഴിഞ്ഞാൽ, അവ `accelerator.prepare()` മെത്തേഡിന് നൽകാം. ഒരു Colab നോട്ട്‌ബുക്കിൽ TPU-കളിൽ ട്രെയിൻ ചെയ്യാൻ ആഗ്രഹിക്കുന്നെങ്കിൽ, ഈ കോഡ് മുഴുവനും ഒരു ട്രെയിനിംഗ് ഫംഗ്‌ഷനിലേക്ക് മാറ്റേണ്ടിവരും എന്നും, ഒരു `Accelerator` ഇൻസ്‌റ്റാൻഷിയേറ്റ് ചെയ്യുന്ന ഒരു സെല്ലും അത് എക്‌സിക്യൂട്ട് ചെയ്യരുത് എന്നും ഓർമ്മിക്കുക. `Accelerator`-ന് `fp16=True` നൽകിക്കൊണ്ട് മിക്‌സഡ്-പ്രിസിഷൻ ട്രെയിനിംഗ് നമുക്ക് നിർബന്ധിതമാക്കാം (അല്ലെങ്കിൽ, കോഡ് ഒരു സ്‌ക്രിപ്‌റ്റായി എക്‌സിക്യൂട്ട് ചെയ്യുകയാണെങ്കിൽ, 🤗 Accelerate `config` ഉചിതമായി പൂരിപ്പിക്കാൻ മറക്കരുത്). + +```py +from accelerate import Accelerator + +accelerator = Accelerator(fp16=True) +model, optimizer, train_dataloader, eval_dataloader = accelerator.prepare( + model, optimizer, train_dataloader, eval_dataloader +) +``` + +മുൻ ഭാഗങ്ങളിൽ നിന്ന് നിങ്ങൾക്ക് അറിയാവുന്നതുപോലെ, `train_dataloader` എന്നത് `accelerator.prepare()` മെത്തേഡിലൂടെ കടന്നുപോയതിന് ശേഷം മാത്രമേ ട്രെയിനിംഗ് സ്‌റ്റെപ്പുകളുടെ എണ്ണം കണക്കാക്കാൻ അതിന്റെ ദൈർഘ്യം നമുക്ക് ഉപയോഗിക്കാൻ കഴിയൂ. മുൻ ഭാഗങ്ങളിലെ അതേ ലീനിയർ ഷെഡ്യൂൾ നമ്മൾ ഉപയോഗിക്കുന്നു: + +```py +from transformers import get_scheduler + +num_train_epochs = 3 +num_update_steps_per_epoch = len(train_dataloader) +num_training_steps = num_train_epochs * num_update_steps_per_epoch + +lr_scheduler = get_scheduler( + "linear", + optimizer=optimizer, + num_warmup_steps=0, + num_training_steps=num_training_steps, +) +``` + +നമ്മുടെ മോഡൽ Hub-ലേക്ക് പുഷ് ചെയ്യാൻ, ഒരു വർക്കിംഗ് ഫോൾഡറിൽ ഒരു `Repository` ഒബ്‌ജക്റ്റ് ഉണ്ടാക്കേണ്ടിവരും. ഇതിനകം ലോഗിൻ ചെയ്തിട്ടില്ലെങ്കിൽ, ആദ്യം Hugging Face Hub-ൽ ലോഗിൻ ചെയ്യുക. നമ്മുടെ മോഡലിന് നൽകാൻ ആഗ്രഹിക്കുന്ന മോഡൽ ID-യിൽ നിന്ന് റിപ്പോസിറ്ററിയുടെ പേര് നമ്മൾ നിർണ്ണയിക്കും (`repo_name` നിങ്ങളുടെ ഇഷ്ടപ്രകാരം മാറ്റാൻ മടിക്കേണ്ട; അതിൽ നിങ്ങളുടെ യൂസർനെയിം അടങ്ങിയിരിക്കണം എന്ന് മാത്രം, അതാണ് `get_full_repo_name()` ഫംഗ്‌ഷൻ ചെയ്യുന്നത്): + +```py +from huggingface_hub import Repository, get_full_repo_name + +model_name = "bert-finetuned-squad-accelerate" +repo_name = get_full_repo_name(model_name) +repo_name +``` + +```python out +'sgugger/bert-finetuned-squad-accelerate' +``` + +തുടർന്ന് ആ റിപ്പോസിറ്ററി ഒരു ലോക്കൽ ഫോൾഡറിൽ ക്ലോൺ ചെയ്യാം. അത് ഇതിനകം നിലവിലുണ്ടെങ്കിൽ, ഈ ലോക്കൽ ഫോൾഡർ നമ്മൾ പ്രവർത്തിക്കുന്ന റിപ്പോസിറ്ററിയുടെ ഒരു ക്ലോൺ ആയിരിക്കണം: + +```py +output_dir = "bert-finetuned-squad-accelerate" +repo = Repository(output_dir, clone_from=repo_name) +``` + +`repo.push_to_hub()` മെത്തേഡ് വിളിച്ചുകൊണ്ട് `output_dir`-ൽ നമ്മൾ സേവ് ചെയ്യുന്ന എന്തും ഇപ്പോൾ അപ്‌ലോഡ് ചെയ്യാം. ഓരോ എപ്പോക്കിന്റെയും അവസാനം ഇടക്കാല മോഡലുകൾ അപ്‌ലോഡ് ചെയ്യാൻ ഇത് നമ്മെ സഹായിക്കും. + +## ട്രെയിനിംഗ് ലൂപ്പ്[[training-loop]] + +ഇപ്പോൾ മുഴുവൻ ട്രെയിനിംഗ് ലൂപ്പും എഴുതാൻ നമ്മൾ തയ്യാറാണ്. ട്രെയിനിംഗ് എങ്ങനെ പുരോഗമിക്കുന്നു എന്ന് പിന്തുടരാൻ ഒരു പ്രോഗ്രസ് ബാർ നിർവചിച്ച ശേഷം, ലൂപ്പിന് മൂന്ന് ഭാഗങ്ങളുണ്ട്: + +- ട്രെയിനിംഗ് തന്നെ; `train_dataloader`-ലൂടെയുള്ള ക്ലാസിക് ഇറ്ററേഷൻ, മോഡലിലൂടെയുള്ള ഫോർവേഡ് പാസ്, പിന്നെ ബാക്ക്‌വേഡ് പാസും ഒപ്‌റ്റിമൈസർ സ്‌റ്റെപ്പും ആണിത്. +- ഇവാല്യുവേഷൻ; ഇതിൽ `start_logits`-ന്റെയും `end_logits`-ന്റെയും എല്ലാ മൂല്യങ്ങളും NumPy അറേകളാക്കി മാറ്റുന്നതിന് മുമ്പ് നമ്മൾ ശേഖരിക്കുന്നു (gather). ഇവാല്യുവേഷൻ ലൂപ്പ് പൂർത്തിയായിക്കഴിഞ്ഞാൽ, എല്ലാ ഫലങ്ങളും നമ്മൾ കൂട്ടിച്ചേർക്കുന്നു (concatenate). ഓരോ പ്രോസസ്സിലും ഒരേ എണ്ണം ഉദാഹരണങ്ങൾ ഉണ്ടെന്ന് ഉറപ്പാക്കാൻ `Accelerator` അവസാനം ഏതാനും സാമ്പിളുകൾ കൂട്ടിച്ചേർത്തിരിക്കാം എന്നതിനാൽ നമ്മൾ ട്രങ്കേറ്റ് ചെയ്യേണ്ടതുണ്ട് എന്നത് ശ്രദ്ധിക്കുക. +- സേവ് ചെയ്യലും അപ്‌ലോഡ് ചെയ്യലും; ഇവിടെ ആദ്യം മോഡലും ടോക്കണൈസറും സേവ് ചെയ്യുന്നു, പിന്നീട് `repo.push_to_hub()` വിളിക്കുന്നു. മുമ്പ് ചെയ്തതുപോലെ, ഒരു അസിൻക്രണസ് പ്രോസസ്സിൽ പുഷ് ചെയ്യാൻ 🤗 Hub ലൈബ്രറിയോട് പറയാൻ `blocking=False` എന്ന ആർഗ്യുമെന്റ് നമ്മൾ ഉപയോഗിക്കുന്നു. ഇങ്ങനെ, ട്രെയിനിംഗ് സാധാരണപോലെ തുടരുകയും ഈ (ദൈർഘ്യമേറിയ) നിർദ്ദേശം പശ്ചാത്തലത്തിൽ എക്‌സിക്യൂട്ട് ചെയ്യപ്പെടുകയും ചെയ്യുന്നു. + +ട്രെയിനിംഗ് ലൂപ്പിന്റെ പൂർണ്ണമായ കോഡ് ഇതാ: + +```py +from tqdm.auto import tqdm +import torch + +progress_bar = tqdm(range(num_training_steps)) + +for epoch in range(num_train_epochs): + # Training + model.train() + for step, batch in enumerate(train_dataloader): + outputs = model(**batch) + loss = outputs.loss + accelerator.backward(loss) + + optimizer.step() + lr_scheduler.step() + optimizer.zero_grad() + progress_bar.update(1) + + # Evaluation + model.eval() + start_logits = [] + end_logits = [] + accelerator.print("Evaluation!") + for batch in tqdm(eval_dataloader): + with torch.no_grad(): + outputs = model(**batch) + + start_logits.append(accelerator.gather(outputs.start_logits).cpu().numpy()) + end_logits.append(accelerator.gather(outputs.end_logits).cpu().numpy()) + + start_logits = np.concatenate(start_logits) + end_logits = np.concatenate(end_logits) + start_logits = start_logits[: len(validation_dataset)] + end_logits = end_logits[: len(validation_dataset)] + + metrics = compute_metrics( + start_logits, end_logits, validation_dataset, raw_datasets["validation"] + ) + print(f"epoch {epoch}:", metrics) + + # Save and upload + accelerator.wait_for_everyone() + unwrapped_model = accelerator.unwrap_model(model) + unwrapped_model.save_pretrained(output_dir, save_function=accelerator.save) + if accelerator.is_main_process: + tokenizer.save_pretrained(output_dir) + repo.push_to_hub( + commit_message=f"Training in progress epoch {epoch}", blocking=False + ) +``` + +🤗 Accelerate ഉപയോഗിച്ച് ഒരു മോഡൽ സേവ് ചെയ്യുന്നത് നിങ്ങൾ ആദ്യമായി കാണുന്നതാണെങ്കിൽ, അതിനോടൊപ്പമുള്ള മൂന്ന് വരി കോഡ് പരിശോധിക്കാൻ ഒരു നിമിഷം എടുക്കാം: + +```py +accelerator.wait_for_everyone() +unwrapped_model = accelerator.unwrap_model(model) +unwrapped_model.save_pretrained(output_dir, save_function=accelerator.save) +``` + +ആദ്യത്തെ വരി സ്വയം വ്യക്തമാണ്: തുടരുന്നതിന് മുമ്പ് എല്ലാവരും ആ ഘട്ടത്തിൽ എത്തുന്നതുവരെ കാത്തിരിക്കാൻ ഇത് എല്ലാ പ്രോസസ്സുകളോടും പറയുന്നു. സേവ് ചെയ്യുന്നതിന് മുമ്പ് എല്ലാ പ്രോസസ്സിലും ഒരേ മോഡൽ ഉണ്ടെന്ന് ഉറപ്പാക്കാനാണിത്. തുടർന്ന് നമ്മൾ നിർവചിച്ച അടിസ്ഥാന മോഡലായ `unwrapped_model` എടുക്കുന്നു. `accelerator.prepare()` മെത്തേഡ് ഡിസ്‌ട്രിബ്യൂട്ടഡ് ട്രെയിനിംഗിൽ പ്രവർത്തിക്കാനായി മോഡലിനെ മാറ്റുന്നു, അതിനാൽ അതിന് ഇനി `save_pretrained()` മെത്തേഡ് ഉണ്ടാകില്ല; `accelerator.unwrap_model()` മെത്തേഡ് ആ ഘട്ടം പഴയപടിയാക്കുന്നു. അവസാനമായി, നമ്മൾ `save_pretrained()` വിളിക്കുന്നു, എന്നാൽ `torch.save()`-ന് പകരം `accelerator.save()` ഉപയോഗിക്കാൻ ആ മെത്തേഡിനോട് പറയുന്നു. + +ഇത് ചെയ്തുകഴിഞ്ഞാൽ, `Trainer` ഉപയോഗിച്ച് ട്രെയിൻ ചെയ്തതിനോട് ഏറെ സാമ്യമുള്ള ഫലങ്ങൾ നൽകുന്ന ഒരു മോഡൽ നിങ്ങൾക്ക് ഉണ്ടായിരിക്കണം. ഈ കോഡ് ഉപയോഗിച്ച് ഞങ്ങൾ ട്രെയിൻ ചെയ്ത മോഡൽ [*huggingface-course/bert-finetuned-squad-accelerate*](https://huggingface.co/huggingface-course/bert-finetuned-squad-accelerate)-ൽ നിങ്ങൾക്ക് പരിശോധിക്കാം. ട്രെയിനിംഗ് ലൂപ്പിൽ എന്തെങ്കിലും മാറ്റങ്ങൾ പരീക്ഷിക്കാൻ നിങ്ങൾ ആഗ്രഹിക്കുന്നെങ്കിൽ, മുകളിൽ കാണിച്ച കോഡ് എഡിറ്റ് ചെയ്തുകൊണ്ട് അവ നേരിട്ട് ഇംപ്ലിമെന്റ് ചെയ്യാം! + +{/if} + +## ഫൈൻ-ട്യൂൻ ചെയ്ത മോഡൽ ഉപയോഗിക്കുന്നു[[using-the-fine-tuned-model]] + +നമ്മൾ ഫൈൻ-ട്യൂൻ ചെയ്ത മോഡൽ Model Hub-ൽ ഇൻഫറൻസ് വിഡ്‌ജെറ്റ് ഉപയോഗിച്ച് എങ്ങനെ ഉപയോഗിക്കാമെന്ന് ഞങ്ങൾ ഇതിനകം കാണിച്ചുതന്നിട്ടുണ്ട്. ഒരു `pipeline`-ൽ ഇത് ലോക്കലായി ഉപയോഗിക്കാൻ, മോഡൽ ഐഡന്റിഫയർ വ്യക്തമാക്കിയാൽ മാത്രം മതി: + +```py +from transformers import pipeline + +# Replace this with your own checkpoint +model_checkpoint = "huggingface-course/bert-finetuned-squad" +question_answerer = pipeline("question-answering", model=model_checkpoint) + +context = """ +🤗 Transformers is backed by the three most popular deep learning libraries — Jax, PyTorch and TensorFlow — with a seamless integration +between them. It's straightforward to train your models with one before loading them for inference with the other. +""" +question = "Which deep learning libraries back 🤗 Transformers?" +question_answerer(question=question, context=context) +``` + +```python out +{'score': 0.9979003071784973, + 'start': 78, + 'end': 105, + 'answer': 'Jax, PyTorch and TensorFlow'} +``` + +വളരെ നന്നായി! ഈ പൈപ്പ്‌ലൈനിന്റെ ഡിഫോൾട്ട് മോഡൽ പോലെ തന്നെ നന്നായി നമ്മുടെ മോഡൽ പ്രവർത്തിക്കുന്നു! diff --git a/chapters/ml/chapter7/8.mdx b/chapters/ml/chapter7/8.mdx new file mode 100644 index 000000000..5fea24a3d --- /dev/null +++ b/chapters/ml/chapter7/8.mdx @@ -0,0 +1,34 @@ +# LLM-കളിൽ പ്രാവീണ്യം നേടുന്നു[[mastering-llms]] + + + +കോഴ്‌സിൽ ഇത്രയും ദൂരം എത്തിയെങ്കിൽ, അഭിനന്ദനങ്ങൾ — 🤗 Transformers-ഉം Hugging Face ഇക്കോസിസ്‌റ്റവും ഉപയോഗിച്ച് (ഏറെക്കുറെ) ഏത് ഭാഷാ ടാസ്‌ക്കും കൈകാര്യം ചെയ്യാൻ ആവശ്യമായ എല്ലാ അറിവും ടൂളുകളും ഇപ്പോൾ നിങ്ങളുടെ പക്കലുണ്ട്! + +## NLP-യിൽ നിന്ന് LLM-കളിലേക്ക് + +ഈ കോഴ്‌സിൽ നമ്മൾ പരമ്പരാഗതമായ പല NLP ടാസ്‌ക്കുകളും പഠിച്ചെങ്കിലും, ലാർജ് ലാംഗ്വേജ് മോഡലുകൾ (LLM-കൾ) ഈ മേഖലയിൽ ഒരു വിപ്ലവം സൃഷ്ടിച്ചിരിക്കുന്നു. ഭാഷാ പ്രോസസ്സിംഗിൽ സാധ്യമായ കാര്യങ്ങളുടെ പരിധി ഈ മോഡലുകൾ വളരെയധികം വികസിപ്പിച്ചിരിക്കുന്നു: + +- ടാസ്‌ക്-നിർദ്ദിഷ്ട ഫൈൻ-ട്യൂണിംഗ് ഇല്ലാതെ തന്നെ ഒന്നിലധികം ടാസ്‌ക്കുകൾ കൈകാര്യം ചെയ്യാൻ അവയ്ക്ക് കഴിയും +- നിർദ്ദേശങ്ങൾ പിന്തുടരുന്നതിലും വ്യത്യസ്ത സന്ദർഭങ്ങളുമായി പൊരുത്തപ്പെടുന്നതിലും അവ മികവ് പുലർത്തുന്നു +- വിവിധ ആപ്ലിക്കേഷനുകൾക്കായി യുക്തിഭദ്രവും സന്ദർഭോചിതവുമായ ടെക്‌സ്‌റ്റ് ജനറേറ്റ് ചെയ്യാൻ അവയ്ക്ക് കഴിയും +- ചെയിൻ-ഓഫ്-തോട്ട് പ്രോംപ്‌റ്റിംഗ് (chain-of-thought prompting) പോലുള്ള ടെക്‌നിക്കുകളിലൂടെ യുക്തിചിന്ത (reasoning) നടത്താനും സങ്കീർണ്ണമായ പ്രശ്നങ്ങൾ പരിഹരിക്കാനും അവയ്ക്ക് കഴിയും + +നിങ്ങൾ പഠിച്ച അടിസ്ഥാന NLP വൈദഗ്ധ്യങ്ങൾ LLM-കളുമായി ഫലപ്രദമായി പ്രവർത്തിക്കാൻ ഇപ്പോഴും അത്യാവശ്യമാണ്. ടോക്കണൈസേഷൻ, മോഡൽ ആർക്കിടെക്ചറുകൾ, ഫൈൻ-ട്യൂണിംഗ് സമീപനങ്ങൾ, ഇവാല്യുവേഷൻ മെട്രിക്കുകൾ എന്നിവ മനസ്സിലാക്കുന്നത്, LLM-കളുടെ പൂർണ്ണ ശേഷി പ്രയോജനപ്പെടുത്താൻ ആവശ്യമായ അറിവ് നൽകുന്നു. + +നമ്മൾ വളരെയധികം വ്യത്യസ്ത ഡേറ്റാ കൊളേറ്ററുകൾ (data collators) കണ്ടു; അതിനാൽ ഓരോ ടാസ്‌ക്കിനും ഏതാണ് ഉപയോഗിക്കേണ്ടത് എന്ന് കണ്ടെത്താൻ നിങ്ങളെ സഹായിക്കുന്നതിനായി ഞങ്ങൾ ഈ ചെറിയ വീഡിയോ തയ്യാറാക്കിയിട്ടുണ്ട്: + + + +പ്രധാന ഭാഷാ ടാസ്‌ക്കുകളിലൂടെയുള്ള ഈ മിന്നൽ പര്യടനം പൂർത്തിയാക്കിയ ശേഷം, നിങ്ങൾക്ക് താഴെ പറയുന്നവ സാധിക്കേണ്ടതാണ്: + +* ഓരോ ടാസ്‌ക്കിനും ഏറ്റവും അനുയോജ്യമായ ആർക്കിടെക്ചറുകൾ (എൻകോഡർ, ഡീകോഡർ, അല്ലെങ്കിൽ എൻകോഡർ-ഡീകോഡർ) ഏതൊക്കെയാണെന്ന് അറിയുക +* ഒരു ലാംഗ്വേജ് മോഡലിന്റെ പ്രീട്രെയിനിംഗും ഫൈൻ-ട്യൂണിംഗും തമ്മിലുള്ള വ്യത്യാസം മനസ്സിലാക്കുക +* നിങ്ങൾ പിന്തുടരുന്ന ട്രാക്ക് അനുസരിച്ച്, `Trainer` API-യും 🤗 Accelerate-ന്റെ ഡിസ്‌ട്രിബ്യൂട്ടഡ് ട്രെയിനിംഗ് സവിശേഷതകളും ഉപയോഗിച്ചോ അല്ലെങ്കിൽ TensorFlow-ഉം Keras-ഉം ഉപയോഗിച്ചോ Transformer മോഡലുകൾ എങ്ങനെ ട്രെയിൻ ചെയ്യാമെന്ന് അറിയുക +* ടെക്‌സ്‌റ്റ് ജനറേഷൻ ടാസ്‌ക്കുകൾക്കുള്ള ROUGE, BLEU പോലുള്ള മെട്രിക്കുകളുടെ അർത്ഥവും പരിമിതികളും മനസ്സിലാക്കുക +* Hub-ലും 🤗 Transformers-ലെ `pipeline` ഉപയോഗിച്ചും, നിങ്ങൾ ഫൈൻ-ട്യൂൻ ചെയ്ത മോഡലുകളുമായി എങ്ങനെ സംവദിക്കാമെന്ന് അറിയുക +* പരമ്പരാഗത NLP ടെക്‌നിക്കുകളെ അടിസ്ഥാനമാക്കി LLM-കൾ എങ്ങനെ വളരുകയും അവയെ വികസിപ്പിക്കുകയും ചെയ്യുന്നു എന്ന് തിരിച്ചറിയുക + +ഈ അറിവെല്ലാം ഉണ്ടായിട്ടും, നിങ്ങളുടെ കോഡിൽ ബുദ്ധിമുട്ടുള്ള ഒരു ബഗ് നേരിടുകയോ, ഒരു പ്രത്യേക ഭാഷാ പ്രോസസ്സിംഗ് പ്രശ്നം എങ്ങനെ പരിഹരിക്കണം എന്നതിനെക്കുറിച്ച് ഒരു സംശയം ഉണ്ടാകുകയോ ചെയ്യുന്ന ഒരു സമയം വരും. ഭാഗ്യവശാൽ, നിങ്ങളെ സഹായിക്കാൻ Hugging Face കമ്മ്യൂണിറ്റി ഇവിടെയുണ്ട്! കോഴ്‌സിന്റെ ഈ ഭാഗത്തിന്റെ അവസാന അധ്യായത്തിൽ, നിങ്ങളുടെ Transformer മോഡലുകൾ എങ്ങനെ ഡീബഗ് ചെയ്യാമെന്നും ഫലപ്രദമായി എങ്ങനെ സഹായം ചോദിക്കാമെന്നും നമ്മൾ പരിശോധിക്കും. diff --git a/chapters/ml/chapter7/9.mdx b/chapters/ml/chapter7/9.mdx new file mode 100644 index 000000000..a78028d2a --- /dev/null +++ b/chapters/ml/chapter7/9.mdx @@ -0,0 +1,329 @@ + + + + +# അധ്യായത്തിന്റെ അവസാന ക്വിസ്[[end-of-chapter-quiz]] + + + +ഈ അധ്യായത്തിൽ നിങ്ങൾ പഠിച്ചത് നമുക്ക് പരീക്ഷിക്കാം! + +### 1. താഴെ പറയുന്ന ടാസ്‌ക്കുകളിൽ ഏതൊക്കെ ഒരു ടോക്കൺ ക്ലാസിഫിക്കേഷൻ പ്രശ്നമായി രൂപപ്പെടുത്താം? + + + +### 2. ടോക്കൺ ക്ലാസിഫിക്കേഷനുള്ള പ്രീപ്രോസസ്സിംഗിന്റെ ഏത് ഭാഗമാണ് മറ്റ് പ്രീപ്രോസസ്സിംഗ് പൈപ്പ്‌ലൈനുകളിൽ നിന്ന് വ്യത്യസ്തമായിരിക്കുന്നത്? + +-100 ഉപയോഗിക്കുന്നു.", + explain: "അത് ടോക്കൺ ക്ലാസിഫിക്കേഷന് മാത്രമുള്ള ഒരു കാര്യമല്ല — ലോസിൽ അവഗണിക്കേണ്ട ടോക്കണുകൾക്കുള്ള ലേബലായി നമ്മൾ എപ്പോഴും -100 ഉപയോഗിക്കുന്നു." + }, + { + text: "ട്രങ്കേഷൻ/പാഡിംഗ് പ്രയോഗിക്കുമ്പോൾ, ലേബലുകളെയും ഇൻപുട്ടുകളുടെ അതേ വലിപ്പത്തിലേക്ക് വെട്ടിച്ചുരുക്കുകയോ പാഡ് ചെയ്യുകയോ ചെയ്യുന്നുണ്ടെന്ന് നമ്മൾ ഉറപ്പാക്കണം.", + explain: "തീർച്ചയായും! എന്നാൽ, അത് മാത്രമല്ല വ്യത്യാസം.", + correct: true + } + ]} +/> + +### 3. ഒരു ടോക്കൺ ക്ലാസിഫിക്കേഷൻ പ്രശ്നത്തിൽ വാക്കുകൾ ടോക്കണൈസ് ചെയ്ത് ടോക്കണുകളെ ലേബൽ ചെയ്യാൻ ആഗ്രഹിക്കുമ്പോൾ എന്ത് പ്രശ്നമാണ് ഉണ്ടാകുന്നത്? + +-100 എന്ന് ലേബൽ ചെയ്യുന്നു." + }, + { + text: "ഓരോ വാക്കും ഒന്നിലധികം ടോക്കണുകൾ ഉണ്ടാക്കിയേക്കാം, അതിനാൽ നമുക്കുള്ള ലേബലുകളെക്കാൾ കൂടുതൽ ടോക്കണുകൾ ഉണ്ടാകുന്നു.", + explain: "അതാണ് പ്രധാന പ്രശ്നം; യഥാർത്ഥ ലേബലുകളെ ടോക്കണുകളുമായി നമ്മൾ അലൈൻ ചെയ്യേണ്ടതുണ്ട്.", + correct: true + }, + { + text: "ചേർത്ത ടോക്കണുകൾക്ക് ലേബലുകളില്ല, അതിനാൽ ഒരു പ്രശ്നവുമില്ല.", + explain: "അത് തെറ്റാണ്; നമുക്ക് ടോക്കണുകളുടെ എണ്ണത്തിന് തുല്യമായ ലേബലുകൾ ആവശ്യമാണ്, അല്ലാത്തപക്ഷം നമ്മുടെ മോഡലുകൾ എറർ കാണിക്കും." + } + ]} +/> + +### 4. "ഡൊമെയ്‌ൻ അഡാപ്‌റ്റേഷൻ" (domain adaptation) എന്നാൽ എന്താണ്? + + + +### 5. ഒരു മാസ്‌ക്ഡ് ലാംഗ്വേജ് മോഡലിംഗ് പ്രശ്നത്തിൽ ലേബലുകൾ എന്തൊക്കെയാണ്? + + + +### 6. ഇവയിൽ ഏതൊക്കെ ടാസ്‌ക്കുകളെ ഒരു സീക്വൻസ്-ടു-സീക്വൻസ് പ്രശ്നമായി കാണാം? + + + +### 7. ഒരു സീക്വൻസ്-ടു-സീക്വൻസ് പ്രശ്നത്തിനായി ഡേറ്റ പ്രീപ്രോസസ്സ് ചെയ്യാനുള്ള ശരിയായ മാർഗ്ഗം എന്താണ്? + +inputs=..., targets=... എന്നിവ ഉപയോഗിച്ച് ഒരുമിച്ച് ടോക്കണൈസറിലേക്ക് അയയ്ക്കണം.", + explain: "ഭാവിയിൽ ഞങ്ങൾ ചേർക്കാനിടയുള്ള ഒരു API ആയിരിക്കാം ഇത്, എന്നാൽ ഇപ്പോൾ അത് സാധ്യമല്ല." + }, + { + text: "ഇൻപുട്ടുകളും ടാർഗെറ്റുകളും രണ്ടും, ടോക്കണൈസറിലേക്കുള്ള രണ്ട് വെവ്വേറെ കോളുകളിലായി പ്രീപ്രോസസ്സ് ചെയ്യണം.", + explain: "അത് ശരിയാണ്, പക്ഷേ അപൂർണ്ണമാണ്. ടോക്കണൈസർ രണ്ടും ശരിയായി പ്രോസസ്സ് ചെയ്യുന്നുണ്ടെന്ന് ഉറപ്പാക്കാൻ നിങ്ങൾ ചെയ്യേണ്ട ഒരു കാര്യമുണ്ട്." + }, + { + text: "പതിവുപോലെ, ഇൻപുട്ടുകൾ ടോക്കണൈസ് ചെയ്താൽ മാത്രം മതി.", + explain: "ഒരു സീക്വൻസ് ക്ലാസിഫിക്കേഷൻ പ്രശ്നത്തിൽ അങ്ങനെയല്ല; ടാർഗെറ്റുകളും നമ്മൾ സംഖ്യകളാക്കി മാറ്റേണ്ട ടെക്‌സ്‌റ്റുകളാണ്!" + }, + { + text: "ഇൻപുട്ടുകൾ ടോക്കണൈസറിലേക്ക് അയയ്ക്കണം, ടാർഗെറ്റുകളും അയയ്ക്കണം, എന്നാൽ ഒരു പ്രത്യേക കോൺടെക്‌സ്‌റ്റ് മാനേജറിനുള്ളിൽ (context manager) വച്ചാണ്.", + explain: "അത് ശരിയാണ്; ആ കോൺടെക്‌സ്‌റ്റ് മാനേജർ ഉപയോഗിച്ച് ടോക്കണൈസറിനെ ടാർഗെറ്റ് മോഡിലാക്കേണ്ടതുണ്ട്.", + correct: true + } + ]} +/> + +{#if fw === 'pt'} + +### 8. സീക്വൻസ്-ടു-സീക്വൻസ് പ്രശ്നങ്ങൾക്കായി `Trainer`-ന്റെ ഒരു പ്രത്യേക സബ്‌ക്ലാസ് ഉള്ളത് എന്തുകൊണ്ടാണ്? + +-100 ആയി സെറ്റ് ചെയ്ത ലേബലുകൾ അവഗണിക്കാൻ ഒരു കസ്‌റ്റം ലോസ് ഉപയോഗിക്കുന്നതിനാൽ", + explain: "അത് ഒരു കസ്‌റ്റം ലോസ് അല്ലേയല്ല; ലോസ് എപ്പോഴും കണക്കാക്കുന്ന രീതി തന്നെയാണ് അത്." + }, + { + text: "സീക്വൻസ്-ടു-സീക്വൻസ് പ്രശ്നങ്ങൾക്ക് ഒരു പ്രത്യേക ഇവാല്യുവേഷൻ ലൂപ്പ് ആവശ്യമായതിനാൽ", + explain: "അത് ശരിയാണ്. സീക്വൻസ്-ടു-സീക്വൻസ് മോഡലുകളുടെ പ്രവചനങ്ങൾ പലപ്പോഴും generate() മെത്തേഡ് ഉപയോഗിച്ചാണ് റൺ ചെയ്യുന്നത്.", + correct: true + }, + { + text: "സീക്വൻസ്-ടു-സീക്വൻസ് പ്രശ്നങ്ങളിൽ ടാർഗെറ്റുകൾ ടെക്‌സ്‌റ്റുകളായതിനാൽ", + explain: "അവ മുമ്പേ പ്രീപ്രോസസ്സ് ചെയ്തിട്ടുള്ളതിനാൽ Trainer-ന് അത് യഥാർത്ഥത്തിൽ ഒരു വിഷയമേയല്ല." + }, + { + text: "സീക്വൻസ്-ടു-സീക്വൻസ് പ്രശ്നങ്ങളിൽ നമ്മൾ രണ്ട് മോഡലുകൾ ഉപയോഗിക്കുന്നതിനാൽ", + explain: "ഒരു തരത്തിൽ നമ്മൾ രണ്ട് മോഡലുകൾ ഉപയോഗിക്കുന്നുണ്ട് — ഒരു എൻകോഡറും ഒരു ഡീകോഡറും — എന്നാൽ അവ ഒരൊറ്റ മോഡലായി ഒരുമിച്ച് ചേർത്തിരിക്കുന്നു." + } + ]} +/> + +{:else} + +### 9. ഒരു Transformer മോഡലിൽ `compile()` വിളിക്കുമ്പോൾ ഒരു ലോസ് വ്യക്തമാക്കേണ്ട ആവശ്യം പലപ്പോഴും ഇല്ലാത്തത് എന്തുകൊണ്ടാണ്? + + + +{/if} + +### 10. എപ്പോഴാണ് നിങ്ങൾ ഒരു പുതിയ മോഡൽ പ്രീട്രെയിൻ ചെയ്യേണ്ടത്? + + + +### 11. വളരെയേറെ ടെക്‌സ്‌റ്റുകളിൽ ഒരു ലാംഗ്വേജ് മോഡൽ പ്രീട്രെയിൻ ചെയ്യുന്നത് എളുപ്പമായിരിക്കുന്നത് എന്തുകൊണ്ടാണ്? + + + +### 12. ഒരു ചോദ്യോത്തര ടാസ്‌ക്കിനായി ഡേറ്റ പ്രീപ്രോസസ്സ് ചെയ്യുമ്പോഴുള്ള പ്രധാന വെല്ലുവിളികൾ എന്തൊക്കെയാണ്? + + + +### 13. ചോദ്യോത്തരത്തിൽ പോസ്‌റ്റ്-പ്രോസസ്സിംഗ് സാധാരണയായി എങ്ങനെയാണ് ചെയ്യുന്നത്? + +