Welvet examples

78. NativeCPU: TrainMode stack / parallel / mesh / line

Open original example ↗Recorded results · not a live execution

Part: X · NativeCPU (welvet.cpp)
Package: github.com/openfluke/welvet/nativecpp + layers
Status: ok: ✅ linux/amd64 + cgo

When

You want in-process welvet.cpp MatVec / NormalBP / TrainMSE instead of Go CPU tiled.

Where

import "github.com/openfluke/welvet/nativecpp" and layer TrainNativeMSE / TrainStackMSE.

cd 78-native-trainmodes && source ../env.sh && go run .

Why

Opt-in BackendNativeCPU keeps Go as default. Mirror Capture + SyncWeightsFromNative before .entity.

What

See feature book §78.

Sample output (captured)

(run locally: needs linux/amd64 libwelvet)

Source

Mirrored from the Welvet feature book (openfluke.github.io/welvet/examples/78-native-trainmodes).

main.go

Download source ↓
package main

import (
	"fmt"

	"github.com/openfluke/welvet/core"
	"github.com/openfluke/welvet/layers/dense"
	"github.com/openfluke/welvet/layers/parallel"
	"github.com/openfluke/welvet/nativecpp"
	"github.com/openfluke/welvet/quant"
)

func main() {
	if !nativecpp.NativeCPUAvailable() {
		fmt.Println("SKIP: need linux/amd64 libwelvet")
		return
	}
	demoStackFamilies()
	demoParallelModes()
	demoGridMesh()
	demoLineStep()
	fmt.Println("native-trainmodes done")
}

func demoStackFamilies() {
	modes := []parallel.TrainMode{
		parallel.ModeNormalBP, parallel.ModeTween, parallel.ModeTweenChain,
		parallel.ModeTweenSplit, parallel.ModeTweenAlt, parallel.ModeFreeze,
	}
	for _, mode := range modes {
		children := make([]any, 2)
		for i := 0; i < 2; i++ {
			init := make([]float32, 16)
			for j := range init {
				init[j] = 0.04 * float32(i*16+j+1)
			}
			d, err := dense.NewConfigured(4, 4, core.ActivationLinear, core.DTypeFloat32, quant.FormatNone, init)
			must(err)
			children[i] = d
		}
		s, err := parallel.NewStack(children...)
		must(err)
		s.SetBackend(core.BackendNativeCPU)
		x, t := core.NewTensor[float32](2, 4), core.NewTensor[float32](2, 4)
		for i := range x.Data {
			x.Data[i] = 0.08 * float32(i+1)
			t.Data[i] = 0.3
		}
		loss, err := parallel.TrainStackMSE(s, x, t, mode, 0.05)
		must(err)
		must(s.SyncWeightsFromNative())
		fmt.Println("stack", mode, "loss", loss)
	}
}

func demoParallelModes() {
	for _, mode := range []parallel.TrainMode{parallel.ModeTween, parallel.ModeAdversarial} {
		init := make([]float32, 2*4*4)
		for i := range init {
			init[i] = 0.02 * float32(i+1)
		}
		l, err := parallel.NewConfigured(parallel.Config{Dim: 4, OutFeat: 4, Branches: 2, Combine: parallel.CombineAdd},
			core.DTypeFloat32, quant.FormatNone, init, nil)
		must(err)
		l.Exec.Backend = core.BackendNativeCPU
		l.SyncBranchExec()
		x, t := core.NewTensor[float32](2, 4), core.NewTensor[float32](2, 4)
		for i := range x.Data {
			x.Data[i] = 0.07 * float32(i+1)
			t.Data[i] = 0.25
		}
		loss, err := parallel.TrainMSE(l, x, t, mode, 0.08)
		must(err)
		must(l.SyncWeightsFromNative())
		fmt.Println("parallel", mode, "loss", loss)
	}
}

func demoGridMesh() {
	const dim, batch, ticks = 3, 2, 2
	packed := make([]float32, 2*dim*dim)
	for i := range packed {
		packed[i] = 0.05 * float32(i+1)
	}
	wAfter := make([]float32, len(packed))
	x := make([]float32, batch*dim)
	tgt := make([]float32, batch*dim)
	for i := range x {
		x[i] = 0.1 * float32(i+1)
		tgt[i] = 0.3
	}
	loss, err := nativecpp.GridTrainMSE(
		int32(parallel.ModeMeshBP), 1, 1, 2, 1, batch, ticks, dim,
		1, 0, int32(core.ActivationLinear), int32(core.DTypeFloat32), 0,
		packed, x, tgt, 0.1, wAfter,
	)
	must(err)
	fmt.Println("grid MeshBP loss", loss)
}

func demoLineStep() {
	const nChildren, nTicks, batch, dim = 2, 3, 2, 3
	inH := []int32{dim, dim}
	outH := []int32{dim, dim}
	act := []int32{int32(core.ActivationLinear), int32(core.ActivationLinear)}
	packed := make([]float32, nChildren*dim*dim)
	for i := range packed {
		packed[i] = 0.04 * float32(i+1)
	}
	wAfter := make([]float32, len(packed))
	xTicks := make([]float32, nTicks*batch*dim)
	tgtTicks := make([]float32, nTicks*batch*dim)
	for i := range xTicks {
		xTicks[i] = 0.05 * float32(i+1)
		tgtTicks[i] = 0.2
	}
	loss, err := nativecpp.StackLineTrainMSE(
		int32(parallel.ModeStepTween), nChildren, nTicks, batch, 0.1, int32(core.DTypeFloat32),
		inH, outH, act, packed, xTicks, tgtTicks, wAfter,
	)
	must(err)
	fmt.Println("line StepTween loss", loss)
}

func must(err error) {
	if err != nil {
		panic(err)
	}
}