Files
NeuralNetworks.Unity/Assets/Perceptron.cs
T

175 lines
4.5 KiB
C#
Raw Normal View History

2025-05-13 02:53:08 +03:00
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Perceptron : MonoBehaviour
{
public List<Layer> Layers;
public List<Synapses> _synapses;
[System.Serializable]
public class Layer {
public int Size;
public bool AddOffsetNeuron;
public int TotalSize {
get {
return AddOffsetNeuron ? (Size + 1) : Size;
}
}
public void Init() {
Values = new float[TotalSize];
Errors = new float[TotalSize];
if (AddOffsetNeuron) {
Values[Values.Length - 1] = 1.0f;
}
}
public float[] Values;
public float[] Errors;
}
[System.Serializable]
public class Synapses {
public float[,] Values;
public int InSize;
public int OutSize;
public Synapses(int inSize, int outSize) {
InSize = inSize;
OutSize = outSize;
Values = new float[inSize, outSize];
SetRandom();
// SetOne();
Debug.Log($"Make synapses: {inSize}x{outSize}");
}
public void SetOne() {
for (int i = 0; i < InSize; ++i) {
for (int j = 0; j < OutSize; ++j) {
Values[i, j] = 1;
}
}
}
public void SetRandom() {
for(int i = 0; i < InSize; ++i) {
for (int j = 0; j < OutSize; ++j) {
Values[i, j] = UnityEngine.Random.value * 2.0f - 1.0f;
}
}
}
}
const float FxCapDerivative = 0.01f;
//float Fx(float x) {
// if(x > 1.0f) {
// return 1.0f + FxCapDerivative * (x - 1.0f);
// }else if(x < 0.0f) {
// return FxCapDerivative * x;
// }
// return x;
//}
//
//float FxDerivative(float x) {
// if (x > 1.0f) {
// return FxCapDerivative;
// } else if (x < 0.0f) {
// return FxCapDerivative;
// }
// return 1.0f;
//}
float Fx(float x) {
return 1.0f / (1.0f + Mathf.Exp(-x));
}
float FxDerivative(float x) {
return x * (1.0f - x);
}
public void PropagateErrors() {
for (int inLayerId = Layers.Count - 2; inLayerId >= 0; --inLayerId) {
int outLayerId = inLayerId + 1;
var inLayer = Layers[inLayerId];
var outLayer = Layers[outLayerId];
var weights = _synapses[inLayerId];
for(int i = 0; i < inLayer.Size; ++i) {
float err = 0.0f;
for (int o = 0; o < outLayer.Size; ++o) {
err += outLayer.Errors[o] * weights.Values[i, o];
}
inLayer.Errors[i] = err;
}
}
}
public void RecalculateWeights(float learnRate) {
for (int inLayerId = 0; inLayerId < Layers.Count - 1; ++inLayerId) {
int outLayerId = inLayerId + 1;
var inLayer = Layers[inLayerId];
var outLayer = Layers[outLayerId];
var weights = _synapses[inLayerId];
for (int i = 0; i < inLayer.TotalSize; ++i) {
for (int o = 0; o < outLayer.Size; ++o) {
weights.Values[i, o] += (learnRate * outLayer.Errors[o]) * FxDerivative(outLayer.Values[o]) * inLayer.Values[i];
}
}
}
}
public void CalculateOutputs() {
for (int inLayerId = 0; inLayerId < Layers.Count - 1; ++inLayerId) {
int outLayerId = inLayerId + 1;
var inLayer = Layers[inLayerId];
var outLayer = Layers[outLayerId];
var weights = _synapses[inLayerId];
for (int o = 0; o < outLayer.Size; ++o) {
float sum = 0;
for (int i = 0; i < inLayer.TotalSize; ++i) {
sum += weights.Values[i, o] * inLayer.Values[i];
}
outLayer.Values[o] = Fx(sum);
}
}
}
public void Learn(float learnRate) {
PropagateErrors();
RecalculateWeights(learnRate);
}
void Start()
{
foreach(var layer in Layers) {
layer.Init();
}
_synapses = new List<Synapses>();
for (int i = 0; i < Layers.Count - 1; ++i) {
_synapses.Add(new Synapses(Layers[i].TotalSize, Layers[i + 1].Size));
}
}
void Update()
{
}
}