v0.3.0-dev-18 #459
@ -7,6 +7,7 @@ description = "Google tensorflow connector"
|
|||||||
dependencies {
|
dependencies {
|
||||||
api(project(":kmath-tensors"))
|
api(project(":kmath-tensors"))
|
||||||
api("org.tensorflow:tensorflow-core-api:0.3.3")
|
api("org.tensorflow:tensorflow-core-api:0.3.3")
|
||||||
|
testImplementation("org.tensorflow:tensorflow-core-platform:0.3.3")
|
||||||
}
|
}
|
||||||
|
|
||||||
readme {
|
readme {
|
||||||
|
@ -5,6 +5,7 @@ import org.tensorflow.Output
|
|||||||
import org.tensorflow.ndarray.NdArray
|
import org.tensorflow.ndarray.NdArray
|
||||||
import org.tensorflow.op.core.Constant
|
import org.tensorflow.op.core.Constant
|
||||||
import org.tensorflow.types.TFloat64
|
import org.tensorflow.types.TFloat64
|
||||||
|
import space.kscience.kmath.expressions.Symbol
|
||||||
import space.kscience.kmath.misc.PerformancePitfall
|
import space.kscience.kmath.misc.PerformancePitfall
|
||||||
import space.kscience.kmath.nd.DefaultStrides
|
import space.kscience.kmath.nd.DefaultStrides
|
||||||
import space.kscience.kmath.nd.Shape
|
import space.kscience.kmath.nd.Shape
|
||||||
@ -13,20 +14,22 @@ import space.kscience.kmath.operations.DoubleField
|
|||||||
|
|
||||||
public class DoubleTensorFlowOutput(
|
public class DoubleTensorFlowOutput(
|
||||||
graph: Graph,
|
graph: Graph,
|
||||||
output: Output<TFloat64>
|
output: Output<TFloat64>,
|
||||||
) : TensorFlowOutput<Double, TFloat64>(graph, output) {
|
) : TensorFlowOutput<Double, TFloat64>(graph, output) {
|
||||||
override fun org.tensorflow.Tensor.actualizeTensor(): NdArray<Double> = output.asTensor()
|
|
||||||
|
override fun org.tensorflow.Tensor.actualizeTensor(): NdArray<Double> = this as TFloat64
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DoubleTensorFlowAlgebra internal constructor(
|
public class DoubleTensorFlowAlgebra internal constructor(
|
||||||
graph: Graph
|
graph: Graph,
|
||||||
) : TensorFlowAlgebra<Double, TFloat64, DoubleField>(graph) {
|
) : TensorFlowAlgebra<Double, TFloat64, DoubleField>(graph) {
|
||||||
|
|
||||||
override val elementAlgebra: DoubleField get() = DoubleField
|
override val elementAlgebra: DoubleField get() = DoubleField
|
||||||
|
|
||||||
override fun structureND(
|
override fun structureND(
|
||||||
shape: Shape,
|
shape: Shape,
|
||||||
initializer: DoubleField.(IntArray) -> Double
|
initializer: DoubleField.(IntArray) -> Double,
|
||||||
): StructureND<Double> {
|
): StructureND<Double> {
|
||||||
val res = TFloat64.tensorOf(org.tensorflow.ndarray.Shape.of(*shape.toLongArray())) { array ->
|
val res = TFloat64.tensorOf(org.tensorflow.ndarray.Shape.of(*shape.toLongArray())) { array ->
|
||||||
DefaultStrides(shape).forEach { index ->
|
DefaultStrides(shape).forEach { index ->
|
||||||
@ -53,4 +56,20 @@ public class DoubleTensorFlowAlgebra internal constructor(
|
|||||||
override fun Output<TFloat64>.wrap(): TensorFlowOutput<Double, TFloat64> = DoubleTensorFlowOutput(graph, this)
|
override fun Output<TFloat64>.wrap(): TensorFlowOutput<Double, TFloat64> = DoubleTensorFlowOutput(graph, this)
|
||||||
|
|
||||||
override fun const(value: Double): Constant<TFloat64> = ops.constant(value)
|
override fun const(value: Double): Constant<TFloat64> = ops.constant(value)
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun DoubleField.produceWithTF(
|
||||||
|
block: DoubleTensorFlowAlgebra.() -> StructureND<Double>,
|
||||||
|
): StructureND<Double> = Graph().use { graph ->
|
||||||
|
val scope = DoubleTensorFlowAlgebra(graph)
|
||||||
|
scope.export(scope.block())
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun DoubleField.produceMapWithTF(
|
||||||
|
block: DoubleTensorFlowAlgebra.() -> Map<Symbol, StructureND<Double>>,
|
||||||
|
): Map<Symbol, StructureND<Double>> = Graph().use { graph ->
|
||||||
|
val scope = DoubleTensorFlowAlgebra(graph)
|
||||||
|
scope.block().mapValues { scope.export(it.value) }
|
||||||
}
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package space.kscience.kmath.tensorflow
|
||||||
|
|
||||||
|
import org.tensorflow.Graph
|
||||||
|
import org.tensorflow.Output
|
||||||
|
import org.tensorflow.ndarray.NdArray
|
||||||
|
import org.tensorflow.types.TInt32
|
||||||
|
import org.tensorflow.types.TInt64
|
||||||
|
|
||||||
|
public class IntTensorFlowOutput(
|
||||||
|
graph: Graph,
|
||||||
|
output: Output<TInt32>,
|
||||||
|
) : TensorFlowOutput<Int, TInt32>(graph, output) {
|
||||||
|
override fun org.tensorflow.Tensor.actualizeTensor(): NdArray<Int> = this as TInt32
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LongTensorFlowOutput(
|
||||||
|
graph: Graph,
|
||||||
|
output: Output<TInt64>,
|
||||||
|
) : TensorFlowOutput<Long, TInt64>(graph, output) {
|
||||||
|
override fun org.tensorflow.Tensor.actualizeTensor(): NdArray<Long> = this as TInt64
|
||||||
|
}
|
@ -8,8 +8,13 @@ import org.tensorflow.Session
|
|||||||
import org.tensorflow.ndarray.NdArray
|
import org.tensorflow.ndarray.NdArray
|
||||||
import org.tensorflow.op.Ops
|
import org.tensorflow.op.Ops
|
||||||
import org.tensorflow.op.core.Constant
|
import org.tensorflow.op.core.Constant
|
||||||
|
import org.tensorflow.op.core.Max
|
||||||
|
import org.tensorflow.op.core.Min
|
||||||
|
import org.tensorflow.op.core.Sum
|
||||||
|
import org.tensorflow.types.TInt32
|
||||||
import org.tensorflow.types.family.TType
|
import org.tensorflow.types.family.TType
|
||||||
import space.kscience.kmath.misc.PerformancePitfall
|
import space.kscience.kmath.misc.PerformancePitfall
|
||||||
|
import space.kscience.kmath.misc.UnstableKMathAPI
|
||||||
import space.kscience.kmath.nd.Shape
|
import space.kscience.kmath.nd.Shape
|
||||||
import space.kscience.kmath.nd.StructureND
|
import space.kscience.kmath.nd.StructureND
|
||||||
import space.kscience.kmath.operations.Ring
|
import space.kscience.kmath.operations.Ring
|
||||||
@ -38,8 +43,8 @@ public value class TensorFlowArray<T>(public val tensor: NdArray<T>) : Tensor<T>
|
|||||||
}
|
}
|
||||||
|
|
||||||
public abstract class TensorFlowOutput<T, TT : TType>(
|
public abstract class TensorFlowOutput<T, TT : TType>(
|
||||||
private val graph: Graph,
|
protected val graph: Graph,
|
||||||
output: Output<TT>
|
output: Output<TT>,
|
||||||
) : TensorFlowTensor<T> {
|
) : TensorFlowTensor<T> {
|
||||||
|
|
||||||
public var output: Output<TT> = output
|
public var output: Output<TT> = output
|
||||||
@ -49,9 +54,10 @@ public abstract class TensorFlowOutput<T, TT : TType>(
|
|||||||
|
|
||||||
protected abstract fun org.tensorflow.Tensor.actualizeTensor(): NdArray<T>
|
protected abstract fun org.tensorflow.Tensor.actualizeTensor(): NdArray<T>
|
||||||
|
|
||||||
private val actualTensor by lazy {
|
internal val actualTensor by lazy {
|
||||||
val session = Session(graph)
|
Session(graph).use { session ->
|
||||||
TensorFlowArray(session.runner().fetch(output).run().first().actualizeTensor())
|
TensorFlowArray(session.runner().fetch(output).run().first().actualizeTensor())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun get(index: IntArray): T = actualTensor[index]
|
override fun get(index: IntArray): T = actualTensor[index]
|
||||||
@ -66,9 +72,9 @@ public abstract class TensorFlowOutput<T, TT : TType>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public abstract class TensorFlowAlgebra<T, TT : TType, A: Ring<T>> internal constructor(
|
public abstract class TensorFlowAlgebra<T, TT : TType, A : Ring<T>> internal constructor(
|
||||||
protected val graph: Graph
|
protected val graph: Graph,
|
||||||
) : TensorAlgebra<T,A> {
|
) : TensorAlgebra<T, A> {
|
||||||
|
|
||||||
protected val ops: Ops by lazy { Ops.create(graph) }
|
protected val ops: Ops by lazy { Ops.create(graph) }
|
||||||
|
|
||||||
@ -83,7 +89,7 @@ public abstract class TensorFlowAlgebra<T, TT : TType, A: Ring<T>> internal cons
|
|||||||
|
|
||||||
private inline fun StructureND<T>.biOp(
|
private inline fun StructureND<T>.biOp(
|
||||||
other: StructureND<T>,
|
other: StructureND<T>,
|
||||||
operation: (left: Operand<TT>, right: Operand<TT>) -> Operand<TT>
|
operation: (left: Operand<TT>, right: Operand<TT>) -> Operand<TT>,
|
||||||
): TensorFlowOutput<T, TT> {
|
): TensorFlowOutput<T, TT> {
|
||||||
val left = asTensorFlow().output
|
val left = asTensorFlow().output
|
||||||
val right = other.asTensorFlow().output
|
val right = other.asTensorFlow().output
|
||||||
@ -92,7 +98,7 @@ public abstract class TensorFlowAlgebra<T, TT : TType, A: Ring<T>> internal cons
|
|||||||
|
|
||||||
private inline fun T.biOp(
|
private inline fun T.biOp(
|
||||||
other: StructureND<T>,
|
other: StructureND<T>,
|
||||||
operation: (left: Operand<TT>, right: Operand<TT>) -> Operand<TT>
|
operation: (left: Operand<TT>, right: Operand<TT>) -> Operand<TT>,
|
||||||
): TensorFlowOutput<T, TT> {
|
): TensorFlowOutput<T, TT> {
|
||||||
val left = const(this)
|
val left = const(this)
|
||||||
val right = other.asTensorFlow().output
|
val right = other.asTensorFlow().output
|
||||||
@ -101,7 +107,7 @@ public abstract class TensorFlowAlgebra<T, TT : TType, A: Ring<T>> internal cons
|
|||||||
|
|
||||||
private inline fun StructureND<T>.biOp(
|
private inline fun StructureND<T>.biOp(
|
||||||
value: T,
|
value: T,
|
||||||
operation: (left: Operand<TT>, right: Operand<TT>) -> Operand<TT>
|
operation: (left: Operand<TT>, right: Operand<TT>) -> Operand<TT>,
|
||||||
): TensorFlowOutput<T, TT> {
|
): TensorFlowOutput<T, TT> {
|
||||||
val left = asTensorFlow().output
|
val left = asTensorFlow().output
|
||||||
val right = const(value)
|
val right = const(value)
|
||||||
@ -110,7 +116,7 @@ public abstract class TensorFlowAlgebra<T, TT : TType, A: Ring<T>> internal cons
|
|||||||
|
|
||||||
private inline fun Tensor<T>.inPlaceOp(
|
private inline fun Tensor<T>.inPlaceOp(
|
||||||
other: StructureND<T>,
|
other: StructureND<T>,
|
||||||
operation: (left: Operand<TT>, right: Operand<TT>) -> Operand<TT>
|
operation: (left: Operand<TT>, right: Operand<TT>) -> Operand<TT>,
|
||||||
): Unit {
|
): Unit {
|
||||||
val origin = asTensorFlow()
|
val origin = asTensorFlow()
|
||||||
val left = origin.output
|
val left = origin.output
|
||||||
@ -120,7 +126,7 @@ public abstract class TensorFlowAlgebra<T, TT : TType, A: Ring<T>> internal cons
|
|||||||
|
|
||||||
private inline fun Tensor<T>.inPlaceOp(
|
private inline fun Tensor<T>.inPlaceOp(
|
||||||
value: T,
|
value: T,
|
||||||
operation: (left: Operand<TT>, right: Operand<TT>) -> Operand<TT>
|
operation: (left: Operand<TT>, right: Operand<TT>) -> Operand<TT>,
|
||||||
): Unit {
|
): Unit {
|
||||||
val origin = asTensorFlow()
|
val origin = asTensorFlow()
|
||||||
val left = origin.output
|
val left = origin.output
|
||||||
@ -128,8 +134,8 @@ public abstract class TensorFlowAlgebra<T, TT : TType, A: Ring<T>> internal cons
|
|||||||
origin.output = operation(left, right).asOutput()
|
origin.output = operation(left, right).asOutput()
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun unOp(value: StructureND<T>, operation: (Operand<TT>) -> Operand<TT>): TensorFlowOutput<T, TT> =
|
private inline fun StructureND<T>.unOp(operation: (Operand<TT>) -> Operand<TT>): TensorFlowOutput<T, TT> =
|
||||||
operation(value.asTensorFlow().output).asOutput().wrap()
|
operation(asTensorFlow().output).asOutput().wrap()
|
||||||
|
|
||||||
override fun T.plus(arg: StructureND<T>): TensorFlowOutput<T, TT> = biOp(arg, ops.math::add)
|
override fun T.plus(arg: StructureND<T>): TensorFlowOutput<T, TT> = biOp(arg, ops.math::add)
|
||||||
|
|
||||||
@ -149,67 +155,79 @@ public abstract class TensorFlowAlgebra<T, TT : TType, A: Ring<T>> internal cons
|
|||||||
|
|
||||||
override fun Tensor<T>.minusAssign(value: T): Unit = inPlaceOp(value, ops.math::sub)
|
override fun Tensor<T>.minusAssign(value: T): Unit = inPlaceOp(value, ops.math::sub)
|
||||||
|
|
||||||
override fun Tensor<T>.minusAssign(other: StructureND<T>): Unit = inPlaceOp(other, ops.math::sub)
|
override fun Tensor<T>.minusAssign(arg: StructureND<T>): Unit = inPlaceOp(arg, ops.math::sub)
|
||||||
|
|
||||||
override fun T.times(arg: StructureND<T>): TensorFlowOutput<T, TT> = biOp(arg, ops.math::mul)
|
override fun T.times(arg: StructureND<T>): TensorFlowOutput<T, TT> = biOp(arg, ops.math::mul)
|
||||||
|
|
||||||
override fun StructureND<T>.times(arg: T): TensorFlowOutput<T, TT> = biOp(arg, ops.math::mul)
|
override fun StructureND<T>.times(arg: T): TensorFlowOutput<T, TT> = biOp(arg, ops.math::mul)
|
||||||
|
|
||||||
override fun StructureND<T>.times(other: StructureND<T>): TensorFlowOutput<T, TT> = biOp(other, ops.math::mul)
|
override fun StructureND<T>.times(arg: StructureND<T>): TensorFlowOutput<T, TT> = biOp(arg, ops.math::mul)
|
||||||
|
|
||||||
override fun Tensor<T>.timesAssign(value: T): Unit = inPlaceOp(value, ops.math::mul)
|
override fun Tensor<T>.timesAssign(value: T): Unit = inPlaceOp(value, ops.math::mul)
|
||||||
|
|
||||||
override fun Tensor<T>.timesAssign(arg: StructureND<T>): Unit = inPlaceOp(arg, ops.math::mul)
|
override fun Tensor<T>.timesAssign(arg: StructureND<T>): Unit = inPlaceOp(arg, ops.math::mul)
|
||||||
|
|
||||||
override fun StructureND<T>.unaryMinus(): TensorFlowOutput<T, TT> = unOp(this, ops.math::neg)
|
override fun StructureND<T>.unaryMinus(): TensorFlowOutput<T, TT> = unOp(ops.math::neg)
|
||||||
|
|
||||||
override fun StructureND<T>.get(i: Int): Tensor<T> {
|
override fun Tensor<T>.get(i: Int): Tensor<T> = unOp {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun StructureND<T>.transpose(i: Int, j: Int): Tensor<T> = unOp(this) {
|
override fun Tensor<T>.transpose(i: Int, j: Int): Tensor<T> = unOp {
|
||||||
ops.linalg.transpose(it, ops.constant(intArrayOf(i, j)))
|
ops.linalg.transpose(it, ops.constant(intArrayOf(i, j)))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun Tensor<T>.view(shape: IntArray): Tensor<T> {
|
override fun Tensor<T>.view(shape: IntArray): Tensor<T> = unOp {
|
||||||
TODO("Not yet implemented")
|
ops.reshape(it, ops.constant(shape))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun Tensor<T>.viewAs(other: StructureND<T>): Tensor<T> {
|
override fun Tensor<T>.viewAs(other: StructureND<T>): Tensor<T> = biOp(other) { l, r ->
|
||||||
TODO("Not yet implemented")
|
ops.reshape(l, ops.shape(r))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun StructureND<T>.dot(other: StructureND<T>): TensorFlowOutput<T, TT> = biOp(other) { l, r ->
|
override fun StructureND<T>.dot(other: StructureND<T>): TensorFlowOutput<T, TT> = biOp(other) { l, r ->
|
||||||
ops.linalg.matMul(l, r)
|
ops.linalg.matMul(l, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun diagonalEmbedding(diagonalEntries: Tensor<T>, offset: Int, dim1: Int, dim2: Int): Tensor<T> = ops.run {
|
override fun diagonalEmbedding(
|
||||||
TODO("Not yet implemented")
|
diagonalEntries: Tensor<T>,
|
||||||
|
offset: Int,
|
||||||
|
dim1: Int,
|
||||||
|
dim2: Int,
|
||||||
|
): TensorFlowOutput<T, TT> = diagonalEntries.unOp {
|
||||||
|
TODO()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun StructureND<T>.sum(): T = TODO("Not yet implemented")
|
override fun StructureND<T>.sum(): T = unOp {
|
||||||
|
ops.sum(it, ops.constant(intArrayOf()))
|
||||||
|
}.value()
|
||||||
|
|
||||||
override fun StructureND<T>.sum(dim: Int, keepDim: Boolean): Tensor<T> {
|
override fun StructureND<T>.sum(dim: Int, keepDim: Boolean): TensorFlowOutput<T, TT> = unOp {
|
||||||
TODO("Not yet implemented")
|
ops.sum(it, ops.constant(dim), Sum.keepDims(keepDim))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun StructureND<T>.min(): T {
|
override fun StructureND<T>.min(): T = unOp {
|
||||||
TODO("Not yet implemented")
|
ops.min(it, ops.constant(intArrayOf()))
|
||||||
|
}.value()
|
||||||
|
|
||||||
|
override fun StructureND<T>.min(dim: Int, keepDim: Boolean): Tensor<T> = unOp {
|
||||||
|
ops.min(it, ops.constant(dim), Min.keepDims(keepDim))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun StructureND<T>.min(dim: Int, keepDim: Boolean): Tensor<T> {
|
override fun StructureND<T>.max(): T = unOp {
|
||||||
TODO("Not yet implemented")
|
ops.max(it, ops.constant(intArrayOf()))
|
||||||
|
}.value()
|
||||||
|
|
||||||
|
override fun StructureND<T>.max(dim: Int, keepDim: Boolean): Tensor<T> = unOp {
|
||||||
|
ops.max(it, ops.constant(dim), Max.keepDims(keepDim))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun StructureND<T>.max(): T {
|
override fun StructureND<T>.argMax(dim: Int, keepDim: Boolean): Tensor<Int> = IntTensorFlowOutput(
|
||||||
TODO("Not yet implemented")
|
graph,
|
||||||
}
|
ops.math.argMax(asTensorFlow().output, ops.constant(dim), TInt32::class.java).output()
|
||||||
|
).actualTensor
|
||||||
|
|
||||||
override fun StructureND<T>.max(dim: Int, keepDim: Boolean): Tensor<T> {
|
@OptIn(UnstableKMathAPI::class)
|
||||||
TODO("Not yet implemented")
|
override fun export(arg: StructureND<T>): StructureND<T> =
|
||||||
}
|
if (arg is TensorFlowOutput<T, *>) arg.actualTensor else arg
|
||||||
|
|
||||||
override fun StructureND<T>.argMax(dim: Int, keepDim: Boolean): Tensor<T> {
|
|
||||||
TODO("Not yet implemented")
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package space.kscience.kmath.tensorflow
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import space.kscience.kmath.nd.StructureND
|
||||||
|
import space.kscience.kmath.nd.structureND
|
||||||
|
import space.kscience.kmath.operations.DoubleField
|
||||||
|
|
||||||
|
class DoubleTensorFlowOps {
|
||||||
|
@Test
|
||||||
|
fun basicOps() {
|
||||||
|
val res = DoubleField.produceWithTF {
|
||||||
|
val initial = structureND(2, 2) { 1.0 }
|
||||||
|
|
||||||
|
initial + (initial * 2.0)
|
||||||
|
}
|
||||||
|
println(StructureND.toString(res))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -3,6 +3,8 @@
|
|||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@file:OptIn(PerformancePitfall::class)
|
||||||
|
|
||||||
package space.kscience.kmath.viktor
|
package space.kscience.kmath.viktor
|
||||||
|
|
||||||
import org.jetbrains.bio.viktor.F64Array
|
import org.jetbrains.bio.viktor.F64Array
|
||||||
|
Loading…
Reference in New Issue
Block a user