|
| 1 | +"""Routine for decoding the FER2013 binary file format.""" |
| 2 | + |
| 3 | +from __future__ import absolute_import |
| 4 | +from __future__ import division |
| 5 | +from __future__ import print_function |
| 6 | + |
| 7 | +import os |
| 8 | + |
| 9 | +from six.moves import xrange # pylint: disable=redefined-builtin |
| 10 | +import tensorflow as tf |
| 11 | + |
| 12 | +# Process images of this size. Original FER2013 image size is 48 x 48. |
| 13 | +IMAGE_SIZE = 32 |
| 14 | + |
| 15 | +# Global constants describing the FER2013 data set. |
| 16 | +NUM_CLASSES = 7 |
| 17 | +NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN = 28709 # The training set #50000 |
| 18 | +NUM_EXAMPLES_PER_EPOCH_FOR_EVAL = 3589 # The public test set #10000 |
| 19 | + |
| 20 | + |
| 21 | +def read_fer2013(filename_queue): |
| 22 | + """Reads and parses examples from FER2013 data files. |
| 23 | +
|
| 24 | + Recommendation: if you want N-way read parallelism, call this function |
| 25 | + N times. This will give you N independent Readers reading different |
| 26 | + files & positions within those files, which will give better mixing of |
| 27 | + examples. |
| 28 | +
|
| 29 | + Args: |
| 30 | + filename_queue: A queue of strings with the filenames to read from. |
| 31 | +
|
| 32 | + Returns: |
| 33 | + An object representing a single example, with the following fields: |
| 34 | + height: number of rows in the result (48) |
| 35 | + width: number of columns in the result (348) |
| 36 | + depth: number of color channels in the result (1) |
| 37 | + key: a scalar string Tensor describing the filename & record number |
| 38 | + for this example. |
| 39 | + label: an int32 Tensor with the label in the range 0..7. |
| 40 | + uint8image: a [height, width, depth] uint8 Tensor with the image data |
| 41 | + """ |
| 42 | + |
| 43 | + class FER2013Record(object): |
| 44 | + pass |
| 45 | + result = FER2013Record() |
| 46 | + |
| 47 | + label_bytes = 1 |
| 48 | + result.height = 48 |
| 49 | + result.width = 48 |
| 50 | + result.depth = 1 # 3 for RGB |
| 51 | + image_bytes = result.height * result.width * result.depth |
| 52 | + |
| 53 | + # Every record consists of a label followed by the image, with a |
| 54 | + # fixed number of bytes for each. |
| 55 | + record_bytes = label_bytes + image_bytes |
| 56 | + |
| 57 | + # Read a record, getting filenames from the filename_queue. No |
| 58 | + # header or footer in the FER2013 format, so we leave header_bytes |
| 59 | + # and footer_bytes at their default of 0. |
| 60 | + reader = tf.FixedLengthRecordReader(record_bytes=record_bytes) |
| 61 | + result.key, value = reader.read(filename_queue) |
| 62 | + |
| 63 | + # Convert from a string to a vector of uint8 that is record_bytes long. |
| 64 | + record_bytes = tf.decode_raw(value, tf.uint8) |
| 65 | + |
| 66 | + # The first bytes represent the label, which we convert from uint8->int32. |
| 67 | + result.label = tf.cast( |
| 68 | + tf.slice(record_bytes, [0], [label_bytes]), tf.int32) |
| 69 | + |
| 70 | + # The remaining bytes after the label represent the image, which we reshape |
| 71 | + # from [depth * height * width] to [depth, height, width]. |
| 72 | + depth_major = tf.reshape(tf.slice(record_bytes, [label_bytes], [image_bytes]), |
| 73 | + [result.depth, result.height, result.width]) |
| 74 | + # Convert from [depth, height, width] to [height, width, depth]. |
| 75 | + result.uint8image = tf.transpose(depth_major, [1, 2, 0]) |
| 76 | + |
| 77 | + return result |
| 78 | + |
| 79 | + |
| 80 | +def _generate_image_and_label_batch(image, label, min_queue_examples, |
| 81 | + batch_size): |
| 82 | + """Construct a queued batch of images and labels. |
| 83 | +
|
| 84 | + Args: |
| 85 | + image: 3-D Tensor of [height, width, 1] of type.float32. |
| 86 | + label: 1-D Tensor of type.int32 |
| 87 | + min_queue_examples: int32, minimum number of samples to retain |
| 88 | + in the queue that provides of batches of examples. |
| 89 | + batch_size: Number of images per batch. |
| 90 | +
|
| 91 | + Returns: |
| 92 | + images: Images. 4D tensor of [batch_size, height, width, 1] size. |
| 93 | + labels: Labels. 1D tensor of [batch_size] size. |
| 94 | + """ |
| 95 | + # Create a queue that shuffles the examples, and then |
| 96 | + # read 'batch_size' images + labels from the example queue. |
| 97 | + num_preprocess_threads = 16 |
| 98 | + images, label_batch = tf.train.shuffle_batch( |
| 99 | + [image, label], |
| 100 | + batch_size=batch_size, |
| 101 | + num_threads=num_preprocess_threads, |
| 102 | + capacity=min_queue_examples + 3 * batch_size, |
| 103 | + min_after_dequeue=min_queue_examples) |
| 104 | + |
| 105 | + # Display the training images in the visualizer. |
| 106 | + tf.image_summary('images', images) |
| 107 | + |
| 108 | + return images, tf.reshape(label_batch, [batch_size]) |
| 109 | + |
| 110 | + |
| 111 | +def distorted_inputs(data_dir, batch_size): |
| 112 | + """Construct distorted input for FER2013 training using the Reader ops. |
| 113 | +
|
| 114 | + Args: |
| 115 | + data_dir: Path to the FER2013 data directory. |
| 116 | + batch_size: Number of images per batch. |
| 117 | +
|
| 118 | + Returns: |
| 119 | + images: Images. 4D tensor of [batch_size, IMAGE_SIZE, IMAGE_SIZE, 3] size. |
| 120 | + labels: Labels. 1D tensor of [batch_size] size. |
| 121 | + """ |
| 122 | + |
| 123 | + filenames = [os.path.join(data_dir, 'fer2013.bin')] |
| 124 | + |
| 125 | + for f in filenames: |
| 126 | + if not tf.gfile.Exists(f): |
| 127 | + raise ValueError('Failed to find file: ' + f) |
| 128 | + |
| 129 | + # Create a queue that produces the filenames to read. |
| 130 | + filename_queue = tf.train.string_input_producer(filenames) |
| 131 | + |
| 132 | + # Read examples from files in the filename queue. |
| 133 | + read_input = read_fer2013(filename_queue) |
| 134 | + reshaped_image = tf.cast(read_input.uint8image, tf.float32) |
| 135 | + |
| 136 | + height = IMAGE_SIZE |
| 137 | + width = IMAGE_SIZE |
| 138 | + |
| 139 | + # 32 x 32 cropping. |
| 140 | + # Resizes an image to a target width and height by either centrally cropping the image |
| 141 | + # or padding it evenly with zeros. |
| 142 | + |
| 143 | + # distorted_image = tf.image.crop_to_bounding_box(reshaped_image, 12, 12, 24, 24) |
| 144 | + distorted_image = tf.image.resize_image_with_crop_or_pad(reshaped_image, width, height) |
| 145 | + |
| 146 | + # Because these operations are not commutative, consider randomizing |
| 147 | + # randomize the order their operation. |
| 148 | + distorted_image = tf.image.random_brightness(distorted_image, max_delta=63) |
| 149 | + distorted_image = tf.image.random_contrast(distorted_image, lower=0.2, upper=1.8) |
| 150 | + |
| 151 | + # Subtract off the mean and divide by the variance of the pixels. |
| 152 | + float_image = tf.image.per_image_whitening(distorted_image) |
| 153 | + |
| 154 | + # Ensure that the random shuffling has good mixing properties. |
| 155 | + min_fraction_of_examples_in_queue = 0.4 |
| 156 | + min_queue_examples = int(NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN * |
| 157 | + min_fraction_of_examples_in_queue) |
| 158 | + print ('Filling queue with %d FER2013 images before starting to train. ' |
| 159 | + 'This might take a few minutes.' % min_queue_examples) |
| 160 | + |
| 161 | + # Generate a batch of images and labels by building up a queue of examples. |
| 162 | + return _generate_image_and_label_batch(float_image, read_input.label, |
| 163 | + min_queue_examples, batch_size) |
| 164 | + |
| 165 | + |
| 166 | +def inputs(eval_data, data_dir, batch_size): |
| 167 | + """Construct input for FER2013 evaluation using the Reader ops. |
| 168 | +
|
| 169 | + Args: |
| 170 | + eval_data: bool, indicating if one should use the train or eval data set. |
| 171 | + data_dir: Path to the FER2013 data directory. |
| 172 | + batch_size: Number of images per batch. |
| 173 | +
|
| 174 | + Returns: |
| 175 | + images: Images. 4D tensor of [batch_size, IMAGE_SIZE, IMAGE_SIZE, 3] size. |
| 176 | + labels: Labels. 1D tensor of [batch_size] size. |
| 177 | + """ |
| 178 | + if not eval_data: |
| 179 | + filenames = [os.path.join(data_dir, 'fer2013.bin')] |
| 180 | + num_examples_per_epoch = NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN |
| 181 | + else: |
| 182 | + filenames = [os.path.join(data_dir, 'test_batch.bin')] |
| 183 | + num_examples_per_epoch = NUM_EXAMPLES_PER_EPOCH_FOR_EVAL |
| 184 | + |
| 185 | + print("Reading file:",filenames) |
| 186 | + |
| 187 | + for f in filenames: |
| 188 | + if not tf.gfile.Exists(f): |
| 189 | + raise ValueError('Failed to find file: ' + f) |
| 190 | + |
| 191 | + # Create a queue that produces the filenames to read. |
| 192 | + filename_queue = tf.train.string_input_producer(filenames) |
| 193 | + |
| 194 | + # Read examples from files in the filename queue. |
| 195 | + read_input = read_fer2013(filename_queue) |
| 196 | + reshaped_image = tf.cast(read_input.uint8image, tf.float32) |
| 197 | + |
| 198 | + height = IMAGE_SIZE |
| 199 | + width = IMAGE_SIZE |
| 200 | + |
| 201 | + # Image processing for evaluation. |
| 202 | + # Crop the central [height, width] of the image. |
| 203 | + resized_image = tf.image.resize_image_with_crop_or_pad(reshaped_image, |
| 204 | + width, height) |
| 205 | + |
| 206 | + # Subtract off the mean and divide by the variance of the pixels. |
| 207 | + float_image = tf.image.per_image_whitening(resized_image) |
| 208 | + |
| 209 | + # Ensure that the random shuffling has good mixing properties. |
| 210 | + min_fraction_of_examples_in_queue = 0.4 |
| 211 | + min_queue_examples = int(num_examples_per_epoch * |
| 212 | + min_fraction_of_examples_in_queue) |
| 213 | + |
| 214 | + # Generate a batch of images and labels by building up a queue of examples. |
| 215 | + return _generate_image_and_label_batch(float_image, read_input.label, |
| 216 | + min_queue_examples, batch_size) |
0 commit comments