analytic tests and examples #314

Merged
AndreiKingsley merged 1 commits from andrew into feature/tensor-algebra 2021-05-05 18:11:56 +03:00
4 changed files with 186 additions and 18 deletions

View File

@ -0,0 +1,46 @@
/*
* Copyright 2018-2021 KMath contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package space.kscience.kmath.tensors
import space.kscience.kmath.operations.invoke
import space.kscience.kmath.tensors.core.algebras.BroadcastDoubleTensorAlgebra
import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra
// Dataset normalization
fun main() {
// work in context with analytic methods
DoubleAnalyticTensorAlgebra {
// take dataset of 5-element vectors from normal distribution
val dataset = randomNormal(intArrayOf(100, 5)) * 1.5 // all elements from N(0, 1.5)
BroadcastDoubleTensorAlgebra {
dataset += fromArray(
intArrayOf(5),
doubleArrayOf(0.0, 1.0, 1.5, 3.0, 5.0) // rows means
)
}
// find out mean and standard deviation of each column
val mean = dataset.mean(0, false)
val std = dataset.std(0, false)
println("Mean:\n$mean")
println("Standard deviation:\n$std")
// also we can calculate other statistic as minimum and maximum of rows
println("Minimum:\n${dataset.min(0, false)}")
println("Maximum:\n${dataset.max(0, false)}")
// now we can scale dataset with mean normalization
val datasetScaled = BroadcastDoubleTensorAlgebra { (dataset - mean) / std }
// find out mean and std of scaled dataset
println("Mean of scaled:\n${datasetScaled.mean(0, false)}")
println("Mean of scaled:\n${datasetScaled.std(0, false)}")
}
}

View File

@ -51,7 +51,6 @@ public interface AnalyticTensorAlgebra<T> :
*/ */
public fun Tensor<T>.max(dim: Int, keepDim: Boolean): Tensor<T> public fun Tensor<T>.max(dim: Int, keepDim: Boolean): Tensor<T>
/** /**
* @return the mean of all elements in the input tensor. * @return the mean of all elements in the input tensor.
*/ */
@ -110,7 +109,7 @@ public interface AnalyticTensorAlgebra<T> :
public fun Tensor<T>.exp(): Tensor<T> public fun Tensor<T>.exp(): Tensor<T>
//For information: https://pytorch.org/docs/stable/generated/torch.log.html //For information: https://pytorch.org/docs/stable/generated/torch.log.html
public fun Tensor<T>.log(): Tensor<T> public fun Tensor<T>.ln(): Tensor<T>
//For information: https://pytorch.org/docs/stable/generated/torch.sqrt.html //For information: https://pytorch.org/docs/stable/generated/torch.sqrt.html
public fun Tensor<T>.sqrt(): Tensor<T> public fun Tensor<T>.sqrt(): Tensor<T>

View File

@ -25,7 +25,6 @@ public object DoubleAnalyticTensorAlgebra :
override fun Tensor<Double>.max(dim: Int, keepDim: Boolean): DoubleTensor = override fun Tensor<Double>.max(dim: Int, keepDim: Boolean): DoubleTensor =
foldDim({ x -> x.maxOrNull()!! }, dim, keepDim) foldDim({ x -> x.maxOrNull()!! }, dim, keepDim)
override fun Tensor<Double>.mean(): Double = this.fold { it.sum() / tensor.numElements } override fun Tensor<Double>.mean(): Double = this.fold { it.sum() / tensor.numElements }
override fun Tensor<Double>.mean(dim: Int, keepDim: Boolean): DoubleTensor = override fun Tensor<Double>.mean(dim: Int, keepDim: Boolean): DoubleTensor =
@ -70,7 +69,7 @@ public object DoubleAnalyticTensorAlgebra :
override fun Tensor<Double>.exp(): DoubleTensor = tensor.map(::exp) override fun Tensor<Double>.exp(): DoubleTensor = tensor.map(::exp)
override fun Tensor<Double>.log(): DoubleTensor = tensor.map(::ln) override fun Tensor<Double>.ln(): DoubleTensor = tensor.map(::ln)
override fun Tensor<Double>.sqrt(): DoubleTensor = tensor.map(::sqrt) override fun Tensor<Double>.sqrt(): DoubleTensor = tensor.map(::sqrt)

View File

