# TensorFlow

TensorFlow has two types of APIs: Keras and tf. Keras and tf use different code for training and saving models, but the same code for inference.

#### Training a Model (Keras API)

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35

    from keras.models import Sequential
    model = Sequential()
    from keras.layers import Dense
    import tensorflow as tf

    # Import a training dataset.
    mnist = tf.keras.datasets.mnist
    (x_train, y_train),(x_test, y_test) = mnist.load_data()
    x_train, x_test = x_train / 255.0, x_test / 255.0

    print(x_train.shape)

    from keras.layers import Dense
    from keras.models import Sequential
    import keras
    from keras.layers import Dense, Activation, Flatten, Dropout

    # Define a model network.
    model = Sequential()
    model.add(Flatten(input_shape=(28,28)))
    model.add(Dense(units=5120,activation='relu'))
    model.add(Dropout(0.2))

    model.add(Dense(units=10, activation='softmax'))

    # Define an optimizer and loss functions.
    model.compile(optimizer='adam',
                  loss='sparse_categorical_crossentropy',
                  metrics=['accuracy'])

    model.summary()
    # Train the model.
    model.fit(x_train, y_train, epochs=2)
    # Evaluate the model.
    model.evaluate(x_test, y_test)

#### Saving a Model (Keras API)

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31

    from keras import backend as K

    # K.get_session().run(tf.global_variables_initializer())

    # Define the inputs and outputs of the prediction API.
    # The key values of the inputs and outputs dictionaries are used as the index keys for the input and output tensors of the model.
     # The input and output definitions of the model must match the custom inference script.
    predict_signature = tf.saved_model.signature_def_utils.predict_signature_def(
        inputs={"images" : model.input},
        outputs={"scores" : model.output}
    )

    # Define a save path.
    builder = tf.saved_model.builder.SavedModelBuilder('./mnist_keras/')

    builder.add_meta_graph_and_variables(

        sess = K.get_session(),
        # The tf.saved_model.tag_constants.SERVING tag needs to be defined for inference and deployment.
        tags=[tf.saved_model.tag_constants.SERVING],
        """
        signature_def_map: Only single items can exist, or the corresponding key needs to be defined as follows:
        tf.saved_model.signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY
        """
        signature_def_map={
            tf.saved_model.signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY:
                predict_signature
        }

    )
    builder.save()

