Full Code of visipedia/tf_classification for AI

master 7dac8bb3a419 cached
47 files
397.8 KB
103.3k tokens
192 symbols
1 requests
Download .txt
Showing preview only (415K chars total). Download the full file or copy to clipboard to get everything.
Repository: visipedia/tf_classification
Branch: master
Commit: 7dac8bb3a419
Files: 47
Total size: 397.8 KB

Directory structure:
gitextract_pxfoh05k/

├── .gitignore
├── LICENSE
├── README.md
├── classify.py
├── config/
│   ├── README.md
│   ├── __init__.py
│   ├── config_classify.yaml
│   ├── config_export.yaml
│   ├── config_test.yaml
│   ├── config_train.yaml
│   └── parse_config.py
├── export.py
├── extract.py
├── nets/
│   ├── README.md
│   ├── __init__.py
│   ├── inception.py
│   ├── inception_resnet_v2.py
│   ├── inception_resnet_v2_test.py
│   ├── inception_utils.py
│   ├── inception_v1.py
│   ├── inception_v1_test.py
│   ├── inception_v2.py
│   ├── inception_v2_test.py
│   ├── inception_v3.py
│   ├── inception_v3_test.py
│   ├── inception_v4.py
│   ├── inception_v4_test.py
│   ├── mobilenet_v1.py
│   ├── mobilenet_v1_test.py
│   ├── net_profile.py
│   ├── nets_factory.py
│   ├── nets_factory_test.py
│   ├── resnet_utils.py
│   ├── resnet_v2.py
│   └── resnet_v2_test.py
├── preprocessing/
│   ├── __init__.py
│   ├── decode_example.py
│   └── inputs.py
├── requirements.txt
├── test.py
├── tfserving/
│   ├── README.md
│   ├── __init__.py
│   ├── client.py
│   ├── inputs.py
│   └── tfserver.py
├── train.py
└── visualize_train_inputs.py

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# IPython Notebook
.ipynb_checkpoints

# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# dotenv
.env

# virtualenv
venv/
ENV/

# Spyder project settings
.spyderproject

# Rope project settings
.ropeproject

# Mac stuff
.DS_Store

# Visual Studio Code stuff
.vscode/

================================================
FILE: LICENSE
================================================
MIT License

Copyright (c) 2017 Visipedia

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.


