-
Notifications
You must be signed in to change notification settings - Fork 5.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Go optimizer: integrate Go with optimizer library #2610
Conversation
go/pserver/optimizer.go
Outdated
// 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++ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/Users/dzh/.go/src/github.com
need to be a relative path: #cgo LDFLAGS: -L${SRCDIR}/xxx
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cgo cannot get cmake predefined variable here. use relative path here
fix done.
go/pserver/optimizer.go
Outdated
c := paramWithConfigs.Config | ||
var cbuffer unsafe.Pointer | ||
cbuffer = unsafe.Pointer(&p.Content[0]) | ||
o.opt = C.paddle_create_optimizer((*C.uchar)(&c[0]), C.int(len(c)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
&p.Content[0]
is a pointer allocated in Go's stack, which is owned by Go. The optimizer will own the parameter buffer. So we need to either make a copy of &p.Content[0]
here, or inside the implementation of paddle_element_type
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fix done.
go/pserver/optimizer.go
Outdated
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)) | ||
func (o *optimizer) GetWeights(p *Parameter) error { | ||
// FIXME: get weigths from optimizer has bug |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The optimizer is working before, we should not check in code that has bug and make optimizer not working. I think we need to debug the bug before merge in the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
go/pserver/optimizer.go
Outdated
} | ||
|
||
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))) | ||
// FIXME: do we need a copy? discard g.Content by GC ok |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do not need to make a copy of &g.Content[0]
, since C.paddle_update_parameter
will not use &g.Content[0]
anymore after return.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
go/pserver/service.go
Outdated
opt *optimizer | ||
paramMap map[string]Parameter | ||
mu sync.Mutex | ||
// injection from parameter to optimizer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't quite understand the comment here, is this necessary?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
go/pserver/optimizer.go
Outdated
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)) | ||
func (o *optimizer) GetWeights(p *Parameter) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe func (o *optimizer) GetWeights() []byte
is easier to read.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fix done
ElementType: Int32, | ||
} | ||
p.Content = []byte{1, 3} | ||
config, err := ioutil.ReadFile("./cclient/test/testdata/optimizer.pb.txt") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test file is not generated nor pushed to git.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is pushed under the testdata folder. here it is
https://github.com/dzhwinter/Paddle/blob/242df4f07bda6de94399cc60b31cb22f27a94434/go/pserver/cclient/test/testdata/optimizer.pb.txt
Binary file can not shown in PR reviews. : )
go/pserver/optimizer.go
Outdated
var nullPtr = unsafe.Pointer(uintptr(0)) | ||
|
||
type optimizer struct { | ||
opt *C.struct_paddle_optimizer | ||
// used in GetParam, reconstruct Parameter from optimizer | ||
ElementType ElementType |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ElementType ElementType
-> elementType ElementType
. We should not expose anything more than necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
go/pserver/optimizer.go
Outdated
var nullPtr = unsafe.Pointer(uintptr(0)) | ||
|
||
type optimizer struct { | ||
opt *C.struct_paddle_optimizer | ||
// used in GetParam, reconstruct Parameter from optimizer |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Perhaps the code ElementType ElementType
is already self documenting, if user want to know where ElementType
is used, he can just search through the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
go/pserver/optimizer.go
Outdated
} | ||
|
||
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))) | ||
fmt.Println(g) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe this is not necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
go/pserver/optimizer.go
Outdated
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)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need a functionfunc (o *optimizer) Release()
that releases the C++ optimizer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we already have a funcition CleanUp
76func (o *optimizer) Cleanup() {
77 if unsafe.Pointer(o.opt) != nullPtr {
78 C.paddle_release_optimizer(o.opt)
79 o.opt = (*C.struct_paddle_optimizer)(nullPtr)
80 }
81}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! My bad!
go/pserver/optimizer.go
Outdated
p := paramWithConfigs.Param | ||
c := paramWithConfigs.Config | ||
var cbuffer unsafe.Pointer | ||
cbuffer_len := int(unsafe.Sizeof(p.Content[0])) * len(p.Content) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it's a good idea to log here for Param.ElementType, len(Param.Content), len(Config.Content).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good idea. Done.
go/pserver/optimizer.go
Outdated
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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add a TODO here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought CleanUp
is enough
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry my bad, I thought (*C.char)(nullPtr), 0
is for parameter config, but it's actually for recover state, which is not necessary here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM++ Maybe need to rebase, because there are merge conflict.
go/pserver/optimizer.go
Outdated
// #cgo pkg-config: protobuf | ||
// #cgo CFLAGS: -I ../../ | ||
// //FIXME: ldflags contain "build" path | ||
// #cgo LDFLAGS: ../../build/go/pserver/cclient/libpaddle_go_optimizer.a -lstdc++ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add -lm
after -lstdc++
, or build will error at:
# github.com/PaddlePaddle/Paddle/go/pserver
/usr/bin/ld: ../../build/go/pserver/cclient/libpaddle_go_optimizer.a(adam_optimizer.cc.o): undefined reference to symbol 'pow@@GLIBC_2.2.5'
//lib/x86_64-linux-gnu/libm.so.6: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there is no any part use math library, I cannot reproduce it in my computer and docker environment. Will talk with you offline
anyway, add the flags.
In
should not |
I tried to use Tensor* parameter =
new Tensor(reinterpret_cast<float*>(param_buffer), num_bytes/4); and tested ok. But better fix should be at 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) to get proper size from the element type, instead of |
Thanks a lot! fix it @typhoonzero |
fix #2516
related #2560