Skip to content

Commit

Permalink
NNVM Refactor (apache#3194)
Browse files Browse the repository at this point in the history
* Init nnvm change

* temp checkin

* Move TShape to NNVM

* Redirect Symbolic API to NNVM

* Add Op Prop Adapter

* Finish migrate in shape infer

* Pass all symbolic test

* temp commit

* enable aux data

* [EXEC] Basic version of exec for forward only

* [EXEC] Enable most optimizations, still wait grad and context

* fix legacy op with latest one

* Update NNVM NodeRef

* Adapt to newer interface

* ALl registry of backop is complete

* temp commit

* Hack finish backward pass

* [EXEC] One day pass

* [EXEC] Pass all operator unittest

* [EXEC] enable model parallel

* Fully pass all legacy tests

* Remove legacy symbolic code

* update news

* Make travis compile

* Fix python3

* Update viz module to new json format
  • Loading branch information
tqchen authored and piiswrong committed Dec 29, 2016
1 parent 3e0210b commit bcc7547
Show file tree
Hide file tree
Showing 34 changed files with 2,365 additions and 5,340 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,6 @@
[submodule "ps-lite"]
path = ps-lite
url = https://github.com/dmlc/ps-lite
[submodule "nnvm"]
path = nnvm
url = https://github.com/dmlc/nnvm
36 changes: 30 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ ifndef DMLC_CORE
DMLC_CORE = $(ROOTDIR)/dmlc-core
endif

ifndef NNVM_PATH
NNVM_PATH = $(ROOTDIR)/nnvm
endif

ifneq ($(USE_OPENMP), 1)
export NO_OPENMP = 1
endif
Expand All @@ -33,7 +37,7 @@ ifeq ($(DEBUG), 1)
else
CFLAGS += -O3
endif
CFLAGS += -I$(ROOTDIR)/mshadow/ -I$(ROOTDIR)/dmlc-core/include -fPIC -Iinclude $(MSHADOW_CFLAGS)
CFLAGS += -I$(ROOTDIR)/mshadow/ -I$(ROOTDIR)/dmlc-core/include -fPIC -I$(NNVM_PATH)/include -Iinclude $(MSHADOW_CFLAGS)
LDFLAGS = -pthread $(MSHADOW_LDFLAGS) $(DMLC_LDFLAGS)
ifeq ($(DEBUG), 1)
NVCCFLAGS = -std=c++11 -Xcompiler -D_FORCE_INLINES -g -G -O0 -ccbin $(CXX) $(MSHADOW_NVCCFLAGS)
Expand Down Expand Up @@ -152,15 +156,20 @@ ifeq ($(OS),Windows_NT)
else
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S), Darwin)
WHOLE_ARCH= -all_load
NO_WHOLE_ARCH= -noall_load
SCALA_PKG_PROFILE := osx-x86_64
else
SCALA_PKG_PROFILE := linux-x86_64
WHOLE_ARCH= --whole-archive
NO_WHOLE_ARCH= --no-whole-archive
endif
endif

# all dep
LIB_DEP += $(DMLC_CORE)/libdmlc.a
LIB_DEP += $(DMLC_CORE)/libdmlc.a $(NNVM_PATH)/lib/libnnvm.a
ALL_DEP = $(OBJ) $(EXTRA_OBJ) $(PLUGIN_OBJ) $(LIB_DEP)

ifeq ($(USE_CUDA), 1)
ALL_DEP += $(CUOBJ) $(EXTRA_CUOBJ) $(PLUGIN_CUOBJ)
LDFLAGS += -lcuda
Expand All @@ -169,6 +178,17 @@ else
SCALA_PKG_PROFILE := $(SCALA_PKG_PROFILE)-cpu
endif

# For quick compile test, used smaller subset
ALLX_DEP = $(filter-out build/src/operator/%, $(ALL_DEP))
ALLX_DEP+= build/src/operator/fully_connected.o
ALLX_DEP+= build/src/operator/fully_connected_gpu.o
ALLX_DEP+= build/src/operator/operator.o
ALLX_DEP+= build/src/operator/operator_util.o
ALLX_DEP+= build/src/operator/elementwise_unary_op.o
ALLX_DEP+= build/src/operator/custom.o

ALLX_DEP= $(ALL_DEP)

