The Wayback Machine - https://web.archive.org/web/20200910052418/https://github.com/ppknap/tensor
Skip to content
This repository has been archived by the owner. It is now read-only.
master
Go to file
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

README.md

tensor Build Status codecov Go Report Card Maintainability FOSSA Status GoDoc

Tensor is a powerful, multi-typed N-dimensional array similar to numpy's ndarray without reflection overhead.

Table of Contents

Getting Started

The goal of this project is to create a simple, fast and easy to use N-dimensional array structure with an idiomatic Go interface that supports multiple data types. Here is the current state of this project:

  • single and idiomatic API.
  • support for all Go's boolean, numeric and string types.
  • no reflection under the hood.
  • no external dependencies.
  • pure Go implementation.
  • interoperability with numpy's NPY format via binary Tensor representation.
  • completely open source and free to use.

Installation

Just like other Go libraries, you can get this package via go get:

$ go get github.com/ppknap/tensor

Then, just import it in your application:

import "github.com/ppknap/tensor"

Requirements

  • Go1.10+

Examples

Softmax function

Following code shows how to implement a simple softmax function for vectors and matrices. Note, that the returned tensor's data type will be inherited from a given argument.

package main

import (
	"fmt"

	"github.com/ppknap/tensor"
)

func softmax(t *tensor.Tensor) *tensor.Tensor {
	var sm = t.Copy()
	if sm.NDim() == 1 {
		return sm.Divide(sm.Exp().Sum())
	}

	for _, row := range sm.Split(0) {
		row.Divide(row.Subtract(row.Max()).Exp().Sum())
	}

	return sm
}

func main() {
	mat := tensor.NewMatrix([][]float64{
		{1, 2, 3, 6},
		{2, 4, 5, 6},
		{1, 2, 3, 6},
	})

	fmt.Printf("Softmax of:%v\nis equal to:%.6f\n", mat, softmax(mat))
}

Output:

Softmax of:
[[1 2 3 6]
 [2 4 5 6]
 [1 2 3 6]]
is equal to:
[[0.006269 0.017040 0.046320 0.930370]
 [0.012038 0.088947 0.241783 0.657233]
 [0.006269 0.017040 0.046320 0.930370]]

Dot product

This example shows how to compute a dot product of two matrices. Note that when working with tensors, one doesn't have to worry about the underlying data types for most of the time.

package main

import (
	"fmt"

	"github.com/ppknap/tensor"
)

func main() {
	res := tensor.Dot(
		tensor.NewMatrix([][]int{
			{4, 5, 1},
			{2, 0, 3},
			{1, 1, 1},
		}),
		tensor.NewMatrix([][]float64{
			{1.0, 0, 0.5},
			{0.0, 1, 0.0},
			{0.5, 1, 1.5},
		}),
	)

	fmt.Printf("Dot result:%v (dtype: %s)\n", res, res.DType())
}

Output:

Dot result:
[[4.5   6 3.5]
 [3.5   3 5.5]
 [1.5   2   2]] (dtype: float64)

Element access

One can walk and access all elements in the tensor. This example shows how to randomly distribute elements from a source tensor to a destination one.

package main

import (
	"fmt"
	"math/rand"

	"github.com/ppknap/tensor"
)

func main() {
	var words = tensor.NewVector([]string{"Tom", "Alice", "John", "Kate"})
	f := func(t *tensor.Tensor, pos []int) bool {
		t.ItemSet(words.ItemAt(rand.Intn(words.Len())), pos...)
		return true
	}

	fmt.Printf("Result:%q\n", tensor.New(5, 5).Walk(f))
}

Example output:

Result:
[["Alice"  "Kate"  "Kate"  "Kate" "Alice"]
 [ "John" "Alice"   "Tom"   "Tom"   "Tom"]
 [ "John"  "Kate"  "John" "Alice"   "Tom"]
 [ "John"  "Kate" "Alice" "Alice"  "John"]
 [ "Kate"  "John"   "Tom"  "John"  "Kate"]]

Splitting

Splitting is a powerful feature that enables complex operations on selected parts of a tensor. This example shows how to fill every third column of a matrix with random values.

package main

import (
	"fmt"

	"github.com/ppknap/tensor"
)

