Giter Site home page Giter Site logo

gorgonia / tensor Goto Github PK

View Code? Open in Web Editor NEW
340.0 340.0 48.0 1.5 MB

package tensor provides efficient and generic n-dimensional arrays in Go that are useful for machine learning and deep learning purposes

License: Apache License 2.0

Go 99.92% Assembly 0.03% Shell 0.05%
deep-learning golang hacktoberfest machine-learning multidimensional-arrays ndarray tensor

tensor's Introduction

Logo

GoDoc GitHub version Build and Tests codecov Go Report Card unstable

Gorgonia is a library that helps facilitate machine learning in Go. Write and evaluate mathematical equations involving multidimensional arrays easily. If this sounds like Theano or TensorFlow, it's because the idea is quite similar. Specifically, the library is pretty low-level, like Theano, but has higher goals like Tensorflow.

Gorgonia:

  • Can perform automatic differentiation
  • Can perform symbolic differentiation
  • Can perform gradient descent optimizations
  • Can perform numerical stabilization
  • Provides a number of convenience functions to help create neural networks
  • Is fairly quick (comparable to Theano and TensorFlow speed)
  • Supports CUDA/GPGPU computation (OpenCL not yet supported, send a pull request)
  • Will support distributed computing

Goals

The primary goal for Gorgonia is to be a highly performant machine learning/graph computation-based library that can scale across multiple machines. It should bring the appeal of Go (simple compilation and deployment process) to the ML world. It's a long way from there currently, however, the baby steps are already there.

The secondary goal for Gorgonia is to provide a platform for the exploration of non-standard deep-learning and neural network-related things. This includes things like neo-hebbian learning, corner-cutting algorithms, evolutionary algorithms, and the like.

Why Use Gorgonia?

The main reason to use Gorgonia is developer comfort. If you're using a Go stack extensively, now you have access to the ability to create production-ready machine learning systems in an environment that you are already familiar with and comfortable with.

ML/AI at large is usually split into two stages: the experimental stage where one builds various models, tests, and retests; and the deployed state where a model after being tested and played with, is deployed. This necessitates different roles like data scientist and data engineer.

Typically the two phases have different tools: Python (PyTorch, etc) is commonly used for the experimental stage, and then the model is rewritten in some more performant language like C++ (using dlib, mlpack etc). Of course, nowadays the gap is closing and people frequently share the tools between them. Tensorflow is one such tool that bridges the gap.

Gorgonia aims to do the same but for the Go environment. Gorgonia is currently fairly performant - its speeds are comparable to PyTorch's and Tensorflow's CPU implementations. GPU implementations are a bit finicky to compare due to the heavy CGO tax, but rest assured that this is an area of active improvement.

Getting started

Installation

The package is go-gettable: go get -u gorgonia.org/gorgonia.

Gorgonia is compatible with Go modules.

Documentation

Up-to-date documentation, references, and tutorials are present on the official Gorgonia website at https://gorgonia.org.

Keeping Updated

Gorgonia's project has a Slack channel on gopherslack, as well as a Twitter account. Official updates and announcements will be posted to those two sites.

Usage

Gorgonia works by creating a computation graph and then executing it. Think of it as a programming language, but is limited to mathematical functions, and has no branching capability (no if/then or loops). In fact, this is the dominant paradigm that the user should be used to thinking about. The computation graph is an AST.

Microsoft's CNTK, with its BrainScript, is perhaps the best at exemplifying the idea that building a computation graph and running the computation graphs are different things and that the user should be in different modes of thought when going about them.

Whilst Gorgonia's implementation doesn't enforce the separation of thought as far as CNTK's BrainScript does, the syntax does help a little bit.

Here's an example - say you want to define a math expression z = x + y. Here's how you'd do it:

package gorgonia_test

import (
	"fmt"
	"log"

	. "gorgonia.org/gorgonia"
)

// Basic example of representing mathematical equations as graphs.
//
// In this example, we want to represent the following equation
//		z = x + y
func Example_basic() {
	g := NewGraph()

	var x, y, z *Node
	var err error

	// define the expression
	x = NewScalar(g, Float64, WithName("x"))
	y = NewScalar(g, Float64, WithName("y"))
	if z, err = Add(x, y); err != nil {
		log.Fatal(err)
	}

	// create a VM to run the program on
	machine := NewTapeMachine(g)
	defer machine.Close()

	// set initial values then run
	Let(x, 2.0)
	Let(y, 2.5)
	if err = machine.RunAll(); err != nil {
		log.Fatal(err)
	}

	fmt.Printf("%v", z.Value())
	// Output: 4.5
}

You might note that it's a little more verbose than other packages of similar nature. For example, instead of compiling to a callable function, Gorgonia specifically compiles into a *program which requires a *TapeMachine to run. It also requires manual a Let(...) call.

The author would like to contend that this is a Good Thing - to shift one's thinking to machine-based thinking. It helps a lot in figuring out where things might go wrong.

Additionally, there is no support for branching - that is to say, there are no conditionals (if/else) or loops. The aim is not to build a Turing-complete computer.


More examples are present in the example subfolder of the project, and step-by-step tutorials are present on the main website

Using CUDA

Gorgonia comes with CUDA support out of the box. Please see the reference documentation about how cuda works on the Gorgonia.org website, or jump to the tutorial.

About Gorgonia's development process

Versioning

