Closed eaplatanios closed 7 years ago
For reference: Documentation of the C++ Op interface: https://www.tensorflow.org/extend/adding_an_op#building_advanced_features_into_your_op
I've done some thinking about typed Output
as well as some tinkering. The result is a draft table of how the types could look like for different cases.
I'm assuming DataType
as it's currenty implemented, with ScalaType
as type member and subclassing objects fixing the type. I'm also assuming that each Output[T]
will produce a single Tensor[T]
when evaluated. This is how the types roughly look like:
sealed trait Output[T <: DataType] {
def evaluate(...): Tensor[T]
...
}
class INT32Output extends Output[INT32] {
override def evaluate(...): Tensor[INT32] = ...
...
}
sealed trait Tensor[T <: DataType] {
def entriesIterator: Iterator[T#ScalaType]
...
}
class INT32Tensor extends Tensor[INT32] {
def entriesIterator: Iterator[Int] = ...
...
}
Based on those types here are the possible cases I could think of with examples. Could you have a look to check if it's reasonable or if I missed something?
Datatype | |||||
---|---|---|---|---|---|
Static | Parameterized | Parameterized (restricted) | Dynamic (runtime) | ||
Output Size / Shape | Single | Output[INT32] |
[T <: DataType] Output[T] |
[T: IsIntOrFloat] Output[T]) |
UntypedOutput |
Multiple fixed size | (Output[INT32], Output[FLOAT32]) |
[T <: DataType, U <: DataType](Output[T], Output[U]) |
[T: IsIntOrFloat, U: IsFloatingPoint](Output[T], Output[U])) |
(UntypedOutput, UntypedOutput) |
|
Multiple dynamic size (homogeneous) | Seq[Output[INT32]] |
[T <: DataType] Seq[Output[T]] |
[T: IsIntOrFloat] Seq[Output[T]] |
Seq[UntypedOutput] |
|
Multiple dynamic size (heterogeneous) | - | - | - | Seq[UntypedOutput] |
|
Combined fixed size and homogeneous dynamic | (Seq[Output[INT32]], Seq[Output[FLOAT32]]) |
[T <: DataType, U <: DataType](Seq[Output[T]], Seq[Output[U]]) |
[T: IsIntOrFloat, U: IsFloatingPoint](Seq[Output[T]], Seq[Output[U]]) |
(Seq[UntypedOutput], Seq[UntypedOutput]) |
|
Combined fixed size and heterogeneous dynamic | - | - | - | (Seq[UntypedOutput], Seq[UntypedOutput]) |
It would be nice for the op outputs to be strongly-typed (e.g., an op returns an INT32 output and a FLOAT32 output). Using an HList might be necessary for that. However, the problem lies with ops that have a variable number of inputs/outputs that are only known at runtime. This means it may be impossible to do this.
One example is an op that returns two lists of tensors. In the C API that would be represented as a single list of tensors that is the concatenation of the two lists. In this case, we would like to have an HList with two elements, each being a list of tensors of the appropriate data type. However, that would be impossible to resolve at compile-time since the number of tensors in each list may be unknown at that time. The
Unpack
op, for example, returns a list of tensors of unknown length.