{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "fc68f037",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:20:04.280028Z",
     "start_time": "2023-10-24T17:20:04.202971Z"
    }
   },
   "outputs": [],
   "source": [
    "import os\n",
    "import glob\n",
    "import subprocess\n",
    "import tarfile\n",
    "import wget\n",
    "import copy\n",
    "from omegaconf import OmegaConf, open_dict"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "3e60ab39",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:20:04.380015Z",
     "start_time": "2023-10-24T17:20:04.378138Z"
    }
   },
   "outputs": [],
   "source": [
    "data_dir = \"datasets/\"\n",
    "\n",
    "if not os.path.exists(data_dir):\n",
    "    os.makedirs(data_dir, exist_ok=True)\n",
    "\n",
    "if not os.path.exists(\"scripts\"):\n",
    "    os.makedirs(\"scripts\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "67809f28",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:20:09.839163Z",
     "start_time": "2023-10-24T17:20:04.542814Z"
    }
   },
   "outputs": [],
   "source": [
    "import nemo\n",
    "import nemo.collections.asr as nemo_asr\n",
    "from nemo.collections.asr.metrics.wer import word_error_rate\n",
    "from nemo.utils import logging, exp_manager"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "3f961c59",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:25:11.069818Z",
     "start_time": "2023-10-24T17:25:09.954576Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--2023-10-24 17:25:09--  https://github.com/NVIDIA/NeMo/blob/main/scripts/dataset_processing/get_commonvoice_data.py\n",
      "Resolving github.com (github.com)... 20.27.177.113\n",
      "Connecting to github.com (github.com)|20.27.177.113|:443... connected.\n",
      "HTTP request sent, awaiting response... 200 OK\n",
      "Length: 50453 (49K) [text/plain]\n",
      "Saving to: ‘scripts/get_commonvoice_data.py’\n",
      "\n",
      "get_commonvoice_dat 100%[===================>]  49.27K  --.-KB/s    in 0.1s    \n",
      "\n",
      "2023-10-24 17:25:10 (518 KB/s) - ‘scripts/get_commonvoice_data.py’ saved [50453/50453]\n",
      "\n"
     ]
    }
   ],
   "source": [
    "if not os.path.exists(\"scripts/get_commonvoice_data.py\"):\n",
    "    !wget -P scripts/ https://github.com/NVIDIA/NeMo/blob/main/scripts/dataset_processing/get_commonvoice_data.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "d4a76d69",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:25:13.073112Z",
     "start_time": "2023-10-24T17:25:13.070691Z"
    }
   },
   "outputs": [],
   "source": [
    "VERSION = \"cv-corpus-6.1-2020-12-11\"\n",
    "LANGUAGE = \"ja\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "1997ad2e",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:25:13.276519Z",
     "start_time": "2023-10-24T17:25:13.274644Z"
    }
   },
   "outputs": [],
   "source": [
    "tokenizer_dir = os.path.join('tokenizers', LANGUAGE)\n",
    "manifest_dir = os.path.join('manifests', LANGUAGE)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "250f0276",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:25:13.584569Z",
     "start_time": "2023-10-24T17:25:13.454464Z"
    }
   },
   "outputs": [],
   "source": [
    "!mkdir -p datasets"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "20f9cd93",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:27:56.817676Z",
     "start_time": "2023-10-24T17:26:37.085082Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "--2023-10-24 17:26:37--  https://voice-prod-bundler-ee1969a6ce8178826482b88e843c335139bd3fb4.s3.amazonaws.com/cv-corpus-6.1-2020-12-11/ja.tar.gz\n",
      "Resolving voice-prod-bundler-ee1969a6ce8178826482b88e843c335139bd3fb4.s3.amazonaws.com (voice-prod-bundler-ee1969a6ce8178826482b88e843c335139bd3fb4.s3.amazonaws.com)... 52.92.208.161, 52.92.179.25, 52.92.162.57, ...\n",
      "Connecting to voice-prod-bundler-ee1969a6ce8178826482b88e843c335139bd3fb4.s3.amazonaws.com (voice-prod-bundler-ee1969a6ce8178826482b88e843c335139bd3fb4.s3.amazonaws.com)|52.92.208.161|:443... connected.\n",
      "HTTP request sent, awaiting response... 200 OK\n",
      "Length: 152879796 (146M) [application/octet-stream]\n",
      "Saving to: ‘datasets/ja/ja.tar.gz’\n",
      "\n",
      "datasets/ja/ja.tar. 100%[===================>] 145.80M  15.5MB/s    in 9.9s    \n",
      "\n",
      "2023-10-24 17:26:48 (14.7 MB/s) - ‘datasets/ja/ja.tar.gz’ saved [152879796/152879796]\n",
      "\n",
      "100%|████████████████████████████████████████| 721/721 [00:02<00:00, 242.55it/s]\n",
      "100%|█████████████████████████████████████| 721/721 [00:00<00:00, 128630.08it/s]\n",
      "100%|████████████████████████████████████████| 585/585 [00:02<00:00, 237.13it/s]\n",
      "100%|█████████████████████████████████████| 585/585 [00:00<00:00, 123256.53it/s]\n",
      "100%|████████████████████████████████████████| 631/631 [00:02<00:00, 240.51it/s]\n",
      "100%|█████████████████████████████████████| 631/631 [00:00<00:00, 128669.64it/s]\n"
     ]
    }
   ],
   "source": [
    "!python scripts/get_commonvoice_data.py \\\n",
    "  --data_root \"datasets/$LANGUAGE/\" \\\n",
    "  --manifest_dir=$manifest_dir \\\n",
    "  --sample_rate=16000 \\\n",
    "  --n_channels=1 \\\n",
    "  --version=$VERSION \\\n",
    "  --language=$LANGUAGE \\\n",
    "  --files_to_process 'train.tsv' 'dev.tsv' 'test.tsv'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "9e43c8da",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:27:56.822872Z",
     "start_time": "2023-10-24T17:27:56.820138Z"
    }
   },
   "outputs": [],
   "source": [
    "train_manifest = f\"{manifest_dir}/commonvoice_train_manifest.json\"\n",
    "dev_manifest = f\"{manifest_dir}/commonvoice_dev_manifest.json\"\n",
    "test_manifest = f\"{manifest_dir}/commonvoice_test_manifest.json\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "08fdf1e5",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:28:29.212850Z",
     "start_time": "2023-10-24T17:28:29.204721Z"
    }
   },
   "outputs": [],
   "source": [
    "# Manifest Utils\n",
    "from tqdm.auto import tqdm\n",
    "from nemo.collections.asr.parts.utils.manifest_utils import read_manifest, write_manifest\n",
    "import json\n",
    "\n",
    "\n",
    "def write_processed_manifest(data, original_path):\n",
    "    original_manifest_name = os.path.basename(original_path)\n",
    "    new_manifest_name = original_manifest_name.replace(\".json\", \"_processed.json\")\n",
    "\n",
    "    manifest_dir = os.path.split(original_path)[0]\n",
    "    filepath = os.path.join(manifest_dir, new_manifest_name)\n",
    "    write_manifest(filepath, data)\n",
    "    print(f\"Finished writing manifest: {filepath}\")\n",
    "    return filepath"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "05807009",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:28:35.067622Z",
     "start_time": "2023-10-24T17:28:35.058542Z"
    }
   },
   "outputs": [],
   "source": [
    "train_manifest_data = read_manifest(train_manifest)\n",
    "dev_manifest_data = read_manifest(dev_manifest)\n",
    "test_manifest_data = read_manifest(test_manifest)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "d3699205",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:28:39.029833Z",
     "start_time": "2023-10-24T17:28:39.027552Z"
    }
   },
   "outputs": [],
   "source": [
    "train_text = [data['text'] for data in train_manifest_data]\n",
    "dev_text = [data['text'] for data in dev_manifest_data]\n",
    "test_text = [data['text'] for data in test_manifest_data]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "bdb3aa24",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:28:46.690890Z",
     "start_time": "2023-10-24T17:28:46.688347Z"
    }
   },
   "outputs": [],
   "source": [
    "from collections import defaultdict\n",
    "\n",
    "def get_charset(manifest_data):\n",
    "    charset = defaultdict(int)\n",
    "    for row in tqdm(manifest_data, desc=\"Computing character set\"):\n",
    "        text = row['text']\n",
    "        for character in text:\n",
    "            charset[character] += 1\n",
    "    return charset"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "3a1821a5",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:28:52.623033Z",
     "start_time": "2023-10-24T17:28:52.598785Z"
    }
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "4eb3c524943a49babeb7c46691b96e46",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Computing character set:   0%|          | 0/721 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "309c2638116841a7a393813b80e537d6",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Computing character set:   0%|          | 0/585 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "033e1439c8ac459c97babcf928301359",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Computing character set:   0%|          | 0/631 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "train_charset = get_charset(train_manifest_data)\n",
    "dev_charset = get_charset(dev_manifest_data)\n",
    "test_charset = get_charset(test_manifest_data)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "5cb408e4",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:28:58.769828Z",
     "start_time": "2023-10-24T17:28:58.767770Z"
    }
   },
   "outputs": [],
   "source": [
    "train_dev_set = set.union(set(train_charset.keys()), set(dev_charset.keys()))\n",
    "test_set = set(test_charset.keys())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "8d319953",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:29:03.279972Z",
     "start_time": "2023-10-24T17:29:03.277997Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Number of tokens in train+dev set : 1254\n",
      "Number of tokens in test set : 1058\n"
     ]
    }
   ],
   "source": [
    "print(f\"Number of tokens in train+dev set : {len(train_dev_set)}\")\n",
    "print(f\"Number of tokens in test set : {len(test_set)}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "1df0a413",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:30:56.981191Z",
     "start_time": "2023-10-24T17:30:56.978586Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Number of OOV tokens in test set : 177\n",
      "\n",
      "{'君', '塵', '瞬', '訪', '髴', '犠', '剥', '艇', '称', '占', '署', '追', '遇', '躇', '接', '温', '眺', '吉', '躍', '賄', '柱', '冊', '硬', '翻', '釣', '繋', '？', '岸', '溢', '承', '乾', '劇', '躊', '鍵', '湯', '償', '草', '獲', '〇', '希', '像', '牲', '南', '印', '震', '触', '遭', '歓', '奏', '殖', '旧', '冠', '肥', '処', '照', '懸', '効', '擬', '帝', '珍', '渠', '命', '裕', '拍', '鞄', '融', '肘', '既', '打', 'ｐ', '寵', '穴', '忠', '滅', '苑', '扉', '示', '伝', '洒', '宴', '景', 'ｄ', '刑', '士', '麗', '噂', '襲', '繕', '賂', '区', '因', '掌', '紫', '筋', '負', '瀬', '袋', '抑', 'ぷ', '級', '髣', '垢', '弊', '退', '獅', '駐', '否', '浸', '碑', '届', '憶', '県', '彩', '僕', '衣', '採', '劣', '塁', '領', '諸', '器', '懐', '却', '騒', '挙', '岩', '卒', '罅', '灯', '郡', '森', '殿', '床', '纏', '翌', '旋', '完', '層', '粉', '縁', '概', '顧', '璧', '具', '極', '淵', '識', '丸', '往', '偉', '謙', '砲', '協', '叩', '幅', '皆', '孫', '捨', '茂', '異', '胴', 'ｇ', '棋', '純', '可', '件', '郊', '壮', '盛', '嶋', '殻', '餐', '浅', '闘', '税', '昔', '綴'}\n"
     ]
    }
   ],
   "source": [
    "train_test_common = set.intersection(train_dev_set, test_set)\n",
    "test_oov = test_set - train_test_common\n",
    "print(f\"Number of OOV tokens in test set : {len(test_oov)}\")\n",
    "print()\n",
    "print(test_oov)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "4efcca1a",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:31:32.749844Z",
     "start_time": "2023-10-24T17:31:32.746609Z"
    }
   },
   "outputs": [],
   "source": [
    "# Populate dictionary mapping count: list[tokens]\n",
    "train_counts = defaultdict(list)\n",
    "for token, count in train_charset.items():\n",
    "    train_counts[count].append(token)\n",
    "for token, count in dev_charset.items():\n",
    "    train_counts[count].append(token)\n",
    "\n",
    "# Compute sorter order of the count keys\n",
    "count_keys = sorted(list(train_counts.keys()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "e97e9100",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:31:46.228970Z",
     "start_time": "2023-10-24T17:31:46.226244Z"
    }
   },
   "outputs": [],
   "source": [
    "MAX_COUNT = 32\n",
    "\n",
    "TOKEN_COUNT_X = []\n",
    "NUM_TOKENS_Y = []\n",
    "for count in range(1, MAX_COUNT + 1):\n",
    "    if count in train_counts:\n",
    "        num_tokens = len(train_counts[count])\n",
    "\n",
    "        TOKEN_COUNT_X.append(count)\n",
    "        NUM_TOKENS_Y.append(num_tokens)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "eae9fb2c",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:31:51.204784Z",
     "start_time": "2023-10-24T17:31:50.999022Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/png": "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CUFeXh6CgoKwYMECqb1KlSrYuHEjhg8fDj8/P1haWiI0NBTTp09/nqtARERElViles+OsfA9O0RERC+eF+49O0REREQVgWGHiIiIZI1hh4iIiGTN6Dcov0hcJ/1tUP+LM4Of3ImIiIgqFM/sEBERkawx7BAREZGsMewQERGRrDHsEBERkawx7BAREZGsMewQERGRrDHsEBERkawx7BAREZGsMewQERGRrDHsEBERkawx7BAREZGsMewQERGRrDHsEBERkawx7BAREZGsMewQERGRrDHsEBERkawx7BAREZGsMewQERGRrDHsEBERkawx7BAREZGsMewQERGRrDHsEBERkawx7BAREZGsMewQERGRrDHsEBERkawx7BAREZGsMewQERGRrDHsEBERkawx7BAREZGsMewQERGRrDHsEBERkawx7BAREZGsMewQERGRrDHsEBERkawx7BAREZGsMewQERGRrDHsEBERkawZPexcvXoV7733HqpXrw5zc3M0adIER44ckdqFEJgyZQqcnJxgbm6OgIAAJCYm6s3j1q1b6NevH9RqNWxsbDBkyBDcvXv3ea8KERERVUJGDTu3b99G69atYWpqis2bN+PMmTP4+uuvUa1aNanPrFmzMG/ePCxcuBCHDx+GpaUlgoKCkJubK/Xp168f4uPjER0djY0bN2Lv3r0YOnSoMVaJiIiIKhmFEEIYa+GTJk3CgQMHsG/fvhLbhRBwdnbGuHHjMH78eABAVlYWHBwcsGTJErzzzjs4e/YsPDw8EBsbi+bNmwMAtmzZgjfffBNXrlyBs7PzE+vQarXQaDTIysqCWq0utZ/rpL8NWr+LM4MN6k9ERERlV9a/30Y9s/PXX3+hefPmePvtt2Fvb49XX30VP/30k9SenJyMtLQ0BAQESOM0Gg1atWqFmJgYAEBMTAxsbGykoAMAAQEBMDExweHDh0tcbl5eHrRard5ARERE8mTUsPPvv//ihx9+QP369bF161YMHz4co0aNwtKlSwEAaWlpAAAHBwe96RwcHKS2tLQ02Nvb67VXrVoVtra2Up9HzZgxAxqNRhpq165d3qtGRERElYRRw45Op0OzZs3wxRdf4NVXX8XQoUPx/vvvY+HChRW63MjISGRlZUnD5cuXK3R5REREZDxGDTtOTk7w8PDQG9eoUSOkpKQAABwdHQEA6enpen3S09OlNkdHR2RkZOi1379/H7du3ZL6PEqlUkGtVusNREREJE9GDTutW7dGQkKC3rjz58/DxcUFAODm5gZHR0fs2LFDatdqtTh8+DD8/PwAAH5+fsjMzMTRo0elPjt37oROp0OrVq2ew1oQERFRZVbVmAsfM2YMXnvtNXzxxRfo3bs3/vnnHyxatAiLFi0CACgUCowePRqfffYZ6tevDzc3N3zyySdwdnZG9+7dATw4E9SpUyfp8ldBQQHCw8PxzjvvlOlJLCIiIpI3o4adFi1aYN26dYiMjMT06dPh5uaGuXPnol+/flKfCRMmIDs7G0OHDkVmZibatGmDLVu2wMzMTOqzbNkyhIeHo0OHDjAxMUFISAjmzZtnjFUiIiKiSsao79mpLPieHSIiohfPC/GeHSIiIqKKxrBDREREssawQ0RERLLGsENERESyxrBDREREssawQ0RERLLGsENERESyxrBDREREssawQ0RERLLGsENERESyxrBDREREssawQ0RERLLGsENERESyxrBDREREssawQ0RERLLGsENERESyxrBDREREssawQ0RERLLGsENERESyxrBDREREssawQ0RERLLGsENERESyxrBDREREssawQ0RERLLGsENERESyxrBDREREssawQ0RERLLGsENERESyxrBDREREssawQ0RERLLGsENERESyxrBDREREssawQ0RERLLGsENERESyxrBDREREssawQ0RERLLGsENERESyxrBDREREssawQ0RERLLGsENERESyZtSwExUVBYVCoTc0bNhQas/NzUVYWBiqV68OKysrhISEID09XW8eKSkpCA4OhoWFBezt7REREYH79+8/71UhIiKiSqqqsQvw9PTE9u3bpe+rVv2/ksaMGYO///4bq1evhkajQXh4OHr27IkDBw4AAAoLCxEcHAxHR0ccPHgQ165dw4ABA2Bqaoovvvjiua8LERERVT5GDztVq1aFo6NjsfFZWVn4+eefsXz5crzxxhsAgMWLF6NRo0Y4dOgQfH19sW3bNpw5cwbbt2+Hg4MDmjZtik8//RQTJ05EVFQUlErl814dIiIiqmSMfs9OYmIinJ2dUbduXfTr1w8pKSkAgKNHj6KgoAABAQFS34YNG6JOnTqIiYkBAMTExKBJkyZwcHCQ+gQFBUGr1SI+Pv75rggRERFVSkY9s9OqVSss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Hh4ehq4aERERyZDBZ3YCAwMxd+5cLFq0CACgUChw9+5dTJ061aCPkLC2tkbjxo31xllaWqJ69erS+CFDhmDs2LGwtbWFWq3GyJEj4efnB19fX6kWDw8P9O/fH7NmzUJaWhomT56MsLAwnrkhIiIiAE8Rdr7++msEBQXBw8MDubm5ePfdd5GYmIgaNWpgxYoV5VrcnDlzYGJigpCQEOTl5SEoKAgLFiyQ2qtUqYKNGzdi+PDh8PPzg6WlJUJDQzF9+vRyrYOIiIheXE/1np379+/j999/x4kTJ6T35PTr10/vhuUXCd+zQ0RE9OIp699vg8/srFixAn379kW/fv3Qr18/vbaIiAjMnj3b8GqJiIiIKojBNygPHz4cmzdvLjZ+zJgx+O2338qlKCIiIqLyYnDYWbZsGfr27Yv9+/dL40aOHIlVq1Zh165d5VocERER0bMyOOwEBwdjwYIFeOutt3D06FGMGDECa9euxa5du9CwYcOKqJGIiIjoqRl8zw4AvPvuu8jMzETr1q1hZ2eHPXv2oF69euVdGxEREdEzK1PYGTt2bInj7ezspE8sL/LNN9+UT2VERERE5aBMYef48eMljq9Xrx60Wq3UrlAoyq8yIiIionJQprDDG4+JiIjoRWXwDcoPu3LlCq5cuVJetRARERGVu6f6INDp06dDo9HAxcUFLi4usLGxwaeffgqdTlcRNRIRERE9NYOfxvr444/x888/Y+bMmWjdujUAYP/+/YiKikJubi4+//zzci+SiIiI6GkZHHaWLl2K//73v3jrrbekcV5eXqhZsyZGjBjBsENERESVisGXsW7dulXiywMbNmyIW7dulUtRREREROXF4LDj7e2N77//vtj477//Ht7e3uVSFBEREVF5Mfgy1qxZsxAcHIzt27fDz88PABATE4PLly9j06ZN5V4gERER0bMw+MyOv78/zp8/jx49eiAzMxOZmZno2bMnEhIS0LZt24qokYiIiOipGXxmJyUlBbVr1y7xRuSUlBTUqVOnXAojIiIiKg8Gn9lxc3PD9evXi42/efMm3NzcyqUoIiIiovJicNgRQpT4GVh3796FmZlZuRRFREREVF7KfBmr6JPPFQoFPvnkE1hYWEhthYWFOHz4MJo2bVruBRIRERE9izKHnaJPNhdC4NSpU1AqlVKbUqmEt7c3xo8fX/4VEhERET2D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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "\n",
    "plt.bar(x=TOKEN_COUNT_X, height=NUM_TOKENS_Y)\n",
    "plt.title(\"Occurrences of unique tokens in train+dev set\")\n",
    "plt.xlabel(\"# of occurrences\")\n",
    "plt.ylabel(\"# of tokens\")\n",
    "plt.xlim(0, MAX_COUNT);"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "451d6f3b",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:32:15.849045Z",
     "start_time": "2023-10-24T17:32:15.845977Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Number of tokens with <= 5 occurrences : 1040\n"
     ]
    }
   ],
   "source": [
    "UNCOMMON_TOKENS_COUNT = 5\n",
    "\n",
    "chars_with_infrequent_occurrence = set()\n",
    "for count in range(1, UNCOMMON_TOKENS_COUNT + 1):\n",
    "    if count in train_counts:\n",
    "        token_list = train_counts[count]\n",
    "        chars_with_infrequent_occurrence.update(set(token_list))\n",
    "\n",
    "print(f\"Number of tokens with <= {UNCOMMON_TOKENS_COUNT} occurrences : {len(chars_with_infrequent_occurrence)}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "a19aefb6",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:32:23.410206Z",
     "start_time": "2023-10-24T17:32:23.407842Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Original train+dev+test vocab size : 1431\n",
      "New train vocab size : 1254\n"
     ]
    }
   ],
   "source": [
    "all_tokens = set.union(train_dev_set, test_set)\n",
    "print(f\"Original train+dev+test vocab size : {len(all_tokens)}\")\n",
    "\n",
    "extra_kanji = set(test_oov)\n",
    "train_token_set = all_tokens - extra_kanji\n",
    "print(f\"New train vocab size : {len(train_token_set)}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "b4f417ff",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:33:13.625348Z",
     "start_time": "2023-10-24T17:33:13.622657Z"
    }
   },
   "outputs": [],
   "source": [
    "import unicodedata\n",
    "def process_dakuten(text):\n",
    "    normalized_text = unicodedata.normalize('NFD', text)\n",
    "    normalized_text = normalized_text.replace(\"\\u3099\", \"\").replace(\"\\u309A\", \"\")\n",
    "    return normalized_text"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "0027d318",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:33:37.825896Z",
     "start_time": "2023-10-24T17:33:37.822623Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "After dakuten normalization, number of train tokens : 1209\n"
     ]
    }
   ],
   "source": [
    "PERFORM_DAKUTEN_NORMALIZATION = True\n",
    "if PERFORM_DAKUTEN_NORMALIZATION:\n",
    "    normalized_train_token_set = set()\n",
    "    for token in train_token_set:\n",
    "        normalized_token = process_dakuten(str(token))\n",
    "        normalized_train_token_set.update(normalized_token)\n",
    "        \n",
    "    print(f\"After dakuten normalization, number of train tokens : {len(normalized_train_token_set)}\")\n",
    "else:\n",
    "    normalized_train_token_set = train_token_set"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "86c8d2b2",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:33:48.902309Z",
     "start_time": "2023-10-24T17:33:48.899114Z"
    }
   },
   "outputs": [],
   "source": [
    "# Preprocessing steps\n",
    "import re\n",
    "import unicodedata\n",
    "\n",
    "chars_to_ignore_regex = '[\\,\\?\\.\\!\\-\\;\\:\\\"\\“\\%\\‘\\”\\�\\…\\{\\}\\【\\】\\・\\。\\『\\』\\、\\ー\\〜]'  # remove special character tokens\n",
    "kanji_removal_regex = '[' + \"\".join([f\"\\{token}\" for token in extra_kanji]) + ']'  # remove test set kanji\n",
    "\n",
    "\n",
    "def remove_special_characters(data):\n",
    "    data[\"text\"] = re.sub(chars_to_ignore_regex, '', data[\"text\"]).lower().strip()\n",
    "    return data\n",
    "\n",
    "def remove_extra_kanji(data):\n",
    "    data[\"text\"] = re.sub(kanji_removal_regex, '', data[\"text\"])\n",
    "    return data\n",
    "\n",
    "def remove_dakuten(data):\n",
    "    # perform dakuten normalization (if it was requested)\n",
    "    if PERFORM_DAKUTEN_NORMALIZATION:\n",
    "        text = data['text']\n",
    "        data['text'] = process_dakuten(text)\n",
    "    return data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "412ba8ad",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:33:55.580932Z",
     "start_time": "2023-10-24T17:33:55.578762Z"
    }
   },
   "outputs": [],
   "source": [
    "# Processing pipeline\n",
    "def apply_preprocessors(manifest, preprocessors):\n",
    "    for processor in preprocessors:\n",
    "        for idx in tqdm(range(len(manifest)), desc=f\"Applying {processor.__name__}\"):\n",
    "            manifest[idx] = processor(manifest[idx])\n",
    "\n",
    "    print(\"Finished processing manifest !\")\n",
    "    return manifest"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "318ca8e2",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:33:59.716386Z",
     "start_time": "2023-10-24T17:33:59.714474Z"
    }
   },
   "outputs": [],
   "source": [
    "# List of pre-processing functions\n",
    "PREPROCESSORS = [\n",
    "    remove_special_characters,\n",
    "    remove_extra_kanji,\n",
    "    remove_dakuten,\n",
    "]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "07935544",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:34:05.928394Z",
     "start_time": "2023-10-24T17:34:05.811907Z"
    }
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "4ac3535a8a034e10b2dd1148e90c069f",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Applying remove_special_characters:   0%|          | 0/721 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "a0aa817bc0e345e598faf8a12bfb7ace",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Applying remove_extra_kanji:   0%|          | 0/721 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "657303b54ac54efc93b2662d04fa43b7",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Applying remove_dakuten:   0%|          | 0/721 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Finished processing manifest !\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "4b9bf16c1d2d453096f978e2f688053e",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Applying remove_special_characters:   0%|          | 0/585 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "95a2caaf2fcb4da39a10c6b6e7e58755",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Applying remove_extra_kanji:   0%|          | 0/585 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "af43134625d449b99223058fee982c85",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Applying remove_dakuten:   0%|          | 0/585 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Finished processing manifest !\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "e44d29c75e3146c7aa90484b3840f5b9",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Applying remove_special_characters:   0%|          | 0/631 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "4730c029a6824c3b8c79b97ad7d97cf7",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Applying remove_extra_kanji:   0%|          | 0/631 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "c4a4203198b84600a3f6a5b9d8513c19",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Applying remove_dakuten:   0%|          | 0/631 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Finished processing manifest !\n",
      "Finished writing manifest: manifests/ja/commonvoice_train_manifest_processed.json\n",
      "Finished writing manifest: manifests/ja/commonvoice_dev_manifest_processed.json\n",
      "Finished writing manifest: manifests/ja/commonvoice_test_manifest_processed.json\n"
     ]
    }
   ],
   "source": [
    "# Load manifests\n",
    "train_data = read_manifest(train_manifest)\n",
    "dev_data = read_manifest(dev_manifest)\n",
    "test_data = read_manifest(test_manifest)\n",
    "\n",
    "# Apply preprocessing\n",
    "train_data_processed = apply_preprocessors(train_data, PREPROCESSORS)\n",
    "dev_data_processed = apply_preprocessors(dev_data, PREPROCESSORS)\n",
    "test_data_processed = apply_preprocessors(test_data, PREPROCESSORS)\n",
    "\n",
    "# Write new manifests\n",
    "train_manifest_cleaned = write_processed_manifest(train_data_processed, train_manifest)\n",
    "dev_manifest_cleaned = write_processed_manifest(dev_data_processed, dev_manifest)\n",
    "test_manifest_cleaned = write_processed_manifest(test_data_processed, test_manifest)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "6dc511f1",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:34:14.496111Z",
     "start_time": "2023-10-24T17:34:14.477581Z"
    }
   },
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "fed033e481264900a4369fdc7cc5df1b",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Computing character set:   0%|          | 0/721 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "b8b5662b8e42484398dfcf806a6a4055",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "Computing character set:   0%|          | 0/585 [00:00<?, ?it/s]"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "train_manifest_data = read_manifest(train_manifest_cleaned)\n",
    "train_charset = get_charset(train_manifest_data)\n",
    "\n",
    "dev_manifest_data = read_manifest(dev_manifest_cleaned)\n",
    "dev_charset = get_charset(dev_manifest_data)\n",
    "\n",
    "train_dev_set = set.union(set(train_charset.keys()), set(dev_charset.keys()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "135788c3",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:34:18.932025Z",
     "start_time": "2023-10-24T17:34:18.929768Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Number of tokens in preprocessed train+dev set : 1205\n"
     ]
    }
   ],
   "source": [
    "print(f\"Number of tokens in preprocessed train+dev set : {len(train_dev_set)}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "77295e58",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:34:33.656512Z",
     "start_time": "2023-10-24T17:34:26.942238Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[NeMo I 2023-10-24 17:34:26 cloud:68] Downloading from: https://api.ngc.nvidia.com/v2/models/nvidia/nemo/stt_en_quartznet15x5/versions/1.0.0rc1/files/stt_en_quartznet15x5.nemo to /home/tony/.cache/torch/NeMo/NeMo_1.20.0/stt_en_quartznet15x5/16661021d16e679bdfd97a2a03944c49/stt_en_quartznet15x5.nemo\n",
      "100% [........................................................................] 70993538 / 70993538[NeMo I 2023-10-24 17:34:31 common:913] Instantiating model from pre-trained checkpoint\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[NeMo W 2023-10-24 17:34:32 modelPT:161] If you intend to do training or fine-tuning, please call the ModelPT.setup_training_data() method and provide a valid configuration file to setup the train data loader.\n",
      "    Train config : \n",
      "    manifest_filepath: /data2/voices/train_1k.json\n",
      "    sample_rate: 16000\n",
      "    labels:\n",
      "    - ' '\n",
      "    - a\n",
      "    - b\n",
      "    - c\n",
      "    - d\n",
      "    - e\n",
      "    - f\n",
      "    - g\n",
      "    - h\n",
      "    - i\n",
      "    - j\n",
      "    - k\n",
      "    - l\n",
      "    - m\n",
      "    - 'n'\n",
      "    - o\n",
      "    - p\n",
      "    - q\n",
      "    - r\n",
      "    - s\n",
      "    - t\n",
      "    - u\n",
      "    - v\n",
      "    - w\n",
      "    - x\n",
      "    - 'y'\n",
      "    - z\n",
      "    - ''''\n",
      "    batch_size: 32\n",
      "    trim_silence: true\n",
      "    max_duration: 16.7\n",
      "    shuffle: true\n",
      "    is_tarred: false\n",
      "    tarred_audio_filepaths: /asr_set_1.2/train/train_{0..1023}.tar\n",
      "    num_workers: 20\n",
      "    \n",
      "[NeMo W 2023-10-24 17:34:32 modelPT:168] If you intend to do validation, please call the ModelPT.setup_validation_data() or ModelPT.setup_multiple_validation_data() method and provide a valid configuration file to setup the validation data loader(s). \n",
      "    Validation config : \n",
      "    manifest_filepath: /data2/voices/train_1k_samp.json\n",
      "    sample_rate: 16000\n",
      "    labels:\n",
      "    - ' '\n",
      "    - a\n",
      "    - b\n",
      "    - c\n",
      "    - d\n",
      "    - e\n",
      "    - f\n",
      "    - g\n",
      "    - h\n",
      "    - i\n",
      "    - j\n",
      "    - k\n",
      "    - l\n",
      "    - m\n",
      "    - 'n'\n",
      "    - o\n",
      "    - p\n",
      "    - q\n",
      "    - r\n",
      "    - s\n",
      "    - t\n",
      "    - u\n",
      "    - v\n",
      "    - w\n",
      "    - x\n",
      "    - 'y'\n",
      "    - z\n",
      "    - ''''\n",
      "    batch_size: 32\n",
      "    shuffle: false\n",
      "    \n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[NeMo I 2023-10-24 17:34:32 features:289] PADDING: 16\n",
      "[NeMo I 2023-10-24 17:34:33 audio_preprocessing:517] Numba CUDA SpecAugment kernel is being used\n",
      "[NeMo I 2023-10-24 17:34:33 save_restore_connector:249] Model EncDecCTCModel was successfully restored from /home/tony/.cache/torch/NeMo/NeMo_1.20.0/stt_en_quartznet15x5/16661021d16e679bdfd97a2a03944c49/stt_en_quartznet15x5.nemo.\n"
     ]
    }
   ],
   "source": [
    "char_model = nemo_asr.models.ASRModel.from_pretrained(\"stt_en_quartznet15x5\", map_location='cpu')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "561df755",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2023-10-24T17:34:41.896413Z",
     "start_time": "2023-10-24T17:34:41.247149Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[NeMo I 2023-10-24 17:34:41 ctc_models:309] Changed decoder to output to ['頼', '止', 'ウ', '王', '以', '敷', '役', '捕', '庫', '惑', '整', '編', '胃', '海', '遠', 'か', 'ニ', '研', 'な', '住', '票', '期', '揺', '嫌', '離', '究', '助', '深', '悲', '条', '常', '軌', '結', '木', '浜', '残', '動', '唯', '描', '州', '出', '対', '傷', '賀', '浴', '庁', '取', 'く', '尺', '体', '威', '円', '転', '坂', '寸', '冬', '当', 'お', '帰', '貧', '長', '独', '小', '粧', '若', 'マ', '制', '向', '米', '畑', '無', '橋', '決', '踏', '作', '後', '障', '積', '式', '樫', '微', '危', '瞳', '招', '師', '帯', '浮', '間', '験', '揚', '女', '墓', '互', '羊', '運', '型', '降', '重', '主', '修', '思', '林', '千', '濯', '員', '依', '安', 'ナ', '核', '滑', '職', '来', '絹', '十', '「', '急', '慌', '札', '泥', '務', '焦', '用', '青', '崩', 'ェ', '席', '秀', '良', '建', '城', '害', 'り', '脳', '廊', '済', '陸', '越', '池', '供', '舗', '苦', '約', '窓', '植', '能', '冷', '辛', '淡', '類', '糾', '歳', '遊', '空', '力', '大', '土', '漢', '習', 'ほ', '音', '勤', '苗', '者', '回', '伏', '忙', '新', '各', '医', '根', '笛', '姉', 'に', '岡', '壁', '放', '健', '豚', 'ク', '文', '毛', 'ト', '昭', 'え', '上', '荷', '遍', 'ィ', '夕', '歯', '角', '保', '万', '位', 'あ', '複', '猟', '返', 'き', '外', '呼', '胸', '鵜', '守', '延', '茶', '吹', '船', '灰', '算', 'は', '置', '考', '骨', '映', '怠', '稿', '需', '次', '晩', 'ひ', '辺', '犬', '留', '拡', '浄', '肋', '寓', '憐', '比', '問', '着', '腐', '恐', '優', '備', '包', '宅', '屋', '午', '味', '室', '継', '圧', '案', '弱', '術', '賛', '歌', '鉛', '敗', '膝', '造', '鯨', '属', '形', '与', '為', '勢', '余', '遂', '光', '望', '護', '匠', '忍', '郵', '黄', '駅', '振', '並', '容', '肩', '暇', '賢', '写', '恋', '易', '栓', '派', '散', '活', '末', '燃', '最', '入', '中', '故', '掃', 'ソ', '内', '待', '布', '発', '紛', '踊', '歴', '漁', '葬', '事', '球', 'し', '機', '裂', '路', '応', '不', '争', '帽', '探', '預', '雪', '訳', '団', 'ォ', '富', '交', '工', 'リ', '誕', '受', '射', '遅', '宙', '誌', '利', '刊', '豆', '候', '図', '象', 'す', '管', 'へ', '通', '標', '目', 'っ', '材', '忘', '怖', '葉', 'を', 'よ', '邪', '賑', '念', '弾', '番', '々', '全', '氏', 'の', '吐', '鰻', '従', '白', '柔', '石', '殊', '要', '細', '抒', 'ヤ', '率', '壊', '校', '払', '書', 'テ', '慮', '証', '枚', '際', '欲', '松', '販', '券', '有', 'チ', '般', '組', '封', '弁', '爆', '燐', '宿', '方', '尋', '態', '晴', '酸', '屈', '吸', '坊', '張', '司', '失', '汗', '憩', '康', '肉', '影', '火', '使', '平', '流', '縫', 'そ', '多', '試', '靴', '伸', '暖', '題', '何', '暴', '定', '病', '牽', 'イ', '徐', '状', '老', 'ロ', '衆', '風', '懺', '銘', '黙', '睡', '然', '聞', 'ゅ', '航', '倉', '京', '況', '料', '顔', '田', '覆', '改', '消', '悪', '囲', '気', '眼', '教', '痢', '治', '掘', '押', '偽', '列', '庭', '専', '配', '日', '難', '商', '巡', '均', '程', '局', '雑', '横', '扱', '巻', '演', '裾', '国', '去', '章', '旅', '豊', '川', '首', '拝', '少', '賃', '告', '群', '鉢', '信', '詰', 'ま', '神', '戸', '患', '呆', '永', '真', '欠', '倫', '部', '乱', '己', '肌', '情', '共', '域', '食', '引', '将', '糖', 'い', '口', '策', '表', '導', '築', 'ヒ', '始', 'ョ', '祭', '怪', '肝', '走', '冒', '意', '府', '底', '労', '滴', '狩', '和', '偶', '奈', '許', 'ネ', '突', '熱', '紅', 'メ', '名', '願', '岬', '適', '揮', '果', '史', '漏', '量', '性', '妃', 'ッ', '周', '父', '及', '違', '寿', '鉄', '軍', '撮', '濫', '久', '暮', '貸', '禰', '悔', '百', '構', '授', '距', 'カ', '便', '疲', '蔵', '侵', '加', '界', '春', 'み', '初', '西', '季', '絶', '付', '資', '都', '頭', '幼', '集', '求', 'オ', '客', '覚', '個', '善', '一', '談', '友', '夜', '宝', '児', 'ゃ', 'ヘ', 'ラ', '設', 'め', '古', '移', '曜', '同', '見', '曲', '妹', '洋', '氷', '息', '菜', '束', '奇', '指', '抜', '酷', '説', '行', 'ぬ', '誰', '絡', '喰', '戻', 'む', '任', '泳', '本', '数', '洗', '枠', '画', '潤', '店', 'ヌ', '笑', '開', '規', '刺', '言', '慢', '輸', '場', 'こ', '再', '検', '痴', '成', '前', 'セ', '生', '替', '短', '休', '掛', '隣', '机', '藩', '他', '充', '我', '合', '島', '興', '倒', '併', '私', '子', '紙', '密', '由', '埋', '眠', '広', '財', 'ュ', 'わ', '割', '姿', '愛', '磨', '喜', '栄', '朝', 'る', '頑', '透', '鳴', '飛', 'ヶ', '読', '湖', '速', '沈', '宇', '倍', '訓', '赤', '琉', '牛', '喫', 'ふ', '逃', '干', '単', '所', '投', '露', '麦', '港', '膜', '夫', '緑', '毎', '差', '鼻', '品', '北', '係', '脱', '増', '鳥', '感', '働', '野', '模', '五', '競', '天', '理', '六', '境', '乗', 'ム', '菓', '限', '鋼', '耳', '参', '魚', '点', '立', '別', '宮', '市', '鏡', '混', '答', '暑', '夢', '認', '直', '汚', '鮮', '注', '症', '花', '評', '更', '福', '腫', '油', '的', '得', '彼', 'レ', '官', '段', '襞', 'ケ', 'ゆ', '髪', '巧', '送', '飲', '込', '弟', '帳', '費', '奥', '箱', '精', 'ね', '歩', '迎', 'せ', '昼', '癖', '裏', '仕', '赴', '八', '世', '地', '握', '薬', '台', '腕', '練', 'フ', '公', '杯', '拠', '関', '緊', '館', '響', '則', '聖', '雄', '銀', '身', '縦', '正', '渡', 'ち', '譲', '寺', '価', '致', '淋', '産', '氾', 'ン', '終', '農', '柄', '売', '丈', '寒', '政', '存', '霧', '幌', '超', '寄', '凡', '折', '自', '排', '四', '腸', '扶', '救', '井', '援', '飾', '伴', '責', '欧', '似', 'う', '暗', '搬', '錨', '几', '涙', '買', '版', '省', '塩', '慰', '二', '借', '炎', '軒', '講', '楽', '施', '狭', '人', 'ヨ', '知', '房', '芸', '厚', '閉', '計', '妻', '警', '七', '皿', '努', '非', '園', '減', '破', '先', '両', '馬', '会', '格', '元', 'ょ', 'と', '低', '避', '里', '支', '連', '給', '手', '九', '辞', '心', '剤', '準', '餓', 'つ', '匹', '切', 'ア', '進', '叔', '軽', '板', '羽', '齢', '娘', '徴', '傘', '泣', '技', '面', '実', '静', '舶', 'ろ', '予', '窒', '民', '業', '俵', 'モ', '央', '耐', '縮', '端', '漆', '嬉', '査', '種', '郷', '変', '厳', '丁', '経', '報', '製', '卵', '濃', 'も', '強', '物', '沼', '繊', '下', '死', '虚', '門', '素', '飯', '線', '途', '舟', '甘', '話', '金', '隔', '困', '脅', '化', '村', '山', '特', '械', '綿', '繁', '仏', '太', '凍', '幸', '陥', '続', '座', '了', '今', '拷', '焼', '．', '源', '河', '収', '雰', '三', '邦', '略', '擦', '英', '血', '家', 'ノ', 'た', '志', '満', 'ャ', '解', '昇', '舞', '水', '背', '妬', '普', '雨', '隊', 'ホ', '系', '菌', '現', '咲', '免', '装', '鎮', '好', '記', '零', '月', '明', '婚', 'ら', '染', '毒', '慕', '道', '兼', '声', '総', '飄', '虜', '戦', '階', '営', '勝', '盤', '曇', '必', '徒', '筒', '涼', '怒', '畳', '服', '防', 'ス', '虫', '年', '社', '符', '落', '跡', '学', 'キ', '溜', '字', '臓', '高', '介', '片', '乳', '調', '催', '勉', '醜', '猫', '電', 'ツ', '節', '薄', '貿', '扇', '過', '波', '激', '塀', '俺', '絵', '秘', '母', '右', '枝', 'け', 'ァ', '竹', '男', '色', '沿', '功', 'ワ', '週', '酒', '様', '半', '語', '遺', '美', 'ユ', '東', '妙', '秋', '糸', '持', '観', '達', '脈', '法', '勇', '義', 'ル', '脚', '車', 'ミ', '分', '携', '恵', '兄', '逆', '度', '筆', 'コ', '徹', '親', '選', '左', '緒', '皮', '原', '側', '補', 'エ', 'シ', '確', '除', '養', '足', 'さ', '阪', '衛', '療', '痛', '監', '闇', '輪', '黒', '腹', '復', '質', '在', '御', '玄', '玉', '議', 'サ', '棚', '号', '固', '紋', '熊', '寝', '泊', '瓶', '企', '雲', '院', 'れ', '育', '含', '時', '夏', '星', '賞', '町', 'ん', '視', '悩', '撃', '族', 'ハ', '砂', '論', 'や', 'タ', '反', '早', '登', '」', '相', '起', '堂', '近', '攻', '街', '潜', '婦', 'て', '代'] vocabulary.\n"
     ]
    }
   ],
   "source": [
    "char_model.change_vocabulary(new_vocabulary=list(train_dev_set))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "69ffaf1a",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "nemo",
   "language": "python",
   "name": "nemo"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.12"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