================================================
FILE: README.md
================================================
# TensorFlow Classification
This repo contains training, testing and classifcation code for image classification using [TensorFlow](https://www.tensorflow.org/). Whole image classification as well as multi instance bounding box classification is supported. 

Checkout the [Wiki](https://github.com/visipedia/tf_classification/wiki) for more detailed tutorials. 

---

## Requirements
TensorFlow 1.0+ is required. The code is tested with TensorFlow 1.3 and Python 2.7 on Ubuntu 16.04 and Mac OSX 10.11. Check out the [requirements.txt](requirements.txt) file for a list of python dependencies. 

---

## Prepare the Data
The models require the image data to be in a specific format. You can use the Visipedia [tfrecords repo](https://github.com/visipedia/tfrecords) to produce the files. 

For the commands below, I'll assume that you have created a `DATASET_DIR` environment variable that points to the directory that contains your tfrecords:
```
$ export DATASET_DIR=/home/ubuntu/tf_datasets/cub
```

---

## Directory Structure
I have found that its useful to have the following directory and file setup:
* experiment/
  * logdir/
    * train_summaries/
    * val_summaries/
    * test_summaries/
    * results/
    * finetune/
      * train_summaries/
      * val_summaries/
  * cmds.txt
  * config_train.yaml
  * config_test.yaml
  * config_export.yaml

The purpose of each directory and file will be explained below. 

The `cmds.txt` is useful to save the different training and testing commands. There are quite a few command-line arguments to some of the scripts, so its convienent to compose the commands in an editor. 

For the commands below, I'll assume that you have created a `EXPERIMENT_DIR` environment variable that points to your experiment directory:
```
$ export EXPERIMENT_DIR=/home/ubuntu/tf_experiments/cub
```

---

## Configuration
There are example configuration files in the [config directory](config/). At the very least you'll need a `config_train.yaml` file, and you'll probably want a `config_test.yaml` file. It is convienent to copy the example configuration files into your `experiment` directory. See the configuration [README](config/README.md) for more details.

### Choose a Network Architecture
This repo currently supports the Google Inception, ResNet and MobileNet flavor of networks. See the nets [README](nets/README.md) for more information on the different Inception versions. At the moment, `inception_v3` probably offers the best tradeoff in terms of size and performance, although its always worth experimenting with a few different architectures. The [README](nets/README.md) also contains links where you can download checkpoint files for the models. In most cases you should start your training from these checkpoint files rather than training from scratch. 

You can specify the name of the choosen network in the configuration yaml file. Alternatively you can pass it in as a command-line argument to most of the scripts. 

For the commands below, I'll assume that you have created an environment variable that points to the pretrained checkpoint file that you downloaded:
```
$ export PRETRAINED_MODEL=/home/ubuntu/tf_models/inception_v3.ckpt
```

---

## Data Visualization
Now that you have a configuration script for training, it is a good idea to visualize the inputs to the network and ensure that they look good. This allows you to debug any problems with your tfrecords and lets you play with different augmentation techniques. Visualize your data by doing:
```
$ CUDA_VISIBLE_DEVICES=1 python visualize_train_inputs.py \
--tfrecords $DATASET_DIR/train* \
--config $EXPERIMENT_DIR/config_train.yaml
```

If you are in a virtualenv and Matplotlib is complaining, then you may need to modify your environment. See this [FAQ](http://matplotlib.org/faq/virtualenv_faq.html) and [this document](http://matplotlib.org/faq/osx_framework.html#osxframework-faq) for fixing this issue. I use a virtualenv on my Mac OSX 10.11 machine and I needed to do the `PYTHONHOME` [work around](http://matplotlib.org/faq/osx_framework.html#pythonhome-function) for Matplotlib to work properly. In this case the command looks like:
```
$ CUDA_VISIBLE_DEVICES=1 frameworkpython visualize_train_inputs.py \
--tfrecords $DATASET_DIR/train* \
--config $EXPERIMENT_DIR/config_train.yaml
```

---

## Training and Validating
It's recommended to start from a pretrained network when training a network on your own data. However, this isn't necessary and you can train from scratch if you have enough data. The following warmup section assumes you are starting from a pretrained network. See the nets [README](nets/README.md) to find links to pretrained checkpoint files.

### Finetune A Pretrained Network
Finetuning a pretrained network essentially uses the pretrained network as a generic feature extractor and learns a new final layer that will output predictions for your target classes (rather than the original classes that the pretrained network was trained on). To do this, we will specify the pretrained model as the starting point, and only allow the logits layers to be modified. We can put the trained models in the `experiment/logdir/finetune` directory. 

```
$ CUDA_VISIBLE_DEVICES=0 python train.py \
--tfrecords $DATASET_DIR/train* \
--logdir $EXPERIMENT_DIR/logdir/finetune \
--config $EXPERIMENT_DIR/config_train.yaml \
--pretrained_model $PRETRAINED_MODEL \
--trainable_scopes InceptionV3/Logits InceptionV3/AuxLogits \
--checkpoint_exclude_scopes InceptionV3/Logits InceptionV3/AuxLogits \
--learning_rate_decay_type fixed \
--lr 0.01 
```

#### Monitoring Progress
We'll want to monitor performance of the model on a validation set. Once the model performance starts to plateau we can assume that the final layer is warmed up and we can switch to full training. We can monitor the validation performance by running:
```
$ CUDA_VISIBLE_DEVICES=1 python test.py \
--tfrecords $DATASET_DIR/val* \
--save_dir $EXPERIMENT_DIR/logdir/finetune/val_summaries \
--checkpoint_path $EXPERIMENT_DIR/logdir/finetune \
--config $EXPERIMENT_DIR/config_test.yaml \
--batches 100 \
--eval_interval_secs 300
```

You may want to also monitor the accuracy on the train set. Simply pass in the train tfrecords to the `test.py` script and change the output directory:
```
$ CUDA_VISIBLE_DEVICES=1 python test.py \
--tfrecords $DATASET_DIR/train* \
--save_dir $EXPERIMENT_DIR/logdir/finetune/train_summaries \
--checkpoint_path $EXPERIMENT_DIR/logdir/finetune \
--config $EXPERIMENT_DIR/config_test.yaml \
--batches 100 \
--eval_interval_secs 300
```

Keeping the train summaries and val summaries in separate directories will keep the tensorboard ui clean. To monitor the training process you can fireup tensorboard:
```
$ tensorboard --logdir=$EXPERIMENT_DIR/logdir --port=6006
```

### Training the Entire Network
The benefit of finetuning a network is that the training is very fast, as only the last layer is modified. However, to get the best performance you'll typically want to modify more (or all) of the layers of the network. Starting from a pretrained network (which can happen to be a finetuned network), this full training step essentially adapts the network to operating on the domain of your specific dataset.  We'll store the generated files in the `experiment/logdir` directory. You can do the finetuning process as a warmup and then start the full train:
```
$ CUDA_VISIBLE_DEVICES=0 python train.py \
--tfrecords $DATASET_DIR/train* \
--logdir $EXPERIMENT_DIR/logdir \
--config $EXPERIMENT_DIR/config_train.yaml \
--pretrained_model $EXPERIMENT_DIR/logdir/finetune
```

Or you can just start the full train from a pretrained model:
```
$ CUDA_VISIBLE_DEVICES=0 python train.py \
--tfrecords $DATASET_DIR/train* \
--logdir $EXPERIMENT_DIR/logdir \
--config $EXPERIMENT_DIR/config_train.yaml \
--pretrained_model $PRETRAINED_MODEL \
--checkpoint_exclude_scopes InceptionV3/Logits InceptionV3/AuxLogits
```

Or if you have enough data, you may not want to even use the pretrained model. Rather you can train from scratch:
```
$ CUDA_VISIBLE_DEVICES=0 python train.py \
--tfrecords $DATASET_DIR/train* \
--logdir $EXPERIMENT_DIR/logdir/ \
--config $EXPERIMENT_DIR/config_train.yaml
``` 

#### Monitoring Progress

For watching the validation performance we can do:
```
$ CUDA_VISIBLE_DEVICES=1 python test.py \
--tfrecords $DATASET_DIR/val* \
--save_dir $EXPERIMENT_DIR/logdir/val_summaries \
--checkpoint_path $EXPERIMENT_DIR/logdir \
--config $EXPERIMENT_DIR/config_test.yaml \
--batches 100 \
--eval_interval_secs 300
```

Similar for the train data: 
```
$ CUDA_VISIBLE_DEVICES=1 python test.py \
--tfrecords $DATASET_DIR/train* \
--save_dir $EXPERIMENT_DIR/train_summaries \
--checkpoint_path $EXPERIMENT_DIR/logdir \
--config $EXPERIMENT_DIR/config_test.yaml \
--batches 100 \
--eval_interval_secs 300
```

The command for tensorboard doesn't need to change:
```
$ tensorboard --logdir=$EXPERIMENT_DIR/logdir --port=6006
```
You will be able to see the fine-tune and the full train data plotted on the same plots. 

---

## Test
Once performance on the validation data has plateaued (or some other criterion has been met), you can test the model on a held out set of images to see how well it generalizes to new data:
```
$ CUDA_VISIBLE_DEVICES=1 python test.py \
--tfrecords $DATASET_DIR/test* \
--save_dir $EXPERIMENT_DIR/logdir/test_summaries \
--checkpoint_path $EXPERIMENT_DIR/logdir \
--config $EXPERIMENT_DIR/config_test.yaml \
--batch_size 32 \
--batches 100
```

If you are happy with the performance of the model, then you are ready to classify new images and export the model for production use. Otherwise its back to the drawing board to figure out how to increase performance. 

---

## Classifying 
If you want to classify data offline using the trained model then you can do:
```
CUDA_VISIBLE_DEVICES=1 python classify.py \
--tfrecords $DATASET_DIR/new/* \
--checkpoint_path $EXPERIMENT_DIR/logdir \
--save_path $EXPERIMENT_DIR/logdir/results/classification_results.npz \
--config $EXPERIMENT_DIR/config_test.yaml \
--batch_size 32 \
--batches 1000 \
--save_logits
```

The output of the script is a numpy uncompressed .npz file saved at `--save_path`. The file will contain at least 2 arrays: one that contains ids and one that contains the predicted class label. If `--save_logits` is specified, then the raw logits (before going through the softmax) will also be saved. 

---

## Export & Compress
To export a model for easy use on a mobile device you can use:
```
python export.py \
--checkpoint_path model.ckpt-399739 \
--export_dir ./export \
--export_version 1 \
--config config_export.yaml \
--class_names class-codes.txt
```
The input node is called `images` and the output node is called `Predictions`. Checkout [this](https://github.com/visipedia/tf_classification/wiki/Exporting-an-Optimized-Model) wiki article for more tips. 

If you are going to use the model with [TensorFlow Serving](https://www.tensorflow.org/deploy/tfserve) then you can use the following:
```
python export.py \
--checkpoint_path model.ckpt-399739 \
--export_dir ./export \
--export_version 1 \
--config config_export.yaml \
--serving \
--add_preprocess \
--class_names class-codes.txt
```
Check out the resources in the [tfserving](tfserving/) directory for more help with deploying on TensorFlow Serving.


================================================
FILE: classify.py
================================================
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import argparse
import os
import time

import numpy as np
import tensorflow as tf
import tensorflow.contrib.slim as slim

from config.parse_config import parse_config_file
from nets import nets_factory
from preprocessing import inputs

def classify(tfrecords, checkpoint_path, save_path, max_iterations, save_logits, cfg, read_images=False):
    """
    Args:
        tfrecords (list)
        checkpoint_path (str)
        save_dir (str)
        max_iterations (int)
        save_logits (bool)
        cfg (EasyDict)
    """
    tf.logging.set_verbosity(tf.logging.DEBUG)

    graph = tf.Graph()

    with graph.as_default():

        global_step = slim.get_or_create_global_step()

        with tf.device('/cpu:0'):
            batch_dict = inputs.input_nodes(
                tfrecords=tfrecords,
                cfg=cfg.IMAGE_PROCESSING,
                num_epochs=1,
                batch_size=cfg.BATCH_SIZE,
                num_threads=cfg.NUM_INPUT_THREADS,
                shuffle_batch =cfg.SHUFFLE_QUEUE,
                random_seed=cfg.RANDOM_SEED,
                capacity=cfg.QUEUE_CAPACITY,
                min_after_dequeue=cfg.QUEUE_MIN,
                add_summaries=False,
                input_type='classification',
                read_filenames=read_images
            )

        arg_scope = nets_factory.arg_scopes_map[cfg.MODEL_NAME]()

        with slim.arg_scope(arg_scope):
            logits, end_points = nets_factory.networks_map[cfg.MODEL_NAME](
                inputs=batch_dict['inputs'],
                num_classes=cfg.NUM_CLASSES,
                is_training=False
            )

            predicted_labels = tf.argmax(end_points['Predictions'], 1)

        if 'MOVING_AVERAGE_DECAY' in cfg and cfg.MOVING_AVERAGE_DECAY > 0:
            variable_averages = tf.train.ExponentialMovingAverage(
                cfg.MOVING_AVERAGE_DECAY, global_step)
            variables_to_restore = variable_averages.variables_to_restore(
                slim.get_model_variables())
            variables_to_restore[global_step.op.name] = global_step
        else:
            variables_to_restore = slim.get_variables_to_restore()
            variables_to_restore.append(global_step)

        saver = tf.train.Saver(variables_to_restore, reshape=True)

        num_batches = max_iterations
        num_images = num_batches * cfg.BATCH_SIZE
        label_array = np.empty(num_images, dtype=np.int32)
        id_array = np.empty(num_images, dtype=np.object)
        fetches = [predicted_labels, batch_dict['ids']]
        if save_logits:
            fetches.append(logits)
            logits_array = np.empty((num_images, cfg.NUM_CLASSES), dtype=np.float32)

        if os.path.isdir(checkpoint_path):
            checkpoint_dir = checkpoint_path
            checkpoint_path = tf.train.latest_checkpoint(checkpoint_dir)

            if checkpoint_path is None:
                raise ValueError("Unable to find a model checkpoint in the " \
                                 "directory %s" % (checkpoint_dir,))

        tf.logging.info('Classifying records using %s' % checkpoint_path)

        coord = tf.train.Coordinator()

        sess_config = tf.ConfigProto(
                log_device_placement=cfg.SESSION_CONFIG.LOG_DEVICE_PLACEMENT,
                allow_soft_placement = True,
                gpu_options = tf.GPUOptions(
                    per_process_gpu_memory_fraction=cfg.SESSION_CONFIG.PER_PROCESS_GPU_MEMORY_FRACTION
                ),
                intra_op_parallelism_threads=cfg.SESSION_CONFIG.INTRA_OP_PARALLELISM_THREADS if 'INTRA_OP_PARALLELISM_THREADS' in cfg.SESSION_CONFIG else None,
                inter_op_parallelism_threads=cfg.SESSION_CONFIG.INTER_OP_PARALLELISM_THREADS if 'INTER_OP_PARALLELISM_THREADS' in cfg.SESSION_CONFIG else None
            )
        sess = tf.Session(graph=graph, config=sess_config)

        with sess.as_default():

            tf.global_variables_initializer().run()
            tf.local_variables_initializer().run()
            threads = tf.train.start_queue_runners(sess=sess, coord=coord)

            try:

                # Restore from checkpoint
                saver.restore(sess, checkpoint_path)

                print_str = ', '.join([
                  'Step: %d',
                  'Time/image (ms): %.1f'
                ])

                step = 0
                while not coord.should_stop():

                    t = time.time()
                    outputs = sess.run(fetches)
                    dt = time.time()-t

                    idx1 = cfg.BATCH_SIZE * step
                    idx2 = idx1 + cfg.BATCH_SIZE
                    label_array[idx1:idx2] = outputs[0]
                    id_array[idx1:idx2] = outputs[1]
                    if save_logits:
                        logits_array[idx1:idx2] = outputs[2]

                    step += 1
                    print(print_str % (step, (dt / cfg.BATCH_SIZE) * 1000))

                    if max_iterations > 0 and step == max_iterations:
                        break

            except tf.errors.OutOfRangeError as e:
                pass

        coord.request_stop()
        coord.join(threads)

        # save the results
        if save_logits:
            np.savez(save_path, labels=label_array, ids=id_array, logits=logits_array)
        else:
            np.savez(save_path, labels=label_array, ids=id_array)


def parse_args():

    parser = argparse.ArgumentParser(description='Classify images, optionally saving the logits.')

    parser.add_argument('--tfrecords', dest='tfrecords',
                        help='Paths to tfrecords.', type=str,
                        nargs='+', required=True)

    parser.add_argument('--checkpoint_path', dest='checkpoint_path',
                          help='Path to a specific model to test against. If a directory, then the newest checkpoint file will be used.', type=str,
                          required=True, default=None)

    parser.add_argument('--save_path', dest='save_path',
                          help='File name path to a save the classification results.', type=str,
                          required=True, default=None)

    parser.add_argument('--config', dest='config_file',
                        help='Path to the configuration file',
                        required=True, type=str)

    parser.add_argument('--batch_size', dest='batch_size',
                        help='The number of images in a batch.',
                        required=True, type=int, default=None)

    parser.add_argument('--batches', dest='batches',
                        help='Maximum number of iterations to run. Default is all records (modulo the batch size).',
                        required=True, type=int, default=0)

    parser.add_argument('--save_logits', dest='save_logits',
                        help='Should the logits be saved?',
                        action='store_true', default=False)

    parser.add_argument('--model_name', dest='model_name',
                        help='The name of the architecture to use.',
                        required=False, type=str, default=None)

    parser.add_argument('--read_images', dest='read_images',
                        help='Read the images from the file system using the `filename` field rather than using the `encoded` field of the tfrecord.',
                        action='store_true', default=False)


    args = parser.parse_args()
    return args

def main():
    args = parse_args()

    cfg = parse_config_file(args.config_file)

    if args.batch_size != None:
        cfg.BATCH_SIZE = args.batch_size

    if args.model_name != None:
        cfg.MODEL_NAME = args.model_name

    classify(
        tfrecords=args.tfrecords,
        checkpoint_path=args.checkpoint_path,
        save_path = args.save_path,
        max_iterations=args.batches,
        save_logits=args.save_logits,
        cfg=cfg,
        read_images=args.read_images
    )

if __name__ == '__main__':
    main()


================================================
FILE: config/README.md
================================================
This directory contains example configuration scripts for training, testing, classifying and exporting models. I find it easy to copy these configuration files to my experiment directory and make the necessary changes. 

## Training Configuration
See the [example training config file](config_train.yaml). 

The training configuration script contains the most configurations. The other scripts mainly contain subsets of the training configuration. The `Learning Rate Parameters`, `Regularization`, and `Optimization` configurations provided experimenters fine-grained control over the learning process. Non-researchers will probably find most of the default settings adequate. I will not go into detail for these configuration parameters, but there are comments for these parameters in the [example training config file](config_train.yaml).

The configuration sections that you will want to pay attention to are the `Dataset Info` section and the `Image Processing and Augmentation` section. You'll most likely be modifying these for each experiment. Once you determine good settings for the `Queues` and `Saving Models and Summaries` you'll probably reuse these values across experiments.

### Dataset Info
| Config Name | Type | Description |
:----:|:----:|------------|
NUM_CLASSES | int | This is how you specify how many classes are in your dataset. |
NUM_TRAIN_EXAMPLES | int | This is the number of images (or bounding boxes) in your training tfrecords. This value, along with the `BATCH_SIZE` is used to compute the number of iterations in an epoch (i.e. the number of batches it takes to go through the whole training set) |
NUM_TRAIN_ITERATIONS | int | The maximum number of iterations to execute before stopping. If you are manually monitoring the training, then you can set this to a large number (e.g. 1000000) |
BATCH_SIZE | int | The number of images to process in one iteration. This number is constrained by the amount of GPU memory you have. The larger the batch size, the more GPU memory you need. You typically want the largest batch size that will fit on your GPU. |
MODEL_NAME | str | The architecture to use. Its important to keep this configuration parameter constant in all of your configuration files. |

### Image Processing and Augmentation
Deep neural networks are notoriously data hungry. One technique for increasing the amount of data that you can pass through the network is to augment your training data. Augmentations can be as simple as randomly flipping the images horizontally, or as complex as extracting crops and perturbing the pixel values. You will typically only want to augment data for the training phase. 

`IMAGE_PROCESSING` contains the parameters for controlling how to extract data from the images:

| Config Name | Type | Description |
:----:|:----:|------------|
INPUT_SIZE | int | All images will be resized to [`INPUT_SIZE`, `INPUT_SIZE`, 3] prior to passing through the network. You'll want to set this to the same value that the pretrained model used. See the nets [README](../nets/README.md) for the input size of each model architecture. |
REGION_TYPE | str | Which region should be used when creating an example? Possible values are `image` and `bbox`. |
MAINTAIN_ASPECT_RATIO | bool | When we resize an extracted region, should we maintain the aspect ratio? Or just squish it? 
RESIZE_FAST | bool | If true, then slower resize operations will be avoided and only [bilinear resizing](https://en.wikipedia.org/wiki/Bilinear_interpolation) will be used. Otherwise, a random choice between [bilinear](), [nearest neighbor](https://en.wikipedia.org/wiki/Nearest-neighbor_interpolation), [bicubic](https://en.wikipedia.org/wiki/Bicubic_interpolation) and area interpolation will be used. |
DO_RANDOM_FLIP_LEFT_RIGHT | bool | If true, then each region has a 50% chance of being flipped. | 
DO_COLOR_DISTORTION | float | Value between 0 and 1. 0 means never distort the color, and 1 means always distort the color. |
COLOR_DISTORT_FAST | bool | Its possible to distort the brightness, saturation, hue and contrast of an image. If true, then slower modifications (hue and contrast) are avoided. |

#### Region Extraction

Currently there are two different region extraction protocols: 
* `image`: The entire image is extracted and passed to the next phase of augmentation 
* `bbox`: Each bounding box in the tfrecord is used to crop out an image region. These regions are passed on to the next phase of augmentation. If there are `n` bounding boxes in a tfrecord, then `n` regions will be extracted from the image. 

For bounding boxes, we can specify wether we want to enlarge the box. This can be used as another form of augmentation (loose bounding boxes vs tight bounding boxes).

| Config Name | Type | Description |
:----:|:----:|------------|
DO_EXPANSION | float | Value between 0 and 1. 0 means never expand the box. 1 means always expand the box. |
EXPANSION_CFG | | Contains the parameters controlling the expansion of the bounding box. | 
EXPANSION_CFG.<br />WIDTH_EXPANSION_FACTOR | float | Scaling factor for the width of the box. | 
EXPANSION_CFG.<br />HEIGHT_EXPANSION_FACTOR | float | Scaling factor for the height of the box. | 


#### Random Cropping

Each region that is extracted from an image can then be randomly cropped. Again, this is a form of data augmentation. We are trying to make the network robust to changes in the data that do not effect the class label. 

`RANDOM_CROP_CFG` contains parameters for cropping out a rectangular patch from each region. 

| Config Name | Type | Description |
:----:|:----:|------------|
DO_RANDOM_CROP | float | Value between 0 and 1. 0 means never crop a region. 1 means always take a crop. |
RANDOM_CROP_CFG | | This contains parameters that controls the types of crops that are possible. |
RANDOM_CROP_CFG.<br />MIN_AREA | float | Value between 0 and 1. This controls how much of the region is required to be in the crop, essentially controlling how small a crop can be. |
RANDOM_CROP_CFG.<br />MAX_AREA | float | Value between 0 and 1. This controls the maximum size of the crop. |
RANDOM_CROP_CFG.<br />MIN_ASPECT_RATIO | float | The minimum [aspect ratio](https://en.wikipedia.org/wiki/Aspect_ratio_(image)) of the crop. Don't forget that this crop will be resized to [`INPUT_SIZE`, `INPUT_SIZE`, 3] prior to passing through the network. |
RANDOM_CROP_CFG.<br />MAX_ASPECT_RATIO | float | The maximum [aspect ratio](https://en.wikipedia.org/wiki/Aspect_ratio_(image)) of the crop. Don't forget that this crop will be resized to [`INPUT_SIZE`, `INPUT_SIZE`, 3] prior to passing through the network. |
RANDOM_CROP_CFG.<br />MAX_ATTEMPTS | int | The number of crop attempts to try before returning the whole region. |

### Queues
This section of the config file contains parameters for controlling the queueing of data to feed the network. These setting depend on the number of cores in your machine and the amount of memory available. Please see the comments in the example config file for more information. 

### Saving Models and Summaries 
This section of the config file contains parameters for controlling how often a model checkpoint should be created and how often tensorboard summary files should be generated. Please see the comments in the example config file for more information. 

## Testing Configuration
See the [example testing config file](config_test.yaml). 

The `Learning Rate Parameters`, `Optimization`, and `Saving Models and Summaries` parameters are not necessary for testing. The remaining parameters from the training config carry over to testing. In addition there are a few new configurations:

| Config Name | Type | Description |
:----:|:----:|------------|
PRECISION_AT_K_METRIC | array of ints | You can track top-k metrics using this array. Top-1 (i.e. accuracy) will always be plotted |
NUM_TEST_EXAMPLES | int | The number of images (or bounding boxes) in the tfrecords. This can be ignored if you use the `--batches` command line flag. | 

Typically in a testing situation you'll want to turn off the augmentations to the extracted image regions. This way you are passing "real" data to the network. See the `Image Processing and Augmentation` section of the [example testing config file](config_test.yaml) to see how to extract regions without augmentations.

## Classification Configuration
See the [example classification config file](config_classify.yaml).

The classification configuration contains even fewer necessary fields than the testing configuration. The `Metrics` section is removed and you'll need to pass batch size and total batch information through command-line arguments. 

## Export Configuration
See the [example export config file](config_export.yaml).

The export configuration is the smallest configuration file. See the [example](config_export.yaml) for which fields are required. 


================================================
FILE: config/__init__.py
================================================


================================================
FILE: config/config_classify.yaml
================================================
# Classification specific configuration

RANDOM_SEED : 1.0

SESSION_CONFIG : {
  # If true, then the device location of each variable will be printed
  LOG_DEVICE_PLACEMENT : false,

  # How much GPU memory we are allowed to pre-allocate
  PER_PROCESS_GPU_MEMORY_FRACTION : 0.9,

  # Set the number of accessible cpu threads. Leave as null to use everything.
  # Set to 1 to help with debugging (makes the print statements legible)
  INTRA_OP_PARALLELISM_THREADS : null,
  INTER_OP_PARALLELISM_THREADS : null
}

#################################################
# Dataset Info
# The number of classes we are classifying
NUM_CLASSES : 200

# The model architecture to use.
MODEL_NAME : 'inception_v3'

# END: Dataset Info
#################################################
# Image Processing and Augmentation
# There are 5 steps to image processing:
# 1) Extract regions from the image
# 2) Extract a crops from each region
# 3) Resize the crops for the network architecture
# 4) Flip the crops
# 5) Modify the colors of the crops
IMAGE_PROCESSING : {
    # All images will be resized to the [INPUT_SIZE, INPUT_SIZE, 3]
    INPUT_SIZE : 299,

    # 1) First we extract regions from the image
    # What type of region should be extracted, either 'image' or 'bbox'
    REGION_TYPE : 'image',

    # Specific whole image region extraction configuration
    WHOLE_IMAGE_CFG : {},

    # Specific bounding box region extraction configuration
    BBOX_CFG : {
        # We can centrally expand a bbox (i.e. turn a tight crop into a loose crop)
        # The fraction of time to expand the bounding box, 0 is never, 1 is always
        DO_EXPANSION : 1,
        EXPANSION_CFG : {
            WIDTH_EXPANSION_FACTOR : 2.0, # Expand the width by a factor of 2 (centrally)
            HEIGHT_EXPANSION_FACTOR : 2.0, # Expand the height by a factor of 2 (centrally)
        }
    },

    # 2) Then we take a random crop from the region
    # The fraction of time to take a random crop, 0 is never, 1 is always
    DO_RANDOM_CROP : 0,
    RANDOM_CROP_CFG : {
        MIN_AREA : 0.5, # between 0 and 1, how much of the region must be included
        MAX_AREA : 1.0, # between 0 and 1, how much of the region can be included
        MIN_ASPECT_RATIO : 0.7, # minimum aspect ratio of the crop
        MAX_ASPECT_RATIO : 1.33, # maximum aspect ratio of the crop
        MAX_ATTEMPTS : 100, # maximum number of attempts before returning the whole region
    },

    # Alternatively we can take a central crop from the image
    DO_CENTRAL_CROP : 0, # Fraction of the time to take a central crop, 0 is never, 1 is always
    CENTRAL_CROP_FRACTION : 0.875, # Between 0 and 1, fraction of size to crop

    # 3) We need to resize the extracted regions to feed into the network.
    MAINTAIN_ASPECT_RATIO : false,
    # Avoid slower resize operations (bi-cubic, etc.)
    RESIZE_FAST : true,

    # 4) We can flip the regions
    # Randomly flip the image left right, 50% chance of flipping
    DO_RANDOM_FLIP_LEFT_RIGHT : false,

    # 5) We can distort the colors of the regions
    # The fraction of time to distort the color, 0 is never, 1 is always
    DO_COLOR_DISTORTION : 0,
    # Avoids slower ops (random_hue and random_contrast)
    COLOR_DISTORT_FAST : false
}

# END: Image Processing and Augmentation
#################################################
# Queues
#
# Number of threads to populate the batch queue
NUM_INPUT_THREADS : 2
# Should the data be shuffled?
SHUFFLE_QUEUE : false
# Capacity of the queue producing batched examples
QUEUE_CAPACITY : 1000
# Minimum size of the queue to ensure good shuffling
QUEUE_MIN :  200

# END: Queues
#################################################
# Regularization
#
# The decay to use for the moving average. If 0, then moving average is not computed
# When restoring models, this value is needed to determine whether to restore moving
# average variables or not.
MOVING_AVERAGE_DECAY : 0.9999

# End: Regularization
#################################################

================================================
FILE: config/config_export.yaml
================================================
# Export specific configuration

RANDOM_SEED : 1.0

SESSION_CONFIG : {
  # If true, then the device location of each variable will be printed
  LOG_DEVICE_PLACEMENT : false,

  # How much GPU memory we are allowed to pre-allocate
  PER_PROCESS_GPU_MEMORY_FRACTION : 0.9,

  # Set the number of accessible cpu threads. Leave as null to use everything.
  # Set to 1 to help with debugging (makes the print statements legible)
  INTRA_OP_PARALLELISM_THREADS : null,
  INTER_OP_PARALLELISM_THREADS : null
}

#################################################
# Dataset Info
# The number of classes we are classifying
NUM_CLASSES : 200

# The model architecture to use.
MODEL_NAME : 'inception_v3'

# END: Dataset Info
#################################################
# Image Processing and Augmentation

IMAGE_PROCESSING : {
    # Images are assumed to be raveled, and have length  INPUT_SIZE * INPUT_SIZE * 3
    INPUT_SIZE : 299
}

# END: Image Processing and Augmentation
#################################################
# Regularization
#
# The decay to use for the moving average. If 0, then moving average is not computed
# When restoring models, this value is needed to determine whether to restore moving
# average variables or not.
MOVING_AVERAGE_DECAY : 0.9999

# End: Regularization
#################################################

================================================
FILE: config/config_test.yaml
================================================
# Testing specific configuration

RANDOM_SEED : 1.0

SESSION_CONFIG : {
  # If true, then the device location of each variable will be printed
  LOG_DEVICE_PLACEMENT : false,

  # How much GPU memory we are allowed to pre-allocate
  PER_PROCESS_GPU_MEMORY_FRACTION : 0.9,

  # Set the number of accessible cpu threads. Leave as null to use everything.
  # Set to 1 to help with debugging (makes the print statements legible)
  INTRA_OP_PARALLELISM_THREADS : null,
  INTER_OP_PARALLELISM_THREADS : null
}

#################################################
# Metrics
#
# Top-k precision information. Each entry is a different k value.
ACCURACY_AT_K_METRIC : [3, 5]

# END: Metrics
#################################################
# Dataset Info
# The number of classes we are classifying
NUM_CLASSES : 200

# Number of test examples in the tfrecords. This is needed to compute the total number of
# batches to pass through the network.
NUM_TEST_EXAMPLES : 5794

# The number of images to pass through the network on each iteration
BATCH_SIZE : 32

# The model architecture to use.
MODEL_NAME : 'inception_v3'

# END: Dataset Info
#################################################
# Image Processing and Augmentation
# There are 5 steps to image processing:
# 1) Extract regions from the image
# 2) Extract a crops from each region
# 3) Resize the crops for the network architecture
# 4) Flip the crops
# 5) Modify the colors of the crops
IMAGE_PROCESSING : {
    # All images will be resized to the [INPUT_SIZE, INPUT_SIZE, 3]
    INPUT_SIZE : 299,

    # 1) First we extract regions from the image
    # What type of region should be extracted, either 'image' or 'bbox'
    REGION_TYPE : 'image',

    # Specific whole image region extraction configuration
    WHOLE_IMAGE_CFG : {},

    # Specific bounding box region extraction configuration
    BBOX_CFG : {
        # We can centrally expand a bbox (i.e. turn a tight crop into a loose crop)
        # The fraction of time to expand the bounding box, 0 is never, 1 is always
        DO_EXPANSION : 1,
        EXPANSION_CFG : {
            WIDTH_EXPANSION_FACTOR : 2.0, # Expand the width by a factor of 2 (centrally)
            HEIGHT_EXPANSION_FACTOR : 2.0, # Expand the height by a factor of 2 (centrally)
        }
    },

    # 2) Then we take a random crop from the region
    # The fraction of time to take a random crop, 0 is never, 1 is always
    DO_RANDOM_CROP : 0,
    RANDOM_CROP_CFG : {
        MIN_AREA : 0.5, # between 0 and 1, how much of the region must be included
        MAX_AREA : 1.0, # between 0 and 1, how much of the region can be included
        MIN_ASPECT_RATIO : 0.7, # minimum aspect ratio of the crop
        MAX_ASPECT_RATIO : 1.33, # maximum aspect ratio of the crop
        MAX_ATTEMPTS : 100, # maximum number of attempts before returning the whole region
    },

    # Alternatively we can take a central crop from the image
    DO_CENTRAL_CROP : 0, # Fraction of the time to take a central crop, 0 is never, 1 is always
    CENTRAL_CROP_FRACTION : 0.875, # Between 0 and 1, fraction of size to crop

    # 3) We need to resize the extracted regions to feed into the network.
    MAINTAIN_ASPECT_RATIO : false,
    # Avoid slower resize operations (bi-cubic, etc.)
    RESIZE_FAST : true,

    # 4) We can flip the regions
    # Randomly flip the image left right, 50% chance of flipping
    DO_RANDOM_FLIP_LEFT_RIGHT : false,

    # 5) We can distort the colors of the regions
    # The fraction of time to distort the color, 0 is never, 1 is always
    DO_COLOR_DISTORTION : 0,
    # Avoids slower ops (random_hue and random_contrast)
    COLOR_DISTORT_FAST : false
}

# END: Image Processing and Augmentation
#################################################
# Queues
#
# Number of threads to populate the batch queue
NUM_INPUT_THREADS : 2
# Should the data be shuffled?
SHUFFLE_QUEUE : false
# Capacity of the queue producing batched examples
QUEUE_CAPACITY : 1000
# Minimum size of the queue to ensure good shuffling
QUEUE_MIN :  200

# END: Queues
#################################################
# Regularization
#
# The decay to use for the moving average. If 0, then moving average is not computed
# When restoring models, this value is needed to determine whether to restore moving
# average variables or not.
MOVING_AVERAGE_DECAY : 0.9999

# End: Regularization
#################################################

================================================
FILE: config/config_train.yaml
================================================
# Training specific configuration

RANDOM_SEED : 1.0

SESSION_CONFIG : {
  # If true, then the device location of each variable will be printed
  LOG_DEVICE_PLACEMENT : false,

  # How much GPU memory we are allowed to pre-allocate
  PER_PROCESS_GPU_MEMORY_FRACTION : 0.9,

  # Set the number of accessible cpu threads. Leave as null to use everything.
  # Set to 1 to help with debugging (makes the print statements legible)
  INTRA_OP_PARALLELISM_THREADS : null,
  INTER_OP_PARALLELISM_THREADS : null
}

#################################################
# Dataset Info
#
# The number of classes we are classifying
NUM_CLASSES : 200

# Number of training examples in the tfrecords. This is needed to compute the number of
# batches in an epoch
NUM_TRAIN_EXAMPLES : 5994

# Maximum number of iterations to run before stopping
NUM_TRAIN_ITERATIONS : 20000

# The number of images to pass through the network in a single iteration
BATCH_SIZE : 32

# Which model architecture to use.
MODEL_NAME : 'inception_v3'

# END: Dataset Info
#################################################
# Image Processing and Augmentation
# There are 5 steps to image processing:
# 1) Extract regions from the image
# 2) Extract a crops from each region
# 3) Resize the crops for the network architecture
# 4) Flip the crops
# 5) Modify the colors of the crops
IMAGE_PROCESSING : {
    # All images will be resized to the [INPUT_SIZE, INPUT_SIZE, 3]
    INPUT_SIZE : 299,

    # 1) First we extract regions from the image
    # What type of region should be extracted, either 'image' or 'bbox'
    REGION_TYPE : 'image',

    # Specific whole image region extraction configuration
    WHOLE_IMAGE_CFG : {},

    # Specific bounding box region extraction configuration
    BBOX_CFG : {
        # We can centrally expand a bbox (i.e. turn a tight crop into a loose crop)
        # The fraction of time to expand the bounding box, 0 is never, 1 is always
        DO_EXPANSION : 1,
        EXPANSION_CFG : {
            WIDTH_EXPANSION_FACTOR : 2.0, # Expand the width by a factor of 2 (centrally)
            HEIGHT_EXPANSION_FACTOR : 2.0, # Expand the height by a factor of 2 (centrally)
        }
    },

    # 2) Then we take a random crop from the region
    # The fraction of time to take a random crop, 0 is never, 1 is always
    DO_RANDOM_CROP : 1,
    RANDOM_CROP_CFG : {
        MIN_AREA : 0.5, # between 0 and 1, how much of the region must be included
        MAX_AREA : 1.0, # between 0 and 1, how much of the region can be included
        MIN_ASPECT_RATIO : 0.7, # minimum aspect ratio of the crop
        MAX_ASPECT_RATIO : 1.33, # maximum aspect ratio of the crop
        MAX_ATTEMPTS : 100, # maximum number of attempts before returning the whole region
    },

    # Alternatively we can take a central crop from the image
    DO_CENTRAL_CROP : 0, # Fraction of the time to take a central crop, 0 is never, 1 is always
    CENTRAL_CROP_FRACTION : 0.875, # Between 0 and 1, fraction of size to crop

    # 3) We need to resize the extracted regions to feed into the network.
    MAINTAIN_ASPECT_RATIO : false,
    # Avoid slower resize operations (bi-cubic, etc.)
    RESIZE_FAST : false,

    # 4) We can flip the regions
    # Randomly flip the image left right, 50% chance of flipping
    DO_RANDOM_FLIP_LEFT_RIGHT : true,

    # 5) We can distort the colors of the regions
    # The fraction of time to distort the color, 0 is never, 1 is always
    DO_COLOR_DISTORTION : 0.3,
    # Avoids slower ops (random_hue and random_contrast)
    COLOR_DISTORT_FAST : false
}

# END: Image Processing and Augmentation
#################################################
# Queues
#
# Number of threads to populate the batch queue
NUM_INPUT_THREADS : 4
# Should the data be shuffled?
SHUFFLE_QUEUE : true
# Capacity of the queue producing batched examples
QUEUE_CAPACITY : 1000
# Minimum size of the queue to ensure good shuffling
QUEUE_MIN :  200

# END: Queues
#################################################
# Saving Models and Summaries
#
# How often, in seconds, to save summaries.
SAVE_SUMMARY_SECS : 30

# How often, in seconds, to save the model
SAVE_INTERVAL_SECS : 1800

# The maximum number of recent checkpoint files to keep.
MAX_TO_KEEP : 3

# In addition to keeping the most recent `max_to_keep` checkpoint files,
# you might want to keep one checkpoint file for every N hours of training
# The default value of 10,000 hours effectively disables the feature.
KEEP_CHECKPOINT_EVERY_N_HOURS : 10000

# The frequency, in terms of global steps, that the loss and global step and logged.
LOG_EVERY_N_STEPS : 10

# END: Saving Models and Summaries
#################################################
# Learning Rate Parameters
LEARNING_RATE_DECAY_TYPE : 'exponential' # One of "fixed", "exponential", or "polynomial"

INITIAL_LEARNING_RATE : 0.01

# The minimal end learning rate used by a polynomial decay learning rate.
END_LEARNING_RATE : 0.0001

# The amount of label smoothing.
LABEL_SMOOTHING : 0.1

# How much to decay the learning rate
LEARNING_RATE_DECAY_FACTOR : 0.94
# Number of epochs between decaying the learning rate
NUM_EPOCHS_PER_DELAY : 4

LEARNING_RATE_STAIRCASE : true

# END: Learning Rate Parameters
#################################################
# Regularization
#
# The decay to use for the moving average. If 0, then moving average is not computed
MOVING_AVERAGE_DECAY : 0.9999

# The weight decay on the model weights
WEIGHT_DECAY : 0.00004

BATCHNORM_MOVING_AVERAGE_DECAY : 0.9997
BATCHNORM_EPSILON : 0.001

DROPOUT_KEEP_PROB : 0.5

CLIP_GRADIENT_NORM : 0 # If 0, no clipping is performed. Otherwise acts as a threshold to clip the gradients.

# End: Regularization
#################################################
# Optimization
#
# The name of the optimizer, one of "adadelta", "adagrad", "adam", "ftrl", "momentum", "sgd" or "rmsprop"
OPTIMIZER : 'rmsprop'
OPTIMIZER_EPSILON : 1.0

# The decay rate for adadelta.
ADADELTA_RHO: 0.95

# Starting value for the AdaGrad accumulators.
ADAGRAD_INITIAL_ACCUMULATOR_VALUE: 0.1

# The exponential decay rate for the 1st moment estimates.
ADAM_BETA1 : 0.9
# The exponential decay rate for the 2nd moment estimates.
ADAM_BETA2 : 0.99

# The learning rate power.
FTRL_LEARNING_RATE_POWER : -0.5
# Starting value for the FTRL accumulators.
FTRL_INITIAL_ACCUMULATOR_VALUE : 0.1
# The FTRL l1 regularization strength.
FTRL_L1 : 0.0
# The FTRL l2 regularization strength.
FTRL_L2 : 0.0

# The momentum for the MomentumOptimizer and RMSPropOptimizer
MOMENTUM : 0.9

# Decay term for RMSProp.
RMSPROP_DECAY : 0.9

# END: Optimization
#################################################

================================================
FILE: config/parse_config.py
================================================
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import yaml
from easydict import EasyDict as easydict

def parse_config_file(path_to_config):

    with open(path_to_config) as f:
        cfg = yaml.load(f)

    return easydict(cfg)

================================================
FILE: export.py
================================================
"""
Export a trained model for application use.

Example for use with TensorFlow Serving:
python export.py \
--checkpoint_path model.ckpt-399739 \
--export_dir export \
--export_version 1 \
--config config_export.yaml \
--serving \
--add_preprocess \
--class_names class-codes.txt

Example for use with TensorFlow Mobile:
python export.py \
--checkpoint_path model.ckpt-399739 \
--export_dir export \
--export_version 1 \
--config config_export.yaml \
--class_names class-codes.txt

Author: Grant Van Horn
"""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import argparse
import os

import tensorflow as tf
from tensorflow.python.framework import dtypes
from tensorflow.python.framework import graph_util
from tensorflow.python.saved_model import builder as saved_model_builder
from tensorflow.python.saved_model import signature_constants
from tensorflow.python.saved_model import signature_def_utils
from tensorflow.python.saved_model import tag_constants
from tensorflow.python.saved_model import utils
from tensorflow.python.tools import optimize_for_inference_lib
slim = tf.contrib.slim

from config.parse_config import parse_config_file
from nets import nets_factory


def export(checkpoint_path,
           export_dir, export_version, export_for_serving, export_tflite, export_coreml,
           add_preprocess_step,
           output_classes, class_names,
           batch_size, raveled_input,
           cfg):
    """Export a model for use with TensorFlow Serving or for more conveinent use on mobile devices, etc.
    Arguments:
      checkpoint_path (str): Path to the specific model checkpoint file to export.
      export_dir (str): Path to a directory to store the export files.
      export_version (int): The version number of this export. If `export_for_serving` is True, then this version
        number must not exist in the `export_dir`.
      export_for_serving (bool): Export a model for use with TensorFlow Serving.
      export_tflite (bool): Export a model for tensorflow lite.
      export_coreml (bool): Export a model for coreml.
      add_preprocess_step (bool): If True, then an input path for handling image byte strings will be added to the graph.
      output_classes (bool): If True, then the class indices (or `class_names` if provided) will be output along with the scores.
      class_names (list): A list of semantic class identifiers to embed within the model that correspond to the prediction
        indices. Set to None to not embed.
      batch_size (int or None): Specify a fixed batch size, or use None to keep it flexible. For tflite export you'll need a fixed batch size.
      raveled_input (bool): If True, then the input is considered to be a raveled vector that will be reshaped to a fixed height and width. Otherwise it will be treated as the proper shape.
      cfg (dict): Configuration dictionary.
    """

    if not os.path.exists(export_dir):
        print("Making export directory: %s" % (export_dir,))
        os.makedirs(export_dir)

    graph = tf.Graph()

    array_input_node_name = "images"
    bytes_input_node_name = "image_bytes"

    output_node_name = "Predictions"
    class_names_node_name = "names"

    input_height = cfg.IMAGE_PROCESSING.INPUT_SIZE
    input_width = cfg.IMAGE_PROCESSING.INPUT_SIZE
    input_depth = 3

    with graph.as_default():

        global_step = slim.get_or_create_global_step()

        # We want to store the preprocessing operation in the graph
        if add_preprocess_step:

            # The TensorFlow map_fn() function passes one argument only,
            # so I have put this method here to take advantage of scope
            # (to access input_height, etc.)
            def preprocess_image(image_buffer):
                """Preprocess image bytes to 3D float Tensor."""

                # Decode image bytes
                image = tf.image.decode_image(image_buffer)
                image = tf.image.convert_image_dtype(image, dtype=tf.float32)

                # make sure the image is of rank 3
                image = tf.cond(
                    tf.equal(tf.rank(image), 2),
                    lambda: tf.expand_dims(image, 2),
                    lambda: image
                )

                num_channels = tf.shape(image)[2]

                # if we decoded 1 channel (grayscale), then convert to a RGB image
                image = tf.cond(
                    tf.equal(num_channels, 1),
                    lambda: tf.image.grayscale_to_rgb(image),
                    lambda: image
                )

                # if we decoded 2 channels (grayscale + alpha), then strip off the last dim and convert to rgb
                image = tf.cond(
                    tf.equal(num_channels, 2),
                    lambda: tf.image.grayscale_to_rgb(
                        tf.expand_dims(image[:, :, 0], 2)),
                    lambda: image
                )

                # if we decoded 4 or more channels (rgb + alpha), then take the first three channels
                image = tf.cond(
                    tf.greater(num_channels, 3),
                    lambda: image[:, :, :3],
                    lambda: image
                )

                # Resize the image to the input height and width for the network.
                image = tf.expand_dims(image, 0)
                image = tf.image.resize_bilinear(image,
                                                 [input_height, input_width],
                                                 align_corners=False)
                image = tf.squeeze(image, [0])
                # Finally, rescale to [-1,1] instead of [0, 1)
                image = tf.subtract(image, 0.5)
                image = tf.multiply(image, 2.0)
                return image

            image_bytes_placeholder = tf.placeholder(
                tf.string, name=bytes_input_node_name)
            preped_images = tf.map_fn(
                preprocess_image, image_bytes_placeholder, dtype=tf.float32)
            # Explicit name (we can't name the map_fn)
            input_placeholder = tf.identity(
                preped_images, name=array_input_node_name)

        # We assume the client has preprocessed the data for us
        else:
            # Is the input coming in as a raveled vector? Or is it a tensor?
            if raveled_input:
                input_placeholder = tf.placeholder(tf.float32, shape=[batch_size, input_height * input_width * input_depth], name=array_input_node_name)
            else:
                input_placeholder = tf.placeholder(tf.float32, shape=[batch_size, input_height, input_width, input_depth], name=array_input_node_name)

        # Reshape the images to proper tensors if they are coming in as vectors.
        if raveled_input:
            images = tf.reshape(input_placeholder,
                                [-1, input_height, input_width, input_depth])
        else:
            images = input_placeholder

        arg_scope = nets_factory.arg_scopes_map[cfg.MODEL_NAME]()

        with slim.arg_scope(arg_scope):
            logits, end_points = nets_factory.networks_map[cfg.MODEL_NAME](
                inputs=images,
                num_classes=cfg.NUM_CLASSES,
                is_training=False
            )

        class_scores = end_points['Predictions']
        if output_classes:
            if class_names == None:
                class_names = tf.range(class_scores.get_shape().as_list()[1])
            predicted_classes = tf.tile(tf.expand_dims(class_names, 0), [
                                        tf.shape(class_scores)[0], 1], name=class_names_node_name)

        # GVH: I would like to use tf.identity here, but the function tensorflow.python.framework.graph_util.remove_training_nodes
        # called in (optimize_for_inference_lib.optimize_for_inference) removes the identity function.
        # Sticking with an add 0 operation for now.
        # We are doing this so that we can rename the output to `output_node_name` (i.e. something consistent)
        output_node = tf.add(
            end_points['Predictions'], 0., name=output_node_name)
        output_node_name = output_node.op.name

        if 'MOVING_AVERAGE_DECAY' in cfg and cfg.MOVING_AVERAGE_DECAY > 0:
            variable_averages = tf.train.ExponentialMovingAverage(
                cfg.MOVING_AVERAGE_DECAY, global_step)
            variables_to_restore = variable_averages.variables_to_restore(
                slim.get_model_variables())
        else:
            variables_to_restore = slim.get_variables_to_restore()

        saver = tf.train.Saver(variables_to_restore, reshape=True)

        if os.path.isdir(checkpoint_path):
            checkpoint_dir = checkpoint_path
            checkpoint_path = tf.train.latest_checkpoint(checkpoint_dir)

            if checkpoint_path is None:
                raise ValueError("Unable to find a model checkpoint in the "
                                 "directory %s" % (checkpoint_dir,))

        tf.logging.info('Exporting model: %s' % checkpoint_path)

        sess_config = tf.ConfigProto(
            log_device_placement=cfg.SESSION_CONFIG.LOG_DEVICE_PLACEMENT,
            allow_soft_placement=True,
            gpu_options=tf.GPUOptions(
                per_process_gpu_memory_fraction=cfg.SESSION_CONFIG.PER_PROCESS_GPU_MEMORY_FRACTION
            )
        )
        sess = tf.Session(graph=graph, config=sess_config)

        if export_for_serving:

            with tf.Session(graph=graph) as sess:

                tf.global_variables_initializer().run()

                saver.restore(sess, checkpoint_path)

                save_path = os.path.join(export_dir, "%d" % (export_version,))

                builder = saved_model_builder.SavedModelBuilder(save_path)

                # Build the signature_def_map.
                signature_def_map = {}
                signature_def_outputs = {
                    'scores': utils.build_tensor_info(class_scores)}
                if output_classes:
                    signature_def_outputs['classes'] = utils.build_tensor_info(
                        predicted_classes)

                # image bytes input
                if add_preprocess_step:
                    image_bytes_tensor_info = utils.build_tensor_info(
                        image_bytes_placeholder)
                    image_bytes_prediction_signature = signature_def_utils.build_signature_def(
                        inputs={'images': image_bytes_tensor_info},
                        outputs=signature_def_outputs,
                        method_name=signature_constants.PREDICT_METHOD_NAME
                    )
                    signature_def_map['predict_image_bytes'] = image_bytes_prediction_signature

                # image array input
                image_array_tensor_info = utils.build_tensor_info(
                    input_placeholder)
                image_array_prediction_signature = signature_def_utils.build_signature_def(
                    inputs={'images': image_array_tensor_info},
                    outputs=signature_def_outputs,
                    method_name=signature_constants.PREDICT_METHOD_NAME
                )
                signature_def_map['predict_image_array'] = image_array_prediction_signature
                signature_def_map[signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY] = image_array_prediction_signature

                legacy_init_op = tf.group(
                    tf.tables_initializer(), name='legacy_init_op')

                builder.add_meta_graph_and_variables(
                    sess, [tag_constants.SERVING],
                    signature_def_map=signature_def_map,
                    legacy_init_op=legacy_init_op
                )

                builder.save()

                print("Saved optimized model for TensorFlow Serving.")

        else:
            with sess.as_default():

                tf.global_variables_initializer().run()

                saver.restore(sess, checkpoint_path)

                input_graph_def = graph.as_graph_def()
                input_node_names = [array_input_node_name]
                if add_preprocess_step:
                    input_node_names.append(bytes_input_node_name)
                output_node_names = [output_node_name]
                if output_classes:
                    output_node_names.append(class_names_node_name)

                constant_graph_def = graph_util.convert_variables_to_constants(
                    sess=sess,
                    input_graph_def=input_graph_def,
                    output_node_names=output_node_names,
                    variable_names_whitelist=None,
                    variable_names_blacklist=None
                )

                if add_preprocess_step:
                    optimized_graph_def = constant_graph_def
                else:
                    optimized_graph_def = optimize_for_inference_lib.optimize_for_inference(
                        input_graph_def=constant_graph_def,
                        input_node_names=input_node_names,
                        output_node_names=output_node_names,
                        placeholder_type_enum=dtypes.float32.as_datatype_enum
                    )

                save_dir = os.path.join(export_dir, str(export_version))
                if not os.path.exists(save_dir):
                    print("Making version directory in export directory: %s" %
                          (save_dir,))
                    os.makedirs(save_dir)
                save_path = os.path.join(save_dir, 'optimized_model.pb')
                with open(save_path, 'w') as f:
                    f.write(optimized_graph_def.SerializeToString())

                print("Saved optimized model for mobile devices at: %s." %
                      (save_path,))
                print("Input node names: %s" % (input_node_names,))
                print("Output node name: %s" % (output_node_names,))

                if export_tflite:

                    # Patch the tensorflow lite conversion module
                    # See here: https://github.com/tensorflow/tensorflow/issues/15410
                    import tempfile
                    import subprocess
                    tf.contrib.lite.tempfile = tempfile
                    tf.contrib.lite.subprocess = subprocess

                    assert batch_size != None, "We need a fixed batch size for the tensorflow lite export. (e.g. set --batch_size=1)"

                    tflite_model = tf.contrib.lite.toco_convert(
                        optimized_graph_def, [input_placeholder], [output_node])
                    tflite_save_path = os.path.join(
                        save_dir, 'optimized_model.tflite')
                    with open(tflite_save_path, 'wb') as f:
                        f.write(tflite_model)

                    print()
                    print("Saved optimized model for tensorflow lite: %s." %
                          (tflite_save_path,))
                    print("Input node names: %s" % (input_node_names,))
                    print("Output node name: %s" % (output_node_name,))

    # We have to get out of the graph scope.
    if export_coreml:
        try:
            import tfcoreml as tf_converter
        except:
            raise ValueError("Can't import tfcoreml, so we can't create a coreml model.")

        assert batch_size != None, "We need a fixed batch size for the coreml export. (e.g. set --batch_size=1)"
        assert raveled_input == False, "The input cannot be raveled. CoreML does not support `reshape()`."

        coreml_save_path = os.path.join(save_dir, 'optimized_model.mlmodel')
        tf_converter.convert(tf_model_path=save_path,
                             mlmodel_path=coreml_save_path,
                             output_feature_names=[output_node_name + ":0"],
                             input_name_shape_dict={'images:0': [
                                 batch_size, input_height, input_width, input_depth]}
                             )

        print()
        print("Saved optimized model for coreml: %s." % (coreml_save_path,))
        print("Input node names: %s" % (input_node_names,))
        print("Output node name: %s" % (output_node_name,))


def parse_args():

    parser = argparse.ArgumentParser(
        description='Test an Inception V3 network')

    parser.add_argument('--checkpoint_path', dest='checkpoint_path',
                        help='Path to the specific model you want to export.',
                        required=True, type=str)

    parser.add_argument('--export_dir', dest='export_dir',
                        help='Path to a directory where the exported model will be saved.',
                        required=True, type=str)

    parser.add_argument('--export_version', dest='export_version',
                        help='Version number of the model.',
                        required=True, type=int)

    parser.add_argument('--config', dest='config_file',
                        help='Path to the configuration file',
                        required=True, type=str)

    parser.add_argument('--serving', dest='serving',
                        help='Export for TensorFlow Serving usage. Otherwise, a constant graph will be generated.',
                        action='store_true', default=False)

    parser.add_argument('--export_tflite', dest='export_tflite',
                        help='If True, then a tensorflow lite file will be produced along with the normal tensorflow model export (This is ignored if --serving is present).',
                        action='store_true', default=False)

    parser.add_argument('--export_coreml', dest='export_coreml',
                        help='If True, then a coreml file will be produced along with the normal tensorflow model export (This is ignored if --serving is present).',
                        action='store_true', default=False)

    parser.add_argument('--add_preprocess', dest='add_preprocess',
                        help='Add the image decoding and preprocessing nodes to the graph so that image bytes can be passed in.',
                        action='store_true', default=False)

    parser.add_argument('--output_classes', dest='output_classes',
                        help='If True, then class indices (or names if `class_names` is provided) are output along with the scores.',
                        action='store_true', default=False)

    parser.add_argument('--class_names', dest='class_names_path',
                        help='Path to the class names corresponding to each entry in the predictions output. This file should have one line for each index.',
                        required=False, type=str, default=None)

    parser.add_argument('--batch_size', dest='batch_size',
                        help='Use this to specify a fixed batch size. Leave as None to have a flexible batch size. This must be specified to create tflite and coreml exports.',
                        required=False, type=int, default=None)

    parser.add_argument('--raveled_input', dest='raveled_input',
                        help='If True, then the input is considered to be a vector that will be reshaped to the proper tensor form. This cannot be used with coreml',
                        action='store_true', default=False)

    args = parser.parse_args()

    return args


if __name__ == '__main__':

    args = parse_args()
    cfg = parse_config_file(args.config_file)

    if args.class_names_path != None:
        class_names = []
        with open(args.class_names_path) as f:
            for line in f:
                class_names.append(line.strip())
    else:
        class_names = None

    export(checkpoint_path=args.checkpoint_path,
           export_dir=args.export_dir,
           export_version=args.export_version,
           export_for_serving=args.serving,
           export_tflite=args.export_tflite,
           export_coreml=args.export_coreml,
           add_preprocess_step=args.add_preprocess,
           output_classes=args.output_classes,
           class_names=class_names,
           batch_size=args.batch_size,
           raveled_input=args.raveled_input,
           cfg=cfg
    )


================================================
FILE: extract.py
================================================
"""
Extract features.
"""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import argparse
import os
import time

import numpy as np
import tensorflow as tf
import tensorflow.contrib.slim as slim

from config.parse_config import parse_config_file
from nets import nets_factory
from preprocessing import inputs

def extract_features(tfrecords, checkpoint_path, num_iterations, feature_keys, cfg, read_images=False):
    """
    Extract and return the features
    """

    tf.logging.set_verbosity(tf.logging.INFO)

    graph = tf.Graph()

    with graph.as_default():

        global_step = slim.get_or_create_global_step()

        with tf.device('/cpu:0'):
            batch_dict = inputs.input_nodes(
                tfrecords=tfrecords,
                cfg=cfg.IMAGE_PROCESSING,
                num_epochs=1,
                batch_size=cfg.BATCH_SIZE,
                num_threads=cfg.NUM_INPUT_THREADS,
                shuffle_batch =cfg.SHUFFLE_QUEUE,
                random_seed=cfg.RANDOM_SEED,
                capacity=cfg.QUEUE_CAPACITY,
                min_after_dequeue=cfg.QUEUE_MIN,
                add_summaries=False,
                input_type='classification',
                read_filenames=read_images
            )

        arg_scope = nets_factory.arg_scopes_map[cfg.MODEL_NAME]()

        with slim.arg_scope(arg_scope):
            logits, end_points = nets_factory.networks_map[cfg.MODEL_NAME](
                inputs=batch_dict['inputs'],
                num_classes=cfg.NUM_CLASSES,
                is_training=False
            )

            predicted_labels = tf.argmax(end_points['Predictions'], 1)

        if 'MOVING_AVERAGE_DECAY' in cfg and cfg.MOVING_AVERAGE_DECAY > 0:
            variable_averages = tf.train.ExponentialMovingAverage(
                cfg.MOVING_AVERAGE_DECAY, global_step)
            variables_to_restore = variable_averages.variables_to_restore(
                slim.get_model_variables())
            variables_to_restore[global_step.op.name] = global_step
        else:
            variables_to_restore = slim.get_variables_to_restore()
            variables_to_restore.append(global_step)


        saver = tf.train.Saver(variables_to_restore, reshape=True)

        num_batches = num_iterations
        num_items = num_batches * cfg.BATCH_SIZE

        fetches = []
        feature_stores = []
        for feature_key in feature_keys:
            feature = tf.reshape(end_points[feature_key], [cfg.BATCH_SIZE, -1])
            num_elements = feature.get_shape().as_list()[1]
            feature_stores.append(np.empty([num_items, num_elements], dtype=np.float32))
            fetches.append(feature)

        fetches.append(batch_dict['ids'])
        feature_stores.append(np.empty(num_items, dtype=np.object))

        if os.path.isdir(checkpoint_path):
            checkpoint_dir = checkpoint_path
            checkpoint_path = tf.train.latest_checkpoint(checkpoint_dir)

            if checkpoint_path is None:
                raise ValueError("Unable to find a model checkpoint in the " \
                                 "directory %s" % (checkpoint_dir,))

        tf.logging.info('Classifying records using %s' % checkpoint_path)

        coord = tf.train.Coordinator()

        sess_config = tf.ConfigProto(
                log_device_placement=cfg.SESSION_CONFIG.LOG_DEVICE_PLACEMENT,
                allow_soft_placement = True,
                gpu_options = tf.GPUOptions(
                    per_process_gpu_memory_fraction=cfg.SESSION_CONFIG.PER_PROCESS_GPU_MEMORY_FRACTION
                )
            )
        sess = tf.Session(graph=graph, config=sess_config)

        with sess.as_default():

            tf.global_variables_initializer().run()
            tf.local_variables_initializer().run()
            threads = tf.train.start_queue_runners(sess=sess, coord=coord)

            try:

                # Restore from checkpoint
                saver.restore(sess, checkpoint_path)

                print_str = ', '.join([
                  'Step: %d',
                  'Time/image (ms): %.1f'
                ])

                step = 0
                while not coord.should_stop():

                    t = time.time()
                    outputs = sess.run(fetches)
                    dt = time.time()-t

                    idx1 = cfg.BATCH_SIZE * step
                    idx2 = idx1 + cfg.BATCH_SIZE

                    for i in range(len(outputs)):
                        feature_stores[i][idx1:idx2] = outputs[i]

                    step += 1
                    print(print_str % (step, (dt / cfg.BATCH_SIZE) * 1000))

                    if num_iterations > 0 and step == num_iterations:
                        break

            except tf.errors.OutOfRangeError as e:
                pass

        coord.request_stop()
        coord.join(threads)

        feature_dict = {feature_key : feature for feature_key, feature in zip(feature_keys, feature_stores[:-1])}
        feature_dict['ids'] = feature_stores[-1]

        return feature_dict

def extract_and_save(tfrecords, checkpoint_path, save_path, num_iterations, feature_keys, cfg, read_images=False):
    """Extract and save the features
    Args:
        tfrecords (list)
        checkpoint_path (str)
        save_dir (str)
        max_iterations (int)
        save_logits (bool)
        cfg (EasyDict)
    """

    feature_dict = extract_features(tfrecords, checkpoint_path, num_iterations, feature_keys, cfg, read_images=read_images)

    # save the results
    np.savez(save_path, **feature_dict)


def parse_args():

    parser = argparse.ArgumentParser(description='Classify images, optionally saving the logits.')

    parser.add_argument('--tfrecords', dest='tfrecords',
                        help='Paths to tfrecords.', type=str,
                        nargs='+', required=True)

    parser.add_argument('--checkpoint_path', dest='checkpoint_path',
                          help='Path to a specific model to test against. If a directory, then the newest checkpoint file will be used.', type=str,
                          required=True)

    parser.add_argument('--save_path', dest='save_path',
                          help='File name path to a save the classification results.', type=str,
                          required=True)

    parser.add_argument('--config', dest='config_file',
                        help='Path to the configuration file',
                        required=True, type=str)

    parser.add_argument('--batch_size', dest='batch_size',
                        help='The number of images in a batch.',
                        required=True, type=int)

    parser.add_argument('--batches', dest='batches',
                        help='Maximum number of iterations to run. Default is all records (modulo the batch size).',
                        required=True, type=int)

    parser.add_argument('--features', dest='features',
                        help='The features to extract. These are keys into the end_points dictionary returned by the model architecture.',
                        type=str, nargs='+', required=True)

    parser.add_argument('--model_name', dest='model_name',
                        help='The name of the architecture to use.',
                        required=False, type=str, default=None)

    parser.add_argument('--read_images', dest='read_images',
                        help='Read the images from the file system using the `filename` field rather than using the `encoded` field of the tfrecord.',
                        action='store_true', default=False)



    args = parser.parse_args()
    return args

def main():
    args = parse_args()

    cfg = parse_config_file(args.config_file)

    if args.batch_size != None:
        cfg.BATCH_SIZE = args.batch_size

    if args.model_name != None:
        cfg.MODEL_NAME = args.model_name

    extract_and_save(
        tfrecords=args.tfrecords,
        checkpoint_path=args.checkpoint_path,
        save_path = args.save_path,
        num_iterations=args.batches,
        feature_keys=args.features,
        cfg=cfg,
        read_images=args.read_images
    )

if __name__ == '__main__':
    main()


================================================
FILE: nets/README.md
================================================
# Models

This directory contains the available classification models. All of these models were copied from the [TensorFlow Models repo](https://github.com/tensorflow/models/tree/master/slim/nets) and updated to TensorFlow r1.0.

The table below lists relevant information for each model. To use one of these models (e.g. when using the training scripts), simply set the `--model_name` flag to the appropriate name. The number of parameters and the number of flops were computed using the `profile` function in [net_profile.py](net_profile.py). I assumed a batch size of 1, and 1000 classes for all models. All available checkpoint files are from models trained on the [ILSVRC-2012-CLS](http://www.image-net.org/challenges/LSVRC/2012/) dataset. Top-1 and Top-5 numbers correspond to performance on that datasets. When fine-tuning from one of these checkpoints, it is recommended to use the same image size as the default image size for that model.

| Model | Name | TF-Slim File | Checkpoint | Top-1 Accuracy | Top-5 Accuracy | Default Image Size | Num Params | Num Flops |
:----:|:----:|:------------:|:----------:|:-------:|:--------:|:--------:|:--------:|:--------:|
[Inception V1](http://arxiv.org/abs/1409.4842v1) | inception_v1 | [Code](inception_v1.py) | [Checkpoint](http://download.tensorflow.org/models/inception_v1_2016_08_28.tar.gz) | 69.8 | 89.6 | 224px | 6,617,624 | 3.00b |
[Inception V2](http://arxiv.org/abs/1502.03167) | inception_v2 | [Code](inception_v2.py) | [Checkpoint](http://download.tensorflow.org/models/inception_v2_2016_08_28.tar.gz) | 73.9 | 91.8 | 224px | 11,178,336 | 3.87b |
[Inception V3](http://arxiv.org/abs/1512.00567) | inception_v3 | [Code](inception_v3.py) | [Checkpoint](http://download.tensorflow.org/models/inception_v3_2016_08_28.tar.gz) | 78.0 | 93.9 | 299px | 27,143,152 | 11.44b |
[Inception V4](http://arxiv.org/abs/1602.07261) | inception_v4 | [Code](inception_v4.py) | [Checkpoint](http://download.tensorflow.org/models/inception_v4_2016_09_09.tar.gz) | 80.2 | 95.2 | 299px | 46,006,800 | 24.52b |
[Inception-ResNet-v2](http://arxiv.org/abs/1602.07261) | inception_resnet_v2 | [Code](inception_resnet_v2.py) | [Checkpoint](http://download.tensorflow.org/models/inception_resnet_v2_2016_08_30.tar.gz) | 80.4 | 95.3 | 299px | 59,179,952 | 26.34b |
[ResNet V2 50](https://arxiv.org/abs/1603.05027) | resnet_v2_50 | [Code](resnet_v2.py) | [Checkpoint](http://download.tensorflow.org/models/resnet_v2_50_2017_04_14.tar.gz) | 75.6 | 92.8 | 299px | 25,568,360 | 13.08b |
[ResNet V2 101](https://arxiv.org/abs/1603.05027) | resnet_v2_101 | [Code](resnet_v2.py) | [Checkpoint](http://download.tensorflow.org/models/resnet_v2_101_2017_04_14.tar.gz) | 77.0 | 93.7 | 299px | 44,577,896 | 26.77b |
[ResNet V2 152](https://arxiv.org/abs/1603.05027) | resnet_v2_152 | [Code](resnet_v2.py) | [Checkpoint](http://download.tensorflow.org/models/resnet_v2_152_2017_04_14.tar.gz) | 77.8 | 94.1 | 299px | 60,236,904 | 40.45b |
[MobileNet-v1](https://arxiv.org/abs/1704.04861) | mobilenet_v1 | [Code](mobilenet_v1.py) | [Checkpoint](http://download.tensorflow.org/models/mobilenet_v1_1.0_224_2017_06_14.tar.gz) | 70.7 | 89.5 | 224px | 4,231,976 | 1.14b |

# Finetuning

When you finetune one of the above models, you'll start the training procedure using something like:
```
python train.py \
--tfrecords $DATASET_DIR/train* \
--logdir $EXPERIMENT_DIR/logdir \
--config $EXPERIMENT_DIR/config_train.yaml \
--pretrained_model $PRETRAINED_MODEL \
--checkpoint_exclude_scopes <model specific scopes>
```

The `--checkpoint_exclude_scopes` argument allows you to prevent restoring variables that have different sizes, which are typically your logit variables (which have a different size due to the number of classes in your application being different than the number of classes in ImageNet). The below table provides the proper value for `--checkpoint_exclude_scopes` for each model.

| Model | Name | TF-Slim File | Default Image Size | Exclude Scopes |
:----:|:----:|:------------:|:----------:|:-------:|
[Inception V1](http://arxiv.org/abs/1409.4842v1) | inception_v1 | [Code](inception_v1.py) | 224px | InceptionV1/Logits |
[Inception V2](http://arxiv.org/abs/1502.03167) | inception_v2 | [Code](inception_v2.py) | 224px | InceptionV2/Logits |
[Inception V3](http://arxiv.org/abs/1512.00567) | inception_v3 | [Code](inception_v3.py) | 299px | InceptionV3/Logits InceptionV3/AuxLogits |
[Inception V4](http://arxiv.org/abs/1602.07261) | inception_v4 | [Code](inception_v4.py) | 299px | InceptionV4/Logits InceptionV4/AuxLogits |
[Inception-ResNet-v2](http://arxiv.org/abs/1602.07261) | inception_resnet_v2 | [Code](inception_resnet_v2.py) | 299px | InceptionResnetV2/Logits InceptionResnetV2/AuxLogits |
[ResNet V2 50](https://arxiv.org/abs/1603.05027) | resnet_v2_50 | [Code](resnet_v2.py) | 224px | resnet_v2_50/logits |
[ResNet V2 101](https://arxiv.org/abs/1603.05027) | resnet_v2_101 | [Code](resnet_v2.py) | 224px | resnet_v2_101/logits |
[ResNet V2 152](https://arxiv.org/abs/1603.05027) | resnet_v2_152 | [Code](resnet_v2.py) | 224px | resnet_v2_152/logits |
[MobileNet-v1](https://arxiv.org/abs/1704.04861) | mobilenet_v1 | [Code](mobilenet_v1.py) | 224px | MobilenetV1/Logits |


================================================
FILE: nets/__init__.py
================================================



================================================
FILE: nets/inception.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Brings all inception models under one namespace."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

# pylint: disable=unused-import
from nets.inception_resnet_v2 import inception_resnet_v2
from nets.inception_resnet_v2 import inception_resnet_v2_arg_scope
from nets.inception_v1 import inception_v1
from nets.inception_v1 import inception_v1_arg_scope
from nets.inception_v1 import inception_v1_base
from nets.inception_v2 import inception_v2
from nets.inception_v2 import inception_v2_arg_scope
from nets.inception_v2 import inception_v2_base
from nets.inception_v3 import inception_v3
from nets.inception_v3 import inception_v3_arg_scope
from nets.inception_v3 import inception_v3_base
from nets.inception_v4 import inception_v4
from nets.inception_v4 import inception_v4_arg_scope
from nets.inception_v4 import inception_v4_base
# pylint: enable=unused-import


================================================
FILE: nets/inception_resnet_v2.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Contains the definition of the Inception Resnet V2 architecture.

As described in http://arxiv.org/abs/1602.07261.

  Inception-v4, Inception-ResNet and the Impact of Residual Connections
    on Learning
  Christian Szegedy, Sergey Ioffe, Vincent Vanhoucke, Alex Alemi
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function


import tensorflow as tf

slim = tf.contrib.slim


def block35(net, scale=1.0, activation_fn=tf.nn.relu, scope=None, reuse=None):
  """Builds the 35x35 resnet block."""
  with tf.variable_scope(scope, 'Block35', [net], reuse=reuse):
    with tf.variable_scope('Branch_0'):
      tower_conv = slim.conv2d(net, 32, 1, scope='Conv2d_1x1')
    with tf.variable_scope('Branch_1'):
      tower_conv1_0 = slim.conv2d(net, 32, 1, scope='Conv2d_0a_1x1')
      tower_conv1_1 = slim.conv2d(tower_conv1_0, 32, 3, scope='Conv2d_0b_3x3')
    with tf.variable_scope('Branch_2'):
      tower_conv2_0 = slim.conv2d(net, 32, 1, scope='Conv2d_0a_1x1')
      tower_conv2_1 = slim.conv2d(tower_conv2_0, 48, 3, scope='Conv2d_0b_3x3')
      tower_conv2_2 = slim.conv2d(tower_conv2_1, 64, 3, scope='Conv2d_0c_3x3')
    mixed = tf.concat(axis=3, values=[tower_conv, tower_conv1_1, tower_conv2_2])
    up = slim.conv2d(mixed, net.get_shape()[3], 1, normalizer_fn=None,
                     activation_fn=None, scope='Conv2d_1x1')
    net += scale * up
    if activation_fn:
      net = activation_fn(net)
  return net


def block17(net, scale=1.0, activation_fn=tf.nn.relu, scope=None, reuse=None):
  """Builds the 17x17 resnet block."""
  with tf.variable_scope(scope, 'Block17', [net], reuse=reuse):
    with tf.variable_scope('Branch_0'):
      tower_conv = slim.conv2d(net, 192, 1, scope='Conv2d_1x1')
    with tf.variable_scope('Branch_1'):
      tower_conv1_0 = slim.conv2d(net, 128, 1, scope='Conv2d_0a_1x1')
      tower_conv1_1 = slim.conv2d(tower_conv1_0, 160, [1, 7],
                                  scope='Conv2d_0b_1x7')
      tower_conv1_2 = slim.conv2d(tower_conv1_1, 192, [7, 1],
                                  scope='Conv2d_0c_7x1')
    mixed = tf.concat(axis=3, values=[tower_conv, tower_conv1_2])
    up = slim.conv2d(mixed, net.get_shape()[3], 1, normalizer_fn=None,
                     activation_fn=None, scope='Conv2d_1x1')
    net += scale * up
    if activation_fn:
      net = activation_fn(net)
  return net


def block8(net, scale=1.0, activation_fn=tf.nn.relu, scope=None, reuse=None):
  """Builds the 8x8 resnet block."""
  with tf.variable_scope(scope, 'Block8', [net], reuse=reuse):
    with tf.variable_scope('Branch_0'):
      tower_conv = slim.conv2d(net, 192, 1, scope='Conv2d_1x1')
    with tf.variable_scope('Branch_1'):
      tower_conv1_0 = slim.conv2d(net, 192, 1, scope='Conv2d_0a_1x1')
      tower_conv1_1 = slim.conv2d(tower_conv1_0, 224, [1, 3],
                                  scope='Conv2d_0b_1x3')
      tower_conv1_2 = slim.conv2d(tower_conv1_1, 256, [3, 1],
                                  scope='Conv2d_0c_3x1')
    mixed = tf.concat(axis=3, values=[tower_conv, tower_conv1_2])
    up = slim.conv2d(mixed, net.get_shape()[3], 1, normalizer_fn=None,
                     activation_fn=None, scope='Conv2d_1x1')
    net += scale * up
    if activation_fn:
      net = activation_fn(net)
  return net


def inception_resnet_v2(inputs, num_classes=1001, is_training=True,
                        dropout_keep_prob=0.8,
                        reuse=None,
                        scope='InceptionResnetV2'):
  """Creates the Inception Resnet V2 model.

  Args:
    inputs: a 4-D tensor of size [batch_size, height, width, 3].
    num_classes: number of predicted classes.
    is_training: whether is training or not.
    dropout_keep_prob: float, the fraction to keep before final layer.
    reuse: whether or not the network and its variables should be reused. To be
      able to reuse 'scope' must be given.
    scope: Optional variable_scope.

  Returns:
    logits: the logits outputs of the model.
    end_points: the set of end_points from the inception model.
  """
  end_points = {}

  with tf.variable_scope(scope, 'InceptionResnetV2', [inputs], reuse=reuse):
    with slim.arg_scope([slim.batch_norm, slim.dropout],
                        is_training=is_training):
      with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d],
                          stride=1, padding='SAME'):

        # 149 x 149 x 32
        net = slim.conv2d(inputs, 32, 3, stride=2, padding='VALID',
                          scope='Conv2d_1a_3x3')
        end_points['Conv2d_1a_3x3'] = net
        # 147 x 147 x 32
        net = slim.conv2d(net, 32, 3, padding='VALID',
                          scope='Conv2d_2a_3x3')
        end_points['Conv2d_2a_3x3'] = net
        # 147 x 147 x 64
        net = slim.conv2d(net, 64, 3, scope='Conv2d_2b_3x3')
        end_points['Conv2d_2b_3x3'] = net
        # 73 x 73 x 64
        net = slim.max_pool2d(net, 3, stride=2, padding='VALID',
                              scope='MaxPool_3a_3x3')
        end_points['MaxPool_3a_3x3'] = net
        # 73 x 73 x 80
        net = slim.conv2d(net, 80, 1, padding='VALID',
                          scope='Conv2d_3b_1x1')
        end_points['Conv2d_3b_1x1'] = net
        # 71 x 71 x 192
        net = slim.conv2d(net, 192, 3, padding='VALID',
                          scope='Conv2d_4a_3x3')
        end_points['Conv2d_4a_3x3'] = net
        # 35 x 35 x 192
        net = slim.max_pool2d(net, 3, stride=2, padding='VALID',
                              scope='MaxPool_5a_3x3')
        end_points['MaxPool_5a_3x3'] = net

        # 35 x 35 x 320
        with tf.variable_scope('Mixed_5b'):
          with tf.variable_scope('Branch_0'):
            tower_conv = slim.conv2d(net, 96, 1, scope='Conv2d_1x1')
          with tf.variable_scope('Branch_1'):
            tower_conv1_0 = slim.conv2d(net, 48, 1, scope='Conv2d_0a_1x1')
            tower_conv1_1 = slim.conv2d(tower_conv1_0, 64, 5,
                                        scope='Conv2d_0b_5x5')
          with tf.variable_scope('Branch_2'):
            tower_conv2_0 = slim.conv2d(net, 64, 1, scope='Conv2d_0a_1x1')
            tower_conv2_1 = slim.conv2d(tower_conv2_0, 96, 3,
                                        scope='Conv2d_0b_3x3')
            tower_conv2_2 = slim.conv2d(tower_conv2_1, 96, 3,
                                        scope='Conv2d_0c_3x3')
          with tf.variable_scope('Branch_3'):
            tower_pool = slim.avg_pool2d(net, 3, stride=1, padding='SAME',
                                         scope='AvgPool_0a_3x3')
            tower_pool_1 = slim.conv2d(tower_pool, 64, 1,
                                       scope='Conv2d_0b_1x1')
          net = tf.concat(axis=3, values=[tower_conv, tower_conv1_1,
                              tower_conv2_2, tower_pool_1])

        end_points['Mixed_5b'] = net
        net = slim.repeat(net, 10, block35, scale=0.17)

        # 17 x 17 x 1024
        with tf.variable_scope('Mixed_6a'):
          with tf.variable_scope('Branch_0'):
            tower_conv = slim.conv2d(net, 384, 3, stride=2, padding='VALID',
                                     scope='Conv2d_1a_3x3')
          with tf.variable_scope('Branch_1'):
            tower_conv1_0 = slim.conv2d(net, 256, 1, scope='Conv2d_0a_1x1')
            tower_conv1_1 = slim.conv2d(tower_conv1_0, 256, 3,
                                        scope='Conv2d_0b_3x3')
            tower_conv1_2 = slim.conv2d(tower_conv1_1, 384, 3,
                                        stride=2, padding='VALID',
                                        scope='Conv2d_1a_3x3')
          with tf.variable_scope('Branch_2'):
            tower_pool = slim.max_pool2d(net, 3, stride=2, padding='VALID',
                                         scope='MaxPool_1a_3x3')
          net = tf.concat(axis=3, values=[tower_conv, tower_conv1_2, tower_pool])

        end_points['Mixed_6a'] = net
        net = slim.repeat(net, 20, block17, scale=0.10)

        # Auxillary tower
        with tf.variable_scope('AuxLogits'):
          # Originally, kernel_size = 5
          # However, if we change the input size then we need to change the kernel size
          # We want to pool the feature map to be 5x5xC
          # With padding = 0, and stride 3, this means our kernel is H - 12
          kernel_size = [net.get_shape().as_list()[1] - 12] * 2
          aux = slim.avg_pool2d(net, kernel_size, stride=3, padding='VALID',
                                scope='Conv2d_1a_3x3')
          aux = slim.conv2d(aux, 128, 1, scope='Conv2d_1b_1x1')
          aux = slim.conv2d(aux, 768, aux.get_shape()[1:3],
                            padding='VALID', scope='Conv2d_2a_5x5')
          aux = slim.flatten(aux)
          aux = slim.fully_connected(aux, num_classes, activation_fn=None,
                                     scope='Logits')
          end_points['AuxLogits'] = aux

        with tf.variable_scope('Mixed_7a'):
          with tf.variable_scope('Branch_0'):
            tower_conv = slim.conv2d(net, 256, 1, scope='Conv2d_0a_1x1')
            tower_conv_1 = slim.conv2d(tower_conv, 384, 3, stride=2,
                                       padding='VALID', scope='Conv2d_1a_3x3')
          with tf.variable_scope('Branch_1'):
            tower_conv1 = slim.conv2d(net, 256, 1, scope='Conv2d_0a_1x1')
            tower_conv1_1 = slim.conv2d(tower_conv1, 288, 3, stride=2,
                                        padding='VALID', scope='Conv2d_1a_3x3')
          with tf.variable_scope('Branch_2'):
            tower_conv2 = slim.conv2d(net, 256, 1, scope='Conv2d_0a_1x1')
            tower_conv2_1 = slim.conv2d(tower_conv2, 288, 3,
                                        scope='Conv2d_0b_3x3')
            tower_conv2_2 = slim.conv2d(tower_conv2_1, 320, 3, stride=2,
                                        padding='VALID', scope='Conv2d_1a_3x3')
          with tf.variable_scope('Branch_3'):
            tower_pool = slim.max_pool2d(net, 3, stride=2, padding='VALID',
                                         scope='MaxPool_1a_3x3')
          net = tf.concat(axis=3, values=[tower_conv_1, tower_conv1_1,
                              tower_conv2_2, tower_pool])

        end_points['Mixed_7a'] = net

        net = slim.repeat(net, 9, block8, scale=0.20)
        net = block8(net, activation_fn=None)

        net = slim.conv2d(net, 1536, 1, scope='Conv2d_7b_1x1')
        end_points['Conv2d_7b_1x1'] = net

        with tf.variable_scope('Logits'):
          end_points['PrePool'] = net
          net = slim.avg_pool2d(net, net.get_shape()[1:3], padding='VALID',
                                scope='AvgPool_1a_8x8')
          net = slim.flatten(net)

          net = slim.dropout(net, dropout_keep_prob, is_training=is_training,
                             scope='Dropout')

          end_points['PreLogitsFlatten'] = net
          logits = slim.fully_connected(net, num_classes, activation_fn=None,
                                        scope='Logits')
          end_points['Logits'] = logits
          end_points['Predictions'] = tf.nn.softmax(logits, name='Predictions')

    return logits, end_points
inception_resnet_v2.default_image_size = 299


def inception_resnet_v2_arg_scope(weight_decay=0.00004,
                                  batch_norm_decay=0.9997,
                                  batch_norm_epsilon=0.001):
  """Yields the scope with the default parameters for inception_resnet_v2.

  Args:
    weight_decay: the weight decay for weights variables.
    batch_norm_decay: decay for the moving average of batch_norm momentums.
    batch_norm_epsilon: small float added to variance to avoid dividing by zero.

  Returns:
    a arg_scope with the parameters needed for inception_resnet_v2.
  """
  # Set weight_decay for weights in conv2d and fully_connected layers.
  with slim.arg_scope([slim.conv2d, slim.fully_connected],
                      weights_regularizer=slim.l2_regularizer(weight_decay),
                      biases_regularizer=slim.l2_regularizer(weight_decay)):

    batch_norm_params = {
        'decay': batch_norm_decay,
        'epsilon': batch_norm_epsilon,
    }
    # Set activation_fn and parameters for batch_norm.
    with slim.arg_scope([slim.conv2d], activation_fn=tf.nn.relu,
                        normalizer_fn=slim.batch_norm,
                        normalizer_params=batch_norm_params) as scope:
      return scope


================================================
FILE: nets/inception_resnet_v2_test.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Tests for slim.inception_resnet_v2."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import tensorflow as tf

from nets import inception


class InceptionTest(tf.test.TestCase):

  def testBuildLogits(self):
    batch_size = 5
    height, width = 299, 299
    num_classes = 1000
    with self.test_session():
      inputs = tf.random_uniform((batch_size, height, width, 3))
      logits, _ = inception.inception_resnet_v2(inputs, num_classes)
      self.assertTrue(logits.op.name.startswith('InceptionResnetV2/Logits'))
      self.assertListEqual(logits.get_shape().as_list(),
                           [batch_size, num_classes])

  def testBuildEndPoints(self):
    batch_size = 5
    height, width = 299, 299
    num_classes = 1000
    with self.test_session():
      inputs = tf.random_uniform((batch_size, height, width, 3))
      _, end_points = inception.inception_resnet_v2(inputs, num_classes)
      self.assertTrue('Logits' in end_points)
      logits = end_points['Logits']
      self.assertListEqual(logits.get_shape().as_list(),
                           [batch_size, num_classes])
      self.assertTrue('AuxLogits' in end_points)
      aux_logits = end_points['AuxLogits']
      self.assertListEqual(aux_logits.get_shape().as_list(),
                           [batch_size, num_classes])
      pre_pool = end_points['PrePool']
      self.assertListEqual(pre_pool.get_shape().as_list(),
                           [batch_size, 8, 8, 1536])

  def testVariablesSetDevice(self):
    batch_size = 5
    height, width = 299, 299
    num_classes = 1000
    with self.test_session():
      inputs = tf.random_uniform((batch_size, height, width, 3))
      # Force all Variables to reside on the device.
      with tf.variable_scope('on_cpu'), tf.device('/cpu:0'):
        inception.inception_resnet_v2(inputs, num_classes)
      with tf.variable_scope('on_gpu'), tf.device('/gpu:0'):
        inception.inception_resnet_v2(inputs, num_classes)
      for v in tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='on_cpu'):
        self.assertDeviceEqual(v.device, '/cpu:0')
      for v in tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='on_gpu'):
        self.assertDeviceEqual(v.device, '/gpu:0')

  def testHalfSizeImages(self):
    batch_size = 5
    height, width = 150, 150
    num_classes = 1000
    with self.test_session():
      inputs = tf.random_uniform((batch_size, height, width, 3))
      logits, end_points = inception.inception_resnet_v2(inputs, num_classes)
      self.assertTrue(logits.op.name.startswith('InceptionResnetV2/Logits'))
      self.assertListEqual(logits.get_shape().as_list(),
                           [batch_size, num_classes])
      pre_pool = end_points['PrePool']
      self.assertListEqual(pre_pool.get_shape().as_list(),
                           [batch_size, 3, 3, 1536])

  def testUnknownBatchSize(self):
    batch_size = 1
    height, width = 299, 299
    num_classes = 1000
    with self.test_session() as sess:
      inputs = tf.placeholder(tf.float32, (None, height, width, 3))
      logits, _ = inception.inception_resnet_v2(inputs, num_classes)
      self.assertTrue(logits.op.name.startswith('InceptionResnetV2/Logits'))
      self.assertListEqual(logits.get_shape().as_list(),
                           [None, num_classes])
      images = tf.random_uniform((batch_size, height, width, 3))
      sess.run(tf.global_variables_initializer())
      output = sess.run(logits, {inputs: images.eval()})
      self.assertEquals(output.shape, (batch_size, num_classes))

  def testEvaluation(self):
    batch_size = 2
    height, width = 299, 299
    num_classes = 1000
    with self.test_session() as sess:
      eval_inputs = tf.random_uniform((batch_size, height, width, 3))
      logits, _ = inception.inception_resnet_v2(eval_inputs,
                                                num_classes,
                                                is_training=False)
      predictions = tf.argmax(logits, 1)
      sess.run(tf.global_variables_initializer())
      output = sess.run(predictions)
      self.assertEquals(output.shape, (batch_size,))

  def testTrainEvalWithReuse(self):
    train_batch_size = 5
    eval_batch_size = 2
    height, width = 150, 150
    num_classes = 1000
    with self.test_session() as sess:
      train_inputs = tf.random_uniform((train_batch_size, height, width, 3))
      inception.inception_resnet_v2(train_inputs, num_classes)
      eval_inputs = tf.random_uniform((eval_batch_size, height, width, 3))
      logits, _ = inception.inception_resnet_v2(eval_inputs,
                                                num_classes,
                                                is_training=False,
                                                reuse=True)
      predictions = tf.argmax(logits, 1)
      sess.run(tf.global_variables_initializer())
      output = sess.run(predictions)
      self.assertEquals(output.shape, (eval_batch_size,))


if __name__ == '__main__':
  tf.test.main()


================================================
FILE: nets/inception_utils.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Contains common code shared by all inception models.

Usage of arg scope:
  with slim.arg_scope(inception_arg_scope()):
    logits, end_points = inception.inception_v3(images, num_classes,
                                                is_training=is_training)

"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import tensorflow as tf

slim = tf.contrib.slim


def inception_arg_scope(weight_decay=0.00004,
                        use_batch_norm=True,
                        batch_norm_decay=0.9997,
                        batch_norm_epsilon=0.001):
  """Defines the default arg scope for inception models.

  Args:
    weight_decay: The weight decay to use for regularizing the model.
    use_batch_norm: "If `True`, batch_norm is applied after each convolution.
    batch_norm_decay: Decay for batch norm moving average.
    batch_norm_epsilon: Small float added to variance to avoid dividing by zero
      in batch norm.

  Returns:
    An `arg_scope` to use for the inception models.
  """
  batch_norm_params = {
      # Decay for the moving averages.
      'decay': batch_norm_decay,
      # epsilon to prevent 0s in variance.
      'epsilon': batch_norm_epsilon,
      # collection containing update_ops.
      'updates_collections': tf.GraphKeys.UPDATE_OPS,
  }
  if use_batch_norm:
    normalizer_fn = slim.batch_norm
    normalizer_params = batch_norm_params
  else:
    normalizer_fn = None
    normalizer_params = {}
  # Set weight_decay for weights in Conv and FC layers.
  with slim.arg_scope([slim.conv2d, slim.fully_connected],
                      weights_regularizer=slim.l2_regularizer(weight_decay)):
    with slim.arg_scope(
        [slim.conv2d],
        weights_initializer=slim.variance_scaling_initializer(),
        activation_fn=tf.nn.relu,
        normalizer_fn=normalizer_fn,
        normalizer_params=normalizer_params) as sc:
      return sc


================================================
FILE: nets/inception_v1.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Contains the definition for inception v1 classification network."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import tensorflow as tf

from nets import inception_utils

slim = tf.contrib.slim
trunc_normal = lambda stddev: tf.truncated_normal_initializer(0.0, stddev)


def inception_v1_base(inputs,
                      final_endpoint='Mixed_5c',
                      scope='InceptionV1'):
  """Defines the Inception V1 base architecture.

  This architecture is defined in:
    Going deeper with convolutions
    Christian Szegedy, Wei Liu, Yangqing Jia, Pierre Sermanet, Scott Reed,
    Dragomir Anguelov, Dumitru Erhan, Vincent Vanhoucke, Andrew Rabinovich.
    http://arxiv.org/pdf/1409.4842v1.pdf.

  Args:
    inputs: a tensor of size [batch_size, height, width, channels].
    final_endpoint: specifies the endpoint to construct the network up to. It
      can be one of ['Conv2d_1a_7x7', 'MaxPool_2a_3x3', 'Conv2d_2b_1x1',
      'Conv2d_2c_3x3', 'MaxPool_3a_3x3', 'Mixed_3b', 'Mixed_3c',
      'MaxPool_4a_3x3', 'Mixed_4b', 'Mixed_4c', 'Mixed_4d', 'Mixed_4e',
      'Mixed_4f', 'MaxPool_5a_2x2', 'Mixed_5b', 'Mixed_5c']
    scope: Optional variable_scope.

  Returns:
    A dictionary from components of the network to the corresponding activation.

  Raises:
    ValueError: if final_endpoint is not set to one of the predefined values.
  """
  end_points = {}
  with tf.variable_scope(scope, 'InceptionV1', [inputs]):
    with slim.arg_scope(
        [slim.conv2d, slim.fully_connected],
        weights_initializer=trunc_normal(0.01)):
      with slim.arg_scope([slim.conv2d, slim.max_pool2d],
                          stride=1, padding='SAME'):
        end_point = 'Conv2d_1a_7x7'
        net = slim.conv2d(inputs, 64, [7, 7], stride=2, scope=end_point)
        end_points[end_point] = net
        if final_endpoint == end_point: return net, end_points
        end_point = 'MaxPool_2a_3x3'
        net = slim.max_pool2d(net, [3, 3], stride=2, scope=end_point)
        end_points[end_point] = net
        if final_endpoint == end_point: return net, end_points
        end_point = 'Conv2d_2b_1x1'
        net = slim.conv2d(net, 64, [1, 1], scope=end_point)
        end_points[end_point] = net
        if final_endpoint == end_point: return net, end_points
        end_point = 'Conv2d_2c_3x3'
        net = slim.conv2d(net, 192, [3, 3], scope=end_point)
        end_points[end_point] = net
        if final_endpoint == end_point: return net, end_points
        end_point = 'MaxPool_3a_3x3'
        net = slim.max_pool2d(net, [3, 3], stride=2, scope=end_point)
        end_points[end_point] = net
        if final_endpoint == end_point: return net, end_points

        end_point = 'Mixed_3b'
        with tf.variable_scope(end_point):
          with tf.variable_scope('Branch_0'):
            branch_0 = slim.conv2d(net, 64, [1, 1], scope='Conv2d_0a_1x1')
          with tf.variable_scope('Branch_1'):
            branch_1 = slim.conv2d(net, 96, [1, 1], scope='Conv2d_0a_1x1')
            branch_1 = slim.conv2d(branch_1, 128, [3, 3], scope='Conv2d_0b_3x3')
          with tf.variable_scope('Branch_2'):
            branch_2 = slim.conv2d(net, 16, [1, 1], scope='Conv2d_0a_1x1')
            branch_2 = slim.conv2d(branch_2, 32, [3, 3], scope='Conv2d_0b_3x3')
          with tf.variable_scope('Branch_3'):
            branch_3 = slim.max_pool2d(net, [3, 3], scope='MaxPool_0a_3x3')
            branch_3 = slim.conv2d(branch_3, 32, [1, 1], scope='Conv2d_0b_1x1')
          net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
        end_points[end_point] = net
        if final_endpoint == end_point: return net, end_points

        end_point = 'Mixed_3c'
        with tf.variable_scope(end_point):
          with tf.variable_scope('Branch_0'):
            branch_0 = slim.conv2d(net, 128, [1, 1], scope='Conv2d_0a_1x1')
          with tf.variable_scope('Branch_1'):
            branch_1 = slim.conv2d(net, 128, [1, 1], scope='Conv2d_0a_1x1')
            branch_1 = slim.conv2d(branch_1, 192, [3, 3], scope='Conv2d_0b_3x3')
          with tf.variable_scope('Branch_2'):
            branch_2 = slim.conv2d(net, 32, [1, 1], scope='Conv2d_0a_1x1')
            branch_2 = slim.conv2d(branch_2, 96, [3, 3], scope='Conv2d_0b_3x3')
          with tf.variable_scope('Branch_3'):
            branch_3 = slim.max_pool2d(net, [3, 3], scope='MaxPool_0a_3x3')
            branch_3 = slim.conv2d(branch_3, 64, [1, 1], scope='Conv2d_0b_1x1')
          net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
        end_points[end_point] = net
        if final_endpoint == end_point: return net, end_points

        end_point = 'MaxPool_4a_3x3'
        net = slim.max_pool2d(net, [3, 3], stride=2, scope=end_point)
        end_points[end_point] = net
        if final_endpoint == end_point: return net, end_points

        end_point = 'Mixed_4b'
        with tf.variable_scope(end_point):
          with tf.variable_scope('Branch_0'):
            branch_0 = slim.conv2d(net, 192, [1, 1], scope='Conv2d_0a_1x1')
          with tf.variable_scope('Branch_1'):
            branch_1 = slim.conv2d(net, 96, [1, 1], scope='Conv2d_0a_1x1')
            branch_1 = slim.conv2d(branch_1, 208, [3, 3], scope='Conv2d_0b_3x3')
          with tf.variable_scope('Branch_2'):
            branch_2 = slim.conv2d(net, 16, [1, 1], scope='Conv2d_0a_1x1')
            branch_2 = slim.conv2d(branch_2, 48, [3, 3], scope='Conv2d_0b_3x3')
          with tf.variable_scope('Branch_3'):
            branch_3 = slim.max_pool2d(net, [3, 3], scope='MaxPool_0a_3x3')
            branch_3 = slim.conv2d(branch_3, 64, [1, 1], scope='Conv2d_0b_1x1')
          net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
        end_points[end_point] = net
        if final_endpoint == end_point: return net, end_points

        end_point = 'Mixed_4c'
        with tf.variable_scope(end_point):
          with tf.variable_scope('Branch_0'):
            branch_0 = slim.conv2d(net, 160, [1, 1], scope='Conv2d_0a_1x1')
          with tf.variable_scope('Branch_1'):
            branch_1 = slim.conv2d(net, 112, [1, 1], scope='Conv2d_0a_1x1')
            branch_1 = slim.conv2d(branch_1, 224, [3, 3], scope='Conv2d_0b_3x3')
          with tf.variable_scope('Branch_2'):
            branch_2 = slim.conv2d(net, 24, [1, 1], scope='Conv2d_0a_1x1')
            branch_2 = slim.conv2d(branch_2, 64, [3, 3], scope='Conv2d_0b_3x3')
          with tf.variable_scope('Branch_3'):
            branch_3 = slim.max_pool2d(net, [3, 3], scope='MaxPool_0a_3x3')
            branch_3 = slim.conv2d(branch_3, 64, [1, 1], scope='Conv2d_0b_1x1')
          net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
        end_points[end_point] = net
        if final_endpoint == end_point: return net, end_points

        end_point = 'Mixed_4d'
        with tf.variable_scope(end_point):
          with tf.variable_scope('Branch_0'):
            branch_0 = slim.conv2d(net, 128, [1, 1], scope='Conv2d_0a_1x1')
          with tf.variable_scope('Branch_1'):
            branch_1 = slim.conv2d(net, 128, [1, 1], scope='Conv2d_0a_1x1')
            branch_1 = slim.conv2d(branch_1, 256, [3, 3], scope='Conv2d_0b_3x3')
          with tf.variable_scope('Branch_2'):
            branch_2 = slim.conv2d(net, 24, [1, 1], scope='Conv2d_0a_1x1')
            branch_2 = slim.conv2d(branch_2, 64, [3, 3], scope='Conv2d_0b_3x3')
          with tf.variable_scope('Branch_3'):
            branch_3 = slim.max_pool2d(net, [3, 3], scope='MaxPool_0a_3x3')
            branch_3 = slim.conv2d(branch_3, 64, [1, 1], scope='Conv2d_0b_1x1')
          net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
        end_points[end_point] = net
        if final_endpoint == end_point: return net, end_points

        end_point = 'Mixed_4e'
        with tf.variable_scope(end_point):
          with tf.variable_scope('Branch_0'):
            branch_0 = slim.conv2d(net, 112, [1, 1], scope='Conv2d_0a_1x1')
          with tf.variable_scope('Branch_1'):
            branch_1 = slim.conv2d(net, 144, [1, 1], scope='Conv2d_0a_1x1')
            branch_1 = slim.conv2d(branch_1, 288, [3, 3], scope='Conv2d_0b_3x3')
          with tf.variable_scope('Branch_2'):
            branch_2 = slim.conv2d(net, 32, [1, 1], scope='Conv2d_0a_1x1')
            branch_2 = slim.conv2d(branch_2, 64, [3, 3], scope='Conv2d_0b_3x3')
          with tf.variable_scope('Branch_3'):
            branch_3 = slim.max_pool2d(net, [3, 3], scope='MaxPool_0a_3x3')
            branch_3 = slim.conv2d(branch_3, 64, [1, 1], scope='Conv2d_0b_1x1')
          net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
        end_points[end_point] = net
        if final_endpoint == end_point: return net, end_points

        end_point = 'Mixed_4f'
        with tf.variable_scope(end_point):
          with tf.variable_scope('Branch_0'):
            branch_0 = slim.conv2d(net, 256, [1, 1], scope='Conv2d_0a_1x1')
          with tf.variable_scope('Branch_1'):
            branch_1 = slim.conv2d(net, 160, [1, 1], scope='Conv2d_0a_1x1')
            branch_1 = slim.conv2d(branch_1, 320, [3, 3], scope='Conv2d_0b_3x3')
          with tf.variable_scope('Branch_2'):
            branch_2 = slim.conv2d(net, 32, [1, 1], scope='Conv2d_0a_1x1')
            branch_2 = slim.conv2d(branch_2, 128, [3, 3], scope='Conv2d_0b_3x3')
          with tf.variable_scope('Branch_3'):
            branch_3 = slim.max_pool2d(net, [3, 3], scope='MaxPool_0a_3x3')
            branch_3 = slim.conv2d(branch_3, 128, [1, 1], scope='Conv2d_0b_1x1')
          net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
        end_points[end_point] = net
        if final_endpoint == end_point: return net, end_points

        end_point = 'MaxPool_5a_2x2'
        net = slim.max_pool2d(net, [2, 2], stride=2, scope=end_point)
        end_points[end_point] = net
        if final_endpoint == end_point: return net, end_points

        end_point = 'Mixed_5b'
        with tf.variable_scope(end_point):
          with tf.variable_scope('Branch_0'):
            branch_0 = slim.conv2d(net, 256, [1, 1], scope='Conv2d_0a_1x1')
          with tf.variable_scope('Branch_1'):
            branch_1 = slim.conv2d(net, 160, [1, 1], scope='Conv2d_0a_1x1')
            branch_1 = slim.conv2d(branch_1, 320, [3, 3], scope='Conv2d_0b_3x3')
          with tf.variable_scope('Branch_2'):
            branch_2 = slim.conv2d(net, 32, [1, 1], scope='Conv2d_0a_1x1')
            branch_2 = slim.conv2d(branch_2, 128, [3, 3], scope='Conv2d_0a_3x3')
          with tf.variable_scope('Branch_3'):
            branch_3 = slim.max_pool2d(net, [3, 3], scope='MaxPool_0a_3x3')
            branch_3 = slim.conv2d(branch_3, 128, [1, 1], scope='Conv2d_0b_1x1')
          net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
        end_points[end_point] = net
        if final_endpoint == end_point: return net, end_points

        end_point = 'Mixed_5c'
        with tf.variable_scope(end_point):
          with tf.variable_scope('Branch_0'):
            branch_0 = slim.conv2d(net, 384, [1, 1], scope='Conv2d_0a_1x1')
          with tf.variable_scope('Branch_1'):
            branch_1 = slim.conv2d(net, 192, [1, 1], scope='Conv2d_0a_1x1')
            branch_1 = slim.conv2d(branch_1, 384, [3, 3], scope='Conv2d_0b_3x3')
          with tf.variable_scope('Branch_2'):
            branch_2 = slim.conv2d(net, 48, [1, 1], scope='Conv2d_0a_1x1')
            branch_2 = slim.conv2d(branch_2, 128, [3, 3], scope='Conv2d_0b_3x3')
          with tf.variable_scope('Branch_3'):
            branch_3 = slim.max_pool2d(net, [3, 3], scope='MaxPool_0a_3x3')
            branch_3 = slim.conv2d(branch_3, 128, [1, 1], scope='Conv2d_0b_1x1')
          net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
        end_points[end_point] = net
        if final_endpoint == end_point: return net, end_points
    raise ValueError('Unknown final endpoint %s' % final_endpoint)


def inception_v1(inputs,
                 num_classes=1000,
                 is_training=True,
                 dropout_keep_prob=0.8,
                 prediction_fn=slim.softmax,
                 spatial_squeeze=True,
                 reuse=None,
                 scope='InceptionV1'):
  """Defines the Inception V1 architecture.

  This architecture is defined in:

    Going deeper with convolutions
    Christian Szegedy, Wei Liu, Yangqing Jia, Pierre Sermanet, Scott Reed,
    Dragomir Anguelov, Dumitru Erhan, Vincent Vanhoucke, Andrew Rabinovich.
    http://arxiv.org/pdf/1409.4842v1.pdf.

  The default image size used to train this network is 224x224.

  Args:
    inputs: a tensor of size [batch_size, height, width, channels].
    num_classes: number of predicted classes.
    is_training: whether is training or not.
    dropout_keep_prob: the percentage of activation values that are retained.
    prediction_fn: a function to get predictions out of logits.
    spatial_squeeze: if True, logits is of shape is [B, C], if false logits is
        of shape [B, 1, 1, C], where B is batch_size and C is number of classes.
    reuse: whether or not the network and its variables should be reused. To be
      able to reuse 'scope' must be given.
    scope: Optional variable_scope.

  Returns:
    logits: the pre-softmax activations, a tensor of size
      [batch_size, num_classes]
    end_points: a dictionary from components of the network to the corresponding
      activation.
  """
  # Final pooling and prediction
  with tf.variable_scope(scope, 'InceptionV1', [inputs, num_classes],
                         reuse=reuse) as scope:
    with slim.arg_scope([slim.batch_norm, slim.dropout],
                        is_training=is_training):
      net, end_points = inception_v1_base(inputs, scope=scope)
      with tf.variable_scope('Logits'):
        net = slim.avg_pool2d(net, [7, 7], stride=1, scope='MaxPool_0a_7x7')
        net = slim.dropout(net,
                           dropout_keep_prob, scope='Dropout_0b')
        logits = slim.conv2d(net, num_classes, [1, 1], activation_fn=None,
                             normalizer_fn=None, scope='Conv2d_0c_1x1')
        if spatial_squeeze:
          logits = tf.squeeze(logits, [1, 2], name='SpatialSqueeze')

        end_points['Logits'] = logits
        end_points['Predictions'] = prediction_fn(logits, scope='Predictions')
  return logits, end_points
inception_v1.default_image_size = 224

inception_v1_arg_scope = inception_utils.inception_arg_scope


================================================
FILE: nets/inception_v1_test.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Tests for nets.inception_v1."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import numpy as np
import tensorflow as tf

from nets import inception

slim = tf.contrib.slim


class InceptionV1Test(tf.test.TestCase):

  def testBuildClassificationNetwork(self):
    batch_size = 5
    height, width = 224, 224
    num_classes = 1000

    inputs = tf.random_uniform((batch_size, height, width, 3))
    logits, end_points = inception.inception_v1(inputs, num_classes)
    self.assertTrue(logits.op.name.startswith('InceptionV1/Logits'))
    self.assertListEqual(logits.get_shape().as_list(),
                         [batch_size, num_classes])
    self.assertTrue('Predictions' in end_points)
    self.assertListEqual(end_points['Predictions'].get_shape().as_list(),
                         [batch_size, num_classes])

  def testBuildBaseNetwork(self):
    batch_size = 5
    height, width = 224, 224

    inputs = tf.random_uniform((batch_size, height, width, 3))
    mixed_6c, end_points = inception.inception_v1_base(inputs)
    self.assertTrue(mixed_6c.op.name.startswith('InceptionV1/Mixed_5c'))
    self.assertListEqual(mixed_6c.get_shape().as_list(),
                         [batch_size, 7, 7, 1024])
    expected_endpoints = ['Conv2d_1a_7x7', 'MaxPool_2a_3x3', 'Conv2d_2b_1x1',
                          'Conv2d_2c_3x3', 'MaxPool_3a_3x3', 'Mixed_3b',
                          'Mixed_3c', 'MaxPool_4a_3x3', 'Mixed_4b', 'Mixed_4c',
                          'Mixed_4d', 'Mixed_4e', 'Mixed_4f', 'MaxPool_5a_2x2',
                          'Mixed_5b', 'Mixed_5c']
    self.assertItemsEqual(end_points.keys(), expected_endpoints)

  def testBuildOnlyUptoFinalEndpoint(self):
    batch_size = 5
    height, width = 224, 224
    endpoints = ['Conv2d_1a_7x7', 'MaxPool_2a_3x3', 'Conv2d_2b_1x1',
                 'Conv2d_2c_3x3', 'MaxPool_3a_3x3', 'Mixed_3b', 'Mixed_3c',
                 'MaxPool_4a_3x3', 'Mixed_4b', 'Mixed_4c', 'Mixed_4d',
                 'Mixed_4e', 'Mixed_4f', 'MaxPool_5a_2x2', 'Mixed_5b',
                 'Mixed_5c']
    for index, endpoint in enumerate(endpoints):
      with tf.Graph().as_default():
        inputs = tf.random_uniform((batch_size, height, width, 3))
        out_tensor, end_points = inception.inception_v1_base(
            inputs, final_endpoint=endpoint)
        self.assertTrue(out_tensor.op.name.startswith(
            'InceptionV1/' + endpoint))
        self.assertItemsEqual(endpoints[:index+1], end_points)

  def testBuildAndCheckAllEndPointsUptoMixed5c(self):
    batch_size = 5
    height, width = 224, 224

    inputs = tf.random_uniform((batch_size, height, width, 3))
    _, end_points = inception.inception_v1_base(inputs,
                                                final_endpoint='Mixed_5c')
    endpoints_shapes = {'Conv2d_1a_7x7': [5, 112, 112, 64],
                        'MaxPool_2a_3x3': [5, 56, 56, 64],
                        'Conv2d_2b_1x1': [5, 56, 56, 64],
                        'Conv2d_2c_3x3': [5, 56, 56, 192],
                        'MaxPool_3a_3x3': [5, 28, 28, 192],
                        'Mixed_3b': [5, 28, 28, 256],
                        'Mixed_3c': [5, 28, 28, 480],
                        'MaxPool_4a_3x3': [5, 14, 14, 480],
                        'Mixed_4b': [5, 14, 14, 512],
                        'Mixed_4c': [5, 14, 14, 512],
                        'Mixed_4d': [5, 14, 14, 512],
                        'Mixed_4e': [5, 14, 14, 528],
                        'Mixed_4f': [5, 14, 14, 832],
                        'MaxPool_5a_2x2': [5, 7, 7, 832],
                        'Mixed_5b': [5, 7, 7, 832],
                        'Mixed_5c': [5, 7, 7, 1024]}

    self.assertItemsEqual(endpoints_shapes.keys(), end_points.keys())
    for endpoint_name in endpoints_shapes:
      expected_shape = endpoints_shapes[endpoint_name]
      self.assertTrue(endpoint_name in end_points)
      self.assertListEqual(end_points[endpoint_name].get_shape().as_list(),
                           expected_shape)

  def testModelHasExpectedNumberOfParameters(self):
    batch_size = 5
    height, width = 224, 224
    inputs = tf.random_uniform((batch_size, height, width, 3))
    with slim.arg_scope(inception.inception_v1_arg_scope()):
      inception.inception_v1_base(inputs)
    total_params, _ = slim.model_analyzer.analyze_vars(
        slim.get_model_variables())
    self.assertAlmostEqual(5607184, total_params)

  def testHalfSizeImages(self):
    batch_size = 5
    height, width = 112, 112

    inputs = tf.random_uniform((batch_size, height, width, 3))
    mixed_5c, _ = inception.inception_v1_base(inputs)
    self.assertTrue(mixed_5c.op.name.startswith('InceptionV1/Mixed_5c'))
    self.assertListEqual(mixed_5c.get_shape().as_list(),
                         [batch_size, 4, 4, 1024])

  def testUnknownImageShape(self):
    tf.reset_default_graph()
    batch_size = 2
    height, width = 224, 224
    num_classes = 1000
    input_np = np.random.uniform(0, 1, (batch_size, height, width, 3))
    with self.test_session() as sess:
      inputs = tf.placeholder(tf.float32, shape=(batch_size, None, None, 3))
      logits, end_points = inception.inception_v1(inputs, num_classes)
      self.assertTrue(logits.op.name.startswith('InceptionV1/Logits'))
      self.assertListEqual(logits.get_shape().as_list(),
                           [batch_size, num_classes])
      pre_pool = end_points['Mixed_5c']
      feed_dict = {inputs: input_np}
      tf.global_variables_initializer().run()
      pre_pool_out = sess.run(pre_pool, feed_dict=feed_dict)
      self.assertListEqual(list(pre_pool_out.shape), [batch_size, 7, 7, 1024])

  def testUnknowBatchSize(self):
    batch_size = 1
    height, width = 224, 224
    num_classes = 1000

    inputs = tf.placeholder(tf.float32, (None, height, width, 3))
    logits, _ = inception.inception_v1(inputs, num_classes)
    self.assertTrue(logits.op.name.startswith('InceptionV1/Logits'))
    self.assertListEqual(logits.get_shape().as_list(),
                         [None, num_classes])
    images = tf.random_uniform((batch_size, height, width, 3))

    with self.test_session() as sess:
      sess.run(tf.global_variables_initializer())
      output = sess.run(logits, {inputs: images.eval()})
      self.assertEquals(output.shape, (batch_size, num_classes))

  def testEvaluation(self):
    batch_size = 2
    height, width = 224, 224
    num_classes = 1000

    eval_inputs = tf.random_uniform((batch_size, height, width, 3))
    logits, _ = inception.inception_v1(eval_inputs, num_classes,
                                       is_training=False)
    predictions = tf.argmax(logits, 1)

    with self.test_session() as sess:
      sess.run(tf.global_variables_initializer())
      output = sess.run(predictions)
      self.assertEquals(output.shape, (batch_size,))

  def testTrainEvalWithReuse(self):
    train_batch_size = 5
    eval_batch_size = 2
    height, width = 224, 224
    num_classes = 1000

    train_inputs = tf.random_uniform((train_batch_size, height, width, 3))
    inception.inception_v1(train_inputs, num_classes)
    eval_inputs = tf.random_uniform((eval_batch_size, height, width, 3))
    logits, _ = inception.inception_v1(eval_inputs, num_classes, reuse=True)
    predictions = tf.argmax(logits, 1)

    with self.test_session() as sess:
      sess.run(tf.global_variables_initializer())
      output = sess.run(predictions)
      self.assertEquals(output.shape, (eval_batch_size,))

  def testLogitsNotSqueezed(self):
    num_classes = 25
    images = tf.random_uniform([1, 224, 224, 3])
    logits, _ = inception.inception_v1(images,
                                       num_classes=num_classes,
                                       spatial_squeeze=False)

    with self.test_session() as sess:
      tf.global_variables_initializer().run()
      logits_out = sess.run(logits)
      self.assertListEqual(list(logits_out.shape), [1, 1, 1, num_classes])


if __name__ == '__main__':
  tf.test.main()


================================================
FILE: nets/inception_v2.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Contains the definition for inception v2 classification network."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import tensorflow as tf

from nets import inception_utils

slim = tf.contrib.slim
trunc_normal = lambda stddev: tf.truncated_normal_initializer(0.0, stddev)


def inception_v2_base(inputs,
                      final_endpoint='Mixed_5c',
                      min_depth=16,
                      depth_multiplier=1.0,
                      scope=None):
  """Inception v2 (6a2).

  Constructs an Inception v2 network from inputs to the given final endpoint.
  This method can construct the network up to the layer inception(5b) as
  described in http://arxiv.org/abs/1502.03167.

  Args:
    inputs: a tensor of shape [batch_size, height, width, channels].
    final_endpoint: specifies the endpoint to construct the network up to. It
      can be one of ['Conv2d_1a_7x7', 'MaxPool_2a_3x3', 'Conv2d_2b_1x1',
      'Conv2d_2c_3x3', 'MaxPool_3a_3x3', 'Mixed_3b', 'Mixed_3c', 'Mixed_4a',
      'Mixed_4b', 'Mixed_4c', 'Mixed_4d', 'Mixed_4e', 'Mixed_5a', 'Mixed_5b',
      'Mixed_5c'].
    min_depth: Minimum depth value (number of channels) for all convolution ops.
      Enforced when depth_multiplier < 1, and not an active constraint when
      depth_multiplier >= 1.
    depth_multiplier: Float multiplier for the depth (number of channels)
      for all convolution ops. The value must be greater than zero. Typical
      usage will be to set this value in (0, 1) to reduce the number of
      parameters or computation cost of the model.
    scope: Optional variable_scope.

  Returns:
    tensor_out: output tensor corresponding to the final_endpoint.
    end_points: a set of activations for external use, for example summaries or
                losses.

  Raises:
    ValueError: if final_endpoint is not set to one of the predefined values,
                or depth_multiplier <= 0
  """

  # end_points will collect relevant activations for external use, for example
  # summaries or losses.
  end_points = {}

  # Used to find thinned depths for each layer.
  if depth_multiplier <= 0:
    raise ValueError('depth_multiplier is not greater than zero.')
  depth = lambda d: max(int(d * depth_multiplier), min_depth)

  with tf.variable_scope(scope, 'InceptionV2', [inputs]):
    with slim.arg_scope(
        [slim.conv2d, slim.max_pool2d, slim.avg_pool2d, slim.separable_conv2d],
        stride=1, padding='SAME'):

      # Note that sizes in the comments below assume an input spatial size of
      # 224x224, however, the inputs can be of any size greater 32x32.

      # 224 x 224 x 3
      end_point = 'Conv2d_1a_7x7'
      # depthwise_multiplier here is different from depth_multiplier.
      # depthwise_multiplier determines the output channels of the initial
      # depthwise conv (see docs for tf.nn.separable_conv2d), while
      # depth_multiplier controls the # channels of the subsequent 1x1
      # convolution. Must have
      #   in_channels * depthwise_multipler <= out_channels
      # so that the separable convolution is not overparameterized.
      depthwise_multiplier = min(int(depth(64) / 3), 8)
      net = slim.separable_conv2d(
          inputs, depth(64), [7, 7], depth_multiplier=depthwise_multiplier,
          stride=2, weights_initializer=trunc_normal(1.0),
          scope=end_point)
      end_points[end_point] = net
      if end_point == final_endpoint: return net, end_points
      # 112 x 112 x 64
      end_point = 'MaxPool_2a_3x3'
      net = slim.max_pool2d(net, [3, 3], scope=end_point, stride=2)
      end_points[end_point] = net
      if end_point == final_endpoint: return net, end_points
      # 56 x 56 x 64
      end_point = 'Conv2d_2b_1x1'
      net = slim.conv2d(net, depth(64), [1, 1], scope=end_point,
                        weights_initializer=trunc_normal(0.1))
      end_points[end_point] = net
      if end_point == final_endpoint: return net, end_points
      # 56 x 56 x 64
      end_point = 'Conv2d_2c_3x3'
      net = slim.conv2d(net, depth(192), [3, 3], scope=end_point)
      end_points[end_point] = net
      if end_point == final_endpoint: return net, end_points
      # 56 x 56 x 192
      end_point = 'MaxPool_3a_3x3'
      net = slim.max_pool2d(net, [3, 3], scope=end_point, stride=2)
      end_points[end_point] = net
      if end_point == final_endpoint: return net, end_points
      # 28 x 28 x 192
      # Inception module.
      end_point = 'Mixed_3b'
      with tf.variable_scope(end_point):
        with tf.variable_scope('Branch_0'):
          branch_0 = slim.conv2d(net, depth(64), [1, 1], scope='Conv2d_0a_1x1')
        with tf.variable_scope('Branch_1'):
          branch_1 = slim.conv2d(
              net, depth(64), [1, 1],
              weights_initializer=trunc_normal(0.09),
              scope='Conv2d_0a_1x1')
          branch_1 = slim.conv2d(branch_1, depth(64), [3, 3],
                                 scope='Conv2d_0b_3x3')
        with tf.variable_scope('Branch_2'):
          branch_2 = slim.conv2d(
              net, depth(64), [1, 1],
              weights_initializer=trunc_normal(0.09),
              scope='Conv2d_0a_1x1')
          branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
                                 scope='Conv2d_0b_3x3')
          branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
                                 scope='Conv2d_0c_3x3')
        with tf.variable_scope('Branch_3'):
          branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
          branch_3 = slim.conv2d(
              branch_3, depth(32), [1, 1],
              weights_initializer=trunc_normal(0.1),
              scope='Conv2d_0b_1x1')
        net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
        end_points[end_point] = net
        if end_point == final_endpoint: return net, end_points
      # 28 x 28 x 256
      end_point = 'Mixed_3c'
      with tf.variable_scope(end_point):
        with tf.variable_scope('Branch_0'):
          branch_0 = slim.conv2d(net, depth(64), [1, 1], scope='Conv2d_0a_1x1')
        with tf.variable_scope('Branch_1'):
          branch_1 = slim.conv2d(
              net, depth(64), [1, 1],
              weights_initializer=trunc_normal(0.09),
              scope='Conv2d_0a_1x1')
          branch_1 = slim.conv2d(branch_1, depth(96), [3, 3],
                                 scope='Conv2d_0b_3x3')
        with tf.variable_scope('Branch_2'):
          branch_2 = slim.conv2d(
              net, depth(64), [1, 1],
              weights_initializer=trunc_normal(0.09),
              scope='Conv2d_0a_1x1')
          branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
                                 scope='Conv2d_0b_3x3')
          branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
                                 scope='Conv2d_0c_3x3')
        with tf.variable_scope('Branch_3'):
          branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
          branch_3 = slim.conv2d(
              branch_3, depth(64), [1, 1],
              weights_initializer=trunc_normal(0.1),
              scope='Conv2d_0b_1x1')
        net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
        end_points[end_point] = net
        if end_point == final_endpoint: return net, end_points
      # 28 x 28 x 320
      end_point = 'Mixed_4a'
      with tf.variable_scope(end_point):
        with tf.variable_scope('Branch_0'):
          branch_0 = slim.conv2d(
              net, depth(128), [1, 1],
              weights_initializer=trunc_normal(0.09),
              scope='Conv2d_0a_1x1')
          branch_0 = slim.conv2d(branch_0, depth(160), [3, 3], stride=2,
                                 scope='Conv2d_1a_3x3')
        with tf.variable_scope('Branch_1'):
          branch_1 = slim.conv2d(
              net, depth(64), [1, 1],
              weights_initializer=trunc_normal(0.09),
              scope='Conv2d_0a_1x1')
          branch_1 = slim.conv2d(
              branch_1, depth(96), [3, 3], scope='Conv2d_0b_3x3')
          branch_1 = slim.conv2d(
              branch_1, depth(96), [3, 3], stride=2, scope='Conv2d_1a_3x3')
        with tf.variable_scope('Branch_2'):
          branch_2 = slim.max_pool2d(
              net, [3, 3], stride=2, scope='MaxPool_1a_3x3')
        net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2])
        end_points[end_point] = net
        if end_point == final_endpoint: return net, end_points
      # 14 x 14 x 576
      end_point = 'Mixed_4b'
      with tf.variable_scope(end_point):
        with tf.variable_scope('Branch_0'):
          branch_0 = slim.conv2d(net, depth(224), [1, 1], scope='Conv2d_0a_1x1')
        with tf.variable_scope('Branch_1'):
          branch_1 = slim.conv2d(
              net, depth(64), [1, 1],
              weights_initializer=trunc_normal(0.09),
              scope='Conv2d_0a_1x1')
          branch_1 = slim.conv2d(
              branch_1, depth(96), [3, 3], scope='Conv2d_0b_3x3')
        with tf.variable_scope('Branch_2'):
          branch_2 = slim.conv2d(
              net, depth(96), [1, 1],
              weights_initializer=trunc_normal(0.09),
              scope='Conv2d_0a_1x1')
          branch_2 = slim.conv2d(branch_2, depth(128), [3, 3],
                                 scope='Conv2d_0b_3x3')
          branch_2 = slim.conv2d(branch_2, depth(128), [3, 3],
                                 scope='Conv2d_0c_3x3')
        with tf.variable_scope('Branch_3'):
          branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
          branch_3 = slim.conv2d(
              branch_3, depth(128), [1, 1],
              weights_initializer=trunc_normal(0.1),
              scope='Conv2d_0b_1x1')
        net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
        end_points[end_point] = net
        if end_point == final_endpoint: return net, end_points
      # 14 x 14 x 576
      end_point = 'Mixed_4c'
      with tf.variable_scope(end_point):
        with tf.variable_scope('Branch_0'):
          branch_0 = slim.conv2d(net, depth(192), [1, 1], scope='Conv2d_0a_1x1')
        with tf.variable_scope('Branch_1'):
          branch_1 = slim.conv2d(
              net, depth(96), [1, 1],
              weights_initializer=trunc_normal(0.09),
              scope='Conv2d_0a_1x1')
          branch_1 = slim.conv2d(branch_1, depth(128), [3, 3],
                                 scope='Conv2d_0b_3x3')
        with tf.variable_scope('Branch_2'):
          branch_2 = slim.conv2d(
              net, depth(96), [1, 1],
              weights_initializer=trunc_normal(0.09),
              scope='Conv2d_0a_1x1')
          branch_2 = slim.conv2d(branch_2, depth(128), [3, 3],
                                 scope='Conv2d_0b_3x3')
          branch_2 = slim.conv2d(branch_2, depth(128), [3, 3],
                                 scope='Conv2d_0c_3x3')
        with tf.variable_scope('Branch_3'):
          branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
          branch_3 = slim.conv2d(
              branch_3, depth(128), [1, 1],
              weights_initializer=trunc_normal(0.1),
              scope='Conv2d_0b_1x1')
        net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
        end_points[end_point] = net
        if end_point == final_endpoint: return net, end_points
      # 14 x 14 x 576
      end_point = 'Mixed_4d'
      with tf.variable_scope(end_point):
        with tf.variable_scope('Branch_0'):
          branch_0 = slim.conv2d(net, depth(160), [1, 1], scope='Conv2d_0a_1x1')
        with tf.variable_scope('Branch_1'):
          branch_1 = slim.conv2d(
              net, depth(128), [1, 1],
              weights_initializer=trunc_normal(0.09),
              scope='Conv2d_0a_1x1')
          branch_1 = slim.conv2d(branch_1, depth(160), [3, 3],
                                 scope='Conv2d_0b_3x3')
        with tf.variable_scope('Branch_2'):
          branch_2 = slim.conv2d(
              net, depth(128), [1, 1],
              weights_initializer=trunc_normal(0.09),
              scope='Conv2d_0a_1x1')
          branch_2 = slim.conv2d(branch_2, depth(160), [3, 3],
                                 scope='Conv2d_0b_3x3')
          branch_2 = slim.conv2d(branch_2, depth(160), [3, 3],
                                 scope='Conv2d_0c_3x3')
        with tf.variable_scope('Branch_3'):
          branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
          branch_3 = slim.conv2d(
              branch_3, depth(96), [1, 1],
              weights_initializer=trunc_normal(0.1),
              scope='Conv2d_0b_1x1')
        net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
        end_points[end_point] = net
        if end_point == final_endpoint: return net, end_points

      # 14 x 14 x 576
      end_point = 'Mixed_4e'
      with tf.variable_scope(end_point):
        with tf.variable_scope('Branch_0'):
          branch_0 = slim.conv2d(net, depth(96), [1, 1], scope='Conv2d_0a_1x1')
        with tf.variable_scope('Branch_1'):
          branch_1 = slim.conv2d(
              net, depth(128), [1, 1],
              weights_initializer=trunc_normal(0.09),
              scope='Conv2d_0a_1x1')
          branch_1 = slim.conv2d(branch_1, depth(192), [3, 3],
                                 scope='Conv2d_0b_3x3')
        with tf.variable_scope('Branch_2'):
          branch_2 = slim.conv2d(
              net, depth(160), [1, 1],
              weights_initializer=trunc_normal(0.09),
              scope='Conv2d_0a_1x1')
          branch_2 = slim.conv2d(branch_2, depth(192), [3, 3],
                                 scope='Conv2d_0b_3x3')
          branch_2 = slim.conv2d(branch_2, depth(192), [3, 3],
                                 scope='Conv2d_0c_3x3')
        with tf.variable_scope('Branch_3'):
          branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
          branch_3 = slim.conv2d(
              branch_3, depth(96), [1, 1],
              weights_initializer=trunc_normal(0.1),
              scope='Conv2d_0b_1x1')
        net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
        end_points[end_point] = net
        if end_point == final_endpoint: return net, end_points
      # 14 x 14 x 576
      end_point = 'Mixed_5a'
      with tf.variable_scope(end_point):
        with tf.variable_scope('Branch_0'):
          branch_0 = slim.conv2d(
              net, depth(128), [1, 1],
              weights_initializer=trunc_normal(0.09),
              scope='Conv2d_0a_1x1')
          branch_0 = slim.conv2d(branch_0, depth(192), [3, 3], stride=2,
                                 scope='Conv2d_1a_3x3')
        with tf.variable_scope('Branch_1'):
          branch_1 = slim.conv2d(
              net, depth(192), [1, 1],
              weights_initializer=trunc_normal(0.09),
              scope='Conv2d_0a_1x1')
          branch_1 = slim.conv2d(branch_1, depth(256), [3, 3],
                                 scope='Conv2d_0b_3x3')
          branch_1 = slim.conv2d(branch_1, depth(256), [3, 3], stride=2,
                                 scope='Conv2d_1a_3x3')
        with tf.variable_scope('Branch_2'):
          branch_2 = slim.max_pool2d(net, [3, 3], stride=2,
                                     scope='MaxPool_1a_3x3')
        net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2])
        end_points[end_point] = net
        if end_point == final_endpoint: return net, end_points
      # 7 x 7 x 1024
      end_point = 'Mixed_5b'
      with tf.variable_scope(end_point):
        with tf.variable_scope('Branch_0'):
          branch_0 = slim.conv2d(net, depth(352), [1, 1], scope='Conv2d_0a_1x1')
        with tf.variable_scope('Branch_1'):
          branch_1 = slim.conv2d(
              net, depth(192), [1, 1],
              weights_initializer=trunc_normal(0.09),
              scope='Conv2d_0a_1x1')
          branch_1 = slim.conv2d(branch_1, depth(320), [3, 3],
                                 scope='Conv2d_0b_3x3')
        with tf.variable_scope('Branch_2'):
          branch_2 = slim.conv2d(
              net, depth(160), [1, 1],
              weights_initializer=trunc_normal(0.09),
              scope='Conv2d_0a_1x1')
          branch_2 = slim.conv2d(branch_2, depth(224), [3, 3],
                                 scope='Conv2d_0b_3x3')
          branch_2 = slim.conv2d(branch_2, depth(224), [3, 3],
                                 scope='Conv2d_0c_3x3')
        with tf.variable_scope('Branch_3'):
          branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
          branch_3 = slim.conv2d(
              branch_3, depth(128), [1, 1],
              weights_initializer=trunc_normal(0.1),
              scope='Conv2d_0b_1x1')
        net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
        end_points[end_point] = net
        if end_point == final_endpoint: return net, end_points

      # 7 x 7 x 1024
      end_point = 'Mixed_5c'
      with tf.variable_scope(end_point):
        with tf.variable_scope('Branch_0'):
          branch_0 = slim.conv2d(net, depth(352), [1, 1], scope='Conv2d_0a_1x1')
        with tf.variable_scope('Branch_1'):
          branch_1 = slim.conv2d(
              net, depth(192), [1, 1],
              weights_initializer=trunc_normal(0.09),
              scope='Conv2d_0a_1x1')
          branch_1 = slim.conv2d(branch_1, depth(320), [3, 3],
                                 scope='Conv2d_0b_3x3')
        with tf.variable_scope('Branch_2'):
          branch_2 = slim.conv2d(
              net, depth(192), [1, 1],
              weights_initializer=trunc_normal(0.09),
              scope='Conv2d_0a_1x1')
          branch_2 = slim.conv2d(branch_2, depth(224), [3, 3],
                                 scope='Conv2d_0b_3x3')
          branch_2 = slim.conv2d(branch_2, depth(224), [3, 3],
                                 scope='Conv2d_0c_3x3')
        with tf.variable_scope('Branch_3'):
          branch_3 = slim.max_pool2d(net, [3, 3], scope='MaxPool_0a_3x3')
          branch_3 = slim.conv2d(
              branch_3, depth(128), [1, 1],
              weights_initializer=trunc_normal(0.1),
              scope='Conv2d_0b_1x1')
        net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
        end_points[end_point] = net
        if end_point == final_endpoint: return net, end_points
    raise ValueError('Unknown final endpoint %s' % final_endpoint)


def inception_v2(inputs,
                 num_classes=1000,
                 is_training=True,
                 dropout_keep_prob=0.8,
                 min_depth=16,
                 depth_multiplier=1.0,
                 prediction_fn=slim.softmax,
                 spatial_squeeze=True,
                 reuse=None,
                 scope='InceptionV2'):
  """Inception v2 model for classification.

  Constructs an Inception v2 network for classification as described in
  http://arxiv.org/abs/1502.03167.

  The default image size used to train this network is 224x224.

  Args:
    inputs: a tensor of shape [batch_size, height, width, channels].
    num_classes: number of predicted classes.
    is_training: whether is training or not.
    dropout_keep_prob: the percentage of activation values that are retained.
    min_depth: Minimum depth value (number of channels) for all convolution ops.
      Enforced when depth_multiplier < 1, and not an active constraint when
      depth_multiplier >= 1.
    depth_multiplier: Float multiplier for the depth (number of channels)
      for all convolution ops. The value must be greater than zero. Typical
      usage will be to set this value in (0, 1) to reduce the number of
      parameters or computation cost of the model.
    prediction_fn: a function to get predictions out of logits.
    spatial_squeeze: if True, logits is of shape is [B, C], if false logits is
        of shape [B, 1, 1, C], where B is batch_size and C is number of classes.
    reuse: whether or not the network and its variables should be reused. To be
      able to reuse 'scope' must be given.
    scope: Optional variable_scope.

  Returns:
    logits: the pre-softmax activations, a tensor of size
      [batch_size, num_classes]
    end_points: a dictionary from components of the network to the corresponding
      activation.

  Raises:
    ValueError: if final_endpoint is not set to one of the predefined values,
                or depth_multiplier <= 0
  """
  if depth_multiplier <= 0:
    raise ValueError('depth_multiplier is not greater than zero.')

  # Final pooling and prediction
  with tf.variable_scope(scope, 'InceptionV2', [inputs, num_classes],
                         reuse=reuse) as scope:
    with slim.arg_scope([slim.batch_norm, slim.dropout],
                        is_training=is_training):
      net, end_points = inception_v2_base(
          inputs, scope=scope, min_depth=min_depth,
          depth_multiplier=depth_multiplier)
      with tf.variable_scope('Logits'):
        kernel_size = _reduced_kernel_size_for_small_input(net, [7, 7])
        net = slim.avg_pool2d(net, kernel_size, padding='VALID',
                              scope='AvgPool_1a_{}x{}'.format(*kernel_size))
        # 1 x 1 x 1024
        net = slim.dropout(net, keep_prob=dropout_keep_prob, scope='Dropout_1b')
        logits = slim.conv2d(net, num_classes, [1, 1], activation_fn=None,
                             normalizer_fn=None, scope='Conv2d_1c_1x1')
        if spatial_squeeze:
          logits = tf.squeeze(logits, [1, 2], name='SpatialSqueeze')
      end_points['Logits'] = logits
      end_points['Predictions'] = prediction_fn(logits, scope='Predictions')
  return logits, end_points
inception_v2.default_image_size = 224


def _reduced_kernel_size_for_small_input(input_tensor, kernel_size):
  """Define kernel size which is automatically reduced for small input.

  If the shape of the input images is unknown at graph construction time this
  function assumes that the input images are is large enough.

  Args:
    input_tensor: input tensor of size [batch_size, height, width, channels].
    kernel_size: desired kernel size of length 2: [kernel_height, kernel_width]

  Returns:
    a tensor with the kernel size.

  TODO(jrru): Make this function work with unknown shapes. Theoretically, this
  can be done with the code below. Problems are two-fold: (1) If the shape was
  known, it will be lost. (2) inception.slim.ops._two_element_tuple cannot
  handle tensors that define the kernel size.
      shape = tf.shape(input_tensor)
      return = tf.pack([tf.minimum(shape[1], kernel_size[0]),
                        tf.minimum(shape[2], kernel_size[1])])

  """
  shape = input_tensor.get_shape().as_list()
  if shape[1] is None or shape[2] is None:
    kernel_size_out = kernel_size
  else:
    kernel_size_out = [min(shape[1], kernel_size[0]),
                       min(shape[2], kernel_size[1])]
  return kernel_size_out


inception_v2_arg_scope = inception_utils.inception_arg_scope


================================================
FILE: nets/inception_v2_test.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Tests for nets.inception_v2."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import numpy as np
import tensorflow as tf

from nets import inception

slim = tf.contrib.slim


class InceptionV2Test(tf.test.TestCase):

  def testBuildClassificationNetwork(self):
    batch_size = 5
    height, width = 224, 224
    num_classes = 1000

    inputs = tf.random_uniform((batch_size, height, width, 3))
    logits, end_points = inception.inception_v2(inputs, num_classes)
    self.assertTrue(logits.op.name.startswith('InceptionV2/Logits'))
    self.assertListEqual(logits.get_shape().as_list(),
                         [batch_size, num_classes])
    self.assertTrue('Predictions' in end_points)
    self.assertListEqual(end_points['Predictions'].get_shape().as_list(),
                         [batch_size, num_classes])

  def testBuildBaseNetwork(self):
    batch_size = 5
    height, width = 224, 224

    inputs = tf.random_uniform((batch_size, height, width, 3))
    mixed_5c, end_points = inception.inception_v2_base(inputs)
    self.assertTrue(mixed_5c.op.name.startswith('InceptionV2/Mixed_5c'))
    self.assertListEqual(mixed_5c.get_shape().as_list(),
                         [batch_size, 7, 7, 1024])
    expected_endpoints = ['Mixed_3b', 'Mixed_3c', 'Mixed_4a', 'Mixed_4b',
                          'Mixed_4c', 'Mixed_4d', 'Mixed_4e', 'Mixed_5a',
                          'Mixed_5b', 'Mixed_5c', 'Conv2d_1a_7x7',
                          'MaxPool_2a_3x3', 'Conv2d_2b_1x1', 'Conv2d_2c_3x3',
                          'MaxPool_3a_3x3']
    self.assertItemsEqual(end_points.keys(), expected_endpoints)

  def testBuildOnlyUptoFinalEndpoint(self):
    batch_size = 5
    height, width = 224, 224
    endpoints = ['Conv2d_1a_7x7', 'MaxPool_2a_3x3', 'Conv2d_2b_1x1',
                 'Conv2d_2c_3x3', 'MaxPool_3a_3x3', 'Mixed_3b', 'Mixed_3c',
                 'Mixed_4a', 'Mixed_4b', 'Mixed_4c', 'Mixed_4d', 'Mixed_4e',
                 'Mixed_5a', 'Mixed_5b', 'Mixed_5c']
    for index, endpoint in enumerate(endpoints):
      with tf.Graph().as_default():
        inputs = tf.random_uniform((batch_size, height, width, 3))
        out_tensor, end_points = inception.inception_v2_base(
            inputs, final_endpoint=endpoint)
        self.assertTrue(out_tensor.op.name.startswith(
            'InceptionV2/' + endpoint))
        self.assertItemsEqual(endpoints[:index+1], end_points)

  def testBuildAndCheckAllEndPointsUptoMixed5c(self):
    batch_size = 5
    height, width = 224, 224

    inputs = tf.random_uniform((batch_size, height, width, 3))
    _, end_points = inception.inception_v2_base(inputs,
                                                final_endpoint='Mixed_5c')
    endpoints_shapes = {'Mixed_3b': [batch_size, 28, 28, 256],
                        'Mixed_3c': [batch_size, 28, 28, 320],
                        'Mixed_4a': [batch_size, 14, 14, 576],
                        'Mixed_4b': [batch_size, 14, 14, 576],
                        'Mixed_4c': [batch_size, 14, 14, 576],
                        'Mixed_4d': [batch_size, 14, 14, 576],
                        'Mixed_4e': [batch_size, 14, 14, 576],
                        'Mixed_5a': [batch_size, 7, 7, 1024],
                        'Mixed_5b': [batch_size, 7, 7, 1024],
                        'Mixed_5c': [batch_size, 7, 7, 1024],
                        'Conv2d_1a_7x7': [batch_size, 112, 112, 64],
                        'MaxPool_2a_3x3': [batch_size, 56, 56, 64],
                        'Conv2d_2b_1x1': [batch_size, 56, 56, 64],
                        'Conv2d_2c_3x3': [batch_size, 56, 56, 192],
                        'MaxPool_3a_3x3': [batch_size, 28, 28, 192]}
    self.assertItemsEqual(endpoints_shapes.keys(), end_points.keys())
    for endpoint_name in endpoints_shapes:
      expected_shape = endpoints_shapes[endpoint_name]
      self.assertTrue(endpoint_name in end_points)
      self.assertListEqual(end_points[endpoint_name].get_shape().as_list(),
                           expected_shape)

  def testModelHasExpectedNumberOfParameters(self):
    batch_size = 5
    height, width = 224, 224
    inputs = tf.random_uniform((batch_size, height, width, 3))
    with slim.arg_scope(inception.inception_v2_arg_scope()):
      inception.inception_v2_base(inputs)
    total_params, _ = slim.model_analyzer.analyze_vars(
        slim.get_model_variables())
    self.assertAlmostEqual(10173112, total_params)

  def testBuildEndPointsWithDepthMultiplierLessThanOne(self):
    batch_size = 5
    height, width = 224, 224
    num_classes = 1000

    inputs = tf.random_uniform((batch_size, height, width, 3))
    _, end_points = inception.inception_v2(inputs, num_classes)

    endpoint_keys = [key for key in end_points.keys()
                     if key.startswith('Mixed') or key.startswith('Conv')]

    _, end_points_with_multiplier = inception.inception_v2(
        inputs, num_classes, scope='depth_multiplied_net',
        depth_multiplier=0.5)

    for key in endpoint_keys:
      original_depth = end_points[key].get_shape().as_list()[3]
      new_depth = end_points_with_multiplier[key].get_shape().as_list()[3]
      self.assertEqual(0.5 * original_depth, new_depth)

  def testBuildEndPointsWithDepthMultiplierGreaterThanOne(self):
    batch_size = 5
    height, width = 224, 224
    num_classes = 1000

    inputs = tf.random_uniform((batch_size, height, width, 3))
    _, end_points = inception.inception_v2(inputs, num_classes)

    endpoint_keys = [key for key in end_points.keys()
                     if key.startswith('Mixed') or key.startswith('Conv')]

    _, end_points_with_multiplier = inception.inception_v2(
        inputs, num_classes, scope='depth_multiplied_net',
        depth_multiplier=2.0)

    for key in endpoint_keys:
      original_depth = end_points[key].get_shape().as_list()[3]
      new_depth = end_points_with_multiplier[key].get_shape().as_list()[3]
      self.assertEqual(2.0 * original_depth, new_depth)

  def testRaiseValueErrorWithInvalidDepthMultiplier(self):
    batch_size = 5
    height, width = 224, 224
    num_classes = 1000

    inputs = tf.random_uniform((batch_size, height, width, 3))
    with self.assertRaises(ValueError):
      _ = inception.inception_v2(inputs, num_classes, depth_multiplier=-0.1)
    with self.assertRaises(ValueError):
      _ = inception.inception_v2(inputs, num_classes, depth_multiplier=0.0)

  def testHalfSizeImages(self):
    batch_size = 5
    height, width = 112, 112
    num_classes = 1000

    inputs = tf.random_uniform((batch_size, height, width, 3))
    logits, end_points = inception.inception_v2(inputs, num_classes)
    self.assertTrue(logits.op.name.startswith('InceptionV2/Logits'))
    self.assertListEqual(logits.get_shape().as_list(),
                         [batch_size, num_classes])
    pre_pool = end_points['Mixed_5c']
    self.assertListEqual(pre_pool.get_shape().as_list(),
                         [batch_size, 4, 4, 1024])

  def testUnknownImageShape(self):
    tf.reset_default_graph()
    batch_size = 2
    height, width = 224, 224
    num_classes = 1000
    input_np = np.random.uniform(0, 1, (batch_size, height, width, 3))
    with self.test_session() as sess:
      inputs = tf.placeholder(tf.float32, shape=(batch_size, None, None, 3))
      logits, end_points = inception.inception_v2(inputs, num_classes)
      self.assertTrue(logits.op.name.startswith('InceptionV2/Logits'))
      self.assertListEqual(logits.get_shape().as_list(),
                           [batch_size, num_classes])
      pre_pool = end_points['Mixed_5c']
      feed_dict = {inputs: input_np}
      tf.global_variables_initializer().run()
      pre_pool_out = sess.run(pre_pool, feed_dict=feed_dict)
      self.assertListEqual(list(pre_pool_out.shape), [batch_size, 7, 7, 1024])

  def testUnknowBatchSize(self):
    batch_size = 1
    height, width = 224, 224
    num_classes = 1000

    inputs = tf.placeholder(tf.float32, (None, height, width, 3))
    logits, _ = inception.inception_v2(inputs, num_classes)
    self.assertTrue(logits.op.name.startswith('InceptionV2/Logits'))
    self.assertListEqual(logits.get_shape().as_list(),
                         [None, num_classes])
    images = tf.random_uniform((batch_size, height, width, 3))

    with self.test_session() as sess:
      sess.run(tf.global_variables_initializer())
      output = sess.run(logits, {inputs: images.eval()})
      self.assertEquals(output.shape, (batch_size, num_classes))

  def testEvaluation(self):
    batch_size = 2
    height, width = 224, 224
    num_classes = 1000

    eval_inputs = tf.random_uniform((batch_size, height, width, 3))
    logits, _ = inception.inception_v2(eval_inputs, num_classes,
                                       is_training=False)
    predictions = tf.argmax(logits, 1)

    with self.test_session() as sess:
      sess.run(tf.global_variables_initializer())
      output = sess.run(predictions)
      self.assertEquals(output.shape, (batch_size,))

  def testTrainEvalWithReuse(self):
    train_batch_size = 5
    eval_batch_size = 2
    height, width = 150, 150
    num_classes = 1000

    train_inputs = tf.random_uniform((train_batch_size, height, width, 3))
    inception.inception_v2(train_inputs, num_classes)
    eval_inputs = tf.random_uniform((eval_batch_size, height, width, 3))
    logits, _ = inception.inception_v2(eval_inputs, num_classes, reuse=True)
    predictions = tf.argmax(logits, 1)

    with self.test_session() as sess:
      sess.run(tf.global_variables_initializer())
      output = sess.run(predictions)
      self.assertEquals(output.shape, (eval_batch_size,))

  def testLogitsNotSqueezed(self):
    num_classes = 25
    images = tf.random_uniform([1, 224, 224, 3])
    logits, _ = inception.inception_v2(images,
                                       num_classes=num_classes,
                                       spatial_squeeze=False)

    with self.test_session() as sess:
      tf.global_variables_initializer().run()
      logits_out = sess.run(logits)
      self.assertListEqual(list(logits_out.shape), [1, 1, 1, num_classes])


if __name__ == '__main__':
  tf.test.main()


================================================
FILE: nets/inception_v3.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Contains the definition for inception v3 classification network."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import tensorflow as tf

from nets import inception_utils

slim = tf.contrib.slim
trunc_normal = lambda stddev: tf.truncated_normal_initializer(0.0, stddev)


def inception_v3_base(inputs,
                      final_endpoint='Mixed_7c',
                      min_depth=16,
                      depth_multiplier=1.0,
                      scope=None):
  """Inception model from http://arxiv.org/abs/1512.00567.

  Constructs an Inception v3 network from inputs to the given final endpoint.
  This method can construct the network up to the final inception block
  Mixed_7c.

  Note that the names of the layers in the paper do not correspond to the names
  of the endpoints registered by this function although they build the same
  network.

  Here is a mapping from the old_names to the new names:
  Old name          | New name
  =======================================
  conv0             | Conv2d_1a_3x3
  conv1             | Conv2d_2a_3x3
  conv2             | Conv2d_2b_3x3
  pool1             | MaxPool_3a_3x3
  conv3             | Conv2d_3b_1x1
  conv4             | Conv2d_4a_3x3
  pool2             | MaxPool_5a_3x3
  mixed_35x35x256a  | Mixed_5b
  mixed_35x35x288a  | Mixed_5c
  mixed_35x35x288b  | Mixed_5d
  mixed_17x17x768a  | Mixed_6a
  mixed_17x17x768b  | Mixed_6b
  mixed_17x17x768c  | Mixed_6c
  mixed_17x17x768d  | Mixed_6d
  mixed_17x17x768e  | Mixed_6e
  mixed_8x8x1280a   | Mixed_7a
  mixed_8x8x2048a   | Mixed_7b
  mixed_8x8x2048b   | Mixed_7c

  Args:
    inputs: a tensor of size [batch_size, height, width, channels].
    final_endpoint: specifies the endpoint to construct the network up to. It
      can be one of ['Conv2d_1a_3x3', 'Conv2d_2a_3x3', 'Conv2d_2b_3x3',
      'MaxPool_3a_3x3', 'Conv2d_3b_1x1', 'Conv2d_4a_3x3', 'MaxPool_5a_3x3',
      'Mixed_5b', 'Mixed_5c', 'Mixed_5d', 'Mixed_6a', 'Mixed_6b', 'Mixed_6c',
      'Mixed_6d', 'Mixed_6e', 'Mixed_7a', 'Mixed_7b', 'Mixed_7c'].
    min_depth: Minimum depth value (number of channels) for all convolution ops.
      Enforced when depth_multiplier < 1, and not an active constraint when
      depth_multiplier >= 1.
    depth_multiplier: Float multiplier for the depth (number of channels)
      for all convolution ops. The value must be greater than zero. Typical
      usage will be to set this value in (0, 1) to reduce the number of
      parameters or computation cost of the model.
    scope: Optional variable_scope.

  Returns:
    tensor_out: output tensor corresponding to the final_endpoint.
    end_points: a set of activations for external use, for example summaries or
                losses.

  Raises:
    ValueError: if final_endpoint is not set to one of the predefined values,
                or depth_multiplier <= 0
  """
  # end_points will collect relevant activations for external use, for example
  # summaries or losses.
  end_points = {}

  if depth_multiplier <= 0:
    raise ValueError('depth_multiplier is not greater than zero.')
  depth = lambda d: max(int(d * depth_multiplier), min_depth)

  with tf.variable_scope(scope, 'InceptionV3', [inputs]):
    with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d],
                        stride=1, padding='VALID'):
      # 299 x 299 x 3
      end_point = 'Conv2d_1a_3x3'
      net = slim.conv2d(inputs, depth(32), [3, 3], stride=2, scope=end_point)
      end_points[end_point] = net
      if end_point == final_endpoint: return net, end_points
      # 149 x 149 x 32
      end_point = 'Conv2d_2a_3x3'
      net = slim.conv2d(net, depth(32), [3, 3], scope=end_point)
      end_points[end_point] = net
      if end_point == final_endpoint: return net, end_points
      # 147 x 147 x 32
      end_point = 'Conv2d_2b_3x3'
      net = slim.conv2d(net, depth(64), [3, 3], padding='SAME', scope=end_point)
      end_points[end_point] = net
      if end_point == final_endpoint: return net, end_points
      # 147 x 147 x 64
      end_point = 'MaxPool_3a_3x3'
      net = slim.max_pool2d(net, [3, 3], stride=2, scope=end_point)
      end_points[end_point] = net
      if end_point == final_endpoint: return net, end_points
      # 73 x 73 x 64
      end_point = 'Conv2d_3b_1x1'
      net = slim.conv2d(net, depth(80), [1, 1], scope=end_point)
      end_points[end_point] = net
      if end_point == final_endpoint: return net, end_points
      # 73 x 73 x 80.
      end_point = 'Conv2d_4a_3x3'
      net = slim.conv2d(net, depth(192), [3, 3], scope=end_point)
      end_points[end_point] = net
      if end_point == final_endpoint: return net, end_points
      # 71 x 71 x 192.
      end_point = 'MaxPool_5a_3x3'
      net = slim.max_pool2d(net, [3, 3], stride=2, scope=end_point)
      end_points[end_point] = net
      if end_point == final_endpoint: return net, end_points
      # 35 x 35 x 192.

    # Inception blocks
    with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d],
                        stride=1, padding='SAME'):
      # mixed: 35 x 35 x 256.
      end_point = 'Mixed_5b'
      with tf.variable_scope(end_point):
        with tf.variable_scope('Branch_0'):
          branch_0 = slim.conv2d(net, depth(64), [1, 1], scope='Conv2d_0a_1x1')
        with tf.variable_scope('Branch_1'):
          branch_1 = slim.conv2d(net, depth(48), [1, 1], scope='Conv2d_0a_1x1')
          branch_1 = slim.conv2d(branch_1, depth(64), [5, 5],
                                 scope='Conv2d_0b_5x5')
        with tf.variable_scope('Branch_2'):
          branch_2 = slim.conv2d(net, depth(64), [1, 1], scope='Conv2d_0a_1x1')
          branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
                                 scope='Conv2d_0b_3x3')
          branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
                                 scope='Conv2d_0c_3x3')
        with tf.variable_scope('Branch_3'):
          branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
          branch_3 = slim.conv2d(branch_3, depth(32), [1, 1],
                                 scope='Conv2d_0b_1x1')
        net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
      end_points[end_point] = net
      if end_point == final_endpoint: return net, end_points

      # mixed_1: 35 x 35 x 288.
      end_point = 'Mixed_5c'
      with tf.variable_scope(end_point):
        with tf.variable_scope('Branch_0'):
          branch_0 = slim.conv2d(net, depth(64), [1, 1], scope='Conv2d_0a_1x1')
        with tf.variable_scope('Branch_1'):
          branch_1 = slim.conv2d(net, depth(48), [1, 1], scope='Conv2d_0b_1x1')
          branch_1 = slim.conv2d(branch_1, depth(64), [5, 5],
                                 scope='Conv_1_0c_5x5')
        with tf.variable_scope('Branch_2'):
          branch_2 = slim.conv2d(net, depth(64), [1, 1],
                                 scope='Conv2d_0a_1x1')
          branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
                                 scope='Conv2d_0b_3x3')
          branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
                                 scope='Conv2d_0c_3x3')
        with tf.variable_scope('Branch_3'):
          branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
          branch_3 = slim.conv2d(branch_3, depth(64), [1, 1],
                                 scope='Conv2d_0b_1x1')
        net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
      end_points[end_point] = net
      if end_point == final_endpoint: return net, end_points

      # mixed_2: 35 x 35 x 288.
      end_point = 'Mixed_5d'
      with tf.variable_scope(end_point):
        with tf.variable_scope('Branch_0'):
          branch_0 = slim.conv2d(net, depth(64), [1, 1], scope='Conv2d_0a_1x1')
        with tf.variable_scope('Branch_1'):
          branch_1 = slim.conv2d(net, depth(48), [1, 1], scope='Conv2d_0a_1x1')
          branch_1 = slim.conv2d(branch_1, depth(64), [5, 5],
                                 scope='Conv2d_0b_5x5')
        with tf.variable_scope('Branch_2'):
          branch_2 = slim.conv2d(net, depth(64), [1, 1], scope='Conv2d_0a_1x1')
          branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
                                 scope='Conv2d_0b_3x3')
          branch_2 = slim.conv2d(branch_2, depth(96), [3, 3],
                                 scope='Conv2d_0c_3x3')
        with tf.variable_scope('Branch_3'):
          branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
          branch_3 = slim.conv2d(branch_3, depth(64), [1, 1],
                                 scope='Conv2d_0b_1x1')
        net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
      end_points[end_point] = net
      if end_point == final_endpoint: return net, end_points

      # mixed_3: 17 x 17 x 768.
      end_point = 'Mixed_6a'
      with tf.variable_scope(end_point):
        with tf.variable_scope('Branch_0'):
          branch_0 = slim.conv2d(net, depth(384), [3, 3], stride=2,
                                 padding='VALID', scope='Conv2d_1a_1x1')
        with tf.variable_scope('Branch_1'):
          branch_1 = slim.conv2d(net, depth(64), [1, 1], scope='Conv2d_0a_1x1')
          branch_1 = slim.conv2d(branch_1, depth(96), [3, 3],
                                 scope='Conv2d_0b_3x3')
          branch_1 = slim.conv2d(branch_1, depth(96), [3, 3], stride=2,
                                 padding='VALID', scope='Conv2d_1a_1x1')
        with tf.variable_scope('Branch_2'):
          branch_2 = slim.max_pool2d(net, [3, 3], stride=2, padding='VALID',
                                     scope='MaxPool_1a_3x3')
        net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2])
      end_points[end_point] = net
      if end_point == final_endpoint: return net, end_points

      # mixed4: 17 x 17 x 768.
      end_point = 'Mixed_6b'
      with tf.variable_scope(end_point):
        with tf.variable_scope('Branch_0'):
          branch_0 = slim.conv2d(net, depth(192), [1, 1], scope='Conv2d_0a_1x1')
        with tf.variable_scope('Branch_1'):
          branch_1 = slim.conv2d(net, depth(128), [1, 1], scope='Conv2d_0a_1x1')
          branch_1 = slim.conv2d(branch_1, depth(128), [1, 7],
                                 scope='Conv2d_0b_1x7')
          branch_1 = slim.conv2d(branch_1, depth(192), [7, 1],
                                 scope='Conv2d_0c_7x1')
        with tf.variable_scope('Branch_2'):
          branch_2 = slim.conv2d(net, depth(128), [1, 1], scope='Conv2d_0a_1x1')
          branch_2 = slim.conv2d(branch_2, depth(128), [7, 1],
                                 scope='Conv2d_0b_7x1')
          branch_2 = slim.conv2d(branch_2, depth(128), [1, 7],
                                 scope='Conv2d_0c_1x7')
          branch_2 = slim.conv2d(branch_2, depth(128), [7, 1],
                                 scope='Conv2d_0d_7x1')
          branch_2 = slim.conv2d(branch_2, depth(192), [1, 7],
                                 scope='Conv2d_0e_1x7')
        with tf.variable_scope('Branch_3'):
          branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
          branch_3 = slim.conv2d(branch_3, depth(192), [1, 1],
                                 scope='Conv2d_0b_1x1')
        net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
      end_points[end_point] = net
      if end_point == final_endpoint: return net, end_points

      # mixed_5: 17 x 17 x 768.
      end_point = 'Mixed_6c'
      with tf.variable_scope(end_point):
        with tf.variable_scope('Branch_0'):
          branch_0 = slim.conv2d(net, depth(192), [1, 1], scope='Conv2d_0a_1x1')
        with tf.variable_scope('Branch_1'):
          branch_1 = slim.conv2d(net, depth(160), [1, 1], scope='Conv2d_0a_1x1')
          branch_1 = slim.conv2d(branch_1, depth(160), [1, 7],
                                 scope='Conv2d_0b_1x7')
          branch_1 = slim.conv2d(branch_1, depth(192), [7, 1],
                                 scope='Conv2d_0c_7x1')
        with tf.variable_scope('Branch_2'):
          branch_2 = slim.conv2d(net, depth(160), [1, 1], scope='Conv2d_0a_1x1')
          branch_2 = slim.conv2d(branch_2, depth(160), [7, 1],
                                 scope='Conv2d_0b_7x1')
          branch_2 = slim.conv2d(branch_2, depth(160), [1, 7],
                                 scope='Conv2d_0c_1x7')
          branch_2 = slim.conv2d(branch_2, depth(160), [7, 1],
                                 scope='Conv2d_0d_7x1')
          branch_2 = slim.conv2d(branch_2, depth(192), [1, 7],
                                 scope='Conv2d_0e_1x7')
        with tf.variable_scope('Branch_3'):
          branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
          branch_3 = slim.conv2d(branch_3, depth(192), [1, 1],
                                 scope='Conv2d_0b_1x1')
        net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
      end_points[end_point] = net
      if end_point == final_endpoint: return net, end_points
      # mixed_6: 17 x 17 x 768.
      end_point = 'Mixed_6d'
      with tf.variable_scope(end_point):
        with tf.variable_scope('Branch_0'):
          branch_0 = slim.conv2d(net, depth(192), [1, 1], scope='Conv2d_0a_1x1')
        with tf.variable_scope('Branch_1'):
          branch_1 = slim.conv2d(net, depth(160), [1, 1], scope='Conv2d_0a_1x1')
          branch_1 = slim.conv2d(branch_1, depth(160), [1, 7],
                                 scope='Conv2d_0b_1x7')
          branch_1 = slim.conv2d(branch_1, depth(192), [7, 1],
                                 scope='Conv2d_0c_7x1')
        with tf.variable_scope('Branch_2'):
          branch_2 = slim.conv2d(net, depth(160), [1, 1], scope='Conv2d_0a_1x1')
          branch_2 = slim.conv2d(branch_2, depth(160), [7, 1],
                                 scope='Conv2d_0b_7x1')
          branch_2 = slim.conv2d(branch_2, depth(160), [1, 7],
                                 scope='Conv2d_0c_1x7')
          branch_2 = slim.conv2d(branch_2, depth(160), [7, 1],
                                 scope='Conv2d_0d_7x1')
          branch_2 = slim.conv2d(branch_2, depth(192), [1, 7],
                                 scope='Conv2d_0e_1x7')
        with tf.variable_scope('Branch_3'):
          branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
          branch_3 = slim.conv2d(branch_3, depth(192), [1, 1],
                                 scope='Conv2d_0b_1x1')
        net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
      end_points[end_point] = net
      if end_point == final_endpoint: return net, end_points

      # mixed_7: 17 x 17 x 768.
      end_point = 'Mixed_6e'
      with tf.variable_scope(end_point):
        with tf.variable_scope('Branch_0'):
          branch_0 = slim.conv2d(net, depth(192), [1, 1], scope='Conv2d_0a_1x1')
        with tf.variable_scope('Branch_1'):
          branch_1 = slim.conv2d(net, depth(192), [1, 1], scope='Conv2d_0a_1x1')
          branch_1 = slim.conv2d(branch_1, depth(192), [1, 7],
                                 scope='Conv2d_0b_1x7')
          branch_1 = slim.conv2d(branch_1, depth(192), [7, 1],
                                 scope='Conv2d_0c_7x1')
        with tf.variable_scope('Branch_2'):
          branch_2 = slim.conv2d(net, depth(192), [1, 1], scope='Conv2d_0a_1x1')
          branch_2 = slim.conv2d(branch_2, depth(192), [7, 1],
                                 scope='Conv2d_0b_7x1')
          branch_2 = slim.conv2d(branch_2, depth(192), [1, 7],
                                 scope='Conv2d_0c_1x7')
          branch_2 = slim.conv2d(branch_2, depth(192), [7, 1],
                                 scope='Conv2d_0d_7x1')
          branch_2 = slim.conv2d(branch_2, depth(192), [1, 7],
                                 scope='Conv2d_0e_1x7')
        with tf.variable_scope('Branch_3'):
          branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
          branch_3 = slim.conv2d(branch_3, depth(192), [1, 1],
                                 scope='Conv2d_0b_1x1')
        net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
      end_points[end_point] = net
      if end_point == final_endpoint: return net, end_points

      # mixed_8: 8 x 8 x 1280.
      end_point = 'Mixed_7a'
      with tf.variable_scope(end_point):
        with tf.variable_scope('Branch_0'):
          branch_0 = slim.conv2d(net, depth(192), [1, 1], scope='Conv2d_0a_1x1')
          branch_0 = slim.conv2d(branch_0, depth(320), [3, 3], stride=2,
                                 padding='VALID', scope='Conv2d_1a_3x3')
        with tf.variable_scope('Branch_1'):
          branch_1 = slim.conv2d(net, depth(192), [1, 1], scope='Conv2d_0a_1x1')
          branch_1 = slim.conv2d(branch_1, depth(192), [1, 7],
                                 scope='Conv2d_0b_1x7')
          branch_1 = slim.conv2d(branch_1, depth(192), [7, 1],
                                 scope='Conv2d_0c_7x1')
          branch_1 = slim.conv2d(branch_1, depth(192), [3, 3], stride=2,
                                 padding='VALID', scope='Conv2d_1a_3x3')
        with tf.variable_scope('Branch_2'):
          branch_2 = slim.max_pool2d(net, [3, 3], stride=2, padding='VALID',
                                     scope='MaxPool_1a_3x3')
        net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2])
      end_points[end_point] = net
      if end_point == final_endpoint: return net, end_points
      # mixed_9: 8 x 8 x 2048.
      end_point = 'Mixed_7b'
      with tf.variable_scope(end_point):
        with tf.variable_scope('Branch_0'):
          branch_0 = slim.conv2d(net, depth(320), [1, 1], scope='Conv2d_0a_1x1')
        with tf.variable_scope('Branch_1'):
          branch_1 = slim.conv2d(net, depth(384), [1, 1], scope='Conv2d_0a_1x1')
          branch_1 = tf.concat(axis=3, values=[
              slim.conv2d(branch_1, depth(384), [1, 3], scope='Conv2d_0b_1x3'),
              slim.conv2d(branch_1, depth(384), [3, 1], scope='Conv2d_0b_3x1')])
        with tf.variable_scope('Branch_2'):
          branch_2 = slim.conv2d(net, depth(448), [1, 1], scope='Conv2d_0a_1x1')
          branch_2 = slim.conv2d(
              branch_2, depth(384), [3, 3], scope='Conv2d_0b_3x3')
          branch_2 = tf.concat(axis=3, values=[
              slim.conv2d(branch_2, depth(384), [1, 3], scope='Conv2d_0c_1x3'),
              slim.conv2d(branch_2, depth(384), [3, 1], scope='Conv2d_0d_3x1')])
        with tf.variable_scope('Branch_3'):
          branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
          branch_3 = slim.conv2d(
              branch_3, depth(192), [1, 1], scope='Conv2d_0b_1x1')
        net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
      end_points[end_point] = net
      if end_point == final_endpoint: return net, end_points

      # mixed_10: 8 x 8 x 2048.
      end_point = 'Mixed_7c'
      with tf.variable_scope(end_point):
        with tf.variable_scope('Branch_0'):
          branch_0 = slim.conv2d(net, depth(320), [1, 1], scope='Conv2d_0a_1x1')
        with tf.variable_scope('Branch_1'):
          branch_1 = slim.conv2d(net, depth(384), [1, 1], scope='Conv2d_0a_1x1')
          branch_1 = tf.concat(axis=3, values=[
              slim.conv2d(branch_1, depth(384), [1, 3], scope='Conv2d_0b_1x3'),
              slim.conv2d(branch_1, depth(384), [3, 1], scope='Conv2d_0c_3x1')])
        with tf.variable_scope('Branch_2'):
          branch_2 = slim.conv2d(net, depth(448), [1, 1], scope='Conv2d_0a_1x1')
          branch_2 = slim.conv2d(
              branch_2, depth(384), [3, 3], scope='Conv2d_0b_3x3')
          branch_2 = tf.concat(axis=3, values=[
              slim.conv2d(branch_2, depth(384), [1, 3], scope='Conv2d_0c_1x3'),
              slim.conv2d(branch_2, depth(384), [3, 1], scope='Conv2d_0d_3x1')])
        with tf.variable_scope('Branch_3'):
          branch_3 = slim.avg_pool2d(net, [3, 3], scope='AvgPool_0a_3x3')
          branch_3 = slim.conv2d(
              branch_3, depth(192), [1, 1], scope='Conv2d_0b_1x1')
        net = tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])
      end_points[end_point] = net
      if end_point == final_endpoint: return net, end_points
    raise ValueError('Unknown final endpoint %s' % final_endpoint)


def inception_v3(inputs,
                 num_classes=1000,
                 is_training=True,
                 dropout_keep_prob=0.8,
                 min_depth=16,
                 depth_multiplier=1.0,
                 prediction_fn=slim.softmax,
                 spatial_squeeze=True,
                 reuse=None,
                 scope='InceptionV3'):
  """Inception model from http://arxiv.org/abs/1512.00567.

  "Rethinking the Inception Architecture for Computer Vision"

  Christian Szegedy, Vincent Vanhoucke, Sergey Ioffe, Jonathon Shlens,
  Zbigniew Wojna.

  With the default arguments this method constructs the exact model defined in
  the paper. However, one can experiment with variations of the inception_v3
  network by changing arguments dropout_keep_prob, min_depth and
  depth_multiplier.

  The default image size used to train this network is 299x299.

  Args:
    inputs: a tensor of size [batch_size, height, width, channels].
    num_classes: number of predicted classes.
    is_training: whether is training or not.
    dropout_keep_prob: the percentage of activation values that are retained.
    min_depth: Minimum depth value (number of channels) for all convolution ops.
      Enforced when depth_multiplier < 1, and not an active constraint when
      depth_multiplier >= 1.
    depth_multiplier: Float multiplier for the depth (number of channels)
      for all convolution ops. The value must be greater than zero. Typical
      usage will be to set this value in (0, 1) to reduce the number of
      parameters or computation cost of the model.
    prediction_fn: a function to get predictions out of logits.
    spatial_squeeze: if True, logits is of shape is [B, C], if false logits is
        of shape [B, 1, 1, C], where B is batch_size and C is number of classes.
    reuse: whether or not the network and its variables should be reused. To be
      able to reuse 'scope' must be given.
    scope: Optional variable_scope.

  Returns:
    logits: the pre-softmax activations, a tensor of size
      [batch_size, num_classes]
    end_points: a dictionary from components of the network to the corresponding
      activation.

  Raises:
    ValueError: if 'depth_multiplier' is less than or equal to zero.
  """
  if depth_multiplier <= 0:
    raise ValueError('depth_multiplier is not greater than zero.')
  depth = lambda d: max(int(d * depth_multiplier), min_depth)

  with tf.variable_scope(scope, 'InceptionV3', [inputs, num_classes],
                         reuse=reuse) as scope:
    with slim.arg_scope([slim.batch_norm, slim.dropout],
                        is_training=is_training):
      net, end_points = inception_v3_base(
          inputs, scope=scope, min_depth=min_depth,
          depth_multiplier=depth_multiplier)

      # Auxiliary Head logits
      with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2d],
                          stride=1, padding='SAME'):
        aux_logits = end_points['Mixed_6e']
        with tf.variable_scope('AuxLogits'):
          # We want to pool the feature map to be 5x5xC
          # With padding = 0, and stride 3, this means our kernel is H - 12
          kernel_size = [aux_logits.get_shape().as_list()[1] - 12] * 2
          aux_logits = slim.avg_pool2d(
              aux_logits, kernel_size, stride=3, padding='VALID',
              scope='AvgPool_1a_5x5')
          aux_logits = slim.conv2d(aux_logits, depth(128), [1, 1],
                                   scope='Conv2d_1b_1x1')

          # Shape of feature map before the final layer.
          kernel_size = _reduced_kernel_size_for_small_input(aux_logits, [5, 5])
          aux_logits = slim.conv2d(
              aux_logits, depth(768), kernel_size,
              weights_initializer=trunc_normal(0.01),
              padding='VALID', scope='Conv2d_2a_{}x{}'.format(*kernel_size))
          aux_logits = slim.conv2d(
              aux_logits, num_classes, [1, 1], activation_fn=None,
              normalizer_fn=None, weights_initializer=trunc_normal(0.001),
              scope='Conv2d_2b_1x1')
          if spatial_squeeze:
            aux_logits = tf.squeeze(aux_logits, [1, 2], name='SpatialSqueeze')
          end_points['AuxLogits'] = aux_logits

      # Final pooling and prediction
      with tf.variable_scope('Logits'):
        #kernel_size = _reduced_kernel_size_for_small_input(net, [8, 8])
        kernel_size = _kernel_to_1x1_for_specific_input(net)
        net = slim.avg_pool2d(net, kernel_size, padding='VALID',
                              scope='AvgPool_1a_{}x{}'.format(*kernel_size))
        # 1 x 1 x 2048
        net = slim.dropout(net, keep_prob=dropout_keep_prob, scope='Dropout_1b')
        end_points['PreLogits'] = net
        # 2048
        logits = slim.conv2d(net, num_classes, [1, 1], activation_fn=None,
                             normalizer_fn=None, scope='Conv2d_1c_1x1')
        if spatial_squeeze:
          logits = tf.squeeze(logits, [1, 2], name='SpatialSqueeze')
        # 1000
      end_points['Logits'] = logits
      end_points['Predictions'] = prediction_fn(logits, scope='Predictions')
  return logits, end_points
