tensor.go 6.3 KB
Newer Older
L
LKKlein 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
package paddle

// #include <stdbool.h>
// #include <stdlib.h>
// #include <string.h>
// #include <paddle_c_api.h>
import "C"

import (
	"reflect"
	"runtime"
	"unsafe"
)

type PaddleDType C.PD_DataType

const (
	FLOAT32  PaddleDType = C.PD_FLOAT32
	INT32    PaddleDType = C.PD_INT32
	INT64    PaddleDType = C.PD_INT64
	UINT8    PaddleDType = C.PD_UINT8
	UNKDTYPE PaddleDType = C.PD_UNKDTYPE
)

var types = []struct {
	gotype reflect.Type
	dtype  PaddleDType
}{
	{reflect.TypeOf(float32(0)), FLOAT32},
	{reflect.TypeOf(int32(0)), INT32},
	{reflect.TypeOf(int64(0)), INT64},
	{reflect.TypeOf(uint8(0)), UINT8},
}

35
func typeOfDataType(dtype PaddleDType) reflect.Type {
L
LKKlein 已提交
36 37
	var ret reflect.Type
	for _, t := range types {
38
		if t.dtype == dtype {
L
LKKlein 已提交
39 40 41
			ret = t.gotype
		}
	}
42 43
	return ret
}
L
LKKlein 已提交
44

45 46 47 48 49 50 51 52 53 54
func sizeofDataType(dtype PaddleDType) int32 {
	switch dtype {
	case UINT8:
		return int32(C.sizeof_uchar)
	case INT32:
		return int32(C.sizeof_int)
	case INT64:
		return int32(C.sizeof_longlong)
	case FLOAT32:
		return int32(C.sizeof_float)
L
LKKlein 已提交
55
	}
56 57
	return -1
}
L
LKKlein 已提交
58

59 60 61 62 63 64 65 66
func shapeAndTypeOf(val reflect.Value) (shape []int32, dt PaddleDType) {
	gotype := val.Type()
	for gotype.Kind() == reflect.Array || gotype.Kind() == reflect.Slice {
		shape = append(shape, int32(val.Len()))
		if val.Len() > 0 {
			val = val.Index(0)
		}
		gotype = gotype.Elem()
L
LKKlein 已提交
67
	}
68 69 70 71 72 73 74

	for _, t := range types {
		if gotype.Kind() == t.gotype.Kind() {
			return shape, PaddleDType(t.dtype)
		}
	}
	return shape, dt
L
LKKlein 已提交
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
}

type ZeroCopyTensor struct {
	c     *C.PD_ZeroCopyTensor
	name  string
	shape []int32
}

func NewZeroCopyTensor() *ZeroCopyTensor {
	c_tensor := C.PD_NewZeroCopyTensor()

	tensor := &ZeroCopyTensor{c: c_tensor}
	runtime.SetFinalizer(tensor, (*ZeroCopyTensor).finalize)
	return tensor
}

func (tensor *ZeroCopyTensor) finalize() {
	C.PD_DeleteZeroCopyTensor(tensor.c)
}

func (tensor *ZeroCopyTensor) Shape() []int32 {
	return tensor.shape
}

func (tensor *ZeroCopyTensor) Name() string {
	return C.GoString(tensor.c.name)
}

func (tensor *ZeroCopyTensor) Rename(name string) {
	tensor.name = name
	tensor.c.name = (*C.char)(unsafe.Pointer(tensor.c.name))
}

func (tensor *ZeroCopyTensor) Reshape(shape []int32) {
	tensor.shape = make([]int32, len(shape))
	copy(tensor.shape, shape)
	length := C.sizeof_int * C.size_t(len(shape))
	if tensor.c.shape.capacity < C.size_t(length) {
		if tensor.c.shape.capacity != C.size_t(0) {
			C.free(tensor.c.shape.data)
		}
		tensor.c.shape.data = C.malloc(length)
		tensor.c.shape.capacity = length
	}
	tensor.c.shape.length = length
	C.memcpy(tensor.c.shape.data, unsafe.Pointer(&shape[0]), length)
}

func (tensor *ZeroCopyTensor) DataType() PaddleDType {
	return PaddleDType(tensor.c.dtype)
}

func (tensor *ZeroCopyTensor) SetValue(value interface{}) {
	val := reflect.ValueOf(value)
129
	shape, dtype := shapeAndTypeOf(val)
L
LKKlein 已提交
130
	num := numel(shape)
131
	length := C.size_t(sizeofDataType(dtype) * num)
L
LKKlein 已提交
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
	if tensor.c.data.capacity < length {
		if tensor.c.data.capacity != C.size_t(0) {
			C.free(tensor.c.data.data)
		}
		tensor.c.data.data = C.malloc(length)
		tensor.c.data.capacity = length
	}
	tensor.c.data.length = length

	switch dtype {
	case PaddleDType(UINT8):
		data := val.Interface().([]uint8)
		C.memcpy(tensor.c.data.data, unsafe.Pointer(&data[0]), length)
	case PaddleDType(INT32):
		data := val.Interface().([]int32)
		C.memcpy(tensor.c.data.data, unsafe.Pointer(&data[0]), length)
	case PaddleDType(INT64):
		data := val.Interface().([]int64)
		C.memcpy(tensor.c.data.data, unsafe.Pointer(&data[0]), length)
	case PaddleDType(FLOAT32):
		data := val.Interface().([]float32)
		C.memcpy(tensor.c.data.data, unsafe.Pointer(&data[0]), length)
	}
	tensor.c.dtype = C.PD_DataType(dtype)
}