#### Training a Model (tf API)

      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
     80
     81
     82
     83
     84
     85
     86
     87
     88
     89
     90
     91
     92
     93
     94
     95
     96
     97
     98
     99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225

    from __future__ import print_function

    import gzip
    import os
    import urllib

    import numpy
    import tensorflow as tf
    from six.moves import urllib

    # Training data is obtained from the Yann LeCun official website http://yann.lecun.com/exdb/mnist/.
    SOURCE_URL = 'http://yann.lecun.com/exdb/mnist/'
    TRAIN_IMAGES = 'train-images-idx3-ubyte.gz'
    TRAIN_LABELS = 'train-labels-idx1-ubyte.gz'
    TEST_IMAGES = 't10k-images-idx3-ubyte.gz'
    TEST_LABELS = 't10k-labels-idx1-ubyte.gz'
    VALIDATION_SIZE = 5000

    def maybe_download(filename, work_directory):
        """Download the data from Yann's website, unless it's already here."""
        if not os.path.exists(work_directory):
            os.mkdir(work_directory)
        filepath = os.path.join(work_directory, filename)
        if not os.path.exists(filepath):
            filepath, _ = urllib.request.urlretrieve(SOURCE_URL + filename, filepath)
            statinfo = os.stat(filepath)
            print('Successfully downloaded %s %d bytes.' % (filename, statinfo.st_size))
        return filepath

    def _read32(bytestream):
        dt = numpy.dtype(numpy.uint32).newbyteorder('>')
        return numpy.frombuffer(bytestream.read(4), dtype=dt)[0]

    def extract_images(filename):
        """Extract the images into a 4D uint8 numpy array [index, y, x, depth]."""
        print('Extracting %s' % filename)
        with gzip.open(filename) as bytestream:
            magic = _read32(bytestream)
            if magic != 2051:
                raise ValueError(
                    'Invalid magic number %d in MNIST image file: %s' %
                    (magic, filename))
            num_images = _read32(bytestream)
            rows = _read32(bytestream)
            cols = _read32(bytestream)
            buf = bytestream.read(rows * cols * num_images)
            data = numpy.frombuffer(buf, dtype=numpy.uint8)
            data = data.reshape(num_images, rows, cols, 1)
            return data

    def dense_to_one_hot(labels_dense, num_classes=10):
        """Convert class labels from scalars to one-hot vectors."""
        num_labels = labels_dense.shape[0]
        index_offset = numpy.arange(num_labels) * num_classes
        labels_one_hot = numpy.zeros((num_labels, num_classes))
        labels_one_hot.flat[index_offset + labels_dense.ravel()] = 1
        return labels_one_hot

    def extract_labels(filename, one_hot=False):
        """Extract the labels into a 1D uint8 numpy array [index]."""
        print('Extracting %s' % filename)
        with gzip.open(filename) as bytestream:
            magic = _read32(bytestream)
            if magic != 2049:
                raise ValueError(
                    'Invalid magic number %d in MNIST label file: %s' %
                    (magic, filename))
            num_items = _read32(bytestream)
            buf = bytestream.read(num_items)
            labels = numpy.frombuffer(buf, dtype=numpy.uint8)
            if one_hot:
                return dense_to_one_hot(labels)
            return labels

    class DataSet(object):
        """Class encompassing test, validation and training MNIST data set."""

        def __init__(self, images, labels, fake_data=False, one_hot=False):
            """Construct a DataSet. one_hot arg is used only if fake_data is true."""

            if fake_data:
                self._num_examples = 10000
                self.one_hot = one_hot
            else:
                assert images.shape[0] == labels.shape[0], (
                        'images.shape: %s labels.shape: %s' % (images.shape,
                                                               labels.shape))
                self._num_examples = images.shape[0]

                # Convert shape from [num examples, rows, columns, depth]
                # to [num examples, rows*columns] (assuming depth == 1)
                assert images.shape[3] == 1
                images = images.reshape(images.shape[0],
                                        images.shape[1] * images.shape[2])
                # Convert from [0, 255] -> [0.0, 1.0].
                images = images.astype(numpy.float32)
                images = numpy.multiply(images, 1.0 / 255.0)
            self._images = images
            self._labels = labels
            self._epochs_completed = 0
            self._index_in_epoch = 0

        @property
        def images(self):
            return self._images

        @property
        def labels(self):
            return self._labels

        @property
        def num_examples(self):
            return self._num_examples

        @property
        def epochs_completed(self):
            return self._epochs_completed

        def next_batch(self, batch_size, fake_data=False):
            """Return the next `batch_size` examples from this data set."""
            if fake_data:
                fake_image = [1] * 784
                if self.one_hot:
                    fake_label = [1] + [0] * 9
                else:
                    fake_label = 0
                return [fake_image for _ in range(batch_size)], [
                    fake_label for _ in range(batch_size)
                ]
            start = self._index_in_epoch
            self._index_in_epoch += batch_size
            if self._index_in_epoch > self._num_examples:
                # Finished epoch
                self._epochs_completed += 1
                # Shuffle the data
                perm = numpy.arange(self._num_examples)
                numpy.random.shuffle(perm)
                self._images = self._images[perm]
                self._labels = self._labels[perm]
                # Start next epoch
                start = 0
                self._index_in_epoch = batch_size
                assert batch_size <= self._num_examples
            end = self._index_in_epoch
            return self._images[start:end], self._labels[start:end]

    def read_data_sets(train_dir, fake_data=False, one_hot=False):
        """Return training, validation and testing data sets."""

        class DataSets(object):
            pass

        data_sets = DataSets()

        if fake_data:
            data_sets.train = DataSet([], [], fake_data=True, one_hot=one_hot)
            data_sets.validation = DataSet([], [], fake_data=True, one_hot=one_hot)
            data_sets.test = DataSet([], [], fake_data=True, one_hot=one_hot)
            return data_sets

        local_file = maybe_download(TRAIN_IMAGES, train_dir)
        train_images = extract_images(local_file)

        local_file = maybe_download(TRAIN_LABELS, train_dir)
        train_labels = extract_labels(local_file, one_hot=one_hot)

        local_file = maybe_download(TEST_IMAGES, train_dir)
        test_images = extract_images(local_file)

        local_file = maybe_download(TEST_LABELS, train_dir)
        test_labels = extract_labels(local_file, one_hot=one_hot)

        validation_images = train_images[:VALIDATION_SIZE]
        validation_labels = train_labels[:VALIDATION_SIZE]
        train_images = train_images[VALIDATION_SIZE:]
        train_labels = train_labels[VALIDATION_SIZE:]

        data_sets.train = DataSet(train_images, train_labels)
        data_sets.validation = DataSet(validation_images, validation_labels)
        data_sets.test = DataSet(test_images, test_labels)
        return data_sets

    training_iteration = 1000

    modelarts_example_path =  './modelarts-mnist-train-save-deploy-example'

    export_path = modelarts_example_path + '/model/'
    data_path = './'

    print('Training model...')
    mnist = read_data_sets(data_path, one_hot=True)
    sess = tf.InteractiveSession()
    serialized_tf_example = tf.placeholder(tf.string, name='tf_example')
    feature_configs = {'x': tf.FixedLenFeature(shape=[784], dtype=tf.float32), }
    tf_example = tf.parse_example(serialized_tf_example, feature_configs)
    x = tf.identity(tf_example['x'], name='x')  # use tf.identity() to assign name
    y_ = tf.placeholder('float', shape=[None, 10])
    w = tf.Variable(tf.zeros([784, 10]))
    b = tf.Variable(tf.zeros([10]))
    sess.run(tf.global_variables_initializer())
    y = tf.nn.softmax(tf.matmul(x, w) + b, name='y')
    cross_entropy = -tf.reduce_sum(y_ * tf.log(y))
    train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
    values, indices = tf.nn.top_k(y, 10)
    table = tf.contrib.lookup.index_to_string_table_from_tensor(
        tf.constant([str(i) for i in range(10)]))
    prediction_classes = table.lookup(tf.to_int64(indices))
    for _ in range(training_iteration):
        batch = mnist.train.next_batch(50)
        train_step.run(feed_dict={x: batch[0], y_: batch[1]})
    correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, 'float'))
    print('training accuracy %g' % sess.run(
        accuracy, feed_dict={
            x: mnist.test.images,
            y_: mnist.test.labels
        }))
    print('Done training!')

