{ "nbformat": 4, "nbformat_minor": 0, "metadata": { "colab": { "provenance": [], "gpuType": "T4" }, "kernelspec": { "name": "python3", "display_name": "Python 3" }, "language_info": { "name": "python" }, "accelerator": "GPU" }, "cells": [ { "cell_type": "markdown", "source": [ "# The NLP Pipeline" ], "metadata": { "id": "BK6CXSOk6K-X" } }, { "cell_type": "markdown", "source": [ "![NLP Pipeline](https://images.prismic.io/turing/65980b21531ac2845a272614_Natural_language_processing_pipeline_e3608ff95c.webp?auto=format,compress)" ], "metadata": { "id": "-Q-ktKxN6QFc" } }, { "cell_type": "markdown", "source": [ "## 1. Sentence Segmentation πŸ’¬\n", "\n", "This initial step involves **breaking down raw text into individual sentences**. It's crucial because many subsequent NLP tasks operate at the sentence level. We'll use a library like **NLTK's `punkt` tokenizer**, which is trained to recognize sentence boundaries.\n", "\n", "* **Colab Demo:**\n", " * **Input:** A multi-sentence paragraph.\n", " * **Code:** `from nltk.tokenize import sent_tokenize; text = \"Your sample paragraph here.\"; sentences = sent_tokenize(text)`\n", " * **Output:** A list where each element is a separate sentence." ], "metadata": { "id": "4E-bWQxq6unO" } }, { "cell_type": "markdown", "source": [ "## 2. Word Tokenization 🏷️\n", "\n", "After segmentation, we further break down each sentence into **individual words or \"tokens.\"** Punctuation is often treated as separate tokens. This process creates the fundamental units of text that NLP models will analyze. We'll again use an NLTK tokenizer for this.\n", "\n", "* **Colab Demo:**\n", " * **Input:** A single sentence (from the previous step's output).\n", " * **Code:** `from nltk.tokenize import word_tokenize; sentence = \"Your sample sentence here.\"; words = word_tokenize(sentence)`\n", " * **Output:** A list of individual words and punctuation marks." ], "metadata": { "id": "AuhW2n-h7jHe" } }, { "cell_type": "markdown", "source": [ "## 3. Stemming 🌳\n", "\n", "Stemming is a basic technique to **reduce words to their root or \"stem\" form** by chopping off suffixes. The resulting stem might not be a linguistically valid word, but it helps group together variations of a word. It's often used for information retrieval. We'll demonstrate with **NLTK's Porter Stemmer**.\n", "\n", "* **Colab Demo:**\n", " * **Input:** A list of words (e.g., \"running,\" \"runs,\" \"ran,\" \"runner\").\n", " * **Code:** `from nltk.stem import PorterStemmer; stemmer = PorterStemmer(); stemmed_words = [stemmer.stem(word) for word in words_list]`\n", " * **Output:** The list of words with their stemmed versions (e.g., \"run,\" \"run,\" \"ran,\" \"runner\")." ], "metadata": { "id": "uN-UpLCq7oUf" } }, { "cell_type": "markdown", "source": [ "## 4. Lemmatization πŸ‹\n", "\n", "Lemmatization is a more sophisticated process that **reduces words to their base or dictionary form (lemma)**. Unlike stemming, the lemma is always a valid word. It uses morphological analysis and often requires knowing the word's part of speech for accuracy. We'll use **NLTK's WordNetLemmatizer**.\n", "\n", "* **Colab Demo:**\n", " * **Input:** A list of words (e.g., \"better,\" \"cars,\" \"geese,\" \"ran\").\n", " * **Code:** `from nltk.stem import WordNetLemmatizer; lemmatizer = WordNetLemmatizer(); lemmatized_words = [lemmatizer.lemmatize(word) for word in words_list]`\n", " * **Output:** The list of words with their lemmatized versions (e.g., \"good,\" \"car,\" \"goose,\" \"run\")." ], "metadata": { "id": "hQ7ZDOs37s5F" } }, { "cell_type": "markdown", "source": [ "## 5. Stop Word Analysis 🚫\n", "\n", "**Stop words are common words** (like \"the,\" \"a,\" \"is,\" \"and\") that often carry little significant meaning and can be removed without losing much context. Removing them helps reduce noise and focus on more important terms for analysis. We'll use NLTK's predefined list of English stop words.\n", "\n", "* **Colab Demo:**\n", " * **Input:** A sentence or list of words containing stop words.\n", " * **Code:** `from nltk.corpus import stopwords; stop_words = set(stopwords.words('english')); filtered_words = [word for word in word_list if word.lower() not in stop_words]`\n", " * **Output:** The list of words with stop words removed." ], "metadata": { "id": "fRjDQklN7xbz" } }, { "cell_type": "markdown", "source": [], "metadata": { "id": "oOrr6EPQ7z5h" } }, { "cell_type": "markdown", "source": [ "## 6. Dependency Parsing πŸ”—\n", "\n", "Dependency parsing analyzes the **grammatical relationships between words in a sentence**. It identifies which words are dependent on others, forming a tree-like structure. This helps us understand the syntactic structure and how words relate to each other's meanings. We'll use **spaCy** for its efficient dependency parser.\n", "\n", "* **Colab Demo:**\n", " * **Input:** A simple sentence.\n", " * **Code:** `import spacy; nlp = spacy.load(\"en_core_web_sm\"); doc = nlp(\"The quick brown fox jumps over the lazy dog.\"); for token in doc: print(f\"{token.text} -- {token.dep_} -- {token.head.text}\")`\n", " * **Output:** A table showing each word, its dependency relation, and its head word. You might also display spaCy's built-in dependency visualizer." ], "metadata": { "id": "HR6r2uLy75JP" } }, { "cell_type": "markdown", "source": [ "## 7. Part-of-Speech Tagging 🏷️\n", "\n", "Part-of-Speech (POS) tagging is the process of **assigning a grammatical category to each word** in a sentence. This includes tags like noun (NN), verb (VB), adjective (JJ), adverb (RB), etc. It's a fundamental step that helps subsequent analyses understand the role of each word. We'll use **spaCy** for this.\n", "\n", "* **Colab Demo:**\n", " * **Input:** A sentence.\n", " * **Code:** `import spacy; nlp = spacy.load(\"en_core_web_sm\"); doc = nlp(\"The quick brown fox jumps over the lazy dog.\"); for token in doc: print(f\"{token.text} -- {token.pos_}\")`\n", " * **Output:** Each word followed by its assigned POS tag." ], "metadata": { "id": "n87eCqiG752y" } }, { "cell_type": "markdown", "source": [ "---" ], "metadata": { "id": "2WUj-RLl8EyW" } }, { "cell_type": "markdown", "source": [ "# Natural Language Processing (NLP) Pipeline & Sentiment Analysis Demo" ], "metadata": { "id": "x7L3ZGft8GEi" } }, { "cell_type": "markdown", "source": [ "This Google Colab notebook demonstrates fundamental steps in a Natural Language Processing (NLP) pipeline,\n", "followed by a practical example of sentiment analysis.\n", "\n", "We will cover:\n", "1. **NLP Pipeline Steps:**\n", " * Sentence Segmentation\n", " * Word Tokenization\n", " * Stemming\n", " * Lemmatization\n", " * Stop Word Removal\n", " * Dependency Parsing\n", " * Part-of-Speech Tagging\n", "2. **Sentiment Analysis:**\n", " * Using NLTK's VADER (Valence Aware Dictionary and sEntiment Reasoner)\n", "\n", "Let's get started!" ], "metadata": { "id": "ujVtZFGRGSxI" } }, { "cell_type": "code", "source": [ "%%bash\n", "pip install nltk huggingface_hub transformers spacy gensim fastai==2.7.12 fastcore==1.5.29 inltk==0.5.1\n", "\n", "# Download necessary NLTK data\n", "python -c \"import nltk; nltk.download('punkt'); nltk.download('wordnet'); nltk.download('stopwords'); nltk.download('averaged_perceptron_tagger'); nltk.download('vader_lexicon')\"\n", "\n", "# Download necessary spaCy model\n", "python -m spacy download en_core_web_sm" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "Yffv35qsBiqf", "outputId": "d070ca40-b633-4e85-d7b5-882b149ee2c1" }, "execution_count": 2, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Requirement already satisfied: nltk in /usr/local/lib/python3.11/dist-packages (3.9.1)\n", "Requirement already satisfied: huggingface_hub in /usr/local/lib/python3.11/dist-packages (0.33.4)\n", "Requirement already satisfied: transformers in /usr/local/lib/python3.11/dist-packages (4.53.2)\n", "Requirement already satisfied: spacy in /usr/local/lib/python3.11/dist-packages (3.8.7)\n", "Collecting gensim\n", " Downloading gensim-4.3.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (8.1 kB)\n", "Collecting fastai==2.7.12\n", " Downloading fastai-2.7.12-py3-none-any.whl.metadata (9.6 kB)\n", "Collecting fastcore==1.5.29\n", " Downloading fastcore-1.5.29-py3-none-any.whl.metadata (3.5 kB)\n", "Collecting en-core-web-sm==3.8.0\n", " Downloading https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.8.0/en_core_web_sm-3.8.0-py3-none-any.whl (12.8 MB)\n", " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 12.8/12.8 MB 106.5 MB/s eta 0:00:00\n", "\u001b[38;5;2mβœ” Download and installation successful\u001b[0m\n", "You can now load the package via spacy.load('en_core_web_sm')\n", "\u001b[38;5;3m⚠ Restart to reload dependencies\u001b[0m\n", "If you are in a Jupyter or Colab notebook, you may need to restart Python in\n", "order to load all the package's dependencies. You can do this by selecting the\n", "'Restart kernel' or 'Restart runtime' option.\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "ERROR: Could not find a version that satisfies the requirement inltk==0.5.1 (from versions: 0.0.2, 0.0.3, 0.0.4, 0.0.5, 0.0.6, 0.0.7, 0.0.8, 0.1.0, 0.2.0, 0.3.0, 0.4.0, 0.5.0, 0.6.0, 0.6.1, 0.7, 0.7.1, 0.7.2, 0.7.3, 0.7.4, 0.7.5, 0.8, 0.8.1, 0.9)\n", "ERROR: No matching distribution found for inltk==0.5.1\n", "[nltk_data] Downloading package punkt to /root/nltk_data...\n", "[nltk_data] Unzipping tokenizers/punkt.zip.\n", "[nltk_data] Downloading package wordnet to /root/nltk_data...\n", "[nltk_data] Downloading package stopwords to /root/nltk_data...\n", "[nltk_data] Unzipping corpora/stopwords.zip.\n", "[nltk_data] Downloading package averaged_perceptron_tagger to\n", "[nltk_data] /root/nltk_data...\n", "[nltk_data] Unzipping taggers/averaged_perceptron_tagger.zip.\n", "[nltk_data] Downloading package vader_lexicon to /root/nltk_data...\n" ] } ] }, { "cell_type": "markdown", "metadata": { "id": "4ecccc97" }, "source": [ "## NLP Pipeline Demonstration (English)" ] }, { "cell_type": "code", "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "c71fac50", "outputId": "436a9190-607a-4e6f-e51a-1d555776f6b4" }, "source": [ "import nltk\n", "import spacy\n", "from nltk.tokenize import sent_tokenize, word_tokenize\n", "from nltk.stem import PorterStemmer, WordNetLemmatizer\n", "from nltk.corpus import stopwords\n", "from nltk.sentiment.vader import SentimentIntensityAnalyzer\n", "\n", "# Download necessary NLTK data (already done in setup but good to have here too)\n", "# These lines are typically run once in the setup cell.\n", "# For this standalone snippet, uncomment if running in a fresh environment\n", "# nltk.download('punkt')\n", "# nltk.download('wordnet')\n", "# nltk.download('stopwords')\n", "# nltk.download('averaged_perceptron_tagger') # Needed for default POS tagging with NLTK, but we use spaCy here\n", "# nltk.download('vader_lexicon')\n", "# nltk.download('punkt_tab') # This specific download is often not needed if 'punkt' is already there\n", "print(\"NLTK data resources checked/downloaded...\")\n", "\n", "\n", "# Load spaCy model\n", "try:\n", " nlp_en = spacy.load(\"en_core_web_sm\")\n", " print(\"\\nEnglish Core Web spaCy Model Loaded successfully.\\n\")\n", "except OSError:\n", " print(\"SpaCy model 'en_core_web_sm' not found. Downloading...\")\n", " !python -m spacy download en_core_web_sm\n", " nlp_en = spacy.load(\"en_core_web_sm\")\n", " print(\"\\nEnglish Core Web spaCy Model Downloaded and Loaded.\\n\")\n", "\n", "\n", "text_en = \"\"\"Natural Language Processing (NLP) is a fascinating and rapidly evolving field at the intersection of computer science, artificial intelligence, and linguistics. At its core, NLP enables computers to understand, interpret, and generate human language in a valuable and meaningful way. It's about bridging the communication gap between humans and machines, allowing us to interact with technology using our most natural form of expression: language.\\n\n", "The utility of NLP spans a vast array of applications that touch our daily lives, often without us even realizing it. From the moment you ask a virtual assistant a question, to the automatic translation of a webpage, or even the spam filter protecting your inbox, NLP is hard at work. It's the engine behind search engines that understand your queries, recommendation systems that suggest content, and grammar checkers that refine your writing.\\n\n", "One of NLP's crucial applications is in sentiment analysis, where it determines the emotional tone behind a piece of text. Businesses use this to gauge customer feedback from social media, reviews, and surveys, allowing them to understand public perception of their products or services. This insight is invaluable for strategic decision-up making, product development, and customer relationship management.\\n\n", "Machine translation is another cornerstone of NLP, breaking down language barriers across the globe. Services like Google Translate utilize sophisticated NLP models to convert text or speech from one language to another, facilitating international communication, trade, and cultural exchange.11 While still imperfect, these systems are constantly improving, striving for more nuanced and contextually accurate translations.\\n\n", "The rise of chatbots and virtual assistants is heavily reliant on NLP. These AI-powered entities process user queries, understand their intent, and generate coherent and relevant responses, simulating human-like conversation.14 They are increasingly deployed in customer service, healthcare, and education, providing instant support and information, thereby enhancing user experience and operational efficiency.\\n\n", "NLP also plays a pivotal role in information extraction, where it identifies and pulls specific data points from unstructured text. This can involve extracting names, dates, locations, or key facts from legal documents, research papers, or news articles. It transforms vast quantities of raw text into structured, actionable data, significantly reducing the manual effort required for data analysis and knowledge discovery.\\n\n", "The importance of NLP cannot be overstated in today's data-driven world. As the volume of digital text data explodes, NLP provides the tools to make sense of this information, transforming it into valuable insights. It empowers organizations to automate tasks, improve decision-making, enhance customer interactions, and uncover hidden patterns in textual data that would otherwise be impossible to analyze at scale.\\n\n", "Furthermore, NLP is critical for accessibility and inclusion. By enabling text-to-speech and speech-to-text functionalities, it assists individuals with disabilities in accessing information and communicating more effectively. It also helps bridge linguistic divides, allowing people from different language backgrounds to interact and share knowledge seamlessly.\\n\n", "The advancements in NLP are largely driven by breakthroughs in machine learning and deep learning, particularly with the advent of transformer models like BERT, GPT, and others. These models have revolutionized the field, pushing the boundaries of what's possible in language understanding and generation, leading to more accurate translations, more coherent text generation, and more sophisticated conversational AI.\\n\n", "In conclusion, NLP is not just a technological innovation; it's a transformative force that is reshaping how humans interact with technology and each other. Its continuous evolution promises to unlock even more sophisticated applications, further integrating intelligent language capabilities into every facet of our digital and real-world experiences, making information more accessible and interactions more intuitive.\\n\"\"\"\n", "\n", "# --- Original Text Display ---\n", "print(\"\\n\" + \"=\"*50)\n", "print(\" ORIGINAL TEXT\")\n", "print(\"=\"*50)\n", "print(f\"\\n{text_en}\\n\")\n", "print(\"=\"*50)\n", "\n", "\n", "# --- 1. Sentence Segmentation ---\n", "print(\"\\n\\n\" + \"=\"*50)\n", "print(\" 1. SENTENCE SEGMENTATION\")\n", "print(\"=\"*50)\n", "sentences_en = sent_tokenize(text_en)\n", "print(\"\\nDetected Sentences:\")\n", "for i, sentence in enumerate(sentences_en):\n", " print(f\" [{i+1}] {sentence}\")\n", "print(\"-\" * 50)\n", "\n", "\n", "# --- 2. Word Tokenization ---\n", "print(\"\\n\\n\" + \"=\"*50)\n", "print(\" 2. WORD TOKENIZATION\")\n", "print(\"=\"*50)\n", "# Using the first sentence for demonstration\n", "words_en = word_tokenize(sentences_en[0])\n", "print(f\"\\nSentence for Tokenization: '{sentences_en[0]}'\")\n", "print(f\"Tokens: {words_en}\")\n", "print(\"-\" * 50)\n", "\n", "\n", "# --- 3. Stemming (using Porter Stemmer) ---\n", "print(\"\\n\\n\" + \"=\"*50)\n", "print(\" 3. STEMMING (Porter Stemmer)\")\n", "print(\"=\"*50)\n", "stemmer = PorterStemmer()\n", "stemmed_words_en = [stemmer.stem(word) for word in words_en]\n", "print(f\"\\nOriginal Tokens: {words_en}\")\n", "print(f\"Stemmed Tokens: {stemmed_words_en}\")\n", "print(\"-\" * 50)\n", "\n", "\n", "# --- 4. Lemmatization (using WordNetLemmatizer) ---\n", "print(\"\\n\\n\" + \"=\"*50)\n", "print(\" 4. LEMMATIZATION (WordNetLemmatizer)\")\n", "print(\"=\"*50)\n", "lemmatizer = WordNetLemmatizer()\n", "# Note: Lemmatization often benefits from POS tagging for accuracy\n", "# For a simple demo, we'll just use the default (noun)\n", "lemmatized_words_en = [lemmatizer.lemmatize(word) for word in words_en]\n", "print(f\"\\nOriginal Tokens: {words_en}\")\n", "print(f\"Lemmatized Tokens: {lemmatized_words_en}\")\n", "print(\"-\" * 50)\n", "\n", "\n", "# --- 5. Stop Word Analysis ---\n", "print(\"\\n\\n\" + \"=\"*50)\n", "print(\" 5. STOP WORD REMOVAL\")\n", "print(\"=\"*50)\n", "stop_words_en = set(stopwords.words('english'))\n", "filtered_words_en = [word for word in words_en if word.lower() not in stop_words_en]\n", "print(f\"\\nOriginal Tokens: {words_en}\")\n", "print(f\"Tokens after Stop Word Removal: {filtered_words_en}\")\n", "print(\"-\" * 50)\n", "\n", "\n", "# --- 6. Dependency Parsing (using spaCy) ---\n", "print(\"\\n\\n\" + \"=\"*50)\n", "print(\" 6. DEPENDENCY PARSING (using spaCy)\")\n", "print(\"=\"*50)\n", "# Corrected: Process the first sentence (a string) with spaCy\n", "doc_en_parsed = nlp_en(sentences_en[0])\n", "print(f\"\\nSentence for Dependency Parsing: '{sentences_en[0]}'\")\n", "print(\"\\n{:<15} {:<20} {:<15} {:<10}\".format(\"Word\", \"Dependency Relation\", \"Head Word\", \"Head POS\"))\n", "print(\"-\" * 70) # Adjusted length for better visual separation\n", "for token in doc_en_parsed:\n", " print(f\"{token.text:<15} {token.dep_:<20} {token.head.text:<15} {token.head.pos_:<10}\")\n", "print(\"-\" * 70)\n", "\n", "\n", "# --- 7. Part-of-Speech Tagging (using spaCy) ---\n", "print(\"\\n\\n\" + \"=\"*50)\n", "print(\" 7. PART-OF-SPEECH TAGGING (using spaCy)\")\n", "print(\"=\"*50)\n", "# Using the same doc_en_parsed from the previous step for consistency\n", "print(f\"\\nSentence for POS Tagging: '{sentences_en[0]}'\")\n", "print(\"\\n{:<15} {:<15} {:<25}\".format(\"Word\", \"POS Tag\", \"Explanation\"))\n", "print(\"-\" * 55)\n", "for token in doc_en_parsed:\n", " print(f\"{token.text:<15} {token.pos_:<15} {spacy.explain(token.pos_):<25}\")\n", "print(\"-\" * 55)\n", "\n", "print(\"\\n\\n\" + \"=\"*50)\n", "print(\" NLP Pipeline Demo Complete!\")\n", "print(\"=\"*50)\n" ], "execution_count": 1, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "NLTK data resources checked/downloaded...\n", "\n", "English Core Web spaCy Model Loaded successfully.\n", "\n", "\n", "==================================================\n", " ORIGINAL TEXT\n", "==================================================\n", "\n", "Natural Language Processing (NLP) is a fascinating and rapidly evolving field at the intersection of computer science, artificial intelligence, and linguistics. At its core, NLP enables computers to understand, interpret, and generate human language in a valuable and meaningful way. It's about bridging the communication gap between humans and machines, allowing us to interact with technology using our most natural form of expression: language.\n", "\n", "The utility of NLP spans a vast array of applications that touch our daily lives, often without us even realizing it. From the moment you ask a virtual assistant a question, to the automatic translation of a webpage, or even the spam filter protecting your inbox, NLP is hard at work. It's the engine behind search engines that understand your queries, recommendation systems that suggest content, and grammar checkers that refine your writing.\n", "\n", "One of NLP's crucial applications is in sentiment analysis, where it determines the emotional tone behind a piece of text. Businesses use this to gauge customer feedback from social media, reviews, and surveys, allowing them to understand public perception of their products or services. This insight is invaluable for strategic decision-up making, product development, and customer relationship management.\n", "\n", "Machine translation is another cornerstone of NLP, breaking down language barriers across the globe. Services like Google Translate utilize sophisticated NLP models to convert text or speech from one language to another, facilitating international communication, trade, and cultural exchange.11 While still imperfect, these systems are constantly improving, striving for more nuanced and contextually accurate translations.\n", "\n", "The rise of chatbots and virtual assistants is heavily reliant on NLP. These AI-powered entities process user queries, understand their intent, and generate coherent and relevant responses, simulating human-like conversation.14 They are increasingly deployed in customer service, healthcare, and education, providing instant support and information, thereby enhancing user experience and operational efficiency.\n", "\n", "NLP also plays a pivotal role in information extraction, where it identifies and pulls specific data points from unstructured text. This can involve extracting names, dates, locations, or key facts from legal documents, research papers, or news articles. It transforms vast quantities of raw text into structured, actionable data, significantly reducing the manual effort required for data analysis and knowledge discovery.\n", "\n", "The importance of NLP cannot be overstated in today's data-driven world. As the volume of digital text data explodes, NLP provides the tools to make sense of this information, transforming it into valuable insights. It empowers organizations to automate tasks, improve decision-making, enhance customer interactions, and uncover hidden patterns in textual data that would otherwise be impossible to analyze at scale.\n", "\n", "Furthermore, NLP is critical for accessibility and inclusion. By enabling text-to-speech and speech-to-text functionalities, it assists individuals with disabilities in accessing information and communicating more effectively. It also helps bridge linguistic divides, allowing people from different language backgrounds to interact and share knowledge seamlessly.\n", "\n", "The advancements in NLP are largely driven by breakthroughs in machine learning and deep learning, particularly with the advent of transformer models like BERT, GPT, and others. These models have revolutionized the field, pushing the boundaries of what's possible in language understanding and generation, leading to more accurate translations, more coherent text generation, and more sophisticated conversational AI.\n", "\n", "In conclusion, NLP is not just a technological innovation; it's a transformative force that is reshaping how humans interact with technology and each other. Its continuous evolution promises to unlock even more sophisticated applications, further integrating intelligent language capabilities into every facet of our digital and real-world experiences, making information more accessible and interactions more intuitive.\n", "\n", "\n", "==================================================\n", "\n", "\n", "==================================================\n", " 1. SENTENCE SEGMENTATION\n", "==================================================\n", "\n", "Detected Sentences:\n", " [1] Natural Language Processing (NLP) is a fascinating and rapidly evolving field at the intersection of computer science, artificial intelligence, and linguistics.\n", " [2] At its core, NLP enables computers to understand, interpret, and generate human language in a valuable and meaningful way.\n", " [3] It's about bridging the communication gap between humans and machines, allowing us to interact with technology using our most natural form of expression: language.\n", " [4] The utility of NLP spans a vast array of applications that touch our daily lives, often without us even realizing it.\n", " [5] From the moment you ask a virtual assistant a question, to the automatic translation of a webpage, or even the spam filter protecting your inbox, NLP is hard at work.\n", " [6] It's the engine behind search engines that understand your queries, recommendation systems that suggest content, and grammar checkers that refine your writing.\n", " [7] One of NLP's crucial applications is in sentiment analysis, where it determines the emotional tone behind a piece of text.\n", " [8] Businesses use this to gauge customer feedback from social media, reviews, and surveys, allowing them to understand public perception of their products or services.\n", " [9] This insight is invaluable for strategic decision-up making, product development, and customer relationship management.\n", " [10] Machine translation is another cornerstone of NLP, breaking down language barriers across the globe.\n", " [11] Services like Google Translate utilize sophisticated NLP models to convert text or speech from one language to another, facilitating international communication, trade, and cultural exchange.11 While still imperfect, these systems are constantly improving, striving for more nuanced and contextually accurate translations.\n", " [12] The rise of chatbots and virtual assistants is heavily reliant on NLP.\n", " [13] These AI-powered entities process user queries, understand their intent, and generate coherent and relevant responses, simulating human-like conversation.14 They are increasingly deployed in customer service, healthcare, and education, providing instant support and information, thereby enhancing user experience and operational efficiency.\n", " [14] NLP also plays a pivotal role in information extraction, where it identifies and pulls specific data points from unstructured text.\n", " [15] This can involve extracting names, dates, locations, or key facts from legal documents, research papers, or news articles.\n", " [16] It transforms vast quantities of raw text into structured, actionable data, significantly reducing the manual effort required for data analysis and knowledge discovery.\n", " [17] The importance of NLP cannot be overstated in today's data-driven world.\n", " [18] As the volume of digital text data explodes, NLP provides the tools to make sense of this information, transforming it into valuable insights.\n", " [19] It empowers organizations to automate tasks, improve decision-making, enhance customer interactions, and uncover hidden patterns in textual data that would otherwise be impossible to analyze at scale.\n", " [20] Furthermore, NLP is critical for accessibility and inclusion.\n", " [21] By enabling text-to-speech and speech-to-text functionalities, it assists individuals with disabilities in accessing information and communicating more effectively.\n", " [22] It also helps bridge linguistic divides, allowing people from different language backgrounds to interact and share knowledge seamlessly.\n", " [23] The advancements in NLP are largely driven by breakthroughs in machine learning and deep learning, particularly with the advent of transformer models like BERT, GPT, and others.\n", " [24] These models have revolutionized the field, pushing the boundaries of what's possible in language understanding and generation, leading to more accurate translations, more coherent text generation, and more sophisticated conversational AI.\n", " [25] In conclusion, NLP is not just a technological innovation; it's a transformative force that is reshaping how humans interact with technology and each other.\n", " [26] Its continuous evolution promises to unlock even more sophisticated applications, further integrating intelligent language capabilities into every facet of our digital and real-world experiences, making information more accessible and interactions more intuitive.\n", "--------------------------------------------------\n", "\n", "\n", "==================================================\n", " 2. WORD TOKENIZATION\n", "==================================================\n", "\n", "Sentence for Tokenization: 'Natural Language Processing (NLP) is a fascinating and rapidly evolving field at the intersection of computer science, artificial intelligence, and linguistics.'\n", "Tokens: ['Natural', 'Language', 'Processing', '(', 'NLP', ')', 'is', 'a', 'fascinating', 'and', 'rapidly', 'evolving', 'field', 'at', 'the', 'intersection', 'of', 'computer', 'science', ',', 'artificial', 'intelligence', ',', 'and', 'linguistics', '.']\n", "--------------------------------------------------\n", "\n", "\n", "==================================================\n", " 3. STEMMING (Porter Stemmer)\n", "==================================================\n", "\n", "Original Tokens: ['Natural', 'Language', 'Processing', '(', 'NLP', ')', 'is', 'a', 'fascinating', 'and', 'rapidly', 'evolving', 'field', 'at', 'the', 'intersection', 'of', 'computer', 'science', ',', 'artificial', 'intelligence', ',', 'and', 'linguistics', '.']\n", "Stemmed Tokens: ['natur', 'languag', 'process', '(', 'nlp', ')', 'is', 'a', 'fascin', 'and', 'rapidli', 'evolv', 'field', 'at', 'the', 'intersect', 'of', 'comput', 'scienc', ',', 'artifici', 'intellig', ',', 'and', 'linguist', '.']\n", "--------------------------------------------------\n", "\n", "\n", "==================================================\n", " 4. LEMMATIZATION (WordNetLemmatizer)\n", "==================================================\n", "\n", "Original Tokens: ['Natural', 'Language', 'Processing', '(', 'NLP', ')', 'is', 'a', 'fascinating', 'and', 'rapidly', 'evolving', 'field', 'at', 'the', 'intersection', 'of', 'computer', 'science', ',', 'artificial', 'intelligence', ',', 'and', 'linguistics', '.']\n", "Lemmatized Tokens: ['Natural', 'Language', 'Processing', '(', 'NLP', ')', 'is', 'a', 'fascinating', 'and', 'rapidly', 'evolving', 'field', 'at', 'the', 'intersection', 'of', 'computer', 'science', ',', 'artificial', 'intelligence', ',', 'and', 'linguistics', '.']\n", "--------------------------------------------------\n", "\n", "\n", "==================================================\n", " 5. STOP WORD REMOVAL\n", "==================================================\n", "\n", "Original Tokens: ['Natural', 'Language', 'Processing', '(', 'NLP', ')', 'is', 'a', 'fascinating', 'and', 'rapidly', 'evolving', 'field', 'at', 'the', 'intersection', 'of', 'computer', 'science', ',', 'artificial', 'intelligence', ',', 'and', 'linguistics', '.']\n", "Tokens after Stop Word Removal: ['Natural', 'Language', 'Processing', '(', 'NLP', ')', 'fascinating', 'rapidly', 'evolving', 'field', 'intersection', 'computer', 'science', ',', 'artificial', 'intelligence', ',', 'linguistics', '.']\n", "--------------------------------------------------\n", "\n", "\n", "==================================================\n", " 6. DEPENDENCY PARSING (using spaCy)\n", "==================================================\n", "\n", "Sentence for Dependency Parsing: 'Natural Language Processing (NLP) is a fascinating and rapidly evolving field at the intersection of computer science, artificial intelligence, and linguistics.'\n", "\n", "Word Dependency Relation Head Word Head POS \n", "----------------------------------------------------------------------\n", "Natural compound Language PROPN \n", "Language compound Processing PROPN \n", "Processing nsubj is AUX \n", "( punct Processing PROPN \n", "NLP appos Processing PROPN \n", ") punct Processing PROPN \n", "is ROOT is AUX \n", "a det field NOUN \n", "fascinating amod field NOUN \n", "and cc fascinating ADJ \n", "rapidly advmod evolving VERB \n", "evolving conj fascinating ADJ \n", "field attr is AUX \n", "at prep is AUX \n", "the det intersection NOUN \n", "intersection pobj at ADP \n", "of prep intersection NOUN \n", "computer compound science NOUN \n", "science pobj of ADP \n", ", punct science NOUN \n", "artificial amod intelligence NOUN \n", "intelligence conj science NOUN \n", ", punct intelligence NOUN \n", "and cc intelligence NOUN \n", "linguistics conj intelligence NOUN \n", ". punct is AUX \n", "----------------------------------------------------------------------\n", "\n", "\n", "==================================================\n", " 7. PART-OF-SPEECH TAGGING (using spaCy)\n", "==================================================\n", "\n", "Sentence for POS Tagging: 'Natural Language Processing (NLP) is a fascinating and rapidly evolving field at the intersection of computer science, artificial intelligence, and linguistics.'\n", "\n", "Word POS Tag Explanation \n", "-------------------------------------------------------\n", "Natural PROPN proper noun \n", "Language PROPN proper noun \n", "Processing PROPN proper noun \n", "( PUNCT punctuation \n", "NLP PROPN proper noun \n", ") PUNCT punctuation \n", "is AUX auxiliary \n", "a DET determiner \n", "fascinating ADJ adjective \n", "and CCONJ coordinating conjunction \n", "rapidly ADV adverb \n", "evolving VERB verb \n", "field NOUN noun \n", "at ADP adposition \n", "the DET determiner \n", "intersection NOUN noun \n", "of ADP adposition \n", "computer NOUN noun \n", "science NOUN noun \n", ", PUNCT punctuation \n", "artificial ADJ adjective \n", "intelligence NOUN noun \n", ", PUNCT punctuation \n", "and CCONJ coordinating conjunction \n", "linguistics NOUN noun \n", ". PUNCT punctuation \n", "-------------------------------------------------------\n", "\n", "\n", "==================================================\n", " NLP Pipeline Demo Complete!\n", "==================================================\n" ] } ] }, { "cell_type": "markdown", "metadata": { "id": "a9a5ba97" }, "source": [ "### Sentiment Analysis Demonstration" ] }, { "cell_type": "code", "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "343fe3ab", "outputId": "cb3b0f40-ce74-4fda-daae-faeb1765790f" }, "source": [ "from nltk.sentiment.vader import SentimentIntensityAnalyzer\n", "\n", "# --- Sentiment Analysis ---\n", "print(\"=\"*60) # Increased width for new headers\n", "print(\" SENTIMENT ANALYSIS (using NLTK's VADER)\")\n", "print(\"=\"*60) # Increased width for new headers\n", "analyzer_en = SentimentIntensityAnalyzer()\n", "\n", "sentences_for_sentiment_en = [\n", " \"This is a great movie!\",\n", " \"I really disliked that experience.\",\n", " \"The weather is neutral today.\",\n", " \"This product is amazing and I love it!\",\n", " \"It was okay, nothing special.\"\n", "]\n", "\n", "# Print table header with full words\n", "print(\"\\n{:<45} {:>10} {:>10} {:>10} {:>12} {:>12}\".format(\n", " \"Sentence\", \"Negative\", \"Neutral\", \"Positive\", \"Compound\", \"Sentiment\"\n", "))\n", "print(\"-\" * 105) # Adjusted length for new headers and wider columns\n", "\n", "# Analyze and print each sentence in a table row\n", "for sentence in sentences_for_sentiment_en:\n", " vs = analyzer_en.polarity_scores(sentence)\n", " if vs['compound'] >= 0.05:\n", " sentiment = 'Positive'\n", " elif vs['compound'] <= -0.05:\n", " sentiment = 'Negative'\n", " else:\n", " sentiment = 'Neutral'\n", " print(\"{:<45} {:>10.3f} {:>10.3f} {:>10.3f} {:>12.3f} {:>12}\".format( # Adjusted width for numbers\n", " f\"'{sentence}'\",\n", " vs['neg'], vs['neu'], vs['pos'], vs['compound'], sentiment\n", " ))\n", "\n", "print(\"\\n\" + \"=\"*60)\n", "print(\" NLP Pipeline & Sentiment Analysis Demo Complete!\")\n", "print(\"=\"*60)" ], "execution_count": 5, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "============================================================\n", " SENTIMENT ANALYSIS (using NLTK's VADER)\n", "============================================================\n", "\n", "Sentence Negative Neutral Positive Compound Sentiment\n", "---------------------------------------------------------------------------------------------------------\n", "'This is a great movie!' 0.000 0.406 0.594 0.659 Positive\n", "'I really disliked that experience.' 0.499 0.501 0.000 -0.458 Negative\n", "'The weather is neutral today.' 0.000 1.000 0.000 0.000 Neutral\n", "'This product is amazing and I love it!' 0.000 0.376 0.624 0.852 Positive\n", "'It was okay, nothing special.' 0.315 0.419 0.265 -0.092 Negative\n", "\n", "============================================================\n", " NLP Pipeline & Sentiment Analysis Demo Complete!\n", "============================================================\n" ] } ] }, { "cell_type": "markdown", "source": [ "### πŸ˜ƒ What is Sentiment Analysis?\n", "\n", "Sentiment analysis, also known as opinion mining, is a Natural Language Processing (NLP) technique used to determine the **emotional tone** of a piece of text. Its goal is to classify the sentiment expressed in text as positive, negative, or neutral. This technology helps computers understand subjective information, making it incredibly useful for:\n", "\n", " * **Understanding customer feedback:** Analyzing reviews, social media comments, and support tickets to gauge satisfaction.\n", " * **Market research:** Tracking public opinion about products, brands, or political candidates.\n", " * **Brand monitoring:** Identifying mentions of a brand and understanding the sentiment associated with them.\n", " * **Customer service:** Prioritizing urgent or negative feedback.\n", "\n", "\n", "### πŸ› οΈ How Sentiment Analysis Works in our Code (using VADER)\n", "\n", "Our code uses **NLTK's VADER (Valence Aware Dictionary and sEntiment Reasoner)** for sentiment analysis. VADER is a rule-based sentiment analysis model specifically attuned to sentiments expressed in social media contexts. It doesn't rely on training data (like machine learning models) but instead uses a lexicon (a dictionary of words) and a set of rules.\n", "\n", "Here's a breakdown of how it works in oour code:\n", "\n", "#### 1\\. The VADER Lexicon\n", "\n", "VADER comes with a **pre-built lexicon** containing a list of words, each associated with a sentiment score (valence). For example:\n", "\n", " * \"good\" might have a positive score.\n", " * \"bad\" might have a negative score.\n", " * \"amazing\" would have a higher positive score than \"good.\"\n", "\n", "It also considers:\n", "\n", " * **Punctuation:** Exclamation marks (e.g., \"amazing\\!\\!\\!\") increase intensity.\n", " * **Capitalization:** All-caps words (e.g., \"AWFUL\") increase intensity.\n", " * **Degree modifiers (Adverbs):** Words like \"very\" or \"not\" can alter the sentiment of a subsequent word (e.g., \"very good\" is stronger than \"good\"; \"not good\" flips the sentiment).\n", " * **Conjunctions:** Words like \"but\" can shift sentiment focus.\n", "\n", "#### 2\\. The `SentimentIntensityAnalyzer()`\n", "\n", "In oour code:\n", "\n", "```python\n", "analyzer_en = SentimentIntensityAnalyzer()\n", "```\n", "\n", "This line **initializes the VADER sentiment analyzer**. It loads the VADER lexicon and rules, preparing the `analyzer_en` object to process text.\n", "\n", "#### 3\\. Analyzing Sentences with `polarity_scores()`\n", "\n", "For each sentence in your `sentences_for_sentiment_en` list:\n", "\n", "```python\n", "vs = analyzer_en.polarity_scores(sentence)\n", "```\n", "\n", "The `polarity_scores()` method takes a sentence as input and returns a dictionary (`vs`) containing four key scores:\n", "\n", " * **`'neg'` (Negative):** The proportion of text that expresses **negative** sentiment.\n", " * **`'neu'` (Neutral):** The proportion of text that expresses **neutral** sentiment.\n", " * **`'pos'` (Positive):** The proportion of text that expresses **positive** sentiment.\n", " * *Note: The sum of `neg`, `neu`, and `pos` for a sentence will approximately add up to 1.0.*\n", " * **`'compound'` (Compound):** This is the most important score. It's a normalized, weighted composite score ranging from **-1 (most extreme negative)** to **+1 (most extreme positive)**. It's derived by summing the valence scores of each word in the lexicon, adjusting for rules (like intensity boosters or negations), and then normalizing the result.\n", "\n", "#### 4\\. Interpreting the `compound` Score\n", "\n", "Your code then uses the `compound` score to classify the overall sentiment:\n", "\n", "```python\n", "if vs['compound'] >= 0.05:\n", " sentiment = 'Positive'\n", "elif vs['compound'] <= -0.05:\n", " sentiment = 'Negative'\n", "else:\n", " sentiment = 'Neutral'\n", "```\n", "\n", "This logic applies common thresholds for interpreting the `compound` score:\n", "\n", " * If `compound` is **0.05 or greater**, the sentiment is considered **Positive**.\n", " * If `compound` is **-0.05 or less**, the sentiment is considered **Negative**.\n", " * If `compound` is **between -0.05 and 0.05** (exclusive of the bounds), the sentiment is considered **Neutral**.\n", "\n", "This simple yet effective rule-based approach makes VADER a popular choice for quick and relatively accurate sentiment analysis, especially for informal text like social media posts." ], "metadata": { "id": "75mhvP_9S4Lo" } }, { "cell_type": "markdown", "source": [ "## NLP Pipeline (Part Two)" ], "metadata": { "id": "8-9T4A-OTl5P" } }, { "cell_type": "code", "source": [ "# Install required libraries\n", "!pip install nltk spacy transformers sentencepiece --quiet\n", "!python -m spacy download en_core_web_sm" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "VExPAM_hVm5k", "outputId": "1580689d-ff26-4f07-d9f0-96313bc5807b" }, "execution_count": 6, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Collecting en-core-web-sm==3.8.0\n", " Downloading https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.8.0/en_core_web_sm-3.8.0-py3-none-any.whl (12.8 MB)\n", "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m12.8/12.8 MB\u001b[0m \u001b[31m55.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25h\u001b[38;5;2mβœ” Download and installation successful\u001b[0m\n", "You can now load the package via spacy.load('en_core_web_sm')\n", "\u001b[38;5;3m⚠ Restart to reload dependencies\u001b[0m\n", "If you are in a Jupyter or Colab notebook, you may need to restart Python in\n", "order to load all the package's dependencies. You can do this by selecting the\n", "'Restart kernel' or 'Restart runtime' option.\n" ] } ] }, { "cell_type": "code", "source": [ "import nltk\n", "import spacy\n", "nltk.download('punkt')\n", "nltk.download('stopwords')\n", "nltk.download('wordnet')\n", "nltk.download('averaged_perceptron_tagger')\n", "nltk.download('vader_lexicon')" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "0I5io_qWVnMg", "outputId": "9093102a-de9b-4054-d2e9-2bd3022631cf" }, "execution_count": 2, "outputs": [ { "output_type": "stream", "name": "stderr", "text": [ "[nltk_data] Downloading package punkt to /root/nltk_data...\n", "[nltk_data] Package punkt is already up-to-date!\n", "[nltk_data] Downloading package stopwords to /root/nltk_data...\n", "[nltk_data] Package stopwords is already up-to-date!\n", "[nltk_data] Downloading package wordnet to /root/nltk_data...\n", "[nltk_data] Package wordnet is already up-to-date!\n", "[nltk_data] Downloading package averaged_perceptron_tagger to\n", "[nltk_data] /root/nltk_data...\n", "[nltk_data] Package averaged_perceptron_tagger is already up-to-\n", "[nltk_data] date!\n", "[nltk_data] Downloading package vader_lexicon to /root/nltk_data...\n", "[nltk_data] Package vader_lexicon is already up-to-date!\n" ] }, { "output_type": "execute_result", "data": { "text/plain": [ "True" ] }, "metadata": {}, "execution_count": 2 } ] }, { "cell_type": "markdown", "source": [ "2. NLP Pipeline Steps\n", "\n", " 2.1. Sentence Segmentation" ], "metadata": { "id": "2VvjnJjvVzkr" } }, { "cell_type": "code", "source": [ "from nltk.tokenize import sent_tokenize\n", "\n", "text = \"Natural Language Processing is fascinating. It enables computers to understand human language!\"\n", "\n", "sentences = sent_tokenize(text)\n", "print(\"Sentence Segmentation:\", sentences)" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "5hlX2ilrVviA", "outputId": "6fc7284c-ba2a-45f3-d20d-db7c028471d8" }, "execution_count": 3, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Sentence Segmentation: ['Natural Language Processing is fascinating.', 'It enables computers to understand human language!']\n" ] } ] }, { "cell_type": "markdown", "source": [ "2.2. Word Tokenization" ], "metadata": { "id": "0dltR_hIV8rS" } }, { "cell_type": "code", "source": [ "from nltk.tokenize import word_tokenize\n", "\n", "tokens = word_tokenize(text)\n", "print(\"Word Tokens:\", tokens)" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "L4NAcXGGV4q9", "outputId": "4b1f2b61-03aa-4757-fd8d-df86e46a217b" }, "execution_count": 4, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Word Tokens: ['Natural', 'Language', 'Processing', 'is', 'fascinating', '.', 'It', 'enables', 'computers', 'to', 'understand', 'human', 'language', '!']\n" ] } ] }, { "cell_type": "markdown", "source": [ "2.3 Stemming" ], "metadata": { "id": "3LyiR8XcWCBh" } }, { "cell_type": "code", "source": [ "from nltk.stem import PorterStemmer\n", "\n", "stemmer = PorterStemmer()\n", "stems = [stemmer.stem(token) for token in tokens]\n", "print(\"Stems:\", stems)" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "q4-hPHXvV_e3", "outputId": "5b8adead-be41-41f8-9715-aa70f7360ed0" }, "execution_count": 5, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Stems: ['natur', 'languag', 'process', 'is', 'fascin', '.', 'it', 'enabl', 'comput', 'to', 'understand', 'human', 'languag', '!']\n" ] } ] }, { "cell_type": "markdown", "source": [ "2.4 Lemmatization" ], "metadata": { "id": "EFMk66vjWGiT" } }, { "cell_type": "code", "source": [ "from nltk.stem import WordNetLemmatizer\n", "\n", "lemmatizer = WordNetLemmatizer()\n", "lemmas = [lemmatizer.lemmatize(token) for token in tokens]\n", "print(\"Lemmas:\", lemmas)" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "SHbByxuBWDu2", "outputId": "89087832-c6df-4033-f67b-3356d675bf48" }, "execution_count": 6, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Lemmas: ['Natural', 'Language', 'Processing', 'is', 'fascinating', '.', 'It', 'enables', 'computer', 'to', 'understand', 'human', 'language', '!']\n" ] } ] }, { "cell_type": "markdown", "source": [ "2.5 Stop Words Removal" ], "metadata": { "id": "62aKLv4cWK4l" } }, { "cell_type": "code", "source": [ "from nltk.corpus import stopwords\n", "\n", "stop_words = set(stopwords.words('english'))\n", "filtered_tokens = [token for token in tokens if token.lower() not in stop_words]\n", "print(\"Tokens after Stop Word Removal:\", filtered_tokens)" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "HGsGcS97WIc8", "outputId": "5d572f5c-461c-4f69-e08d-2c7ae3445d1f" }, "execution_count": 7, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Tokens after Stop Word Removal: ['Natural', 'Language', 'Processing', 'fascinating', '.', 'enables', 'computers', 'understand', 'human', 'language', '!']\n" ] } ] }, { "cell_type": "markdown", "source": [ "2.6. Dependency Parsing" ], "metadata": { "id": "l6cvxTbqWRTL" } }, { "cell_type": "code", "source": [ "nlp = spacy.load(\"en_core_web_sm\")\n", "doc = nlp(text)\n", "\n", "print(\"Dependency Parsing:\")\n", "for token in doc:\n", " print(f\"\\n{token.text} --> {token.dep_} --> {token.head.text}\")" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "AGWREIQ5WOOp", "outputId": "2ea03a79-1180-41ea-d7cc-555f2388cac3" }, "execution_count": 8, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Dependency Parsing:\n", "\n", "Natural --> compound --> Language\n", "\n", "Language --> compound --> Processing\n", "\n", "Processing --> nsubj --> is\n", "\n", "is --> ROOT --> is\n", "\n", "fascinating --> acomp --> is\n", "\n", ". --> punct --> is\n", "\n", "It --> nsubj --> enables\n", "\n", "enables --> ROOT --> enables\n", "\n", "computers --> nsubj --> understand\n", "\n", "to --> aux --> understand\n", "\n", "understand --> ccomp --> enables\n", "\n", "human --> amod --> language\n", "\n", "language --> dobj --> understand\n", "\n", "! --> punct --> enables\n" ] } ] }, { "cell_type": "markdown", "source": [ "2.7 Parts of Speech Tagging" ], "metadata": { "id": "Pzgbg8UwWumt" } }, { "cell_type": "code", "source": [ "print(\"Part-of-Speech Tagging:\\n\")\n", "for token in doc:\n", " print(f\"{token.text} --> {token.pos_}\")" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "-JN5V8haWT0S", "outputId": "236d32ba-4f5d-4e5f-ff3b-853eaa0fce40" }, "execution_count": 9, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Part-of-Speech Tagging:\n", "\n", "Natural --> PROPN\n", "Language --> PROPN\n", "Processing --> NOUN\n", "is --> AUX\n", "fascinating --> ADJ\n", ". --> PUNCT\n", "It --> PRON\n", "enables --> VERB\n", "computers --> NOUN\n", "to --> PART\n", "understand --> VERB\n", "human --> ADJ\n", "language --> NOUN\n", "! --> PUNCT\n" ] } ] }, { "cell_type": "markdown", "source": [ "3. Sentiment Analysis with NLTK's VADER" ], "metadata": { "id": "Ltd-DcosW_ix" } }, { "cell_type": "code", "source": [ "from nltk.sentiment import SentimentIntensityAnalyzer\n", "\n", "sia = SentimentIntensityAnalyzer()\n", "sentiment = sia.polarity_scores(text)\n", "print(\"VADER Sentiment Scores:\", sentiment)" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "qkuhRYrOW0jV", "outputId": "cac8f9b7-34d5-4cff-ea97-a257c1458722" }, "execution_count": 10, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "VADER Sentiment Scores: {'neg': 0.0, 'neu': 0.614, 'pos': 0.386, 'compound': 0.7424}\n" ] } ] }, { "cell_type": "markdown", "source": [ "4. Translation using Huggingface Transformers" ], "metadata": { "id": "AIVJfTwCXJXM" } }, { "cell_type": "code", "source": [ "from transformers import pipeline\n", "\n", "# English to French translation\n", "translator_fr = pipeline(\"translation_en_to_fr\", model=\"Helsinki-NLP/opus-mt-en-fr\")\n", "translation = translator_fr(text)\n", "print(\"\\n\\nTranslation (EN->FR):\", translation[0]['translation_text'])\n", "\n", "print(\"\\n\\n\")" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "FaKMSZ7IXE5i", "outputId": "aeb55cc3-cdd0-4242-b464-bbf2a603368e" }, "execution_count": 11, "outputs": [ { "output_type": "stream", "name": "stderr", "text": [ "/usr/local/lib/python3.11/dist-packages/transformers/models/marian/tokenization_marian.py:175: UserWarning: Recommended: pip install sacremoses.\n", " warnings.warn(\"Recommended: pip install sacremoses.\")\n", "Device set to use cpu\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "\n", "\n", "Translation (EN->FR): Le traitement du langage naturel est fascinant. Il permet aux ordinateurs de comprendre le langage humain!\n", "\n", "\n", "\n" ] } ] }, { "cell_type": "markdown", "source": [ "5. Text Generation Model Creation (Word-LSTM Model)" ], "metadata": { "id": "VeqTijUvXURn" } }, { "cell_type": "code", "source": [ "!pip install --upgrade datasets gcsfs fsspec --quiet" ], "metadata": { "id": "xGyym_LsgNrj" }, "execution_count": 7, "outputs": [] }, { "cell_type": "code", "source": [ "# Imports, setting up devices and seed\n", "# !pip install datasets tqdm --quiet\n", "\n", "import torch\n", "import torch.nn as nn\n", "import torch.optim as optim\n", "import numpy as np\n", "from tqdm import tqdm\n", "from datasets import load_dataset\n", "import re\n", "import os\n", "import matplotlib.pyplot as plt\n", "from collections import Counter\n", "from sklearn.model_selection import train_test_split\n", "\n", "torch.manual_seed(42)\n", "np.random.seed(42)\n", "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n", "print(\"Using device:\", device)" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "8ETP7K3geUEN", "outputId": "f80f7c93-a3d3-4b0c-d520-a23d256776f2" }, "execution_count": 1, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Using device: cuda\n" ] } ] }, { "cell_type": "code", "source": [ "# Load 10% of dataset and tokenize\n", "\n", "ds = load_dataset(\"nirajandhakal/Mahabharata-HHGTTG-Text\", split=\"train[:90%]\")\n", "corpus = \" \".join(ds['text'])\n", "\n", "def tokenize(text):\n", " # Split on whitespace and punctuation\n", " return re.findall(r\"\\b\\w+\\b|[^\\w\\s]\", text.lower())\n", "\n", "tokens = tokenize(corpus)\n", "print(f\"Number of tokens: {len(tokens)}\")\n", "print(\"Sample tokens:\", tokens[:20])" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "vKBU1auceYXm", "outputId": "4984aacc-b077-426f-b966-9e5938556d60" }, "execution_count": 22, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Number of tokens: 3634450\n", "Sample tokens: ['the', 'epicurean', 'paradox', 'the', 'epicurean', 'paradox', 'is', 'a', 'philosophical', 'argument', 'that', 'has', 'intrigued', 'thinkers', 'for', 'centuries', '.', 'it', 'is', 'an']\n" ] } ] }, { "cell_type": "code", "source": [ "# Build vocabulary and Encode\n", "vocab_size = 10000\n", "most_common = Counter(tokens).most_common(vocab_size-2)\n", "vocab = [w for w, _ in most_common]\n", "word2idx = {w: i+2 for i, w in enumerate(vocab)}\n", "word2idx[\"\"] = 0\n", "word2idx[\"\"] = 1\n", "idx2word = {i: w for w, i in word2idx.items()}\n", "\n", "# Encode tokens\n", "encoded = [word2idx.get(w, 1) for w in tokens] # 1 is \n", "print(f\"Vocabulary size: {len(word2idx)}\")" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "75flr-GKec1H", "outputId": "555722ca-8a85-4155-9bb3-89126f63b1f8" }, "execution_count": 3, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Vocabulary size: 10000\n" ] } ] }, { "cell_type": "code", "source": [ "# Prepare data for training\n", "\n", "seq_length = 15 # Longer context for better quality\n", "step = 1 # More overlap, more data, better quality\n", "\n", "sequences = []\n", "next_words = []\n", "for i in range(0, len(encoded) - seq_length, step):\n", " sequences.append(encoded[i:i+seq_length])\n", " next_words.append(encoded[i+seq_length])\n", "\n", "X = np.array(sequences, dtype=np.int32)\n", "y = np.array(next_words, dtype=np.int32)\n", "\n", "# Train/validation split\n", "X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.1, random_state=42)\n", "\n", "print(f\"Train samples: {len(X_train)}, Val samples: {len(X_val)}\")\n", "\n", "from torch.utils.data import TensorDataset, DataLoader\n", "\n", "batch_size = 256\n", "train_dataset = TensorDataset(torch.tensor(X_train, dtype=torch.long), torch.tensor(y_train, dtype=torch.long))\n", "val_dataset = TensorDataset(torch.tensor(X_val, dtype=torch.long), torch.tensor(y_val, dtype=torch.long))\n", "train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\n", "val_loader = DataLoader(val_dataset, batch_size=batch_size)" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "lkhqyVW2esLf", "outputId": "8bfec172-9e2d-4ee2-e01a-69aa2d5447bf" }, "execution_count": 6, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Train samples: 391758, Val samples: 43529\n" ] } ] }, { "cell_type": "code", "source": [ "# Define the Model\n", "\n", "class WordLSTM(nn.Module):\n", " def __init__(self, vocab_size, embed_size, hidden_size, num_layers=3, dropout=0.3):\n", " super().__init__()\n", " self.embedding = nn.Embedding(vocab_size, embed_size, padding_idx=0)\n", " self.lstm = nn.LSTM(embed_size, hidden_size, num_layers, batch_first=True, dropout=dropout)\n", " self.fc = nn.Linear(hidden_size, vocab_size)\n", " def forward(self, x, hidden=None):\n", " x = self.embedding(x)\n", " out, hidden = self.lstm(x, hidden)\n", " out = self.fc(out[:, -1, :])\n", " return out, hidden\n", "\n", "embed_size = 256\n", "hidden_size = 512\n", "num_layers = 3\n", "dropout = 0.3\n", "\n", "model = WordLSTM(len(word2idx), embed_size, hidden_size, num_layers, dropout).to(device)\n", "loss_fn = nn.CrossEntropyLoss()\n", "optimizer = optim.Adam(model.parameters(), lr=0.002)" ], "metadata": { "id": "VdxeA4U7evTC" }, "execution_count": 7, "outputs": [] }, { "cell_type": "code", "source": [ "# Train the model and plot the loss\n", "\n", "epochs = 10 # Increase for better quality\n", "train_losses, val_losses = [], []\n", "train_accuracies, val_accuracies = [], []\n", "\n", "def accuracy(preds, targets):\n", " return (preds.argmax(dim=1) == targets).float().mean().item()\n", "\n", "for epoch in range(epochs):\n", " model.train()\n", " total_loss, total_acc, total_count = 0, 0, 0\n", " for xb, yb in tqdm(train_loader, desc=f\"Train Epoch {epoch+1}/{epochs}\"):\n", " xb, yb = xb.to(device), yb.to(device)\n", " optimizer.zero_grad()\n", " output, _ = model(xb)\n", " loss = loss_fn(output, yb)\n", " loss.backward()\n", " optimizer.step()\n", " total_loss += loss.item() * xb.size(0)\n", " total_acc += accuracy(output, yb) * xb.size(0)\n", " total_count += xb.size(0)\n", " avg_loss = total_loss / total_count\n", " avg_acc = total_acc / total_count\n", " train_losses.append(avg_loss)\n", " train_accuracies.append(avg_acc)\n", "\n", " # Validation\n", " model.eval()\n", " val_loss, val_acc, val_count = 0, 0, 0\n", " with torch.no_grad():\n", " for xb, yb in val_loader:\n", " xb, yb = xb.to(device), yb.to(device)\n", " output, _ = model(xb)\n", " loss = loss_fn(output, yb)\n", " val_loss += loss.item() * xb.size(0)\n", " val_acc += accuracy(output, yb) * xb.size(0)\n", " val_count += xb.size(0)\n", " val_losses.append(val_loss / val_count)\n", " val_accuracies.append(val_acc / val_count)\n", " print(f\"Epoch {epoch+1}: Train Loss={avg_loss:.4f}, Val Loss={val_losses[-1]:.4f}, Train Acc={avg_acc:.4f}, Val Acc={val_accuracies[-1]:.4f}\")" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "08g9D-RlfAVt", "outputId": "7f0a6668-54bb-4ef1-d680-248be4285512" }, "execution_count": 8, "outputs": [ { "output_type": "stream", "name": "stderr", "text": [ "Train Epoch 1/10: 100%|β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ| 1531/1531 [01:16<00:00, 20.14it/s]\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "Epoch 1: Train Loss=6.3144, Val Loss=6.2408, Train Acc=0.0783, Val Acc=0.0786\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "Train Epoch 2/10: 100%|β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ| 1531/1531 [01:17<00:00, 19.84it/s]\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "Epoch 2: Train Loss=6.1643, Val Loss=5.7447, Train Acc=0.0869, Val Acc=0.1387\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "Train Epoch 3/10: 100%|β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ| 1531/1531 [01:17<00:00, 19.65it/s]\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "Epoch 3: Train Loss=5.2669, Val Loss=4.9505, Train Acc=0.1835, Val Acc=0.2157\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "Train Epoch 4/10: 100%|β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ| 1531/1531 [01:18<00:00, 19.56it/s]\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "Epoch 4: Train Loss=4.6935, Val Loss=4.7041, Train Acc=0.2291, Val Acc=0.2411\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "Train Epoch 5/10: 100%|β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ| 1531/1531 [01:17<00:00, 19.73it/s]\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "Epoch 5: Train Loss=4.3577, Val Loss=4.5889, Train Acc=0.2505, Val Acc=0.2542\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "Train Epoch 6/10: 100%|β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ| 1531/1531 [01:17<00:00, 19.68it/s]\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "Epoch 6: Train Loss=4.1002, Val Loss=4.5632, Train Acc=0.2639, Val Acc=0.2616\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "Train Epoch 7/10: 100%|β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ| 1531/1531 [01:18<00:00, 19.58it/s]\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "Epoch 7: Train Loss=3.8865, Val Loss=4.5903, Train Acc=0.2751, Val Acc=0.2651\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "Train Epoch 8/10: 100%|β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ| 1531/1531 [01:17<00:00, 19.68it/s]\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "Epoch 8: Train Loss=3.7002, Val Loss=4.6680, Train Acc=0.2864, Val Acc=0.2686\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "Train Epoch 9/10: 100%|β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ| 1531/1531 [01:17<00:00, 19.75it/s]\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "Epoch 9: Train Loss=3.5370, Val Loss=4.7425, Train Acc=0.2969, Val Acc=0.2683\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "Train Epoch 10/10: 100%|β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ| 1531/1531 [01:17<00:00, 19.71it/s]\n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "Epoch 10: Train Loss=3.3925, Val Loss=4.8263, Train Acc=0.3082, Val Acc=0.2688\n" ] } ] }, { "cell_type": "code", "source": [ "print(model)" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "IXtEKalQjAEG", "outputId": "4628b64f-b075-4f88-8efd-e95cd2a87067" }, "execution_count": 9, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "WordLSTM(\n", " (embedding): Embedding(10000, 256, padding_idx=0)\n", " (lstm): LSTM(256, 512, num_layers=3, batch_first=True, dropout=0.3)\n", " (fc): Linear(in_features=512, out_features=10000, bias=True)\n", ")\n" ] } ] }, { "cell_type": "code", "source": [ "# Plot Training and Validation Curves\n", "\n", "plt.figure(figsize=(12,5))\n", "plt.subplot(1,2,1)\n", "plt.plot(train_losses, label='Train Loss')\n", "plt.plot(val_losses, label='Val Loss')\n", "plt.xlabel('Epoch')\n", "plt.ylabel('Loss')\n", "plt.title('Loss Curve')\n", "plt.legend()\n", "plt.grid(True)\n", "\n", "plt.subplot(1,2,2)\n", "plt.plot(train_accuracies, label='Train Acc')\n", "plt.plot(val_accuracies, label='Val Acc')\n", "plt.xlabel('Epoch')\n", "plt.ylabel('Accuracy')\n", "plt.title('Accuracy Curve')\n", "plt.legend()\n", "plt.grid(True)\n", "\n", "plt.tight_layout()\n", "plt.show()" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 507 }, "id": "vHm3p94_hDm5", "outputId": "308aa0f2-63aa-4ff4-9f77-7d02843bbede" }, "execution_count": 10, "outputs": [ { "output_type": "display_data", "data": { "text/plain": [ "
" ], "image/png": "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/cSiRYt45ZVXGD9+PEuXLqVevXqXrbdSpUo4OzuzdevWfMVxpW8j//mN5z+5ublhNl+a97/tttuoUKECs2fP5u677+aXX37h/Pnztm/hACwWC2CdVyooKOiSOux5YSoiIiL2s3TpUhITE5k5cyYzZ868ZPu0adPo1KmTXdu0xzVKbm4uHTt25NSpUzz//PNUq1aNEiVKcPToUQYPHmy7NrkWAwcO5IknnuDIkSNkZmby119/8X//939XfV21atXYtGkTWVlZuLq6XnO7F1zp+P85IuwCNzc3evTowdy5c/nf//5HcnIyK1as4M0337Ttc+E9eOaZZ4iKirps3VdLuInIpfTJRkQKXUBAAJ6enuzevfuSbbt27cJsNhMWFmYrK1WqFPfffz/3338/Z8+epVWrVowdO9aWlAKIiIjg6aef5umnn2bv3r3UrVuX999/n+++++6yMXh6etKuXTuWLl3K4cOH87R3OX5+foB1lZx/OnToUH4P26Zv37589NFHpKamMmvWLCpUqMBtt92W51gAypQpQ4cOHa65fhEREXGMadOmUaZMGT799NNLts2ZM4e5c+cyadIkPDw8iIiIyLOq2+VERESwevVqsrOzcXFxuew+9rhG2bp1K3v27GHq1KkMHDjQVv7P1Y4B27QLV4sboH///owcOZIZM2Zw/vx5XFxc8nwJdyXdu3dn1apV/PjjjwwYMOCq+/v5+V1y7FlZWSQmJl71tf/Ur18/pk6dSkxMDDt37sQwjDzxXjh2FxcXXZ+J2JFu3xORQufk5ESnTp34+eefOXjwoK08OTmZ6dOn06JFC9vtdSdPnszzWi8vLypVqkRmZiZgXbkuIyMjzz4RERF4e3vb9rmSMWPGYBgG9913X545ni5Yv349U6dOBaB8+fI4OTmxfPnyPPv873//y99B/0O/fv3IzMxk6tSpLFy4kL59++bZHhUVhY+PD2+++SbZ2dmXvP748ePX3KaIiIgUrPPnzzNnzhy6detG7969L/kZMWIEaWlptlv4e/XqxebNm5k7d+4ldRmGYdvnxIkTlx1hdGEfe1yjXJhj6UKdFx5/9NFHefYLCAigVatWTJ48mfj4+MvGc4G/vz9dunThu+++Y9q0aXTu3Bl/f/+rxjJ8+HCCg4N5+umn2bNnzyXbjx07xuuvv257HhERccmxf/7551ccKXUlHTp0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fewiIiJyXpSUEhEREcP4+1gYFB/DoPgY8opKmb3BnqBatD2X9fvyWL8vj3GzNtOhfiiDE2K4unU0tYN8jQ5bXMAyfzxmWwmFEe2ZdqgViz9fyfKdBzlWXLk4eVSwH92ahNOtSRhdG4cTFeJnUMQiIiJyoZSUEhEREbcQ7OfNje3rcmP7uhwqKOGXtExmpO5nxe5DrNxzmJV7DjN2xga6Ng7nrq4N6BsXaXTI4iR7NqYQm/olALdnDGZ1+qaK10L8venSKMyehGoSTqPwQNUhExER8VBKSomIiIjbqRXow+2d63N75/pkHS3i5xMJqrUZR1i0PZfLLwsHlJSqqmw2K2utjci2hbLB0pweDWvRtbF9NVTLmBAsZiWhREREqgIlpURERMStRYX4cU/3htzTvSHpBwuZsW4/gxNijA5LnKh+XCd+6P4Fpv2prLq5FzUCtCVPRESkKtI9cEVERMRj1AsLYGSvJkSHqPB5VWYymRjZqzENQv3w1d3yREREqiwlpURERERERERExOWUlBIREREREREREZdTUkpERERERERERFxOSSkREREREREREXE5JaVERERERERERMTllJQSERERERERERGXU1JKRERERERERERcTkkpERERERERERFxOSWlRERERERERETE5ZSUEhERERERERERl1NSSkREREREREREXE5JKRERERERERERcTklpURERERERERExOWUlBIREREREREREZdTUkpERERERERERFzOy+gAXM1mswGQl5fnlPZLS0spLCwkLy8Pb29vp/Qhl0Zj5Bk0Tu5PY+QZNE4X5uT84OR8Qc5McyrRGHkGjZP70xh5Bo3ThTnfOVW1S0odO3YMgNjYWIMjEREREXd17NgxQkJCjA7DrWlOJSIiIudyrjmVyVbNPgq0Wq3s37+foKAgTCaTw9vPy8sjNjaWjIwMgoODHd6+XDqNkWfQOLk/jZFn0DhdGJvNxrFjx4iJicFsVpWDs9GcSjRGnkHj5P40Rp5B43RhzndOVe1WSpnNZurWrev0foKDg/UX1c1pjDyDxsn9aYw8g8bp/GmF1PnRnEpO0hh5Bo2T+9MYeQaN0/k7nzmVPgIUERERERERERGXU1JKRERERERERERcTkkpB/P19eW5557D19fX6FDkDDRGnkHj5P40Rp5B4ySeSn933Z/GyDNonNyfxsgzaJyco9oVOhcREREREREREeNppZSIiIiIiIiIiLicklIiIiIiIiIiIuJySkqJiIiIiIiIiIjLKSnlQO+99x4NGjTAz8+PxMREVqxYYXRI8ifjxo2jY8eOBAUFERERwZAhQ9iyZYvRYclZjB8/HpPJxMMPP2x0KPIX+/bt4/bbbycsLAx/f39at27NypUrjQ5LTigvL+eZZ56hYcOG+Pv707hxY1588UVURlI8heZU7k1zKs+jOZX70pzKvWlO5XxKSjnItGnTGDNmDM899xyrV68mISGBq666ipycHKNDkxPmz5/PyJEjWbZsGUlJSZSWlnLllVdSUFBgdGhyGikpKUyePJn4+HijQ5G/OHz4MN26dcPb25tZs2axceNG3nzzTUJDQ40OTU549dVXmTRpEhMnTmTTpk28+uqrvPbaa/znP/8xOjSRc9Kcyv1pTuVZNKdyX5pTuT/NqZxPd99zkMTERDp27MjEiRMBsFqtxMbG8uCDD/Lkk08aHJ2czoEDB4iIiGD+/PlcfvnlRocjf5Kfn0+7du14//33eemll2jTpg0TJkwwOiw54cknn2Tx4sUsXLjQ6FDkDAYNGkRkZCRTpkypOHfDDTfg7+/P//3f/xkYmci5aU7leTSncl+aU7k3zancn+ZUzqeVUg5QUlLCqlWr6Nu3b8U5s9lM3759Wbp0qYGRydkcPXoUgFq1ahkcifzVyJEjGThwYKV/U+I+fvrpJzp06MBNN91EREQEbdu25aOPPjI6LPmTrl27kpyczNatWwFITU1l0aJFDBgwwODIRM5OcyrPpDmV+9Kcyr1pTuX+NKdyPi+jA6gKcnNzKS8vJzIystL5yMhINm/ebFBUcjZWq5WHH36Ybt260apVK6PDkT/56quvWL16NSkpKUaHImewc+dOJk2axJgxY/jXv/5FSkoKDz30ED4+PgwfPtzo8AT7J695eXk0b94ci8VCeXk5L7/8MsOGDTM6NJGz0pzK82hO5b40p3J/mlO5P82pnE9JKamWRo4cyfr161m0aJHRocifZGRkMHr0aJKSkvDz8zM6HDkDq9VKhw4deOWVVwBo27Yt69ev54MPPtAEyk18/fXXfPHFF0ydOpWWLVuydu1aHn74YWJiYjRGIuJQmlO5J82pPIPmVO5PcyrnU1LKAcLDw7FYLGRnZ1c6n52dTVRUlEFRyZmMGjWKmTNnsmDBAurWrWt0OPInq1atIicnh3bt2lWcKy8vZ8GCBUycOJHi4mIsFouBEQpAdHQ0cXFxlc61aNGC7777zqCI5K8ef/xxnnzySYYOHQpA69at2bNnD+PGjdMEStya5lSeRXMq96U5lWfQnMr9aU7lfKop5QA+Pj60b9+e5OTkinNWq5Xk5GS6dOliYGTyZzabjVGjRjF9+nR+//13GjZsaHRI8hd9+vQhLS2NtWvXVjw6dOjAsGHDWLt2rSZPbqJbt26n3Pp769at1K9f36CI5K8KCwsxmyv/iLdYLFitVoMiEjk/mlN5Bs2p3J/mVJ5Bcyr3pzmV82mllIOMGTOG4cOH06FDBzp16sSECRMoKChgxIgRRocmJ4wcOZKpU6fy448/EhQURFZWFgAhISH4+/sbHJ0ABAUFnVKPIjAwkLCwMNWpcCOPPPIIXbt25ZVXXuHmm29mxYoVfPjhh3z44YdGhyYnDB48mJdffpl69erRsmVL1qxZw1tvvcXdd99tdGgi56Q5lfvTnMr9aU7lGTSncn+aUzmfyWaz2YwOoqqYOHEir7/+OllZWbRp04Z3332XxMREo8OSE0wm02nPf/rpp9x1112uDUbO2xVXXKHbF7uhmTNn8tRTT7Ft2zYaNmzImDFjuO+++4wOS044duwYzzzzDNOnTycnJ4eYmBhuvfVWnn32WXx8fIwOT+ScNKdyb5pTeSbNqdyT5lTuTXMq51NSSkREREREREREXE41pURERERERERExOWUlBIREREREREREZdTUkpERERERERERFxOSSkREREREREREXE5JaVERERERERERMTllJQSERERERERERGXU1JKRERERERERERcTkkpERERERERERFxOSWlREQugslk4ocffjA6DBERERGPpjmVSPWmpJSIeJy77roLk8l0yqN///5GhyYiIiLiMTSnEhGjeRkdgIjIxejfvz+ffvpppXO+vr4GRSMiIiLimTSnEhEjaaWUiHgkX19foqKiKj1CQ0MB+zLwSZMmMWDAAPz9/WnUqBHffvttpe9PS0ujd+/e+Pv7ExYWxv33309+fn6laz755BNatmyJr68v0dHRjBo1qtLrubm5XHfddQQEBNC0aVN++ukn575pEREREQfTnEpEjKSklIhUSc888ww33HADqampDBs2jKFDh7Jp0yYACgoKuOqqqwgNDSUlJYVvvvmGOXPmVJogTZo0iZEjR3L//feTlpbGTz/9RJMmTSr1MXbsWG6++WbWrVvH1VdfzbBhwzh06JBL36eIiIiIM2lOJSJOZRMR8TDDhw+3WSwWW2BgYKXHyy+/bLPZbDbA9ve//73S9yQmJtoeeOABm81ms3344Ye20NBQW35+fsXrP//8s81sNtuysrJsNpvNFhMTY3v66afPGANg+/e//13xPD8/3wbYZs2a5bD3KSIiIuJMmlOJiNFUU0pEPFKvXr2YNGlSpXO1atWqOO7SpUul17p06cLatWsB2LRpEwkJCQQGBla83q1bN6xWK1u2bMFkMrF//3769Olz1hji4+MrjgMDAwkODiYnJ+di35KIiIiIy2lOJSJGUlJKRDxSYGDgKUu/HcXf3/+8rvP29q703GQyYbVanRGSiIiIiFNoTiUiRlJNKRGpkpYtW3bK8xYtWgDQokULUlNTKSgoqHh98eLFmM1mmjVrRlBQEA0aNCA5OdmlMYuIiIi4G82pRMSZtFJKRDxScXExWVlZlc55eXkRHh4OwDfffEOHDh3o3r07X3zxBStWrGDKlCkADBs2jOeee47hw4fz/PPPc+DAAR588EHuuOMOIiMjAXj++ef5+9//TkREBAMGDODYsWMsXryYBx980LVvVERERMSJNKcSESMpKSUiHunXX38lOjq60rlmzZqxefNmwH4Xl6+++op//OMfREdH8+WXXxIXFwdAQEAAv/32G6NHj6Zjx44EBARwww038NZbb1W0NXz4cIqKinj77bd57LHHCA8P58Ybb3TdGxQRERFxAc2pRMRIJpvNZjM6CBERRzKZTEyfPp0hQ4YYHYqIiIiIx9KcSkScTTWlRERERERERETE5ZSUEhERERERERERl9P2PRERERERERERcTmtlBIREREREREREZdTUkpERERERERERFxOSSkREREREREREXE5JaVERERERERERMTllJQSERERERERERGXU1JKRERERERERERcTkkpERERERERERFxOSWlRERERERERETE5ZSUEhERERERERERl/t/f8OJ7Y2JKscAAAAASUVORK5CYII=\n" }, "metadata": {} } ] }, { "cell_type": "code", "source": [ "# Save the model\n", "\n", "save_path = \"word_lstm_standard.pth\"\n", "torch.save({\n", " 'model_state_dict': model.state_dict(),\n", " 'word2idx': word2idx,\n", " 'idx2word': idx2word,\n", " 'vocab_size': len(word2idx),\n", " 'embed_size': embed_size,\n", " 'hidden_size': hidden_size,\n", " 'num_layers': num_layers,\n", " 'dropout': dropout,\n", " 'seq_length': seq_length\n", "}, save_path)\n", "print(f\"Model saved to {save_path}\")" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "ejY0IN1QfFz4", "outputId": "5b48210a-4a1f-4954-a0f9-e0c50f701ee7" }, "execution_count": 11, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Model saved to word_lstm_standard.pth\n" ] } ] }, { "cell_type": "code", "source": [ "# Load the Model\n", "\n", "def load_model(path):\n", " checkpoint = torch.load(path, map_location=device)\n", " model = WordLSTM(\n", " checkpoint['vocab_size'],\n", " checkpoint['embed_size'],\n", " checkpoint['hidden_size'],\n", " checkpoint['num_layers'],\n", " checkpoint['dropout']\n", " ).to(device)\n", " model.load_state_dict(checkpoint['model_state_dict'])\n", " model.eval()\n", " return model, checkpoint['word2idx'], checkpoint['idx2word'], checkpoint['seq_length']\n", "\n", "loaded_model, loaded_word2idx, loaded_idx2word, loaded_seq_length = load_model(save_path)\n", "print(\"Model loaded!\")" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "Za9zPxsLfTAq", "outputId": "52a645fc-8a56-44da-aba1-da290dc76946" }, "execution_count": 12, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Model loaded!\n" ] } ] }, { "cell_type": "code", "source": [ "# Generate Text\n", "\n", "def tokenize(text):\n", " return re.findall(r\"\\b\\w+\\b|[^\\w\\s]\", text.lower())\n", "\n", "def generate_text(model, word2idx, idx2word, seq_length, seed, length=40, temperature=1.0):\n", " model.eval()\n", " seed_tokens = tokenize(seed.lower())\n", " seed_encoded = [word2idx.get(w, 1) for w in seed_tokens]\n", " if len(seed_encoded) < seq_length:\n", " seed_encoded = [0]*(seq_length-len(seed_encoded)) + seed_encoded\n", " else:\n", " seed_encoded = seed_encoded[-seq_length:]\n", " generated = seed_tokens.copy()\n", " inp = torch.tensor([seed_encoded], dtype=torch.long, device=device)\n", " hidden = None\n", " for _ in range(length):\n", " out, hidden = model(inp, hidden)\n", " out = out[0].detach().cpu().numpy()\n", " out = out / temperature\n", " exp_out = np.exp(out - np.max(out))\n", " probs = exp_out / np.sum(exp_out)\n", " idx = np.random.choice(range(len(idx2word)), p=probs)\n", " next_word = idx2word.get(idx, \"\")\n", " generated.append(next_word)\n", " inp = torch.cat([inp[:, 1:], torch.tensor([[idx]], device=device)], dim=1)\n", " return \" \".join(generated)\n", "\n", "seed_text = \"The universe is such a place where Krishna is the creator\"\n", "print(\"Generated text (temperature=0.5):\\n\")\n", "print(generate_text(loaded_model, loaded_word2idx, loaded_idx2word, loaded_seq_length, seed_text, length=100, temperature=0.2))" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "ek3K3dBLfXzW", "outputId": "d05d7b63-687b-4ba0-b95c-483bcde8875b" }, "execution_count": 21, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Generated text (temperature=0.5):\n", "\n", "the universe is such a place where krishna is the creator of the universe . it is possible that the gospels is that weΓ’ Β€ Β™ t areas of multiple , and that the universe is that the gospels is that the values is the product of the universe . the number of nasaΓ’ is the temperature . the number of slokas composed by the gods and the kaikeyas , the planets , the , and the andhakas , the planets , the , and the , the , the , and the , and the , the , and the ,\n" ] } ] } ] }