Repository navigation
[RFC][GOLANG] TVM Golang Runtime Interface Discussion #1559
Copy link
Copy link
Closed
Labels
Description
Here briefing the golang interface design aspects.
Few golang concepts
- Usage of packages
Candunsafegolang packages to go across golang boundary while accessing functions, types and pointer ..etc. - Slices: Usage if golang slice where ever is possible to simplify application programming. Example being use
slice of stringinstead of argument pair containingargc, argv
Please refer to golang tutorials for details of cgo, unsafe, slices ..etc.
Objective
- Initial version is expected to cover basic inference API listed below.
- Similar to many programming languages a package which can be imported and used is the best option here too.
- Hence the objective of this effort is a golang package
gotvmwhich is wrapped over TVMc_runtime_api.
API
This initial version expected to cover the below API
func FuncListGlobalNames() (retVal []string, err error)
func GetGlobalFunction(funcname string) (retVal func(args ...interface{}) (*Value, error), err error)
func RegisterFunction(args ...interface{}) (err error)
type Array
func Empty(shape []int64, args ...interface{}) (parray *Array, err error)
func (parray Array) AsSlice() (retVal interface{}, err error)
func (parray Array) CopyFrom(val interface{}) (err error)
func (parray Array) GetCtx() (retVal Context)
func (parray Array) GetDType() (retVal string)
func (parray Array) GetNdim() (retVal int32)
func (parray Array) GetShape() (retVal []int64)
type ByteArray
func NewByteArray(val []uint8) (retVal *ByteArray)
func (tbytearray ByteArray) GetData() (retVal string)
type Context
func CPU(index int32) Context
func CPUPinned(index int32) Context
func GPU(index int32) Context
func Metal(index int32) Context
func OpenCL(index int32) Context
func OpenGL(index int32) Context
func ROCM(index int32) Context
func SDAccel(index int32) Context
func VPI(index int32) Context
func Vulkan(index int32) Context
type Function
func ConvertFunction(args ...interface{}) (fhandle Function, err error)
func (tvmfunction Function) Invoke(args ...interface{}) (retVal *Value, err error)
type Module
func LoadModuleFromFile(modpath string, args ...interface{}) (retVal *Module, err error)
func (tvmmodule *Module) GetFunction(funcname string, args ...interface{}) (retVal func(args ...interface{}) (*Value, error), err error)
type Value
func (tvmval Value) AsFloat64() (retVal float64)
func (tvmval Value) AsFunction() (retVal *Function)
func (tvmval Value) AsInt64() (retVal int64)
func (tvmval Value) AsModule() (retVal *Module)
func (tvmval Value) AsStr() (retVal string)Sample Code
/*!
* Copyright (c) 2018 by Contributors
* \brief Sample golang application deployment over tvm.
* \file simple.go
*/
package main
import (
"fmt"
"runtime"
"./gotvm"
)
// NNVM compiled model paths.
const (
modLib = "./deploy.so"
)
// main
func main() {
// Welcome
defer runtime.GC()
fmt.Printf("TVM Go Interface : v%v\n", gotvm.GoTVMVersion)
fmt.Printf("TVM Version : v%v\n", gotvm.TVMVersion)
fmt.Printf("DLPACK Version: v%v\n\n", gotvm.DLPackVersion)
// Import tvm module (so)
modp, _ := gotvm.LoadModuleFromFile(modLib)
fmt.Printf("Module Imported\n")
// Allocate Array for inputs and outputs.
// Allocation by explicit type and context.
tshapeIn := []int64{4}
inX, _ := gotvm.Empty(tshapeIn, "float32", gotvm.CPU(0))
// Default allocation on CPU
inY, _ := gotvm.Empty(tshapeIn, "float32")
// Default allocation to type "float32" and on CPU
out, _ := gotvm.Empty(tshapeIn)
fmt.Printf("Input and Output Arrays allocated\n")
// Fill Input Data : inX , inY
inXSlice := []float32 {1, 2, 3, 4}
inYSlice := []float32 {5, 6, 7, 8}
// Copy the data on target memory through runtime CopyFrom api.
inX.CopyFrom(inXSlice)
inY.CopyFrom(inYSlice)
fmt.Printf("X: %v\n", inXSlice)
fmt.Printf("Y: %v\n", inYSlice)
// Get function "myadd"
funp, _ := modp.GetFunction("myadd")
// Call function
funp(inX, inY, out)
fmt.Printf("Module function myadd executed\n")
// Get the output tensor as an interface holding a slice through runtime CopyTo api.
outSlice, _ := out.AsSlice()
// Print results
fmt.Printf("Result:%v\n", outSlice.([]float32))
}@dmlc/tvm-team welcome to comment on this info.
Please refer to #1470 to have a look at initial effort.
Activity
tqchen commentedon Aug 5, 2018
I hope we can have a healthy discussion on what high-level API that goes beyond C FFI style API can be provided. Specifically, if we look at tvm runtime API of java, js, python, we have specific object class for Module, Array, and Function which automatically manages their lifecycle and when necessary overloads the ops. I know little about go but from what I learnt, this should be possible
[-][RFC][GOLANG] TVM runtime for golang v0.1[/-][+][RFC][GOLANG] TVM Golang Runtime Interface Discussion[/+]tqchen commentedon Aug 5, 2018
Some things I think that are related. In python and js we use variadic interface to implement function invocation, it seems to be possible to implement a dynamically dispatched variadic function via
func function_name(a ...interface{})tqchen commentedon Aug 5, 2018
Point2: ideally we want to remove Free functions and automatically manage the objects, and always use Finalizer to trigger the free of the objects https://golang.org/pkg/runtime/#SetFinalizer
tqchen commentedon Aug 5, 2018
Point3: from user's point of view, we may not need to have a TVMFunction object at all, the handle can be captured, but module.GetFunction can directly return a closure with signature:
This way the function returned by module.GetFunction can be directly invoked as a function
tqchen commentedon Aug 8, 2018
Please update the examples accordingly, once we have a clear interface proposal, we can proceed on implementation again
srkreddy1238 commentedon Aug 8, 2018
Updated the interface and example code above.
This version is based on
The PR #1470 also updated accordingly for review.
tqchen commentedon Aug 8, 2018
Three things:
srkreddy1238 commentedon Aug 9, 2018
@tqchen Sorry, I forgot to submit the edited sample code and final API interface above :)
Have a look now.
ret, err. Optional second return value is golang style of reporting error. Here I am returning TVMGetLastErr as golang error object.tqchen commentedon Aug 10, 2018
tqchen commentedon Aug 10, 2018
maybe @yzhliu can also chime in to comment on api design
srkreddy1238 commentedon Aug 12, 2018
Addressed above changes.
tqchen commentedon Aug 14, 2018
@srkreddy1238 can you please also update the sample code on the first post?
srkreddy1238 commentedon Aug 14, 2018
Updated the sample code.
3 remaining items
srkreddy1238 commentedon Aug 14, 2018
Ref below from complex.go example
Packed Function return is handled and it return an interface holding the value based on the ret_type_code from TVM runtime.
tqchen commentedon Aug 14, 2018
according to java's wrapping, we can introduce TVMValue object as an intermediate variant type, and use AsXX function to do the explicit conversion with type checking, and the call will look like
srkreddy1238 commentedon Aug 14, 2018
Sure, I will refer java wrappers and add them in golang too.
tqchen commentedon Aug 16, 2018
Please update the examples once you have an updated API and I will check again
srkreddy1238 commentedon Aug 16, 2018
Updated API interface above with wrappers on
TVMValueandTVMContextwrappers API.Please find below complex example which use these wrappers.
tqchen commentedon Aug 17, 2018
The API looks good, please also include examples for how can we use callbacks
srkreddy1238 commentedon Aug 18, 2018
@tqchen
One situation while designing function callbacks for discussion.
The function closure is defined as
func (args ...interface{}) (*Value, error)which takes golang types as variadic args and packs them as TVMValue array internally. The return value is TVMValue and AsXXX wrappers are provided to access the underlying values.I am looking at function callbacks definition as
func (args ...interface{}) (interface{})which takes variadic args and returns an interface.The signature should be same for both cases.
Reason behind proposing
interface{}instead ofTVMValueis user don't' need to explicitly embed golang types intoTVMValuewith wrappers.Samples:
else user need to handle embedding jsonStr, modp ..etc. into TVMValue with functions.
Please advice.
tqchen commentedon Aug 20, 2018
OK, I think it is fine to use the interface if go users are familiar with that.
One second thought on the callbacks, we do need a way to convert functions into handles and pass PackedFunc handle back when there is a function argument. We can do it either by attaching a field to the closure(if go permit that, as in https://github.com/dmlc/tvm/blob/master/web/tvm_runtime.js#L466), or we do need a customized Function struct, and use a special method Call to call the function
srkreddy1238 commentedon Aug 21, 2018
@tqchen
Here is the final sample with packed function system support for golang.
Please comment on the
//TODObelow to finalize.Also the API above is updated with addition of
RegisterFunction,ConvertFunctionandInvoketqchen commentedon Aug 21, 2018
tqchen commentedon Aug 21, 2018
One possible problem of the current callback interface is that the value types seem to be pretty strict, for example, we do
pfunc.Invoke((int64)(0)), but ideally, we want to supportpfunc.Invoke(0).One option is to Value as a signature for the implementation of callback could be helpful. So callback's signature takes in Value and call AsXXX during to get the argument and construct Value during return.
The invoke expose the signature
(args ...interface{}) Value, and we allow user to directly pass in int/closure/Value/float/Array etc and do the automated conversion to Value under the hoodsrkreddy1238 commentedon Aug 22, 2018
To summarize the TODO
GetGlobalFunction should return TVMFunction (Packed Function) which will be called via Invoke method to be consistent across.
Packed function implementation signature would be
(args ...Value) (interface{})where AsXXX functions will be helpful to receive arguments and user can return any type.Packed Function invoke signature would be
(args ...interface{}) (*Value)where user can pass any types as arguments and receives Value where AsXXX helpers will be helpful.sampleFunctionCbin above example demonstrate go-closure turning into PackedFunc under the hood automatically. I will add more samples for the same.tqchen commentedon Aug 23, 2018
One thing to keep in mind is that in the cases where interface{} is used, we also need to support Value as a argument/return
srkreddy1238 commentedon Aug 24, 2018
Yes, Value is handled.
Also covering
[]Valuewhich is possible whena callback function calling another callback function with slice of it's own arguments.