We use semver 2.0.0 for our versioning. Before 1.0, Gorgonia's APIs are expected to change quite a bit. API is defined by the exported functions, variables, and methods. For the developers' sanity, there are minor differences to SemVer that we will apply before version 1.0. They are enumerated below:

  • The MINOR number will be incremented every time there is a deleterious break in API. This means any deletion or any change in function signature or interface methods will lead to a change in the MINOR number.
  • Additive changes will NOT change the MINOR version number before version 1.0. This means that if new functionality were added that does not break the way you use Gorgonia, there would not be an increment in the MINOR version. There will be an increment in the PATCH version.

API Stability

Gorgonia's API is as of right now, not considered stable. It will be stable from version 1.0 forward.

Go Version Support

Gorgonia supports 2 versions below the Master branch of Go. This means Gorgonia will support the current released version of Go, and up to 4 previous versions - providing something doesn't break. Where possible a shim will be provided (for things like new sort APIs or math/bits which came out in Go 1.9).

The current version of Go is 1.13.1. The earliest version Gorgonia supports is Go 1.11.x but Gonum supports only 1.12+. Therefore, the minimum Go version to run the master branch is Go > 1.12.

Hardware and OS supported

Gorgonia runs on :

  • linux/AMD64
  • linux/ARM7
  • linux/ARM64
  • win32/AMD64
  • darwin/AMD64
  • freeBSD/AMD64

If you have tested Gorgonia on other platforms, please update this list.

Hardware acceleration

Gorgonia uses some pure assembler instructions to accelerate some mathematical operations. Unfortunately, only amd64 is supported.

Contributing

Obviously, since you are most probably reading this on Github, Github will form the major part of the workflow for contributing to this package.

See also: CONTRIBUTING.md

Contributors and Significant Contributors

All contributions are welcome. However, there is a new class of contributors, called Significant Contributors.

A Significant Contributor has shown a deep understanding of how the library works and/or its environs. Here are examples of what constitutes a Significant Contribution:

  • Wrote significant amounts of documentation on why/the mechanics of particular functions/methods and how the different parts affect one another
  • Wrote code and tests around the more intricately connected parts of Gorgonia
  • Wrote code and tests, and had at least 5 pull requests accepted
  • Provided expert analysis on parts of the package (for example, you may be a floating point operations expert who optimized one function)
  • Answered at least 10 support questions.

The significant Contributors list will be updated once a month (if anyone even uses Gorgonia that is).

How To Get Support

The best way of support right now is to open a ticket on Github.

Frequently Asked Questions

Why are there seemingly random runtime.GC() calls in the tests?

The answer to this is simple - the design of the package uses CUDA in a particular way: specifically, a CUDA device and context are tied to a VM, instead of at the package level. This means for every VM created, a different CUDA context is created per device per VM. This way all the operations will play nicely with other applications that may be using CUDA (this needs to be stress-tested, however).

The CUDA contexts are only destroyed when the VM gets garbage collected (with the help of a finalizer function). In the tests, about 100 VMs get created, and garbage collection for the most part can be considered random. This leads to cases where the GPU runs out of memory as there are too many contexts being used.

Therefore at the end of any tests that may use GPU, a runtime.GC() call is made to force garbage collection, freeing GPU memories.

In production, one is unlikely to start that many VMs, therefore it's not a problem. If there is, open a ticket on GitHub, and we'll look into adding a Finish() method for the VMs.

Licence

Gorgonia is licensed under a variant of Apache 2.0. It's the same as the Apache 2.0 Licence, except not being able to commercially profit directly from the package unless you're a Significant Contributor (for example, providing commercial support for the package). It's perfectly fine to profit directly from a derivative of Gorgonia (for example, if you use Gorgonia as a library in your product)

Everyone is still allowed to use Gorgonia for commercial purposes (for example: using it in software for your business).

Dependencies

There are very few dependencies that Gorgonia uses - and they're all pretty stable, so as of now there isn't a need for vendoring tools. These are the list of external packages that Gorgonia calls, ranked in order of reliance that this package has (sub-packages are omitted):

Package Used For Vitality Notes Licence
gonum/graph Sorting *ExprGraph Vital. Removal means Gorgonia will not work Development of Gorgonia is committed to keeping up with the most updated version gonum license (MIT/BSD-like)
gonum/blas Tensor subpackage linear algebra operations Vital. Removal means Gorgonial will not work Development of Gorgonia is committed to keeping up with the most updated version gonum license (MIT/BSD-like)
cu CUDA drivers Needed for CUDA operations Same maintainer as Gorgonia MIT/BSD-like
math32 float32 operations Can be replaced by float32(math.XXX(float64(x))) Same maintainer as Gorgonia, same API as the built-in math package MIT/BSD-like
hm Type system for Gorgonia Gorgonia's graphs are pretty tightly coupled with the type system Same maintainer as Gorgonia MIT/BSD-like
vecf64 optimized []float64 operations Can be generated in the tensor/genlib package. However, plenty of optimizations have been made/will be made Same maintainer as Gorgonia MIT/BSD-like
vecf32 optimized []float32 operations Can be generated in the tensor/genlib package. However, plenty of optimizations have been made/will be made Same maintainer as Gorgonia MIT/BSD-like
set Various set operations Can be easily replaced Stable API for the past 1 year set licence (MIT/BSD-like)
gographviz Used for printing graphs Graph printing is only vital to debugging. Gorgonia can survive without, but with a major (but arguably nonvital) feature loss Last update 12th April 2017 gographviz license (Apache 2.0)
rng Used to implement helper functions to generate initial weights Can be replaced fairly easily. Gorgonia can do without the convenience functions too rng license (Apache 2.0)
errors Error wrapping Gorgonia won't die without it. In fact Gorgonia has also used goerrors/errors in the past. Stable API for the past 6 months errors licence (MIT/BSD-like)
gonum/mat Compatibility between Tensor and Gonum's Matrix Development of Gorgonia is committed to keeping up with the most updated version gonum license (MIT/BSD-like)
testify/assert Testing Can do without but will be a massive pain in the ass to test testify license (MIT/BSD-like)

