perceptron = new SimpleBinaryPerceptron($synapticWeightsProvider->generate($datasetReader->getInputSize())); } public function start(): void { $this->iteration = 0; $error = 0; do { $this->iterationErrorCounter = 0; $this->iteration++; while ($nextRow = $this->datasetReader->getRandomLine()) { $inputs = array_slice($nextRow, 0, -1); $correctOutput = (float) end($nextRow); $correctOutput = $correctOutput > 0 ? 1 : 0; // Modify labels for non binary datasets $error = $this->iterationFunction($inputs, $correctOutput); // Broadcast the training iteration event $this->addIterationToBuffer($error, [[$this->perceptron->getSynapticWeights()]]); } $this->datasetReader->reset(); // Reset the dataset for the next iteration } while ($this->iteration < $this->maxIterations && !$this->stopCondition()); $this->iterationEventBuffer->flush(); // Ensure all iterations are sent to the frontend $this->checkPassedMaxIterations(null); } protected function stopCondition(): bool { $condition = $this->iterationErrorCounter == 0; if ($condition === true) { event(new PerceptronTrainingEnded('Le perceptron ne commet plus d\'erreurs sur aucune des données', $this->sessionId, $this->trainingId)); } return $this->iterationErrorCounter == 0; } private function iterationFunction(array $inputs, int $correctOutput) { $output = $this->perceptron->test($inputs); $error = $correctOutput - $output; if (abs($error) > $this::MIN_ERROR) { $this->iterationErrorCounter++; } if ($error !== 0) { // Update synaptic weights if needed $synaptic_weights = $this->perceptron->getSynapticWeights(); $inputs_with_bias = array_merge([1], $inputs); // Add bias input $new_weights = array_map(fn($weight, $input) => $weight + $this->learningRate * $error * $input, $synaptic_weights, $inputs_with_bias); $this->perceptron->setSynapticWeights($new_weights); } return $error; } }