supervised_reptile/omniglot.py (40 lines of code) (raw):
"""
Loading and augmenting the Omniglot dataset.
To use these APIs, you should prepare a directory that
contains all of the alphabets from both images_background
and images_evaluation.
"""
import os
import random
from PIL import Image
import numpy as np
def read_dataset(data_dir):
"""
Iterate over the characters in a data directory.
Args:
data_dir: a directory of alphabet directories.
Returns:
An iterable over Characters.
The dataset is unaugmented and not split up into
training and test sets.
"""
for alphabet_name in sorted(os.listdir(data_dir)):
alphabet_dir = os.path.join(data_dir, alphabet_name)
if not os.path.isdir(alphabet_dir):
continue
for char_name in sorted(os.listdir(alphabet_dir)):
if not char_name.startswith('character'):
continue
yield Character(os.path.join(alphabet_dir, char_name), 0)
def split_dataset(dataset, num_train=1200):
"""
Split the dataset into a training and test set.
Args:
dataset: an iterable of Characters.
Returns:
A tuple (train, test) of Character sequences.
"""
all_data = list(dataset)
random.shuffle(all_data)
return all_data[:num_train], all_data[num_train:]
def augment_dataset(dataset):
"""
Augment the dataset by adding 90 degree rotations.
Args:
dataset: an iterable of Characters.
Returns:
An iterable of augmented Characters.
"""
for character in dataset:
for rotation in [0, 90, 180, 270]:
yield Character(character.dir_path, rotation=rotation)
# pylint: disable=R0903
class Character:
"""
A single character class.
"""
def __init__(self, dir_path, rotation=0):
self.dir_path = dir_path
self.rotation = rotation
self._cache = {}
def sample(self, num_images):
"""
Sample images (as numpy arrays) from the class.
Returns:
A sequence of 28x28 numpy arrays.
Each pixel ranges from 0 to 1.
"""
names = [f for f in os.listdir(self.dir_path) if f.endswith('.png')]
random.shuffle(names)
images = []
for name in names[:num_images]:
images.append(self._read_image(os.path.join(self.dir_path, name)))
return images
def _read_image(self, path):
if path in self._cache:
return self._cache[path]
with open(path, 'rb') as in_file:
img = Image.open(in_file).resize((28, 28)).rotate(self.rotation)
self._cache[path] = np.array(img).astype('float32')
return self._cache[path]