Various Other Copyright Notices

These are the packages and libraries that inspired and were adapted from in the process of writing Gorgonia (the Go packages that were used were already declared above):

Source How it's Used Licence
Numpy Inspired large portions. Directly adapted algorithms for a few methods (explicitly labeled in the docs) MIT/BSD-like. Numpy Licence
Theano Inspired large portions. (Unsure: number of directly adapted algorithms) MIT/BSD-like Theano's license
Caffe im2col and col2im directly taken from Caffe. Convolution algorithms inspired by the original Caffee methods Caffe Licence

tensor's People

Contributors

bdleitner avatar bezineb5 avatar cfgt avatar chewxy avatar cpllbstr avatar dcu avatar dependabot[bot] avatar jlauinger avatar khezen avatar ksw2000 avatar markkremer avatar mlg556 avatar owulveryck avatar pointlander avatar poopoothegorilla avatar strigi-form avatar tiagorlampert avatar wzzhu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

tensor's Issues

"array2 is incomplete (or unallocatable); stack allocation disallowed" from examples

I'm getting this error with the example from the Gorgonia website:

gorgonia.org/tensor

../../../../go/pkg/mod/gorgonia.org/[email protected]/array.go:24:7: array2 is incomplete (or unallocatable); stack allocation disallowed
../../../../go/pkg/mod/gorgonia.org/[email protected]/array.go:168:38: array2 is incomplete (or unallocatable); stack allocation disallowed
../../../../go/pkg/mod/gorgonia.org/[email protected]/array.go:298:2: rawdata is incomplete (or unallocatable); stack allocation disallowed
../../../../go/pkg/mod/gorgonia.org/[email protected]/array.go:371:3: array2 is incomplete (or unallocatable); stack allocation disallowed
../../../../go/pkg/mod/gorgonia.org/[email protected]/array.go:372:3: array2 is incomplete (or unallocatable); stack allocation disallowed

I'm running on macOS 10.13.6 High Sierra with go1.15.3 darwin/amd64 on a 2010 machine.

Can I quickly verify this isn't an issue with environment setup or platform? I've checked for the response on another machine from 2013 running macOS 10.15.7 and it's still present.

The example I'm using is as follows:

package main
import (
  "fmt"
  "log"
  "gorgonia.org/gorgonia"
)

func main(){
  g := NewGraph()

  var a, c, c *Node
  var err error

  a = NewScalar(g, Float64, WithName("a"))
  b = NewScalar(g, Float64, WithName("b"))

  c, err = Add(a, b)

  if err != nil {
    log.Fatal(err)
  }

  machine := NewTapeMachine(g)

  Let(a, 1.0)
  Let(b, 2.0)
  if machine.RunAll() != nil {
    log.Fatal(err)
  }
  fmt.Printf("%v", c.Value())

}```

Typechecked generic tensor?

Ref this quote from https://github.com/gorgonia/tensor?tab=readme-ov-file#generic-features:

One could argue that this sidesteps the compiler's type checking system, deferring it to runtime (which a number of people consider dangerous). However, tools are being developed to type check these things, and until Go does support typechecked generics, unfortunately this will be the way it has to be.
Currently, the tensor package supports limited type of genericity - limited to a tensor of any primitive type.

Go does have typechecked generics as of 1.18. I'm sure you've thought more about this than I have, so I'm very curious to hear your thoughts on templating the Tensor interface by T, so you'd write Tensor[float32] for example. It would allow writing functions operating only on float tensors like so: func dostuff[T Float](t Tensor[T]) Tensor[T]. Another consequence would be Apply taking a function of func (v T) T, rather than func (v interface{}) interface{}).

Casting between data types

Is there a way to cast a dense matrix between different data types. The use case is that I have data that's a uint8 but I want to represent it as a dense matrix of float32.

thank you

Any particular reason why ss and rs are not exported

Hi!
I would like to use this library for tensor manipulations in Golang. Is there any reason as to why range slices and single element slices are not exported in slice.go? It would be very convenient if they were exported, e.g. like this:

func RangeSlice(start, end int, opts ...int) Slice {
...
}
type SS int

Clarify Semantics breaks Slicing on vectors with shape 1

To reproduce:

	v = tensor.New(
		tensor.WithShape(1),
		tensor.WithBacking([]float64{2}),
	)
	sliced, err = v.Slice(gorgonia.S(0))
	handleErr(err)
	fmt.Printf("[0:1]\n%v\n%v\n\n", sliced.Shape(), sliced)

yields

panic: runtime error: index out of range [0] with length 0
goroutine 1 [running]:
gorgonia.org/tensor.(*AP).S(0xc000298400, 0x1, 0xc000159e98, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, ...)
	/Users/dcuadrado/go/src/gorgonia.org/tensor/ap.go:243 +0xcfc

h/t @dcu

MulScalar bug

@bezineb5 discovered this and opened #51

The bug is described as follows:

a2 := New(WithBacking([]float64{2}))
	b2 := New(WithBacking([]float64{3}))
	var correct interface{} = 6.0

	res, err := Mul(a2, b2)
	if err != nil {
		t.Fatalf("Error: %v", err)
	}
	assert.Equal(t, correct, res.Data())
	t.Logf("a2 %v b2 %v, res %v", a2, b2, res)
	a := New(WithBacking([]float64{3, 2}))
	b := New(WithBacking([]float64{2}))
	correct := []float64{6, 4}

	res, err := Mul(a, b)
	if err != nil {
		t.Fatalf("Error: %v", err)
	}
	assert.Equal(t, correct, res.Data())
	t.Logf("a %v b %v, res %v", a, b, res)

	// Test commutativity
	res, err = Mul(b, a)
	if err != nil {
		t.Fatalf("Error: %v", err)
	}
	assert.Equal(t, correct, res.Data())
	t.Logf("a %v b %v, res %v", a, b, res)

The bug happens in https://github.com/gorgonia/tensor/blob/master/defaultengine_arith.go#L665 and https://github.com/gorgonia/tensor/blob/master/defaultengine_arith.go#L639 as well.

The bug affects all generated SV and VS arithmetic functions.

cannot use b (type BLAS) as type "gorgonia.org/tensor"

i am loading my model and i take this problem

` // Create a backend receiver
backend := gorgonnx.NewGraph()
// Create a model and set the execution backend
model := onnx.NewModel(backend)
// read the onnx model
b, _ := ioutil.ReadFile("REDPropiaFinal.onnx")

