Skip to content

Commit

Permalink
V0.4.0 (#27)
Browse files Browse the repository at this point in the history
* update batch norm layer

* optim max pooling

* expose profiler api

* list network blobs

* remove cudnn v4 support

* test buffer io

* find cuda arch for vs2015
  • Loading branch information
luoyetx authored Mar 20, 2017
1 parent ad9c8e4 commit ac27a62
Show file tree
Hide file tree
Showing 22 changed files with 286 additions and 53 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ If you don't use Ubuntu, then you may need to install OpenBLAS and protobuf thro

Mini-Caffe now can be cross compiled for Android platform, checkout the document [here](android).

### With CUDA and CUDNN
### With CUDA and CUDNN support

Install [CUDA8](https://developer.nvidia.com/cuda-downloads) and [cuDNN5.1](https://developer.nvidia.com/cudnn) in your system, then we can compile Mini-Caffe with GPU support. Run CMake command below.

Expand All @@ -89,4 +89,4 @@ To use Mini-Caffe as a library, you may refer to [example](example).

### How to profile your network

The Profiler in Mini-Caffe can help you profile your network performance, see docs [here](profile.md)
The Profiler in Mini-Caffe can help you profile your network performance, see docs [here](profile.md).
22 changes: 14 additions & 8 deletions cmake/Cuda.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,21 @@ function(caffe_detect_installed_gpus out_variable)
" return 0;\n"
"}\n")
if(MSVC)
# Add directory of "cl.exe" to system path, otherwise "nvcc --run" will fail with "Cannot find compiler 'cl.exe' in PATH"
get_filename_component(CL_DIR ${CMAKE_C_COMPILER} DIRECTORY)
set(ENV{PATH} "$ENV{PATH};${CL_DIR}")
#find vcvarsall.bat and run it building msvc environment
get_filename_component(MY_COMPILER_DIR ${CMAKE_CXX_COMPILER} DIRECTORY)
find_file(MY_VCVARSALL_BAT vcvarsall.bat "${MY_COMPILER_DIR}/.." "${MY_COMPILER_DIR}/../..")
execute_process(COMMAND ${MY_VCVARSALL_BAT} && ${CUDA_NVCC_EXECUTABLE} -arch sm_30 --run ${__cufile}
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/CMakeFiles/"
RESULT_VARIABLE __nvcc_res OUTPUT_VARIABLE __nvcc_out
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
else()
execute_process(COMMAND ${CUDA_NVCC_EXECUTABLE} -arch sm_30 --run ${__cufile}
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/CMakeFiles/"
RESULT_VARIABLE __nvcc_res OUTPUT_VARIABLE __nvcc_out
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
endif()
execute_process(COMMAND "${CUDA_NVCC_EXECUTABLE}" "--run" "${__cufile}"
WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/CMakeFiles/"
RESULT_VARIABLE __nvcc_res OUTPUT_VARIABLE __nvcc_out
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)

if(__nvcc_res EQUAL 0)
# nvcc outputs text containing line breaks when building with MSVC.
Expand Down
25 changes: 25 additions & 0 deletions include/caffe/c_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,31 @@ CAFFE_API int CaffeNetListParam(NetHandle net,
const char ***names,
BlobHandle **params);

// Profiler, don't enable Profiler in multi-thread Env

/*!
* \brief enable profiler
*/
CAFFE_API int CaffeProfilerEnable();
/*!
* \brief disable profiler
*/
CAFFE_API int CaffeProfilerDisable();
/*!
* \brief open a scope on profiler
* \param name scope name
*/
CAFFE_API int CaffeProfilerScopeStart(const char *name);
/*!
* \brief close a scope
*/
CAFFE_API int CaffeProfilerScopeEnd();
/*!
* \brief dump profile data to file
* \param fn file name or path
*/
CAFFE_API int CaffeProfilerDump(const char *fn);

// Helper

/*!
Expand Down
2 changes: 1 addition & 1 deletion include/caffe/logging.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ class LogMessageFatal {
#else
~LogMessageFatal() noexcept(false) {
#endif
// LOG(ERROR) << log_stream_.str();
LOG(ERROR) << log_stream_.str();
throw Error(log_stream_.str());
}
std::ostringstream &stream() { return log_stream_; }
Expand Down
2 changes: 1 addition & 1 deletion include/caffe/profiler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
namespace caffe {

/*!
* \brief Profiler for Caffe
* \brief Profiler for Caffe, don't enable Profiler in Multi-thread Env
* This class is used to profile a range of source code as a scope.
* The basic usage is like below.
*
Expand Down
1 change: 1 addition & 0 deletions java/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,4 @@ gradle-app.setting
# gradle/wrapper/gradle-wrapper.properties

*.log
*.json
47 changes: 47 additions & 0 deletions java/src/main/java/com/luoyetx/minicaffe/Utils.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,56 @@ public static void SetCaffeMode(int mode, int device) {
throw new RuntimeException(GetLastError());
}
}
/**
* enable profiler
*/
public static void EnableProfiler() {
if (jniProfilerEnable() != 0) {
throw new RuntimeException(GetLastError());
}
}
/**
* disable profiler
*/
public static void DisableProfiler() {
if (jniProfilerDisable() != 0) {
throw new RuntimeException(GetLastError());
}
}
/**
* open a scope on profiler
* @param naem scope name
*/
public static void OpenScope(String name) {
if (jniProfilerScopeStart(name) != 0) {
throw new RuntimeException(GetLastError());
}
}
/**
* close a scope
*/
public static void CloseScope() {
if (jniProfilerScopeEnd() != 0) {
throw new RuntimeException(GetLastError());
}
}
/**
* dump profiler data to file
* @param fn file path
*/
public static void DumpProfile(String fn) {
if (jniProfilerDump(fn) != 0) {
throw new RuntimeException(GetLastError());
}
}
private static native String jniGetLastError();
private static native int jniGPUAvailable();
private static native int jniSetMode(int mode, int device);
private static native int jniProfilerEnable();
private static native int jniProfilerDisable();
private static native int jniProfilerScopeStart(String name);
private static native int jniProfilerScopeEnd();
private static native int jniProfilerDump(String fn);

static {
System.loadLibrary("caffe");
Expand Down
5 changes: 5 additions & 0 deletions java/src/test/java/MiniCaffeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,15 @@ public class MiniCaffeTest {
} else {
System.out.println("Use CPU to run model");
}
Utils.EnableProfiler();
System.out.println("Create NIN");
Net net = new Net("../build/model/nin.prototxt",
"../build/model/nin.caffemodel");
Utils.OpenScope("nin");
testForward(net);
Utils.CloseScope();
Utils.DisableProfiler();
Utils.DumpProfile("nin-profile.json");
// test create from buffer
System.out.println("Create ResNet from buffer");
try {
Expand Down
1 change: 1 addition & 0 deletions python/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ dist
build

*.pyc
*.json
1 change: 1 addition & 0 deletions python/minicaffe/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
from .net import Net
from .base import check_gpu_available, set_runtime_mode
from .craft import LayerCrafter
from .profiler import Profiler

__version__ = '0.4.0'
24 changes: 23 additions & 1 deletion python/minicaffe/net.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
# pylint: disable=invalid-name
"""Net represents caffe::Net in C++"""
from __future__ import absolute_import
import ctypes
from collections import defaultdict
import ctypes
from .base import LIB
from .base import c_str, py_str, check_call
from .base import NetHandle, BlobHandle
Expand Down Expand Up @@ -51,6 +51,28 @@ def get_blob(self, name):
check_call(LIB.CaffeNetGetBlob(self.handle, c_str(name), ctypes.byref(handle)))
return Blob(handle)

@property
def blobs(self):
"""return network internal blobs
Returns
-------
blobs: dict(name: Blob)
network internal blobs with their name
"""
ctypes_n = ctypes.c_int32()
ctypes_names = ctypes.POINTER(ctypes.c_char_p)()
ctypes_blobs = ctypes.POINTER(BlobHandle)()
check_call(LIB.CaffeNetListBlob(self.handle, ctypes.byref(ctypes_n),
ctypes.byref(ctypes_names),
ctypes.byref(ctypes_blobs)))
blobs = dict()
for i in range(ctypes_n.value):
name = py_str(ctypes_names[i])
blob = Blob(BlobHandle(ctypes_blobs[i]))
blobs[name] = blob
return blobs

@property
def params(self):
"""return network params
Expand Down
50 changes: 50 additions & 0 deletions python/minicaffe/profiler.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# coding = utf-8
# pylint: disable=invalid-name
"""Profiler in mini-caffe"""
from .base import LIB
from .base import c_str, check_call


class Profiler(object):
"""Profiler
"""

@staticmethod
def enable():
"""enable profiler
"""
check_call(LIB.CaffeProfilerEnable())

@staticmethod
def disable():
"""disable profiler
"""
check_call(LIB.CaffeProfilerDisable())

@staticmethod
def open_scope(name):
"""open a scope on profiler
Parameters
----------
name: string
scope name
"""
check_call(LIB.CaffeProfilerScopeStart(c_str(name)))

@staticmethod
def close_scope():
"""close a scope on profiler
"""
check_call(LIB.CaffeProfilerScopeEnd())

@staticmethod
def dump(fn):
"""dump profiler data to fn
Parameters
----------
fn: string
file path to save profiler data
"""
check_call(LIB.CaffeProfilerDump(c_str(fn)))
12 changes: 12 additions & 0 deletions python/tests/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,11 @@ def test_network():
# check gpu available
if mcaffe.check_gpu_available():
mcaffe.set_runtime_mode(1, 0)
mcaffe.Profiler.enable()
# set up network
net = mcaffe.Net(os.path.join(model_dir, 'resnet.prototxt'),
os.path.join(model_dir, 'resnet.caffemodel'))
mcaffe.Profiler.open_scope("resnet")
blob = net.get_blob('data')
shape = blob.shape
size = 1
Expand All @@ -53,6 +55,9 @@ def test_network():
net.forward()
t1 = time.clock()
t = (t1 - t0) * 1000
mcaffe.Profiler.close_scope()
mcaffe.Profiler.disable()
mcaffe.Profiler.dump("resnet-profile.json")
print('Forward ResNet costs %f ms'%t)
# network parameters
params = net.params
Expand All @@ -62,6 +67,13 @@ def test_network():
shape = param.shape
print('\t%s: [%d, %d, %d, %d]'%(name, shape[0], shape[1], shape[2], shape[3]))
print('}')
# network internal blobs
blobs = net.blobs
print('{')
for name, blob in list(blobs.items()):
shape = blob.shape
print('\t%s: [%d, %d, %d, %d]'%(name, shape[0], shape[1], shape[2], shape[3]))
print('}')


if __name__ == '__main__':
Expand Down
31 changes: 31 additions & 0 deletions src/c_api.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "caffe/c_api.h"
#include "caffe/blob.hpp"
#include "caffe/net.hpp"
#include "caffe/profiler.hpp"

// ThreadLocal Template

Expand Down Expand Up @@ -129,6 +130,36 @@ int CaffeNetGetBlob(NetHandle net, const char *name, BlobHandle *blob) {
API_END();
}

int CaffeProfilerEnable() {
API_BEGIN();
caffe::Profiler::Get()->TurnON();
API_END();
}

int CaffeProfilerDisable() {
API_BEGIN();
caffe::Profiler::Get()->TurnOFF();
API_END();
}

int CaffeProfilerScopeStart(const char *name) {
API_BEGIN();
caffe::Profiler::Get()->ScopeStart(name);
API_END();
}

int CaffeProfilerScopeEnd() {
API_BEGIN();
caffe::Profiler::Get()->ScopeEnd();
API_END();
}

int CaffeProfilerDump(const char *fn) {
API_BEGIN();
caffe::Profiler::Get()->DumpProfile(fn);
API_END();
}

struct BlobsEntry {
std::vector<const char*> vec_charp;
std::vector<void*> vec_handle;
Expand Down
30 changes: 30 additions & 0 deletions src/jni/jni.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,3 +157,33 @@ CaffeJNIMethod(Utils, SetMode, jint)(JNIEnv *env, jobject thiz,
jint mode, jint device) {
return CaffeSetMode(mode, device);
}

CaffeJNIMethod(Utils, ProfilerEnable, jint)(JNIEnv *env, jobject thiz) {
return CaffeProfilerEnable();
}

CaffeJNIMethod(Utils, ProfilerDisable, jint)(JNIEnv *env, jobject thiz) {
return CaffeProfilerDisable();
}

CaffeJNIMethod(Utils, ProfilerScopeStart, jint)(JNIEnv *env, jobject thiz,
jstring name) {
const char *name_cstr = (*env)->GetStringUTFChars(env, name, NULL);
CHECK_SUCCESS(CaffeProfilerScopeStart(name_cstr), {
(*env)->ReleaseStringUTFChars(env, name, name_cstr);
});
return 0;
}

CaffeJNIMethod(Utils, ProfilerScopeEnd, jint)(JNIEnv *env, jobject thiz) {
return CaffeProfilerScopeEnd();
}

CaffeJNIMethod(Utils, ProfilerDump, jint)(JNIEnv *env, jobject thiz,
jstring fn) {
const char *fn_cstr = (*env)->GetStringUTFChars(env, fn, NULL);
CHECK_SUCCESS(CaffeProfilerDump(fn_cstr), {
(*env)->ReleaseStringUTFChars(env, fn, fn_cstr);
});
return 0;
}
Loading

0 comments on commit ac27a62

Please sign in to comment.