├── LICENSE ├── README.md └── caffemodel2json.py /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Vadim Kantorov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | 24 | 25 | 26 | 27 | Following the request in https://github.com/dpp-name/protobuf-json/blob/master/protobuf_json.py (we are reusing the pb2json function from there) 28 | 29 | # JSON serialization support for Google's protobuf Messages 30 | # Copyright (c) 2009, Paul Dovbush 31 | # All rights reserved. 32 | # http://code.google.com/p/protobuf-json/ 33 | # 34 | # Redistribution and use in source and binary forms, with or without 35 | # modification, are permitted provided that the following conditions are 36 | # met: 37 | # 38 | # * Redistributions of source code must retain the above copyright 39 | # notice, this list of conditions and the following disclaimer. 40 | # * Redistributions in binary form must reproduce the above 41 | # copyright notice, this list of conditions and the following disclaimer 42 | # in the documentation and/or other materials provided with the 43 | # distribution. 44 | # * Neither the name of nor the names of its 45 | # contributors may be used to endorse or promote products derived from 46 | # this software without specific prior written permission. 47 | # 48 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 49 | # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 50 | # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 51 | # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 52 | # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 53 | # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 54 | # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 55 | # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 56 | # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 57 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 58 | # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 59 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | A small tool to dump Caffe's \*.caffemodel to JSON for inspection (\*.prototxt files is not needed). Will not print all the weights to make the output concise. This tool (with all weights output) can be used to generate json input for [DeepLearningKit](http://DeepLearningKit.org) for conv.nets generated in Caffe. 3 | 4 | ### Example 5 | > ./caffemodel2json.py CAFFE_ROOT/src/caffe/proto/caffe.proto model_name.caffemodel > dump.json 6 | 7 | Output would be something like: 8 | ``` 9 | protobuf: calling protoc 10 | protobuf: generated 11 | protobuf: imported 12 | model: caffemodel read in memory. Deserialization will take a few minutes. Take a coffee! 13 | model: deserialized 14 | model: json saved 15 | 16 | ALLOK. Quitting 17 | ``` 18 | 19 | ### Dependencies 20 | 1. Python 21 | 2. protobuf (with Python bindings) 22 | 3. Caffe's caffe.proto (or from a Caffe's fork, it's important if you are inspecting a model that implements new Caffe layers) 23 | 24 | ### Credits 25 | The tool reuses a function from https://github.com/dpp-name/protobuf-json. Great thanks to Paul Dovbush for making it available. 26 | -------------------------------------------------------------------------------- /caffemodel2json.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import json 4 | import argparse 5 | import tempfile 6 | import subprocess 7 | 8 | def log(x, prefix = None): 9 | if prefix != None: 10 | x = '%8s: %s' % (prefix, x) 11 | print >> sys.stderr, x 12 | 13 | def pb2json(pb): 14 | from google.protobuf.descriptor import FieldDescriptor as FD 15 | _ftype2js = { 16 | FD.TYPE_DOUBLE: float, 17 | FD.TYPE_FLOAT: float, 18 | FD.TYPE_INT64: long, 19 | FD.TYPE_UINT64: long, 20 | FD.TYPE_INT32: int, 21 | FD.TYPE_FIXED64: float, 22 | FD.TYPE_FIXED32: float, 23 | FD.TYPE_BOOL: bool, 24 | FD.TYPE_STRING: unicode, 25 | FD.TYPE_BYTES: lambda x: x.encode('string_escape'), 26 | FD.TYPE_UINT32: int, 27 | FD.TYPE_ENUM: int, 28 | FD.TYPE_SFIXED32: float, 29 | FD.TYPE_SFIXED64: float, 30 | FD.TYPE_SINT32: int, 31 | FD.TYPE_SINT64: long, 32 | } 33 | js = {} 34 | fields = pb.ListFields() #only filled (including extensions) 35 | for field,value in fields: 36 | if field.type == FD.TYPE_MESSAGE: 37 | ftype = pb2json 38 | elif field.type in _ftype2js: 39 | ftype = _ftype2js[field.type] 40 | else: 41 | log("WARNING: Field %s.%s of type '%d' is not supported" % (pb.__class__.__name__, field.name, field.type, )) 42 | if field.label == FD.LABEL_REPEATED: 43 | js_value = [] 44 | for v in value: 45 | js_value.append(ftype(v)) 46 | # Add the 3 commented lines if you want just a "preview" (short) mode of the json generated (for human inspection) 47 | # note that the preview json is useless for actual deep learning processing 48 | # 49 | # if len(js_value) > 64 or (field.name == 'data' and len(js_value) > 8): 50 | # head_n = 5 51 | # js_value = js_value[:head_n] + ['(%d elements more)' % (len(js_value) - head_n)] 52 | else: 53 | js_value = ftype(value) 54 | js[field.name] = js_value 55 | return js 56 | 57 | parser = argparse.ArgumentParser('Dump model_name.caffemodel to a file JSON format for debugging') 58 | parser.add_argument('caffe_proto', help = 'Path to caffe.proto (typically located at CAFFE_ROOT/src/caffe/proto/caffe.proto)') 59 | parser.add_argument('model_caffemodel', help = 'Path to model.caffemodel') 60 | parser.add_argument('--codegenDir', help = 'Path to an existing temporary directory to save generated protobuf Python classes', default = tempfile.mkdtemp()) 61 | args = parser.parse_args() 62 | 63 | log('calling protoc', 'protobuf') 64 | subprocess.check_call(['protoc', '--proto_path', os.path.dirname(args.caffe_proto), '--python_out', args.codegenDir, args.caffe_proto]) 65 | log('generated', 'protobuf') 66 | 67 | sys.path.insert(0, args.codegenDir) 68 | import caffe_pb2 69 | log('imported', 'protobuf') 70 | 71 | 72 | netParam = caffe_pb2.NetParameter() 73 | msg = open(args.model_caffemodel, 'rb').read() 74 | log('caffemodel read in memory. Deserialization will take a few minutes. Take a coffee!', 'model') 75 | netParam.ParseFromString(msg) 76 | log('deserialized', 'model') 77 | 78 | json.dump(pb2json(netParam), sys.stdout, indent = 2) 79 | log('json saved', 'model') 80 | 81 | log('') 82 | log('ALLOK. Quitting') 83 | --------------------------------------------------------------------------------