Wiki
linter / quality (push) Successful in 5m1s
tests / ci (8.4) (push) Successful in 5m8s
tests / ci (8.5) (push) Successful in 6m31s

This commit is contained in:
2026-09-15 19:44:58 +02:00
parent ca6c9fe38c
commit 6d4fdffee9
82 changed files with 29906 additions and 151 deletions
+44 -13
View File
@@ -37,12 +37,15 @@ class PerceptronController extends Controller
$learningRate = 0.015;
$maxIterations = 150;
break;
case 'gradientdescent':
case 'adaline':
$learningRate = 0.00003;
break;
case 'gradientdescent':
$learningRate = 0.00003;
$maxIterations = 300;
break;
case 'monolayer':
$learningRate = 0.03;
$learningRate = 0.001;
break;
case 'multilayer':
$learningRate = 0.8;
@@ -57,6 +60,7 @@ class PerceptronController extends Controller
'minError' => $minError,
'learningRate' => $learningRate,
'maxIterations' => $maxIterations,
'maxIterationsLimit' => config('perceptron.max_iterations'),
'maxDisplayedWeights' => config('perceptron.max_displayed_weights'),
]);
}
@@ -68,9 +72,14 @@ class PerceptronController extends Controller
$datasets = [];
foreach ($files as $file) {
if (pathinfo($file, PATHINFO_EXTENSION) === 'csv') {
if (str_starts_with($file, 'hidden')) {
continue;
}
$dataset = [];
$dataset['label'] = str_replace('.csv', '', $file);
$dataSetReader = new LinearOrderDataSetReader($dataSetsDirectory.'/'.$file);
$dataset['inputCount'] = count($dataSetReader->lines[0]) - 1;
$dataset['data'] = [];
switch (count($dataSetReader->lines[0])) {
case 3:
@@ -97,7 +106,7 @@ class PerceptronController extends Controller
}
switch ($dataset['label']) {
case 'logic_and_gradient':
case 'Classification_-_Porte_logique_ET_(linéairement_séparable)':
switch ($perceptronType) {
case 'gradientdescent':
$dataset['defaultLearningRate'] = 0.3;
@@ -107,9 +116,12 @@ class PerceptronController extends Controller
$dataset['defaultLearningRate'] = 0.05;
$dataset['defaultMinError'] = 0.125;
break;
case 'monolayer':
$dataset['defaultMinError'] = 0.001;
break;
}
break;
case 'logic_xor':
case 'Classification_-_Porte_logique_XOR_(non_linéairement_séparable)':
switch ($perceptronType) {
case 'multilayer':
$dataset['defaultLearningRate'] = 0.3;
@@ -120,7 +132,8 @@ class PerceptronController extends Controller
break;
}
break;
case 'table_2_9':
case 'Classification_-_Oblique_(linéairement_séparable)':
case 'Classification_-_Oblique_modifié_(non_linéairement_séparable)':
switch ($perceptronType) {
case 'simple':
$dataset['defaultLearningRate'] = 0.015;
@@ -128,27 +141,45 @@ class PerceptronController extends Controller
case 'gradientdescent':
case 'adaline':
$dataset['defaultLearningRate'] = 0.001;
$dataset['defaultMinError'] = 0.09;
$dataset['defaultMaxIterations'] = 2000;
break;
}
break;
case 'table_2_11':
case 'Régression_-_Oblique':
$dataset['defaultMinError'] = 0.02;
switch ($perceptronType) {
case 'gradientdescent':
case 'adaline':
$dataset['defaultMinError'] = 0.68;
$dataset['defaultMaxIterations'] = 100;
break;
case 'monolayer':
$dataset['defaultLearningRate'] = 0.0015;
break;
}
break;
case 'table_4_12':
case 'Classification_-_3_classes_(linéairement_séparable)':
switch ($perceptronType) {
case 'multilayer':
$dataset['defaultLearningRate'] = 0.8;
$dataset['defaultMinError'] = 0.001;
$dataset['defaultMaxIterations'] = 2000;
case 'monolayer':
$dataset['defaultLearningRate'] = 0.005;
$dataset['defaultMaxIterations'] = 100;
break;
}
break;
case 'table_4_17':
case 'Classification_-_Donut_(non_linéairement_séparable)':
switch ($perceptronType) {
case 'multilayer':
$dataset['defaultLearningRate'] = 0.8;
$dataset['defaultMinError'] = 0.0001;
$dataset['defaultMaxIterations'] = 2000;
$dataset['defaultHiddenLayers'] = 3;
$dataset['defaultHiddenLayersNeurons'] = 4;
break;
}
break;
case 'Régression_-_Vague':
$dataset['defaultMinError'] = 0.055;
switch ($perceptronType) {
case 'multilayer':
@@ -217,7 +248,7 @@ class PerceptronController extends Controller
$networkTraining->start();
return response()->json([
return back()->with('success', [
'message' => 'Training completed',
'execution_time' => microtime(true) - $startTime,
]);
+2 -2
View File
@@ -15,13 +15,13 @@ class RunPerceptronRequest extends FormRequest
{
return [
'type' => ['required', 'string', 'in:simple,gradientdescent,adaline,monolayer,multilayer'],
'dataset' => ['required', 'string', 'max:100', 'regex:/^[A-Za-z0-9_-]+$/'],
'dataset' => ['required', 'string', 'max:200'],
'weight_init_method' => ['required', 'string', 'in:random,zeros'],
'learning_rate' => ['required', 'numeric', 'min:0'],
'min_error' => ['required', 'numeric', 'min:0'],
'hidden_layers' => ['required', 'integer', 'min:1', 'max:5'],
'hidden_layers_neurons' => ['required', 'integer', 'min:1', 'max:5'],
'max_iterations' => ['required', 'integer', 'min:1', 'max:5000'],
'max_iterations' => ['required', 'integer', 'min:1', 'max:'.config('perceptron.max_iterations')],
'session_id' => ['required', 'string', 'max:100'],
'training_id' => ['required', 'string', 'max:100'],
];
@@ -2,7 +2,6 @@
namespace App\Models\NetworksTraining;
use App\Events\PerceptronTrainingEnded;
use App\Models\ActivationsFunctions;
use App\Models\Perceptrons\GradientDescentPerceptron;
use App\Models\Perceptrons\Perceptron;
@@ -84,7 +83,7 @@ class ADALINEPerceptronTraining extends NetworkTraining
{
$condition = $this->epochError <= $this->minError;
if ($condition === true) {
event(new PerceptronTrainingEnded('Le perceptron à atteint l\'erreur minimale', $this->sessionId, $this->trainingId));
$this->broadcastTrainingEnded('Le perceptron à atteint l\'erreur minimale');
}
return $condition;
@@ -2,7 +2,6 @@
namespace App\Models\NetworksTraining;
use App\Events\PerceptronTrainingEnded;
use App\Models\ActivationsFunctions;
use App\Models\Perceptrons\GradientDescentPerceptron;
use App\Models\Perceptrons\Perceptron;
@@ -80,7 +79,7 @@ class GradientDescentPerceptronTraining extends NetworkTraining
{
$condition = $this->epochError <= $this->minError;
if ($condition === true) {
event(new PerceptronTrainingEnded('Le perceptron à atteint l\'erreur minimale', $this->sessionId, $this->trainingId));
$this->broadcastTrainingEnded('Le perceptron à atteint l\'erreur minimale');
}
return $condition;
@@ -2,7 +2,6 @@
namespace App\Models\NetworksTraining;
use App\Events\PerceptronTrainingEnded;
use App\Models\ActivationsFunctions;
use App\Models\Perceptrons\GradientDescentPerceptron;
use App\Models\Perceptrons\NetworkPerceptron;
@@ -19,6 +18,8 @@ class MonoLayerPerceptronTraining extends NetworkTraining
private array $labels;
private bool $isRegression;
public ActivationsFunctions $activationFunction = ActivationsFunctions::LINEAR;
public ?ActivationsFunctions $presentationLayerActivationFunction = ActivationsFunctions::STEP;
@@ -36,11 +37,12 @@ class MonoLayerPerceptronTraining extends NetworkTraining
private float $minError,
) {
parent::__construct($datasetReader, $maxEpochs, $iterationEventBuffer, $sessionId, $trainingId);
$this->isRegression = $datasetReader->getInputSize() === 1;
$networkWeightsProvider = new SimpleNetworkWeightsProvider($synapticWeightsProvider);
$this->network = new NetworkPerceptron(
$networkWeightsProvider->generate(
$datasetReader->getInputSize(),
$datasetReader->getOutputSize(),
$this->isRegression ? 1 : $datasetReader->getOutputSize(),
0, // No hidden layer
0, // No hidden layer neurons
),
@@ -103,7 +105,7 @@ class MonoLayerPerceptronTraining extends NetworkTraining
{
$condition = $this->epochError <= $this->minError;
if ($condition === true) {
event(new PerceptronTrainingEnded('Le perceptron à atteint l\'erreur minimale', $this->sessionId, $this->trainingId));
$this->broadcastTrainingEnded('Le perceptron à atteint l\'erreur minimale');
}
return $condition;
@@ -140,6 +142,10 @@ class MonoLayerPerceptronTraining extends NetworkTraining
private function getDesiredOutputFromCorrectOutput(float $correctOutput): array
{
if ($this->isRegression) {
return [$correctOutput];
}
$desiredOutput = array_fill(0, count($this->labels), -1);
$labelIndex = Arr::first(array_keys($this->labels), fn ($key) => $this->labels[$key] == $correctOutput);
if ($labelIndex !== null) {
@@ -2,7 +2,6 @@
namespace App\Models\NetworksTraining;
use App\Events\PerceptronTrainingEnded;
use App\Models\ActivationsFunctions;
use App\Models\Perceptrons\GradientDescentPerceptron;
use App\Models\Perceptrons\NetworkPerceptron;
@@ -116,7 +115,7 @@ class MultiLayerPerceptronTraining extends NetworkTraining
{
$condition = $this->epochError <= $this->minError;
if ($condition === true) {
event(new PerceptronTrainingEnded('Le perceptron à atteint l\'erreur minimale', $this->sessionId, $this->trainingId));
$this->broadcastTrainingEnded('Le perceptron à atteint l\'erreur minimale');
}
return $condition;
@@ -33,7 +33,7 @@ abstract class NetworkTraining
protected function checkPassedMaxIterations(?float $finalError)
{
if ($this->epoch >= $this->maxEpochs) {
$message = 'Le nombre maximal d\'epoch a été atteint';
$message = 'Le nombre maximal d\'époques a été atteint';
if ($finalError) {
$message .= " avec une erreur finale de $finalError";
}
@@ -42,6 +42,12 @@ abstract class NetworkTraining
}
}
protected function broadcastTrainingEnded(string $reason): void
{
$this->iterationEventBuffer->flush();
event(new PerceptronTrainingEnded($reason, $this->sessionId, $this->trainingId));
}
protected function addIterationToBuffer(float $error, array $synapticWeights)
{
$this->iterationEventBuffer->addIteration($this->epoch, $this->datasetReader->getLastReadLineIndex(), $error, $synapticWeights);
@@ -8,6 +8,8 @@ class PerceptronLimitedEpochEventBuffer implements IPerceptronIterationEventBuff
{
private array $data = [];
private array $lastEpochData = [];
private ?int $activeEpoch = null;
private bool $shouldBroadcastEpoch = false;
@@ -22,14 +24,20 @@ class PerceptronLimitedEpochEventBuffer implements IPerceptronIterationEventBuff
public function flush(): void
{
if ($this->data === []) {
if ($this->data !== []) {
$this->flushSelectedData();
return;
}
if ($this->lastEpochData === [] || $this->shouldBroadcastEpoch) {
return;
}
$this->waitForBroadcastInterval();
event(new PerceptronTrainingIteration($this->data, $this->sessionId, $this->trainingId));
event(new PerceptronTrainingIteration($this->lastEpochData, $this->sessionId, $this->trainingId));
$this->lastBroadcastAt = microtime(true);
$this->data = [];
$this->lastEpochData = [];
}
public function addIteration(int $epoch, int $exampleIndex, float $error, array $synaptic_weights): void
@@ -42,22 +50,37 @@ class PerceptronLimitedEpochEventBuffer implements IPerceptronIterationEventBuff
];
if ($this->activeEpoch !== $epoch) {
$this->flush();
$this->flushSelectedData();
$this->lastEpochData = [];
$this->activeEpoch = $epoch;
$this->shouldBroadcastEpoch = $epoch === 1 || $epoch % $this->epochInterval === 0;
}
if (! $this->shouldBroadcastEpoch) {
$this->lastEpochData[] = $newData;
return;
}
$this->data[] = $newData;
if ($this->payloadExceedsLimit() || count($this->data) >= config('perceptron.broadcast_iteration_size')) {
$this->flush();
$this->flushSelectedData();
}
}
private function flushSelectedData(): void
{
if ($this->data === []) {
return;
}
$this->waitForBroadcastInterval();
event(new PerceptronTrainingIteration($this->data, $this->sessionId, $this->trainingId));
$this->lastBroadcastAt = microtime(true);
$this->data = [];
}
private function payloadExceedsLimit(): bool
{
return strlen(json_encode([