@ -2,35 +2,159 @@ package space.kscience.kmath.tensors.core
import space.kscience.kmath.operations.invoke import space.kscience.kmath.operations.invoke
import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra
import kotlin.math.abs import space.kscience.kmath.tensors.core.algebras.DoubleAnalyticTensorAlgebra.tan
import kotlin.math.exp import kotlin.math.*
import kotlin.test.Test import kotlin.test.Test
import kotlin.test.assertTrue import kotlin.test.assertTrue
internal class TestDoubleAnalyticTensorAlgebra { internal class TestDoubleAnalyticTensorAlgebra {
val shape = intArrayOf(2, 1, 3, 2) val shape = intArrayOf(2, 1, 3, 2)
val buffer = doubleArrayOf(27.1, 20.0, 19.84, 23.123, 0.0, 1.0, 3.23, 133.7, 25.3, 100.3, 11.0, 12.012) val buffer = doubleArrayOf(
27.1, 20.0, 19.84,
23.123, 3.0, 2.0,
3.23, 133.7, 25.3,
100.3, 11.0, 12.012
)
val tensor = DoubleTensor(shape, buffer) val tensor = DoubleTensor(shape, buffer)
fun DoubleArray.fmap(transform: (Double) -> Double): DoubleArray { fun DoubleArray.fmap(transform: (Double) -> Double): DoubleArray {
return this.map(transform).toDoubleArray() return this.map(transform).toDoubleArray()
} }
fun DoubleArray.epsEqual(other: DoubleArray, eps: Double = 1e-5): Boolean { fun expectedTensor(transform: (Double) -> Double): DoubleTensor {
for ((elem1, elem2) in this.asSequence().zip(other.asSequence())) { return DoubleTensor(shape, buffer.fmap(transform))
if (abs(elem1 - elem2) > eps) {
return false
}
}
return true
} }
@Test @Test
fun testExp() = DoubleAnalyticTensorAlgebra { fun testExp() = DoubleAnalyticTensorAlgebra {
tensor.exp().let { assertTrue { tensor.exp() eq expectedTensor(::exp) }
assertTrue { shape contentEquals it.shape }
assertTrue { buffer.fmap(::exp).epsEqual(it.mutableBuffer.array())}
}
} }
@Test
fun testLog() = DoubleAnalyticTensorAlgebra {
assertTrue { tensor.ln() eq expectedTensor(::ln) }
}
@Test
fun testSqrt() = DoubleAnalyticTensorAlgebra {
assertTrue { tensor.sqrt() eq expectedTensor(::sqrt) }
}
@Test
fun testCos() = DoubleAnalyticTensorAlgebra {
assertTrue { tensor.cos() eq expectedTensor(::cos) }
}
@Test
fun testCosh() = DoubleAnalyticTensorAlgebra {
assertTrue { tensor.cosh() eq expectedTensor(::cosh) }
}
@Test
fun testAcosh() = DoubleAnalyticTensorAlgebra {
assertTrue { tensor.acosh() eq expectedTensor(::acosh) }
}
@Test
fun testSin() = DoubleAnalyticTensorAlgebra {
assertTrue { tensor.sin() eq expectedTensor(::sin) }
}
@Test
fun testSinh() = DoubleAnalyticTensorAlgebra {
assertTrue { tensor.sinh() eq expectedTensor(::sinh) }
}
@Test
fun testAsinh() = DoubleAnalyticTensorAlgebra {
assertTrue { tensor.asinh() eq expectedTensor(::asinh) }
}
@Test
fun testTan() = DoubleAnalyticTensorAlgebra {
assertTrue { tensor.tan() eq expectedTensor(::tan) }
}
@Test
fun testAtan() = DoubleAnalyticTensorAlgebra {
assertTrue { tensor.atan() eq expectedTensor(::atan) }
}
@Test
fun testTanh() = DoubleAnalyticTensorAlgebra {
assertTrue { tensor.tanh() eq expectedTensor(::tanh) }
}
@Test
fun testCeil() = DoubleAnalyticTensorAlgebra {
assertTrue { tensor.ceil() eq expectedTensor(::ceil) }
}
@Test
fun testFloor() = DoubleAnalyticTensorAlgebra {
assertTrue { tensor.floor() eq expectedTensor(::floor) }
}
val shape2 = intArrayOf(2, 2)
val buffer2 = doubleArrayOf(
1.0, 2.0,
-3.0, 4.0
)
val tensor2 = DoubleTensor(shape2, buffer2)
@Test
fun testMin() = DoubleAnalyticTensorAlgebra {
assertTrue { tensor2.min() == -3.0 }
assertTrue { tensor2.min(0, true) eq fromArray(
intArrayOf(1, 2),
doubleArrayOf(-3.0, 2.0)
)}
assertTrue { tensor2.min(1, false) eq fromArray(
intArrayOf(2),
doubleArrayOf(1.0, -3.0)
)}
}
@Test
fun testMax() = DoubleAnalyticTensorAlgebra {
assertTrue { tensor2.max() == 4.0 }
assertTrue { tensor2.max(0, true) eq fromArray(
intArrayOf(1, 2),
doubleArrayOf(1.0, 4.0)
)}
assertTrue { tensor2.max(1, false) eq fromArray(
intArrayOf(2),
doubleArrayOf(2.0, 4.0)
)}
}
@Test
fun testSum() = DoubleAnalyticTensorAlgebra {
assertTrue { tensor2.sum() == 4.0 }
assertTrue { tensor2.sum(0, true) eq fromArray(
intArrayOf(1, 2),
doubleArrayOf(-2.0, 6.0)
)}
assertTrue { tensor2.sum(1, false) eq fromArray(
intArrayOf(2),
doubleArrayOf(3.0, 1.0)
)}
}
@Test
fun testMean() = DoubleAnalyticTensorAlgebra {
assertTrue { tensor2.mean() == 1.0 }
assertTrue { tensor2.mean(0, true) eq fromArray(
intArrayOf(1, 2),
doubleArrayOf(-1.0, 3.0)
)}
assertTrue { tensor2.mean(1, false) eq fromArray(
intArrayOf(2),
doubleArrayOf(1.5, 0.5)
)}
}
} }