From ae589fb3ffdbf6c4bb1ae35345f7a3665deeebc5 Mon Sep 17 00:00:00 2001 From: Gustaf Rydholm Date: Tue, 23 Mar 2021 21:55:42 +0100 Subject: refactored emnist lines dataset --- notebooks/01-look-at-emnist.ipynb | 117 +++++++--------- notebooks/02b-emnist-lines-dataset.ipynb | 2 +- pyproject.toml | 1 + text_recognizer/datasets/base_data_module.py | 2 +- text_recognizer/datasets/base_dataset.py | 8 +- text_recognizer/datasets/emnist.py | 12 +- text_recognizer/datasets/emnist_essentials.json | 2 +- text_recognizer/datasets/emnist_lines.py | 172 ++++++++++++++++++------ text_recognizer/datasets/sentence_generator.py | 30 +++-- 9 files changed, 215 insertions(+), 131 deletions(-) diff --git a/notebooks/01-look-at-emnist.ipynb b/notebooks/01-look-at-emnist.ipynb index b70ce12..1f393db 100644 --- a/notebooks/01-look-at-emnist.ipynb +++ b/notebooks/01-look-at-emnist.ipynb @@ -2,9 +2,18 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The autoreload extension is already loaded. To reload it, use:\n", + " %reload_ext autoreload\n" + ] + } + ], "source": [ "%load_ext autoreload\n", "%autoreload 2\n", @@ -12,118 +21,88 @@ "%matplotlib inline\n", "import matplotlib.pyplot as plt\n", "import numpy as np\n", - "from PIL import Image\n", - "import torch\n", + "\n", "from importlib.util import find_spec\n", "if find_spec(\"text_recognizer\") is None:\n", " import sys\n", - " sys.path.append('..')" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "from text_recognizer.datasets import EmnistDataset" + " sys.path.append('..')\n", + "\n", + "from text_recognizer.datasets.emnist import EMNIST" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, - "outputs": [], - "source": [ - "dataset = EmnistDataset(train=False, sample_to_balance=True)" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "dataset.load_or_generate_data()" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "EMNIST Dataset\n", - "Num classes: 80\n", - "Input shape: [28, 28]\n", - "Mapping: {0: '0', 1: '1', 2: '2', 3: '3', 4: '4', 5: '5', 6: '6', 7: '7', 8: '8', 9: '9', 10: 'A', 11: 'B', 12: 'C', 13: 'D', 14: 'E', 15: 'F', 16: 'G', 17: 'H', 18: 'I', 19: 'J', 20: 'K', 21: 'L', 22: 'M', 23: 'N', 24: 'O', 25: 'P', 26: 'Q', 27: 'R', 28: 'S', 29: 'T', 30: 'U', 31: 'V', 32: 'W', 33: 'X', 34: 'Y', 35: 'Z', 36: 'a', 37: 'b', 38: 'c', 39: 'd', 40: 'e', 41: 'f', 42: 'g', 43: 'h', 44: 'i', 45: 'j', 46: 'k', 47: 'l', 48: 'm', 49: 'n', 50: 'o', 51: 'p', 52: 'q', 53: 'r', 54: 's', 55: 't', 56: 'u', 57: 'v', 58: 'w', 59: 'x', 60: 'y', 61: 'z', 62: ' ', 63: '!', 64: '\"', 65: '#', 66: '&', 67: \"'\", 68: '(', 69: ')', 70: '*', 71: '+', 72: ',', 73: '-', 74: '.', 75: '/', 76: ':', 77: ';', 78: '?', 79: None}\n", + "Num classes: 83\n", + "Mapping: ['', '', '', '

', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', ' ', '!', '\"', '#', '&', \"'\", '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '?']\n", + "Dims: (1, 28, 28)\n", + "Train/val/test sizes: 260276, 65070, 54028\n", + "Batch x stats: (torch.Size([128, 1, 28, 28]), torch.float32, tensor(0.), tensor(0.1715), tensor(0.3314), tensor(1.))\n", + "Batch y stats: (torch.Size([128]), torch.int64, tensor(4), tensor(65))\n", "\n" ] } ], "source": [ - "print(dataset)" + "data = EMNIST()\n", + "data.prepare_data()\n", + "data.setup()\n", + "print(data)" ] }, { "cell_type": "code", - "execution_count": 45, - "metadata": {}, - "outputs": [], - "source": [ - "def display_images(dataset, shift=0):\n", - " fig = plt.figure(figsize=(9, 9))\n", - " for i in range(9):\n", - " x, y = dataset[i + shift]\n", - " ax = fig.add_subplot(3, 3, i + 1)\n", - " x = x.squeeze(0).numpy()\n", - " ax.imshow(x, cmap='gray')\n", - " ax.set_xticks([])\n", - " ax.set_yticks([])\n", - " ax.set_title(dataset.mapper(int(y)))" - ] - }, - { - "cell_type": "code", - "execution_count": 46, + "execution_count": 4, "metadata": {}, "outputs": [ { - "data": { - "image/png": "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2LFDXo86N15NcuSM+MxSVFTksu985zsuU8Wm6dOnuywnJyeh61EFO1XeVWWlkydPRnqOsNejOktela/69Onjsp49e7pMnRG/c+dOl506dUpeD5o2VWLt1q2by+6++26XqYmeZrrAq9awytR7c4cOHSJdoyrJm1EqBAAAjYgNAQAAYEMAAADYEAAAAMuAUqGaIPWVr3zFZaNHj470tVGpYp6Z2ZYtW1xWUVHhshEjRrhs0qRJLps9e3ak51aFKjOzPXv2uKyqqsplFy9edBmT2lJDFQjnzJnjMlU6LSwsdFnUSYNhRdLTp0+7bNOmTS5TUwDPnz/vMnXUtypPPf744/J6JkyY4LKSkhKXqfKh+llMnDjRZep46OXLl8vr4XWRndSkT1XEe/jhh12mji+eOnWqy9QaNIs+mTNquVsVcFWZvmvXrvLrjx496rJkFA35hAAAALAhAAAAbAgAAICxIQAAAJbCUqEqIZmZDRw40GUPPvigy1S5QhU41BTAqEUpM7Mf/OAHLjt8+LDLevXq5bLvf//7LlMFqN69e0f6fma6dLZv3z6XqX+PmnJ46dIl+Tz448LKfg899JDLnn76aZdFPS5VrWs1QfPQoUPyel599VWXrVy50mW1tbWRnluVldR1f/e735XXo9b7k08+6bL777/fZarkpabGjR071mXvvfeevB5VwEVmUb93NUVQlQVVoVeV+Fq0aOGysKmc6nrUtFr1ulDvGypTpclUHGX+h/iEAAAAsCEAAABsCAAAgLEhAAAAlsJSoSrHmZktWLDAZapoqI48/eSTT1y2ZMkSl+3evdtlYYUsVd5SRasDBw647Hvf+57LVKFKTXSbMWOGvJ6ZM2dGeuzXvvY1l6mS14oVK1ymjsGFF3YUaY8ePVwW9bhU5cqVKy5TEzTDirEbNmxwmVrXifze1WuipqZGPlaV+FavXu0ydeyz+pmrqXFq0md+fn7k60F6hJXm1NHEzz77rMu6d+/usoKCApepYvlbb73lstdff11ej/r7NXToUJep170qHavXnppKe+7cOXk9jTVtk08IAAAAGwIAAMCGAAAAGBsCAABgKSwVdujQQebqWGM1FergwYMu++u//muXqfKVKmlFPaYyTNQpiarM9Td/8zcuU8fTmunJiaq4okpVjz76qMtUwVL9bCkaemFHkapjS9XR3FGnEqp19PLL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\n", - "text/plain": [ - "

" - ] - }, - "metadata": {}, - "output_type": "display_data" + "name": "stdout", + "output_type": "stream", + "text": [ + "torch.Size([128, 1, 28, 28]) torch.float32 tensor(0.) tensor(0.2204) tensor(0.3593) tensor(1.)\n", + "torch.Size([128]) torch.int64 tensor(4) tensor(4)\n" + ] } ], "source": [ - "display_images(dataset)" + "x, y = next(iter(data.test_dataloader()))\n", + "print(x.shape, x.dtype, x.min(), x.mean(), x.std(), x.max())\n", + "print(y.shape, y.dtype, y.min(), y.max())" ] }, { "cell_type": "code", - "execution_count": 47, + "execution_count": 5, "metadata": {}, "outputs": [ { "data": { - "image/png": "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\n", + "image/png": "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/vvvd9lZZ53lsqiprFqz16BBgzI95mmnneay6JK006dPd9nSpUtdRvNlda1Sw5FqjZW7iuo1aviVpE2bNmV6zOg11dbW5rLoMs2nnHKKy66++upwOz/84Q9dFq0aesABB7js9ttvd9mGDRvC7RRdK9dxI0QryP70pz912dixYzM9XrTS7JIlS8LbRq/TX/ziF5m2feaZZ7rsX//1X10WNUk3WpaPPI6RNEnSAjObV8muUnvx/sLMLpG0UtJ5dRkhkB81jFZAHaPQOpxQpJQelFRtkf2TajscoPaoYbQC6hhFx0qZAAAgNyYUAAAgt25z+fJoBb8tW7a4LGrsOv30010Wrd4nSZ///OddFjVg7rfffi6bNm2ay26++WaXRSu0ofVt3LjRZXPmzHFZ1LC4Zs0al916663hdrI2LW7dutVljz32mMuiFTD79Onjsg9/+MPhdo455hiXRSvfrlvnT9KZOXOmy8ralIna23vvvV0WrbgaNVUuXLjQZZ1ZmTXrv0nDhw932YABfnX1F154IfO264UjFAAAIDcmFAAAIDcmFAAAIDcmFAAAILdu05SZVdQs9s///M8u69u3b3j/d77znS7bfffdXbZ8+XKXXXPNNS5buXJluB10Py+++KLLvv71r7vsiSeecFlUb1HDopS9sSxqVItWpjz++ONdtv/++7ssWpFWkkaOHJlpPFHTKvCWqJFxn332yXTf6LUXNTVnXbm2M6JxR82kNGUCAICWwIQCAADkxoQCAADkxoQCAADk1m2aMqNmmWhVv2j1s8MPPzzzdl566SWX/e53v3PZN77xDZdVW30TkOJL1K9YscJlP/rRjzLdtx4NZA888IDLZsyY4bKzzjrLZVHzmRQ3W0ZZ9FwU4ZLOaLxotctoxdZqNberVatWuSxqfu6MHj16uGy33bL9H79fv365tl0vHKEAAAC5MaEAAAC5MaEAAAC5MaEAAAC5dTihMLPhZnavmS02s0Vm9oVKfo2ZrTazeZU//hrfQAFQwyg7ahhlkOUsj+2SvpxSeszM9pL0qJm9tWbvdSml79RveLUTdbT/4Q9/cFm01PXEiRMzbyc6S+Shhx5yWRGWSe1GWqKGs8q6dHY9RHX9la98xWXRmU+jR48OH3PRokUuW7x4scu2bt3qstWrV4ePWULdqobzGjp0qMsuv/xylz377LOZHu/mm292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\n", "text/plain": [ "
" ] }, - "metadata": {}, + "metadata": { + "needs_background": "light" + }, "output_type": "display_data" } ], "source": [ - "display_images(dataset, 9)" + "fig = plt.figure(figsize=(9, 9))\n", + "for i in range(9):\n", + " ax = fig.add_subplot(3, 3, i + 1)\n", + " rand_i = np.random.randint(len(data.data_test))\n", + " image, label = data.data_test[rand_i]\n", + " ax.imshow(image.reshape(28, 28), cmap='gray')\n", + " ax.set_title(data.mapping[label])" ] } ], @@ -143,7 +122,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.7.4" + "version": "3.9.1" } }, "nbformat": 4, diff --git a/notebooks/02b-emnist-lines-dataset.ipynb b/notebooks/02b-emnist-lines-dataset.ipynb index f82342b..7bc979d 100644 --- a/notebooks/02b-emnist-lines-dataset.ipynb +++ b/notebooks/02b-emnist-lines-dataset.ipynb @@ -322,7 +322,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.2" + "version": "3.9.1" } }, "nbformat": 4, diff --git a/pyproject.toml b/pyproject.toml index 33d539e..e9a41b4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,6 +71,7 @@ fail_under = 50 [tool.poetry.scripts] download-emnist = "text_recognizer.datasets.emnist:download_emnist" +generate-emnist-lines = "text_recognizer.datasets.emnist_lines:generate_emnist_lines" download-iam = "text_recognizer.datasets.iam_dataset:main" create-emnist-support-files = "text_recognizer.tests.support.create_emnist_support_files:create_emnist_support_files" create-emnist-lines-datasets = "text_recognizer.datasets.emnist_lines_dataset:create_datasets" diff --git a/text_recognizer/datasets/base_data_module.py b/text_recognizer/datasets/base_data_module.py index 830b39b..f5e7300 100644 --- a/text_recognizer/datasets/base_data_module.py +++ b/text_recognizer/datasets/base_data_module.py @@ -46,7 +46,7 @@ class BaseDataModule(pl.LightningDataModule): def setup(self, stage: str = None) -> None: """Split into train, val, test, and set dims. - + Should assign `torch Dataset` objects to self.data_train, self.data_val, and optionally self.data_test. diff --git a/text_recognizer/datasets/base_dataset.py b/text_recognizer/datasets/base_dataset.py index a004b8d..a9e9c24 100644 --- a/text_recognizer/datasets/base_dataset.py +++ b/text_recognizer/datasets/base_dataset.py @@ -61,13 +61,13 @@ def convert_strings_to_labels( strings: Sequence[str], mapping: Dict[str, int], length: int ) -> Tensor: """ - Convert a sequence of N strings to (N, length) ndarray, with each string wrapped with and tokens, - and padded wiht the

token. + Convert a sequence of N strings to (N, length) ndarray, with each string wrapped with and tokens, + and padded wiht the

token. """ - labels = torch.ones((len(strings), length), dtype=torch.long) * mapping["

"] + labels = torch.ones((len(strings), length), dtype=torch.long) * mapping["

"] for i, string in enumerate(strings): tokens = list(string) - tokens = ["", *tokens, ""] + tokens = ["", *tokens, ""] for j, token in enumerate(tokens): labels[i, j] = mapping[token] return labels diff --git a/text_recognizer/datasets/emnist.py b/text_recognizer/datasets/emnist.py index 7c208c4..66101b5 100644 --- a/text_recognizer/datasets/emnist.py +++ b/text_recognizer/datasets/emnist.py @@ -70,9 +70,11 @@ class EMNIST(BaseDataModule): if stage == "fit" or stage is None: with h5py.File(PROCESSED_DATA_FILENAME, "r") as f: self.x_train = f["x_train"][:] - self.y_train = f["y_train"][:] + self.y_train = f["y_train"][:].squeeze().astype(int) - dataset_train = BaseDataset(self.x_train, self.y_train, transform=self.transform) + dataset_train = BaseDataset( + self.x_train, self.y_train, transform=self.transform + ) train_size = int(self.train_fraction * len(dataset_train)) val_size = len(dataset_train) - train_size self.data_train, self.data_val = random_split( @@ -82,8 +84,10 @@ class EMNIST(BaseDataModule): if stage == "test" or stage is None: with h5py.File(PROCESSED_DATA_FILENAME, "r") as f: self.x_test = f["x_test"][:] - self.y_test = f["y_test"][:] - self.data_test = BaseDataset(self.x_test, self.y_test, transform=self.transform) + self.y_test = f["y_test"][:].squeeze().astype(int) + self.data_test = BaseDataset( + self.x_test, self.y_test, transform=self.transform + ) def __repr__(self) -> str: basic = f"EMNIST Dataset\nNum classes: {len(self.mapping)}\nMapping: {self.mapping}\nDims: {self.dims}\n" diff --git a/text_recognizer/datasets/emnist_essentials.json b/text_recognizer/datasets/emnist_essentials.json index 100b36a..3f46a73 100644 --- a/text_recognizer/datasets/emnist_essentials.json +++ b/text_recognizer/datasets/emnist_essentials.json @@ -1 +1 @@ -{"characters": ["", "", "", "

", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", " ", "!", "\"", "#", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", ":", ";", "?"], "input_shape": [28, 28]} \ No newline at end of file +{"characters": ["", "", "", "

", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", " ", "!", "\"", "#", "&", "'", "(", ")", "*", "+", ",", "-", ".", "/", ":", ";", "?"], "input_shape": [28, 28]} diff --git a/text_recognizer/datasets/emnist_lines.py b/text_recognizer/datasets/emnist_lines.py index ae23feb..9ebad22 100644 --- a/text_recognizer/datasets/emnist_lines.py +++ b/text_recognizer/datasets/emnist_lines.py @@ -1,16 +1,21 @@ """Dataset of generated text from EMNIST characters.""" from collections import defaultdict from pathlib import Path -from typing import Dict, Sequence +from typing import Callable, Dict, Tuple, Sequence import h5py from loguru import logger import numpy as np +from PIL import Image import torch from torchvision import transforms +from torchvision.transforms.functional import InterpolationMode -from text_recognizer.datasets.base_dataset import BaseDataset -from text_recognizer.datasets.base_data_module import BaseDataModule +from text_recognizer.datasets.base_dataset import BaseDataset, convert_strings_to_labels +from text_recognizer.datasets.base_data_module import ( + BaseDataModule, + load_and_print_info, +) from text_recognizer.datasets.emnist import EMNIST from text_recognizer.datasets.sentence_generator import SentenceGenerator @@ -54,18 +59,23 @@ class EMNISTLines(BaseDataModule): self.emnist = EMNIST() self.mapping = self.emnist.mapping - max_width = int(self.emnist.dims[2] * (self.max_length + 1) * (1 - self.min_overlap)) + IMAGE_X_PADDING - - if max_width <= IMAGE_WIDTH: - raise ValueError("max_width greater than IMAGE_WIDTH") + max_width = ( + int(self.emnist.dims[2] * (self.max_length + 1) * (1 - self.min_overlap)) + + IMAGE_X_PADDING + ) + + if max_width >= IMAGE_WIDTH: + raise ValueError( + f"max_width {max_width} greater than IMAGE_WIDTH {IMAGE_WIDTH}" + ) self.dims = ( self.emnist.dims[0], - self.emnist.dims[1], - self.emnist.dims[2] * self.max_length, + IMAGE_HEIGHT, + IMAGE_WIDTH ) - if self.max_length <= MAX_OUTPUT_LENGTH: + if self.max_length >= MAX_OUTPUT_LENGTH: raise ValueError("max_length greater than MAX_OUTPUT_LENGTH") self.output_dims = (MAX_OUTPUT_LENGTH, 1) @@ -77,8 +87,11 @@ class EMNISTLines(BaseDataModule): def data_filename(self) -> Path: """Return name of dataset.""" return ( - DATA_DIRNAME - / f"ml_{self.max_length}_o{self.min_overlap:f}_{self.max_overlap:f}_ntr{self.num_train}_ntv{self.num_val}_nte{self.num_test}_{self.with_start_end_tokens}.h5" + DATA_DIRNAME / (f"ml_{self.max_length}_" + f"o{self.min_overlap:f}_{self.max_overlap:f}_" + f"ntr{self.num_train}_" + f"ntv{self.num_val}_" + f"nte{self.num_test}.h5") ) def prepare_data(self) -> None: @@ -92,21 +105,28 @@ class EMNISTLines(BaseDataModule): def setup(self, stage: str = None) -> None: logger.info("EMNISTLinesDataset loading data from HDF5...") if stage == "fit" or stage is None: + print(self.data_filename) with h5py.File(self.data_filename, "r") as f: x_train = f["x_train"][:] y_train = torch.LongTensor(f["y_train"][:]) x_val = f["x_val"][:] y_val = torch.LongTensor(f["y_val"][:]) - self.data_train = BaseDataset(x_train, y_train, transform=_get_transform(augment=self.augment)) - self.data_val = BaseDataset(x_val, y_val, transform=_get_transform(augment=self.augment)) + self.data_train = BaseDataset( + x_train, y_train, transform=_get_transform(augment=self.augment) + ) + self.data_val = BaseDataset( + x_val, y_val, transform=_get_transform(augment=self.augment) + ) if stage == "test" or stage is None: with h5py.File(self.data_filename, "r") as f: x_test = f["x_test"][:] y_test = torch.LongTensor(f["y_test"][:]) - self.data_train = BaseDataset(x_test, y_test, transform=_get_transform(augment=False)) + self.data_test = BaseDataset( + x_test, y_test, transform=_get_transform(augment=False) + ) def __repr__(self) -> str: """Return str about dataset.""" @@ -132,53 +152,129 @@ class EMNISTLines(BaseDataModule): def _generate_data(self, split: str) -> None: logger.info(f"EMNISTLines generating data for {split}...") - sentence_generator = SentenceGenerator(self.max_length - 2) # Subtract by 2 because start/end token + sentence_generator = SentenceGenerator( + self.max_length - 2 + ) # Subtract by 2 because start/end token emnist = self.emnist emnist.prepare_data() emnist.setup() if split == "train": - samples_by_char = _get_samples_by_char(emnist.x_train, emnist.y_train, emnist.mapping) + samples_by_char = _get_samples_by_char( + emnist.x_train, emnist.y_train, emnist.mapping + ) num = self.num_train elif split == "val": - samples_by_char = _get_samples_by_char(emnist.x_train, emnist.y_train, emnist.mapping) + samples_by_char = _get_samples_by_char( + emnist.x_train, emnist.y_train, emnist.mapping + ) num = self.num_val - elif split == "test": - samples_by_char = _get_samples_by_char(emnist.x_test, emnist.y_test, emnist.mapping) + else: + samples_by_char = _get_samples_by_char( + emnist.x_test, emnist.y_test, emnist.mapping + ) num = self.num_test DATA_DIRNAME.mkdir(parents=True, exist_ok=True) - with h5py.File(self.data_filename, "w") as f: + with h5py.File(self.data_filename, "a") as f: x, y = _create_dataset_of_images( - num, samples_by_char, sentence_generator, self.min_overlap, self.max_overlap, self.dims - ) - y = _convert_strings_to_labels( - y, - emnist.inverse_mapping, - length=MAX_OUTPUT_LENGTH - ) + num, + samples_by_char, + sentence_generator, + self.min_overlap, + self.max_overlap, + self.dims, + ) + y = convert_strings_to_labels( + y, emnist.inverse_mapping, length=MAX_OUTPUT_LENGTH + ) f.create_dataset(f"x_{split}", data=x, dtype="u1", compression="lzf") f.create_dataset(f"y_{split}", data=y, dtype="u1", compression="lzf") -def _get_samples_by_char(samples: np.ndarray, labels: np.ndarray, mapping: Dict) -> defaultdict: + +def _get_samples_by_char( + samples: np.ndarray, labels: np.ndarray, mapping: Dict +) -> defaultdict: samples_by_char = defaultdict(list) for sample, label in zip(samples, labels): samples_by_char[mapping[label]].append(sample) return samples_by_char -def _construct_image_from_string(): - pass - - def _select_letter_samples_for_string(string: str, samples_by_char: defaultdict): - pass - - -def _create_dataset_of_images(num_samples: int, samples_by_char: defaultdict, sentence_generator: SentenceGenerator, min_overlap: float, max_overlap: float, dims: Tuple) -> Tuple[torch.Tensor, torch.Tensor]: + null_image = torch.zeros((28, 28), dtype=torch.uint8) + sample_image_by_char = {} + for char in string: + if char in sample_image_by_char: + continue + samples = samples_by_char[char] + sample = samples[np.random.choice(len(samples))] if samples else null_image + sample_image_by_char[char] = sample.reshape(28, 28) + return [sample_image_by_char[char] for char in string] + + +def _construct_image_from_string( + string: str, + samples_by_char: defaultdict, + min_overlap: float, + max_overlap: float, + width: int, +) -> torch.Tensor: + overlap = np.random.uniform(min_overlap, max_overlap) + sampled_images = _select_letter_samples_for_string(string, samples_by_char) + N = len(sampled_images) + H, W = sampled_images[0].shape + next_overlap_width = W - int(overlap * W) + concatenated_image = torch.zeros((H, width), dtype=torch.uint8) + x = IMAGE_X_PADDING + for image in sampled_images: + concatenated_image[:, x : (x + W)] += image + x += next_overlap_width + return torch.minimum(torch.Tensor([255]), concatenated_image) + + +def _create_dataset_of_images( + num_samples: int, + samples_by_char: defaultdict, + sentence_generator: SentenceGenerator, + min_overlap: float, + max_overlap: float, + dims: Tuple, +) -> Tuple[torch.Tensor, torch.Tensor]: images = torch.zeros((num_samples, IMAGE_HEIGHT, dims[2])) labels = [] for n in range(num_samples): label = sentence_generator.generate() - crop = _construct_image_from_string() + crop = _construct_image_from_string( + label, samples_by_char, min_overlap, max_overlap, dims[-1] + ) + height = crop.shape[0] + y = (IMAGE_HEIGHT - height) // 2 + images[n, y : (y + height), :] = crop + labels.append(label) + return images, labels + + +def _get_transform(augment: bool = False) -> Callable: + if not augment: + return transforms.Compose([transforms.ToTensor()]) + return transforms.Compose( + [ + transforms.ToTensor(), + transforms.ColorJitter(brightness=(0.5, 1.0)), + transforms.RandomAffine( + degrees=3, + translate=(0.0, 0.05), + scale=(0.4, 1.1), + shear=(-40, 50), + interpolation=InterpolationMode.BILINEAR, + fill=0, + ), + ] + ) + + +def generate_emnist_lines() -> None: + """Generates a synthetic handwritten dataset and displays info,""" + load_and_print_info(EMNISTLines) diff --git a/text_recognizer/datasets/sentence_generator.py b/text_recognizer/datasets/sentence_generator.py index dd76652..53b781c 100644 --- a/text_recognizer/datasets/sentence_generator.py +++ b/text_recognizer/datasets/sentence_generator.py @@ -11,7 +11,7 @@ import numpy as np from text_recognizer.datasets.util import DATA_DIRNAME -NLTK_DATA_DIRNAME = DATA_DIRNAME / "raw" / "nltk" +NLTK_DATA_DIRNAME = DATA_DIRNAME / "downloaded" / "nltk" class SentenceGenerator: @@ -47,18 +47,22 @@ class SentenceGenerator: raise ValueError( "Must provide max_length to this method or when making this object." ) - - index = np.random.randint(0, len(self.word_start_indices) - 1) - start_index = self.word_start_indices[index] - end_index_candidates = [] - for index in range(index + 1, len(self.word_start_indices)): - if self.word_start_indices[index] - start_index > max_length: - break - end_index_candidates.append(self.word_start_indices[index]) - end_index = np.random.choice(end_index_candidates) - sampled_text = self.corpus[start_index:end_index].strip() - padding = "_" * (max_length - len(sampled_text)) - return sampled_text + padding + + for _ in range(10): + try: + index = np.random.randint(0, len(self.word_start_indices) - 1) + start_index = self.word_start_indices[index] + end_index_candidates = [] + for index in range(index + 1, len(self.word_start_indices)): + if self.word_start_indices[index] - start_index > max_length: + break + end_index_candidates.append(self.word_start_indices[index]) + end_index = np.random.choice(end_index_candidates) + sampled_text = self.corpus[start_index:end_index].strip() + return sampled_text + except Exception: + pass + raise RuntimeError("Was not able to generate a valid string") def brown_corpus() -> str: -- cgit v1.2.3-70-g09d2