err := model.UnmarshalBinary(b)
if err != nil {
	log.Fatal(err)
}`

and I get the following error

vendor/gorgonia.org/gorgonia/blas.go:46:12: cannot use b (type BLAS) as type "gorgonia.org/tensor".BLAS in argument to "gorgonia.org/tensor".Use:
BLAS does not implement "gorgonia.org/tensor".BLAS (missing Caxpy method)

my go.mod file:

module workspace/keras
go 1.16
require (
github.com/apache/arrow/go/arrow v0.0.0-20210716061910-93bdbf1df56f // indirect
github.com/chewxy/math32 v1.0.8 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/owulveryck/onnx-go v0.5.0
gonum.org/v1/gonum v0.9.3 // indirect
gorgonia.org/tensor v0.9.20
)

P.S. Sorry but it`s my first question in github

Guidelines on use of Borrow and Return

From @kabaka0 on March 22, 2017 14:50

For consistency, it would be good to have guidelines on when to use Borrow in contributed code. It would be great if Borrow/Return could be the default for allocation (including new types going forward)- it would make contributing to the code easier, as well as make it easier to manage performance. You could probably do this without too much of a performance hit, although the Borrow/Return functions would need to become a bit more complex to make sure that returns only correspond to borrowed objects. Thoughts on this?

Copied from original issue: gorgonia/gorgonia#100

XXXScalar functions do not respect the Dtype of the tensor.

	a := New(WithShape(4, 2), WithBacking([]float64{1, 1, 1, 1, 1, 1, 1, 1}))
	b := New(WithShape(2, 4), WithBacking([]float64{0, 1, 0, 1, 0, 1, 0, 1}))
	c, _ := a.MatMul(b)
	d, err := Div(c, 2) // 2 is an untyped constant that will be used as an int.
	if err == nil {
		log.Fatal("expected an error")
	}

Go Version 1.15.3

Hello,

There appears to be an issue w.r.t Go v1.15.3. The code to reproduce the below was a simple copy/paste from the README or Gorgonia. Please see the below trace;

# gorgonia.org/tensor
../../../go/src/gorgonia.org/tensor/array.go:24:7: array2 is incomplete (or unallocatable); stack allocation disallowed
../../../go/src/gorgonia.org/tensor/array.go:168:38: array2 is incomplete (or unallocatable); stack allocation disallowed
../../../go/src/gorgonia.org/tensor/array.go:298:2: rawdata is incomplete (or unallocatable); stack allocation disallowed
../../../go/src/gorgonia.org/tensor/array.go:371:3: array2 is incomplete (or unallocatable); stack allocation disallowed
../../../go/src/gorgonia.org/tensor/array.go:372:3: array2 is incomplete (or unallocatable); stack allocation disallowed
../../../go/src/gorgonia.org/tensor/defaultengine_matop_misc.go:211:8: array2 is incomplete (or unallocatable); stack allocation disallowed
../../../go/src/gorgonia.org/tensor/defaultengine_matop_misc.go:220:5: array2 is incomplete (or unallocatable); stack allocation disallowed
../../../go/src/gorgonia.org/tensor/array.go:376:19: array2 is incomplete (or unallocatable); stack allocation disallowed
../../../go/src/gorgonia.org/tensor/array.go:377:19: array2 is incomplete (or unallocatable); stack allocation disallowed
../../../go/src/gorgonia.org/tensor/dense.go:608:45: array2 is incomplete (or unallocatable); stack allocation disallowed
../../../go/src/gorgonia.org/tensor/dense.go:608:45: too many errors

I'm new to Go, and looking to port a few things over from TF. I rolled back to 1.13.9 and of course have no problems (haven't tested any intermediate versions). I had a quick look at the change logs from v1.14 -> v1.15 where it mentions making some allocations mandatory so I'm assuming it has to do with storage.Header inside the array2 struct, but like I said i'm new to the language so would be in no place to suggest a fix myself.

Thanks 😄

MaskedTensor has some fundamental arithmetic issues if we follow Numpy's conventions.

From @chewxy on July 9, 2017 22:30