158 159
func (tensor *ZeroCopyTensor) tensorData() []byte {
	cbytes := tensor.c.data.data
L
LKKlein 已提交
160 161 162
	length := tensor.c.data.length
	var slice []byte
	if unsafe.Sizeof(unsafe.Pointer(nil)) == 8 {
163
		slice = (*[1<<50 - 1]byte)(unsafe.Pointer(cbytes))[:length:length]
L
LKKlein 已提交
164
	} else {
165
		slice = (*[1 << 30]byte)(unsafe.Pointer(cbytes))[:length:length]
L
LKKlein 已提交
166
	}
167
	return slice
L
LKKlein 已提交
168 169
}

170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
func (tensor *ZeroCopyTensor) Value() interface{} {
	t := typeOfDataType(PaddleDType(tensor.c.dtype))
	data := tensor.tensorData()
	return decodeTensor(data, tensor.Shape(), t).Interface()
}

// It isn't safe to use reflect.SliceHeader as it uses a uintptr for Data and
// this is not inspected by the garbage collector
type sliceHeader struct {
	Data unsafe.Pointer
	Len  int
	Cap  int
}

func decodeTensor(raw []byte, shape []int32, t reflect.Type) reflect.Value {
	// Create a 1-dimensional slice of the base large enough for the data and
	// copy the data in.
	n := int(numel(shape))

	l := n * int(t.Size())
	typ := reflect.SliceOf(t)
	slice := reflect.MakeSlice(typ, n, n)
	baseBytes := *(*[]byte)(unsafe.Pointer(&sliceHeader{
		Data: unsafe.Pointer(slice.Pointer()),
		Len:  l,
		Cap:  l,
	}))
	copy(baseBytes, raw)

	if len(shape) == 0 {
		// for n
		return slice.Index(0)
	}
	if len(shape) == 1 {
		// for {}
		return slice
L
LKKlein 已提交
206
	}
207 208 209 210 211 212 213 214 215 216
	// for {{} {}} {{} {}} {{} {}}
	if n == 0 {
		n = int(numel(shape[:len(shape)-1]))
	}
	for i := len(shape) - 2; i >= 0; i-- {
		underlyingSize := typ.Elem().Size()
		typ = reflect.SliceOf(typ)
		subsliceLen := int(shape[i+1])
		if subsliceLen != 0 {
			n = n / subsliceLen
L
LKKlein 已提交
217
		}
218 219 220 221 222 223 224 225 226 227
		data := unsafe.Pointer(slice.Pointer())
		nextSlice := reflect.MakeSlice(typ, n, n)

		for j := 0; j < n; j++ {
			// This is equivalent to nSlice[j] = slice[j*subsliceLen: (j+1)*subsliceLen]
			setSliceInSlice(nextSlice, j, sliceHeader{
				Data: unsafe.Pointer(uintptr(data) + (uintptr(j*subsliceLen) * underlyingSize)),
				Len:  subsliceLen,
				Cap:  subsliceLen,
			})
L
LKKlein 已提交
228 229
		}

230
		slice = nextSlice
L
LKKlein 已提交
231
	}
232
	return slice
L
LKKlein 已提交
233 234
}

235 236 237 238 239 240 241
// setSliceInSlice sets slice[index] = content.
func setSliceInSlice(slice reflect.Value, index int, content sliceHeader) {
	const sliceSize = unsafe.Sizeof(sliceHeader{})
	// We must cast slice.Pointer to uninptr & back again to avoid GC issues.
	// See https://github.com/google/go-cmp/issues/167#issuecomment-546093202
	*(*sliceHeader)(unsafe.Pointer(uintptr(unsafe.Pointer(slice.Pointer())) + (uintptr(index) * sliceSize))) = content
}
L
LKKlein 已提交
242

243 244 245 246 247 248 249
func (tensor *ZeroCopyTensor) Lod() []uint {
	var val []uint
	valHdr := (*reflect.SliceHeader)(unsafe.Pointer(&val))
	valHdr.Data = uintptr(unsafe.Pointer(tensor.c.lod.data))
	valHdr.Len = int(tensor.c.lod.length / C.sizeof_size_t)
	valHdr.Cap = int(tensor.c.lod.length / C.sizeof_size_t)
	return val
L
LKKlein 已提交
250
}