{ "cells": [ { "cell_type": "markdown", "metadata": { "colab_type": "text" }, "source": [ "This is a companion notebook for the book [Deep Learning with Python, Third Edition](https://www.manning.com/books/deep-learning-with-python-third-edition). For readability, it only contains runnable code blocks and section titles, and omits everything else in the book: text paragraphs, figures, and pseudocode.\n\n**If you want to be able to follow what's going on, I recommend reading the notebook side by side with your copy of the book.**\n\nThe book's contents are available online at [deeplearningwithpython.io](https://deeplearningwithpython.io)." ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "!pip install keras keras-hub --upgrade -q" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "import os\n", "os.environ[\"KERAS_BACKEND\"] = \"jax\"" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "cellView": "form", "colab_type": "code" }, "outputs": [], "source": [ "# @title\n", "import os\n", "from IPython.core.magic import register_cell_magic\n", "\n", "@register_cell_magic\n", "def backend(line, cell):\n", " current, required = os.environ.get(\"KERAS_BACKEND\", \"\"), line.split()[-1]\n", " if current == required:\n", " get_ipython().run_cell(cell)\n", " else:\n", " print(\n", " f\"This cell requires the {required} backend. To run it, change KERAS_BACKEND to \"\n", " f\"\\\"{required}\\\" at the top of the notebook, restart the runtime, and rerun the notebook.\"\n", " )" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text" }, "source": [ "## Text classification" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text" }, "source": [ "### A brief history of natural language processing" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text" }, "source": [ "### Preparing text data" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "import regex as re\n", "\n", "def split_chars(text):\n", " return re.findall(r\".\", text)" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "chars = split_chars(\"The quick brown fox jumped over the lazy dog.\")\n", "chars[:12]" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "def split_words(text):\n", " return re.findall(r\"[\\w]+|[.,!?;]\", text)" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "split_words(\"The quick brown fox jumped over the dog.\")" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "vocabulary = {\n", " \"[UNK]\": 0,\n", " \"the\": 1,\n", " \"quick\": 2,\n", " \"brown\": 3,\n", " \"fox\": 4,\n", " \"jumped\": 5,\n", " \"over\": 6,\n", " \"dog\": 7,\n", " \".\": 8,\n", "}\n", "words = split_words(\"The quick brown fox jumped over the lazy dog.\")\n", "indices = [vocabulary.get(word, 0) for word in words]" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text" }, "source": [ "#### Character and word tokenization" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "class CharTokenizer:\n", " def __init__(self, vocabulary):\n", " self.vocabulary = vocabulary\n", " self.unk_id = vocabulary[\"[UNK]\"]\n", "\n", " def standardize(self, inputs):\n", " return inputs.lower()\n", "\n", " def split(self, inputs):\n", " return re.findall(r\".\", inputs)\n", "\n", " def index(self, tokens):\n", " return [self.vocabulary.get(t, self.unk_id) for t in tokens]\n", "\n", " def __call__(self, inputs):\n", " inputs = self.standardize(inputs)\n", " tokens = self.split(inputs)\n", " indices = self.index(tokens)\n", " return indices" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "import collections\n", "\n", "def compute_char_vocabulary(inputs, max_size):\n", " char_counts = collections.Counter()\n", " for x in inputs:\n", " x = x.lower()\n", " tokens = re.findall(r\".\", x)\n", " char_counts.update(tokens)\n", " vocabulary = [\"[UNK]\"]\n", " most_common = char_counts.most_common(max_size - len(vocabulary))\n", " for token, count in most_common:\n", " vocabulary.append(token)\n", " return dict((token, i) for i, token in enumerate(vocabulary))" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "class WordTokenizer:\n", " def __init__(self, vocabulary):\n", " self.vocabulary = vocabulary\n", " self.unk_id = vocabulary[\"[UNK]\"]\n", "\n", " def standardize(self, inputs):\n", " return inputs.lower()\n", "\n", " def split(self, inputs):\n", " return re.findall(r\"[\\w]+|[.,!?;]\", inputs)\n", "\n", " def index(self, tokens):\n", " return [self.vocabulary.get(t, self.unk_id) for t in tokens]\n", "\n", " def __call__(self, inputs):\n", " inputs = self.standardize(inputs)\n", " tokens = self.split(inputs)\n", " indices = self.index(tokens)\n", " return indices" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "def compute_word_vocabulary(inputs, max_size):\n", " word_counts = collections.Counter()\n", " for x in inputs:\n", " x = x.lower()\n", " tokens = re.findall(r\"[\\w]+|[.,!?;]\", x)\n", " word_counts.update(tokens)\n", " vocabulary = [\"[UNK]\"]\n", " most_common = word_counts.most_common(max_size - len(vocabulary))\n", " for token, count in most_common:\n", " vocabulary.append(token)\n", " return dict((token, i) for i, token in enumerate(vocabulary))" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "import keras\n", "\n", "filename = keras.utils.get_file(\n", " origin=\"https://www.gutenberg.org/files/2701/old/moby10b.txt\",\n", ")\n", "moby_dick = list(open(filename, \"r\"))\n", "\n", "vocabulary = compute_char_vocabulary(moby_dick, max_size=100)\n", "char_tokenizer = CharTokenizer(vocabulary)" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "print(\"Vocabulary length:\", len(vocabulary))" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "print(\"Vocabulary start:\", list(vocabulary.keys())[:10])" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "print(\"Vocabulary end:\", list(vocabulary.keys())[-10:])" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "print(\"Line length:\", len(char_tokenizer(\n", " \"Call me Ishmael. Some years ago--never mind how long precisely.\"\n", ")))" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "vocabulary = compute_word_vocabulary(moby_dick, max_size=2_000)\n", "word_tokenizer = WordTokenizer(vocabulary)" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "print(\"Vocabulary length:\", len(vocabulary))" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "print(\"Vocabulary start:\", list(vocabulary.keys())[:5])" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "print(\"Vocabulary end:\", list(vocabulary.keys())[-5:])" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "print(\"Line length:\", len(word_tokenizer(\n", " \"Call me Ishmael. Some years ago--never mind how long precisely.\"\n", ")))" ] }, { "cell_type": "markdown", "metadata": { "colab_type": "text" }, "source": [ "#### Subword tokenization" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "data = [\n", " \"the quick brown fox\",\n", " \"the slow brown fox\",\n", " \"the quick brown foxhound\",\n", "]" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "def count_and_split_words(data):\n", " counts = collections.Counter()\n", " for line in data:\n", " line = line.lower()\n", " for word in re.findall(r\"[\\w]+|[.,!?;]\", line):\n", " chars = re.findall(r\".\", word)\n", " split_word = \" \".join(chars)\n", " counts[split_word] += 1\n", " return dict(counts)\n", "\n", "counts = count_and_split_words(data)" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "counts" ] }, { "cell_type": "code", "execution_count": 0, "metadata": { "colab_type": "code" }, "outputs": [], "source": [ "def count_pairs(counts):\n", " pairs = collections.Counter()\n", " for word, freq in counts.items():\n", " symbols = word.split()\n", " for pair in zip(symbols[:-1], symbols[1:]):\n", " pairs[pair] += freq\n", " return pairs\n", "\n", "def merge_pair(counts, first, second):\n", " split = re.compile(f\"(?