func TestMaskedPlay(t *testing.T) {
	a := New(WithShape(2, 2), WithBacking([]float64{1, 2, 3, 4}), WithMask([]bool{true, false, false, false}))
	t.Logf("a \n%v", a)
	t.Logf("%v | %v", a.mask, a.l)

	b := New(WithShape(2, 2), WithBacking([]float64{1, 2, 3, 4}))
	t.Logf("b \n%v", b)

	incr := New(WithShape(2, 2), WithBacking([]float64{100, 100, 100, 100}))
	StdEng{}.Add(a, b, WithIncr(incr))
	t.Logf("\n%v ", incr)
}

Results in:

	masked_test.go:7: a 
		⎡--   2⎤
		⎣ 3   4⎦
	masked_test.go:8: [true false false false] | 4
	masked_test.go:11: b 
		⎡1  2⎤
		⎣3  4⎦
	masked_test.go:21: 
		⎡100  104⎤
		⎣106  108⎦

By and large this makes sense. However, current tests fail mainly because the original APIs were built to be mirrors of Numpy's API for masked arrays. In Numpy:

>>> import numpy as np
>>> import numpy.ma as ma
>>> y = ma.array([1, 2, 3], mask = [0, 1, 0])

>>> incr = np.array([100,100,100])
>>> x = np.array([2,4,6])
>>> incr += x + y
>>> incr
array([103, 104, 109])
>>> x
array([2, 4, 6])
>>> y
masked_array(data = [1 -- 3],
             mask = [False  True False],
       fill_value = 999999)

>>> incr = np.array([100,100,100])
>>> incr += x * y
>>> incr
array([102, 104, 118])

The last answer is pretty WTF-ing. It violates an arithmetic convention (PEDMAS)

@kabaka0 care to weigh in? What should the correct way be?

Copied from original issue: gorgonia/gorgonia#133

FromScalar makes no sense with mask

From @chewxy on July 3, 2017 23:12

// FromScalar is a construction option for representing a scalar value as a Tensor
func FromScalar(x interface{}, argMask ...[]bool) ConsOpt {
	var mask []bool
	if len(argMask) > 0 {
		mask = argMask[0]
	}

	f := func(t Tensor) {
		switch tt := t.(type) {
		case *Dense:
			xt := reflect.TypeOf(x)
			xv := reflect.New(xt)
			xvi := reflect.Indirect(xv)
			xvi.Set(reflect.ValueOf(x))
			ptr := xv.Pointer()
			uptr := unsafe.Pointer(ptr)

			tt.ptr = uptr
			tt.l = 1
			tt.c = 1
			tt.v = x
			tt.t = Dtype{xt}
			tt.mask = mask
			tt.shape = 

		default:
			panic("Unsupported Tensor Type")
		}
	}
	return f
}

A scalar value should not be masked. Is there a reason why a scalar value is maskable? @kabaka0

There are various instances where retVal = New(FromScalar(argmaxI(t.Ints(), t.mask))) or something similar is called, but I cannot for rhyme or reason figure out why.

Copied from original issue: gorgonia/gorgonia#132

Why not sync.Pool

???

  1. Write a sync.Pool version
  2. Benchmark against channel pool

Compare the meercats

Upgrade assume-no-moving-gc to the latest version.

Hi

We have been using this package in some of our projects. It has been working great so far. Since go 1.18 we have a panic caused by assume-no-moving-gc. This can be fixed by setting the env var : ASSUME_NO_MOVING_GC_UNSAFE_RISK_IT_WITH=go1.18

I updated the version in go.mod and it looks like everything is working. I don't know if this has any other implications. But Would be nice to get rid of the panic and update the package to go 1.18?

I'll try to create a pull request with the changes.

Reduction Ops fail

While working on gorgonia/gorgonia#326, I found that calls into the standard engine for max operations were failing if multiple (>2) reduction dimensions were given. I tracked this to a problem in the default engine where axis were tweaked due to prior reductions.

Filing this for tracking purposes. I intend to try and fix it myself.

Random index out of range [0] with length 0 error in some tests

Follow up on #108 on why the test failed randomly. I got the following error:

--- FAIL: TestFloat64Engine_makeArray (0.00s)
panic: runtime error: index out of range [0] with length 0 [recovered]
	panic: runtime error: index out of range [0] with length 0

goroutine 128 [running]:
testing.tRunner.func1.1(0x14a0a80, 0xc000244080)
	/opt/hostedtoolcache/go/1.14.15/x64/src/testing/testing.go:999 +0x461
testing.tRunner.func1(0xc00045c240)
	/opt/hostedtoolcache/go/1.14.15/x64/src/testing/testing.go:1002 +0x606
panic(0x14a0a80, 0xc000244080)
	/opt/hostedtoolcache/go/1.14.15/x64/src/runtime/panic.go:975 +0x3e3
gorgonia.org/tensor.(*array).Uintptr(...)
	/home/runner/work/tensor/tensor/array.go:158
gorgonia.org/tensor.array.Data(0x1e438f0, 0x0, 0x0, 0x169fc40, 0x13eb260, 0x13f33f7, 0x13f33e0)
	/home/runner/work/tensor/tensor/array.go:167 +0x211
gorgonia.org/tensor.TestFloat64Engine_makeArray.func1(0x0, 0x0)
	/home/runner/work/tensor/tensor/defaultenginefloat64_test.go:26 +0x199
reflect.Value.call(0x140fb00, 0xc000466040, 0x13, 0x14f71eb, 0x4, 0xc0001b8000, 0x1, 0x1, 0x49d7c2, 0x53aa60, ...)
	/opt/hostedtoolcache/go/1.14.15/x64/src/reflect/value.go:460 +0x967