ifeq ($(USE_NVRTC), 1)
LDFLAGS += -lnvrtc
CFLAGS += -DMXNET_USE_NVRTC=1
Expand Down Expand Up @@ -210,13 +230,14 @@ build/plugin/%.o: plugin/%.cc

# NOTE: to statically link libmxnet.a we need the option
# --Wl,--whole-archive -lmxnet --Wl,--no-whole-archive
lib/libmxnet.a: $(ALL_DEP)
lib/libmxnet.a: $(ALLX_DEP)
@mkdir -p $(@D)
ar crv $@ $(filter %.o, $?)

lib/libmxnet.so: $(ALL_DEP)
lib/libmxnet.so: $(ALLX_DEP)
@mkdir -p $(@D)
$(CXX) $(CFLAGS) -shared -o $@ $(filter %.o %.a, $^) $(LDFLAGS)
$(CXX) $(CFLAGS) -shared -o $@ $(filter %.o, $^) $(LDFLAGS) \
-Wl,${WHOLE_ARCH} $(filter %.a, $^) -Wl,${NO_WHOLE_ARCH}

$(PS_PATH)/build/libps.a: PSLITE

Expand All @@ -228,7 +249,10 @@ $(DMLC_CORE)/libdmlc.a: DMLCCORE
DMLCCORE:
+ cd $(DMLC_CORE); make libdmlc.a USE_SSE=$(USE_SSE) config=$(ROOTDIR)/$(config); cd $(ROOTDIR)

bin/im2rec: tools/im2rec.cc $(ALL_DEP)
$(NNVM_PATH)/lib/libnnvm.a:
+ cd $(NNVM_PATH); make lib/libnnvm.a; cd $(ROOTDIR)

bin/im2rec: tools/im2rec.cc $(ALLX_DEP)

$(BIN) :
@mkdir -p $(@D)
Expand Down
14 changes: 13 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
MXNet Change Log
================
## in progress version
## NNVM: inprogress refactor branch
- Move symbolic API to NNVM @tqchen
- Most front-end C API are backward compatible
- Removed symbolic api in MXNet and relies on NNVM
- Change of JSON format
- param and attr field are merged to attr
- New code is backward compatible can load old json format
- OpProperty registration now is deprecated
- New operators are encouraged to register their property to NNVM op registry attribute
- Known features removed limitations to be fixed
- Bulk segment execution not yet added.
- The gradient aggregation optimization hack by switching to addto is not yet added,
can harm LSTM if it is constructed by unrolling the graph

## v0.8
This is the last release before the NNVM refactor.
Expand Down
50 changes: 25 additions & 25 deletions R-package/R/viz.graph.R
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#'
#'
#' Convert symbol to dot object for visualization purpose.
#'
#'
#' @importFrom magrittr %>%
#' @importFrom stringr str_extract_all
#' @importFrom magrittr %>%
Expand All @@ -14,14 +14,14 @@
#' @importFrom DiagrammeR create_edges
#' @importFrom DiagrammeR combine_edges
#' @importFrom DiagrammeR render_graph
#'
#'
#' @param model a \code{string} representing the path to a file containing the \code{JSon} of a model dump or the actual model dump.
#' @param graph.title a \code{string} displayed on top of the viz.
#' @param graph.title.font.name a \code{string} representing the font to use for the title.
#' @param graph.title.font.size a \code{numeric} representing the size of the font to use for the title.
#' @param graph.width.px a \code{numeric} representing the size (width) of the graph. In pixels
#' @param graph.height.px a \code{numeric} representing the size (height) of the graph. In pixels
#'
#'
#' @return a graph object ready to be displayed with the \code{print} function.
#'
#' @export
Expand All @@ -44,7 +44,7 @@ graph.viz <- function(model, graph.title = "Computation graph", graph.title.font
"#fccde5" # default value
)
}

