diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index dd3082f..8d81eb0 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,5 +1,5 @@ # Use the official .NET 8 SDK image -FROM mcr.microsoft.com/dotnet/sdk:8.0 +FROM mcr.microsoft.com/dotnet/sdk:10.0 # Set the working directory inside the container WORKDIR /workspace diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index a0eb06a..5e11f15 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,8 +1,11 @@ { - "name": "NET 8 DevContainer", + "name": "NET 10 DevContainer", "build": { "dockerfile": "Dockerfile" }, + "mounts": [ + "source=${localEnv:USERPROFILE}/.nuget/packages,target=/root/.nuget/packages,type=bind,consistency=cached" + ], "settings": { "terminal.integrated.shell.linux": "/bin/bash" }, diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 97e8beb..2a8108a 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -15,10 +15,10 @@ jobs: - name: Checkout uses: actions/checkout@main - - name: Setup .NET 8 + - name: Setup .NET 10 uses: actions/setup-dotnet@v1 with: - dotnet-version: '8.0.100' + dotnet-version: '10.0.x' - name: Build run: | diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml index 96125e2..ae84f70 100644 --- a/.github/workflows/publish.yaml +++ b/.github/workflows/publish.yaml @@ -15,10 +15,10 @@ jobs: - name: Checkout uses: actions/checkout@main - - name: Setup .NET 8 + - name: Setup .NET 10 uses: actions/setup-dotnet@v1 with: - dotnet-version: '8.0.100' + dotnet-version: '10.0.x' source-url: https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json env: NUGET_AUTH_TOKEN: ${{ github.token }} diff --git a/.gitignore b/.gitignore index 6491931..d46d88a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,8 @@ -.idea/ -.vscode/ - -tiny-brain.sln.DotSettings.user - -obj/ -bin/ - +.idea/ +.vscode/ + +tiny-brain.sln.DotSettings.user + +obj/ +bin/ + diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..8d10d63 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,63 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Commands + +```bash +# Build entire solution +dotnet build code/tiny-brain.sln + +# Run all tests +dotnet test code/test/tiny-brain-test.csproj + +# Run tests with coverage +dotnet test code/test/tiny-brain-test.csproj /p:CollectCoverage=true /p:CoverletOutput=TestResults/ /p:CoverletOutputFormat=lcov + +# Run a single test by name +dotnet test code/test/tiny-brain-test.csproj --filter "FullyQualifiedName~" + +# Run the bigram use-case +dotnet run --project code/use-cases/biagram/biagram.csproj + +# Run the playground +dotnet run --project code/use-cases/playground/playgroung.csproj +``` + +## Architecture + +The library is a from-scratch implementation of a neural network with autograd (inspired by micrograd / cs231n). Target: .NET 8, namespace `TinyBrain`. + +### Core abstraction: `Operand` + +`Operand` (`code/src/Expression/Operand.cs`) is the fundamental building block — a scalar value that carries its gradient and a `_backward` closure. All arithmetic operators (`+`, `-`, `*`, `/`) and unary ops (`Exp`, `Log`, `Pow`, `Relu`, `Tanh`) are overloaded to return new `Operand` instances that record their `Previous` pair. Calling `Backpropagation()` on an `Operand` runs a non-recursive topological sort over the expression graph and then invokes each node's `_backward` in reverse order. + +### Neural network layers + +``` +Brain (MLP) + └─ Layer[] (one per hidden/output layer) + └─ Neuron[] (each neuron owns its weights + bias as Operands) +``` + +- `Neuron` (`code/src/Neuron/Neuron.cs`) computes `f(Σ(xᵢ·wᵢ) + b)` where `f` is determined by `ActivationType`. +- `Layer` (`code/src/Layers/Layer.cs`) fans inputs through all neurons; `Forward` returns one `Operand` per neuron. +- `Brain` (`code/src/MLP/Brain.cs`) chains layers via `Fold`; `Forward` auto-zeros gradients before each pass. + +### Activation functions + +`Activations.cs` holds the dispatch dictionary keyed on `ActivationType` (currently `None` and `Tanh`). `Tanh` is expressed in terms of `Exp`, `/`, and `-` on `Operand` so its gradient flows automatically through the graph — no hand-coded derivative needed. + +### Functional style + +The library depends on `tiny-fp` (functional primitives: `Option`, `Unit`, `Map`, `Tee`, `Fold`, `ForEach`). Prefer these combinators over imperative loops; `Unit` is used as the return type of side-effecting void-like operations. + +### Use-cases + +`code/use-cases/biagram/` implements a character-level bigram language model using a `Brain(27 → 27)` with `ActivationType.None` followed by a manual softmax. Parameters can be saved/loaded via `SaveParameters` / `LoadParameters` to `parameters.txt`. + +`code/use-cases/playground/` is a scratch area for manual experiments. + +### Test structure + +Tests use NUnit 3 + Shouldly assertions. `MLPTrainingTests.Training` is a full end-to-end gradient-descent loop that runs until loss < 0.00001 or 10 000 steps — it is intentionally slow and exercises the entire autograd pipeline. diff --git a/LICENSE b/LICENSE index 5ec4e56..1b04fad 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2025 Franco Melandri - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Copyright (c) 2025 Franco Melandri + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index a449b9e..1134550 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ -# tiny-brain - -The aim of the project is to create a small system based on neural network. - -This system is called `tiny brain`. - -I would like to consider this like a small brain that could be integrated inside bigger application -I would like to use the brain as a base engine to perform tasks - - +# tiny-brain + +The aim of the project is to create a small system based on neural network. + +This system is called `tiny brain`. + +I would like to consider this like a small brain that could be integrated inside bigger application +I would like to use the brain as a base engine to perform tasks + + diff --git a/code/src/Expression/Operand.cs b/code/src/Expression/Operand.cs index ddcb294..5d1f668 100644 --- a/code/src/Expression/Operand.cs +++ b/code/src/Expression/Operand.cs @@ -1,178 +1,178 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection.Metadata.Ecma335; -using TinyFp; -using TinyFp.Extensions; -using static TinyFp.Extensions.Functional; -using static TinyBrain.Constants; - -namespace TinyBrain; - -public class Operand -{ - public (Option Operand1, Option Operand2) Previous { get; } - public double Data { get; set; } - public double Gradient { get; set; } - public string Label { get; set; } - private Func _backward; - - private Operand() - { - Previous = (Option.None(), Option.None()); - Gradient = ZERO; - Label = string.Empty; - _backward = () => Unit.Default; - } - - private Operand(double data) - : this() - { - Data = data; - } - - private Operand(double data, string label) - : this(data) - { - Label = label; - } - - private Operand(double data, (Operand, Operand) previous) - : this(data) - { - Previous = (previous.Item1.ToOption(), previous.Item2.ToOption()); - } - - public static Operand Of(double data) => new(data); - - public static Operand Of(double data, string label) => new(data, label); - - public static Operand operator +(Operand a, Operand b) - => new Operand(a.Data + b.Data, (a, b)) - .Tee(_ => _._backward = () => - Unit.Default - .Tee(__ => a.Gradient += GRADIENT_PLUS * _.Gradient) - .Tee(__ => b.Gradient += GRADIENT_PLUS * _.Gradient)); - - public static Operand operator +(Operand a, double bval) - => a + Of(bval); - - public static Operand operator +(double aval, Operand b) - => Of(aval) + b; - - public static Operand operator -(Operand a, Operand b) - => new Operand(a.Data - b.Data, (a, b)) - .Tee(_ => _._backward = () => - Unit.Default - .Tee(__ => a.Gradient += GRADIENT_MINUS * _.Gradient) - .Tee(__ => b.Gradient += GRADIENT_MINUS * _.Gradient)); - - public static Operand operator -(Operand a, double bval) - => a - Of(bval); - - public static Operand operator -(double aval, Operand b) - => Of(aval) - b; - - public static Operand operator *(Operand a, Operand b) - => new Operand(a.Data * b.Data, (a, b)) - .Tee(_ => _._backward = () => - Unit.Default - .Tee(__ => a.Gradient += b.Data * _.Gradient) - .Tee(__ => b.Gradient += a.Data * _.Gradient)); - - public static Operand operator *(Operand a, double bval) - => a * Of(bval); - - public static Operand operator *(double aval, Operand b) - => Of(aval) * b ; - - public static Operand operator /(Operand a, Operand b) - => new Operand(a.Data / b.Data, (a, b)) - .Tee(_ => _._backward = () => - Unit.Default - .Tee(__ => a.Gradient += 1/b.Data * _.Gradient) - .Tee(__ => b.Gradient += (-a.Data/Math.Pow(b.Data, 2)) * _.Gradient)); - - public static Operand operator /(Operand a, double bval) - => a / Of(bval); - - public static Operand operator /(double aval, Operand b) - => Of(aval) / b; - - public Operand Exp() - => new Operand(Math.Exp(Data), (this, null)) - .Tee(_ => _._backward = () => - Unit.Default - .Tee(__ => Gradient += _.Data * _.Gradient)); - - public Operand Log() - => new Operand(Math.Log(Data), (this, null)) - .Tee(_ => _._backward = () => - Unit.Default - .Tee(__ => Gradient += 1/_.Data * _.Gradient)); - - public Operand Pow(double exponent) - => new Operand(Math.Pow(Data, exponent), (this, null)) - .Tee(_ => _._backward = () => - Unit.Default - .Tee(__ => Gradient += exponent * Math.Pow(Data, exponent - 1) * _.Gradient)); - - public Operand Relu() - => new Operand( - Data < 0 ? 0 : Data, - (this, null)) - .Tee(_ => _._backward = () => - Unit.Default - .Tee(__ => Gradient += _.Data * _.Gradient)); - - private static HashSet BuildTopologicalRecursive(HashSet operands, Operand item) - => operands - .ToOption(_ => _.Contains(item)) - .Map(_ => _.Tee(_ => item.Previous.Operand1.OnSome(operand1 => BuildTopologicalRecursive(_, operand1)))) - .Map(_ => _.Tee(_ => item.Previous.Operand2.OnSome(operand2 => BuildTopologicalRecursive(_, operand2)))) - .Map(_ => _.Tee(_ => _.Add(item))) - .OrElse(operands); - - private static List BuildTopologicalNonRecursive(Operand root) - => While(() => (HashSet: new HashSet(), Stack: new Stack().Tee(_ => _.Push(root))), - _ => _.Stack.Count > 0, - _ => - { - var current = _.Stack.Peek(); - - if (!_.HashSet.Contains(current)) - { - if (current.Previous.Operand2.IsSome) - { - var operand2 = current.Previous.Operand2.Unwrap(); - if (!_.HashSet.Contains(operand2)) - { - _.Stack.Push(operand2); - return _; - } - } - - if (current.Previous.Operand1.IsSome) - { - var operand1 = current.Previous.Operand1.Unwrap(); - if (!_.HashSet.Contains(operand1)) - { - _.Stack.Push(operand1); - return _; - } - } - } - _.HashSet.Add(current); - _.Stack.Pop(); - return _; - } - ) - .Map(_ => _.Item1.ToList()); - - public Unit Backpropagation() - => Unit.Default - .Tee(_ => Gradient = ONE) - .Tee(_ => BuildTopologicalNonRecursive(this) - .Map(operands => operands.Tee(_ => operands.Reverse())) - .ForEach(operand => operand._backward())); -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection.Metadata.Ecma335; +using TinyFp; +using TinyFp.Extensions; +using static TinyFp.Extensions.Functional; +using static TinyBrain.Constants; + +namespace TinyBrain; + +public class Operand +{ + public (Option Operand1, Option Operand2) Previous { get; } + public double Data { get; set; } + public double Gradient { get; set; } + public string Label { get; set; } + private Func _backward; + + private Operand() + { + Previous = (Option.None(), Option.None()); + Gradient = ZERO; + Label = string.Empty; + _backward = () => Unit.Default; + } + + private Operand(double data) + : this() + { + Data = data; + } + + private Operand(double data, string label) + : this(data) + { + Label = label; + } + + private Operand(double data, (Operand, Operand) previous) + : this(data) + { + Previous = (previous.Item1.ToOption(), previous.Item2.ToOption()); + } + + public static Operand Of(double data) => new(data); + + public static Operand Of(double data, string label) => new(data, label); + + public static Operand operator +(Operand a, Operand b) + => new Operand(a.Data + b.Data, (a, b)) + .Tee(_ => _._backward = () => + Unit.Default + .Tee(__ => a.Gradient += GRADIENT_PLUS * _.Gradient) + .Tee(__ => b.Gradient += GRADIENT_PLUS * _.Gradient)); + + public static Operand operator +(Operand a, double bval) + => a + Of(bval); + + public static Operand operator +(double aval, Operand b) + => Of(aval) + b; + + public static Operand operator -(Operand a, Operand b) + => new Operand(a.Data - b.Data, (a, b)) + .Tee(_ => _._backward = () => + Unit.Default + .Tee(__ => a.Gradient += GRADIENT_MINUS * _.Gradient) + .Tee(__ => b.Gradient += GRADIENT_MINUS * _.Gradient)); + + public static Operand operator -(Operand a, double bval) + => a - Of(bval); + + public static Operand operator -(double aval, Operand b) + => Of(aval) - b; + + public static Operand operator *(Operand a, Operand b) + => new Operand(a.Data * b.Data, (a, b)) + .Tee(_ => _._backward = () => + Unit.Default + .Tee(__ => a.Gradient += b.Data * _.Gradient) + .Tee(__ => b.Gradient += a.Data * _.Gradient)); + + public static Operand operator *(Operand a, double bval) + => a * Of(bval); + + public static Operand operator *(double aval, Operand b) + => Of(aval) * b ; + + public static Operand operator /(Operand a, Operand b) + => new Operand(a.Data / b.Data, (a, b)) + .Tee(_ => _._backward = () => + Unit.Default + .Tee(__ => a.Gradient += 1/b.Data * _.Gradient) + .Tee(__ => b.Gradient += (-a.Data/Math.Pow(b.Data, 2)) * _.Gradient)); + + public static Operand operator /(Operand a, double bval) + => a / Of(bval); + + public static Operand operator /(double aval, Operand b) + => Of(aval) / b; + + public Operand Exp() + => new Operand(Math.Exp(Data), (this, null)) + .Tee(_ => _._backward = () => + Unit.Default + .Tee(__ => Gradient += _.Data * _.Gradient)); + + public Operand Log() + => new Operand(Math.Log(Data), (this, null)) + .Tee(_ => _._backward = () => + Unit.Default + .Tee(__ => Gradient += 1/_.Data * _.Gradient)); + + public Operand Pow(double exponent) + => new Operand(Math.Pow(Data, exponent), (this, null)) + .Tee(_ => _._backward = () => + Unit.Default + .Tee(__ => Gradient += exponent * Math.Pow(Data, exponent - 1) * _.Gradient)); + + public Operand Relu() + => new Operand( + Data < 0 ? 0 : Data, + (this, null)) + .Tee(_ => _._backward = () => + Unit.Default + .Tee(__ => Gradient += _.Data * _.Gradient)); + + private static HashSet BuildTopologicalRecursive(HashSet operands, Operand item) + => operands + .ToOption(_ => _.Contains(item)) + .Map(_ => _.Tee(_ => item.Previous.Operand1.OnSome(operand1 => BuildTopologicalRecursive(_, operand1)))) + .Map(_ => _.Tee(_ => item.Previous.Operand2.OnSome(operand2 => BuildTopologicalRecursive(_, operand2)))) + .Map(_ => _.Tee(_ => _.Add(item))) + .OrElse(operands); + + private static List BuildTopologicalNonRecursive(Operand root) + => While(() => (HashSet: new HashSet(), Stack: new Stack().Tee(_ => _.Push(root))), + _ => _.Stack.Count > 0, + _ => + { + var current = _.Stack.Peek(); + + if (!_.HashSet.Contains(current)) + { + if (current.Previous.Operand2.IsSome) + { + var operand2 = current.Previous.Operand2.Unwrap(); + if (!_.HashSet.Contains(operand2)) + { + _.Stack.Push(operand2); + return _; + } + } + + if (current.Previous.Operand1.IsSome) + { + var operand1 = current.Previous.Operand1.Unwrap(); + if (!_.HashSet.Contains(operand1)) + { + _.Stack.Push(operand1); + return _; + } + } + } + _.HashSet.Add(current); + _.Stack.Pop(); + return _; + } + ) + .Map(_ => _.Item1.ToList()); + + public Unit Backpropagation() + => Unit.Default + .Tee(_ => Gradient = ONE) + .Tee(_ => BuildTopologicalNonRecursive(this) + .Map(operands => operands.Tee(_ => operands.Reverse())) + .ForEach(operand => operand._backward())); +} diff --git a/code/src/tiny-brain.csproj b/code/src/tiny-brain.csproj index 9eae227..140dac7 100644 --- a/code/src/tiny-brain.csproj +++ b/code/src/tiny-brain.csproj @@ -1,12 +1,12 @@ - - - - net8.0 - TinyBrain - - - - - - - + + + + net10.0 + TinyBrain + + + + + + + diff --git a/code/test/OperandTests.cs b/code/test/OperandTests.cs index 5628d2f..f5292e1 100644 --- a/code/test/OperandTests.cs +++ b/code/test/OperandTests.cs @@ -1,266 +1,266 @@ -using Shouldly; - -namespace TinyBrain.Test; - -public class OperandTests -{ - [Test] - public void Token_Sum_Is_Right() - { - var operand1 = Operand.Of(42.0); - var operand2 = Operand.Of(66.0); - var token = operand1 + operand2; - token.Data.ShouldBe(108.0); - token.Previous.Operand1.Unwrap().ShouldBe(operand1); - token.Previous.Operand2.Unwrap().ShouldBe(operand2); - } - - [Test] - public void Token_And_Constant_Sum_Is_Right() - { - var operand1 = Operand.Of(42.0); - var operand2 = operand1 + 10; - var token3 = 10 + operand1; - operand2.Data.ShouldBe(52.0); - token3.Data.ShouldBe(52.0); - operand2.Previous.Operand1.Unwrap().ShouldBe(operand1); - operand2.Previous.Operand2.Unwrap().Previous.Operand1.IsNone.ShouldBe(true); - operand2.Previous.Operand2.Unwrap().Previous.Operand2.IsNone.ShouldBe(true); - token3.Previous.Operand2.Unwrap().ShouldBe(operand1); - token3.Previous.Operand2.Unwrap().Previous.Operand1.IsNone.ShouldBe(true); - token3.Previous.Operand2.Unwrap().Previous.Operand2.IsNone.ShouldBe(true); - } - - [Test] - public void Token_Sub_Is_Right() - { - var operand1 = Operand.Of(66.0); - var operand2 = Operand.Of(42.0); - var token = operand1 - operand2; - token.Data.ShouldBe(24.0); - token.Previous.Operand1.Unwrap().ShouldBe(operand1); - token.Previous.Operand2.Unwrap().ShouldBe(operand2); - } - - [Test] - public void Token_Sub_Constant_Sum_Is_Right() - { - var operand1 = Operand.Of(42.0); - var operand2 = operand1 - 10; - var token3 = 10 - operand1; - operand2.Data.ShouldBe(32.0); - token3.Data.ShouldBe(-32.0); - operand2.Previous.Operand1.Unwrap().ShouldBe(operand1); - operand2.Previous.Operand2.Unwrap().Previous.Operand1.IsNone.ShouldBe(true); - operand2.Previous.Operand2.Unwrap().Previous.Operand2.IsNone.ShouldBe(true); - token3.Previous.Operand2.Unwrap().ShouldBe(operand1); - token3.Previous.Operand2.Unwrap().Previous.Operand1.IsNone.ShouldBe(true); - token3.Previous.Operand2.Unwrap().Previous.Operand2.IsNone.ShouldBe(true); - } - - [Test] - public void Token_Mul_Is_Right() - { - var operand1 = Operand.Of(42.0); - var operand2 = Operand.Of(2.0); - var token = operand1 * operand2; - token.Data.ShouldBe(84.0); - token.Previous.Operand1.Unwrap().ShouldBe(operand1); - token.Previous.Operand2.Unwrap().ShouldBe(operand2); - } - - [Test] - public void Token_And_Constant_Mul_Is_Right() - { - var operand1 = Operand.Of(42.0); - var operand2 = operand1 * 2; - var token3 = 2 * operand1; - operand2.Data.ShouldBe(84.0); - token3.Data.ShouldBe(84.0); - operand2.Previous.Operand1.Unwrap().ShouldBe(operand1); - operand2.Previous.Operand2.Unwrap().Previous.Operand1.IsNone.ShouldBe(true); - operand2.Previous.Operand2.Unwrap().Previous.Operand2.IsNone.ShouldBe(true); - token3.Previous.Operand2.Unwrap().ShouldBe(operand1); - token3.Previous.Operand2.Unwrap().Previous.Operand1.IsNone.ShouldBe(true); - token3.Previous.Operand2.Unwrap().Previous.Operand2.IsNone.ShouldBe(true); - } - [Test] - public void Token_Div_Is_Right() - { - var operand1 = Operand.Of(42.0); - var operand2 = Operand.Of(2.0); - var token = operand1 / operand2; - token.Data.ShouldBe(21.0); - token.Previous.Operand1.Unwrap().ShouldBe(operand1); - token.Previous.Operand2.Unwrap().ShouldBe(operand2); - } - - [Test] - public void Token_And_Constant_Div_Is_Right() - { - var operand1 = Operand.Of(42.0); - var operand2 = operand1 / 2; - var token3 = 84 / operand1; - operand2.Data.ShouldBe(21.0); - token3.Data.ShouldBe(2.0); - operand2.Previous.Operand1.Unwrap().ShouldBe(operand1); - operand2.Previous.Operand2.Unwrap().Previous.Operand1.IsNone.ShouldBe(true); - operand2.Previous.Operand2.Unwrap().Previous.Operand2.IsNone.ShouldBe(true); - token3.Previous.Operand2.Unwrap().ShouldBe(operand1); - token3.Previous.Operand2.Unwrap().Previous.Operand1.IsNone.ShouldBe(true); - token3.Previous.Operand2.Unwrap().Previous.Operand2.IsNone.ShouldBe(true); - } - - [Test] - public void Complex_Right() - { - var a = Operand.Of(2.0); - var b = Operand.Of(-3.0); - var c = Operand.Of(10); - var e = a*b; - var d = e + c; - - d.Data.ShouldBe(4.0); - d.Previous.Operand1.Unwrap().Data.ShouldBe(-6); - d.Previous.Operand2.Unwrap().Data.ShouldBe(10); - - d.Previous.Operand2.Unwrap().Previous.Operand1.IsNone.ShouldBe(true); - d.Previous.Operand2.Unwrap().Previous.Operand2.IsNone.ShouldBe(true); - - d.Previous.Operand1.Unwrap().Previous.Operand1.Unwrap().Data.ShouldBe(2); - d.Previous.Operand1.Unwrap().Previous.Operand2.Unwrap().Data.ShouldBe(-3); - - d.Previous.Operand1.Unwrap().Previous.Operand1.Unwrap().Previous.Operand1.IsNone.ShouldBe(true); - d.Previous.Operand1.Unwrap().Previous.Operand1.Unwrap().Previous.Operand2.IsNone.ShouldBe(true); - d.Previous.Operand1.Unwrap().Previous.Operand2.Unwrap().Previous.Operand1.IsNone.ShouldBe(true); - d.Previous.Operand1.Unwrap().Previous.Operand2.Unwrap().Previous.Operand2.IsNone.ShouldBe(true); - } - - [Test] - public void Neuron() - { - // bidimensional - // x1*w1 + x2*w2 + b - - // inputs - var x1 = Operand.Of(2.0); - var x2 =Operand.Of(0); - - // weights - var w1 = Operand.Of(-3.0); - var w2 =Operand.Of(1); - - // BIAS - var b = Operand.Of(6.8813735870195432); - - var x1w1 = x1*w1; - var x2w2 = x2*w2; - - var x1w1x2w2 = x1w1 + x2w2; - var n = x1w1x2w2 + b; - - var o = n.Tanh(); - o.Backpropagation(); - - o.Data.ShouldBe(0.7071067811865476); - n.Gradient.ShouldBe(0.4999999999999999); - - x1w1x2w2.Gradient.ShouldBe(0.4999999999999999); - b.Gradient.ShouldBe(0.4999999999999999); - - x1w1.Gradient.ShouldBe(0.4999999999999999); - x2w2.Gradient.ShouldBe(0.4999999999999999); - - x2.Gradient.ShouldBe(0.4999999999999999); - w2.Gradient.ShouldBe(0); - x1.Gradient.ShouldBe(-1.4999999999999996); - w1.Gradient.ShouldBe(0.9999999999999998); - } - - [Test] - public void Neuron_Breaking_Activation() - { - // bidimensional - // x1*w1 + x2*w2 + b - - // inputs - var x1 = Operand.Of(2.0, "x1"); - var x2 = Operand.Of(0, "x2"); - - // weights - var w1 = Operand.Of(-3.0, "w1"); - var w2 =Operand.Of(1, "w2"); - - // BIAS - var b = Operand.Of(6.8813735870195432, "bias"); - - var x1w1 = x1*w1; - x1w1.Label = "x1w1"; - var x2w2 = x2*w2; - x2w2.Label = "x2w2"; - - var x1w1x2w2 = x1w1 + x2w2; - x1w1x2w2.Label = "x1w1x2w2"; - var n = x1w1x2w2 + b; - n.Label = "n"; - var n2 = n * 2; - n2.Label = "n2"; - var e = n2.Exp(); - e.Label = "e"; - var e1 = e - 1; - e1.Label = "e1"; - var e2 = e + 1; - e2.Label = "e2"; - - var o = e1/e2; - o.Label = "o"; - - - o.Gradient = 1.0; - o.Backpropagation(); - o.Data.ShouldBe(0.7071067811865476); - n.Gradient.ShouldBe(0.4999999999999999); - - b.Gradient.ShouldBe(0.4999999999999999); - x1w1x2w2.Gradient.ShouldBe(0.4999999999999999); - - x1w1.Gradient.ShouldBe(0.4999999999999999); - x2w2.Gradient.ShouldBe(0.4999999999999999); - - x2.Gradient.ShouldBe(0.4999999999999999); - w2.Gradient.ShouldBe(0); - x1.Gradient.ShouldBe(-1.4999999999999996); - w1.Gradient.ShouldBe(0.9999999999999998); - } - - [Test] - public void Token_Exp_Is_Right() - { - var operand1 = Operand.Of(2.0); - var operand2 = operand1.Exp(); - operand2.Data.ShouldBe(7.38905609893065); - operand2.Previous.Operand1.Unwrap().ShouldBe(operand1); - operand2.Previous.Operand2.IsNone.ShouldBe(true); - } - - [Test] - public void Token_LogIs_Right() - { - var operand1 = Operand.Of(5.0); - var operand2 = operand1.Log(); - operand2.Data.ShouldBe(1.6094379124341003746007593332262); - operand2.Previous.Operand1.Unwrap().ShouldBe(operand1); - operand2.Previous.Operand2.IsNone.ShouldBe(true); - } - - [Test] - public void Token_Pow_Is_Right() - { - var operand1 = Operand.Of(2.0); - var operand2 = operand1.Pow(3); - - operand2.Data.ShouldBe(8); - operand2.Previous.Operand1.Unwrap().ShouldBe(operand1); - operand2.Previous.Operand2.IsNone.ShouldBe(true); - } +using Shouldly; + +namespace TinyBrain.Test; + +public class OperandTests +{ + [Test] + public void Token_Sum_Is_Right() + { + var operand1 = Operand.Of(42.0); + var operand2 = Operand.Of(66.0); + var token = operand1 + operand2; + token.Data.ShouldBe(108.0); + token.Previous.Operand1.Unwrap().ShouldBe(operand1); + token.Previous.Operand2.Unwrap().ShouldBe(operand2); + } + + [Test] + public void Token_And_Constant_Sum_Is_Right() + { + var operand1 = Operand.Of(42.0); + var operand2 = operand1 + 10; + var token3 = 10 + operand1; + operand2.Data.ShouldBe(52.0); + token3.Data.ShouldBe(52.0); + operand2.Previous.Operand1.Unwrap().ShouldBe(operand1); + operand2.Previous.Operand2.Unwrap().Previous.Operand1.IsNone.ShouldBe(true); + operand2.Previous.Operand2.Unwrap().Previous.Operand2.IsNone.ShouldBe(true); + token3.Previous.Operand2.Unwrap().ShouldBe(operand1); + token3.Previous.Operand2.Unwrap().Previous.Operand1.IsNone.ShouldBe(true); + token3.Previous.Operand2.Unwrap().Previous.Operand2.IsNone.ShouldBe(true); + } + + [Test] + public void Token_Sub_Is_Right() + { + var operand1 = Operand.Of(66.0); + var operand2 = Operand.Of(42.0); + var token = operand1 - operand2; + token.Data.ShouldBe(24.0); + token.Previous.Operand1.Unwrap().ShouldBe(operand1); + token.Previous.Operand2.Unwrap().ShouldBe(operand2); + } + + [Test] + public void Token_Sub_Constant_Sum_Is_Right() + { + var operand1 = Operand.Of(42.0); + var operand2 = operand1 - 10; + var token3 = 10 - operand1; + operand2.Data.ShouldBe(32.0); + token3.Data.ShouldBe(-32.0); + operand2.Previous.Operand1.Unwrap().ShouldBe(operand1); + operand2.Previous.Operand2.Unwrap().Previous.Operand1.IsNone.ShouldBe(true); + operand2.Previous.Operand2.Unwrap().Previous.Operand2.IsNone.ShouldBe(true); + token3.Previous.Operand2.Unwrap().ShouldBe(operand1); + token3.Previous.Operand2.Unwrap().Previous.Operand1.IsNone.ShouldBe(true); + token3.Previous.Operand2.Unwrap().Previous.Operand2.IsNone.ShouldBe(true); + } + + [Test] + public void Token_Mul_Is_Right() + { + var operand1 = Operand.Of(42.0); + var operand2 = Operand.Of(2.0); + var token = operand1 * operand2; + token.Data.ShouldBe(84.0); + token.Previous.Operand1.Unwrap().ShouldBe(operand1); + token.Previous.Operand2.Unwrap().ShouldBe(operand2); + } + + [Test] + public void Token_And_Constant_Mul_Is_Right() + { + var operand1 = Operand.Of(42.0); + var operand2 = operand1 * 2; + var token3 = 2 * operand1; + operand2.Data.ShouldBe(84.0); + token3.Data.ShouldBe(84.0); + operand2.Previous.Operand1.Unwrap().ShouldBe(operand1); + operand2.Previous.Operand2.Unwrap().Previous.Operand1.IsNone.ShouldBe(true); + operand2.Previous.Operand2.Unwrap().Previous.Operand2.IsNone.ShouldBe(true); + token3.Previous.Operand2.Unwrap().ShouldBe(operand1); + token3.Previous.Operand2.Unwrap().Previous.Operand1.IsNone.ShouldBe(true); + token3.Previous.Operand2.Unwrap().Previous.Operand2.IsNone.ShouldBe(true); + } + [Test] + public void Token_Div_Is_Right() + { + var operand1 = Operand.Of(42.0); + var operand2 = Operand.Of(2.0); + var token = operand1 / operand2; + token.Data.ShouldBe(21.0); + token.Previous.Operand1.Unwrap().ShouldBe(operand1); + token.Previous.Operand2.Unwrap().ShouldBe(operand2); + } + + [Test] + public void Token_And_Constant_Div_Is_Right() + { + var operand1 = Operand.Of(42.0); + var operand2 = operand1 / 2; + var token3 = 84 / operand1; + operand2.Data.ShouldBe(21.0); + token3.Data.ShouldBe(2.0); + operand2.Previous.Operand1.Unwrap().ShouldBe(operand1); + operand2.Previous.Operand2.Unwrap().Previous.Operand1.IsNone.ShouldBe(true); + operand2.Previous.Operand2.Unwrap().Previous.Operand2.IsNone.ShouldBe(true); + token3.Previous.Operand2.Unwrap().ShouldBe(operand1); + token3.Previous.Operand2.Unwrap().Previous.Operand1.IsNone.ShouldBe(true); + token3.Previous.Operand2.Unwrap().Previous.Operand2.IsNone.ShouldBe(true); + } + + [Test] + public void Complex_Right() + { + var a = Operand.Of(2.0); + var b = Operand.Of(-3.0); + var c = Operand.Of(10); + var e = a*b; + var d = e + c; + + d.Data.ShouldBe(4.0); + d.Previous.Operand1.Unwrap().Data.ShouldBe(-6); + d.Previous.Operand2.Unwrap().Data.ShouldBe(10); + + d.Previous.Operand2.Unwrap().Previous.Operand1.IsNone.ShouldBe(true); + d.Previous.Operand2.Unwrap().Previous.Operand2.IsNone.ShouldBe(true); + + d.Previous.Operand1.Unwrap().Previous.Operand1.Unwrap().Data.ShouldBe(2); + d.Previous.Operand1.Unwrap().Previous.Operand2.Unwrap().Data.ShouldBe(-3); + + d.Previous.Operand1.Unwrap().Previous.Operand1.Unwrap().Previous.Operand1.IsNone.ShouldBe(true); + d.Previous.Operand1.Unwrap().Previous.Operand1.Unwrap().Previous.Operand2.IsNone.ShouldBe(true); + d.Previous.Operand1.Unwrap().Previous.Operand2.Unwrap().Previous.Operand1.IsNone.ShouldBe(true); + d.Previous.Operand1.Unwrap().Previous.Operand2.Unwrap().Previous.Operand2.IsNone.ShouldBe(true); + } + + [Test] + public void Neuron() + { + // bidimensional + // x1*w1 + x2*w2 + b + + // inputs + var x1 = Operand.Of(2.0); + var x2 =Operand.Of(0); + + // weights + var w1 = Operand.Of(-3.0); + var w2 =Operand.Of(1); + + // BIAS + var b = Operand.Of(6.8813735870195432); + + var x1w1 = x1*w1; + var x2w2 = x2*w2; + + var x1w1x2w2 = x1w1 + x2w2; + var n = x1w1x2w2 + b; + + var o = n.Tanh(); + o.Backpropagation(); + + o.Data.ShouldBe(0.7071067811865476); + n.Gradient.ShouldBe(0.4999999999999999); + + x1w1x2w2.Gradient.ShouldBe(0.4999999999999999); + b.Gradient.ShouldBe(0.4999999999999999); + + x1w1.Gradient.ShouldBe(0.4999999999999999); + x2w2.Gradient.ShouldBe(0.4999999999999999); + + x2.Gradient.ShouldBe(0.4999999999999999); + w2.Gradient.ShouldBe(0); + x1.Gradient.ShouldBe(-1.4999999999999996); + w1.Gradient.ShouldBe(0.9999999999999998); + } + + [Test] + public void Neuron_Breaking_Activation() + { + // bidimensional + // x1*w1 + x2*w2 + b + + // inputs + var x1 = Operand.Of(2.0, "x1"); + var x2 = Operand.Of(0, "x2"); + + // weights + var w1 = Operand.Of(-3.0, "w1"); + var w2 =Operand.Of(1, "w2"); + + // BIAS + var b = Operand.Of(6.8813735870195432, "bias"); + + var x1w1 = x1*w1; + x1w1.Label = "x1w1"; + var x2w2 = x2*w2; + x2w2.Label = "x2w2"; + + var x1w1x2w2 = x1w1 + x2w2; + x1w1x2w2.Label = "x1w1x2w2"; + var n = x1w1x2w2 + b; + n.Label = "n"; + var n2 = n * 2; + n2.Label = "n2"; + var e = n2.Exp(); + e.Label = "e"; + var e1 = e - 1; + e1.Label = "e1"; + var e2 = e + 1; + e2.Label = "e2"; + + var o = e1/e2; + o.Label = "o"; + + + o.Gradient = 1.0; + o.Backpropagation(); + o.Data.ShouldBe(0.7071067811865476); + n.Gradient.ShouldBe(0.4999999999999999); + + b.Gradient.ShouldBe(0.4999999999999999); + x1w1x2w2.Gradient.ShouldBe(0.4999999999999999); + + x1w1.Gradient.ShouldBe(0.4999999999999999); + x2w2.Gradient.ShouldBe(0.4999999999999999); + + x2.Gradient.ShouldBe(0.4999999999999999); + w2.Gradient.ShouldBe(0); + x1.Gradient.ShouldBe(-1.4999999999999996); + w1.Gradient.ShouldBe(0.9999999999999998); + } + + [Test] + public void Token_Exp_Is_Right() + { + var operand1 = Operand.Of(2.0); + var operand2 = operand1.Exp(); + operand2.Data.ShouldBe(7.38905609893065); + operand2.Previous.Operand1.Unwrap().ShouldBe(operand1); + operand2.Previous.Operand2.IsNone.ShouldBe(true); + } + + [Test] + public void Token_LogIs_Right() + { + var operand1 = Operand.Of(5.0); + var operand2 = operand1.Log(); + operand2.Data.ShouldBe(1.6094379124341003746007593332262); + operand2.Previous.Operand1.Unwrap().ShouldBe(operand1); + operand2.Previous.Operand2.IsNone.ShouldBe(true); + } + + [Test] + public void Token_Pow_Is_Right() + { + var operand1 = Operand.Of(2.0); + var operand2 = operand1.Pow(3); + + operand2.Data.ShouldBe(8); + operand2.Previous.Operand1.Unwrap().ShouldBe(operand1); + operand2.Previous.Operand2.IsNone.ShouldBe(true); + } } \ No newline at end of file diff --git a/code/test/tiny-brain-test.csproj b/code/test/tiny-brain-test.csproj index 68d02dd..970e30b 100644 --- a/code/test/tiny-brain-test.csproj +++ b/code/test/tiny-brain-test.csproj @@ -1,26 +1,26 @@ - - - - net8.0 - TinyBrain.Tests - - - - - - - - - - - - - - - - - - - - - + + + + net10.0 + TinyBrain.Tests + + + + + + + + + + + + + + + + + + + + + diff --git a/code/tiny-brain.sln b/code/tiny-brain.sln index ea0e4ff..68ec787 100644 --- a/code/tiny-brain.sln +++ b/code/tiny-brain.sln @@ -1,76 +1,76 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.5.2.0 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "code", "code", "{314C6247-30EA-3492-19B6-DF847E3B326F}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tiny-brain", "src\tiny-brain.csproj", "{71ED6FFF-AFD9-C033-F93B-B2229AA9472D}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tiny-brain-test", "test\tiny-brain-test.csproj", "{7D35C0D9-71F6-3FD2-A267-1537DF414438}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "files", "files", "{61A6599A-D1C9-4C0A-97A6-4B073FEDDE09}" - ProjectSection(SolutionItems) = preProject - ..\README.md = ..\README.md - ..\version = ..\version - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{7131F29C-2885-4846-972B-DFF7179E4F75}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tiny", "tiny", "{AC36BEF3-595D-4F6B-B7D7-26698B0949AC}" - ProjectSection(SolutionItems) = preProject - ..\docs\tiny\brain.md = ..\docs\tiny\brain.md - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "assets", "assets", "{6E1DF246-D051-4A88-A678-BDFAAFA878E9}" - ProjectSection(SolutionItems) = preProject - ..\docs\assets\neuron.png = ..\docs\assets\neuron.png - ..\docs\assets\tanh.png = ..\docs\assets\tanh.png - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CI", "CI", "{634BF414-5AE2-485E-885F-5A9EBDAF99B7}" - ProjectSection(SolutionItems) = preProject - ..\.github\workflows\ci.yaml = ..\.github\workflows\ci.yaml - ..\.github\workflows\publish.yaml = ..\.github\workflows\publish.yaml - EndProjectSection -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "use-cases", "use-cases", "{DCE521F5-853A-4B3A-AC54-F0914EDF5FEC}" -EndProject -Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "biagram", "biagram", "{52E5086B-877E-44C2-A440-D9EA3BFC70CB}" -EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "biagram", "use-cases\biagram\biagram.csproj", "{811D8B64-35A6-4791-8E20-1C59C8133414}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|Any CPU = Debug|Any CPU - Release|Any CPU = Release|Any CPU - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {71ED6FFF-AFD9-C033-F93B-B2229AA9472D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {71ED6FFF-AFD9-C033-F93B-B2229AA9472D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {71ED6FFF-AFD9-C033-F93B-B2229AA9472D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {71ED6FFF-AFD9-C033-F93B-B2229AA9472D}.Release|Any CPU.Build.0 = Release|Any CPU - {7D35C0D9-71F6-3FD2-A267-1537DF414438}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {7D35C0D9-71F6-3FD2-A267-1537DF414438}.Debug|Any CPU.Build.0 = Debug|Any CPU - {7D35C0D9-71F6-3FD2-A267-1537DF414438}.Release|Any CPU.ActiveCfg = Release|Any CPU - {7D35C0D9-71F6-3FD2-A267-1537DF414438}.Release|Any CPU.Build.0 = Release|Any CPU - {811D8B64-35A6-4791-8E20-1C59C8133414}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {811D8B64-35A6-4791-8E20-1C59C8133414}.Debug|Any CPU.Build.0 = Debug|Any CPU - {811D8B64-35A6-4791-8E20-1C59C8133414}.Release|Any CPU.ActiveCfg = Release|Any CPU - {811D8B64-35A6-4791-8E20-1C59C8133414}.Release|Any CPU.Build.0 = Release|Any CPU - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(NestedProjects) = preSolution - {71ED6FFF-AFD9-C033-F93B-B2229AA9472D} = {314C6247-30EA-3492-19B6-DF847E3B326F} - {7D35C0D9-71F6-3FD2-A267-1537DF414438} = {314C6247-30EA-3492-19B6-DF847E3B326F} - {AC36BEF3-595D-4F6B-B7D7-26698B0949AC} = {7131F29C-2885-4846-972B-DFF7179E4F75} - {6E1DF246-D051-4A88-A678-BDFAAFA878E9} = {7131F29C-2885-4846-972B-DFF7179E4F75} - {DCE521F5-853A-4B3A-AC54-F0914EDF5FEC} = {314C6247-30EA-3492-19B6-DF847E3B326F} - {52E5086B-877E-44C2-A440-D9EA3BFC70CB} = {DCE521F5-853A-4B3A-AC54-F0914EDF5FEC} - {811D8B64-35A6-4791-8E20-1C59C8133414} = {52E5086B-877E-44C2-A440-D9EA3BFC70CB} - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {2E848099-E299-4765-A250-3E96C78553E6} - EndGlobalSection -EndGlobal +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.5.2.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "code", "code", "{314C6247-30EA-3492-19B6-DF847E3B326F}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tiny-brain", "src\tiny-brain.csproj", "{71ED6FFF-AFD9-C033-F93B-B2229AA9472D}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "tiny-brain-test", "test\tiny-brain-test.csproj", "{7D35C0D9-71F6-3FD2-A267-1537DF414438}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "files", "files", "{61A6599A-D1C9-4C0A-97A6-4B073FEDDE09}" + ProjectSection(SolutionItems) = preProject + ..\README.md = ..\README.md + ..\version = ..\version + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{7131F29C-2885-4846-972B-DFF7179E4F75}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tiny", "tiny", "{AC36BEF3-595D-4F6B-B7D7-26698B0949AC}" + ProjectSection(SolutionItems) = preProject + ..\docs\tiny\brain.md = ..\docs\tiny\brain.md + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "assets", "assets", "{6E1DF246-D051-4A88-A678-BDFAAFA878E9}" + ProjectSection(SolutionItems) = preProject + ..\docs\assets\neuron.png = ..\docs\assets\neuron.png + ..\docs\assets\tanh.png = ..\docs\assets\tanh.png + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "CI", "CI", "{634BF414-5AE2-485E-885F-5A9EBDAF99B7}" + ProjectSection(SolutionItems) = preProject + ..\.github\workflows\ci.yaml = ..\.github\workflows\ci.yaml + ..\.github\workflows\publish.yaml = ..\.github\workflows\publish.yaml + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "use-cases", "use-cases", "{DCE521F5-853A-4B3A-AC54-F0914EDF5FEC}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "biagram", "biagram", "{52E5086B-877E-44C2-A440-D9EA3BFC70CB}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "biagram", "use-cases\biagram\biagram.csproj", "{811D8B64-35A6-4791-8E20-1C59C8133414}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {71ED6FFF-AFD9-C033-F93B-B2229AA9472D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {71ED6FFF-AFD9-C033-F93B-B2229AA9472D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {71ED6FFF-AFD9-C033-F93B-B2229AA9472D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {71ED6FFF-AFD9-C033-F93B-B2229AA9472D}.Release|Any CPU.Build.0 = Release|Any CPU + {7D35C0D9-71F6-3FD2-A267-1537DF414438}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7D35C0D9-71F6-3FD2-A267-1537DF414438}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7D35C0D9-71F6-3FD2-A267-1537DF414438}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7D35C0D9-71F6-3FD2-A267-1537DF414438}.Release|Any CPU.Build.0 = Release|Any CPU + {811D8B64-35A6-4791-8E20-1C59C8133414}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {811D8B64-35A6-4791-8E20-1C59C8133414}.Debug|Any CPU.Build.0 = Debug|Any CPU + {811D8B64-35A6-4791-8E20-1C59C8133414}.Release|Any CPU.ActiveCfg = Release|Any CPU + {811D8B64-35A6-4791-8E20-1C59C8133414}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {71ED6FFF-AFD9-C033-F93B-B2229AA9472D} = {314C6247-30EA-3492-19B6-DF847E3B326F} + {7D35C0D9-71F6-3FD2-A267-1537DF414438} = {314C6247-30EA-3492-19B6-DF847E3B326F} + {AC36BEF3-595D-4F6B-B7D7-26698B0949AC} = {7131F29C-2885-4846-972B-DFF7179E4F75} + {6E1DF246-D051-4A88-A678-BDFAAFA878E9} = {7131F29C-2885-4846-972B-DFF7179E4F75} + {DCE521F5-853A-4B3A-AC54-F0914EDF5FEC} = {314C6247-30EA-3492-19B6-DF847E3B326F} + {52E5086B-877E-44C2-A440-D9EA3BFC70CB} = {DCE521F5-853A-4B3A-AC54-F0914EDF5FEC} + {811D8B64-35A6-4791-8E20-1C59C8133414} = {52E5086B-877E-44C2-A440-D9EA3BFC70CB} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2E848099-E299-4765-A250-3E96C78553E6} + EndGlobalSection +EndGlobal diff --git a/code/use-cases/biagram/biagram.csproj b/code/use-cases/biagram/biagram.csproj index 2463306..cc2e5e8 100644 --- a/code/use-cases/biagram/biagram.csproj +++ b/code/use-cases/biagram/biagram.csproj @@ -2,7 +2,7 @@ Exe - net8.0 + net10.0 diff --git a/code/use-cases/playground/playgroung.csproj b/code/use-cases/playground/playgroung.csproj index 45d9127..e04c9e6 100644 --- a/code/use-cases/playground/playgroung.csproj +++ b/code/use-cases/playground/playgroung.csproj @@ -2,7 +2,7 @@ Exe - net8.0 + net10.0 diff --git a/docs/tiny/brain.md b/docs/tiny/brain.md index 894f0d0..698c317 100644 --- a/docs/tiny/brain.md +++ b/docs/tiny/brain.md @@ -1,81 +1,81 @@ -# Tiny Brain - -## Neural Network - -a basic cs231 neuron could be modelled by - -`o = f ( sum (xi * wi ) + b )` - - -where: - -`xi` is the input - -`wi` is the synapse - -`wi*xi` is the dendrite - -`sum (xi * wi ) + b` is the cell body - -`f` is the activation function - -`o` is the output axon - - -#### Activation function -the activation should squash the values coming form the cell body function. - -**hyperbolic tangent function** - -`tanh(x) = (e^x - 1) / (e^x + 1)` - - - -### Backpropagation to train the brain - -#### Derivative -the definition of derivative - -L = lim f(a + h) - f(a) / h -h -> 0 - -giving a function -e = a*b -d = e + c -L = d * f - -backpropagation means starting form L we are going to reverse and calculate the gradient in all intermediate steps -we can think L as the loss function of our neural network. - -to compute the gradient starting from L we know that -dL / dd = f -dL / df = d - -so we can think that -dL/dL = 1 -dL/dd = f -dL/df = d - -we know the derivative of the sum is always equal to 1 -dd/dc = 1 -dd/de = 1 -now we have to compute dL/dc and to do this we have to consider the chain rule -dz/dx = dz/dy * dy/dx - -so: -dL/dc = dL/dd * dd/dc - -considering the neuron - -n = sum (xi * wi ) + b -o = tanh ( n ) - -we know that -dtanh/dn = 1 - tanh(n)^2 -but -tanh(n)=o -so the tanh local derivative is: -dtanh/dn = 1 - o^2 - - - +# Tiny Brain + +## Neural Network + +a basic cs231 neuron could be modelled by + +`o = f ( sum (xi * wi ) + b )` + + +where: + +`xi` is the input + +`wi` is the synapse + +`wi*xi` is the dendrite + +`sum (xi * wi ) + b` is the cell body + +`f` is the activation function + +`o` is the output axon + + +#### Activation function +the activation should squash the values coming form the cell body function. + +**hyperbolic tangent function** + +`tanh(x) = (e^x - 1) / (e^x + 1)` + + + +### Backpropagation to train the brain + +#### Derivative +the definition of derivative + +L = lim f(a + h) - f(a) / h +h -> 0 + +giving a function +e = a*b +d = e + c +L = d * f + +backpropagation means starting form L we are going to reverse and calculate the gradient in all intermediate steps +we can think L as the loss function of our neural network. + +to compute the gradient starting from L we know that +dL / dd = f +dL / df = d + +so we can think that +dL/dL = 1 +dL/dd = f +dL/df = d + +we know the derivative of the sum is always equal to 1 +dd/dc = 1 +dd/de = 1 +now we have to compute dL/dc and to do this we have to consider the chain rule +dz/dx = dz/dy * dy/dx + +so: +dL/dc = dL/dd * dd/dc + +considering the neuron + +n = sum (xi * wi ) + b +o = tanh ( n ) + +we know that +dtanh/dn = 1 - tanh(n)^2 +but +tanh(n)=o +so the tanh local derivative is: +dtanh/dn = 1 - o^2 + + + diff --git a/version b/version index bd52db8..8a9ecc2 100644 --- a/version +++ b/version @@ -1 +1 @@ -0.0.0 \ No newline at end of file +0.0.1 \ No newline at end of file