reflect.Value.Call(0x140fb00, 0xc000466040, 0x13, 0xc0001b8000, 0x1, 0x1, 0xc000188000, 0x0, 0x0)
	/opt/hostedtoolcache/go/1.14.15/x64/src/reflect/value.go:321 +0xd4
testing/quick.Check(0x140fb00, 0xc000466040, 0x0, 0x4dce27, 0x47817b)
	/opt/hostedtoolcache/go/1.14.15/x64/src/testing/quick/quick.go:290 +0x27a
gorgonia.org/tensor.TestFloat64Engine_makeArray(0xc00045c240)
	/home/runner/work/tensor/tensor/defaultenginefloat64_test.go:38 +0xac
testing.tRunner(0xc00045c240, 0x1534a08)
	/opt/hostedtoolcache/go/1.14.15/x64/src/testing/testing.go:1050 +0x1ec
created by testing.(*T).Run
	/opt/hostedtoolcache/go/1.14.15/x64/src/testing/testing.go:1095 +0x538

After looking into it, it seems that quick.Check passes a random value for the size parameter to the test function. In this specific instance that random value was 0. This size is then used to create an array. And some of the functions don't work if the array has a length of 0.

Fun fact: this has a 1 in 65536 chance of occurring. This happened to me twice now. I don't think the chances are evenly distributed.

This can be fixed two ways:

  • Make array work with 0 as a size. (probably hard to do while keeping it efficient)
  • Make sure the tests don't pass in 0. And make sure that the makeArray doesn't get called with 0 (or less) as its size argument by returning an error earlier.

I think there are some other tests that can cause similar errors.

I am not working on fixing this at the moment so feel free to work on this issue if you're interested.

Split *Dense into *Dense and *MaskedDense

From @chewxy on June 27, 2017 2:0

@kabaka0 thoughts? The idea is to as per #128 - the tensor package holds the data structures, and the essential methods (basically implementing Tensor), while things like Add will get moved to tensor/ops

Tasks

  • Write tests to ensure that all the new methods and functions in internal/stdeng can be accomplished using FlatMaskedIterator
  • If yes, then split into *Dense and *MaskedDense

Copied from original issue: gorgonia/gorgonia#131

Rotating Tensors/Denses, similar to numpy implementation

Numpy has a way to rotate matrices by increments of 90 degrees using their rot90 method that uses transposes and flips.

There is a transpose method for Tensors, but no way of flipping the Tensor that I see.

Is there a way of properly rotating a Tensor/Dense currently, other than through manual iteration over the data? If not, should this be added?

README examples don't reflect proper usage

The readme gives the following example:

a := New(WithShape(2, 2), WithBacking([]int{1, 2, 3, 4}))
fmt.Printf("a:\n%v\n", a)

I think this should be:

a := tensor.New(tensor.WithShape(2, 2), tensor.WithBacking([]int{1, 2, 3, 4}))
fmt.Printf("a:\n%v\n", a)

This is how gorgonia uses it currently.
I think the readme was probably using dot imports where the package name wasn't necessary but it is not recommended to do that.

Dot imports. If a program imports a standard package using import . "path", additional names defined in the imported package in future releases may conflict with other names defined in the program. We do not recommend the use of import . outside of tests, and using it may cause a program to fail to compile in future releases.

Import failure

go get -u "github.com/gorgonia/tensor"

return an error of

package github.com/gorgonia/tensor: code in directory C:\go\src\github.com\gorgonia\tensor expects import "gorgonia.org/tensor"

Dense Iterator off by 1

It appears that in 3x3x3 tensor while iterating the iterator Start is not pointing to the first element so that all values are off by one index.

⎡26   0   1⎤
⎢ 2   3   4⎥
⎣ 5   6   7⎦

⎡ 8   9  10⎤
⎢11  12  13⎥
⎣14  15  16⎦

⎡17  18  19⎤
⎢20  21  22⎥
⎣23  24  25⎦

CODE:

import (
	. "fmt"
	t "gorgonia.org/tensor"
)

func main() {
	a := t.New(t.WithShape(3, 3, 3), t.WithBacking(make([]int, 3*3*3)))
	it := t.IteratorFromDense(a)
	for i, err := it.Start(); err == nil; i, err = it.Next() {
		a.SetAt(i, it.Coord()[0], it.Coord()[1], it.Coord()[2])
	}
	Println(a)
}

Upgrade dependency "github.com/google/flatbuffers"

Background

Repo github.com/gorgonia/tensor depends on github.com/google/[email protected].

https://github.com/gorgonia/tensor/blob/master/go.mod#L11

However, comparing version v1.12.0 of github.com/google/flatbuffers from proxy.golang.org and github, there are inconsistencies.

commit time of the copy on github.com

"committer": {
      "name": "Wouter van Oortmerssen",
      "email": "[email protected]",
      "date": "2020-03-12T22:33:39Z"
    }

commit time of the copy on proxy.golang.org

{"Version":"v1.12.0","Time":"2020-03-12T21:45:27Z"}

So the checksum from the code in github does not match the checksum saved in sum.golang.org. The v1.12.0 tag of github.com/google/flatbuffers might have been retagged after a minor edition on github. I guess you use proxy.golang.org to get dependencies, but that also shows that your project is depending on the copy of github.com/google/[email protected] before its edition. Depending upon such inconsistent tag version may also result in some unexpected errors as well as build errors due to different proxy settings.

For example, when someone who does not use proxy.golang.org, say GOPROXY=direct, attempts to get github.com/google/[email protected], the following error occurs.

