ff-performance-tests/go/feed_forward.go

138 lines
3.4 KiB
Go
Raw Permalink Normal View History

2022-07-20 11:13:04 +02:00
package main
import (
"encoding/csv"
"fmt"
"math"
"os"
"path/filepath"
"strconv"
"time"
"gonum.org/v1/gonum/mat"
)
const DATA_DIR string = "data"
type layer struct {
weights *mat.Dense
biases *mat.Dense
}
func array_flatten(two_d_array [][]string) []float64 {
var result []float64
for _, line := range two_d_array {
for _, value := range line {
float_value, _ := strconv.ParseFloat(value, 64)
result = append(result, float_value)
}
}
return result
}
func load_matrix_from_csv(file_path string) (*mat.Dense, error) {
f, err := os.Open(file_path)
if err != nil {
return nil, err
}
defer f.Close()
data, err := csv.NewReader(f).ReadAll()
return mat.NewDense(len(data), len(data[0]), array_flatten(data)), err
}
func load_test_data(dir string) (*mat.Dense, []layer, error) {
inputs, err := load_matrix_from_csv(filepath.Join(dir, "inputs.csv"))
if err != nil { return nil, nil, err }
var layers []layer
var weights *mat.Dense
var biases *mat.Dense
var path string
for n := 1; n < 100; n++ {
path = filepath.Join(dir, fmt.Sprintf("weights%02d.csv", n))
_, err = os.Stat(path)
if err != nil { break }
weights, err = load_matrix_from_csv(path)
if err != nil { return nil, nil, err }
path = filepath.Join(dir, fmt.Sprintf("biases%02d.csv", n))
_, err = os.Stat(path)
if err != nil { break }
biases, err = load_matrix_from_csv(path)
if err != nil { return nil, nil, err }
layers = append(layers, layer{weights, biases})
}
return inputs, layers, nil
}
func sigmoid_scalar(x float64) float64 {
return 1 / (1 + math.Exp(-x))
}
func sigmoid_element(i, j int, value float64) float64 {
return sigmoid_scalar(value)
}
func sigmoid_matrix(x mat.Matrix) *mat.Dense {
var y mat.Dense
y.Apply(sigmoid_element, x)
return &y
}
func layer_func(inputs *mat.Dense, weights *mat.Dense, biases *mat.Dense, activation func(x mat.Matrix) *mat.Dense) *mat.Dense {
var output mat.Dense
output.Mul(weights, inputs)
output.Add(&output, biases)
return sigmoid_matrix(&output)
}
func feed_forward(x *mat.Dense, layers []layer) *mat.Dense {
var y *mat.Dense = x
for _, l := range layers {
y = layer_func(y, l.weights, l.biases, sigmoid_matrix)
}
return y
}
func time_feed_forward(n int) {
inputs, layers, _ := load_test_data(DATA_DIR)
t0 := time.Now()
for i := 0; i < n; i++ { feed_forward(inputs, layers) }
elapsed := time.Since(t0)
fmt.Printf("%.5f\n", elapsed.Seconds())
}
func examples() {
x := mat.NewDense(2, 1, []float64{0, 2})
w1 := mat.NewDense(2, 2, []float64{1, 0, 2, 4})
b1 := mat.NewDense(2, 1, []float64{0, 1})
w2 := mat.NewDense(2, 2, []float64{1, 0, 2, 4})
b2 := mat.NewDense(2, 1, []float64{-0.5, 1})
layers := []layer{{w1, b1}, {w2, b2}}
pre := " "
fmt.Printf("x1 = %v\n", mat.Formatted(x, mat.Prefix(pre)))
fmt.Printf("w1 = %v\n", mat.Formatted(w1, mat.Prefix(pre)))
fmt.Printf("b1 = %v\n", mat.Formatted(b1, mat.Prefix(pre)))
fmt.Println("σ(w1 * x1 + b1) = ")
x2 := layer_func(x, w1, b1, sigmoid_matrix)
fmt.Printf("x2 = %v\n\n", mat.Formatted(x2, mat.Prefix(pre)))
fmt.Printf("w2 = %v\n", mat.Formatted(w2, mat.Prefix(pre)))
fmt.Printf("b2 = %v\n", mat.Formatted(b2, mat.Prefix(pre)))
fmt.Println("σ(w2 * x2 + b2) = ")
x3 := feed_forward(x, layers)
fmt.Printf("x3 = %v\n", mat.Formatted(x3, mat.Prefix(pre)))
}
func main() {
n, err := strconv.Atoi(os.Args[1])
if err != nil {
fmt.Println(err)
os.Exit(2)
}
time_feed_forward(n)
}