Skip to content

Commit

Permalink
caffe-tensorflow supported
Browse files Browse the repository at this point in the history
  • Loading branch information
gauravgupta22 committed Aug 1, 2016
1 parent aeb83ac commit 94f069c
Show file tree
Hide file tree
Showing 60 changed files with 12,178 additions and 11,173 deletions.
1 change: 0 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ module.exports = {
"globals": {
"instance": true,
"addLayerEndpoints": true,
"prototxtId": true,
"jsPlumb": false,
"$": false
}
Expand Down
10 changes: 10 additions & 0 deletions cloudcvIde/caffe-tensorflow-master/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# OS X temporary metadata
._*
*.DS_Store

# Extracted parameters
*.params

# Python cache
*.pyc

30 changes: 30 additions & 0 deletions cloudcvIde/caffe-tensorflow-master/.pylintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[MASTER]
ignore=caffepb.py

[MESSAGES CONTROL]
disable=missing-docstring,invalid-name,wildcard-import,unused-wildcard-import,bad-builtin,no-self-use,locally-disabled

[MISCELLANEOUS]
# Exclude TODOs
notes=

[TYPECHECK]
ignored-classes=numpy,cv2,NodeKind,LayerType,NetParameter,NpzFile

[DESIGN]
# Maximum number of arguments for function / method
max-args=20
# Maximum number of locals for function / method body
max-locals=30
# Maximum number of return / yield for function / method body
max-returns=10
# Maximum number of branch for function / method body
max-branches=12
# Maximum number of statements in function / method body
max-statements=200
# Maximum number of attributes for a class (see R0902).
max-attributes=100
# Maximum number of public methods for a class (see R0904).
max-public-methods=200
# Maximum number of boolean expressions in a if statement
max-bool-expr=10
4 changes: 4 additions & 0 deletions cloudcvIde/caffe-tensorflow-master/.style.yapf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[style]
based_on_style = chromium
column_limit = 100
indent_width = 4
31 changes: 31 additions & 0 deletions cloudcvIde/caffe-tensorflow-master/LICENSE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# License

Each contributor holds copyright over their contributions to Caffe-Tensorflow. In particular:

- Any included network model is provided under its original license.

- Any portion derived from Caffe is provided under its original license.

- Caffe-tensorflow is provided under the MIT license, as specified below.

# The MIT License (MIT)

Copyright (c) 2016 Saumitro Dasgupta

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.
54 changes: 54 additions & 0 deletions cloudcvIde/caffe-tensorflow-master/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Caffe to TensorFlow

Convert [Caffe](https://github.com/BVLC/caffe/) models to [TensorFlow](https://github.com/tensorflow/tensorflow).

## Usage

Run `convert.py` to convert an existing Caffe model to TensorFlow.

Make sure you're using the latest Caffe format (see the notes section for more info).

The output consists of two files:

1. A data file (in NumPy's native format) containing the model's learned parameters.
2. A Python class that constructs the model's graph.

### Examples

See the [examples](examples/) folder for more details.

## Verification

The following converted models have been verified on the ILSVRC2012 validation set using
[validate.py](examples/imagenet/validate.py).

| Model | Top 5 Accuracy |
|:------------------------------------------------------|---------------:|
| [ResNet 152](http://arxiv.org/abs/1512.03385) | 92.92% |
| [ResNet 101](http://arxiv.org/abs/1512.03385) | 92.63% |
| [ResNet 50](http://arxiv.org/abs/1512.03385) | 92.02% |
| [VGG 16](http://arxiv.org/abs/1409.1556) | 89.88% |
| [GoogLeNet](http://arxiv.org/abs/1409.4842) | 89.06% |
| [Network in Network](http://arxiv.org/abs/1312.4400) | 81.21% |
| [CaffeNet](http://arxiv.org/abs/1408.5093) | 79.93% |
| [AlexNet](http://goo.gl/3BilWd) | 79.84% |

## Notes

- Only the new Caffe model format is supported. If you have an old model, use the `upgrade_net_proto_text` and `upgrade_net_proto_binary` tools that ship with Caffe to upgrade them first. Also make sure you're using a fairly recent version of Caffe.

- It appears that Caffe and TensorFlow cannot be concurrently invoked (CUDA conflicts - even with `set_mode_cpu`). This makes it a two-stage process: first extract the parameters with `convert.py`, then import it into TensorFlow.

- Caffe is not strictly required. If PyCaffe is found in your `PYTHONPATH`, and the `USE_PYCAFFE` environment variable is set, it will be used. Otherwise, a fallback will be used. However, the fallback uses the pure Python-based implementation of protobuf, which is astoundingly slow (~1.5 minutes to parse the VGG16 parameters). The experimental CPP protobuf backend doesn't particularly help here, since it runs into the file size limit (Caffe gets around this by overriding this limit in C++). A cleaner solution here would be to implement the loader as a C++ module.

- Only a subset of Caffe layers and accompanying parameters are currently supported.

- Not all Caffe models can be converted to TensorFlow. For instance, Caffe supports arbitrary padding whereas TensorFlow's support is currently restricted to `SAME` and `VALID`.

- The border values are handled differently by Caffe and TensorFlow. However, these don't appear to affect things too much.

- Image rescaling can affect the ILSVRC2012 top 5 accuracy listed above slightly. VGG16 expects isotropic rescaling (anisotropic reduces accuracy to 88.45%) whereas BVLC's implementation of GoogLeNet expects anisotropic (isotropic reduces accuracy to 87.7%).

- The support class `kaffe.tensorflow.Network` has no internal dependencies. It can be safely extracted and deployed without the rest of this library.

- The ResNet model uses 1x1 convolutions with a stride of 2. This is currently only supported in the master branch of TensorFlow (the latest release at time of writing being v0.8.0, which does not support it).
60 changes: 60 additions & 0 deletions cloudcvIde/caffe-tensorflow-master/convert.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#!/usr/bin/env python

import os
import sys
import numpy as np
import argparse
from kaffe import KaffeError, print_stderr
from kaffe.tensorflow import TensorFlowTransformer


def fatal_error(msg):
print_stderr(msg)
exit(-1)


def validate_arguments(args):
if (args.data_output_path is not None) and (args.caffemodel is None):
fatal_error('No input data path provided.')
if (args.caffemodel is not None) and (args.data_output_path is None):
fatal_error('No output data path provided.')
if (args.code_output_path is None) and (args.data_output_path is None):
fatal_error('No output path specified.')


def convert(def_path, caffemodel_path, data_output_path, code_output_path, phase):
try:
transformer = TensorFlowTransformer(def_path, caffemodel_path, phase=phase)
print_stderr('Converting data...')
if caffemodel_path is not None:
data = transformer.transform_data()
print_stderr('Saving data...')
with open(data_output_path, 'wb') as data_out:
np.save(data_out, data)
if code_output_path:
print_stderr('Saving source...')
with open(code_output_path, 'wb') as src_out:
src_out.write(transformer.transform_source())
print_stderr('Done.')
except KaffeError as err:
fatal_error('Error encountered: {}'.format(err))


def main():
parser = argparse.ArgumentParser()
parser.add_argument('def_path', help='Model definition (.prototxt) path')
parser.add_argument('--caffemodel', help='Model data (.caffemodel) path')
parser.add_argument('--data-output-path', help='Converted data output path')
parser.add_argument('--code-output-path', help='Save generated source to this path')
parser.add_argument('-p',
'--phase',
default='test',
help='The phase to convert: test (default) or train')
args = parser.parse_args()
validate_arguments(args)
convert(args.def_path, args.caffemodel, args.data_output_path, args.code_output_path,
args.phase)


if __name__ == '__main__':
main()
41 changes: 41 additions & 0 deletions cloudcvIde/caffe-tensorflow-master/examples/imagenet/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# ImageNet Examples

This folder contains two examples that demonstrate how to use converted networks for
image classification. Also included are sample converted models and helper scripts.

## 1. Image Classification

`classify.py` uses a GoogleNet trained on ImageNet, converted to TensorFlow, for classifying images.

The architecture used is defined in `models/googlenet.py` (which was auto-generated). You will need
to download and convert the weights from Caffe to run the example. The download link for the
corresponding weights can be found in Caffe's `models/bvlc_googlenet/` folder.

You can run this example like so:

$ ./classify.py /path/to/googlenet.npy ~/pics/kitty.png ~/pics/woof.jpg

You should expect to see an output similar to this:

Image Classified As Confidence
----------------------------------------------------------------------
kitty.png Persian cat 99.75 %
woof.jpg Bernese mountain dog 82.02 %


## 2. ImageNet Validation

`validate.py` evaluates a converted model against the ImageNet (ILSVRC12) validation set. To run
this script, you will need a copy of the ImageNet validation set. You can run it as follows:

$ ./validate.py alexnet.npy val.txt imagenet-val/ --model AlexNet

The validation results specified in the main readme were generated using this script.

## Helper Scripts

In addition to the examples above, this folder includes a few additional files:

- `dataset.py` : helper script for loading, pre-processing, and iterating over images
- `models/` : contains converted models (auto-generated)
- `models/helper.py` : describes how the data should be preprocessed for each model
78 changes: 78 additions & 0 deletions cloudcvIde/caffe-tensorflow-master/examples/imagenet/classify.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#!/usr/bin/env python
import argparse
import numpy as np
import tensorflow as tf
import os.path as osp

import models
import dataset


def display_results(image_paths, probs):
'''Displays the classification results given the class probability for each image'''
# Get a list of ImageNet class labels
with open('imagenet-classes.txt', 'rb') as infile:
class_labels = map(str.strip, infile.readlines())
# Pick the class with the highest confidence for each image
class_indices = np.argmax(probs, axis=1)
# Display the results
print('\n{:20} {:30} {}'.format('Image', 'Classified As', 'Confidence'))
print('-' * 70)
for img_idx, image_path in enumerate(image_paths):
img_name = osp.basename(image_path)
class_name = class_labels[class_indices[img_idx]]
confidence = round(probs[img_idx, class_indices[img_idx]] * 100, 2)
print('{:20} {:30} {} %'.format(img_name, class_name, confidence))


def classify(model_data_path, image_paths):
'''Classify the given images using GoogleNet.'''

# Get the data specifications for the GoogleNet model
spec = models.get_data_spec(model_class=models.GoogleNet)

# Create a placeholder for the input image
input_node = tf.placeholder(tf.float32,
shape=(None, spec.crop_size, spec.crop_size, spec.channels))

# Construct the network
net = models.GoogleNet({'data': input_node})

# Create an image producer (loads and processes images in parallel)
image_producer = dataset.ImageProducer(image_paths=image_paths, data_spec=spec)

with tf.Session() as sesh:
# Start the image processing workers
coordinator = tf.train.Coordinator()
threads = image_producer.start(session=sesh, coordinator=coordinator)

# Load the converted parameters
print('Loading the model')
net.load(model_data_path, sesh)

# Load the input image
print('Loading the images')
indices, input_images = image_producer.get(sesh)

# Perform a forward pass through the network to get the class probabilities
print('Classifying')
probs = sesh.run(net.get_output(), feed_dict={input_node: input_images})
display_results([image_paths[i] for i in indices], probs)

# Stop the worker threads
coordinator.request_stop()
coordinator.join(threads, stop_grace_period_secs=2)

def main():
# Parse arguments
parser = argparse.ArgumentParser()
parser.add_argument('model_path', help='Converted parameters for the GoogleNet model')
parser.add_argument('image_paths', nargs='+', help='One or more images to classify')
args = parser.parse_args()

# Classify the image
classify(args.model_path, args.image_paths)


if __name__ == '__main__':
main()
Loading

0 comments on commit 94f069c

Please sign in to comment.