Coder Social home page Coder Social logo

dumpmemory / spago Goto Github PK

View Code? Open in Web Editor NEW

This project forked from nlpodyssey/spago

0.0 0.0 0.0 19.49 MB

spaGO is a beautiful and maintainable machine learning library written in Go designed to support relevant neural network architectures in natural language processing tasks

License: BSD 2-Clause "Simplified" License

Go 88.84% Assembly 11.08% C 0.08%

spago's Introduction



Build Coverage Go Report Card Maintainability Documentation License PRs Welcome Awesome Go


If you like the project, please ★ star this repository to show your support! 🤩

Currently, the main branch contains version v1.0.0-alpha.0, which differs substantially from version v0.7.0. For NLP-related features, check out the v0.7.0 release branch. The CHANGELOG details the major changes.

A Machine Learning library written in pure Go designed to support relevant neural architectures in Natural Language Processing.

Spago is self-contained, in that it uses its own lightweight computational graph both for training and inference, easy to understand from start to finish.

It provides:

  • Automatic differentiation via dynamic define-by-run execution
  • Gradient descent optimizers (Adam, RAdam, RMS-Prop, AdaGrad, SGD)
  • Feed-forward layers (Linear, Highway, Convolution...)
  • Recurrent layers (LSTM, GRU, BiLSTM...)
  • Attention layers (Self-Attention, Multi-Head Attention...)
  • Memory-efficient Word Embeddings (with badger key–value store)
  • Gob compatible neural models for serialization

Usage

Requirements:

Clone this repo or get the library:

go get -u github.com/nlpodyssey/spago

Dependencies

The core module of Spago relies only on testify for unit testing. In other words, it has "zero dependencies", and we are committed to keeping it that way as much as possible.

Spago uses a multi-module workspace to ensure that additional dependencies are downloaded only when specific features (e.g. persistent embeddings) are used.

Getting Started

A good place to start is by looking at the implementation of built-in neural models, such as the LSTM. Except for a few linear algebra operations written in assembly for optimal performance (a bit of copying from Gonum), it's straightforward Go code, so you don't have to worry. In fact, SpaGO could have been written by you :)

The behavior of a neural model is characterized by a combination of parameters and equations. Mathematical expressions must be defined using the auto-grad ag package in order to take advantage of automatic differentiation.

In this sense, we can say the computational graph is at the center of the Spago machine learning framework.

Example 1

Here is an example of how to calculate the sum of two variables:

package main

import (
  "fmt"
  "github.com/nlpodyssey/spago/ag"
  "github.com/nlpodyssey/spago/mat"
)

type T = float32

func main() {
  // create a new node of type variable with a scalar
  a := ag.Var(mat.NewScalar(T(2.0))).WithGrad(true)
  // create another node of type variable with a scalar
  b := ag.Var(mat.NewScalar(T(5.0))).WithGrad(true)
  // create an addition operator (the calculation is actually performed here)
  c := ag.Add(a, b)

  // print the result
  fmt.Printf("c = %v (float%d)\n", c.Value(), c.Value().Scalar().BitSize())

  ag.Backward(c, mat.NewScalar(T(0.5)))
  fmt.Printf("ga = %v\n", a.Grad())
  fmt.Printf("gb = %v\n", b.Grad())
}

Output:

c = [7] (float32)
ga = [0.5]
gb = [0.5]

Example 2

Here is a simple implementation of the perceptron formula:

package main

import (
  "log"
  "os"

  . "github.com/nlpodyssey/spago/ag"
  "github.com/nlpodyssey/spago/ag/encoding"
  "github.com/nlpodyssey/spago/ag/encoding/dot"
  "github.com/nlpodyssey/spago/mat"
)

func main() {
  x := Var(mat.NewScalar(-0.8)).WithName("x")
  w := Var(mat.NewScalar(0.4)).WithName("w")
  b := Var(mat.NewScalar(-0.2)).WithName("b")

  y := Sigmoid(Add(Mul(w, x), b))

  err := dot.Encode(encoding.NewGraph(y), os.Stdout)
  if err != nil {
    log.Fatal(err)
  }
}

In this case, we are interested in rendering the resulting graph with Graphviz:

go run main.go | dot -Tpng -o g.png



Example 3

