From 23961b0c541ed8c9d122194e89e5a97afb1f41ae Mon Sep 17 00:00:00 2001 From: Morteza Hosseini Date: Mon, 13 May 2024 21:10:07 +0100 Subject: [PATCH] Add tokenization article and notebook used in Large Language Models (LLMs) --- README copy.md | 94 ++++++++++ llm/tokenization.ipynb | 239 +++++++++++++++++++++++++ website/docs/llm/img/token-bpe.png | Bin 0 -> 74840 bytes website/docs/llm/index.md | 7 + website/docs/llm/tokenization.md | 272 +++++++++++++++++++++++++++++ 5 files changed, 612 insertions(+) create mode 100644 README copy.md create mode 100644 llm/tokenization.ipynb create mode 100644 website/docs/llm/img/token-bpe.png create mode 100644 website/docs/llm/index.md create mode 100644 website/docs/llm/tokenization.md diff --git a/README copy.md b/README copy.md new file mode 100644 index 00000000..9ebd3e9e --- /dev/null +++ b/README copy.md @@ -0,0 +1,94 @@ +# :rocket: Portfolio + +This repository includes my side projects on various applications of Data Science and Machine Learning. + +Check the documentaion [here](https://smortezah.github.io/portfolio/docs). + +Also, my articles on the Medium platform can be found [here](https://medium.com/@morihosseini/). + +**Note:** The following list is sorted alphabetically. + +## :rotating_light: Anomaly detection + +- [Credit card fraud detection](anomaly-detection/fraud-detection.ipynb): detecting fraudulent transactions in a dataset using neural networks + +## :factory: Automation + +- [Auto commit to GitHub](automation/auto-commit): automating the process of committing and pushing changes to GitHub + +## :camera: Computer Vision + +- [Ants vs bees image classification](computer-vision/ants-bees-classification/image-classification.ipynb): an app for classification of images, employing deep learning models + +## 🧩 Data Structures + +- [Hashing](data-structure/hashing.ipynb): an introduction to hashing, its applications, and Python implementation +- [Sorting](data-structure/sorting-popular.ipynb): a guide to popular sorting algorithms in Python + +## :mag: EDA (Exploratory Data Analysis) + +- [Data balancing](eda/data-balancing.ipynb): balancing imbalanced datasets using different methods +- [Handling missing data](eda/missing-data.ipynb): handling missing data in a dataset using various methods +- [Polars](eda/polars.ipynb): using [polars](https://www.pola.rs) library for data manipulation and analysis + +## :hammer_and_wrench: ETL (Extract, Transform, Load) + +- [ETL pipeline with Airflow and Docker](etl/airflow-docker): automatization of extracting data from various sources, transforming them, and loading the transformed data into a database + +## :gear: Hyperparameter tuning + +- [KerasTuner](hypertune/kerasTuner.ipynb): hyperparameter tuning using [KerasTuner](https://keras.io/keras_tuner/) library +- [Optuna](hypertune/optuna.ipynb): hyperparameter tuning with [Optuna](https://optuna.org/) library + +## :brain: LLM (Large Language Model) + +- [Tokenization](llm/tokenization.ipynb): exploring tokenization of text data + +## :robot: Machine Learning + +- [Best threshold for logistic regression](machine-learning/threshold-logistic-regression.ipynb): different methods to find the optimal threshold for logistic regression + +## :lock: Privacy + +- [Anonymization](privacy/anonymization.ipynb): an introduction to data anonymization and its applications +- [Encryption](privacy/encryption.ipynb): a beginner's guide to Python encryption + +## :snake: Python + +- [Argument parsing](python/argparse.ipynb): a guide to argument parsing using `argparse` module +- [Generators](python/generator.ipynb): a hands-on guide to generators +- [Lambda](python/lambda.ipynb): an introduction to lambda functions +- [Pattern matching](python/match-case.ipynb): a guide to pattern matching with `match-case` statement + +## :chart_with_upwards_trend: Statistical analysis + +- [A/B testing](stats/ab-test.ipynb): testing the effectiveness of a new feature in a web application by A/B testing +- [Hypothesis testing: p-values around 0.05](stats/pvalue-around-0.05.ipynb): should we reject the null hypothesis if the p-value is around 0.05? + +## :bulb: Synthetic data generation + +- [Introduction](synthetic-data/intro.ipynb): generating synthetic data using Python and also, considerations for using synthetic data + +## :desktop_computer: Terminal + +- [jq](terminal/jq.ipynb): JSON manipulating with [jq](https://jqlang.github.io/jq/) +- [Rich](terminal/rich/rich.ipynb): formatting text in the terminal using [Rich](https://github.com/Textualize/rich) library + +## :hourglass_flowing_sand: Time-series + +- [Forecasting with sktime](time-series/sktime.ipynb): time-series forecasting using [sktime](https://github.com/sktime/sktime) library +- [Prevent overfitting](time-series/prevent-overfitting.ipynb): preventing overfitting in time series forecasting using different techniques + +## :art: Visualization + +- [lets-plot](visualization/lets-plot/codebook.ipynb): plotting with [lets-plot](https://lets-plot.org/index.html), a Python port of the R's [ggplot2](https://ggplot2.tidyverse.org/) library +- [Pitfalls](visualization/pitfalls/pitfalls.ipynb): common pitfalls in data visualization and how to avoid them +- [QR code](visualization/qrcode.ipynb): generating QR codes + +## :spider_web: Web scraping + +- [jobinventory](scrape/jobinventory.com/tutorial.ipynb): scraping job listings from jobinventory.com using Python + +## :memo: XAI (Explainable AI) + +- [Introduction](xai/intro.ipynb): an introduction to explainable AI and its importance diff --git a/llm/tokenization.ipynb b/llm/tokenization.ipynb new file mode 100644 index 00000000..32354956 --- /dev/null +++ b/llm/tokenization.ipynb @@ -0,0 +1,239 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Click [here]() to access the associated Medium article." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Setup" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[2K\u001b[2mResolved \u001b[1m22 packages\u001b[0m in 314ms\u001b[0m \u001b[0m\n", + "\u001b[2K\u001b[2mDownloaded \u001b[1m1 package\u001b[0m in 792ms\u001b[0m \u001b[0m\n", + "\u001b[2K\u001b[2mInstalled \u001b[1m3 packages\u001b[0m in 219ms\u001b[0m4.40.2 \u001b[0m\n", + " \u001b[32m+\u001b[39m \u001b[1mnumpy\u001b[0m\u001b[2m==1.26.4\u001b[0m\n", + " \u001b[32m+\u001b[39m \u001b[1msafetensors\u001b[0m\u001b[2m==0.4.3\u001b[0m\n", + " \u001b[32m+\u001b[39m \u001b[1mtransformers\u001b[0m\u001b[2m==4.40.2\u001b[0m\n" + ] + } + ], + "source": [ + "!uv pip install nltk tiktoken tokenizers sentencepiece transformers" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Basic Tokenization Techniques\n", + "\n", + "## Sentence Tokenization" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Tokenization is fascinating.\n", + "Sentence tokenization splits text into sentences.\n", + "It's crucial for NLP.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[nltk_data] Downloading package punkt to /Users/user/nltk_data...\n", + "[nltk_data] Package punkt is already up-to-date!\n" + ] + } + ], + "source": [ + "import nltk\n", + "from nltk.tokenize import sent_tokenize\n", + "\n", + "nltk.download(\"punkt\")\n", + "\n", + "text = \"Tokenization is fascinating. Sentence tokenization splits text into sentences. It's crucial for NLP.\"\n", + "sentences = sent_tokenize(text)\n", + "\n", + "for sentence in sentences:\n", + " print(sentence)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Word Tokenization" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['Word', 'tokenization', 'is', 'essential', 'for', 'NLP', 'tasks', '.']\n" + ] + } + ], + "source": [ + "import nltk\n", + "from nltk.tokenize import word_tokenize\n", + "\n", + "sentence = \"Word tokenization is essential for NLP tasks.\"\n", + "words = word_tokenize(sentence)\n", + "\n", + "print(words)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Subword Tokenization" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[3214, 1178, 4037, 2065, 449, 426, 1777, 374, 8147, 13]\n" + ] + } + ], + "source": [ + "import tiktoken\n", + "\n", + "enc = tiktoken.get_encoding(\"cl100k_base\")\n", + "\n", + "text = \"Subword tokenization with BPE is powerful.\"\n", + "encoded = enc.encode(text)\n", + "decoded = enc.decode(encoded)\n", + "\n", + "assert decoded == text\n", + "\n", + "print(encoded)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Advanced Tokenization Methods\n", + "\n", + "## Byte-Level BPE (Byte-Pair Encoding)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "['[CLS]', 'byte', '-', 'level', 'bp', '##e', 'is', 'fascinating', '.', '[SEP]']\n" + ] + } + ], + "source": [ + "from tokenizers import Tokenizer\n", + "\n", + "tokenizer = Tokenizer.from_pretrained(\"bert-base-uncased\")\n", + "encoded = tokenizer.encode(\"Byte-Level BPE is fascinating.\")\n", + "decoded = tokenizer.decode(encoded.ids)\n", + "\n", + "print(encoded.tokens)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Tokenization in Pretrained LLMs" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "BERT tokens: ['token', '##ization', 'is', 'fascinating', '.']\n", + "GPT-2 tokens: ['Token', 'ization', 'Ġis', 'Ġfascinating', '.']\n" + ] + } + ], + "source": [ + "from transformers import BertTokenizer, GPT2Tokenizer\n", + "\n", + "# Load BERT and GPT2 tokenizers\n", + "bert_tokenizer = BertTokenizer.from_pretrained(\"bert-base-uncased\")\n", + "gpt2_tokenizer = GPT2Tokenizer.from_pretrained(\"gpt2\")\n", + "\n", + "# Tokenize a sentence\n", + "sentence = \"Tokenization is fascinating.\"\n", + "bert_tokens = bert_tokenizer.tokenize(sentence)\n", + "gpt2_tokens = gpt2_tokenizer.tokenize(sentence)\n", + "\n", + "print(\"BERT tokens:\", bert_tokens)\n", + "print(\"GPT-2 tokens:\", gpt2_tokens)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/website/docs/llm/img/token-bpe.png b/website/docs/llm/img/token-bpe.png new file mode 100644 index 0000000000000000000000000000000000000000..d2aa158793fc9cbcf17b212cdeef426848cfb88c GIT binary patch literal 74840 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 +``` diff --git a/website/docs/llm/tokenization.md b/website/docs/llm/tokenization.md new file mode 100644 index 00000000..88a75d0b --- /dev/null +++ b/website/docs/llm/tokenization.md @@ -0,0 +1,272 @@ +--- +description: Explore tokenization techniques +tags: [tokenization, LLM, NLP, python, AI] +--- + +# Tokenization + +![OpenAI tokenizer](img/token-bpe.png) + +Tokenization is a crucial step in natural language processing (NLP), where we break down text into smaller units (tokens) for further analysis. In this article, we’ll explore various tokenization techniques, their pros and cons, and practical tips for implementing them in Python. + +## 1. Introduction to Tokenization + +In this section, we'll explore the basics of tokenization, its importance for large language models (LLMs), and the difference between tokenization and word segmentation. + +### What is Tokenization? + +Tokenization is the process of breaking down a piece of text (usually a sentence or a document) into smaller units called **tokens**. These tokens can be words, subwords, or even characters. Why do we need tokenization? Well, imagine trying to analyze a long paragraph without breaking it down into meaningful chunks-it would be like trying to solve a jigsaw puzzle blindfolded! + +### Why is Tokenization Essential for LLMs? + +Large language models, such as BERT, GPT, and their variants, rely heavily on tokenization. Here's why: + +1. **Input Representation**: LLMs process input text in the form of tokenized sequences. Each token corresponds to a position in the input. + +2. **Fixed-Length Context**: LLMs have a fixed context window (e.g., 512 tokens for BERT). Tokenization ensures that the input fits within this window. + +3. **Embeddings**: Tokens are converted into dense vector representations (embeddings) that capture semantic meaning. These embeddings drive the model's predictions. + +### Tokenization vs. Word Segmentation + +While tokenization and word segmentation might seem similar, they serve different purposes: + +1. **Tokenization**: Focuses on dividing text into meaningful units (tokens). It handles punctuation, special characters, and spaces. + +2. **Word Segmentation**: Specifically deals with splitting languages like Chinese or Japanese, where words don't have clear spaces. Word segmentation breaks down continuous text into individual words. + +## 2. Basic Tokenization Techniques + +In this section, we'll explore the fundamental tokenization techniques that form the building blocks for more advanced methods. + +### Sentence Tokenization + +**Sentence tokenization** involves splitting a text into individual sentences. It's essential because many NLP tasks operate at the sentence level. Python's `nltk` library provides useful tools for sentence tokenization: + +```python title="Python" +import nltk +from nltk.tokenize import sent_tokenize + +nltk.download('punkt') + +text = "Tokenization is fascinating. Sentence tokenization splits text into sentences. It's crucial for NLP." +sentences = sent_tokenize(text) + +for sentence in sentences: + print(sentence) +``` + +Output: + +``` +Tokenization is fascinating. +Sentence tokenization splits text into sentences. +It's crucial for NLP. +``` + +### Word Tokenization + +**Word tokenization** breaks down a sentence into individual words. The `nltk` library also offers word tokenization: + +```python title="Python" +from nltk.tokenize import word_tokenize + +sentence = "Word tokenization is essential for NLP tasks." +words = word_tokenize(sentence) + +print(words) +``` + +Output: + +``` +['Word', 'tokenization', 'is', 'essential', 'for', 'NLP', 'tasks', '.'] +``` + +### Subword Tokenization (e.g., Byte-Pair Encoding) + +Subword tokenization splits text into smaller units, such as subwords or characters. **Byte-Pair Encoding (BPE)** is a popular subword tokenization method. It merges the most frequent character pairs iteratively to create subword tokens. The `tiktoken` library in Python provides an efficient BPE implementation: + +```python title="Python" +import tiktoken + +enc = tiktoken.get_encoding("cl100k_base") + +text = "Subword tokenization with BPE is powerful." +encoded = enc.encode(text) +decoded = enc.decode(encoded) + +assert decoded == text + +print(encoded) +``` + +Output: + +``` +[3214, 1178, 4037, 2065, 449, 426, 1777, 374, 8147, 13] +``` + +## 3. Advanced Tokenization Methods + +In this segment, we'll explore more sophisticated tokenization techniques that go beyond the basics. Let's dive right in! + +### Byte-Level BPE (Byte-Pair Encoding) + +**Byte-Level BPE** is a powerful subword tokenization method. It operates at the byte level, making it suitable for handling various languages, special characters, and emojis. Here's how it works: + +1. **Learn Subword Vocabulary**: Byte-Level BPE starts with a vocabulary containing individual bytes (characters). It then iteratively merges the most frequent byte pairs until reaching a specified vocabulary size. + +2. **Subword Encoding**: Given a text, Byte-Level BPE encodes it by replacing common byte pairs with subword tokens. For example, the word "unhappiness" might be encoded as "un##happiness." + +3. **Decoding**: During decoding, we reverse the process to obtain the original text. + +Let's see an example using Python and the `tokenizers` library: + +```python title="Python" +from tokenizers import Tokenizer + +tokenizer = Tokenizer.from_pretrained("bert-base-uncased") +encoded = tokenizer.encode("Byte-Level BPE is fascinating.") +decoded = tokenizer.decode(encoded.ids) + +print(encoded.tokens) +``` + +Output: + +``` +['[CLS]', 'byte', '-', 'level', 'bp', '##e', 'is', 'fascinating', '.', '[SEP]'] +``` + +### SentencePiece + +**SentencePiece** is another subword tokenization method that's widely used in NLP. It's particularly effective for languages with complex word boundaries (e.g., Japanese, Korean). Here's how it works: + +1. **Unsupervised Learning**: SentencePiece learns subword units from raw text without relying on word boundaries or linguistic knowledge. + +2. **Vocabulary Size**: You can control the vocabulary size, allowing flexibility in balancing token granularity. + +3. **Subword Encoding and Decoding**: Similar to BPE, SentencePiece encodes and decodes text efficiently. + +### Unigram Language Model + +The **Unigram Language Model** tokenizes text based on the likelihood of each subword occurring independently. It doesn't rely on pairs like BPE or SentencePiece. While less common, it's worth exploring if you're working with specific languages or domain-specific data. + +## 4. Handling Special Cases + +In this section, we'll explore how to handle special cases during tokenization. While most tokenization methods work well for standard text, real-world data often contains challenges like emojis, URLs, and hashtags. + +### Dealing with Emojis, URLs, and Hashtags + +#### Emojis + +Emojis add expressive power to text, but they can disrupt tokenization. Here's how to handle them: + +1. **Preserve Emojis**: Some tokenizers treat emojis as separate tokens. If you want to preserve them, ensure your tokenizer doesn't split emojis into individual characters. + +2. **Replace Emojis**: Alternatively, you can replace emojis with a special token (e.g., ``). This simplifies tokenization. + +#### URLs + +URLs contain special characters (e.g., slashes, dots) that can confuse tokenizers. Consider the following approaches: + +1. **Remove URLs**: If URLs don't carry essential information, remove them before tokenization. + +2. **Replace URLs**: Replace URLs with a placeholder (e.g., ``). This ensures they don't interfere with token boundaries. + +#### Hashtags + +Hashtags (common on social media) pose a similar challenge. Here's how to handle them: + +1. **Split Hashtags**: Split hashtags into individual words. For example, `#MachineLearning` becomes `Machine Learning`. + +2. **Preserve Hashtags**: If hashtags convey specific meaning, preserve them as a single token. + +### Custom Tokenization Rules + +Sometimes, you'll encounter domain-specific terms or abbreviations. Custom rules can help: + +1. **Add Custom Tokens**: Extend your tokenizer's vocabulary with domain-specific terms. For instance, include medical abbreviations if working with healthcare data. + +2. **Preprocess Text**: Apply custom preprocessing (e.g., replacing acronyms) before tokenization. + +Adapt your approach based on your specific use case and the nature of your data. + +## 5. Tokenization in Pretrained LLMs + +In this section, we'll explore how tokenization is handled in pretrained large language models (LLMs) like BERT, GPT, and their variants. These models have revolutionized NLP tasks, and understanding their tokenization process is essential for effective usage. + +### How BERT and GPT Tokenize Input + +1. **WordPiece Tokenization (BERT)**: + + - BERT uses **WordPiece** tokenization, which is similar to BPE but operates at the word level. + - It starts with a vocabulary of subword units (usually words). + - During tokenization, BERT splits words into subword tokens (e.g., "unhappiness" becomes "un" + "##happiness"). + - Special tokens like `[CLS]` (classification) and `[SEP]` (separator) are added to the input. + +2. **Byte-Level Tokenization (GPT)**: + + - GPT models, on the other hand, use **byte-level tokenization**. + - They treat each byte (character) as a token. + - This approach handles languages with complex scripts (e.g., Chinese, Japanese) effectively. + +3. **Special Tokens**: + - Both BERT and GPT add special tokens to the input sequence. + - `[CLS]` token marks the start of the input, and `[SEP]` token separates segments (e.g., sentences or paragraphs). + - Positional embeddings ensure the model understands token order. + +### Practical Example + +Let's see how to tokenize a sentence using the popular `transformers` library in Python: + +```python title="Python" +from transformers import BertTokenizer, GPT2Tokenizer + +# Load BERT and GPT2 tokenizers +bert_tokenizer = BertTokenizer.from_pretrained("bert-base-uncased") +gpt2_tokenizer = GPT2Tokenizer.from_pretrained("gpt2") + +# Tokenize a sentence +sentence = "Tokenization is fascinating." +bert_tokens = bert_tokenizer.tokenize(sentence) +gpt2_tokens = gpt2_tokenizer.tokenize(sentence) + +print("BERT tokens:", bert_tokens) +print("GPT-2 tokens:", gpt2_tokens) +``` + +Output: + +``` +BERT tokens: ['token', '##ization', 'is', 'fascinating', '.'] +GPT-2 tokens: ['Token', 'ization', 'Ġis', 'Ġfascinating', '.'] +``` + +### Special Considerations: + +- **Subword Units**: BERT and GPT handle subword units differently, impacting their tokenization behavior. +- **Custom Tokens**: You can add custom tokens to the vocabulary for domain-specific tasks. + +Remember that tokenization affects downstream tasks, so choose the right method based on your use case. + +## 6. Tips for Efficient Tokenization + +Tokenization is a critical step in natural language processing (NLP), and optimizing this process can significantly impact your overall workflow. Here are some practical tips to ensure efficient tokenization: + +1. **Batch Processing**: + + - If you're dealing with a large dataset, consider batch processing. Tokenize multiple sentences at once to reduce overhead and improve speed. + - Libraries like `transformers` allow batch tokenization, which is especially useful when working with pretrained language models. + +2. **Preprocessing**: + + - Clean your text before tokenization. Remove unnecessary characters, HTML tags, or special symbols. + - Address common issues like extra spaces, line breaks, and punctuation. + +3. **Custom Rules**: + - Add custom rules to handle domain-specific terms or special cases. + - For instance, if you're working with medical data, include medical abbreviations in your tokenizer's vocabulary. + +And there you have it! Armed with these practical examples, you're ready to tokenize text like a pro. If you have any questions or need further assistance, feel free to ask!