From 5128714c004f3b3c54d4c389131599c08e5413fd Mon Sep 17 00:00:00 2001 From: dzhwinter Date: Thu, 22 Jun 2017 03:59:51 +0800 Subject: [PATCH 01/40] "integrate go and optimizer library" --- go/pserver/cclient/cclient.go | 12 +++----- go/pserver/optimizer.c | 58 ----------------------------------- go/pserver/optimizer.go | 20 +++++------- go/pserver/optimizer.h | 22 ------------- go/pserver/service.go | 18 ++++++++--- 5 files changed, 26 insertions(+), 104 deletions(-) delete mode 100644 go/pserver/optimizer.c delete mode 100644 go/pserver/optimizer.h diff --git a/go/pserver/cclient/cclient.go b/go/pserver/cclient/cclient.go index 92a41b7f54..6aaaff7409 100644 --- a/go/pserver/cclient/cclient.go +++ b/go/pserver/cclient/cclient.go @@ -123,9 +123,8 @@ func paddle_begin_init_params(client C.paddle_pserver_client) C.int { func paddle_init_param(client C.paddle_pserver_client, param C.paddle_parameter, param_config unsafe.Pointer, config_len C.int) C.int { et := pserver.ElementType(param.element_type) name := C.GoString(param.name) - content := cArrayToSlice(unsafe.Pointer(param.content), int(param.content_len)) pc := pserver.ParameterWithConfig{ - Param: pserver.Parameter{Name: name, ElementType: et, Content: content}, + Param: pserver.Parameter{Name: name, ElementType: et, Content: param.content, Length: para.content_len}, Config: cArrayToSlice(param_config, int(config_len)), } c := get(client) @@ -167,8 +166,7 @@ func paddle_send_grads(client C.paddle_pserver_client, grads **C.paddle_gradient grad := *(**C.paddle_gradient)(unsafe.Pointer((uintptr(unsafe.Pointer(grads)) + uintptr(i)*unsafe.Sizeof(*grads)))) et := pserver.ElementType(grad.element_type) name := C.GoString(grad.name) - content := cArrayToSlice(unsafe.Pointer(grad.content), int(grad.content_len)) - gs = append(gs, pserver.Gradient{Name: name, ElementType: et, Content: content}) + gs = append(gs, pserver.Gradient{Name: name, ElementType: et, Content: grad.content, Length: grad.content_len}) } c := get(client) @@ -225,14 +223,14 @@ func paddle_get_params(client C.paddle_pserver_client, dst **C.paddle_parameter, } if unsafe.Pointer(param.content) != nullPtr { - if int(param.content_len) != len(p.Content) { + if int(param.content_len) != p.Length { log.Errorf("the pre-allocated content len does not match parameter content len. Pre-allocated len: %d, returned len: %d", param.content_len, len(p.Content)) return C.PSERVER_ERROR } } - C.memcpy(unsafe.Pointer(param.content), unsafe.Pointer(&p.Content[0]), C.size_t(len(p.Content))) - param.content_len = C.int(len(p.Content)) + C.memcpy(unsafe.Pointer(param.content), unsafe.Pointer(p.Content), C.size_t(p.Length)) + param.content_len = C.int(p.Length) param.element_type = C.paddle_element_type(p.ElementType) } diff --git a/go/pserver/optimizer.c b/go/pserver/optimizer.c deleted file mode 100644 index f16ba2cbf8..0000000000 --- a/go/pserver/optimizer.c +++ /dev/null @@ -1,58 +0,0 @@ -#include - -#include "optimizer.h" - -typedef int (*update_func)(void*, void*, paddle_element_type, const void*, int); -typedef void (*release_func)(void*); - -typedef struct paddle_optimizer { - update_func update; - release_func release; - void* optimizer; -} paddle_optimizer; - -void paddle_release_optimizer(paddle_optimizer* o) { - o->release(o->optimizer); - free(o); -} - -int paddle_update_parameter(paddle_optimizer* o, - void* buffer, - paddle_element_type element_type, - const void* gradient, - int num_bytes) { - return o->update(o->optimizer, buffer, element_type, gradient, num_bytes); -} - -typedef struct { double learning_rate; } SGD_optimizer; - -int update_SGD(void* optimizer, - void* buffer, - paddle_element_type element_type, - const void* gradient, - int num_bytes) { - SGD_optimizer* o = (SGD_optimizer*)optimizer; - float* parameter = (float*)buffer; - float* grad = (float*)gradient; - - int i; - for (i = 0; i < num_bytes / sizeof(float); ++i) { - parameter[i] -= o->learning_rate * grad[i]; - } - return 0; -} - -void release_SGD(void* optimizer) { - SGD_optimizer* o = (SGD_optimizer*)optimizer; - // nothing allocated on heap -} - -paddle_optimizer* paddle_create_SGD_optimizer(double learning_rate) { - SGD_optimizer* impl = (SGD_optimizer*)malloc(sizeof(SGD_optimizer)); - impl->learning_rate = learning_rate; - paddle_optimizer* opt = (paddle_optimizer*)malloc(sizeof(paddle_optimizer)); - opt->update = update_SGD; - opt->release = release_SGD; - opt->optimizer = impl; - return opt; -} diff --git a/go/pserver/optimizer.go b/go/pserver/optimizer.go index 417f8c5093..5abbca538f 100644 --- a/go/pserver/optimizer.go +++ b/go/pserver/optimizer.go @@ -1,7 +1,7 @@ package pserver /* -#include "optimizer.h" +#include "paddle/optimizer/optimizer.h" */ import "C" import ( @@ -9,34 +9,30 @@ import ( "unsafe" ) -type optimizerType int - -const ( - sgd optimizerType = iota -) - var nullPtr = unsafe.Pointer(uintptr(0)) type optimizer struct { opt *C.struct_paddle_optimizer } -func newOptimizer(t optimizerType, learning_rate float64) *optimizer { +func newOptimizer(paramWithConfigs ParameterWithConfig) *optimizer { o := &optimizer{} - o.opt = C.paddle_create_SGD_optimizer(C.double(learning_rate)) + p := paramWithConfigs.Param + c := paramWithConfigs.Config + o.opt = C.paddle_create_optimizer(C.uchar(c), C.int(len(c)), unsafe.Pointer(p.Content), c.int(p.Length), nullPtr, 0) return o } func (o *optimizer) UpdateParameter(p Parameter, g Gradient) error { - if len(p.Content) != len(g.Content) { - return fmt.Errorf("Name: %s, parameter and gradient length not match, parameter: %d, gradient: %d", p.Name, len(p.Content), len(g.Content)) + if p.Length != g.Length { + return fmt.Errorf("Name: %s, parameter and gradient length not match, parameter: %d, gradient: %d", p.Name, p.Length, g.Length) } if p.ElementType != g.ElementType { return fmt.Errorf("Name: %s, parameter and gradient element type not match, parameter: %v, gradient: %v", p.Name, p.ElementType, g.ElementType) } - r := C.paddle_update_parameter(o.opt, unsafe.Pointer(&p.Content[0]), C.paddle_element_type(p.ElementType), unsafe.Pointer(&g.Content[0]), C.int(len(g.Content))) + r := C.paddle_update_parameter(o.opt, C.paddle_element_type(p.ElementType), unsafe.Pointer(g.Content), C.int(g.Length)) if r != 0 { return fmt.Errorf("optimizer update returned error code: %d", r) } diff --git a/go/pserver/optimizer.h b/go/pserver/optimizer.h deleted file mode 100644 index a7e3ff0530..0000000000 --- a/go/pserver/optimizer.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef PADDLE_PSERVER_OPTIMIZER_H -#define PADDLE_PSERVER_OPTIMIZER_H - -typedef enum { - PADDLE_ELEMENT_TYPE_INT32 = 0, - PADDLE_ELEMENT_TYPE_UINT32 = 1, - PADDLE_ELEMENT_TYPE_INT64 = 2, - PADDLE_ELEMENT_TYPE_UINT64 = 3, - PADDLE_ELEMENT_TYPE_FLOAT32 = 4, - PADDLE_ELEMENT_TYPE_FLOAT64 = 5, -} paddle_element_type; - -struct paddle_optimizer; -struct paddle_optimizer* paddle_create_SGD_optimizer(double learning_rate); -void paddle_release_optimizer(struct paddle_optimizer* o); -int paddle_update_parameter(struct paddle_optimizer* o, - void* buffer, - paddle_element_type element_type, - const void* gradient, - int num_bytes); - -#endif /* PADDLE_PSERVER_OPTIMIZER_H */ diff --git a/go/pserver/service.go b/go/pserver/service.go index 78a2bfaf63..c721388b6a 100644 --- a/go/pserver/service.go +++ b/go/pserver/service.go @@ -28,7 +28,8 @@ const ( type Parameter struct { Name string ElementType ElementType - Content []byte + Content *byte + Length int } // ParameterWithConfig contains the parameter and the configuration. @@ -44,14 +45,16 @@ type Gradient Parameter type Service struct { initialized chan struct{} - mu sync.Mutex - opt *optimizer + mu sync.Mutex + // injection from parameter to optimizer + optMap map[string]*optimizer paramMap map[string]Parameter } // NewService creates a new service. func NewService() *Service { - s := &Service{opt: newOptimizer(sgd, 0.005)} + s := &Service{} + s.optMap = make(map[string]*optimizer) s.paramMap = make(map[string]Parameter) s.initialized = make(chan struct{}) return s @@ -74,6 +77,7 @@ func (s *Service) InitParam(paramWithConfigs ParameterWithConfig, dummy *int) er // properly memory aligned, if not, make copy to a memory // aligned region. s.paramMap[paramWithConfigs.Param.Name] = paramWithConfigs.Param + s.optMap[paramWithConfigs.Param.Name] = newOptimizer(paramWithConfigs) return nil } @@ -106,8 +110,12 @@ func (s *Service) SendGrad(g Gradient, dummy *int) error { if !ok { return fmt.Errorf("parameter: %s does not exist", g.Name) } + o, ok := s.optMap[g.Name] + if !ok { + return fmt.Errorf("optimizer: %s does not exist", g.Name) + } - return s.opt.UpdateParameter(p, g) + return o.UpdateParameter(p, g) } // GetParam gets parameters from the parameter server. From 1f217f0ab319254b901d9f8df8be447e0bed17a6 Mon Sep 17 00:00:00 2001 From: dzhwinter Date: Thu, 22 Jun 2017 12:26:47 +0800 Subject: [PATCH 02/40] "add c testing, python testing TODO" --- go/pserver/cclient/cclient.go | 9 +-------- go/pserver/cclient/test/dump_optimizer_proto.py | 13 +++++++++++++ go/pserver/cclient/test/main.c | 13 ++++++++++++- go/pserver/cclient/test/optimizer.pb.txt | Bin 0 -> 51 bytes go/pserver/cclient/test/test_train.py | 2 ++ go/pserver/client_test.go | 8 ++++++-- python/paddle/v2/optimizer.py | 2 ++ 7 files changed, 36 insertions(+), 11 deletions(-) create mode 100644 go/pserver/cclient/test/dump_optimizer_proto.py create mode 100644 go/pserver/cclient/test/optimizer.pb.txt diff --git a/go/pserver/cclient/cclient.go b/go/pserver/cclient/cclient.go index 6aaaff7409..ba2a235de3 100644 --- a/go/pserver/cclient/cclient.go +++ b/go/pserver/cclient/cclient.go @@ -121,14 +121,7 @@ func paddle_begin_init_params(client C.paddle_pserver_client) C.int { //export paddle_init_param func paddle_init_param(client C.paddle_pserver_client, param C.paddle_parameter, param_config unsafe.Pointer, config_len C.int) C.int { - et := pserver.ElementType(param.element_type) - name := C.GoString(param.name) - pc := pserver.ParameterWithConfig{ - Param: pserver.Parameter{Name: name, ElementType: et, Content: param.content, Length: para.content_len}, - Config: cArrayToSlice(param_config, int(config_len)), - } - c := get(client) - err := c.InitParam(pc) + et if err != nil { if err.Error() == pserver.AlreadyInitialized { diff --git a/go/pserver/cclient/test/dump_optimizer_proto.py b/go/pserver/cclient/test/dump_optimizer_proto.py new file mode 100644 index 0000000000..2ed4db97f9 --- /dev/null +++ b/go/pserver/cclient/test/dump_optimizer_proto.py @@ -0,0 +1,13 @@ +import OptimizerConfig_pb2 as pb + +config = pb.OptimizerConfig() +config.clip_norm = 0.1 +config.lr_policy = pb.OptimizerConfig.Const +config.optimizer = pb.OptimizerConfig.SGD +config.sgd.momentum = 0.0 +config.sgd.decay = 0.0 +config.sgd.nesterov = False +config.const_lr.learning_rate = 0.1 +s = config.SerializeToString() +with open("optimizer.pb.txt", 'w') as f: + f.write(s) diff --git a/go/pserver/cclient/test/main.c b/go/pserver/cclient/test/main.c index 03f749d4e4..7d26127b60 100644 --- a/go/pserver/cclient/test/main.c +++ b/go/pserver/cclient/test/main.c @@ -45,9 +45,20 @@ void getParams(paddle_pserver_client c) { } } + + int main() { char addr[] = "localhost:3000"; paddle_pserver_client c = paddle_new_pserver_client(addr, 1); + char config_proto[1024]; + size_t config_proto_len = 0; + ssize_t nread; + FILE *fp = fopen("optimizer.pb.txt", "r"); + if(!fp) { fail(); } + while((nread = getline(&config_proto, &config_proto_len, fp)) != -1) { + printf("%s", config_proto); + } + fclose(fp); retry: if (paddle_begin_init_params(c)) { paddle_parameter param; @@ -59,7 +70,7 @@ retry: param.name = name_a; param.content = content_a; param.content_len = 2000; - int error = paddle_init_param(c, param, NULL, 0); + int error = paddle_init_param(c, param, config_proto, config_proto_len); if (error != 0) { goto retry; } diff --git a/go/pserver/cclient/test/optimizer.pb.txt b/go/pserver/cclient/test/optimizer.pb.txt new file mode 100644 index 0000000000000000000000000000000000000000..27c8a584df40ab714edfd730f0ff7b7bd3783964 GIT binary patch literal 51 lcmd;JloDUb$N&X9;j9CU3=s@ToSd^}g1}Dum25B;7XZ}t4FdoG literal 0 HcmV?d00001 diff --git a/go/pserver/cclient/test/test_train.py b/go/pserver/cclient/test/test_train.py index 3f8d5d793b..68e1d9b269 100644 --- a/go/pserver/cclient/test/test_train.py +++ b/go/pserver/cclient/test/test_train.py @@ -22,6 +22,8 @@ def main(): # create optimizer optimizer = paddle.optimizer.Momentum(momentum=0) + #TODO(zhihong) : replace optimizer with new OptimizerConfig + trainer = paddle.trainer.SGD(cost=cost, parameters=parameters, update_equation=optimizer, diff --git a/go/pserver/client_test.go b/go/pserver/client_test.go index d0371a26a1..c5d38e4112 100644 --- a/go/pserver/client_test.go +++ b/go/pserver/client_test.go @@ -75,7 +75,9 @@ func TestClientFull(t *testing.T) { var p pserver.Parameter p.Name = "p_" + strconv.Itoa(i) p.ElementType = pserver.Float32 - p.Content = make([]byte, (i+1)*100) + ElementValue := make([]byte, (i+1)*100) + p.Content = &ElementValue[0] + p.Length = len(ElementValue) err := c.InitParam(pserver.ParameterWithConfig{Param: p}) if err != nil { t.Fatal(err) @@ -92,7 +94,9 @@ func TestClientFull(t *testing.T) { var g pserver.Gradient g.Name = "p_" + strconv.Itoa(i) g.ElementType = pserver.Float32 - g.Content = make([]byte, (i+1)*100) + ElementValue := make([]byte, (i+1)*100) + g.Content = &ElementValue[0] + g.Length = len(ElementValue) grads = append(grads, g) } diff --git a/python/paddle/v2/optimizer.py b/python/paddle/v2/optimizer.py index 1ef2dceca9..8124e219ba 100644 --- a/python/paddle/v2/optimizer.py +++ b/python/paddle/v2/optimizer.py @@ -5,6 +5,8 @@ import paddle.trainer_config_helpers.optimizers as v1_optimizers """ Optimizers(update equation) for SGD method. +TODO(zhihong) : create new optimizer with proto config, add new optimizer here + TODO(yuyang18): Complete comments. """ From cc487c09f73e2dc0e29d2ab07401061facd9b782 Mon Sep 17 00:00:00 2001 From: dzhwinter Date: Thu, 22 Jun 2017 12:52:18 +0800 Subject: [PATCH 03/40] "fix typo delete" --- go/pserver/cclient/cclient.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/go/pserver/cclient/cclient.go b/go/pserver/cclient/cclient.go index ba2a235de3..6aaaff7409 100644 --- a/go/pserver/cclient/cclient.go +++ b/go/pserver/cclient/cclient.go @@ -121,7 +121,14 @@ func paddle_begin_init_params(client C.paddle_pserver_client) C.int { //export paddle_init_param func paddle_init_param(client C.paddle_pserver_client, param C.paddle_parameter, param_config unsafe.Pointer, config_len C.int) C.int { - et + et := pserver.ElementType(param.element_type) + name := C.GoString(param.name) + pc := pserver.ParameterWithConfig{ + Param: pserver.Parameter{Name: name, ElementType: et, Content: param.content, Length: para.content_len}, + Config: cArrayToSlice(param_config, int(config_len)), + } + c := get(client) + err := c.InitParam(pc) if err != nil { if err.Error() == pserver.AlreadyInitialized { From eaed87b00ff4254c261136b4ed6de8eb794b8090 Mon Sep 17 00:00:00 2001 From: dzhwinter Date: Thu, 22 Jun 2017 23:33:47 +0800 Subject: [PATCH 04/40] "fix optimizer include error" --- go/pserver/cclient/CMakeLists.txt | 5 +++-- go/pserver/optimizer.go | 1 + go/pserver/optimizer_test.go | 6 ++++++ go/pserver/service_test.go | 8 ++++++-- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/go/pserver/cclient/CMakeLists.txt b/go/pserver/cclient/CMakeLists.txt index fff7ae7858..65a38ba1ad 100644 --- a/go/pserver/cclient/CMakeLists.txt +++ b/go/pserver/cclient/CMakeLists.txt @@ -10,5 +10,6 @@ include(golang) include(flags) go_library(paddle_pserver_cclient STATIC) - -add_subdirectory(test) +if(WITH_TESTING) + add_subdirectory(test) +endif() diff --git a/go/pserver/optimizer.go b/go/pserver/optimizer.go index 5abbca538f..3ee4c74652 100644 --- a/go/pserver/optimizer.go +++ b/go/pserver/optimizer.go @@ -1,6 +1,7 @@ package pserver /* +#cgo CFLAGS: -I ../../ #include "paddle/optimizer/optimizer.h" */ import "C" diff --git a/go/pserver/optimizer_test.go b/go/pserver/optimizer_test.go index 64d6d092aa..4930f0d95f 100644 --- a/go/pserver/optimizer_test.go +++ b/go/pserver/optimizer_test.go @@ -3,6 +3,12 @@ package pserver import "testing" func TestSGDCreateRelease(t *testing.T) { + param := pserver.ParameterWithConfig{ + Param : pserver.Parameter{Name : "a", + ElementType: , + Content: , + Length : } + } o := newOptimizer(sgd, 1) o.Cleanup() } diff --git a/go/pserver/service_test.go b/go/pserver/service_test.go index b746d13e1c..1b2626f7db 100644 --- a/go/pserver/service_test.go +++ b/go/pserver/service_test.go @@ -13,7 +13,9 @@ func TestFull(t *testing.T) { s := pserver.NewService() var p pserver.Parameter p.Name = "param_a" - p.Content = []byte{1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0} + ElementValue := []byte{1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0} + p.Content = &ElementValue[0] + p.Length = len(ElementValue) p.ElementType = pserver.Int32 err := s.InitParam(pserver.ParameterWithConfig{Param: p, Config: nil}, nil) if err != nil { @@ -22,7 +24,9 @@ func TestFull(t *testing.T) { var p1 pserver.Parameter p1.Name = "param_b" - p1.Content = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + ElementValue = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + p1.Content = &ElementValue[0] + p1.Length = len(ElementValue) p1.ElementType = pserver.Float32 err = s.InitParam(pserver.ParameterWithConfig{Param: p1, Config: nil}, nil) if err != nil { From 7386b06ccdec68f71dc71cdcef1588cc0ff68cb3 Mon Sep 17 00:00:00 2001 From: dzhwinter Date: Fri, 23 Jun 2017 01:01:15 +0800 Subject: [PATCH 05/40] "add optimizer naive link option" --- go/pserver/cclient/test/CMakeLists.txt | 4 - go/pserver/cclient/test/main.c | 104 ---------------- go/pserver/cclient/test/test_cclient.c | 159 ++++++++++++------------- go/pserver/optimizer.go | 3 + 4 files changed, 76 insertions(+), 194 deletions(-) delete mode 100644 go/pserver/cclient/test/main.c diff --git a/go/pserver/cclient/test/CMakeLists.txt b/go/pserver/cclient/test/CMakeLists.txt index 1a3dd7e5e9..722bd45d2f 100644 --- a/go/pserver/cclient/test/CMakeLists.txt +++ b/go/pserver/cclient/test/CMakeLists.txt @@ -1,7 +1,5 @@ cmake_minimum_required(VERSION 3.0) -add_executable(main main.c) -add_dependencies(main paddle_pserver_cclient) add_executable(test_cclient test_cclient.c) add_dependencies(test_cclient paddle_pserver_cclient) @@ -13,10 +11,8 @@ endif() if(PROJ_ROOT) include_directories(${CMAKE_CURRENT_BINARY_DIR}/..) - target_link_libraries(main ${CMAKE_CURRENT_BINARY_DIR}/../libpaddle_pserver_cclient.a pthread) target_link_libraries(test_cclient ${CMAKE_CURRENT_BINARY_DIR}/../libpaddle_pserver_cclient.a pthread) else(PROJ_ROOT) include_directories(${CMAKE_BINARY_DIR}) - target_link_libraries(main ${CMAKE_BINARY_DIR}/libpaddle_pserver_cclient.a pthread) target_link_libraries(test_cclient ${CMAKE_BINARY_DIR}/libpaddle_pserver_cclient.a pthread) endif(PROJ_ROOT) diff --git a/go/pserver/cclient/test/main.c b/go/pserver/cclient/test/main.c deleted file mode 100644 index 7d26127b60..0000000000 --- a/go/pserver/cclient/test/main.c +++ /dev/null @@ -1,104 +0,0 @@ -#include -#include - -#include "libpaddle_pserver_cclient.h" - -// TODO(helin): Fix: gtest using cmake is not working, using this -// hacky way for now. -#define fail() \ - fprintf(stderr, "info: %s:%d: ", __FILE__, __LINE__); \ - exit(-1); - -void sendGrads(paddle_pserver_client c) { - unsigned char grad_a[2000] = {2}; - unsigned char grad_b[3000] = {3}; - paddle_gradient grad1 = { - "param_a", PADDLE_ELEMENT_TYPE_FLOAT32, grad_a, 2000}; - paddle_gradient grad2 = { - "param_b", PADDLE_ELEMENT_TYPE_FLOAT32, grad_b, 3000}; - paddle_gradient* grads[2] = {&grad1, &grad2}; - if (paddle_send_grads(c, grads, 2)) { - fail(); - } -} - -void getParams(paddle_pserver_client c) { - paddle_parameter param_a; - paddle_parameter param_b; - char name_a[] = "param_a"; - char name_b[] = "param_b"; - // Must pre-allocate the prameter content before calling paddle_get_params. - unsigned char content_a[2000] = {}; - unsigned char content_b[3000] = {}; - param_a.element_type = PADDLE_ELEMENT_TYPE_FLOAT32; - param_a.name = name_a; - param_a.content = content_a; - param_a.content_len = 2000; - param_b.element_type = PADDLE_ELEMENT_TYPE_FLOAT32; - param_b.name = name_b; - param_b.content = content_b; - param_b.content_len = 3000; - - paddle_parameter* params[2] = {¶m_a, ¶m_b}; - if (paddle_get_params(c, params, 2)) { - fail(); - } -} - - - -int main() { - char addr[] = "localhost:3000"; - paddle_pserver_client c = paddle_new_pserver_client(addr, 1); - char config_proto[1024]; - size_t config_proto_len = 0; - ssize_t nread; - FILE *fp = fopen("optimizer.pb.txt", "r"); - if(!fp) { fail(); } - while((nread = getline(&config_proto, &config_proto_len, fp)) != -1) { - printf("%s", config_proto); - } - fclose(fp); -retry: - if (paddle_begin_init_params(c)) { - paddle_parameter param; - char name_a[] = "param_a"; - char name_b[] = "param_b"; - unsigned char content_a[2000] = {1}; - unsigned char content_b[3000] = {0}; - param.element_type = PADDLE_ELEMENT_TYPE_FLOAT32; - param.name = name_a; - param.content = content_a; - param.content_len = 2000; - int error = paddle_init_param(c, param, config_proto, config_proto_len); - if (error != 0) { - goto retry; - } - - param.element_type = PADDLE_ELEMENT_TYPE_FLOAT32; - param.name = name_b; - param.content = content_b; - param.content_len = 3000; - error = paddle_init_param(c, param, NULL, 0); - if (error != 0) { - goto retry; - } - - error = paddle_finish_init_params(c); - if (error != 0) { - goto retry; - } - } - - int i; - for (i = 0; i < 100; i++) { - sendGrads(c); - getParams(c); - } - - if (paddle_save_model(c, "/tmp/")) { - fail(); - } - - return 0; -} diff --git a/go/pserver/cclient/test/test_cclient.c b/go/pserver/cclient/test/test_cclient.c index 0f9c2ef801..7d26127b60 100644 --- a/go/pserver/cclient/test/test_cclient.c +++ b/go/pserver/cclient/test/test_cclient.c @@ -3,113 +3,100 @@ #include "libpaddle_pserver_cclient.h" -typedef float real; - -void fail() { - // TODO(helin): fix: gtest using cmake is not working, using this - // hacky way for now. - printf("test failed.\n"); +// TODO(helin): Fix: gtest using cmake is not working, using this +// hacky way for now. +#define fail() \ + fprintf(stderr, "info: %s:%d: ", __FILE__, __LINE__); \ exit(-1); + +void sendGrads(paddle_pserver_client c) { + unsigned char grad_a[2000] = {2}; + unsigned char grad_b[3000] = {3}; + paddle_gradient grad1 = { + "param_a", PADDLE_ELEMENT_TYPE_FLOAT32, grad_a, 2000}; + paddle_gradient grad2 = { + "param_b", PADDLE_ELEMENT_TYPE_FLOAT32, grad_b, 3000}; + paddle_gradient* grads[2] = {&grad1, &grad2}; + if (paddle_send_grads(c, grads, 2)) { + fail(); + } } -void print_parameter(paddle_gradient* param) { - if (param == NULL) { - printf("param is NULL!!\n"); - } else { - printf("==== parameter ====\n"); - printf("name: %s\n", param->name); - printf("content_len: %d\n", param->content_len); - printf("content_type: %d\n", param->element_type); - int i; - for (i = 0; i < param->content_len / (int)sizeof(real); ++i) { - printf("%f ", ((float*)param->content)[i]); - } - printf("\n\n"); +void getParams(paddle_pserver_client c) { + paddle_parameter param_a; + paddle_parameter param_b; + char name_a[] = "param_a"; + char name_b[] = "param_b"; + // Must pre-allocate the prameter content before calling paddle_get_params. + unsigned char content_a[2000] = {}; + unsigned char content_b[3000] = {}; + param_a.element_type = PADDLE_ELEMENT_TYPE_FLOAT32; + param_a.name = name_a; + param_a.content = content_a; + param_a.content_len = 2000; + param_b.element_type = PADDLE_ELEMENT_TYPE_FLOAT32; + param_b.name = name_b; + param_b.content = content_b; + param_b.content_len = 3000; + + paddle_parameter* params[2] = {¶m_a, ¶m_b}; + if (paddle_get_params(c, params, 2)) { + fail(); } } + + int main() { char addr[] = "localhost:3000"; paddle_pserver_client c = paddle_new_pserver_client(addr, 1); - - char* names[] = {"param_a", "param_b"}; - + char config_proto[1024]; + size_t config_proto_len = 0; + ssize_t nread; + FILE *fp = fopen("optimizer.pb.txt", "r"); + if(!fp) { fail(); } + while((nread = getline(&config_proto, &config_proto_len, fp)) != -1) { + printf("%s", config_proto); + } + fclose(fp); retry: - printf("init parameter to pserver:\n"); - - real param_content1[] = {0.1, 0.2, 0.3}; - real param_content2[] = {0.4, 0.5, 0.6}; - paddle_parameter** params = - (paddle_parameter**)malloc(sizeof(paddle_parameter*) * 2); - params[0] = (paddle_parameter*)malloc(sizeof(paddle_parameter)); - params[0]->name = names[0]; - params[0]->content = (unsigned char*)param_content1; - params[0]->content_len = 3 * sizeof(real); - params[0]->element_type = PADDLE_ELEMENT_TYPE_FLOAT32; - - params[1] = (paddle_parameter*)malloc(sizeof(paddle_parameter)); - params[1]->name = names[1]; - params[1]->content = (unsigned char*)param_content2; - params[1]->content_len = 3 * sizeof(real); - params[1]->element_type = PADDLE_ELEMENT_TYPE_INT32; - if (paddle_begin_init_params(c)) { - if (paddle_init_param(c, *params[0], NULL, 0) != 0) { + paddle_parameter param; + char name_a[] = "param_a"; + char name_b[] = "param_b"; + unsigned char content_a[2000] = {1}; + unsigned char content_b[3000] = {0}; + param.element_type = PADDLE_ELEMENT_TYPE_FLOAT32; + param.name = name_a; + param.content = content_a; + param.content_len = 2000; + int error = paddle_init_param(c, param, config_proto, config_proto_len); + if (error != 0) { goto retry; } - if (paddle_init_param(c, *params[1], NULL, 0) != 0) { + + param.element_type = PADDLE_ELEMENT_TYPE_FLOAT32; + param.name = name_b; + param.content = content_b; + param.content_len = 3000; + error = paddle_init_param(c, param, NULL, 0); + if (error != 0) { goto retry; } - if (paddle_finish_init_params(c) != 0) { + + error = paddle_finish_init_params(c); + if (error != 0) { goto retry; } - } else { - fail(); - } - - printf("get inited parameters from pserver:\n"); - // get parameters again by reusing the allocated parameter buffers. - if (paddle_get_params(c, params, 2) != 0) { - fail(); - } - print_parameter(params[0]); - print_parameter(params[1]); - - printf("send gradient to pserver:\n"); - real gradient_content1[] = {0.01, 0.02, 0.03}; - real gradinet_content2[] = {0.04, 0.05, 0.06}; - - paddle_gradient** grads = - (paddle_gradient**)malloc(sizeof(paddle_gradient*) * 2); - grads[0] = (paddle_gradient*)malloc(sizeof(paddle_gradient)); - grads[0]->name = names[0]; - grads[0]->content = (unsigned char*)gradient_content1; - grads[0]->content_len = 3 * sizeof(real); - grads[0]->element_type = PADDLE_ELEMENT_TYPE_FLOAT32; - - grads[1] = (paddle_gradient*)malloc(sizeof(paddle_gradient)); - grads[1]->name = names[1]; - grads[1]->content = (unsigned char*)gradinet_content2; - grads[1]->content_len = 3 * sizeof(real); - grads[1]->element_type = PADDLE_ELEMENT_TYPE_INT32; - - printf("print gradient sent to pserver:\n"); - print_parameter(grads[0]); - print_parameter(grads[1]); - - if (paddle_send_grads(c, grads, 2) != 0) { - fail(); } - printf("get updated parameters from pserver:\n"); - // get parameters again by reusing the allocated parameter buffers. - if (paddle_get_params(c, params, 2) != 0) { - fail(); + int i; + for (i = 0; i < 100; i++) { + sendGrads(c); + getParams(c); } - print_parameter(params[0]); - print_parameter(params[1]); - if (paddle_save_model(c, "/tmp/") != 0) { + if (paddle_save_model(c, "/tmp/")) { fail(); } diff --git a/go/pserver/optimizer.go b/go/pserver/optimizer.go index 3ee4c74652..df2219aa84 100644 --- a/go/pserver/optimizer.go +++ b/go/pserver/optimizer.go @@ -1,7 +1,10 @@ package pserver /* +// TODO(zhihong): move compile flags to cmake go_library +#cgo pkg-config: protobuf #cgo CFLAGS: -I ../../ +#cgo LDFLAGS: ../../build/paddle/optimizer/libpaddle_optimizer.a ../../build/proto/libpaddle_proto.a ../../third_party/install/glog/lib/libglog.a ../../third_party/install/gtest/lib/libgtest.a ../../third_party/install/gflags/lib/libgflags.a ../../third_party/install/openblas/lib/libopenblas.a -I/usr/local/lib/ -lprotobuf #include "paddle/optimizer/optimizer.h" */ import "C" From 59b40ecb78781c8ba05973e0f9befc7ed34471e2 Mon Sep 17 00:00:00 2001 From: dzhwinter Date: Sat, 24 Jun 2017 16:20:16 +0800 Subject: [PATCH 06/40] revert parameter with []byte --- go/pserver/optimizer.go | 1 + go/pserver/service.go | 14 +++----------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/go/pserver/optimizer.go b/go/pserver/optimizer.go index df2219aa84..40748d03c1 100644 --- a/go/pserver/optimizer.go +++ b/go/pserver/optimizer.go @@ -5,6 +5,7 @@ package pserver #cgo pkg-config: protobuf #cgo CFLAGS: -I ../../ #cgo LDFLAGS: ../../build/paddle/optimizer/libpaddle_optimizer.a ../../build/proto/libpaddle_proto.a ../../third_party/install/glog/lib/libglog.a ../../third_party/install/gtest/lib/libgtest.a ../../third_party/install/gflags/lib/libgflags.a ../../third_party/install/openblas/lib/libopenblas.a -I/usr/local/lib/ -lprotobuf +#cgo LDFLAGS: /Users/dzh/.go/src/github.com/PaddlePaddle/Paddle/build/lib/libdep.a #include "paddle/optimizer/optimizer.h" */ import "C" diff --git a/go/pserver/service.go b/go/pserver/service.go index c721388b6a..32449f66b7 100644 --- a/go/pserver/service.go +++ b/go/pserver/service.go @@ -28,8 +28,7 @@ const ( type Parameter struct { Name string ElementType ElementType - Content *byte - Length int + Content []byte } // ParameterWithConfig contains the parameter and the configuration. @@ -47,15 +46,13 @@ type Service struct { mu sync.Mutex // injection from parameter to optimizer - optMap map[string]*optimizer - paramMap map[string]Parameter + optMap map[string]*optimizer } // NewService creates a new service. func NewService() *Service { s := &Service{} s.optMap = make(map[string]*optimizer) - s.paramMap = make(map[string]Parameter) s.initialized = make(chan struct{}) return s } @@ -76,7 +73,6 @@ func (s *Service) InitParam(paramWithConfigs ParameterWithConfig, dummy *int) er // TODO(helin): check if paramWithConfigs.Param.Content is // properly memory aligned, if not, make copy to a memory // aligned region. - s.paramMap[paramWithConfigs.Param.Name] = paramWithConfigs.Param s.optMap[paramWithConfigs.Param.Name] = newOptimizer(paramWithConfigs) return nil } @@ -106,13 +102,9 @@ func (s *Service) SendGrad(g Gradient, dummy *int) error { s.mu.Lock() defer s.mu.Unlock() - p, ok := s.paramMap[g.Name] - if !ok { - return fmt.Errorf("parameter: %s does not exist", g.Name) - } o, ok := s.optMap[g.Name] if !ok { - return fmt.Errorf("optimizer: %s does not exist", g.Name) + return fmt.Errorf("parameter: %s does not exist", g.Name) } return o.UpdateParameter(p, g) From 12749ad5526e88d2cc11d62a94065dfcd89d4207 Mon Sep 17 00:00:00 2001 From: dongzhihong Date: Mon, 26 Jun 2017 18:33:26 +0800 Subject: [PATCH 07/40] "fix cmake flags in optimizer" --- go/pserver/cclient/CMakeLists.txt | 2 + .../test/{ => testdata}/optimizer.pb.txt | Bin go/pserver/optimizer.go | 41 ++++++++++++++---- go/pserver/optimizer_test.go | 24 ++++++---- go/pserver/service.go | 11 +++-- go/pserver/service_test.go | 8 +--- paddle/optimizer/CMakeLists.txt | 1 + 7 files changed, 60 insertions(+), 27 deletions(-) rename go/pserver/cclient/test/{ => testdata}/optimizer.pb.txt (100%) diff --git a/go/pserver/cclient/CMakeLists.txt b/go/pserver/cclient/CMakeLists.txt index 65a38ba1ad..b3e79ca661 100644 --- a/go/pserver/cclient/CMakeLists.txt +++ b/go/pserver/cclient/CMakeLists.txt @@ -9,6 +9,8 @@ project(cxx_go C Go) include(golang) include(flags) +cc_library(paddle_go_optimizer DEPS paddle_optimizer paddle_proto glog gflags) + go_library(paddle_pserver_cclient STATIC) if(WITH_TESTING) add_subdirectory(test) diff --git a/go/pserver/cclient/test/optimizer.pb.txt b/go/pserver/cclient/test/testdata/optimizer.pb.txt similarity index 100% rename from go/pserver/cclient/test/optimizer.pb.txt rename to go/pserver/cclient/test/testdata/optimizer.pb.txt diff --git a/go/pserver/optimizer.go b/go/pserver/optimizer.go index 40748d03c1..12bf055b4d 100644 --- a/go/pserver/optimizer.go +++ b/go/pserver/optimizer.go @@ -4,8 +4,7 @@ package pserver // TODO(zhihong): move compile flags to cmake go_library #cgo pkg-config: protobuf #cgo CFLAGS: -I ../../ -#cgo LDFLAGS: ../../build/paddle/optimizer/libpaddle_optimizer.a ../../build/proto/libpaddle_proto.a ../../third_party/install/glog/lib/libglog.a ../../third_party/install/gtest/lib/libgtest.a ../../third_party/install/gflags/lib/libgflags.a ../../third_party/install/openblas/lib/libopenblas.a -I/usr/local/lib/ -lprotobuf -#cgo LDFLAGS: /Users/dzh/.go/src/github.com/PaddlePaddle/Paddle/build/lib/libdep.a +#cgo LDFLAGS: /Users/dzh/.go/src/github.com/PaddlePaddle/Paddle/build/go/pserver/cclient/libpaddle_go_optimizer.a #include "paddle/optimizer/optimizer.h" */ import "C" @@ -18,26 +17,50 @@ var nullPtr = unsafe.Pointer(uintptr(0)) type optimizer struct { opt *C.struct_paddle_optimizer + // used in GetParam, reconstruct Parameter from optimizer + ElementType ElementType +} + +func cArrayToSlice(p unsafe.Pointer, len int) []byte { + if p == nullPtr { + return nil + } + + // create a Go clice backed by a C array, reference: + // https://github.com/golang/go/wiki/cgo#turning-c-arrays-into-go-slices + // + // Go garbage collector will not interact with this data, need + // to be freed properly. + return (*[1 << 30]byte)(p)[:len:len] } func newOptimizer(paramWithConfigs ParameterWithConfig) *optimizer { o := &optimizer{} p := paramWithConfigs.Param c := paramWithConfigs.Config - o.opt = C.paddle_create_optimizer(C.uchar(c), C.int(len(c)), unsafe.Pointer(p.Content), c.int(p.Length), nullPtr, 0) + buffer := &p.Content[0] + o.opt = C.paddle_create_optimizer(C.uchar(c), C.int(len(c)), unsafe.Pointer(buffer), C.int(len(p.Content)), nullPtr, 0) return o } -func (o *optimizer) UpdateParameter(p Parameter, g Gradient) error { - if p.Length != g.Length { - return fmt.Errorf("Name: %s, parameter and gradient length not match, parameter: %d, gradient: %d", p.Name, p.Length, g.Length) +func (o *optimizer) GetWeights(p *Parameter) error { + + var buffer unsafe.Pointer + buffer_len := C.paddle_optimizer_get_weights(unsafe.Pointer(o), &buffer) + if buffer_len == 0 || buffer == nullPtr { + return fmt.Errorf("parameter optimizer error : %s get failed", p.name) } + p.Content = cArrayToSlice(buffer, int(buffer_len)) + return nil +} - if p.ElementType != g.ElementType { - return fmt.Errorf("Name: %s, parameter and gradient element type not match, parameter: %v, gradient: %v", p.Name, p.ElementType, g.ElementType) +func (o *optimizer) UpdateParameter(g Gradient) error { + if o.ElementType != g.ElementType { + return fmt.Errorf("Name: %s, parameter and gradient element type not match, parameter: %v, gradient: %v", g.Name, g.ElementType, g.ElementType) } - r := C.paddle_update_parameter(o.opt, C.paddle_element_type(p.ElementType), unsafe.Pointer(g.Content), C.int(g.Length)) + // FIXME: do we need a copy? discard g.Content by GC ok + r := C.paddle_update_parameter(o.opt, C.paddle_element_type(g.ElementType), unsafe.Pointer(g.Content), C.int(len(g.Content))) if r != 0 { return fmt.Errorf("optimizer update returned error code: %d", r) } diff --git a/go/pserver/optimizer_test.go b/go/pserver/optimizer_test.go index 4930f0d95f..eac744b5cd 100644 --- a/go/pserver/optimizer_test.go +++ b/go/pserver/optimizer_test.go @@ -1,14 +1,22 @@ package pserver -import "testing" +import ( + "io/ioutil" + "testing" +) -func TestSGDCreateRelease(t *testing.T) { - param := pserver.ParameterWithConfig{ - Param : pserver.Parameter{Name : "a", - ElementType: , - Content: , - Length : } +func TestOptimizerCreateRelease(t *testing.T) { + p := Parameter{ + Name: "a", + ElementType: Float32, } - o := newOptimizer(sgd, 1) + p.Content = []byte{0.1, 0.3} + config, err := ioutil.ReadFile("./cclient/test/testdata/optimizer.pb.txt") + + param := ParameterWithConfig{ + Param: p, + Config: config, + } + o := newOptimizer(param) o.Cleanup() } diff --git a/go/pserver/service.go b/go/pserver/service.go index 32449f66b7..d0d57136b5 100644 --- a/go/pserver/service.go +++ b/go/pserver/service.go @@ -107,7 +107,7 @@ func (s *Service) SendGrad(g Gradient, dummy *int) error { return fmt.Errorf("parameter: %s does not exist", g.Name) } - return o.UpdateParameter(p, g) + return o.UpdateParameter(g) } // GetParam gets parameters from the parameter server. @@ -116,7 +116,7 @@ func (s *Service) GetParam(name string, parameter *Parameter) error { s.mu.Lock() defer s.mu.Unlock() - p, ok := s.paramMap[name] + opt, ok := s.optMap[name] if !ok { return fmt.Errorf("parameter: %s does not exist", name) } @@ -128,8 +128,11 @@ func (s *Service) GetParam(name string, parameter *Parameter) error { // nature. This race condition is allowed deliberately // to save the program from making a copy of the // paramter content. - *parameter = p - return nil + p.Name = name + p.ElementType = opt.ElementType + + ok := opt.GetWeights(¶meter) + return ok } // Save tells the parameter server to save parameters. diff --git a/go/pserver/service_test.go b/go/pserver/service_test.go index 1b2626f7db..b746d13e1c 100644 --- a/go/pserver/service_test.go +++ b/go/pserver/service_test.go @@ -13,9 +13,7 @@ func TestFull(t *testing.T) { s := pserver.NewService() var p pserver.Parameter p.Name = "param_a" - ElementValue := []byte{1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0} - p.Content = &ElementValue[0] - p.Length = len(ElementValue) + p.Content = []byte{1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0} p.ElementType = pserver.Int32 err := s.InitParam(pserver.ParameterWithConfig{Param: p, Config: nil}, nil) if err != nil { @@ -24,9 +22,7 @@ func TestFull(t *testing.T) { var p1 pserver.Parameter p1.Name = "param_b" - ElementValue = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - p1.Content = &ElementValue[0] - p1.Length = len(ElementValue) + p1.Content = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} p1.ElementType = pserver.Float32 err = s.InitParam(pserver.ParameterWithConfig{Param: p1, Config: nil}, nil) if err != nil { diff --git a/paddle/optimizer/CMakeLists.txt b/paddle/optimizer/CMakeLists.txt index 4536f62ec7..35f04789cf 100644 --- a/paddle/optimizer/CMakeLists.txt +++ b/paddle/optimizer/CMakeLists.txt @@ -12,6 +12,7 @@ set(OPITMIZER_SRCS add_library(paddle_optimizer STATIC ${OPITMIZER_SRCS}) add_dependencies(paddle_optimizer gen_proto_cpp) + if(WITH_TESTING) add_simple_unittest(serialization_test) add_simple_unittest(parameter_optimizer_test) From c44a94b4dc82db7b4493fe27a60270bee8cf9273 Mon Sep 17 00:00:00 2001 From: dongzhihong Date: Mon, 26 Jun 2017 23:55:30 +0800 Subject: [PATCH 08/40] "fix cmake build flags" --- go/pserver/cclient/cclient.go | 12 +++++++----- go/pserver/cclient/test/test_cclient.c | 8 ++++---- go/pserver/client_test.go | 8 ++------ go/pserver/optimizer.go | 17 +++++++++++------ go/pserver/optimizer_test.go | 8 +++++--- go/pserver/service.go | 8 ++++---- 6 files changed, 33 insertions(+), 28 deletions(-) diff --git a/go/pserver/cclient/cclient.go b/go/pserver/cclient/cclient.go index 6aaaff7409..92a41b7f54 100644 --- a/go/pserver/cclient/cclient.go +++ b/go/pserver/cclient/cclient.go @@ -123,8 +123,9 @@ func paddle_begin_init_params(client C.paddle_pserver_client) C.int { func paddle_init_param(client C.paddle_pserver_client, param C.paddle_parameter, param_config unsafe.Pointer, config_len C.int) C.int { et := pserver.ElementType(param.element_type) name := C.GoString(param.name) + content := cArrayToSlice(unsafe.Pointer(param.content), int(param.content_len)) pc := pserver.ParameterWithConfig{ - Param: pserver.Parameter{Name: name, ElementType: et, Content: param.content, Length: para.content_len}, + Param: pserver.Parameter{Name: name, ElementType: et, Content: content}, Config: cArrayToSlice(param_config, int(config_len)), } c := get(client) @@ -166,7 +167,8 @@ func paddle_send_grads(client C.paddle_pserver_client, grads **C.paddle_gradient grad := *(**C.paddle_gradient)(unsafe.Pointer((uintptr(unsafe.Pointer(grads)) + uintptr(i)*unsafe.Sizeof(*grads)))) et := pserver.ElementType(grad.element_type) name := C.GoString(grad.name) - gs = append(gs, pserver.Gradient{Name: name, ElementType: et, Content: grad.content, Length: grad.content_len}) + content := cArrayToSlice(unsafe.Pointer(grad.content), int(grad.content_len)) + gs = append(gs, pserver.Gradient{Name: name, ElementType: et, Content: content}) } c := get(client) @@ -223,14 +225,14 @@ func paddle_get_params(client C.paddle_pserver_client, dst **C.paddle_parameter, } if unsafe.Pointer(param.content) != nullPtr { - if int(param.content_len) != p.Length { + if int(param.content_len) != len(p.Content) { log.Errorf("the pre-allocated content len does not match parameter content len. Pre-allocated len: %d, returned len: %d", param.content_len, len(p.Content)) return C.PSERVER_ERROR } } - C.memcpy(unsafe.Pointer(param.content), unsafe.Pointer(p.Content), C.size_t(p.Length)) - param.content_len = C.int(p.Length) + C.memcpy(unsafe.Pointer(param.content), unsafe.Pointer(&p.Content[0]), C.size_t(len(p.Content))) + param.content_len = C.int(len(p.Content)) param.element_type = C.paddle_element_type(p.ElementType) } diff --git a/go/pserver/cclient/test/test_cclient.c b/go/pserver/cclient/test/test_cclient.c index 7d26127b60..5bd4913ba3 100644 --- a/go/pserver/cclient/test/test_cclient.c +++ b/go/pserver/cclient/test/test_cclient.c @@ -50,10 +50,10 @@ void getParams(paddle_pserver_client c) { int main() { char addr[] = "localhost:3000"; paddle_pserver_client c = paddle_new_pserver_client(addr, 1); - char config_proto[1024]; + char *config_proto; size_t config_proto_len = 0; ssize_t nread; - FILE *fp = fopen("optimizer.pb.txt", "r"); + FILE *fp = fopen("testdata/optimizer.pb.txt", "r"); if(!fp) { fail(); } while((nread = getline(&config_proto, &config_proto_len, fp)) != -1) { printf("%s", config_proto); @@ -70,7 +70,7 @@ retry: param.name = name_a; param.content = content_a; param.content_len = 2000; - int error = paddle_init_param(c, param, config_proto, config_proto_len); + int error = paddle_init_param(c, param, (void *)config_proto, config_proto_len); if (error != 0) { goto retry; } @@ -79,7 +79,7 @@ retry: param.name = name_b; param.content = content_b; param.content_len = 3000; - error = paddle_init_param(c, param, NULL, 0); + error = paddle_init_param(c, param, (void *)config_proto, config_proto_len); if (error != 0) { goto retry; } diff --git a/go/pserver/client_test.go b/go/pserver/client_test.go index c5d38e4112..d0371a26a1 100644 --- a/go/pserver/client_test.go +++ b/go/pserver/client_test.go @@ -75,9 +75,7 @@ func TestClientFull(t *testing.T) { var p pserver.Parameter p.Name = "p_" + strconv.Itoa(i) p.ElementType = pserver.Float32 - ElementValue := make([]byte, (i+1)*100) - p.Content = &ElementValue[0] - p.Length = len(ElementValue) + p.Content = make([]byte, (i+1)*100) err := c.InitParam(pserver.ParameterWithConfig{Param: p}) if err != nil { t.Fatal(err) @@ -94,9 +92,7 @@ func TestClientFull(t *testing.T) { var g pserver.Gradient g.Name = "p_" + strconv.Itoa(i) g.ElementType = pserver.Float32 - ElementValue := make([]byte, (i+1)*100) - g.Content = &ElementValue[0] - g.Length = len(ElementValue) + g.Content = make([]byte, (i+1)*100) grads = append(grads, g) } diff --git a/go/pserver/optimizer.go b/go/pserver/optimizer.go index 12bf055b4d..4ecae0911c 100644 --- a/go/pserver/optimizer.go +++ b/go/pserver/optimizer.go @@ -4,7 +4,7 @@ package pserver // TODO(zhihong): move compile flags to cmake go_library #cgo pkg-config: protobuf #cgo CFLAGS: -I ../../ -#cgo LDFLAGS: /Users/dzh/.go/src/github.com/PaddlePaddle/Paddle/build/go/pserver/cclient/libpaddle_go_optimizer.a +#cgo LDFLAGS: /Users/dzh/.go/src/github.com/PaddlePaddle/Paddle/build/go/pserver/cclient/libpaddle_go_optimizer.a -lstdc++ #include "paddle/optimizer/optimizer.h" */ import "C" @@ -38,17 +38,20 @@ func newOptimizer(paramWithConfigs ParameterWithConfig) *optimizer { o := &optimizer{} p := paramWithConfigs.Param c := paramWithConfigs.Config - buffer := &p.Content[0] - o.opt = C.paddle_create_optimizer(C.uchar(c), C.int(len(c)), unsafe.Pointer(buffer), C.int(len(p.Content)), nullPtr, 0) + var cbuffer unsafe.Pointer + cbuffer = unsafe.Pointer(&p.Content[0]) + o.opt = C.paddle_create_optimizer((*C.uchar)(&c[0]), C.int(len(c)), + C.paddle_element_type(p.ElementType), cbuffer, C.int(len(p.Content)), + (*C.char)(nullPtr), 0) return o } func (o *optimizer) GetWeights(p *Parameter) error { var buffer unsafe.Pointer - buffer_len := C.paddle_optimizer_get_weights(unsafe.Pointer(o), &buffer) + buffer_len := C.paddle_optimizer_get_weights(o.opt, &buffer) if buffer_len == 0 || buffer == nullPtr { - return fmt.Errorf("parameter optimizer error : %s get failed", p.name) + return fmt.Errorf("parameter optimizer error : %s get failed", p.Name) } p.Content = cArrayToSlice(buffer, int(buffer_len)) return nil @@ -60,7 +63,9 @@ func (o *optimizer) UpdateParameter(g Gradient) error { } // FIXME: do we need a copy? discard g.Content by GC ok - r := C.paddle_update_parameter(o.opt, C.paddle_element_type(g.ElementType), unsafe.Pointer(g.Content), C.int(len(g.Content))) + var cbuffer unsafe.Pointer + cbuffer = unsafe.Pointer(&g.Content[0]) + r := C.paddle_update_parameter(o.opt, C.paddle_element_type(g.ElementType), cbuffer, C.int(len(g.Content))) if r != 0 { return fmt.Errorf("optimizer update returned error code: %d", r) } diff --git a/go/pserver/optimizer_test.go b/go/pserver/optimizer_test.go index eac744b5cd..368047d6f8 100644 --- a/go/pserver/optimizer_test.go +++ b/go/pserver/optimizer_test.go @@ -8,11 +8,13 @@ import ( func TestOptimizerCreateRelease(t *testing.T) { p := Parameter{ Name: "a", - ElementType: Float32, + ElementType: Int32, } - p.Content = []byte{0.1, 0.3} + p.Content = []byte{1, 3} config, err := ioutil.ReadFile("./cclient/test/testdata/optimizer.pb.txt") - + if err != nil { + t.Fatalf("read optimizer proto failed") + } param := ParameterWithConfig{ Param: p, Config: config, diff --git a/go/pserver/service.go b/go/pserver/service.go index d0d57136b5..cdd433260a 100644 --- a/go/pserver/service.go +++ b/go/pserver/service.go @@ -128,11 +128,11 @@ func (s *Service) GetParam(name string, parameter *Parameter) error { // nature. This race condition is allowed deliberately // to save the program from making a copy of the // paramter content. - p.Name = name - p.ElementType = opt.ElementType + parameter.Name = name + parameter.ElementType = opt.ElementType - ok := opt.GetWeights(¶meter) - return ok + err := opt.GetWeights(parameter) + return err } // Save tells the parameter server to save parameters. From cebfae94678b86bbe890077e01bd1a21364b5e2e Mon Sep 17 00:00:00 2001 From: dongzhihong Date: Tue, 27 Jun 2017 01:24:38 +0800 Subject: [PATCH 09/40] "move proto.txt to testdata folder" --- .../cclient/test/dump_optimizer_proto.py | 13 -- .../cclient/test/testdata/optimizer.pb.txt | Bin 51 -> 50 bytes go/pserver/service_test.go | 134 ++++++++++-------- 3 files changed, 72 insertions(+), 75 deletions(-) delete mode 100644 go/pserver/cclient/test/dump_optimizer_proto.py diff --git a/go/pserver/cclient/test/dump_optimizer_proto.py b/go/pserver/cclient/test/dump_optimizer_proto.py deleted file mode 100644 index 2ed4db97f9..0000000000 --- a/go/pserver/cclient/test/dump_optimizer_proto.py +++ /dev/null @@ -1,13 +0,0 @@ -import OptimizerConfig_pb2 as pb - -config = pb.OptimizerConfig() -config.clip_norm = 0.1 -config.lr_policy = pb.OptimizerConfig.Const -config.optimizer = pb.OptimizerConfig.SGD -config.sgd.momentum = 0.0 -config.sgd.decay = 0.0 -config.sgd.nesterov = False -config.const_lr.learning_rate = 0.1 -s = config.SerializeToString() -with open("optimizer.pb.txt", 'w') as f: - f.write(s) diff --git a/go/pserver/cclient/test/testdata/optimizer.pb.txt b/go/pserver/cclient/test/testdata/optimizer.pb.txt index 27c8a584df40ab714edfd730f0ff7b7bd3783964..27dd3bc5f19e2964b4b674cff8860233cbdb445a 100644 GIT binary patch delta 4 LcmXpunqUL~0=NMv delta 6 NcmXpqo?yht1poyT0W$yq diff --git a/go/pserver/service_test.go b/go/pserver/service_test.go index b746d13e1c..a88e2df73a 100644 --- a/go/pserver/service_test.go +++ b/go/pserver/service_test.go @@ -1,7 +1,7 @@ package pserver_test import ( - "reflect" + "io/ioutil" "sync" "testing" "time" @@ -15,73 +15,79 @@ func TestFull(t *testing.T) { p.Name = "param_a" p.Content = []byte{1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0} p.ElementType = pserver.Int32 - err := s.InitParam(pserver.ParameterWithConfig{Param: p, Config: nil}, nil) + config, err := ioutil.ReadFile("./cclient/test/testdata/optimizer.pb.txt") if err != nil { - t.FailNow() - } - - var p1 pserver.Parameter - p1.Name = "param_b" - p1.Content = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - p1.ElementType = pserver.Float32 - err = s.InitParam(pserver.ParameterWithConfig{Param: p1, Config: nil}, nil) - if err != nil { - t.FailNow() - } - - err = s.FinishInitParams(0, nil) - if err != nil { - t.FailNow() - } - - var param pserver.Parameter - err = s.GetParam("param_b", ¶m) - if err != nil { - t.FailNow() - } - - if !reflect.DeepEqual(param, p1) { - t.FailNow() - } - - g1, g2 := pserver.Gradient(p1), pserver.Gradient(p) - err = s.SendGrad(g1, nil) - if err != nil { - t.FailNow() - } - err = s.SendGrad(g2, nil) - - if err != nil { - t.FailNow() - } - - var param1 pserver.Parameter - err = s.GetParam("param_a", ¶m1) - if err != nil { - t.FailNow() - } - - // don't compare content, since it's already changed by - // gradient update. - param1.Content = nil - p.Content = nil - - if !reflect.DeepEqual(param1, p) { - t.FailNow() + t.Fatalf("read optimizer proto failed") } -} -func TestMultipleInit(t *testing.T) { - s := pserver.NewService() - err := s.FinishInitParams(0, nil) + err = s.InitParam(pserver.ParameterWithConfig{Param: p, Config: config}, nil) if err != nil { t.FailNow() } - err = s.FinishInitParams(0, nil) - if err.Error() != pserver.AlreadyInitialized { - t.FailNow() - } + // var p1 pserver.Parameter + // p1.Name = "param_b" + // p1.Content = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + // p1.ElementType = pserver.Float32 + // fmt.Println("paddle passed") + // err = s.InitParam(pserver.ParameterWithConfig{Param: p1, Config: config}, nil) + // if err != nil { + // t.FailNow() + // } + + // err = s.FinishInitParams(0, nil) + // if err != nil { + // t.FailNow() + // } + + // var param pserver.Parameter + // err = s.GetParam("param_b", ¶m) + // if err != nil { + // t.FailNow() + // } + + // if !reflect.DeepEqual(param, p1) { + // t.FailNow() + // } + + // g1, g2 := pserver.Gradient(p1), pserver.Gradient(p) + // err = s.SendGrad(g1, nil) + // if err != nil { + // t.FailNow() + // } + // err = s.SendGrad(g2, nil) + + // if err != nil { + // t.FailNow() + // } + + // var param1 pserver.Parameter + // err = s.GetParam("param_a", ¶m1) + // if err != nil { + // t.FailNow() + // } + + // // don't compare content, since it's already changed by + // // gradient update. + // param1.Content = nil + // p.Content = nil + + // if !reflect.DeepEqual(param1, p) { + // t.FailNow() + // } + // } + + // func TestMultipleInit(t *testing.T) { + // s := pserver.NewService() + // err := s.FinishInitParams(0, nil) + // if err != nil { + // t.FailNow() + // } + + // err = s.FinishInitParams(0, nil) + // if err.Error() != pserver.AlreadyInitialized { + // t.FailNow() + // } } func TestUninitialized(t *testing.T) { @@ -133,7 +139,11 @@ func TestBlockUntilInitialized(t *testing.T) { p.Name = "param_a" p.Content = []byte{1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0} p.ElementType = pserver.Int32 - err := s.InitParam(pserver.ParameterWithConfig{Param: p, Config: nil}, nil) + config, err := ioutil.ReadFile("./cclient/test/testdata/optimizer.pb.txt") + if err != nil { + t.Fatalf("read optimizer proto failed") + } + err = s.InitParam(pserver.ParameterWithConfig{Param: p, Config: config}, nil) if err != nil { t.FailNow() } From e2e0fbd4188fcbcc6bf69d1ef22b3f6f0a927f84 Mon Sep 17 00:00:00 2001 From: Yi Wang Date: Mon, 26 Jun 2017 10:36:49 -0700 Subject: [PATCH 10/40] Add tesnor.h --- paddle/framework/tensor.h | 91 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) create mode 100644 paddle/framework/tensor.h diff --git a/paddle/framework/tensor.h b/paddle/framework/tensor.h new file mode 100644 index 0000000000..a658537430 --- /dev/null +++ b/paddle/framework/tensor.h @@ -0,0 +1,91 @@ +/* + Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +#pragma once + +namespace paddle { +namespace framework { + +class Tensor { + using paddle::platform::Place; + using paddle::platform::get_place; + + public: + explicit Tensor(DDim dims) : dims_(dims), place_(get_place()) {} + explicit Tensor(DDim dims, Place place) : dims_(dims), place_(place) {} + + template + const T* data() const { + PADDLE_ASSERT(holder_ != nullptr); + PADDLE_ASSERT(holder_->Place() == place_); + PADDLE_ASSERT(holder_->Size() >= dims_.product() * sizeof(T)); + return static_cast(holder->Ptr()); + } + + template ::value>::type> + T* mutable_data() { + if (holder_ == nullptr || holder_->Place() != place_ || + holder_->Size() < dims_.product() * sizeof(T)) { + holder_.reset(new PlaceholderImpl(place_, dims.product() * sizeof(T))); + } + return static_cast(holder_->Ptr()); + } + + template ::value>::type> + T* mutable_data(DDim dims) { + dims_ = dims; + return mutable_data(); + } + + template ::value>::type> + T* mutable_data(DDim dims, Place place) { + dims_ = dims; + place_ = place; + return mutable_data(); + } + + private: + // Placeholder hides type T, so it doesn't appear as a template + // parameter of Variable. + struct Placeholder { + virtual ~Placeholder() {} + virtual void* Ptr() const = 0; + virtual Place Place() const = 0; + virtual size_t Size() const = 0; + }; + + template + struct PlaceholderImpl : public Placeholder { + PlaceholderImpl(Place pl, size_t size) + : ptr_(memory::Alloc(pl, size), paddle::memory::Deleter(pl)), + place_(pl), + size_(size) {} + + virtual void* Ptr() const { return static_cast(ptr_.get()); } + virtual size_t Size() const { return size_; } + virtual Place Place() const { return place_; } + + std::unique_ptr ptr_; + Place place_; // record the place of ptr_. + size_t size_; // size of the memory block. + }; + + std::unique_ptr holder_; // holds the memory block if allocated. + DDim dims_; // could be smallers than the holder_->Size(). + paddle::platform::Place place_; +}; + +} // namespace framework +} // namespace paddle From 864386d59682307ba9e033cfce8355029beda9b5 Mon Sep 17 00:00:00 2001 From: dongzhihong Date: Tue, 27 Jun 2017 01:51:10 +0800 Subject: [PATCH 11/40] "change log in optimizer" --- go/pserver/optimizer.go | 4 +- go/pserver/service_test.go | 129 +++++++++++++++++++------------------ 2 files changed, 67 insertions(+), 66 deletions(-) diff --git a/go/pserver/optimizer.go b/go/pserver/optimizer.go index 4ecae0911c..af7faad254 100644 --- a/go/pserver/optimizer.go +++ b/go/pserver/optimizer.go @@ -47,7 +47,7 @@ func newOptimizer(paramWithConfigs ParameterWithConfig) *optimizer { } func (o *optimizer) GetWeights(p *Parameter) error { - + // FIXME: get weigths from optimizer has bug var buffer unsafe.Pointer buffer_len := C.paddle_optimizer_get_weights(o.opt, &buffer) if buffer_len == 0 || buffer == nullPtr { @@ -59,7 +59,7 @@ func (o *optimizer) GetWeights(p *Parameter) error { func (o *optimizer) UpdateParameter(g Gradient) error { if o.ElementType != g.ElementType { - return fmt.Errorf("Name: %s, parameter and gradient element type not match, parameter: %v, gradient: %v", g.Name, g.ElementType, g.ElementType) + return fmt.Errorf("Name: %s, parameter and gradient element type not match, parameter: %v, gradient: %v", g.Name, o.ElementType, g.ElementType) } // FIXME: do we need a copy? discard g.Content by GC ok diff --git a/go/pserver/service_test.go b/go/pserver/service_test.go index a88e2df73a..a09b25dec0 100644 --- a/go/pserver/service_test.go +++ b/go/pserver/service_test.go @@ -2,6 +2,7 @@ package pserver_test import ( "io/ioutil" + "reflect" "sync" "testing" "time" @@ -9,7 +10,7 @@ import ( "github.com/PaddlePaddle/Paddle/go/pserver" ) -func TestFull(t *testing.T) { +func TestNewName(t *testing.T) { s := pserver.NewService() var p pserver.Parameter p.Name = "param_a" @@ -25,69 +26,69 @@ func TestFull(t *testing.T) { t.FailNow() } - // var p1 pserver.Parameter - // p1.Name = "param_b" - // p1.Content = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} - // p1.ElementType = pserver.Float32 - // fmt.Println("paddle passed") - // err = s.InitParam(pserver.ParameterWithConfig{Param: p1, Config: config}, nil) - // if err != nil { - // t.FailNow() - // } - - // err = s.FinishInitParams(0, nil) - // if err != nil { - // t.FailNow() - // } - - // var param pserver.Parameter - // err = s.GetParam("param_b", ¶m) - // if err != nil { - // t.FailNow() - // } - - // if !reflect.DeepEqual(param, p1) { - // t.FailNow() - // } - - // g1, g2 := pserver.Gradient(p1), pserver.Gradient(p) - // err = s.SendGrad(g1, nil) - // if err != nil { - // t.FailNow() - // } - // err = s.SendGrad(g2, nil) - - // if err != nil { - // t.FailNow() - // } - - // var param1 pserver.Parameter - // err = s.GetParam("param_a", ¶m1) - // if err != nil { - // t.FailNow() - // } - - // // don't compare content, since it's already changed by - // // gradient update. - // param1.Content = nil - // p.Content = nil - - // if !reflect.DeepEqual(param1, p) { - // t.FailNow() - // } - // } - - // func TestMultipleInit(t *testing.T) { - // s := pserver.NewService() - // err := s.FinishInitParams(0, nil) - // if err != nil { - // t.FailNow() - // } - - // err = s.FinishInitParams(0, nil) - // if err.Error() != pserver.AlreadyInitialized { - // t.FailNow() - // } + var p1 pserver.Parameter + p1.Name = "param_b" + p1.Content = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} + p1.ElementType = pserver.Float32 + err = s.InitParam(pserver.ParameterWithConfig{Param: p1, Config: config}, nil) + if err != nil { + t.FailNow() + } + + err = s.FinishInitParams(0, nil) + if err != nil { + t.FailNow() + } + + var param pserver.Parameter + err = s.GetParam("param_b", ¶m) + if err != nil { + t.FailNow() + } + + if !reflect.DeepEqual(param, p1) { + t.FailNow() + } + + g1, g2 := pserver.Gradient(p1), pserver.Gradient(p) + + err = s.SendGrad(g1, nil) + if err != nil { + t.FailNow() + } + err = s.SendGrad(g2, nil) + + if err != nil { + t.FailNow() + } + + var param1 pserver.Parameter + err = s.GetParam("param_a", ¶m1) + if err != nil { + t.FailNow() + } + + // don't compare content, since it's already changed by + // gradient update. + param1.Content = nil + p.Content = nil + + if !reflect.DeepEqual(param1, p) { + t.FailNow() + } +} + +func TestMultipleInit(t *testing.T) { + s := pserver.NewService() + err := s.FinishInitParams(0, nil) + if err != nil { + t.FailNow() + } + + err = s.FinishInitParams(0, nil) + if err.Error() != pserver.AlreadyInitialized { + t.FailNow() + } } func TestUninitialized(t *testing.T) { From 242df4f07bda6de94399cc60b31cb22f27a94434 Mon Sep 17 00:00:00 2001 From: dongzhihong Date: Tue, 27 Jun 2017 10:50:13 +0800 Subject: [PATCH 12/40] "copy parameter content with memcpy" --- go/pserver/optimizer.go | 17 ++++++----------- go/pserver/service.go | 8 +++----- 2 files changed, 9 insertions(+), 16 deletions(-) diff --git a/go/pserver/optimizer.go b/go/pserver/optimizer.go index af7faad254..df0ea373bb 100644 --- a/go/pserver/optimizer.go +++ b/go/pserver/optimizer.go @@ -39,22 +39,20 @@ func newOptimizer(paramWithConfigs ParameterWithConfig) *optimizer { p := paramWithConfigs.Param c := paramWithConfigs.Config var cbuffer unsafe.Pointer - cbuffer = unsafe.Pointer(&p.Content[0]) + cbuffer_len := int(unsafe.Sizeof(p.Content[0])) * len(p.Content) + cbuffer = C.malloc(C.size_t(cbuffer_len)) + C.memcpy(cbuffer, unsafe.Pointer(&p.Content[0]), C.size_t(cbuffer_len)) o.opt = C.paddle_create_optimizer((*C.uchar)(&c[0]), C.int(len(c)), C.paddle_element_type(p.ElementType), cbuffer, C.int(len(p.Content)), (*C.char)(nullPtr), 0) return o } -func (o *optimizer) GetWeights(p *Parameter) error { +func (o *optimizer) GetWeights() []byte { // FIXME: get weigths from optimizer has bug var buffer unsafe.Pointer buffer_len := C.paddle_optimizer_get_weights(o.opt, &buffer) - if buffer_len == 0 || buffer == nullPtr { - return fmt.Errorf("parameter optimizer error : %s get failed", p.Name) - } - p.Content = cArrayToSlice(buffer, int(buffer_len)) - return nil + return cArrayToSlice(buffer, int(buffer_len)) } func (o *optimizer) UpdateParameter(g Gradient) error { @@ -62,10 +60,7 @@ func (o *optimizer) UpdateParameter(g Gradient) error { return fmt.Errorf("Name: %s, parameter and gradient element type not match, parameter: %v, gradient: %v", g.Name, o.ElementType, g.ElementType) } - // FIXME: do we need a copy? discard g.Content by GC ok - var cbuffer unsafe.Pointer - cbuffer = unsafe.Pointer(&g.Content[0]) - r := C.paddle_update_parameter(o.opt, C.paddle_element_type(g.ElementType), cbuffer, C.int(len(g.Content))) + r := C.paddle_update_parameter(o.opt, C.paddle_element_type(g.ElementType), unsafe.Pointer(&g.Content[0]), C.int(len(g.Content))) if r != 0 { return fmt.Errorf("optimizer update returned error code: %d", r) } diff --git a/go/pserver/service.go b/go/pserver/service.go index cdd433260a..2ab622d790 100644 --- a/go/pserver/service.go +++ b/go/pserver/service.go @@ -44,8 +44,7 @@ type Gradient Parameter type Service struct { initialized chan struct{} - mu sync.Mutex - // injection from parameter to optimizer + mu sync.Mutex optMap map[string]*optimizer } @@ -130,9 +129,8 @@ func (s *Service) GetParam(name string, parameter *Parameter) error { // paramter content. parameter.Name = name parameter.ElementType = opt.ElementType - - err := opt.GetWeights(parameter) - return err + parameter.Content = opt.GetWeights() + return nil } // Save tells the parameter server to save parameters. From 155e40ef26e337deb82914a7702b669c8d5a5c44 Mon Sep 17 00:00:00 2001 From: wuyi05 Date: Tue, 27 Jun 2017 20:16:53 +0800 Subject: [PATCH 13/40] using glide for go package vendor --- CMakeLists.txt | 4 +- cmake/generic.cmake | 72 +++++++++++++++++++++-------------- go/.gitignore | 1 + go/CMakeLists.txt | 30 +++++++++++++++ go/cmd/master/CMakeLists.txt | 15 ++++++++ go/cmd/pserver/CMakeLists.txt | 15 ++++++++ go/glide.lock | 61 +++++++++++++++++++++++++++++ go/glide.yaml | 12 ++++++ 8 files changed, 179 insertions(+), 31 deletions(-) create mode 100644 go/.gitignore create mode 100644 go/CMakeLists.txt create mode 100644 go/cmd/master/CMakeLists.txt create mode 100644 go/cmd/pserver/CMakeLists.txt create mode 100644 go/glide.lock create mode 100644 go/glide.yaml diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c719d35ec..18e5ebeac2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,7 @@ option(COVERALLS_UPLOAD "Package code coverage data to coveralls" OFF) option(ON_TRAVIS "Exclude special unit test on Travis CI" OFF) option(WITH_C_API "Compile PaddlePaddle with C-API(Prediction)" OFF) option(WITH_GOLANG "Compile PaddlePaddle with GOLANG" OFF) +option(GLIDE_INSTALL "Download and install go dependencies " ON) # CMAKE_BUILD_TYPE if(NOT CMAKE_BUILD_TYPE) @@ -131,8 +132,7 @@ add_subdirectory(paddle) add_subdirectory(python) if(WITH_GOLANG) - #TODO (add go/master/c back when fixed) - add_subdirectory(go/pserver/cclient) + add_subdirectory(go) endif(WITH_GOLANG) if(WITH_DOC) diff --git a/cmake/generic.cmake b/cmake/generic.cmake index 11c1f677ae..0d8bfa17d3 100644 --- a/cmake/generic.cmake +++ b/cmake/generic.cmake @@ -17,7 +17,7 @@ # generic.cmake defines CMakes functions that look like Bazel's # building rules (https://bazel.build/). # -# +# # ------------------------------------------- # C++ CUDA C++ Go # ------------------------------------------- @@ -25,51 +25,51 @@ # cc_binary nv_binary go_binary # cc_test nv_test go_test # ------------------------------------------- -# +# # To build a static library example.a from example.cc using the system # compiler (like GCC): -# +# # cc_library(example SRCS example.cc) -# +# # To build a static library example.a from multiple source files # example{1,2,3}.cc: -# +# # cc_library(example SRCS example1.cc example2.cc example3.cc) -# +# # To build a shared library example.so from example.cc: -# +# # cc_library(example SHARED SRCS example.cc) -# +# # To build a library using Nvidia's NVCC from .cu file(s), use the nv_ # prefixed version: -# +# # nv_library(example SRCS example.cu) -# +# # To specify that a library new_example.a depends on other libraies: -# +# # cc_library(new_example SRCS new_example.cc DEPS example) -# +# # Static libraries can be composed of other static libraries: -# +# # cc_library(composed DEPS dependent1 dependent2 dependent3) -# +# # To build an executable binary file from some source files and # dependent libraries: -# +# # cc_binary(example SRCS main.cc something.cc DEPS example1 example2) -# +# # To build an executable binary file using NVCC, use the nv_ prefixed # version: -# +# # nv_binary(example SRCS main.cc something.cu DEPS example1 example2) -# +# # To build a unit test binary, which is an executable binary with # GoogleTest linked: -# +# # cc_test(example_test SRCS example_test.cc DEPS example) -# +# # To build a unit test binary using NVCC, use the nv_ prefixed version: -# +# # nv_test(example_test SRCS example_test.cu DEPS example) # # It is pretty often that executable and test binaries depend on @@ -256,6 +256,8 @@ endfunction(nv_test) set(GOPATH "${CMAKE_CURRENT_BINARY_DIR}/go") file(MAKE_DIRECTORY ${GOPATH}) set(PADDLE_IN_GOPATH "${GOPATH}/src/github.com/PaddlePaddle/Paddle") +file(MAKE_DIRECTORY "${PADDLE_IN_GOPATH}") +set(PADDLE_GO_SRC "${CMAKE_SOURCE_DIR}/go") function(go_library TARGET_NAME) set(options STATIC static SHARED shared) @@ -280,7 +282,7 @@ function(go_library TARGET_NAME) add_library(${TARGET_NAME} STATIC ${dummyfile}) endif() if(go_library_DEPS) - add_dependencies(${TARGET_NAME} ${go_library_DEPS}) + add_dependencies(${TARGET_NAME} ${go_library_DEPS} paddle_go_path_link) endif(go_library_DEPS) # we need to symlink Paddle directory into GOPATH. If we @@ -289,19 +291,23 @@ function(go_library TARGET_NAME) # without the changes in our current Paddle repo that we # want to build. file(GLOB GO_SOURCE RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "*.go") + string(REPLACE "${PADDLE_GO_SRC}/" "" CMAKE_CURRENT_SOURCE_REL_DIR ${CMAKE_CURRENT_SOURCE_DIR}) add_custom_command(TARGET ${TARGET_NAME} POST_BUILD COMMAND rm "${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}" # Symlink Paddle directory into GOPATH COMMAND mkdir -p ${PADDLE_IN_GOPATH} - COMMAND rm -rf ${PADDLE_IN_GOPATH} + COMMAND rm -rf ${PADDLE_IN_GOPATH} COMMAND ln -sf ${CMAKE_SOURCE_DIR} ${PADDLE_IN_GOPATH} - # Automatically get all dependencies specified in the source code - COMMAND env GOPATH=${GOPATH} ${CMAKE_Go_COMPILER} get -d ./... + WORKING_DIRECTORY ${PADDLE_GO_SRC}) + add_custom_command(TARGET ${TARGET_NAME} POST_BUILD + # Automatically get all dependencies specified in the source code + #COMMAND env GOPATH=${GOPATH} ${CMAKE_Go_COMPILER} get -d ./... # Golang build source code COMMAND env GOPATH=${GOPATH} ${CMAKE_Go_COMPILER} build ${BUILD_MODE} -o "${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}" - ${GO_SOURCE} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + "./${CMAKE_CURRENT_SOURCE_REL_DIR}/${GO_SOURCE}" + # must run under GOPATH + WORKING_DIRECTORY "${PADDLE_IN_GOPATH}/go") endfunction(go_library) function(go_binary TARGET_NAME) @@ -309,12 +315,20 @@ function(go_binary TARGET_NAME) set(oneValueArgs "") set(multiValueArgs SRCS DEPS) cmake_parse_arguments(go_binary "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + string(REPLACE "${PADDLE_GO_SRC}/" "" CMAKE_CURRENT_SOURCE_REL_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + add_custom_command(OUTPUT ${TARGET_NAME}_link + # Symlink Paddle directory into GOPATH + COMMAND mkdir -p ${PADDLE_IN_GOPATH} + COMMAND rm -rf ${PADDLE_IN_GOPATH} + COMMAND ln -sf ${CMAKE_SOURCE_DIR} ${PADDLE_IN_GOPATH} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + add_custom_command(OUTPUT ${TARGET_NAME}_timestamp COMMAND env GOPATH=${GOPATH} ${CMAKE_Go_COMPILER} build -o "${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}" ${go_library_SRCS} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) - add_custom_target(${TARGET_NAME} ALL DEPENDS ${TARGET_NAME}_timestamp ${go_binary_DEPS}) + WORKING_DIRECTORY "${PADDLE_IN_GOPATH}/go/${CMAKE_CURRENT_SOURCE_REL_DIR}") + add_custom_target(${TARGET_NAME} ALL DEPENDS ${TARGET_NAME}_link ${TARGET_NAME}_timestamp ${go_binary_DEPS}) install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME} DESTINATION bin) endfunction(go_binary) diff --git a/go/.gitignore b/go/.gitignore new file mode 100644 index 0000000000..48b8bf9072 --- /dev/null +++ b/go/.gitignore @@ -0,0 +1 @@ +vendor/ diff --git a/go/CMakeLists.txt b/go/CMakeLists.txt new file mode 100644 index 0000000000..fb7bd14b89 --- /dev/null +++ b/go/CMakeLists.txt @@ -0,0 +1,30 @@ +# Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# FIXME(typhoonzero): Download glide into cmake build temprary GOPATH +if(EXISTS $ENV{GOPATH}/bin/glide) + set(GLIDE "$ENV{GOPATH}/bin/glide") +else() + message(FATAL_ERROR "no glide executeble found: $ENV{GOPATH}/bin/glide") +endif() + +set(PADDLE_GO_PATH "${CMAKE_SOURCE_DIR}/go") + +if (GLIDE_INSTALL) + message(STATUS ${PADDLE_GO_PATH}) + execute_process(COMMAND ${GLIDE} install WORKING_DIRECTORY ${PADDLE_GO_PATH}) +endif() + +add_subdirectory(go/pserver/cclient) +#TODO (add go/master/c back when fixed) diff --git a/go/cmd/master/CMakeLists.txt b/go/cmd/master/CMakeLists.txt new file mode 100644 index 0000000000..a604272a08 --- /dev/null +++ b/go/cmd/master/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +go_binary(master) diff --git a/go/cmd/pserver/CMakeLists.txt b/go/cmd/pserver/CMakeLists.txt new file mode 100644 index 0000000000..ad7da915e7 --- /dev/null +++ b/go/cmd/pserver/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +go_binary(pserver) diff --git a/go/glide.lock b/go/glide.lock new file mode 100644 index 0000000000..190a222338 --- /dev/null +++ b/go/glide.lock @@ -0,0 +1,61 @@ +hash: b8f18ce6784bd3fadd9fed0b8443e7b658234ea785ae1f220723ae2c1f652aa7 +updated: 2017-06-27T14:05:48.925262819+08:00 +imports: +- name: github.com/coreos/etcd + version: 61fc123e7a8b14a0a258aa3f5c4159861b1ec2e7 + subpackages: + - auth/authpb + - clientv3 + - clientv3/concurrency + - etcdserver/api/v3rpc/rpctypes + - etcdserver/etcdserverpb + - mvcc/mvccpb +- name: github.com/golang/protobuf + version: 4bd1920723d7b7c925de087aa32e2187708897f7 + subpackages: + - jsonpb + - proto +- name: github.com/golang/snappy + version: 553a641470496b2327abcac10b36396bd98e45c9 +- name: github.com/namsral/flag + version: 71ceffbeb0ba60fccc853971bb3ed4d7d90bfd04 +- name: github.com/PaddlePaddle/recordio + version: edfb82af0739c84f241c87390ec5649c7b28c129 +- name: github.com/sirupsen/logrus + version: 202f25545ea4cf9b191ff7f846df5d87c9382c2b +- name: golang.org/x/net + version: c8c74377599bd978aee1cf3b9b63a8634051cec2 + subpackages: + - context + - http2 + - http2/hpack + - idna + - internal/timeseries + - lex/httplex + - trace +- name: golang.org/x/sys + version: f7928cfef4d09d1b080aa2b6fd3ca9ba1567c733 + subpackages: + - unix +- name: golang.org/x/text + version: 4e9ab9ee170f2a39bd66c92b3e0a47ff47a4bc77 + subpackages: + - secure/bidirule + - transform + - unicode/bidi + - unicode/norm +- name: google.golang.org/grpc + version: 8050b9cbc271307e5a716a9d782803d09b0d6f2d + subpackages: + - codes + - credentials + - grpclog + - internal + - keepalive + - metadata + - naming + - peer + - stats + - tap + - transport +testImports: [] diff --git a/go/glide.yaml b/go/glide.yaml new file mode 100644 index 0000000000..05c5d15ca2 --- /dev/null +++ b/go/glide.yaml @@ -0,0 +1,12 @@ +package: github.com/PaddlePaddle/Paddle/go +import: +- package: github.com/PaddlePaddle/recordio +- package: github.com/coreos/etcd + version: ^3.2.1 + subpackages: + - clientv3 + - clientv3/concurrency +- package: github.com/namsral/flag + version: ^1.7.4-pre +- package: github.com/sirupsen/logrus + version: ^1.0.0 From 7f03817806591ba508652263b2a83788d6baf397 Mon Sep 17 00:00:00 2001 From: dongzhihong Date: Wed, 28 Jun 2017 00:11:31 +0800 Subject: [PATCH 14/40] "cgo ldflags config" --- go/pserver/optimizer.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/go/pserver/optimizer.go b/go/pserver/optimizer.go index df0ea373bb..5824a529fc 100644 --- a/go/pserver/optimizer.go +++ b/go/pserver/optimizer.go @@ -1,13 +1,14 @@ package pserver -/* -// TODO(zhihong): move compile flags to cmake go_library -#cgo pkg-config: protobuf -#cgo CFLAGS: -I ../../ -#cgo LDFLAGS: /Users/dzh/.go/src/github.com/PaddlePaddle/Paddle/build/go/pserver/cclient/libpaddle_go_optimizer.a -lstdc++ -#include "paddle/optimizer/optimizer.h" -*/ +// #cgo pkg-config: protobuf +// #cgo CFLAGS: -I ../../ +// FIXME: ldflags contain "build" path +// #cgo LDFLAGS: ../../build/go/pserver/cclient/libpaddle_go_optimizer.a -lstdc++ +// #include "paddle/optimizer/optimizer.h" +// #include +// #include import "C" + import ( "fmt" "unsafe" From 80d915049f62630bb902c0e62ffc4a3dffef49de Mon Sep 17 00:00:00 2001 From: dongzhihong Date: Wed, 28 Jun 2017 00:29:05 +0800 Subject: [PATCH 15/40] " add elementtype in optimizer" --- go/pserver/optimizer.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/go/pserver/optimizer.go b/go/pserver/optimizer.go index 5824a529fc..4872139c56 100644 --- a/go/pserver/optimizer.go +++ b/go/pserver/optimizer.go @@ -2,7 +2,7 @@ package pserver // #cgo pkg-config: protobuf // #cgo CFLAGS: -I ../../ -// FIXME: ldflags contain "build" path +// //FIXME: ldflags contain "build" path // #cgo LDFLAGS: ../../build/go/pserver/cclient/libpaddle_go_optimizer.a -lstdc++ // #include "paddle/optimizer/optimizer.h" // #include @@ -37,6 +37,7 @@ func cArrayToSlice(p unsafe.Pointer, len int) []byte { func newOptimizer(paramWithConfigs ParameterWithConfig) *optimizer { o := &optimizer{} + o.ElementType = paramWithConfigs.Param.ElementType p := paramWithConfigs.Param c := paramWithConfigs.Config var cbuffer unsafe.Pointer From b49c9baa3501210b5fe859723174570381a6dd60 Mon Sep 17 00:00:00 2001 From: dongzhihong Date: Wed, 28 Jun 2017 00:32:34 +0800 Subject: [PATCH 16/40] "remove unuse comment" --- go/pserver/optimizer.go | 1 - 1 file changed, 1 deletion(-) diff --git a/go/pserver/optimizer.go b/go/pserver/optimizer.go index 4872139c56..5575fab3c0 100644 --- a/go/pserver/optimizer.go +++ b/go/pserver/optimizer.go @@ -51,7 +51,6 @@ func newOptimizer(paramWithConfigs ParameterWithConfig) *optimizer { } func (o *optimizer) GetWeights() []byte { - // FIXME: get weigths from optimizer has bug var buffer unsafe.Pointer buffer_len := C.paddle_optimizer_get_weights(o.opt, &buffer) return cArrayToSlice(buffer, int(buffer_len)) From a2fabcc1144c480d0f972026194693b80ca6c397 Mon Sep 17 00:00:00 2001 From: dongzhihong Date: Wed, 28 Jun 2017 00:57:52 +0800 Subject: [PATCH 17/40] "fix client test" --- go/pserver/client_test.go | 9 +++++++-- go/pserver/optimizer.go | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/go/pserver/client_test.go b/go/pserver/client_test.go index d0371a26a1..d746bf3f26 100644 --- a/go/pserver/client_test.go +++ b/go/pserver/client_test.go @@ -1,6 +1,7 @@ package pserver_test import ( + "io/ioutil" "net" "net/http" "net/rpc" @@ -71,18 +72,22 @@ func TestClientFull(t *testing.T) { } const numParameter = 100 + config, err := ioutil.ReadFile("./cclient/test/testdata/optimizer.pb.txt") + if err != nil { + t.Fatalf("read optimizer proto failed") + } for i := 0; i < numParameter; i++ { var p pserver.Parameter p.Name = "p_" + strconv.Itoa(i) p.ElementType = pserver.Float32 p.Content = make([]byte, (i+1)*100) - err := c.InitParam(pserver.ParameterWithConfig{Param: p}) + err := c.InitParam(pserver.ParameterWithConfig{Param: p, Config: config}) if err != nil { t.Fatal(err) } } - err := c.FinishInitParams() + err = c.FinishInitParams() if err != nil { t.Fatal(err) } diff --git a/go/pserver/optimizer.go b/go/pserver/optimizer.go index 5575fab3c0..9cb2801f30 100644 --- a/go/pserver/optimizer.go +++ b/go/pserver/optimizer.go @@ -61,6 +61,7 @@ func (o *optimizer) UpdateParameter(g Gradient) error { return fmt.Errorf("Name: %s, parameter and gradient element type not match, parameter: %v, gradient: %v", g.Name, o.ElementType, g.ElementType) } + fmt.Println(g) r := C.paddle_update_parameter(o.opt, C.paddle_element_type(g.ElementType), unsafe.Pointer(&g.Content[0]), C.int(len(g.Content))) if r != 0 { return fmt.Errorf("optimizer update returned error code: %d", r) From 2c188a20de53741e6f965738636eb7d6f797a821 Mon Sep 17 00:00:00 2001 From: Yi Wang Date: Tue, 27 Jun 2017 12:00:41 -0700 Subject: [PATCH 18/40] Follow QingQing's suggestion --- paddle/framework/tensor.h | 31 ++++++++----------------------- 1 file changed, 8 insertions(+), 23 deletions(-) diff --git a/paddle/framework/tensor.h b/paddle/framework/tensor.h index a658537430..8962b76a12 100644 --- a/paddle/framework/tensor.h +++ b/paddle/framework/tensor.h @@ -20,23 +20,19 @@ class Tensor { using paddle::platform::get_place; public: - explicit Tensor(DDim dims) : dims_(dims), place_(get_place()) {} - explicit Tensor(DDim dims, Place place) : dims_(dims), place_(place) {} - template const T* data() const { - PADDLE_ASSERT(holder_ != nullptr); - PADDLE_ASSERT(holder_->Place() == place_); - PADDLE_ASSERT(holder_->Size() >= dims_.product() * sizeof(T)); + PADDLE_ASSERT(holder_ != nullptr, + "Tensor::data must be called after Tensor::mutable_data"); return static_cast(holder->Ptr()); } template ::value>::type> - T* mutable_data() { - if (holder_ == nullptr || holder_->Place() != place_ || - holder_->Size() < dims_.product() * sizeof(T)) { - holder_.reset(new PlaceholderImpl(place_, dims.product() * sizeof(T))); + T* mutable_data(DDim dims, Place place) { + if (holder_ == nullptr || holder_->Place() != place || + holder_->Size() < dims.product() * sizeof(T)) { + holder_.reset(new PlaceholderImpl(place, dims.product() * sizeof(T))); } return static_cast(holder_->Ptr()); } @@ -44,16 +40,7 @@ class Tensor { template ::value>::type> T* mutable_data(DDim dims) { - dims_ = dims; - return mutable_data(); - } - - template ::value>::type> - T* mutable_data(DDim dims, Place place) { - dims_ = dims; - place_ = place; - return mutable_data(); + return mutable_data(dims, paddle::platform::get_place()); } private: @@ -69,7 +56,7 @@ class Tensor { template struct PlaceholderImpl : public Placeholder { PlaceholderImpl(Place pl, size_t size) - : ptr_(memory::Alloc(pl, size), paddle::memory::Deleter(pl)), + : ptr_(paddle::memory::Alloc(pl, size), paddle::memory::Deleter(pl)), place_(pl), size_(size) {} @@ -83,8 +70,6 @@ class Tensor { }; std::unique_ptr holder_; // holds the memory block if allocated. - DDim dims_; // could be smallers than the holder_->Size(). - paddle::platform::Place place_; }; } // namespace framework From c263c21f7e0feebca20ab33cd606330de81e9aee Mon Sep 17 00:00:00 2001 From: Yi Wang Date: Tue, 27 Jun 2017 17:35:27 -0700 Subject: [PATCH 19/40] Update copyright informaiton --- paddle/framework/tensor.h | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/paddle/framework/tensor.h b/paddle/framework/tensor.h index 8962b76a12..067f2a8526 100644 --- a/paddle/framework/tensor.h +++ b/paddle/framework/tensor.h @@ -1,15 +1,17 @@ -/* - Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ +/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. */ + #pragma once namespace paddle { From 05ddf23e1dd89dee9c1eeca188f782f38992ce60 Mon Sep 17 00:00:00 2001 From: dongzhihong Date: Wed, 28 Jun 2017 11:43:57 +0800 Subject: [PATCH 20/40] "add log of create optimizer" --- go/pserver/optimizer.go | 24 ++++++++++++++---------- go/pserver/service.go | 2 +- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/go/pserver/optimizer.go b/go/pserver/optimizer.go index 9cb2801f30..46e614d3a1 100644 --- a/go/pserver/optimizer.go +++ b/go/pserver/optimizer.go @@ -12,14 +12,15 @@ import "C" import ( "fmt" "unsafe" + + log "github.com/sirupsen/logrus" ) var nullPtr = unsafe.Pointer(uintptr(0)) type optimizer struct { - opt *C.struct_paddle_optimizer - // used in GetParam, reconstruct Parameter from optimizer - ElementType ElementType + opt *C.struct_paddle_optimizer + elementType ElementType } func cArrayToSlice(p unsafe.Pointer, len int) []byte { @@ -37,13 +38,17 @@ func cArrayToSlice(p unsafe.Pointer, len int) []byte { func newOptimizer(paramWithConfigs ParameterWithConfig) *optimizer { o := &optimizer{} - o.ElementType = paramWithConfigs.Param.ElementType + o.elementType = paramWithConfigs.Param.ElementType p := paramWithConfigs.Param c := paramWithConfigs.Config + log.WithFields(log.Fields{ + "ElementType": p.ElementType, + "ParamSize": len(p.Content), + "ConfigSize": len(c), + }).Info("New Optimizer Created with config:") var cbuffer unsafe.Pointer - cbuffer_len := int(unsafe.Sizeof(p.Content[0])) * len(p.Content) - cbuffer = C.malloc(C.size_t(cbuffer_len)) - C.memcpy(cbuffer, unsafe.Pointer(&p.Content[0]), C.size_t(cbuffer_len)) + cbuffer = C.malloc(C.size_t(len(p.Content))) + C.memcpy(cbuffer, unsafe.Pointer(&p.Content[0]), C.size_t(len(p.Content))) o.opt = C.paddle_create_optimizer((*C.uchar)(&c[0]), C.int(len(c)), C.paddle_element_type(p.ElementType), cbuffer, C.int(len(p.Content)), (*C.char)(nullPtr), 0) @@ -57,11 +62,10 @@ func (o *optimizer) GetWeights() []byte { } func (o *optimizer) UpdateParameter(g Gradient) error { - if o.ElementType != g.ElementType { - return fmt.Errorf("Name: %s, parameter and gradient element type not match, parameter: %v, gradient: %v", g.Name, o.ElementType, g.ElementType) + if o.elementType != g.ElementType { + return fmt.Errorf("Name: %s, parameter and gradient element type not match, parameter: %v, gradient: %v", g.Name, o.elementType, g.ElementType) } - fmt.Println(g) r := C.paddle_update_parameter(o.opt, C.paddle_element_type(g.ElementType), unsafe.Pointer(&g.Content[0]), C.int(len(g.Content))) if r != 0 { return fmt.Errorf("optimizer update returned error code: %d", r) diff --git a/go/pserver/service.go b/go/pserver/service.go index 2ab622d790..555d379bcb 100644 --- a/go/pserver/service.go +++ b/go/pserver/service.go @@ -128,7 +128,7 @@ func (s *Service) GetParam(name string, parameter *Parameter) error { // to save the program from making a copy of the // paramter content. parameter.Name = name - parameter.ElementType = opt.ElementType + parameter.ElementType = opt.elementType parameter.Content = opt.GetWeights() return nil } From 42dcffc29c9a6d0cbd27cc5d32d10c53400d287d Mon Sep 17 00:00:00 2001 From: dongzhihong Date: Wed, 28 Jun 2017 17:19:31 +0800 Subject: [PATCH 21/40] "add optimizer full test" --- go/pserver/service_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/pserver/service_test.go b/go/pserver/service_test.go index a09b25dec0..57397fe586 100644 --- a/go/pserver/service_test.go +++ b/go/pserver/service_test.go @@ -10,7 +10,7 @@ import ( "github.com/PaddlePaddle/Paddle/go/pserver" ) -func TestNewName(t *testing.T) { +func TestServiceFull(t *testing.T) { s := pserver.NewService() var p pserver.Parameter p.Name = "param_a" From 6bb84b963d421394c04c43c202ccea874bdb53f6 Mon Sep 17 00:00:00 2001 From: dongzhihong Date: Wed, 28 Jun 2017 17:20:55 +0800 Subject: [PATCH 22/40] "remove unused debug info" --- go/pserver/optimizer_test.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/go/pserver/optimizer_test.go b/go/pserver/optimizer_test.go index 368047d6f8..49d9df5898 100644 --- a/go/pserver/optimizer_test.go +++ b/go/pserver/optimizer_test.go @@ -2,6 +2,7 @@ package pserver import ( "io/ioutil" + "reflect" "testing" ) @@ -22,3 +23,26 @@ func TestOptimizerCreateRelease(t *testing.T) { o := newOptimizer(param) o.Cleanup() } + +func TestOptimizerFull(t *testing.T) { + p := Parameter{ + Name: "a", + ElementType: Float32, + } + p.Content = []byte{1, 3} + config, err := ioutil.ReadFile("./cclient/test/testdata/optimizer.pb.txt") + if err != nil { + t.Fatalf("read optimizer proto failed") + } + param := ParameterWithConfig{ + Param: p, + Config: config, + } + o := newOptimizer(param) + g := Gradient(p) + if !reflect.DeepEqual(p.Content, o.GetWeights()) { + t.FailNow() + } + o.UpdateParameter(g) + o.Cleanup() +} From f712b027a75fbfdf2456c42d66010dc3c5f100f7 Mon Sep 17 00:00:00 2001 From: dongzhihong Date: Fri, 30 Jun 2017 18:40:32 +0800 Subject: [PATCH 23/40] "fix protobuf depend" --- go/pserver/cclient/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/pserver/cclient/CMakeLists.txt b/go/pserver/cclient/CMakeLists.txt index e12cf88068..7fe74c62f1 100644 --- a/go/pserver/cclient/CMakeLists.txt +++ b/go/pserver/cclient/CMakeLists.txt @@ -1,4 +1,4 @@ -cc_library(paddle_go_optimizer DEPS paddle_optimizer paddle_proto glog gflags) +cc_library(paddle_go_optimizer DEPS paddle_optimizer paddle_proto glog gflags protobuf) go_library(paddle_pserver_cclient STATIC) if(WITH_TESTING) add_subdirectory(test) From a7f9625391f95bbd44b13a946d595b88e1464d42 Mon Sep 17 00:00:00 2001 From: "yi.wu" Date: Sat, 1 Jul 2017 18:38:19 +0800 Subject: [PATCH 24/40] update --- paddle/scripts/docker/build.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/paddle/scripts/docker/build.sh b/paddle/scripts/docker/build.sh index 54e80fee34..a182e5f4ae 100644 --- a/paddle/scripts/docker/build.sh +++ b/paddle/scripts/docker/build.sh @@ -50,7 +50,6 @@ cmake .. \ -DWITH_STYLE_CHECK=${WITH_STYLE_CHECK:-OFF} \ -DWITH_TESTING=${WITH_TESTING:-OFF} \ -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -exit 1 cat < Date: Sun, 2 Jul 2017 16:14:18 +0800 Subject: [PATCH 25/40] "polish cgo link option" --- go/pserver/optimizer.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/go/pserver/optimizer.go b/go/pserver/optimizer.go index 46e614d3a1..070896f7c7 100644 --- a/go/pserver/optimizer.go +++ b/go/pserver/optimizer.go @@ -1,6 +1,5 @@ package pserver -// #cgo pkg-config: protobuf // #cgo CFLAGS: -I ../../ // //FIXME: ldflags contain "build" path // #cgo LDFLAGS: ../../build/go/pserver/cclient/libpaddle_go_optimizer.a -lstdc++ @@ -50,7 +49,7 @@ func newOptimizer(paramWithConfigs ParameterWithConfig) *optimizer { cbuffer = C.malloc(C.size_t(len(p.Content))) C.memcpy(cbuffer, unsafe.Pointer(&p.Content[0]), C.size_t(len(p.Content))) o.opt = C.paddle_create_optimizer((*C.uchar)(&c[0]), C.int(len(c)), - C.paddle_element_type(p.ElementType), cbuffer, C.int(len(p.Content)), + C.paddle_element_type(p.ElementType), cbuffer, C.int(len(p.Content)*C.sizeof_float), (*C.char)(nullPtr), 0) return o } From e2c842353739ce3577b0f79267976928a44deb55 Mon Sep 17 00:00:00 2001 From: fengjiayi Date: Sun, 2 Jul 2017 17:06:28 +0800 Subject: [PATCH 26/40] add simple_op_design.md --- doc/design/simple_op_design.md | 273 +++++++++++++++++++++++++++++++++ 1 file changed, 273 insertions(+) create mode 100644 doc/design/simple_op_design.md diff --git a/doc/design/simple_op_design.md b/doc/design/simple_op_design.md new file mode 100644 index 0000000000..93c0f68ca9 --- /dev/null +++ b/doc/design/simple_op_design.md @@ -0,0 +1,273 @@ +## Interaction between C++ and Python + +Users employ API in Python to describe their own network, however, the network construction actually happens in C++. so Protobuf is introduced to send the message between Python and C++. + +The Interaction between Python and C++ can be simplified as two steps: + +1. C++ tells Python how many Ops there are, and what parameter do users need to offer to initialize a new Op. Python then builds API for each Op at compile time. + +2. Users invoke APIs built by Python and provide necessary parameters. These parameters will be sent to C++ fo finish Op construction task. + +### Message form C++ to Python + +We define a Protobuf message class `OpProto` to hold message needed in the first step. What should an `OpProto` contain? This question is equivalent to “What message do we need to offer, to build a Python API which is legal and user oriented and can use to describe a whole Op.” + +Following message are necessary: + +1. Op's name, and its simple comment. +2. Input and output variable number; each variable's name, type, and comment. +3. Op's attributes; each attribute includes name, type, comment, **default value** and **value range**. + +So `OpProto` can be defined as follows: + +```proto +enum AttrType { + INT = 1; + FLOAT = 2; + STRING = 3; + INTS = 4; + FLOATS = 5; + STRINGS = 6; +}; + +message AttrValue { + AttrType type = 1; + optional int iv = 2; + optional float fv = 3; + optional string sv = 4; + repeated int ivs = 5; + repeated float fvs = 6; + repeated string svs = 7; +}; + +message AttrProto { + required string name = 1; + required string comment = 2; + optional AttrValue default = 3; + optional AttrValue max = 4; + optional AttrValue min = 5; + required AttrType type = 6; +}; + +message VarProto { + required string name = 1; + required string comment = 2; +}; + +message OpProto { + repeated VarProto inputs = 1; + repeated VarProto outputs = 2; + repeated AttrProto attrs = 3; + required string type = 4; + required string comment = 5; +}; +``` + +The default value and value range didn't appear in out previous design. By adding these two fields, we are able to check attribute validity in Python and find out possible error as soon as possible. What's more, by providing the message about default value and value range to Python docstring, it helps to automatically generate more comprehensive documents. + +### Message from Python to C++ + +To hold message needed in the above second step, we define Protobuf message class `OpDesc`. It is used to hold user-specified parameters in Op describing. + +```proto +message OpDesc { + required string type = 1; + repeated string inputs = 2; + repeated string outputs = 3; + map attrs = 4; +}; +``` + +## OpProto Register + +Every Op has its own `OpProto`. For using convenience, we need to register them and record all their messages. For each `Op` class, we define a corresponding `OpMaker` class, in whose constructor we implement the `OpProto`'s building process. `OpMaker`'s constructor will be invoked by another function `OpRegistry::RegisterOp()`. + +```cpp +class OpProtoMaker { +public: + OpProtoMaker(OpProto* proto): proto_(proto) {} +protected: + OpProto* proto_; + void AddInput(const std::string& name, const std::string& desc) {...} + void AddAttr(const std::string& name, const std::string& desc, TypeId type) {...} + void AddComment(const std::string& comment) { ... } +}; + +class OpRegistry { +public: + using OpCreator = std::function; + + template + static void RegisterOp(const std::string& name) { + gCreators_[name] = [](const OpDesc& desc) { + return new OpType(desc); + }; + OpProto& opProto = gProtos_[name]; + OpMaker()(&opProto); + } + + static map gCreators_; + static map gProtos_; +}; + +template +class OpRegister { + public: + OpRegister(std::string type) { + OpRegistry::RegisterOp(type); + } +}; + +#define REGISTER_OP(op_class, op_maker_class, type_name) \ + class op_class##Register { \ + private: \ + const static OpRegister<#op_class, #op_maker_class> reg; \ + }; \ + const Register op_class##Register::reg(#type_name); + +class CosineOp { +// ... +} + +struct CosineOpProtoMaker : public OpProtoMaker { + CosineOpProtoMaker(OpProto* proto) : OpProtoMaker(proto) { + AddInput("input", "input of cosine op"); + AddAttr("scale", "scale of cosine op", float).Default(1.0).LargerThan(0.0); + AddType("cos"); + AddComment("This is cos op"); + } +} + +REGISTER_OP(CosineOp, CosineOpProtoMaker, cos); +``` + +In `REGISTER_OP(CosineOp, CosineOpProtoMaker, cos)`, we register not only `CosineOp` but also `CosineOpProto`. As fields of `CosineOpProto`, the default value and value range of `scale` are also registered here. + +## Python API + +Python APIs are divided into two types, high-level API and low-level API. + +### High-Level API + +High-level API is called by users directly, so it should keep its style consistent with existing V2 APIs. + +Here is a sample about how a define a fc layer: + +```python +hd = fc_layer(input=data, size=56, with_bias=True, activation="sigmoid"); +``` + +`hd` is the output of `fc_layer` and it's a `variable`. It can be further sent into other layers as input. + +The definition of `fc_layer()`: + +```python +def fc_layer(input, size, with_bias, activation): + attr_map = {"size":size} + check_attrs(attr_map) + w = make_variable('w') + if with_bias: + b = make_variable('b') + else: + b = None + fc_output = make_variable('fc_output'); + fc_op(input, w, b, fc_output, attr_map) + act_output = make_variable('sigmod_output'); + if activation == "sigmod": + sigmod_op(fc_output, act_output); + elif: + # ... + return act_output; +``` + +### Low Leval API + +In above sample, `fc_op` and `sigmod_op` are low-level API. They build `OpDesc` and invoke corresponding C++ code. + +*TODO* + +## Op and Kernal + +After completely defined, an Op will be run in a network. However, Op's computing method may differ on different devices. One solution is that write an `Op`'s member function `Op::run()`, which contains computing methods of all possible devices. That may be a bad idea because we have to change all `Op`'s code to add a new device. + +Another choice is adding a concept named `kernal`. A `Kernal` describes an op's computing process on a certain device. After stripping `Variable` and `kernal`, `Op` becomes a pure conceptual class, which holds neither data nor detailed computing process. + +```cpp +class KernalBase { +public: + virtual void RunOnDevice(std::vector input_vars, + std::vector input_vars, + const OpAttrs* attrs) = 0; +}; + +template +class CosineKernal : public KernalBase { +public: + virtual void RunOnDevice(std::vector input_vars, + std::vector input_vars, + const OpAttrs* attrs) { + // no implementation + } +}; + +template <> +class CosineKernal : public KernalBase { +public: + virtual void RunOnDevice(std::vector input_vars, + std::vector input_vars, + const OpAttrs* attrs) { + CosineOpAttrs* cosine_attrs = static_cast(attrs); + // computing code + // ... + } +}; + +struct OpAttrs {...}; + +class Op { + public: + std::string get_kernal_name() { + return kernel_name_; + } + const vector& get_input_names() { + return input_names_; + } + const vector& get_output_names() { + return output_names_; + } + // ... + private: + std::vector input_names_; + std::vector output_names_; + std::string kernal_name_; + +} + +struct CosineOpAttrs : public OpAttrs { + float scale_; +} + +class CosineOp : public Op { + public: + const CosineOpAtrrs* get_attrs() { + return &attrs; + } + + private: + CosineOpAttrs attrs; +} + +RunOp(const Op& op, Scope scope) { + Kernal* kernal = get_kernal(scope, op.get_kernal_name()); + std::vector input_vars = + get_variables(scope, op.get_input_name()); + std::vector output_vars = + get_variables(scope, op.get_output_name()); + + kernal->RunOnDevice(input_vars, output_vars, op.get_attrs()); +} +``` + +All `Kernal` need to be registered beforehand, just like `Op`. + +Now, `Op` is no longer has `Run()` function. It only contains names of variables and kernels. During network running, `RunOp()` is called to invoke `Op`'s corresponding `Kernal`. `get_kernal()` is supposed to return `kernal` for current device. From cee264f3f9e389ed24bbf504d9ab82ebd6354512 Mon Sep 17 00:00:00 2001 From: wuyi05 Date: Mon, 3 Jul 2017 09:51:03 +0800 Subject: [PATCH 27/40] update for comments --- Dockerfile | 7 ++++--- cmake/generic.cmake | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index bf227737c5..d10fad6370 100644 --- a/Dockerfile +++ b/Dockerfile @@ -34,11 +34,12 @@ RUN apt-get update && \ net-tools && \ apt-get clean -y -# Install Go +# Install Go and glide RUN wget -O go.tgz https://storage.googleapis.com/golang/go1.8.1.linux-amd64.tar.gz && \ tar -C /usr/local -xzf go.tgz && \ mkdir /root/gopath && \ - rm go.tgz + rm go.tgz \ + curl https://glide.sh/get | sh ENV GOROOT=/usr/local/go GOPATH=/root/gopath # should not be in the same line with GOROOT definition, otherwise docker build could not find GOROOT. ENV PATH=${PATH}:${GOROOT}/bin @@ -57,7 +58,7 @@ RUN pip install --upgrade pip && \ pip install -U docopt PyYAML sphinx && \ pip install -U sphinx-rtd-theme==0.1.9 recommonmark && \ pip install pre-commit 'requests==2.9.2' 'ipython==5.3.0' && \ - pip install 'ipykernel==4.6.0' 'jupyter==1.0.0' && \ + pip install 'ipykernel==4.6.0' 'jupyter==1.0.0' && \ pip install rarfile # To fix https://github.com/PaddlePaddle/Paddle/issues/1954, we use diff --git a/cmake/generic.cmake b/cmake/generic.cmake index 92e14f2581..ca358da8f1 100644 --- a/cmake/generic.cmake +++ b/cmake/generic.cmake @@ -302,7 +302,7 @@ function(go_binary TARGET_NAME) -o "${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}" "./${CMAKE_CURRENT_SOURCE_REL_DIR}/${go_binary_SRCS}" WORKING_DIRECTORY "${PADDLE_IN_GOPATH}/go") - # add_custom_target(${TARGET_NAME} ALL DEPENDS go_vendor ${TARGET_NAME}_link ${TARGET_NAME}_timestamp ${go_binary_DEPS}) + # TODO: don't know what ${TARGET_NAME}_link does add_custom_target(${TARGET_NAME} ALL DEPENDS go_vendor ${TARGET_NAME}_timestamp ${go_binary_DEPS}) install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME} DESTINATION bin) endfunction(go_binary) From 6f7a9dd5c0d6280c663909add5fe2ff4c0f28c71 Mon Sep 17 00:00:00 2001 From: wuyi05 Date: Mon, 3 Jul 2017 09:57:03 +0800 Subject: [PATCH 28/40] remove unnessesary comments --- go/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/go/CMakeLists.txt b/go/CMakeLists.txt index 9774a89e42..014697d155 100644 --- a/go/CMakeLists.txt +++ b/go/CMakeLists.txt @@ -12,10 +12,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # -# FIXME(typhoonzero): Download glide into cmake build temprary GOPATH add_subdirectory(pserver/cclient) add_subdirectory(cmd/pserver) add_subdirectory(cmd/master) add_subdirectory(master/c) -#TODO (add go/master/c back when fixed) From b9c15b6fffa55b6c42e6f06cc3eba3ccceea073c Mon Sep 17 00:00:00 2001 From: dongzhihong Date: Mon, 3 Jul 2017 12:23:26 +0800 Subject: [PATCH 29/40] "remove unused tests" --- go/pserver/optimizer.go | 6 +++--- go/pserver/optimizer_test.go | 24 ------------------------ go/pserver/service_test.go | 3 +-- 3 files changed, 4 insertions(+), 29 deletions(-) diff --git a/go/pserver/optimizer.go b/go/pserver/optimizer.go index 070896f7c7..b4a040f46b 100644 --- a/go/pserver/optimizer.go +++ b/go/pserver/optimizer.go @@ -49,7 +49,7 @@ func newOptimizer(paramWithConfigs ParameterWithConfig) *optimizer { cbuffer = C.malloc(C.size_t(len(p.Content))) C.memcpy(cbuffer, unsafe.Pointer(&p.Content[0]), C.size_t(len(p.Content))) o.opt = C.paddle_create_optimizer((*C.uchar)(&c[0]), C.int(len(c)), - C.paddle_element_type(p.ElementType), cbuffer, C.int(len(p.Content)*C.sizeof_float), + C.paddle_element_type(p.ElementType), cbuffer, C.int(len(p.Content)/C.sizeof_float), (*C.char)(nullPtr), 0) return o } @@ -57,7 +57,7 @@ func newOptimizer(paramWithConfigs ParameterWithConfig) *optimizer { func (o *optimizer) GetWeights() []byte { var buffer unsafe.Pointer buffer_len := C.paddle_optimizer_get_weights(o.opt, &buffer) - return cArrayToSlice(buffer, int(buffer_len)) + return cArrayToSlice(buffer, int(buffer_len)*C.sizeof_float) } func (o *optimizer) UpdateParameter(g Gradient) error { @@ -65,7 +65,7 @@ func (o *optimizer) UpdateParameter(g Gradient) error { return fmt.Errorf("Name: %s, parameter and gradient element type not match, parameter: %v, gradient: %v", g.Name, o.elementType, g.ElementType) } - r := C.paddle_update_parameter(o.opt, C.paddle_element_type(g.ElementType), unsafe.Pointer(&g.Content[0]), C.int(len(g.Content))) + r := C.paddle_update_parameter(o.opt, C.paddle_element_type(g.ElementType), unsafe.Pointer(&g.Content[0]), C.int(len(g.Content))/C.sizeof_float) if r != 0 { return fmt.Errorf("optimizer update returned error code: %d", r) } diff --git a/go/pserver/optimizer_test.go b/go/pserver/optimizer_test.go index 49d9df5898..368047d6f8 100644 --- a/go/pserver/optimizer_test.go +++ b/go/pserver/optimizer_test.go @@ -2,7 +2,6 @@ package pserver import ( "io/ioutil" - "reflect" "testing" ) @@ -23,26 +22,3 @@ func TestOptimizerCreateRelease(t *testing.T) { o := newOptimizer(param) o.Cleanup() } - -func TestOptimizerFull(t *testing.T) { - p := Parameter{ - Name: "a", - ElementType: Float32, - } - p.Content = []byte{1, 3} - config, err := ioutil.ReadFile("./cclient/test/testdata/optimizer.pb.txt") - if err != nil { - t.Fatalf("read optimizer proto failed") - } - param := ParameterWithConfig{ - Param: p, - Config: config, - } - o := newOptimizer(param) - g := Gradient(p) - if !reflect.DeepEqual(p.Content, o.GetWeights()) { - t.FailNow() - } - o.UpdateParameter(g) - o.Cleanup() -} diff --git a/go/pserver/service_test.go b/go/pserver/service_test.go index c62f92e09b..f86619447c 100644 --- a/go/pserver/service_test.go +++ b/go/pserver/service_test.go @@ -10,8 +10,7 @@ import ( "github.com/PaddlePaddle/Paddle/go/pserver" ) - -func TestFull(t *testing.T) { +func TestServiceFull(t *testing.T) { s, err := pserver.NewService(0) if err != nil { t.Error(err) From 722853312118c6ed1c0624baede84a2c8c2379a7 Mon Sep 17 00:00:00 2001 From: dongzhihong Date: Mon, 3 Jul 2017 12:49:08 +0800 Subject: [PATCH 30/40] test --- go/pserver/cclient/test/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go/pserver/cclient/test/CMakeLists.txt b/go/pserver/cclient/test/CMakeLists.txt index bd50f1db2a..f287f85071 100644 --- a/go/pserver/cclient/test/CMakeLists.txt +++ b/go/pserver/cclient/test/CMakeLists.txt @@ -1,2 +1,2 @@ cc_test(test_cclient SRCS test_cclient.c DEPS paddle_pserver_cclient) - +add_style_check_target(test_cclient test_cclient.c) From f4281ceee47fca4a1002efeea93f9ba39f99de76 Mon Sep 17 00:00:00 2001 From: fengjiayi Date: Mon, 3 Jul 2017 14:27:37 +0800 Subject: [PATCH 31/40] renew simple_op_design --- doc/design/simple_op_design.md | 110 ++++++--------------------------- 1 file changed, 19 insertions(+), 91 deletions(-) diff --git a/doc/design/simple_op_design.md b/doc/design/simple_op_design.md index 93c0f68ca9..49ca5db5da 100644 --- a/doc/design/simple_op_design.md +++ b/doc/design/simple_op_design.md @@ -43,10 +43,7 @@ message AttrValue { message AttrProto { required string name = 1; required string comment = 2; - optional AttrValue default = 3; - optional AttrValue max = 4; - optional AttrValue min = 5; - required AttrType type = 6; + required AttrType type = 3; }; message VarProto { @@ -63,7 +60,24 @@ message OpProto { }; ``` -The default value and value range didn't appear in out previous design. By adding these two fields, we are able to check attribute validity in Python and find out possible error as soon as possible. What's more, by providing the message about default value and value range to Python docstring, it helps to automatically generate more comprehensive documents. +To generate Python code automatically: + +```python +def create_python_ops_creatation_functions(): + op_protos = paddle.framework.OpRegistry.get_all_op_proto() + for type_name in op_protos: + op_proto = op_protos[type_name] + def __impl__(**kwargs): # User must use key word args in Paddle API + inputs = [kwargs.get(ipt.name, "") for ipt in op_proto.inputs] + outputs = [kwargs.get(opt.name, "") for opt in op_proto.outputs] + attrs = [cast_to_op_attr(attr, kwargs.get(attr.name, None)) for attr in op_proto.attrs] + opdesc = (input, outputs, type_name, attrs) + return paddle.framework.OpRegistry.CreateOp(opdesc) + __impl__.__doc__ = create_doc_string(op_proto) + globals()[type_name] = __impl__ + +create_python_ops_creatation_functions() +``` ### Message from Python to C++ @@ -185,89 +199,3 @@ def fc_layer(input, size, with_bias, activation): In above sample, `fc_op` and `sigmod_op` are low-level API. They build `OpDesc` and invoke corresponding C++ code. *TODO* - -## Op and Kernal - -After completely defined, an Op will be run in a network. However, Op's computing method may differ on different devices. One solution is that write an `Op`'s member function `Op::run()`, which contains computing methods of all possible devices. That may be a bad idea because we have to change all `Op`'s code to add a new device. - -Another choice is adding a concept named `kernal`. A `Kernal` describes an op's computing process on a certain device. After stripping `Variable` and `kernal`, `Op` becomes a pure conceptual class, which holds neither data nor detailed computing process. - -```cpp -class KernalBase { -public: - virtual void RunOnDevice(std::vector input_vars, - std::vector input_vars, - const OpAttrs* attrs) = 0; -}; - -template -class CosineKernal : public KernalBase { -public: - virtual void RunOnDevice(std::vector input_vars, - std::vector input_vars, - const OpAttrs* attrs) { - // no implementation - } -}; - -template <> -class CosineKernal : public KernalBase { -public: - virtual void RunOnDevice(std::vector input_vars, - std::vector input_vars, - const OpAttrs* attrs) { - CosineOpAttrs* cosine_attrs = static_cast(attrs); - // computing code - // ... - } -}; - -struct OpAttrs {...}; - -class Op { - public: - std::string get_kernal_name() { - return kernel_name_; - } - const vector& get_input_names() { - return input_names_; - } - const vector& get_output_names() { - return output_names_; - } - // ... - private: - std::vector input_names_; - std::vector output_names_; - std::string kernal_name_; - -} - -struct CosineOpAttrs : public OpAttrs { - float scale_; -} - -class CosineOp : public Op { - public: - const CosineOpAtrrs* get_attrs() { - return &attrs; - } - - private: - CosineOpAttrs attrs; -} - -RunOp(const Op& op, Scope scope) { - Kernal* kernal = get_kernal(scope, op.get_kernal_name()); - std::vector input_vars = - get_variables(scope, op.get_input_name()); - std::vector output_vars = - get_variables(scope, op.get_output_name()); - - kernal->RunOnDevice(input_vars, output_vars, op.get_attrs()); -} -``` - -All `Kernal` need to be registered beforehand, just like `Op`. - -Now, `Op` is no longer has `Run()` function. It only contains names of variables and kernels. During network running, `RunOp()` is called to invoke `Op`'s corresponding `Kernal`. `get_kernal()` is supposed to return `kernal` for current device. From 99e22a825d0d86968d24fc6717b765055c8ac73b Mon Sep 17 00:00:00 2001 From: dongzhihong Date: Mon, 3 Jul 2017 14:53:31 +0800 Subject: [PATCH 32/40] "fix pre-commit hook failed" --- go/pserver/cclient/test/test_cclient.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/go/pserver/cclient/test/test_cclient.c b/go/pserver/cclient/test/test_cclient.c index 5bd4913ba3..b16769b433 100644 --- a/go/pserver/cclient/test/test_cclient.c +++ b/go/pserver/cclient/test/test_cclient.c @@ -16,7 +16,7 @@ void sendGrads(paddle_pserver_client c) { "param_a", PADDLE_ELEMENT_TYPE_FLOAT32, grad_a, 2000}; paddle_gradient grad2 = { "param_b", PADDLE_ELEMENT_TYPE_FLOAT32, grad_b, 3000}; - paddle_gradient* grads[2] = {&grad1, &grad2}; + paddle_gradient *grads[2] = {&grad1, &grad2}; if (paddle_send_grads(c, grads, 2)) { fail(); } @@ -39,14 +39,12 @@ void getParams(paddle_pserver_client c) { param_b.content = content_b; param_b.content_len = 3000; - paddle_parameter* params[2] = {¶m_a, ¶m_b}; + paddle_parameter *params[2] = {¶m_a, ¶m_b}; if (paddle_get_params(c, params, 2)) { fail(); } } - - int main() { char addr[] = "localhost:3000"; paddle_pserver_client c = paddle_new_pserver_client(addr, 1); @@ -54,8 +52,10 @@ int main() { size_t config_proto_len = 0; ssize_t nread; FILE *fp = fopen("testdata/optimizer.pb.txt", "r"); - if(!fp) { fail(); } - while((nread = getline(&config_proto, &config_proto_len, fp)) != -1) { + if (!fp) { + fail(); + } + while ((nread = getline(&config_proto, &config_proto_len, fp)) != -1) { printf("%s", config_proto); } fclose(fp); @@ -70,7 +70,8 @@ retry: param.name = name_a; param.content = content_a; param.content_len = 2000; - int error = paddle_init_param(c, param, (void *)config_proto, config_proto_len); + int error = + paddle_init_param(c, param, (void *)config_proto, config_proto_len); if (error != 0) { goto retry; } From 85c4352ea8eeaa419d3542f378089fc9e1180565 Mon Sep 17 00:00:00 2001 From: dongzhihong Date: Mon, 3 Jul 2017 15:37:47 +0800 Subject: [PATCH 33/40] "pass style check" --- go/pserver/cclient/test/testdata/optimizer.pb.txt | Bin 50 -> 51 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/go/pserver/cclient/test/testdata/optimizer.pb.txt b/go/pserver/cclient/test/testdata/optimizer.pb.txt index 27dd3bc5f19e2964b4b674cff8860233cbdb445a..27c8a584df40ab714edfd730f0ff7b7bd3783964 100644 GIT binary patch delta 6 NcmXpqo?yht1poyT0W$yq delta 4 LcmXpunqUL~0=NMv From bdd27208778e82ca037b2b3f6d25337403db4092 Mon Sep 17 00:00:00 2001 From: Yu Yang Date: Mon, 3 Jul 2017 16:26:33 +0800 Subject: [PATCH 34/40] Add OpProto implementation OpProto is a proto message that helps 3rd-party language bindings, e.g. `Python`, to generate operator creation methods. The operator creation method is the low-level API for 3rd-party language bindings. Op creation methods take the user's input in that language, and convert users inputs into `OpDesc` message, then passing that `OpDesc` message to Paddle's C++ core and create an operator. * A separated `attr_type.proto` is added, because that file wound be included by `op_desc.proto` in future. --- paddle/framework/CMakeLists.txt | 1 + paddle/framework/attr_type.proto | 28 +++++++++++++ paddle/framework/op_proto.proto | 69 ++++++++++++++++++++++++++++++++ 3 files changed, 98 insertions(+) create mode 100644 paddle/framework/attr_type.proto create mode 100644 paddle/framework/op_proto.proto diff --git a/paddle/framework/CMakeLists.txt b/paddle/framework/CMakeLists.txt index 6aa6b9bc2d..3284015908 100644 --- a/paddle/framework/CMakeLists.txt +++ b/paddle/framework/CMakeLists.txt @@ -5,3 +5,4 @@ nv_test(dim_test SRCS dim_test.cu DEPS ddim) cc_test(variable_test SRCS variable_test.cc) cc_test(scope_test SRCS scope_test.cc) cc_test(enforce_test SRCS enforce_test.cc) +proto_library(op_proto SRCS op_proto.proto attr_type.proto) diff --git a/paddle/framework/attr_type.proto b/paddle/framework/attr_type.proto new file mode 100644 index 0000000000..2d8e0476d7 --- /dev/null +++ b/paddle/framework/attr_type.proto @@ -0,0 +1,28 @@ +/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. */ + +syntax="proto2"; +package paddle.framework; + +// Attribute Type for paddle's Op. +// Op contains many attributes. Each type of attributes could be different. +// The AttrType will be shared between AttrDesc and AttrProto. +enum AttrType { + INT = 0; + FLOAT = 1; + STRING = 2; + INTS = 3; + FLOATS = 4; + STRINGS = 5; +} \ No newline at end of file diff --git a/paddle/framework/op_proto.proto b/paddle/framework/op_proto.proto new file mode 100644 index 0000000000..22df6f9c6b --- /dev/null +++ b/paddle/framework/op_proto.proto @@ -0,0 +1,69 @@ +/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserve. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. */ + +// Protocol Message for 3rd-party language binding. +// +// Paddle Python package will use `OpProto` to generate op creation methods. +// The op creation methods take user's input and generate `OpDesc` proto message, +// then pass `OpDesc` to C++ side and create Op pointer. +// +syntax="proto2"; +package paddle.framework; + +import "attr_type.proto"; + +// Attribute protocol message for 3rd-party language binding. +// It will store the Op support what attribute and what type. +message AttrProto { + // Supported attribute name. e.g. `scale` for cosine op. + required string name = 1; + + // Supported attribute type. + required AttrType type = 2; + + // Supported attribute comments. It helps 3rd-party language generate doc-string. + required string comment = 3; +} + +// Input or output message for 3rd-party language binding. +// It contains parameter name and its comments. +message VarProto { + // Input or output name in that op creation function. + // e.g. `cos(a, b, output, ...)`, "a", "b", "output" are names. + required string name = 1; + + // The comment for that input. It helps 3rd-party language generate doc-string. + required string comment = 2; +} + +// Op protocol message for 3rd-party language binding. +// It contains all information for generating op creation method. +message OpProto { + // The input information to generate op creation method. + repeated VarProto inputs = 1; + + // The output information to generate op creation method. + repeated VarProto outputs = 2; + + // The attribute information to generate op creation method. + repeated AttrProto attrs = 3; + + // The comments for that Op. It helps 3rd-party language generate + // doc-string. The whole documentation of that Op is generated by comment, + // inputs, outputs, attrs together. + required string comment = 4; + + // The type of that Op. + required string type = 5; +} From 9bf98168281952efee1ed5fd1a61b743b0847834 Mon Sep 17 00:00:00 2001 From: Yu Yang Date: Mon, 3 Jul 2017 16:47:11 +0800 Subject: [PATCH 35/40] Add OpProto unittest. --- paddle/framework/CMakeLists.txt | 4 +++- paddle/framework/op_proto_test.cc | 31 +++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 paddle/framework/op_proto_test.cc diff --git a/paddle/framework/CMakeLists.txt b/paddle/framework/CMakeLists.txt index 3284015908..50107faaed 100644 --- a/paddle/framework/CMakeLists.txt +++ b/paddle/framework/CMakeLists.txt @@ -5,4 +5,6 @@ nv_test(dim_test SRCS dim_test.cu DEPS ddim) cc_test(variable_test SRCS variable_test.cc) cc_test(scope_test SRCS scope_test.cc) cc_test(enforce_test SRCS enforce_test.cc) -proto_library(op_proto SRCS op_proto.proto attr_type.proto) +proto_library(attr_type SRCS attr_type.proto) +proto_library(op_proto SRCS op_proto.proto) +cc_test(op_proto_test SRCS op_proto_test.cc DEPS attr_type op_proto protobuf) diff --git a/paddle/framework/op_proto_test.cc b/paddle/framework/op_proto_test.cc new file mode 100644 index 0000000000..9c054bde44 --- /dev/null +++ b/paddle/framework/op_proto_test.cc @@ -0,0 +1,31 @@ +#include +#include + +TEST(TestOpProto, ALL) { + paddle::framework::OpProto proto; + { + auto ipt = proto.mutable_inputs()->Add(); + *ipt->mutable_name() = "a"; + *ipt->mutable_comment() = "the one input of cosine op"; + } + { + auto ipt = proto.mutable_inputs()->Add(); + *ipt->mutable_name() = "b"; + *ipt->mutable_comment() = "the other input of cosine op"; + } + { + auto opt = proto.mutable_outputs()->Add(); + *opt->mutable_name() = "output"; + *opt->mutable_comment() = "the output of cosine op"; + } + { + auto attr = proto.mutable_attrs()->Add(); + *attr->mutable_name() = "scale"; + attr->set_type(paddle::framework::AttrType::FLOAT); + *attr->mutable_comment() = "the scale attribute of cosine op"; + } + proto.set_type("cos"); + *proto.mutable_comment() = "cosine op, output = scale * cos(a, b)"; + + ASSERT_TRUE(proto.IsInitialized()); +} \ No newline at end of file From 9b1240456342670098a48884182879cef8789425 Mon Sep 17 00:00:00 2001 From: wuyi05 Date: Mon, 3 Jul 2017 18:48:06 +0800 Subject: [PATCH 36/40] update dockerfile --- Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index d10fad6370..91bda8c734 100644 --- a/Dockerfile +++ b/Dockerfile @@ -38,11 +38,12 @@ RUN apt-get update && \ RUN wget -O go.tgz https://storage.googleapis.com/golang/go1.8.1.linux-amd64.tar.gz && \ tar -C /usr/local -xzf go.tgz && \ mkdir /root/gopath && \ - rm go.tgz \ - curl https://glide.sh/get | sh + rm go.tgz ENV GOROOT=/usr/local/go GOPATH=/root/gopath # should not be in the same line with GOROOT definition, otherwise docker build could not find GOROOT. ENV PATH=${PATH}:${GOROOT}/bin +# install glide +RUN curl https://glide.sh/get | sh # git credential to skip password typing RUN git config --global credential.helper store From 43df61505991fd2c9fa50d08e7cc0717b740ab45 Mon Sep 17 00:00:00 2001 From: wuyi05 Date: Mon, 3 Jul 2017 19:18:47 +0800 Subject: [PATCH 37/40] update dockerfile --- Dockerfile | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 91bda8c734..ed5910d93b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -38,12 +38,14 @@ RUN apt-get update && \ RUN wget -O go.tgz https://storage.googleapis.com/golang/go1.8.1.linux-amd64.tar.gz && \ tar -C /usr/local -xzf go.tgz && \ mkdir /root/gopath && \ + mkdir /root/gopath/bin && \ + mkdir /root/gopath/src && \ rm go.tgz ENV GOROOT=/usr/local/go GOPATH=/root/gopath # should not be in the same line with GOROOT definition, otherwise docker build could not find GOROOT. -ENV PATH=${PATH}:${GOROOT}/bin +ENV PATH=${PATH}:${GOROOT}/bin:${GOPATH}/bin # install glide -RUN curl https://glide.sh/get | sh +RUN curl -q https://glide.sh/get | sh # git credential to skip password typing RUN git config --global credential.helper store From eefcfed337899b77e56daa12470c8a9a69c69502 Mon Sep 17 00:00:00 2001 From: wuyi05 Date: Mon, 3 Jul 2017 19:58:59 +0800 Subject: [PATCH 38/40] fix ci error --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7db8a97381..5349f59805 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -97,6 +97,7 @@ include(external/warpctc) # download, build, install warpctc include(external/any) # download libn::any include(external/eigen) # download eigen3 +include(cudnn) # set cudnn libraries, must before configure include(configure) # add paddle env configuration include(generic) # simplify cmake module include(package) # set paddle packages @@ -105,7 +106,6 @@ include(ccache) # set ccache for compilation include(util) # set unittest and link libs include(rdma) # set rdma libraries include(flags) # set paddle compile flags -include(cudnn) # set cudnn libraries include(version) # set PADDLE_VERSION include(coveralls) # set code coverage From 1100f97e5707737d2dabe5a47bb111ff246e52e4 Mon Sep 17 00:00:00 2001 From: dongzhihong Date: Mon, 3 Jul 2017 21:26:49 +0800 Subject: [PATCH 39/40] "fix style check" --- cmake/cpplint.cmake | 1 + go/pserver/cclient/test/test_cclient.c | 2 +- go/pserver/cclient/test/testdata/optimizer.pb | Bin 0 -> 50 bytes go/pserver/cclient/test/testdata/optimizer.pb.txt | Bin 51 -> 0 bytes go/pserver/client_test.go | 2 +- go/pserver/optimizer_test.go | 2 +- go/pserver/service_test.go | 4 ++-- 7 files changed, 6 insertions(+), 5 deletions(-) create mode 100644 go/pserver/cclient/test/testdata/optimizer.pb delete mode 100644 go/pserver/cclient/test/testdata/optimizer.pb.txt diff --git a/cmake/cpplint.cmake b/cmake/cpplint.cmake index 48f705818b..6bbcd730e1 100644 --- a/cmake/cpplint.cmake +++ b/cmake/cpplint.cmake @@ -25,6 +25,7 @@ set(STYLE_FILTER "${STYLE_FILTER}-readability/casting") set(IGNORE_PATTERN .*ImportanceSampler.* .*cblas\\.h.* + .*\\.pb\\.txt .*LtrDataProvider.* .*MultiDataProvider.*) diff --git a/go/pserver/cclient/test/test_cclient.c b/go/pserver/cclient/test/test_cclient.c index b16769b433..8eababbe33 100644 --- a/go/pserver/cclient/test/test_cclient.c +++ b/go/pserver/cclient/test/test_cclient.c @@ -51,7 +51,7 @@ int main() { char *config_proto; size_t config_proto_len = 0; ssize_t nread; - FILE *fp = fopen("testdata/optimizer.pb.txt", "r"); + FILE *fp = fopen("testdata/optimizer.pb", "r"); if (!fp) { fail(); } diff --git a/go/pserver/cclient/test/testdata/optimizer.pb b/go/pserver/cclient/test/testdata/optimizer.pb new file mode 100644 index 0000000000000000000000000000000000000000..27dd3bc5f19e2964b4b674cff8860233cbdb445a GIT binary patch literal 50 kcmd;JloDUb$N&X9;j9CU3=s@ToSd^}g1}Dum25B;0LStS`2YX_ literal 0 HcmV?d00001 diff --git a/go/pserver/cclient/test/testdata/optimizer.pb.txt b/go/pserver/cclient/test/testdata/optimizer.pb.txt deleted file mode 100644 index 27c8a584df40ab714edfd730f0ff7b7bd3783964..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 51 lcmd;JloDUb$N&X9;j9CU3=s@ToSd^}g1}Dum25B;7XZ}t4FdoG diff --git a/go/pserver/client_test.go b/go/pserver/client_test.go index a248a3fb69..b805efa921 100644 --- a/go/pserver/client_test.go +++ b/go/pserver/client_test.go @@ -75,7 +75,7 @@ func TestClientFull(t *testing.T) { } const numParameter = 100 - config, err := ioutil.ReadFile("./cclient/test/testdata/optimizer.pb.txt") + config, err := ioutil.ReadFile("./cclient/test/testdata/optimizer.pb") if err != nil { t.Fatalf("read optimizer proto failed") } diff --git a/go/pserver/optimizer_test.go b/go/pserver/optimizer_test.go index 368047d6f8..b99b5a5f0b 100644 --- a/go/pserver/optimizer_test.go +++ b/go/pserver/optimizer_test.go @@ -11,7 +11,7 @@ func TestOptimizerCreateRelease(t *testing.T) { ElementType: Int32, } p.Content = []byte{1, 3} - config, err := ioutil.ReadFile("./cclient/test/testdata/optimizer.pb.txt") + config, err := ioutil.ReadFile("./cclient/test/testdata/optimizer.pb") if err != nil { t.Fatalf("read optimizer proto failed") } diff --git a/go/pserver/service_test.go b/go/pserver/service_test.go index f86619447c..30e3ac8ae1 100644 --- a/go/pserver/service_test.go +++ b/go/pserver/service_test.go @@ -19,7 +19,7 @@ func TestServiceFull(t *testing.T) { p.Name = "param_a" p.Content = []byte{1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0} p.ElementType = pserver.Int32 - config, err := ioutil.ReadFile("./cclient/test/testdata/optimizer.pb.txt") + config, err := ioutil.ReadFile("./cclient/test/testdata/optimizer.pb") if err != nil { t.Fatalf("read optimizer proto failed") } @@ -149,7 +149,7 @@ func TestBlockUntilInitialized(t *testing.T) { p.Name = "param_a" p.Content = []byte{1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0} p.ElementType = pserver.Int32 - config, err := ioutil.ReadFile("./cclient/test/testdata/optimizer.pb.txt") + config, err := ioutil.ReadFile("./cclient/test/testdata/optimizer.pb") if err != nil { t.Fatalf("read optimizer proto failed") } From 3f63d96abec165426bcd464f7aff32e2e42ed021 Mon Sep 17 00:00:00 2001 From: Yu Yang Date: Mon, 3 Jul 2017 23:16:11 +0800 Subject: [PATCH 40/40] Fix link error in op_proto_test. --- paddle/framework/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paddle/framework/CMakeLists.txt b/paddle/framework/CMakeLists.txt index 50107faaed..f7e5753ac2 100644 --- a/paddle/framework/CMakeLists.txt +++ b/paddle/framework/CMakeLists.txt @@ -7,4 +7,4 @@ cc_test(scope_test SRCS scope_test.cc) cc_test(enforce_test SRCS enforce_test.cc) proto_library(attr_type SRCS attr_type.proto) proto_library(op_proto SRCS op_proto.proto) -cc_test(op_proto_test SRCS op_proto_test.cc DEPS attr_type op_proto protobuf) +cc_test(op_proto_test SRCS op_proto_test.cc DEPS op_proto attr_type protobuf)