#### Saving a Model (tf API)

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30

    # Export the model.
    # The model needs to be saved using the saved_model API.
    print('Exporting trained model to', export_path)
    builder = tf.saved_model.builder.SavedModelBuilder(export_path)

    tensor_info_x = tf.saved_model.utils.build_tensor_info(x)
    tensor_info_y = tf.saved_model.utils.build_tensor_info(y)

    # Define the inputs and outputs of the prediction API.
    # The key values of the inputs and outputs dictionaries are used as the index keys for the input and output tensors of the model.
     # The input and output definitions of the model must match the custom inference script.
    prediction_signature = (
        tf.saved_model.signature_def_utils.build_signature_def(
            inputs={'images': tensor_info_x},
            outputs={'scores': tensor_info_y},
            method_name=tf.saved_model.signature_constants.PREDICT_METHOD_NAME))

    legacy_init_op = tf.group(tf.tables_initializer(), name='legacy_init_op')
    builder.add_meta_graph_and_variables(
        # Set tag to serve/tf.saved_model.tag_constants.SERVING.
        sess, [tf.saved_model.tag_constants.SERVING],
        signature_def_map={
            'predict_images':
                prediction_signature,
        },
        legacy_init_op=legacy_init_op)

    builder.save()

    print('Done exporting!')

#### Inference Code (Keras and tf APIs)

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38

    from PIL import Image
    import numpy as np
    from model_service.tfserving_model_service import TfServingBaseService

    class mnist_service(TfServingBaseService):

        # Match the model input with the user's HTTPS API input during preprocessing.
        # The model input corresponding to the preceding training part is {"images":<array>}.
        def _preprocess(self, data):

            preprocessed_data = {}
            images = []
            # Iterate the input data.
            for k, v in data.items():
                for file_name, file_content in v.items():
                    image1 = Image.open(file_content)
                    image1 = np.array(image1, dtype=np.float32)
                    image1.resize((1,784))
                    images.append(image1)
            # Return the numpy array.
            images = np.array(images,dtype=np.float32)
            # Perform batch processing on multiple input samples and ensure that the shape is the same as that inputted during training.
            images.resize((len(data), 784))
            preprocessed_data['images'] = images
            return preprocessed_data

        # Processing logic of the inference for invoking the parent class.

        # The output corresponding to model saving in the preceding training part is {"scores":<array>}.
        # Postprocess the HTTPS output.
        def _postprocess(self, data):
            infer_output = {"mnist_result": []}
            # Iterate the model output.
            for output_name, results in data.items():
                for result in results:
                    infer_output["mnist_result"].append(result.index(max(result)))
            return infer_output

Parent topic: Examples of Custom Scripts