As a next step, let's take a look at how to create a linear regression model ($y = wx + b$) and how it will be trained.

The following algorithm will try to learn the correct values for weight and bias.

By the end of our training, our equation will approximate the line of best fit the objective function $y = 3x + 1$.

package main

import (
	"fmt"

	"github.com/nlpodyssey/spago/ag"
	"github.com/nlpodyssey/spago/gd"
	"github.com/nlpodyssey/spago/gd/sgd"
	"github.com/nlpodyssey/spago/initializers"
	"github.com/nlpodyssey/spago/losses"
	"github.com/nlpodyssey/spago/mat"
	"github.com/nlpodyssey/spago/mat/float"
	"github.com/nlpodyssey/spago/mat/rand"
	"github.com/nlpodyssey/spago/nn"
)

const (
	epochs   = 100  // number of epochs
	examples = 1000 // number of examples
)

type Linear struct {
	nn.Module
	W nn.Param `spago:"type:weights"`
	B nn.Param `spago:"type:biases"`
}

func NewLinear[T float.DType](in, out int) *Linear {
	return &Linear{
		W: nn.NewParam(mat.NewEmptyDense[T](out, in)),
		B: nn.NewParam(mat.NewEmptyVecDense[T](out)),
	}
}

func (m *Linear) InitWithRandomWeights(seed uint64) *Linear {
	initializers.XavierUniform(m.W.Value(), 1.0, rand.NewLockedRand(seed))
	return m
}

func (m *Linear) Forward(x ag.Node) ag.Node {
	return ag.Add(ag.Mul(m.W, x), m.B)
}

func main() {
	m := NewLinear[float64](1, 1).InitWithRandomWeights(42)
	
	optimizer := gd.NewOptimizer(m, sgd.New[float64](sgd.NewConfig(0.001, 0.9, true)))

	normalize := func(x float64) float64 { return x / float64(examples) }
	objective := func(x float64) float64 { return 3*x + 1 }
	criterion := losses.MSE

	learn := func(input, expected float64) float64 {
		x, target := ag.Scalar(input), ag.Scalar(expected)
		y := m.Forward(x)
		loss := criterion(y, target, true)
		defer ag.Backward(loss) //  free the memory of the graph before return
		return loss.Value().Scalar().F64()
	}

	for epoch := 0; epoch < epochs; epoch++ {
		for i := 0; i < examples; i++ {
			x := normalize(float64(i))
			loss := learn(x, objective(x))
			if i%100 == 0 {
				fmt.Println(loss)
			}
		}
		optimizer.Do()
	}

	fmt.Printf("\nW: %.2f | B: %.2f\n\n", m.W.Value().Scalar().F64(), m.B.Value().Scalar().F64())
}

Output:

W: 3.00 | B: 1.00

Performance

Goroutines play a very important role in making Spago efficient; in fact Forward operations are executed concurrently (up to GOMAXPROCS). As soon as an Operator is created (usually by calling one of the functions in the ag package, such as Add, Prod, etc.), the related Function's Forward procedure is performed on a new goroutine. Nevertheless, it's always safe to ask for the Operator's Value() without worries: if it's called too soon, the function will lock until the result is computed, and then return the value.

Known Limits

Sadly, at the moment, Spago is not GPU friendly by design.

Projects using SpaGo

Below is a list of projects that use Spago:

Contributing

We're glad you're thinking about contributing to Spago! If you think something is missing or could be improved, please open issues and pull requests. If you'd like to help this project grow, we'd love to have you!

To start contributing, check the Contributing Guidelines.

Contact

We encourage you to write an issue. This would help the community grow.

If you really want to write to us privately, please email Matteo Grella with your questions or comments.

Acknowledgments

Spago is part of the open-source NLP Odyssey initiative initiated by members of the EXOP team (now part of Crisis24). I would therefore like to thank EXOP GmbH here, which is providing full support for development by promoting the project and giving it increasing importance.

Sponsors

We appreciate contributions of all kinds. We especially want to thank Spago fiscal sponsors who contribute to ongoing project maintenance.

See our Open Collective page if you too are interested in becoming a sponsor.

spago's People

Contributors

evanmcclure avatar jcr179 avatar jjviana avatar marco-nicola avatar matteo-grella avatar mattn avatar paralin avatar phanirithvij avatar

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.