inception_v3.default_image_size = 299


def _reduced_kernel_size_for_small_input(input_tensor, kernel_size):
  """Define kernel size which is automatically reduced for small input.

  If the shape of the input images is unknown at graph construction time this
  function assumes that the input images are is large enough.

  Args:
    input_tensor: input tensor of size [batch_size, height, width, channels].
    kernel_size: desired kernel size of length 2: [kernel_height, kernel_width]

  Returns:
    a tensor with the kernel size.

  TODO(jrru): Make this function work with unknown shapes. Theoretically, this
  can be done with the code below. Problems are two-fold: (1) If the shape was
  known, it will be lost. (2) inception.slim.ops._two_element_tuple cannot
  handle tensors that define the kernel size.
      shape = tf.shape(input_tensor)
      return = tf.pack([tf.minimum(shape[1], kernel_size[0]),
                        tf.minimum(shape[2], kernel_size[1])])

  """
  shape = input_tensor.get_shape().as_list()
  if shape[1] is None or shape[2] is None:
    kernel_size_out = kernel_size
  else:
    kernel_size_out = [min(shape[1], kernel_size[0]),
                       min(shape[2], kernel_size[1])]
  return kernel_size_out

def _kernel_to_1x1_for_specific_input(input_tensor):
  """Return a kernel that will transform the input_tensor into a vector.

  We want any input tensor of shape [B, H, W, C] to be transormed into [B, 1, 1, C].
  We assume a known input shape.
  """
  shape = input_tensor.get_shape().as_list()
  return [shape[1], shape[2]]