go: downloading github.com/google/flatbuffers v1.12.0
go: github.com/google/flatbuffers@v1.12.0: verifying module: checksum mismatch
        downloaded: h1:N8EguYFm2wwdpoNcpchQY0tPs85vOJkboFb2dPxmixo=
        sum.golang.org: h1:/PtAHvnBY4Kqnx/xCQ3OIV9uYcSFGScBsWI3Oogeh6w=

SECURITY ERROR
This download does NOT match the one reported by the checksum server.
The bits may have been replaced on the origin server, or an attacker may
have intercepted the download attempt.

For more information, see 'go help module-auth'.

So, this is a reminder in the hope that you can get rid of this problematic version of project github.com/google/flatbuffers.

Solution

1. Bump the version of dependency github.com/google/flatbuffers

I would recommend bumping the version of github.com/google/flatbuffers to a new release, say v1.12.1, to ensure dependency copy in proxy.golang.org and github in sync.

References

unable to get gorgonia.org/[email protected] ...

I am trying to run a gorgonia app that import gorgonia/tensor. in trying to get the tensor v0.9.10, i am getting the following error...
go: gorgonia.org/tensor: gorgonia.org/[email protected]: parsing go.mod: go.mod:6: require github.com/apache/arrow/go/arrow: version "latest" invalid: must be of the form v1.2.3

I am running go version 1.13.6 on macOS Mojave

Any help with resolving this would be greatly appreciated. Thanks in advance - jay

Iterator.Chan() considered harmful

From @chewxy on August 13, 2017 2:9

sketch space for describing how to create a chan int of negative length, and how to reproduce it

Background/Context of the Issue

Gorgonia is a library for representing and executing mathematical equations, and performing automatic differentiation. It's like Tensorflow and PyTorch for Go. It's currently undergoing some major internal refactor (that will not affect the public APIs much)

