Wiki
This commit is contained in:
@@ -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,
|
||||
]);
|
||||
|
||||
@@ -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([
|
||||
|
||||
Reference in New Issue
Block a user