inception_v3_arg_scope = inception_utils.inception_arg_scope


================================================
FILE: nets/inception_v3_test.py
================================================
# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
"""Tests for nets.inception_v1."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import numpy as np
import tensorflow as tf

from nets import inception

slim = tf.contrib.slim


class InceptionV3Test(tf.test.TestCase):

  def testBuildClassificationNetwork(self):
    batch_size = 5
    height, width = 299, 299
    num_classes = 1000

    inputs = tf.random_uniform((batch_size, height, width, 3))
    logits, end_points = inception.inception_v3(inputs, num_classes)
    self.assertTrue(logits.op.name.startswith('InceptionV3/Logits'))
    self.assertListEqual(logits.get_shape().as_list(),
                         [batch_size, num_classes])
    self.assertTrue('Predictions' in end_points)
    self.assertListEqual(end_points['Predictions'].get_shape().as_list(),
                         [batch_size, num_classes])

  def testBuildBaseNetwork(self):
    batch_size = 5
    height, width = 299, 299

    inputs = tf.random_uniform((batch_size, height, width, 3))
    final_endpoint, end_points = inception.inception_v3_base(inputs)
    self.assertTrue(final_endpoint.op.name.startswith(
        'InceptionV3/Mixed_7c'))
    self.assertListEqual(final_endpoint.get_shape().as_list(),
                         [batch_size, 8, 8, 2048])
    expected_endpoints = ['Conv2d_1a_3x3', 'Conv2d_2a_3x3', 'Conv2d_2b_3x3',
                          'MaxPool_3a_3x3', 'Conv2d_3b_1x1', 'Conv2d_4a_3x3',
                          'MaxPool_5a_3x3', 'Mixed_5b', 'Mixed_5c', 'Mixed_5d',
                          'Mixed_6a', 'Mixed_6b', 'Mixed_6c', 'Mixed_6d',
                          'Mixed_6e', 'Mixed_7a', 'Mixed_7b', 'Mixed_7c']
    self.assertItemsEqual(end_points.keys(), expected_endpoints)

  def testBuildOnlyUptoFinalEndpoint(self):
    batch_size = 5
    height, width = 299, 299
    endpoints = ['Conv2d_1a_3x3', 'Conv2d_2a_3x3', 'Conv2d_2b_3x3',
                 'MaxPool_3a_3x3', 'Conv2d_3b_1x1', 'Conv2d_4a_3x3',
                 'MaxPool_5a_3x3', 'Mixed_5b', 'Mixed_5c', 'Mixed_5d',
                 'Mixed_6a', 'Mixed_6b', 'Mixed_6c', 'Mixed_6d',
                 'Mixed_6e', 'Mixed_7a', 'Mixed_7b', 'Mixed_7c']

    for index, endpoint in enumerate(endpoints):
      with tf.Graph().as_default():
        inputs = tf.random_uniform((batch_size, height, width, 3))
        out_tensor, end_points = inception.inception_v3_base(
            inputs, final_endpoint=endpoint)
        self.assertTrue(out_tensor.op.name.startswith(
            'InceptionV3/' + endpoint))
        self.assertItemsEqual(endpoints[:index+1], end_points)

  def testBuildAndCheckAllEndPointsUptoMixed7c(self):
    batch_size = 5
    height, width = 299, 299

    inputs = tf.random_uniform((batch_size, height, width, 3))
    _, end_points = inception.inception_v3_base(
        inputs, final_endpoint='Mixed_7c')
    endpoints_shapes = {'Conv2d_1a_3x3': [batch_size, 149, 149, 32],
                        'Conv2d_2a_3x3': [batch_size, 147, 147, 32],
                        'Conv2d_2b_3x3': [batch_size, 147, 147, 64],
                        'MaxPool_3a_3x3': [batch_size, 73, 73, 64],
                        'Conv2d_3b_1x1': [batch_size, 73, 73, 80],
                        'Conv2d_4a_3x3': [batch_size, 71, 71, 192],
                        'MaxPool_5a_3x3': [batch_size, 35, 35, 192],
                        'Mixed_5b': [batch_size, 35, 35, 256],
                        'Mixed_5c': [batch_size, 35, 35, 288],
                        'Mixed_5d': [batch_size, 35, 35, 288],
                        'Mixed_6a': [batch_size, 17, 17, 768],
                        'Mixed_6b': [batch_size, 17, 17, 768],
                        'Mixed_6c': [batch_size, 17, 17, 768],
                        'Mixed_6d': [batch_size, 17, 17, 768],
                        'Mixed_6e': [batch_size, 17, 17, 768],
                        'Mixed_7a': [batch_size, 8, 8, 1280],
                        'Mixed_7b': [batch_size, 8, 8, 2048],
                        'Mixed_7c': [batch_size, 8, 8, 2048]}
    self.assertItemsEqual(endpoints_shapes.keys(), end_points.keys())
    for endpoint_name in endpoints_shapes:
      expected_shape = endpoints_shapes[endpoint_name]
      self.assertTrue(endpoint_name in end_points)
      self.assertListEqual(end_points[endpoint_name].get_shape().as_list(),
                           expected_shape)

  def testModelHasExpectedNumberOfParameters(self):
    batch_size = 5
    height, width = 299, 299
    inputs = tf.random_uniform((batch_size, height, width, 3))
    with slim.arg_scope(inception.inception_v3_arg_scope()):
      inception.inception_v3_base(inputs)
    total_params, _ = slim.model_analyzer.analyze_vars(
        slim.get_model_variables())
    self.assertAlmostEqual(21802784, total_params)

  def testBuildEndPoints(self):
    batch_size = 5
    height, width = 299, 299
    num_classes = 1000

    inputs = tf.random_uniform((batch_size, height, width, 3))
    _, end_points = inception.inception_v3(inputs, num_classes)
    self.assertTrue('Logits' in end_points)
    logits = end_points['Logits']
    self.assertListEqual(logits.get_shape().as_list(),
                         [batch_size, num_classes])
    self.assertTrue('AuxLogits' in end_points)
    aux_logits = end_points['AuxLogits']
    self.assertListEqual(aux_logits.get_shape().as_list(),
                         [batch_size, num_classes])
    self.assertTrue('Mixed_7c' in end_points)
    pre_pool = end_points['Mixed_7c']
    self.assertListEqual(pre_pool.get_shape().as_list(),
                         [batch_size, 8, 8, 2048])
    self.assertTrue('PreLogits' in end_points)
    pre_logits = end_points['PreLogits']
    self.assertListEqual(pre_logits.get_sha
Download .txt
gitextract_pxfoh05k/

├── .gitignore
├── LICENSE
├── README.md
├── classify.py
├── config/
│   ├── README.md
│   ├── __init__.py
│   ├── config_classify.yaml
│   ├── config_export.yaml
│   ├── config_test.yaml
│   ├── config_train.yaml
│   └── parse_config.py
├── export.py
├── extract.py
├── nets/
│   ├── README.md
│   ├── __init__.py
│   ├── inception.py
│   ├── inception_resnet_v2.py
│   ├── inception_resnet_v2_test.py
│   ├── inception_utils.py
│   ├── inception_v1.py
│   ├── inception_v1_test.py
│   ├── inception_v2.py
│   ├── inception_v2_test.py
│   ├── inception_v3.py
│   ├── inception_v3_test.py
│   ├── inception_v4.py
│   ├── inception_v4_test.py
│   ├── mobilenet_v1.py
│   ├── mobilenet_v1_test.py
│   ├── net_profile.py
│   ├── nets_factory.py
│   ├── nets_factory_test.py
│   ├── resnet_utils.py
│   ├── resnet_v2.py
│   └── resnet_v2_test.py
├── preprocessing/
│   ├── __init__.py
│   ├── decode_example.py
│   └── inputs.py
├── requirements.txt
├── test.py
├── tfserving/
│   ├── README.md
│   ├── __init__.py
│   ├── client.py
│   ├── inputs.py
│   └── tfserver.py
├── train.py
└── visualize_train_inputs.py
Download .txt
SYMBOL INDEX (192 symbols across 31 files)

FILE: classify.py
  function classify (line 17) | def classify(tfrecords, checkpoint_path, save_path, max_iterations, save...
  function parse_args (line 155) | def parse_args():
  function main (line 199) | def main():

FILE: config/parse_config.py
  function parse_config_file (line 8) | def parse_config_file(path_to_config):

FILE: export.py
  function export (line 47) | def export(checkpoint_path,
  function parse_args (line 372) | def parse_args():

FILE: extract.py
  function extract_features (line 21) | def extract_features(tfrecords, checkpoint_path, num_iterations, feature...
  function extract_and_save (line 155) | def extract_and_save(tfrecords, checkpoint_path, save_path, num_iteratio...
  function parse_args (line 172) | def parse_args():
  function main (line 217) | def main():

FILE: nets/inception_resnet_v2.py
  function block35 (line 33) | def block35(net, scale=1.0, activation_fn=tf.nn.relu, scope=None, reuse=...
  function block17 (line 54) | def block17(net, scale=1.0, activation_fn=tf.nn.relu, scope=None, reuse=...
  function block8 (line 74) | def block8(net, scale=1.0, activation_fn=tf.nn.relu, scope=None, reuse=N...
  function inception_resnet_v2 (line 94) | def inception_resnet_v2(inputs, num_classes=1001, is_training=True,
  function inception_resnet_v2_arg_scope (line 259) | def inception_resnet_v2_arg_scope(weight_decay=0.00004,

FILE: nets/inception_resnet_v2_test.py
  class InceptionTest (line 25) | class InceptionTest(tf.test.TestCase):
    method testBuildLogits (line 27) | def testBuildLogits(self):
    method testBuildEndPoints (line 38) | def testBuildEndPoints(self):
    method testVariablesSetDevice (line 57) | def testVariablesSetDevice(self):
    method testHalfSizeImages (line 73) | def testHalfSizeImages(self):
    method testUnknownBatchSize (line 87) | def testUnknownBatchSize(self):
    method testEvaluation (line 102) | def testEvaluation(self):
    method testTrainEvalWithReuse (line 116) | def testTrainEvalWithReuse(self):

FILE: nets/inception_utils.py
  function inception_arg_scope (line 32) | def inception_arg_scope(weight_decay=0.00004,

FILE: nets/inception_v1.py
  function inception_v1_base (line 29) | def inception_v1_base(inputs,
  function inception_v1 (line 248) | def inception_v1(inputs,

FILE: nets/inception_v1_test.py
  class InceptionV1Test (line 29) | class InceptionV1Test(tf.test.TestCase):
    method testBuildClassificationNetwork (line 31) | def testBuildClassificationNetwork(self):
    method testBuildBaseNetwork (line 45) | def testBuildBaseNetwork(self):
    method testBuildOnlyUptoFinalEndpoint (line 61) | def testBuildOnlyUptoFinalEndpoint(self):
    method testBuildAndCheckAllEndPointsUptoMixed5c (line 78) | def testBuildAndCheckAllEndPointsUptoMixed5c(self):
    method testModelHasExpectedNumberOfParameters (line 109) | def testModelHasExpectedNumberOfParameters(self):
    method testHalfSizeImages (line 119) | def testHalfSizeImages(self):
    method testUnknownImageShape (line 129) | def testUnknownImageShape(self):
    method testUnknowBatchSize (line 147) | def testUnknowBatchSize(self):
    method testEvaluation (line 164) | def testEvaluation(self):
    method testTrainEvalWithReuse (line 179) | def testTrainEvalWithReuse(self):
    method testLogitsNotSqueezed (line 196) | def testLogitsNotSqueezed(self):

FILE: nets/inception_v2.py
  function inception_v2_base (line 29) | def inception_v2_base(inputs,
  function inception_v2 (line 416) | def inception_v2(inputs,
  function _reduced_kernel_size_for_small_input (line 489) | def _reduced_kernel_size_for_small_input(input_tensor, kernel_size):

FILE: nets/inception_v2_test.py
  class InceptionV2Test (line 29) | class InceptionV2Test(tf.test.TestCase):
    method testBuildClassificationNetwork (line 31) | def testBuildClassificationNetwork(self):
    method testBuildBaseNetwork (line 45) | def testBuildBaseNetwork(self):
    method testBuildOnlyUptoFinalEndpoint (line 61) | def testBuildOnlyUptoFinalEndpoint(self):
    method testBuildAndCheckAllEndPointsUptoMixed5c (line 77) | def testBuildAndCheckAllEndPointsUptoMixed5c(self):
    method testModelHasExpectedNumberOfParameters (line 106) | def testModelHasExpectedNumberOfParameters(self):
    method testBuildEndPointsWithDepthMultiplierLessThanOne (line 116) | def testBuildEndPointsWithDepthMultiplierLessThanOne(self):
    method testBuildEndPointsWithDepthMultiplierGreaterThanOne (line 136) | def testBuildEndPointsWithDepthMultiplierGreaterThanOne(self):
    method testRaiseValueErrorWithInvalidDepthMultiplier (line 156) | def testRaiseValueErrorWithInvalidDepthMultiplier(self):
    method testHalfSizeImages (line 167) | def testHalfSizeImages(self):
    method testUnknownImageShape (line 181) | def testUnknownImageShape(self):
    method testUnknowBatchSize (line 199) | def testUnknowBatchSize(self):
    method testEvaluation (line 216) | def testEvaluation(self):
    method testTrainEvalWithReuse (line 231) | def testTrainEvalWithReuse(self):
    method testLogitsNotSqueezed (line 248) | def testLogitsNotSqueezed(self):

FILE: nets/inception_v3.py
  function inception_v3_base (line 29) | def inception_v3_base(inputs,
  function inception_v3 (line 419) | def inception_v3(inputs,
  function _reduced_kernel_size_for_small_input (line 532) | def _reduced_kernel_size_for_small_input(input_tensor, kernel_size):
  function _kernel_to_1x1_for_specific_input (line 562) | def _kernel_to_1x1_for_specific_input(input_tensor):

FILE: nets/inception_v3_test.py
  class InceptionV3Test (line 29) | class InceptionV3Test(tf.test.TestCase):
    method testBuildClassificationNetwork (line 31) | def testBuildClassificationNetwork(self):
    method testBuildBaseNetwork (line 45) | def testBuildBaseNetwork(self):
    method testBuildOnlyUptoFinalEndpoint (line 62) | def testBuildOnlyUptoFinalEndpoint(self):
    method testBuildAndCheckAllEndPointsUptoMixed7c (line 80) | def testBuildAndCheckAllEndPointsUptoMixed7c(self):
    method testModelHasExpectedNumberOfParameters (line 112) | def testModelHasExpectedNumberOfParameters(self):
    method testBuildEndPoints (line 122) | def testBuildEndPoints(self):
    method testBuildEndPointsWithDepthMultiplierLessThanOne (line 146) | def testBuildEndPointsWithDepthMultiplierLessThanOne(self):
    method testBuildEndPointsWithDepthMultiplierGreaterThanOne (line 166) | def testBuildEndPointsWithDepthMultiplierGreaterThanOne(self):
    method testRaiseValueErrorWithInvalidDepthMultiplier (line 186) | def testRaiseValueErrorWithInvalidDepthMultiplier(self):
    method testHalfSizeImages (line 197) | def testHalfSizeImages(self):
    method testUnknownImageShape (line 211) | def testUnknownImageShape(self):
    method testUnknowBatchSize (line 228) | def testUnknowBatchSize(self):
    method testEvaluation (line 245) | def testEvaluation(self):
    method testTrainEvalWithReuse (line 260) | def testTrainEvalWithReuse(self):
    method testLogitsNotSqueezed (line 278) | def testLogitsNotSqueezed(self):

FILE: nets/inception_v4.py
  function block_inception_a (line 34) | def block_inception_a(inputs, scope=None, reuse=None):
  function block_reduction_a (line 55) | def block_reduction_a(inputs, scope=None, reuse=None):
  function block_inception_b (line 75) | def block_inception_b(inputs, scope=None, reuse=None):
  function block_reduction_b (line 99) | def block_reduction_b(inputs, scope=None, reuse=None):
  function block_inception_c (line 121) | def block_inception_c(inputs, scope=None, reuse=None):
  function inception_v4_base (line 147) | def inception_v4_base(inputs, final_endpoint='Mixed_7d', scope=None):
  function inception_v4 (line 257) | def inception_v4(inputs, num_classes=1001, is_training=True,

FILE: nets/inception_v4_test.py
  class InceptionTest (line 25) | class InceptionTest(tf.test.TestCase):
    method testBuildLogits (line 27) | def testBuildLogits(self):
    method testBuildWithoutAuxLogits (line 46) | def testBuildWithoutAuxLogits(self):
    method testAllEndPointsShapes (line 58) | def testAllEndPointsShapes(self):
    method testBuildBaseNetwork (line 103) | def testBuildBaseNetwork(self):
    method testBuildOnlyUpToFinalEndpoint (line 121) | def testBuildOnlyUpToFinalEndpoint(self):
    method testVariablesSetDevice (line 139) | def testVariablesSetDevice(self):
    method testHalfSizeImages (line 154) | def testHalfSizeImages(self):
    method testUnknownBatchSize (line 167) | def testUnknownBatchSize(self):
    method testEvaluation (line 182) | def testEvaluation(self):
    method testTrainEvalWithReuse (line 196) | def testTrainEvalWithReuse(self):

FILE: nets/mobilenet_v1.py
  function mobilenet_v1_base (line 142) | def mobilenet_v1_base(inputs,
  function mobilenet_v1 (line 269) | def mobilenet_v1(inputs,
  function wrapped_partial (line 344) | def wrapped_partial(func, *args, **kwargs):
  function _reduced_kernel_size_for_small_input (line 355) | def _reduced_kernel_size_for_small_input(input_tensor, kernel_size):
  function mobilenet_v1_arg_scope (line 377) | def mobilenet_v1_arg_scope(is_training=True,

FILE: nets/mobilenet_v1_test.py
  class MobilenetV1Test (line 29) | class MobilenetV1Test(tf.test.TestCase):
    method testBuildClassificationNetwork (line 31) | def testBuildClassificationNetwork(self):
    method testBuildBaseNetwork (line 45) | def testBuildBaseNetwork(self):
    method testBuildOnlyUptoFinalEndpoint (line 70) | def testBuildOnlyUptoFinalEndpoint(self):
    method testBuildCustomNetworkUsingConvDefs (line 96) | def testBuildCustomNetworkUsingConvDefs(self):
    method testBuildAndCheckAllEndPointsUptoConv2d_13 (line 118) | def testBuildAndCheckAllEndPointsUptoConv2d_13(self):
    method testOutputStride16BuildAndCheckAllEndPointsUptoConv2d_13 (line 160) | def testOutputStride16BuildAndCheckAllEndPointsUptoConv2d_13(self):
    method testOutputStride8BuildAndCheckAllEndPointsUptoConv2d_13 (line 204) | def testOutputStride8BuildAndCheckAllEndPointsUptoConv2d_13(self):
    method testBuildAndCheckAllEndPointsApproximateFaceNet (line 248) | def testBuildAndCheckAllEndPointsApproximateFaceNet(self):
    method testModelHasExpectedNumberOfParameters (line 291) | def testModelHasExpectedNumberOfParameters(self):
    method testBuildEndPointsWithDepthMultiplierLessThanOne (line 302) | def testBuildEndPointsWithDepthMultiplierLessThanOne(self):
    method testBuildEndPointsWithDepthMultiplierGreaterThanOne (line 321) | def testBuildEndPointsWithDepthMultiplierGreaterThanOne(self):
    method testRaiseValueErrorWithInvalidDepthMultiplier (line 341) | def testRaiseValueErrorWithInvalidDepthMultiplier(self):
    method testHalfSizeImages (line 354) | def testHalfSizeImages(self):
    method testUnknownImageShape (line 368) | def testUnknownImageShape(self):
    method testUnknowBatchSize (line 386) | def testUnknowBatchSize(self):
    method testEvaluation (line 403) | def testEvaluation(self):
    method testTrainEvalWithReuse (line 418) | def testTrainEvalWithReuse(self):
    method testLogitsNotSqueezed (line 436) | def testLogitsNotSqueezed(self):

FILE: nets/net_profile.py
  function profile (line 11) | def profile(model_name, num_classes, image_size, batch_size):
  function parse_args (line 43) | def parse_args():
  function main (line 66) | def main():

FILE: nets/nets_factory.py
  function get_network_fn (line 62) | def get_network_fn(name, num_classes, weight_decay=0.0, is_training=False):

FILE: nets/nets_factory_test.py
  class NetworksTest (line 28) | class NetworksTest(tf.test.TestCase):
    method testGetNetworkFn (line 30) | def testGetNetworkFn(self):

FILE: nets/resnet_utils.py
  class Block (line 46) | class Block(collections.namedtuple('Block', ['scope', 'unit_fn', 'args'])):
  function subsample (line 59) | def subsample(inputs, factor, scope=None):
  function conv2d_same (line 77) | def conv2d_same(inputs, num_outputs, kernel_size, stride, rate=1, scope=...
  function stack_blocks_dense (line 126) | def stack_blocks_dense(net, blocks, output_stride=None,
  function resnet_arg_scope (line 199) | def resnet_arg_scope(weight_decay=0.0001,

FILE: nets/resnet_v2.py
  function bottleneck (line 62) | def bottleneck(inputs, depth, depth_bottleneck, stride, rate=1,
  function resnet_v2 (line 111) | def resnet_v2(inputs,
  function resnet_v2_block (line 226) | def resnet_v2_block(scope, base_depth, num_units, stride):
  function resnet_v2_50 (line 251) | def resnet_v2_50(inputs,
  function resnet_v2_101 (line 274) | def resnet_v2_101(inputs,
  function resnet_v2_152 (line 296) | def resnet_v2_152(inputs,
  function resnet_v2_200 (line 319) | def resnet_v2_200(inputs,

FILE: nets/resnet_v2_test.py
  function create_test_input (line 30) | def create_test_input(batch_size, height, width, channels):
  class ResnetUtilsTest (line 56) | class ResnetUtilsTest(tf.test.TestCase):
    method testSubsampleThreeByThree (line 58) | def testSubsampleThreeByThree(self):
    method testSubsampleFourByFour (line 65) | def testSubsampleFourByFour(self):
    method testConv2DSameEven (line 72) | def testConv2DSameEven(self):
    method testConv2DSameOdd (line 113) | def testConv2DSameOdd(self):
    method _resnet_plain (line 154) | def _resnet_plain(self, inputs, blocks, output_stride=None, scope=None):
    method testEndPointsV2 (line 162) | def testEndPointsV2(self):
    method _stack_blocks_nondense (line 190) | def _stack_blocks_nondense(self, net, blocks):
    method testAtrousValuesBottleneck (line 199) | def testAtrousValuesBottleneck(self):
  class ResnetCompleteNetworkTest (line 244) | class ResnetCompleteNetworkTest(tf.test.TestCase):
    method _resnet_small (line 247) | def _resnet_small(self,
    method testClassificationEndPoints (line 274) | def testClassificationEndPoints(self):
    method testClassificationShapes (line 289) | def testClassificationShapes(self):
    method testFullyConvolutionalEndpointShapes (line 306) | def testFullyConvolutionalEndpointShapes(self):
    method testRootlessFullyConvolutionalEndpointShapes (line 324) | def testRootlessFullyConvolutionalEndpointShapes(self):
    method testAtrousFullyConvolutionalEndpointShapes (line 343) | def testAtrousFullyConvolutionalEndpointShapes(self):
    method testAtrousFullyConvolutionalValues (line 364) | def testAtrousFullyConvolutionalValues(self):
    method testUnknownBatchSize (line 393) | def testUnknownBatchSize(self):
    method testFullyConvolutionalUnknownHeightWidth (line 413) | def testFullyConvolutionalUnknownHeightWidth(self):
    method testAtrousFullyConvolutionalUnknownHeightWidth (line 429) | def testAtrousFullyConvolutionalUnknownHeightWidth(self):

FILE: preprocessing/decode_example.py
  function decode_serialized_example (line 7) | def decode_serialized_example(serialized_example, features_to_fetch, dec...

FILE: preprocessing/inputs.py
  function apply_with_random_selector (line 33) | def apply_with_random_selector(x, func, num_cases):
  function distort_color (line 50) | def distort_color(image, color_ordering=0, fast_mode=True, scope=None):
  function distorted_bounding_box_crop (line 101) | def distorted_bounding_box_crop(image,
  function _largest_size_at_most (line 155) | def _largest_size_at_most(height, width, largest_side):
  class DistortedInputs (line 181) | class DistortedInputs():
    method __init__ (line 183) | def __init__(self, cfg, add_summaries):
    method apply (line 187) | def apply(self, original_image, bboxes, distorted_inputs, image_summar...
  function check_normalized_box_values (line 331) | def check_normalized_box_values(xmin, ymin, xmax, ymax, maximum_normaliz...
  function expand_bboxes (line 369) | def expand_bboxes(xmin, xmax, ymin, ymax, cfg):
  function get_region_data (line 390) | def get_region_data(serialized_example, cfg, fetch_ids=True, fetch_label...
  function bbox_crop_loop_cond (line 515) | def bbox_crop_loop_cond(original_image, bboxes, distorted_inputs, image_...
  function get_distorted_inputs (line 519) | def get_distorted_inputs(original_image, bboxes, cfg, add_summaries):
  function create_training_batch (line 559) | def create_training_batch(serialized_example, cfg, add_summaries, read_f...
  function create_visualization_batch (line 577) | def create_visualization_batch(serialized_example, cfg, add_summaries, f...
  function create_classification_batch (line 620) | def create_classification_batch(serialized_example, cfg, add_summaries, ...
  function input_nodes (line 638) | def input_nodes(tfrecords, cfg, num_epochs=None, batch_size=32, num_thre...

FILE: test.py
  function test (line 16) | def test(tfrecords, checkpoint_path, save_dir, max_iterations, eval_inte...
  function parse_args (line 171) | def parse_args():
  function main (line 214) | def main():

FILE: tfserving/client.py
  function parse_args (line 25) | def parse_args():
  function main (line 57) | def main():

FILE: tfserving/inputs.py
  function prepare_image (line 14) | def prepare_image(image, input_height=299, input_width=299):

FILE: tfserving/tfserver.py
  function predict (line 20) | def predict(image_data,
  function process_classification_prediction (line 59) | def process_classification_prediction(predictions, max_classes=10):

FILE: train.py
  function _configure_learning_rate (line 36) | def _configure_learning_rate(global_step, cfg):
  function _configure_optimizer (line 74) | def _configure_optimizer(learning_rate, cfg):
  function get_trainable_variables (line 122) | def get_trainable_variables(trainable_scopes):
  function get_init_function (line 140) | def get_init_function(logdir, pretrained_model_path, checkpoint_exclude_...
  function train (line 251) | def train(tfrecords, logdir, cfg, pretrained_model_path=None, trainable_...
  function parse_args (line 407) | def parse_args():
  function main (line 470) | def main():

FILE: visualize_train_inputs.py
  function visualize_train_inputs (line 14) | def visualize_train_inputs(tfrecords, cfg, show_text_labels=False, read_...
  function parse_args (line 112) | def parse_args():
  function main (line 135) | def main():
Condensed preview — 47 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (420K chars).
[
  {
    "path": ".gitignore",
    "chars": 1104,
    "preview": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packagi"
  },
  {
    "path": "LICENSE",
    "chars": 1066,
    "preview": "MIT License\n\nCopyright (c) 2017 Visipedia\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\n"
  },
  {
    "path": "README.md",
    "chars": 11361,
    "preview": "# TensorFlow Classification\nThis repo contains training, testing and classifcation code for image classification using ["
  },
  {
    "path": "classify.py",
    "chars": 8088,
    "preview": "from __future__ import absolute_import\nfrom __future__ import division\nfrom __future__ import print_function\n\nimport arg"
  },
  {
    "path": "config/README.md",
    "chars": 8865,
    "preview": "This directory contains example configuration scripts for training, testing, classifying and exporting models. I find it"
  },
  {
    "path": "config/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "config/config_classify.yaml",
    "chars": 4005,
    "preview": "# Classification specific configuration\n\nRANDOM_SEED : 1.0\n\nSESSION_CONFIG : {\n  # If true, then the device location of "
  },
  {
    "path": "config/config_export.yaml",
    "chars": 1340,
    "preview": "# Export specific configuration\n\nRANDOM_SEED : 1.0\n\nSESSION_CONFIG : {\n  # If true, then the device location of each var"
  },
  {
    "path": "config/config_test.yaml",
    "chars": 4413,
    "preview": "# Testing specific configuration\n\nRANDOM_SEED : 1.0\n\nSESSION_CONFIG : {\n  # If true, then the device location of each va"
  },
  {
    "path": "config/config_train.yaml",
    "chars": 6640,
    "preview": "# Training specific configuration\n\nRANDOM_SEED : 1.0\n\nSESSION_CONFIG : {\n  # If true, then the device location of each v"
  },
  {
    "path": "config/parse_config.py",
    "chars": 293,
    "preview": "from __future__ import absolute_import\nfrom __future__ import division\nfrom __future__ import print_function\n\nimport yam"
  },
  {
    "path": "export.py",
    "chars": 20240,
    "preview": "\"\"\"\nExport a trained model for application use.\n\nExample for use with TensorFlow Serving:\npython export.py \\\n--checkpoin"
  },
  {
    "path": "extract.py",
    "chars": 8242,
    "preview": "\"\"\"\nExtract features.\n\"\"\"\n\nfrom __future__ import absolute_import\nfrom __future__ import division\nfrom __future__ import"
  },
  {
    "path": "nets/README.md",
    "chars": 5219,
    "preview": "# Models\n\nThis directory contains the available classification models. All of these models were copied from the [TensorF"
  },
  {
    "path": "nets/__init__.py",
    "chars": 1,
    "preview": "\n"
  },
  {
    "path": "nets/inception.py",
    "chars": 1614,
    "preview": "# Copyright 2016 The TensorFlow Authors. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "nets/inception_resnet_v2.py",
    "chars": 13119,
    "preview": "# Copyright 2016 The TensorFlow Authors. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "nets/inception_resnet_v2_test.py",
    "chars": 5732,
    "preview": "# Copyright 2016 The TensorFlow Authors. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "nets/inception_utils.py",
    "chars": 2630,
    "preview": "# Copyright 2016 The TensorFlow Authors. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "nets/inception_v1.py",
    "chars": 15302,
    "preview": "# Copyright 2016 The TensorFlow Authors. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "nets/inception_v1_test.py",
    "chars": 8721,
    "preview": "# Copyright 2016 The TensorFlow Authors. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "nets/inception_v2.py",
    "chars": 23753,
    "preview": "# Copyright 2016 The TensorFlow Authors. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "nets/inception_v2_test.py",
    "chars": 10873,
    "preview": "# Copyright 2016 The TensorFlow Authors. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "nets/inception_v3.py",
    "chars": 27832,
    "preview": "# Copyright 2016 The TensorFlow Authors. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "nets/inception_v3_test.py",
    "chars": 12165,
    "preview": "# Copyright 2016 The TensorFlow Authors. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "nets/inception_v4.py",
    "chars": 15993,
    "preview": "# Copyright 2016 The TensorFlow Authors. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "nets/inception_v4_test.py",
    "chars": 9938,
    "preview": "# Copyright 2016 The TensorFlow Authors. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "nets/mobilenet_v1.py",
    "chars": 19638,
    "preview": "# Copyright 2017 The TensorFlow Authors. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "nets/mobilenet_v1_test.py",
    "chars": 22561,
    "preview": "# Copyright 2017 The TensorFlow Authors. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "nets/net_profile.py",
    "chars": 2510,
    "preview": "from __future__ import absolute_import\nfrom __future__ import division\nfrom __future__ import print_function\n\nimport arg"
  },
  {
    "path": "nets/nets_factory.py",
    "chars": 3850,
    "preview": "# Copyright 2016 The TensorFlow Authors. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "nets/nets_factory_test.py",
    "chars": 1663,
    "preview": "# Copyright 2016 Google Inc. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# "
  },
  {
    "path": "nets/resnet_utils.py",
    "chars": 10448,
    "preview": "# Copyright 2016 The TensorFlow Authors. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "nets/resnet_v2.py",
    "chars": 15682,
    "preview": "# Copyright 2016 The TensorFlow Authors. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "nets/resnet_v2_test.py",
    "chars": 19105,
    "preview": "# Copyright 2016 The TensorFlow Authors. All Rights Reserved.\n#\n# Licensed under the Apache License, Version 2.0 (the \"L"
  },
  {
    "path": "preprocessing/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "preprocessing/decode_example.py",
    "chars": 6067,
    "preview": "from __future__ import absolute_import\nfrom __future__ import division\nfrom __future__ import print_function\n\nimport ten"
  },
  {
    "path": "preprocessing/inputs.py",
    "chars": 29376,
    "preview": "# Some of this code came from the https://github.com/tensorflow/models/tree/master/slim\n# directory, so lets keep the Go"
  },
  {
    "path": "requirements.txt",
    "chars": 76,
    "preview": "easydict>=1.6\nmatplotlib>=2.0.0\nnumpy>=1.12.0\nPyYAML>=3.11\ntensorflow>=1.0.0"
  },
  {
    "path": "test.py",
    "chars": 9548,
    "preview": "from __future__ import absolute_import\nfrom __future__ import division\nfrom __future__ import print_function\n\nimport arg"
  },
  {
    "path": "tfserving/README.md",
    "chars": 5401,
    "preview": "# TensorFlow Serving Utilities\n\nThis directory contains utility code for interacting with a [TensorFlow Serving](https:/"
  },
  {
    "path": "tfserving/__init__.py",
    "chars": 0,
    "preview": ""
  },
  {
    "path": "tfserving/client.py",
    "chars": 2561,
    "preview": "\"\"\"\nA simple client to query a TensorFlow Serving instance.\n\nExample:\n$ python client.py \\\n--images IMG_0932_sm.jpg \\\n--"
  },
  {
    "path": "tfserving/inputs.py",
    "chars": 805,
    "preview": "\"\"\"\nNumpy and scipy image preparation.\n\nAuthor: Grant Van Horn\n\"\"\"\n\nfrom __future__ import absolute_import\nfrom __future"
  },
  {
    "path": "tfserving/tfserver.py",
    "chars": 3180,
    "preview": "\"\"\"\nTensorFlow Serving caller code.\n\nRequirements:\npip install numpy tensorflow tensorflow-serving-api\n\nAuthor: Grant Va"
  },
  {
    "path": "train.py",
    "chars": 21207,
    "preview": "# Some of this code came from the https://github.com/tensorflow/models/tree/master/slim\n# directory, so lets keep the Go"
  },
  {
    "path": "visualize_train_inputs.py",
    "chars": 5168,
    "preview": "from __future__ import absolute_import\nfrom __future__ import division\nfrom __future__ import print_function\n\nimport arg"
  }
]

About this extraction

This page contains the full source code of the visipedia/tf_classification GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 47 files (397.8 KB), approximately 103.3k tokens, and a symbol index with 192 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!