I was improving the backend tensor package by splitting up the data structure into a data structure + pluggable execution engine, instead of having built in methods (see also #128). The reasons are so that it's easier to change out execution backends (CPU, GPU... even a network CPU (actual experiment I did was to run a small neural network on a Raspberry Pi and all computation is offshored to my workstation, and vice versa, which turned out to be a supremely bad idea)).

Another reason was due to the fact that I wanted to do some experiments at my work which use algorithms that involve sparse tensors (see also #127) for matrix factorization tasks.

Lastly, I wanted to clean up the generics support of the tensor package. The current master branch of the tensor package had a lot of code to support arbitrary tensor types. With the split of execution engines and data structure, more of this support could be offloaded to the execution engine instead. This package provides a default execution engine (type StdEng struct{}: https://github.com/chewxy/gorgonia/blob/debugrace/tensor/defaultengine.go), which could be extended (example: https://github.com/chewxy/gorgonia/blob/debugrace/tensor/example_extension_test.go) . The idea was to have an internal/execution package which held all the code for the default execution engine.

Data Structures

The most fundamental data structure is storage.Header, which is an analogue for a Go slice: it's a three word structure. It's chosen because it is a ridiculously simple structure can store Go-allocated memory, C-allocated memory and device-allocated memory (like CUDA).

On top of storage.Header is tensor.array. It's essentially a storage.Header with an additional field for the type. The v field will eventually be phased out once the refactor is complete.

On top of tensor.array are the various implementations of tensor.Tensor. Chief amongst these is the tensor.Dense struct. Essentially it's a tensor.array coupled with some access patterns and meta information.

Access to the data in the tensor.Tensor can be achieved by use of Iterators. The Iterator basically assumes that the data is held in a flat slice, and returns the next index on the slice. There are auxiliary methods like NextValidity to handle special case tensors like masked tensors, where some elements are masked from operations.

The bug happens in the Chan method of the FlatIterator type.

How to reproduce

The branch where the bug is known to exist is the debugrace branch, which can be found here: 1dee6d2 .

  1. git checkout debugrace
  2. Run tests with various GOMAXPROCS like so: GOMAXPROCS=1 go test -run=. . Try it with various GOMAXPROCS, one of them is bound to trigger an issue.
  3. The test won't panic, because I have added a recover statement here https://github.com/chewxy/gorgonia/blob/debugrace/tensor/dense_viewstack_specializations.go#L636. Removing the deferred function causes a index out of bounds panic.
  4. All the tests must be run to trigger the issue.
  5. The issue is found in the test for the Stack function: https://github.com/chewxy/gorgonia/blob/debugrace/tensor/dense_matop_test.go#L768 . If only the stack test is run (for example GOMAXPROCS=1 go test -run=Stack), it is unlikely the problem will show up (I wrote a tiny python script to run it as many times as possible with many GOMAXPROCS configurations and none of them caused an error).

You should get something like this:

image

Environments

I've managed to reproduce the issue on OS X, with Go 1.8 and on Ubuntu 16.10 with Go 1.8.2 and Go tip (whatever gvm thinks is Go tip). I've no access to Go on a windows box so I can't test it on Windows.

Magic and Unsafe Use

As part of the refactoring, there are a few magic bits being used. Here I attempt to list them all (may not be exhaustive):

What I suspect

I suspect that there may be some naughty things happening in memory (because it only happens when all the tests are run). The problem is I don't know exactly where to start looking.

Copied from original issue: gorgonia/gorgonia#135

using big.Int as backing type

Hello all!

I am wondering about the best way to go about using big.Int or big.Float as the backing type for a tensor.

data := make([]*big.Int, 4)
data[0] = big.NewInt(0)
data[1] = big.NewInt(1)
data[2] = big.NewInt(2)
data[3] = big.NewInt(3)

a := tensor.New(tensor.WithShape(2, 2), tensor.WithBacking(data))
b := tensor.New(tensor.WithShape(2, 2), tensor.WithBacking(data))

works fine, but you cannot do

c, err := a.Mul(b)

because the type is not a member of Number.

I browsed the docs for a while and it looks like I could support this by creating an engine that implements Muler. But I would have to do this for a bunch of ops I want, and again for big.Float.

I may be wrong but I feel like I would get a lot of this for free if I could tell tensor how two big.Int's should be multiplied. e.g. return big.NewInt(0).Mul(a,b)

I am fairly new to golang so maybe this is a dumb question, but is there a way to do this?

Is there a more recommended way to go about this?

Thanks!

tensor.Mul bug

The tenor.Mul has bug in multiplying tensor with shape(1, 1). See the test code below. This might be caused by #54

The reason is that e.E.Mul(typ, dataA, retVal.hdr()) always assuming the result would be kept in dataA.

func TestMul(t *testing.T) {
	a := 2.0
	b := tensor.NewDense(tensor.Float64, tensor.Shape{1, 1}, tensor.WithBacking([]float64{3}))
	var correct interface{} = []float64{6.0}

	res, err := tensor.Mul(a, b)
	if err != nil {
		t.Fatalf("Error: %v", err)
	}
	assert.Equal(t, correct, res.Data())
	t.Logf("a %v b %v, res %v", a, b, res)
}

`complex64` and `complex128` are currently excluded in from being generated by `Generate` method for quick check

From @chewxy on August 28, 2017 9:17

What happens for Generate() is that testing/quick will generate really huge complex numbers, such that when it's Pow'd it becomes +Inf+Infi instead of returning the identity.

Example:

var identity complex128 = 1
x := 1.2137443348035267e+308+1.5113294366498325e+308i
y := cmplx.Pow(x, identity)
// returns (+Inf+Infi)

This causes tests and the CI to fail, therefore it's been temporarily removed until we can figure out the right thing to do

Copied from original issue: gorgonia/gorgonia#143

Panic on Transposed RowVector

[Fix found, pull request sent]
This simple code panics

2020/10/15 13:11:28 (3, 1)
C[-1  %!v(PANIC=Format method: runtime error: index out of range [3] with length 3)
package main

import (
	"log"

	"gorgonia.org/tensor"
)

func main() {
	var T tensor.Tensor
	T = tensor.New(
		tensor.WithShape(1, 3),
		tensor.WithBacking([]float64{-1, 0, 1}))
	T, _ = tensor.T(T)
	log.Printf("%v\n%v\n", T.Shape(), T)
}

Slicing should be allowed on contiguous views

Right now this happens

func (t *Dense) Reshape(dims ...int) error {
	if t.viewOf != 0 {
		return errors.Errorf(methodNYI, "Reshape", "views")
	}

	if t.old != nil {
		t.Transpose()
	}

	return t.reshape(dims...)
}

it should be changed to t.viewOf != 0 && ...

Multidimensional array assignment

Given an array x of shape (3, 100, 100), does gorgonia/tensor have a way to do

x[0] = y
x[1] = z
x[2] = w

where w, y and z are of shape (100, 100)

Weird behavior when Iterating over tensors

Whilst working with the tensor.Iterator functionality I found some strange behavior, when using iterator in a for loop like follows:

it = t.Iterator()  // t is a tensor.Dense
for i, err := it.Start(); err == nil; i, err = it.Next() {
	fmt.Printf("i = %v, coord = %v\n", i, it.Coord())
}
  1. When using the iterator as stated above, the 'first' element of the tensor is always last in the iteration. This is not really a big issue if you want to iterate over all elements and order does not matter, but it is weird nonetheless. As an example consider the tensor [1, 2, 3, 4] with shape (2, 2). It will visit the elements in order:
    i = 0, coord = [0 1]
    i = 1, coord = [1 0]
    i = 2, coord = [1 1]
    i = 3, coord = [0 0]  <------------ should be first
    
  2. When iterating over a vector or a scalar, the indices are off by one. Again same tensor, but as a vector (shape (4,)):
    i = 0, coord = [1]
    i = 1, coord = [2]
    i = 2, coord = [3]
    i = 3, coord = [4]  <----------- gives index error when used
    
    The same thing happens with 'scalar-like' tensors, like: [1] with shape (1, 1, 1):
    i = 0, coord = [1 0 0]  <--------- also index error, should be [0 0 0] always for scalars
    
    Interestingly, when the tensor is a vector/scalar View of a tensor that is not a vector/scalar (i.e. obtained by slicing), the issue does not happen.

What I found to work properly is to use the following for loop instead, but I don't think this is the intended way of iterating.

it = t.Iterator()
for it.Reset(); !it.Done(); it.Next() {
	...
}

`*FlatIterator` Support For ColMajor

The *FlatIterator type implements Iterator, which is an interface for stateful iterators. It also supports reverse iteration (by means of the .SetReverse() method).

Currently, the *FlatIterator type supports the following operations

- Row Major Vector Col Major Vector Row Major N-DImensional Col Major N-Dimensional
Forward Next()
Backward Next()
Forward NextValidity()
Backward NextValidity()
Forward NextValid()
Backward NextValid()
Forward NextInvalid()
Backward NextInvalid()

A major internal method that underpins all of these are .ndNext() and .ndPrevious(). The corresponding col-major version are .colMajorNDnext() and .colMajorNDPrevious().

.colMajorNDPrevious() is not implemented. It can be found at Line 402 of iterator.go

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.