get.shape <- function(type) {
switch(
EXPR = type,
Expand All @@ -62,35 +62,35 @@ graph.viz <- function(model, graph.title = "Computation graph", graph.title.font
"box" # default value
)
}

# extract IDs from string list
str2tuple <- function(str) str_extract_all(str, "\\d+") %>% unlist %>% as.numeric

# generate text content for each node.
get.label <- function(type, mat.row) {
switch(
EXPR = type,
"FullyConnected" = mat.row[,param.num_hidden] %>% paste("FullyConnected", ., sep = "\n"),
"FullyConnected" = mat.row[,attr.num_hidden] %>% paste("FullyConnected", ., sep = "\n"),
"Convolution" = {
kernel.parameters <- mat.row[,param.kernel] %>% str2tuple
stride.parameters <- mat.row[,param.stride] %>% str2tuple
num_filter.parameters <- mat.row[,param.num_filter] %>% str2tuple
kernel.parameters <- mat.row[,attr.kernel] %>% str2tuple
stride.parameters <- mat.row[,attr.stride] %>% str2tuple
num_filter.parameters <- mat.row[,attr.num_filter] %>% str2tuple
paste0("Convolution\n", kernel.parameters[1], "x", kernel.parameters[2],
"/", stride.parameters[1], ", ", num_filter.parameters)
},
},
"LeakyReLU" = ,
"Activation" = mat.row[,param.act_type] %>% paste0(type, "\n", .),
"Activation" = mat.row[,attr.act_type] %>% paste0(type, "\n", .),
"Pooling" = {
pool_type.parameters <- mat.row[,param.pool_type] %>% str2tuple
kernel.parameters <- mat.row[,param.kernel] %>% str2tuple
stride.parameters <- mat.row[,param.stride] %>% str2tuple
paste0("Pooling\n", pool_type.parameters, "\n", kernel.parameters[1], "x",
pool_type.parameters <- mat.row[,attr.pool_type] %>% str2tuple
kernel.parameters <- mat.row[,attr.kernel] %>% str2tuple
stride.parameters <- mat.row[,attr.stride] %>% str2tuple
paste0("Pooling\n", pool_type.parameters, "\n", kernel.parameters[1], "x",
kernel.parameters[2], "/", stride.parameters[1])
},
type # default value
)
}

mx.model.json <- fromJSON(model, flatten = T)
mx.model.nodes <- mx.model.json$nodes %>% as.data.table
mx.model.nodes[,id:= .I - 1]
Expand All @@ -99,12 +99,12 @@ graph.viz <- function(model, graph.title = "Computation graph", graph.title.font
mx.model.nodes[,color:= get.color(op), by = id] # by=id to have an execution row per row
mx.model.nodes[,shape:= get.shape(op), by = id] # by=id to have an execution row per row
mx.model.nodes[,label:= get.label(op, .SD), by = id] # by=id to have an execution row per row

nodes.to.keep <-
mx.model.nodes[op != "null",id] %>% unique %>% sort
nodes.to.remove <-
mx.model.nodes[,id] %>% unique %>% setdiff(nodes.to.keep) %>% sort

nodes <-
create_nodes(
nodes = mx.model.nodes[id %in% nodes.to.keep, id],
Expand All @@ -118,14 +118,14 @@ graph.viz <- function(model, graph.title = "Computation graph", graph.title.font
width = "1.3",
height = "0.8034"
)

mx.model.nodes[,has.connection:= sapply(inputs, function(x)
length(x) > 0)]

nodes.to.insert <-
mx.model.nodes[id %in% nodes.to.keep &
has.connection == T, .(id, inputs)]

edges <- NULL
for (i in 1:nrow(nodes.to.insert)) {
current.id <- nodes.to.insert[i, id]
Expand All @@ -140,7 +140,7 @@ graph.viz <- function(model, graph.title = "Computation graph", graph.title.font
else
edges <- combine_edges(edges.temp, edges)
}

graph <-
create_graph(
nodes_df = nodes,
Expand All @@ -151,7 +151,7 @@ graph.viz <- function(model, graph.title = "Computation graph", graph.title.font
# node_attrs = "fontname = Helvetica",
edge_attrs = c("color = gray20", "arrowsize = 0.8", "arrowhead = vee")
)

return(render_graph(graph, width = graph.width.px, height = graph.height.px))
}

Expand Down
8 changes: 8 additions & 0 deletions include/mxnet/base.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@
#include <dmlc/type_traits.h>
#include <dmlc/parameter.h>
#include <mshadow/tensor.h>
// nnvm headers for symbolic construction.
#include <nnvm/op.h>
#include <nnvm/tuple.h>
#include <nnvm/symbolic.h>
#include <string>

/*!
Expand Down Expand Up @@ -80,6 +84,10 @@ typedef mshadow::gpu gpu;
typedef mshadow::index_t index_t;
/*! \brief data type that will be used to store ndarray */
typedef mshadow::default_real_t real_t;
/*! \brief Shape data structure used to record shape information */
using TShape = nnvm::TShape;
/*! \brief operator structure from NNVM */
using Op = nnvm::Op;

/*! \brief Context information about the execution environment */
struct Context {
Expand Down
104 changes: 104 additions & 0 deletions include/mxnet/executor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*!
* Copyright (c) 2015 by Contributors
* \file executor.h
* \brief Symbolic executor interface of mxnet.
* \author Min Lin, Bing Xu
*/
#ifndef MXNET_EXECUTOR_H_
#define MXNET_EXECUTOR_H_

#include <dmlc/base.h>
#include <vector>
#include <memory>
#include <map>
#include <string>
#include <utility>
#include "./base.h"
#include "./c_api.h"
#include "./ndarray.h"
#include "./operator.h"

// check c++11
#if DMLC_USE_CXX11 == 0
#error "CXX11 was required for symbolic module"
#endif

namespace mxnet {
/*! \brief use symbolic graph from NNVM */
using nnvm::Symbol;

/*!
* \brief Executor of a computation graph.
* Executor can be created by Binding a symbol.
*/
class Executor {
public:
/*! \brief destructor */
virtual ~Executor() {}
/*!
* \brief Perform a Forward operation of Operator
* After this operation, user can get the result by using function head.
*/
virtual void Forward(bool is_train) = 0;
/*!
* \brief Perform a Partial Forward operation of Operator.
* Only issue operation specified by step.
* The caller must keep calling PartialForward with increasing steps, until step_left=0.
* \param is_train Whether this is training phase.
* \param step current step, user can always start from 0
* \param step_left Number of steps left to finish the forward.
*/
virtual void PartialForward(bool is_train, int step, int *step_left) = 0;
/*!
* \brief Perform a Backward operation of the Operator.
* This must be called after Forward.
* After this operation, NDArrays specified by grad_in_args_store will be updated accordingly.
* User is allowed to pass in an empty Array if the head node is
* loss function and head gradeitn is not needed.
*
* \param head_grads the gradient of head nodes to be backproped.
*/
virtual void Backward(const std::vector<NDArray> &head_grads) = 0;
/*!
* \brief print the execution plan info to output stream.
* \param os the output stream we like to print to.
*/
virtual void Print(std::ostream &os) const {} // NOLINT(*)
/*!
* \brief get array of outputs in the executor.
* \return array of outputs in the executor.
*/
virtual const std::vector<NDArray> &outputs() const = 0;
/*!
* \brief Create an operator by bind symbol with context and arguments.
* If user do not want to compute the gradients of i-th argument, grad_req_type[i] can be kNullOp.
*
* \param default_ctx the default context of binding.
* \param group2ctx Context mapping group to context.
* \param symbol the symbol that specifies the output of Forward pass.
* \param in_args the NDArray that stores the input arguments to the symbol.
* \param arg_grad_store NDArray that is used to store the gradient output of the input arguments.
* \param grad_req_type requirment type of gradient saving. Can only be in {kNullOp, kAddTo, kWriteTo}.
* \param aux_states NDArray that is used as internal state in op
* \param shared_exec input executor to share memory with.
* \return a new executor.
*/
static Executor *Bind(nnvm::Symbol symbol,
const Context& default_ctx,
const std::map<std::string, Context>& group2ctx,
const std::vector<NDArray> &in_args,
const std::vector<NDArray> &arg_grad_store,
const std::vector<OpReqType> &grad_req_type,
const std::vector<NDArray> &aux_states,
Executor* shared_exec = NULL);
/*!
* \brief the prototype of user-defined monitor callback
*/
typedef std::function<void(const char*, void*)> MonitorCallback;
/*!
* \brief Install a callback to notify the completion of operation.
*/
virtual void SetMonitorCallback(const MonitorCallback& callback) {}
}; // class executor
} // namespace mxnet
#endif // MXNET_EXECUTOR_H_
Loading

0 comments on commit bcc7547

Please sign in to comment.