validate([ 'training_id' => ['required', 'string', 'max:100'], ])['training_id']; Cache::put($this->cancellationKey($trainingId), true, now()->addHour()); return response()->noContent(); } /** * Display the specified resource. */ public function index(Request $request) { $perceptronType = $request->query('type', 'simple'); ; $learningRate = 0.01; $maxIterations = 200; $minError = 0.1; switch ($perceptronType) { case 'simple': $learningRate = 0.015; $maxIterations = 150; break; case 'adaline': $learningRate = 0.00003; break; case 'gradientdescent': $learningRate = 0.00003; $maxIterations = 300; break; case 'monolayer': $learningRate = 0.001; break; case 'multilayer': $learningRate = 0.8; $maxIterations = 2000; break; } return inertia('PerceptronViewer', [ 'type' => $perceptronType, 'sessionId' => session()->getId(), 'datasets' => $this->getDatasets($perceptronType), 'minError' => $minError, 'learningRate' => $learningRate, 'maxIterations' => $maxIterations, 'maxIterationsLimit' => config('perceptron.max_iterations'), 'maxDisplayedWeights' => config('perceptron.max_displayed_weights'), ]); } private function getDatasets(string $perceptronType): array { $dataSetsDirectory = public_path('data_sets'); $files = scandir($dataSetsDirectory); $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: foreach ($dataSetReader->lines as $line) { $dataset['data'][] = [ 'x' => $line[0], 'y' => $line[1], 'label' => $line[2], ]; } break; case 2: foreach ($dataSetReader->lines as $line) { $dataset['data'][] = [ 'x' => $line[0], 'y' => $line[1], 'label' => 1, ]; } break; default: $dataset['data'] = null; // Not supported for viewing break; } switch ($dataset['label']) { case 'Classification_-_Porte_logique_ET_(linéairement_séparable)': switch ($perceptronType) { case 'gradientdescent': $dataset['defaultLearningRate'] = 0.3; $dataset['defaultMinError'] = 0.125; break; case 'adaline': $dataset['defaultLearningRate'] = 0.05; $dataset['defaultMinError'] = 0.125; break; case 'monolayer': $dataset['defaultMinError'] = 0.001; break; } break; case 'Classification_-_Porte_logique_XOR_(non_linéairement_séparable)': switch ($perceptronType) { case 'multilayer': $dataset['defaultLearningRate'] = 0.3; $dataset['defaultMinError'] = 0.001; $dataset['defaultMaxIterations'] = 500; $dataset['defaultHiddenLayers'] = 1; $dataset['defaultHiddenLayersNeurons'] = 2; break; } break; case 'Classification_-_Oblique_(linéairement_séparable)': case 'Classification_-_Oblique_modifié_(non_linéairement_séparable)': switch ($perceptronType) { case 'simple': $dataset['defaultLearningRate'] = 0.015; break; case 'gradientdescent': case 'adaline': $dataset['defaultLearningRate'] = 0.001; $dataset['defaultMinError'] = 0.09; $dataset['defaultMaxIterations'] = 2000; break; } break; 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 'Classification_-_3_classes_(linéairement_séparable)': switch ($perceptronType) { case 'monolayer': $dataset['defaultLearningRate'] = 0.005; $dataset['defaultMaxIterations'] = 100; break; } break; 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': $dataset['defaultLearningRate'] = 0.3; $dataset['defaultMaxIterations'] = 400; $dataset['defaultHiddenLayers'] = 2; $dataset['defaultHiddenLayersNeurons'] = 2; break; } break; } $datasets[] = $dataset; } } return $datasets; } private function getDataSetReader(string $dataSet): IDataSetReader { $dataSetFileName = "data_sets/{$dataSet}.csv"; return new RandomOrderDataSetReader($dataSetFileName); } public function run(RunPerceptronRequest $request, ISynapticWeightsProvider $synapticWeightsProvider) { $startTime = microtime(true); $perceptronType = $request->input('type'); $hiddenLayers = $request->input('hidden_layers', 2); $hiddenLayersNeurons = $request->input('hidden_layers_neurons', 3); $minError = $request->input('min_error', 0.01); $weightInitMethod = $request->input('weight_init_method', 'random'); $dataSet = $request->input('dataset'); $learningRate = $request->input('learning_rate', 0.015); $maxEpochs = $request->input('max_iterations', 100); $sessionId = $request->input('session_id', session()->getId()); $trainingId = $request->input('training_id'); Cache::forget($this->cancellationKey($trainingId)); // Zero initialization prevents hidden layers from receiving a gradient. if ($perceptronType === 'multilayer' && $weightInitMethod === 'zeros') { $synapticWeightsProvider = new RandomSynapticWeights; } elseif ($weightInitMethod === 'zeros') { $synapticWeightsProvider = new ZeroSynapticWeights; } $iterationEventBuffer = new PerceptronIterationEventBuffer($sessionId, $trainingId); if ($maxEpochs > config('perceptron.limited_broadcast_iterations')) { $iterationsInterval = (int) ($maxEpochs / config('perceptron.limited_broadcast_iterations')); $iterationEventBuffer = new PerceptronLimitedEpochEventBuffer($sessionId, $trainingId, $iterationsInterval); } $datasetReader = $this->getDataSetReader($dataSet); $networkTraining = match ($perceptronType) { 'simple' => new SimpleBinaryPerceptronTraining($datasetReader, $learningRate, $maxEpochs, $synapticWeightsProvider, $iterationEventBuffer, $sessionId, $trainingId, fn (): bool => connection_aborted() || Cache::has($this->cancellationKey($trainingId))), 'gradientdescent' => new GradientDescentPerceptronTraining($datasetReader, $learningRate, $maxEpochs, $synapticWeightsProvider, $iterationEventBuffer, $sessionId, $trainingId, $minError, fn (): bool => connection_aborted() || Cache::has($this->cancellationKey($trainingId))), 'adaline' => new ADALINEPerceptronTraining($datasetReader, $learningRate, $maxEpochs, $synapticWeightsProvider, $iterationEventBuffer, $sessionId, $trainingId, $minError, fn (): bool => connection_aborted() || Cache::has($this->cancellationKey($trainingId))), 'monolayer' => new MonoLayerPerceptronTraining($datasetReader, $learningRate, $maxEpochs, $synapticWeightsProvider, $iterationEventBuffer, $sessionId, $trainingId, $minError, fn (): bool => connection_aborted() || Cache::has($this->cancellationKey($trainingId))), 'multilayer' => new MultiLayerPerceptronTraining($datasetReader, $learningRate, $maxEpochs, $hiddenLayers, $hiddenLayersNeurons, $synapticWeightsProvider, $iterationEventBuffer, $sessionId, $trainingId, $minError, fn (): bool => connection_aborted() || Cache::has($this->cancellationKey($trainingId))), default => null, }; event(new PerceptronInitialization($datasetReader->lines, $networkTraining->activationFunction, $sessionId, $trainingId)); try { $networkTraining->start(); } catch (TrainingCancelledException) { $networkTraining->cancel(); Cache::forget($this->cancellationKey($trainingId)); } return back()->with('success', [ 'message' => 'Training completed', 'execution_time' => microtime(true) - $startTime, ]); } }