func main() {
	mat := tensor.New(3, 100)
	for i, vec := range mat.Split(1) {
		if i%3 == 0 {
			vec.Rand().Fill()
		}
	}

	fmt.Printf("Result:%4.2f (dtype: %s)\n", mat, mat.DType())
}

Example output:

Result:
[[0.95 0.00 0.00 0.72 ... 0.49 0.00 0.00 0.26]
 [0.24 0.00 0.00 0.65 ... 0.38 0.00 0.00 0.64]
 [0.66 0.00 0.00 0.94 ... 0.53 0.00 0.00 0.67]] (dtype: float64)

Conversions

It is possible to easily convert a tensor object from/to Go basic types.

package main

import (
	"fmt"

	"github.com/ppknap/tensor"
)

func dot3x3(a, b [9]int) (res [9]int) {
	var (
		at = tensor.NewVector(a[:]).Reshape(3, 3)
		bt = tensor.NewVector(b[:]).Reshape(3, 3)
	)

	for i, t := range at.Dot(bt).Destruct() {
		res[i] = t.Int()
	}

	return res
}

func main() {
	var (
		a = [9]int{10, 20, 30, 40, 50, 60, 70, 80, 90}
		b = [9]int{-1, -2, -3, -4, -5, -6, -7, -8, -9}
	)

	fmt.Printf("Op:\n %v_(3,3) @\n %v_(3,3) =\n %v_(3,3)\n", a, b, dot3x3(a, b))
}

Output:

Op:
 [10 20 30 40 50 60 70 80 90]_(3,3) @
 [-1 -2 -3 -4 -5 -6 -7 -8 -9]_(3,3) =
 [-300 -360 -420 -660 -810 -960 -1020 -1260 -1500]_(3,3)

NumPy interoperability

Tensor's binary encoding format is compatible with NPY encoding. Thus, it is possible to use tensor objects in Python and NumPy arrays in Go.

package main

import (
	"fmt"

	"github.com/ppknap/tensor"
)

func main() {
	vec := tensor.NewVector([]string{"Export", "me", "to", "NPY"})

	b, err := vec.MarshalBinary()
	if err != nil {
		panic(err)
	}

	fmt.Printf("NPY header: %s\n", b[10:67])
}

Output:

NPY header: {'descr': '<U6', 'fortran_order': False, 'shape': (4,), }

Error handling

This example demonstrates how one can handle all tensor's internal errors. Note, that this is not a recommended way of using this package since the errors that could be thrown usually indicate invalid input data or broken logic.

package main

import (
	"fmt"

	"github.com/ppknap/tensor"
)

func main() {
	fmt.Printf("Error: %s\n", tensor.Guard(func() {
		tensor.Divide(tensor.NewVector([]int{5, 6}), tensor.NewScalar("divisor"))
	}))
}

Output:

Error: tensor: invalid division on string type

More...

For other examples see GoDoc.

Milestones

This project is still in beta state. Thus, the items on the following list should be treated more like ideas than a roadmap.

  • API function set similar to the one provided by numpy's routines.
  • BLAS support.
  • Masked tensors.
  • Support for types defined in math/big package.
  • Custom defined types via Field interface.
  • Test coverage over 90%.

There are no intentions to support Google App Engine platform since this library heavily utilizes unsafe package.

Contributing

Please feel free to contribute! See the CONTRIBUTING.md file for more info.

Similar projects

There are two notable packages in the Go ecosystem that were created to solve similar problems as this library. Tensor goal is not to provide alternative for them since it focuses on a single mathematical concept where presented ones are parts of larger and more mature computational ecosystems. Thus, they give you better performance in exchange of code readability.

Project Description
gonum/gonum/mat Rich and highly optimized matrix library for float64 and complex128 types that provides many useful linear algebra operations.
gorgonia/tensor Generic, N-dimensional array library used as main tensors object source in the excellent machine learning library for Go - Gorgonia.

Benchmarks

TODO

Versioning

Tensor package uses 0ver for versioning. For the available versions, see the tags on this repository.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

The API of this project is highly influenced by the great numpy package.

About

Tensor is a powerful, multi-typed N-dimensional array similar to numpy's ndarray without reflection overhead.

Topics

Resources

License

Releases

No releases published

Packages

No packages published

Languages

You can’t perform that action at this time.