func tensorData(c *C.TF_Tensor) []byte { // See: https://github.com/golang/go/wiki/cgo#turning-c-arrays-into-go-slices cbytes := C.TF_TensorData(c) length := int(C.TF_TensorByteSize(c)) slice := (*[1 << 30]byte)(unsafe.Pointer(cbytes))[:length:length] return slice }
// NewTensor converts from a Go value to a Tensor. Valid values are scalars, // slices, and arrays. Every element of a slice must have the same length so // that the resulting Tensor has a valid shape. func NewTensor(value interface{}) (*Tensor, error) { val := reflect.ValueOf(value) dims, dataType, err := dimsAndDataTypeOf(val.Type()) if err != nil { return nil, err } // TODO(ashankar): Remove the bytes.Buffer and endcode directly into // C-memory, avoiding the memcpy and cutting down memory usage in half. shape := make([]int64, dims) buf := new(bytes.Buffer) if err := encodeTensor(buf, shape, val); err != nil { return nil, err } var shapePtr *C.int64_t if len(shape) > 0 { shapePtr = (*C.int64_t)(unsafe.Pointer(&shape[0])) } t := &Tensor{ c: C.TF_AllocateTensor(C.TF_DataType(dataType), shapePtr, C.int(len(shape)), C.size_t(buf.Len())), shape: shape, } runtime.SetFinalizer(t, (*Tensor).finalize) if buf.Len() > 0 { slice := buf.Bytes() // https://github.com/golang/go/issues/14210 C.memcpy(C.TF_TensorData(t.c), unsafe.Pointer(&slice[0]), C.size_t(buf.Len())) } return t, nil }
// c converts the Tensor to a *C.TF_Tensor. Callers must take ownership of // the *C.TF_Tensor, either by passing ownership to the C API or explicitly // calling C.TF_DeleteTensor() on it. func (t *Tensor) c() *C.TF_Tensor { var shapePtr *C.int64_t if len(t.shape) > 0 { shapePtr = (*C.int64_t)(unsafe.Pointer(&t.shape[0])) } tensor := C.TF_AllocateTensor(C.TF_DataType(t.dt), shapePtr, C.int(len(t.shape)), C.size_t(t.buf.Len())) if t.buf.Len() > 0 { slice := t.buf.Bytes() // https://github.com/golang/go/issues/14210 C.memcpy(C.TF_TensorData(tensor), unsafe.Pointer(&slice[0]), C.size_t(t.buf.Len())) } return tensor }
// newTensorFromC converts from a C.TF_Tensor to a Tensor. func newTensorFromC(ct *C.TF_Tensor) *Tensor { t := &Tensor{dt: DataType(C.TF_TensorType(ct))} numDims := int(C.TF_NumDims(ct)) for i := 0; i < numDims; i++ { t.shape = append(t.shape, int64(C.TF_Dim(ct, C.int(i)))) } b := make([]byte, int(C.TF_TensorByteSize(ct))) if len(b) > 0 { C.memcpy(unsafe.Pointer(&b[0]), C.TF_TensorData(ct), C.size_t(len(b))) } t.buf = bytes.NewBuffer(b) return t }
// Value converts the Tensor to a Go value. For now, not all Tensor types are // supported, and this function may panic if it encounters an unsupported // DataType. // // The type of the output depends on the Tensor type and dimensions. // For example: // Tensor(int64, 0): int64 // Tensor(float64, 3): [][][]float64 func (t *Tensor) Value() interface{} { typ, err := typeOf(t.DataType(), t.Shape()) if err != nil { panic(err) } val := reflect.New(typ) // See: https://github.com/golang/go/wiki/cgo#turning-c-arrays-into-go-slices cbytes := C.TF_TensorData(t.c) length := int(C.TF_TensorByteSize(t.c)) slice := (*[1 << 30]byte)(unsafe.Pointer(cbytes))[:length:length] if err := decodeTensor(bytes.NewReader(slice), t.Shape(), typ, val); err != nil { panic(err) } return reflect.Indirect(val).Interface() }