Skip to content
This repository has been archived by the owner on Nov 17, 2023. It is now read-only.

Commit

Permalink
Caffe to MXNet code translator (#8782)
Browse files Browse the repository at this point in the history
Caffe Translator is a migration tool that helps developers migrate their existing Caffe code to MXNet and continue further development using MXNet.

Caffe Translator takes the training/validation prototxt and solver prototxt as input and produces MXNet Python code as output. The translated Python code uses MXNet Symbol and Module API to build the network, reads data from LMDB files, runs training and saves the trained model using the MXNet Module API.

More info here: https://github.com/apache/incubator-mxnet/tree/master/tools/caffe_translator

* Add Caffe Translator.
Caffe Translator translates Caffe training/validation prototxt to MXNet Python code.

* Minor bug fix.

* [WIP] Convergence test for caffe translator

* [WIP - Caffe Translator testing] Skeleton code for going thorough each test, translating, training, testing and generating report. Details are yet to be filled.

* [WIP - Caffe Translator Test] Add code to create directory and invoke translator.

* [WIP Caffe Converter tests] Train the converted network and collect logs.

* [WIP - Caffe Translator test] Add code to search for a particular metric in log file and extract it.

* - Bug fixes
- Code refactoring

* Add ‘num_examples’ parameter to generated CaffeDataIter.

CaffeDataIter requires user to provide number of examples in the dataset using the num_examples parameter.
However this information is not available in Caffe prototxt.

This commit lets user add this information to the caffe prototxt as a comment. Caffe will parse it as comment and ignore it. Translator will pick the value and use it while generating CaffeDataIter.

Example usage:
  data_param {
    source: "data/mnist/mnist_train_lmdb"
    #caffe2mxnet num_examples: 60000
    batch_size: 64
    backend: LMDB
  }

* Update README.md

* Update README.md

* Update README.md

* Create faq.md

* Update faq.md

* Update faq.md

* Update faq.md

* Update faq.md

* Update faq.md

* Update faq.md

* Update README.md

* Update README.md

* Get test directory as input from command line.

* Refactor code.

* Don't print translated code to console.

* Make sure "#caffemxnet num_examples: ..." doesn't go into iterator's prototxt.

* Add sample test_dir

* Add data directory

* Add test configuration.
Use the name test.cfg instead of test_description.txt

* Create README.md

* Update faq.md

* Update faq.md

* Update faq.md

* Add script to convert .caffemodel to .params file.
Only handles convolution and fuly connected layers. But can be easily extended to handle other layers.

* Add ability to initialize networks with pretrained weights.

* Add ability to convert weights for Deconvolution, BatchNorm and Scale.

* Code cleanup.

* Code cleanup. Remove the Constants class.

* Code cleanup.

* Code cleanup

* Cleanup. Replace "indhub/mxnet" with "apache/incubator-mxnet".

* Fix lint errors.

* Fix lint issues.

* Add few more solvers for lenet

* Fix a regression.

* Add Apache license.

* Remove automated tests.

* Create fat jar.
Set version to 0.9.0.

* Add license header.

* Remove the 'all' suffix from the fat jar name.

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update gradle wrapper to use shadow plugin.

* Initial work for signing and uploading artifacts to maven.

* Include jar signature in the artifacts that get uploaded.

* Add gradle properties required for signing and uploading artifacts to maven.

* Print helpful error message when translator is not able to find the prototxt.

* Print helpful error message in console and add a helpful comment in the generated code when an unknown lr policy is encountered.

* Add final modifier when appropriate.

* Rename GenHelper to GenerationHelper.

* Expand imports

* Some code style changes.

* Update README.md

* Update README.md

* Create build_from_source.md

* Update README.md

* Update faq.md

* Update README.md

* Update build_from_source.md

* Update README.md

* Update README.md

* Update faq.md

* - Add source and doc jar.
- Add ability to upload to staging repo.
- Make sure all .asc files get uploaded.

* Update README.md

* Update maven pom with fields required for uploading artifacts.

* Bump version to 0.9.1

* Update README.md

Add the list of command line parameters accepted by the Caffe Translator.

* Update README.md

Update repo location

* After successful translation, print a message indicating the translation was success.

* Update README.md

* Update README.md

* Update faq.md

* Update README.md

* Update README.md

Provide a sample translated output

* Update README.md

Add links to examples to show how the following items looks like:
1. Translated code.
2. LMDB file.
3. Model saved after training.

* Rename #caffe2mxnet directive to #CaffeToMXNet to avoid any confusion with Caffe 2.
  • Loading branch information
indhub authored Dec 2, 2017
1 parent f13ce52 commit 3b3016e
Show file tree
Hide file tree
Showing 84 changed files with 4,143 additions and 0 deletions.
79 changes: 79 additions & 0 deletions tools/caffe_translator/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Caffe Translator
Caffe Translator is a migration tool that helps developers migrate their existing Caffe code to MXNet and continue further development using MXNet. Note that this is different from the Caffe to MXNet model converter which is available [here](https://github.com/apache/incubator-mxnet/tree/master/tools/caffe_converter).

Caffe Translator takes the training/validation prototxt ([example](https://github.com/BVLC/caffe/blob/master/examples/mnist/lenet_train_test.prototxt)) and solver prototxt ([example](https://github.com/BVLC/caffe/blob/master/examples/mnist/lenet_solver.prototxt)) as input and produces MXNet Python code ([example](https://www.caffetranslator.org/examples/lenet/lenet_translated.py)) as output. The translated Python code uses MXNet Symbol and Module API to build the network, reads data from LMDB files ([example](https://www.caffetranslator.org/datasets/mnist.tar.gz)), runs training and saves the trained model using the MXNet Module API ([example](https://www.caffetranslator.org/examples/lenet/lenet_saved_model.tar.gz)).

### How to use

#### Get the translator:
Download the Caffe Translator from maven [repository](https://mvnrepository.com/artifact/org.caffetranslator/caffe-translator) or [build](build_from_source.md) from source. Java Runtime Environment (JRE) is required to run the translator.

#### Translate code:
To translate `train_val.prototxt` and `solver.prototxt` to MXNet Python code, run the following command:
```
java -jar caffe-translator-<version>.jar --training-prototxt <train_val_prototxt_path> \
--solver <solver_prototxt_path> \
--output-file <output_file_path>
```
Example:
```
java -jar caffe-translator-0.9.1.jar --training-prototxt lenet_train_test.prototxt \
--solver lenet_solver.prototxt \
--output-file translated_code.py
```

Here is the list of command line parameters accepted by the Caffe Translator:
- *training-prototxt*: specifies the path to the training/validation prototxt to be translated.
- *solver-prototxt*: specifies the path to the solver prototxt to be translated.
- *output-file*: specifies the file to write the translated output into.
- *params-file* (optional): specifies the .caffemodel file to initialize parameters from.
- *custom-data-layers* (optional): Specifies a comma-separated list of types of the custom data layers used in the prototxt. The translator will use [`CaffeDataIter`](https://mxnet.incubator.apache.org/how_to/caffe.html#use-io-caffedataiter) to translate these layers to MXNet.

**Note:** Translated code uses [`CaffeDataIter`](https://mxnet.incubator.apache.org/how_to/caffe.html#use-io-caffedataiter) to read from LMDB files. `CaffeDataIter` requires the number of examples in LMDB file to be specified as a parameter. You can provide this information before translation using a `#CaffeToMXNet` directive like shown below:

```
data_param {
source: "data/mnist/mnist_train_lmdb"
#CaffeToMXNet num_examples: 60000
batch_size: 64
backend: LMDB
}
```

#### Run the translated code:

Following prerequisites are required to run the translated code:
1. Caffe with MXNet interface ([Why?](faq.md#why_caffe) [How to build?](https://github.com/apache/incubator-mxnet/tree/master/plugin/caffe#install-caffe-with-mxnet-interface))
2. MXNet with Caffe plugin ([How to build?](https://github.com/apache/incubator-mxnet/tree/master/plugin/caffe#compile-with-caffe))
3. The dataset in LMDB format.

Once prerequisites are installed, the translated Python code can be run like any other Python code:

Example:
```
python translated_code.py
```

### What layers are supported?

Caffe Translator can currently translate the following layers:

- Accuracy and Top-k
- Batch Normalization
- Concat
- Convolution
- Data<sup>*</sup>
- Deconvolution
- Eltwise
- Inner Product (Fully Connected layer)
- Flatten
- Permute
- Pooling
- Power
- Relu
- Scale<sup>*</sup>
- SoftmaxOutput

<sup>*</sup> Uses [CaffePlugin](https://github.com/apache/incubator-mxnet/tree/master/plugin/caffe)

If you want Caffe Translator to translate a layer that is not in the above list, please create an [issue](https://github.com/apache/incubator-mxnet/issues/new).
152 changes: 152 additions & 0 deletions tools/caffe_translator/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import org.gradle.api.artifacts.maven.MavenDeployment

apply plugin: 'com.github.johnrengelman.shadow'
apply plugin: 'java'

apply plugin: 'antlr'
apply plugin: 'application'

apply plugin: 'maven'
apply plugin: 'signing'

group 'org.caffetranslator'
version '0.9.1'

def isReleaseBuild
def repositoryUrl

if(hasProperty("release")) {
isReleaseBuild = true
repositoryUrl = stagingRepositoryUrl
} else if(hasProperty("CI")) {
repositoryUrl = snapshotRepositoryUrl
version += "-SNAPSHOT"
}

buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.1'
}
}

sourceCompatibility = 1.8

repositories {
mavenCentral()
}

dependencies {
antlr "org.antlr:antlr4:$antlrVersion"
compile group: 'commons-cli', name: 'commons-cli', version: '1.4'
compileOnly 'org.projectlombok:lombok:1.16.18'
testCompile group: 'junit', name: 'junit', version: '4.12'
}

generateGrammarSource {
arguments += ['-visitor']
}

jar {
baseName = 'caffe-translator'
appendix = 'slim'
version = version
manifest {
attributes 'Main-Class': 'io.mxnet.caffetranslator.Launcher'
}
}

task javadocJar(type: Jar) {
classifier = 'javadoc'
from javadoc
}

task sourcesJar(type: Jar) {
classifier = 'sources'
from sourceSets.main.allSource
}

shadowJar {
baseName = 'caffe-translator'
classifier = ''
version = version
}

configurations {
releaseJars
ascSignatures
}

artifacts {
releaseJars shadowJar
releaseJars sourcesJar
releaseJars javadocJar
}

if(isReleaseBuild) {
signing {
sign configurations.releaseJars
}
} else {
task signReleaseJars {
//no-op
}
}

uploadShadow {
repositories {
mavenDeployer {
beforeDeployment { MavenDeployment deployment ->
if(isReleaseBuild) {
signing.signPom(deployment)
}
configurations.releaseJars.artifacts.each { ra ->
def ascfile = file(ra.file.path + '.asc')
def ascArtifact = project.artifacts.add('ascSignatures', ascfile) {
classifier = ra.classifier
extension = ra.extension + '.asc'
type = ra.type + '.asc'
}
deployment.addArtifact(ra)
deployment.addArtifact(ascArtifact)
}
}

repository(url: repositoryUrl) {
authentication(userName: ossrhUsername, password: ossrhPassword)
}

pom.project {
name 'Caffe Translator'
packaging 'jar'
description 'Translate Caffe code to MXNet Python code'
url 'http://caffetranslator.org'

licenses {
license {
name 'The Apache Software License, Version 2.0'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
distribution 'repo'
}
}

developers {
developer {
name 'Indu Bharathi'
email '[email protected]'
}
}

scm {
connection 'scm:git:git://github.com:apache/incubator-mxnet.git'
developerConnection 'scm:git:[email protected]:apache/incubator-mxnet.git'
url 'https://github.com/apache/incubator-mxnet.git'
}
}
}
}
}

mainClassName = "io.mxnet.caffetranslator.Launcher"
21 changes: 21 additions & 0 deletions tools/caffe_translator/build_from_source.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
### Build Caffe Translator from source

#### Prerequisites:
- JDK

#### Instructions to build

Step 1: Clone the code:
```
git clone https://github.com/apache/incubator-mxnet.git mxnet
```
Step 2: CD to CaffeTranslator directory
```
cd mxnet/tools/caffe_translator/
```
Step 3: Build
```
./gradlew build
```

Caffe Translator will be built at `build/libs/caffe-translator-<version>.jar`
17 changes: 17 additions & 0 deletions tools/caffe_translator/faq.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
### Frequently asked questions

[**Why is Caffe required to run the translated code?**](#why_caffe)

There is a couple of reasons why Caffe is required to run the translated code:

1. The translator does not convert Caffe data layer to native MXNet code because MXNet cannot read from LMDB files. Translator instead generates code that uses [`CaffeDataIter`](https://mxnet.incubator.apache.org/how_to/caffe.html#use-io-caffedataiter) which can read LMDB files. `CaffeDataIter` needs Caffe to run.

2. If the Caffe code to be translated uses custom layers, or layers that don't have equivalent MXNet layers, the translator will generate code that will use [CaffeOp](https://mxnet.incubator.apache.org/how_to/caffe.html#use-sym-caffeop). CaffeOp needs Caffe to run.

[**What version of Caffe prototxt can the translator translate?**](#what_version_of_prototxt)

Caffe Translator supports the `proto2` syntax.

[**Can the translator translate Caffe 2 code?**](#caffe_2_support)

No. At the moment, only Caffe is supported.
12 changes: 12 additions & 0 deletions tools/caffe_translator/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
antlrVersion=4.7

signing.keyId=<key-id>
signing.password=<key-password>
signing.secretKeyRingFile=<path-to-key-ring-file>

snapshotRepositoryUrl=https://oss.sonatype.org/content/repositories/snapshots
stagingRepositoryUrl=https://oss.sonatype.org/service/local/staging/deploy/maven2

ossrhUsername=<ossrh-username>
ossrhPassword=<ossrh_password>

Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.3.1-bin.zip
Loading

0 comments on commit 3b3016e

Please sign in to comment.