Skip to content

Commit

Permalink
Add script to get model files; Update Type-safe Tensor README section…
Browse files Browse the repository at this point in the history
…; Have Travis run mdoc again; add TODOs
  • Loading branch information
EmergentOrder committed Nov 6, 2019
1 parent 2ece2b7 commit d9d93e8
Show file tree
Hide file tree
Showing 6 changed files with 82 additions and 51 deletions.
2 changes: 2 additions & 0 deletions .travis.yml
@@ -1,3 +1,5 @@
language: scala
script:
- bash get_models.sh
- sbt +test -J-Xmx5G
- sbt docsJVM/mdoc
84 changes: 50 additions & 34 deletions README.md
Expand Up @@ -18,7 +18,7 @@ As of v0.1.0, artifacts are published to Sonatype OSS / Maven Central. For the l

### Full ONNX model inference quick start

First, download the [model file](https://s3.amazonaws.com/download.onnx/models/opset_8/squeezenet.tar.gz) for [SqueezeNet](https://en.wikipedia.org/wiki/SqueezeNet), extracting and renaming.
First, download the [model file](https://s3.amazonaws.com/onnx-model-zoo/squeezenet/squeezenet1.1/squeezenet1.1.onnx) for [SqueezeNet](https://en.wikipedia.org/wiki/SqueezeNet).

Using the console, from this project root:

Expand All @@ -41,7 +41,7 @@ import java.nio.file.{Files, Paths}
import org.emergentorder.onnx.{Tensor, TensorFactory}
import org.emergentorder.onnx.backends.NGraphBackendFull

val squeezenet = Files.readAllBytes(Paths.get("squeezenet.onnx"))
val squeezenet = Files.readAllBytes(Paths.get("squeezenet1.1.onnx"))

val backend = new NGraphBackendFull()

Expand All @@ -55,21 +55,21 @@ val out: Tensor[Float] = backend.fullModel(squeezenet, (Some(tens), None, None,
// 0
// out: (Array[Float], Array[Int], org.emergentorder.onnx.package.Axes) = (
// Array(
// 1.7861872E-4F,
// 0.0011791866F,
// 3.2175478E-4F,
// 2.3761144E-4F,
// 0.0012107284F,
// 0.8230884F,
// 2.3508213F,
// 5.1132765F,
// 4.885488F,
// 5.4786053F,
// ...

out._1.size
// res0: Int = 1000

out._1.indices.maxBy(out._1)
// res1: Int = 549
// res1: Int = 418
```

Referring to the [ImageNet 1000 class labels](https://gist.github.com/yrevar/942d3a0ac09ec9e5eb3a), we see that the predicted class is "envelope".
Referring to the [ImageNet 1000 class labels](https://gist.github.com/yrevar/942d3a0ac09ec9e5eb3a), we see that the predicted class is "ballpoint pen".

### Operator-level (Fine-grained) API

Expand Down Expand Up @@ -251,64 +251,67 @@ Currently at ONNX 1.6.0.

## Type-safe Tensors (Experimental, Scala 2.13 only)

Featuring type-checked axis labels (Dim), which along with literal types (new in Scala 2.13) for dimension sizes allow for axes-typed/shape-typed (Axes) tensors (TypesafeTensor).
Using ONNX docs for [dimension](https://github.com/onnx/onnx/blob/master/docs/DimensionDenotation.md) and [type](https://github.com/onnx/onnx/blob/master/docs/TypeDenotation.md) denotation as a reference,
and inspired by [Nexus](https://github.com/ctongfei/nexus), [Neurocat](https://github.com/mandubian/neurocat) and [Named Tensors](https://pytorch.org/docs/stable/named_tensor.html).

```scala
import org.emergentorder.onnx._

trait Image extends Dim
trait DataBatch extends Dim
trait DataChannel extends Dim
trait DataFeature extends Dim

val imageAxes = new Tuple3OfDim(3, new Image{}, 224, new Image{},224, new Image{})
val imageAxes = new Tuple3OfDim(3, new DataChannel{}, 224, new DataFeature{},224, new DataFeature{})
type ImageAxes = imageAxes.type
type ImageTensor = TypesafeTensor[Float, ImageAxes]

val typesafeTens: ImageTensor = TensorFactory.getTypesafeTensor(Array.fill(3*224*224){42f},imageAxes)
backend.Sqrt6[Float, ImageAxes]("sqrt", Some(typesafeTens))
backend.Sqrt6("sqrt", Some(typesafeTens))


trait Word extends Dim
val wordAxes = (new Vec(5, new Word{}))
type WordAxes = wordAxes.type
type WordTensor = TypesafeTensor[Float, WordAxes]
val textAxes = (new Vec(100, new DataFeature{}))
type TextAxes = textAxes.type
type TextTensor = TypesafeTensor[Float, TextAxes]

```

```scala
//Fails, as designed
//Fails at runtime, as designed
val wrongSizeDataTens: ImageTensor = TensorFactory.getTypesafeTensor(Array.fill(3*224*225){42f},imageAxes)
// java.lang.IllegalArgumentException: requirement failed
// at scala.Predef$.require(Predef.scala:327)
// at org.emergentorder.onnx.package$TensorFactory$.getTypesafeTensor(ONNX213.scala:93)
// at repl.Session$App$$anonfun$30.apply$mcV$sp(README.md:148)
// at repl.Session$App$$anonfun$30.apply(README.md:147)
// at repl.Session$App$$anonfun$30.apply(README.md:147)
// at org.emergentorder.onnx.package$TensorFactory$.getTypesafeTensor(ONNX213.scala:94)
// at repl.Session$App$$anonfun$30.apply$mcV$sp(README.md:151)
// at repl.Session$App$$anonfun$30.apply(README.md:150)
// at repl.Session$App$$anonfun$30.apply(README.md:150)
```

```scala
//Fails, as designed
//The rest fail to compile, as designed

val wordShouldBeImageTens: WordTensor = TensorFactory.getTypesafeTensor(Array.fill(3*224*224){42f},imageAxes)
val wordShouldBeImageTens: TextTensor = TensorFactory.getTypesafeTensor(Array.fill(3*224*224){42f},imageAxes)
// error: type mismatch;
// found : repl.Session.App.imageAxes.type (with underlying type org.emergentorder.onnx.Tuple3OfDim[3,repl.Session.App.Image,224,repl.Session.App.Image,224,repl.Session.App.Image])
// required: repl.Session.App.WordAxes
// (which expands to) repl.Session.App.wordAxes.type
// val wordShouldBeImageTens: WordTensor = TensorFactory.getTypesafeTensor(Array.fill(3*224*224){42f},imageAxes)
// found : repl.Session.App.imageAxes.type (with underlying type org.emergentorder.onnx.Tuple3OfDim[3,repl.Session.App.DataChannel,224,repl.Session.App.DataFeature,224,repl.Session.App.DataFeature])
// required: repl.Session.App.TextAxes
// (which expands to) repl.Session.App.textAxes.type
// val wordShouldBeImageTens: TextTensor = TensorFactory.getTypesafeTensor(Array.fill(3*224*224){42f},imageAxes)
// ^^^^^^^^^
```

```scala
//Fails, as designed
backend.Sqrt6[Float, WordAxes]("sqrt", Some(typesafeTens))
backend.Sqrt6[Float, TextAxes]("sqrt", Some(typesafeTens))
// error: type mismatch;
// found : repl.Session.App.ImageTensor
// (which expands to) (Array[Float], Array[Int], repl.Session.App.imageAxes.type)
// required: org.emergentorder.onnx.TypesafeTensor[Float,repl.Session.App.WordAxes]
// (which expands to) (Array[Float], Array[Int], repl.Session.App.wordAxes.type)
// backend.Sqrt6[Float, WordAxes]("sqrt", Some(typesafeTens))
// required: org.emergentorder.onnx.TypesafeTensor[Float,repl.Session.App.TextAxes]
// (which expands to) (Array[Float], Array[Int], repl.Session.App.textAxes.type)
// backend.Sqrt6[Float, TextAxes]("sqrt", Some(typesafeTens))
// ^^^^^^^^^^^^
```

```scala
//Fails, as designed
val wrongSizedImageAxes = (new Vec(15, new Image{}))
val wrongSizedImageAxes = (new Tuple3OfDim(15, new DataChannel{}, 224, new DataFeature{}, 224, new DataFeature{}))
type WrongSizedImageAxes = wrongSizedImageAxes.type
backend.Sqrt6[Float, WrongSizedImageAxes]("sqrt", Some(typesafeTens))
// error: type mismatch;
Expand All @@ -320,6 +323,19 @@ backend.Sqrt6[Float, WrongSizedImageAxes]("sqrt", Some(typesafeTens))
// ^^^^^^^^^^^^
```

```scala
val wrongDimTypeAxes = (new Tuple3OfDim(3, new DataBatch{}, 224, new DataFeature{}, 224, new DataFeature{}))
type WrongDimTypeAxes = wrongDimTypeAxes.type
backend.Sqrt6[Float, WrongDimTypeAxes]("sqrt", Some(typesafeTens))
// error: type mismatch;
// found : repl.Session.App.ImageTensor
// (which expands to) (Array[Float], Array[Int], repl.Session.App.imageAxes.type)
// required: org.emergentorder.onnx.TypesafeTensor[Float,repl.Session.App.WrongDimTypeAxes]
// (which expands to) (Array[Float], Array[Int], repl.Session.App.wrongDimTypeAxes.type)
// backend.Sqrt6[Float, WrongDimTypeAxes]("sqrt", Some(typesafeTens))
// ^^^^^^^^^^^^
```

### Built With

#### Core
Expand Down
1 change: 1 addition & 0 deletions core/src/main/scala/ONNX213.scala
Expand Up @@ -37,6 +37,7 @@ package object onnx {
sealed case class Vec[I <: XInt, T <: Dim](i: I, t: T) extends Axes
sealed case class Mat[I <: XInt, T <: Dim, J <: XInt, U <: Dim](i: I, t: T, j: J, u: U) extends Axes
sealed case class Tuple3OfDim[I <: XInt, T <: Dim, J <: XInt, U <: Dim, K <: XInt, V <: Dim](i:I, t:T, j:J, u:U, k: K, v: V) extends Axes
//TODO: 4+ dimensional

object AxesFactory {
def getAxes[T](shape: Array[XInt], dims: Array[Dim]): Axes = {
Expand Down
2 changes: 2 additions & 0 deletions core/src/main/scala/ONNXHelper.scala
Expand Up @@ -92,13 +92,15 @@ class ONNXHelper(val byteArray: Array[Byte]) extends AutoCloseable {

def onnxTensorProtoToArray(tensorProto: TensorProto) = {

//TODO: Get dim and type denotations here in 2.13 / earlier if possible
val scope = new PointerScope()

val onnxDataType = tensorProto.data_type
val dimsCount = tensorProto.dims_size
val dimsList =
(0 until dimsCount.toInt).map(x => tensorProto.dims(x)).toList

//TODO: Determine whether to use raw_data or type-specific
val rawData = tensorProto.raw_data

//TODO: Add the rest of the types
Expand Down
42 changes: 25 additions & 17 deletions docs/README.md
Expand Up @@ -15,7 +15,7 @@ As of v0.1.0, artifacts are published to Sonatype OSS / Maven Central. For the l


### Full ONNX model inference quick start
First, download the [model file](https://s3.amazonaws.com/download.onnx/models/opset_8/squeezenet.tar.gz) for [SqueezeNet](https://en.wikipedia.org/wiki/SqueezeNet), extracting and renaming.
First, download the [model file](https://s3.amazonaws.com/onnx-model-zoo/squeezenet/squeezenet1.1/squeezenet1.1.onnx) for [SqueezeNet](https://en.wikipedia.org/wiki/SqueezeNet).

Using the console, from this project root:
```
Expand All @@ -36,7 +36,7 @@ import java.nio.file.{Files, Paths}
import org.emergentorder.onnx.{Tensor, TensorFactory}
import org.emergentorder.onnx.backends.NGraphBackendFull

val squeezenet = Files.readAllBytes(Paths.get("squeezenet.onnx"))
val squeezenet = Files.readAllBytes(Paths.get("squeezenet1.1.onnx"))

val backend = new NGraphBackendFull()

Expand All @@ -53,7 +53,7 @@ out._1.size
out._1.indices.maxBy(out._1)
```

Referring to the [ImageNet 1000 class labels](https://gist.github.com/yrevar/942d3a0ac09ec9e5eb3a), we see that the predicted class is "envelope".
Referring to the [ImageNet 1000 class labels](https://gist.github.com/yrevar/942d3a0ac09ec9e5eb3a), we see that the predicted class is "ballpoint pen".

### Operator-level (Fine-grained) API

Expand Down Expand Up @@ -221,44 +221,52 @@ The Scala Native build will fail unless you apply this [PR](https://github.com/s
Currently at ONNX 1.6.0.

## Type-safe Tensors (Experimental, Scala 2.13 only)
Featuring type-checked axis labels (Dim), which along with literal types (new in Scala 2.13) for dimension sizes allow for axes-typed/shape-typed (Axes) tensors (TypesafeTensor).
Using ONNX docs for [dimension](https://github.com/onnx/onnx/blob/master/docs/DimensionDenotation.md) and [type](https://github.com/onnx/onnx/blob/master/docs/TypeDenotation.md) denotation as a reference,
and inspired by [Nexus](https://github.com/ctongfei/nexus), [Neurocat](https://github.com/mandubian/neurocat) and [Named Tensors](https://pytorch.org/docs/stable/named_tensor.html).

```scala mdoc:silent
import org.emergentorder.onnx._

trait Image extends Dim
trait DataBatch extends Dim
trait DataChannel extends Dim
trait DataFeature extends Dim

val imageAxes = new Tuple3OfDim(3, new Image{}, 224, new Image{},224, new Image{})
val imageAxes = new Tuple3OfDim(3, new DataChannel{}, 224, new DataFeature{},224, new DataFeature{})
type ImageAxes = imageAxes.type
type ImageTensor = TypesafeTensor[Float, ImageAxes]

val typesafeTens: ImageTensor = TensorFactory.getTypesafeTensor(Array.fill(3*224*224){42f},imageAxes)
backend.Sqrt6[Float, ImageAxes]("sqrt", Some(typesafeTens))
backend.Sqrt6("sqrt", Some(typesafeTens))


trait Word extends Dim
val wordAxes = (new Vec(5, new Word{}))
type WordAxes = wordAxes.type
type WordTensor = TypesafeTensor[Float, WordAxes]
val textAxes = (new Vec(100, new DataFeature{}))
type TextAxes = textAxes.type
type TextTensor = TypesafeTensor[Float, TextAxes]

```
```scala mdoc:crash
//Fails, as designed
//Fails at runtime, as designed
val wrongSizeDataTens: ImageTensor = TensorFactory.getTypesafeTensor(Array.fill(3*224*225){42f},imageAxes)
```
```scala mdoc:fail
//Fails, as designed
//The rest fail to compile, as designed

val wordShouldBeImageTens: WordTensor = TensorFactory.getTypesafeTensor(Array.fill(3*224*224){42f},imageAxes)
val wordShouldBeImageTens: TextTensor = TensorFactory.getTypesafeTensor(Array.fill(3*224*224){42f},imageAxes)
```
```scala mdoc:fail
//Fails, as designed
backend.Sqrt6[Float, WordAxes]("sqrt", Some(typesafeTens))
backend.Sqrt6[Float, TextAxes]("sqrt", Some(typesafeTens))
```
```scala mdoc:fail
//Fails, as designed
val wrongSizedImageAxes = (new Vec(15, new Image{}))
val wrongSizedImageAxes = (new Tuple3OfDim(15, new DataChannel{}, 224, new DataFeature{}, 224, new DataFeature{}))
type WrongSizedImageAxes = wrongSizedImageAxes.type
backend.Sqrt6[Float, WrongSizedImageAxes]("sqrt", Some(typesafeTens))
```
```scala mdoc:fail
val wrongDimTypeAxes = (new Tuple3OfDim(3, new DataBatch{}, 224, new DataFeature{}, 224, new DataFeature{}))
type WrongDimTypeAxes = wrongDimTypeAxes.type
backend.Sqrt6[Float, WrongDimTypeAxes]("sqrt", Some(typesafeTens))
```

### Built With

Expand Down
2 changes: 2 additions & 0 deletions get_models.sh
@@ -0,0 +1,2 @@
curl -O "https://s3.amazonaws.com/onnx-model-zoo/squeezenet/squeezenet1.1/squeezenet1.1.onnx"
curl -o absnet.onnx "https://raw.githubusercontent.com/onnx/onnx/master/onnx/backend/test/data/node/test_abs/model.onnx"

0 comments on commit d9d93e8

Please sign in to comment.