Tensor
Complete API reference for the Tensor class on Android.
This page reflects ZeticMLange Android 1.9.0.
The Tensor class is the unified data container passed to and returned from ZeticMLangeModel.run(). It wraps a direct ByteBuffer together with its DataType and shape, and provides typed accessors for reading and writing the underlying data.
Package
com.zeticai.mlange.core.tensorImport
import com.zeticai.mlange.core.tensor.Tensor
import com.zeticai.mlange.core.tensor.DataTypeCompanion Factories
The Tensor.of(...) factories are the recommended way to create tensors from typed arrays or NIO buffers. Each overload infers a sensible default DataType matching the source type.
Tensor.of(
data: FloatArray,
dataType: DataType = DataType.Float32,
shape: IntArray = intArrayOf(data.size),
immediateRelease: Boolean = false,
): TensorOverloads are provided for the following source types:
| Source | Default DataType |
|---|---|
ByteBuffer | DataType.Int8 |
ByteArray | DataType.Int8 |
FloatArray, FloatBuffer | DataType.Float32 |
DoubleArray, DoubleBuffer | DataType.Float64 |
IntArray, IntBuffer | DataType.Int32 |
LongArray, LongBuffer | DataType.Int64 |
ShortArray, ShortBuffer | DataType.Int16 |
CharArray, CharBuffer | DataType.Int16 |
Each overload also has a variant that accepts shape: Array<Int> in addition to shape: IntArray.
val input = Tensor.of(
data = floatArrayOf(/* ... */),
dataType = DataType.Float32,
shape = intArrayOf(1, 3, 640, 640),
)Tensor.of(data, dataType, shape) (generic array)
inline fun <reified T> of(
data: Array<T>,
dataType: DataType,
shape: Array<Int>,
immediateRelease: Boolean = false,
): TensorSupported element types: Int, Float, Long, Double, Char, Short.
Tensor.random(dataType, shape, immediateRelease)
Creates a tensor filled with random bytes. Handy for smoke-testing a model graph.
fun random(
dataType: DataType,
shape: IntArray,
immediateRelease: Boolean = false,
): Tensorval fakeInput = Tensor.random(DataType.Float32, intArrayOf(1, 3, 640, 640))Constructor
Tensor(data, dataType, shape, immediateRelease)
Creates a tensor directly from a direct ByteBuffer. Prefer the Tensor.of(...) factories above; use this constructor only when you already hold a direct ByteBuffer (for example, wrapping a native allocation).
Tensor(
data: ByteBuffer,
dataType: DataType = DataType.Int8,
shape: IntArray = intArrayOf(data.capacity()),
immediateRelease: Boolean = false,
)| Parameter | Type | Description |
|---|---|---|
data | ByteBuffer | A direct ByteBuffer holding the raw tensor bytes. Non-direct buffers will throw. |
dataType | DataType | Element type of the tensor. See DataType. Defaults to DataType.Int8. |
shape | IntArray | Tensor shape. The product of its dimensions times dataType.size must equal data.capacity(). |
immediateRelease | Boolean | When true, registers the tensor with TensorCleaner so its native memory is released as soon as it becomes unreachable. |
Throws: IllegalArgumentException if data is not a direct ByteBuffer, or if shape does not match data.capacity().
val buffer = ByteBuffer.allocateDirect(4 * 3 * 4).order(ByteOrder.nativeOrder())
val tensor = Tensor(buffer, DataType.Float32, intArrayOf(1, 3, 2, 2))Methods
count()
Returns the number of elements in the tensor (total bytes divided by dataType.size).
fun count(): Intsize()
Returns the size of the tensor in bytes (equivalent to data.capacity()).
fun size(): Intdata<T>()
Reifies the underlying ByteBuffer as a typed view or array. Useful for reading inference outputs as floats, ints, etc.
inline fun <reified T> data(): TSupported T:
| Type | Returns |
|---|---|
ByteBuffer | The underlying buffer itself. |
IntBuffer, LongBuffer, FloatBuffer, DoubleBuffer, CharBuffer, ShortBuffer | A typed view on the buffer. |
ByteArray, IntArray, LongArray, FloatArray, DoubleArray, CharArray, ShortArray | A backing array copy. |
Throws: IllegalArgumentException if T is not one of the supported types.
val floats: FloatArray = tensor.data()
val floatView: FloatBuffer = tensor.data()get<T>(index)
Reads a single element at index as the requested numeric type.
inline fun <reified T : Number> get(index: Int): TSupported T: Int, Long, Float, Double, Char, Short, Byte.
val first: Float = tensor.get<Float>(0)set(index, value)
Writes value into the tensor at index. The write type is inferred from the runtime type of value.
fun <T> set(index: Int, value: T)Supported value types: Int, Long, Float, Double, Char, Short.
tensor.set(0, 1.5f)order(order)
Changes the byte order of the underlying buffer.
fun order(order: ByteOrder)tensor.order(ByteOrder.LITTLE_ENDIAN)from(tensor)
Copies another tensor's bytes into this tensor. The source tensor must have the same shape.
fun from(tensor: Tensor)Throws: IllegalArgumentException if the source tensor's shape does not match.
output.from(reusedOutputTensor)copy(data, shape, dataType, immediateRelease)
Copies bytes from data into this tensor in place. The total byte size implied by shape and dataType must equal this tensor's current size.
fun copy(
data: ByteBuffer = this.data,
shape: IntArray = this.shape,
dataType: DataType = this.dataType,
immediateRelease: Boolean = this.immediateRelease,
)Throws: IllegalArgumentException if the source or destination buffer is smaller than the expected byte count.
DataType
DataType is a sealed interface describing the element type and byte size of a tensor.
import com.zeticai.mlange.core.tensor.DataType| Variant | Element size (bytes) |
|---|---|
DataType.Float32 | 4 |
DataType.Float64 | 8 |
DataType.Float16, DataType.BFloat16 | 2 |
DataType.UInt8, DataType.Int8, DataType.QInt8, DataType.QInt4 | 1 |
DataType.UInt16, DataType.Int16, DataType.QInt16 | 2 |
DataType.UInt32, DataType.Int32, DataType.QInt32 | 4 |
DataType.UInt64, DataType.Int64 | 8 |
DataType.Boolean | 1 |
DataType.Unknown(size) | Caller-provided |
Use DataType.from(name) to look up a type by its lowercase name (e.g. "float32", "int8", "bool"), and DataType.toName(type) for the reverse.
Properties
data
The underlying direct ByteBuffer backing the tensor.
val data: ByteBufferPrefer the typed data<T>() accessor when you need a typed view.
Full Working Example
Create tensors that match the model's expected shape and data type, then pass them to ZeticMLangeModel.run(...).
import com.zeticai.mlange.core.model.ZeticMLangeModel
import com.zeticai.mlange.core.tensor.Tensor
class MainActivity : AppCompatActivity() {
private lateinit var model: ZeticMLangeModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
model = ZeticMLangeModel(this, PERSONAL_KEY, "Steve/YOLOv11_comparison")
}
private fun runFrame(input: Tensor) {
// (1) Run inference with tensors matching the model input order
val outputs: Array<Tensor> = model.run(arrayOf(input))
// (2) Read outputs as typed arrays
val logits: FloatArray = outputs[0].data()
}
}Memory Management Recommendation
Tensor wraps a direct ByteBuffer that lives in off-heap native memory. How you manage that memory depends on who owns the underlying buffer:
-
Reuse tensors when practical. If your preprocessing output has the same shape every frame, keep the source arrays stable and update their contents before creating or reusing
Tensorvalues forrun(...). -
Only set
immediateRelease = trueon tensors you allocate yourself. When you build a tensor withTensor.of(...)(for example, a per-frame camera input) and pass it torun(), the model copies your bytes into its own input buffer. Your tensor is useless afterrun()returns, so registering it withTensorCleanerviaimmediateRelease = truelets off-heap memory be reclaimed as soon as the object becomes unreachable — which preventsOutOfMemoryError: Direct buffer memoryunder tight loops.
See Also
- ZeticMLangeModel (Android): Uses
Tensoras the input and output type ofrun() - Tensor (iOS): iOS equivalent
- Enums and Constants: Other Android SDK enums