Various fixess and xor
linter / quality (push) Successful in 4m23s
tests / ci (8.4) (push) Successful in 4m35s
tests / ci (8.5) (push) Successful in 5m13s

This commit is contained in:
2026-09-08 18:40:56 +02:00
parent 08aa04fe56
commit 8a50f492ac
7 changed files with 93 additions and 5 deletions
+8 -1
View File
@@ -6,6 +6,7 @@ use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Support\Arr;
use Illuminate\Queue\SerializesModels;
class PerceptronTrainingIteration implements ShouldBroadcast
@@ -38,9 +39,15 @@ class PerceptronTrainingIteration implements ShouldBroadcast
public function broadcastWith(): array
{
$weights = collect($this->iterations)
->pluck('weights')
->first(fn (array $weights): bool => $weights !== []);
$shouldBroadcastAllWeights = $weights !== null
&& count(Arr::flatten($weights)) <= config('perceptron.max_displayed_weights');
$lastIterationIndex = count($this->iterations) - 1;
$iterations = array_map(
fn (array $iteration, int $index): array => $index === $lastIterationIndex
fn (array $iteration, int $index): array => $shouldBroadcastAllWeights || $index === $lastIterationIndex
? $iteration
: [...$iteration, 'weights' => []],
$this->iterations,
@@ -47,6 +47,7 @@ class PerceptronController extends Controller
break;
case 'multilayer':
$learningRate = 0.8;
$maxIterations = 2000;
break;
}
@@ -109,6 +110,17 @@ class PerceptronController extends Controller
break;
}
break;
case 'logic_xor':
switch ($perceptronType) {
case 'multilayer':
$dataset['defaultLearningRate'] = 0.3;
$dataset['defaultMinError'] = 0.001;
$dataset['defaultMaxIterations'] = 500;
$dataset['defaultHiddenLayers'] = 1;
$dataset['defaultHiddenLayersNeurons'] = 2;
break;
}
break;
case 'table_2_9':
switch ($perceptronType) {
case 'simple':
@@ -132,6 +144,15 @@ class PerceptronController extends Controller
break;
}
break;
case 'table_4_17':
switch ($perceptronType) {
case 'multilayer':
$dataset['defaultLearningRate'] = 0.5;
$dataset['defaultMinError'] = 0.08;
$dataset['defaultMaxIterations'] = 400;
break;
}
break;
}
$datasets[] = $dataset;
}
+3 -2
View File
@@ -20,9 +20,10 @@ return [
'broadcast_iteration_size' => 75,
/**
* Hide the weight columns in the iteration table above this count.
* Maximum number of weights for which all iteration weights are broadcast
* and displayed in the iteration table.
*/
'max_displayed_weights' => 25,
'max_displayed_weights' => 5,
'run_inputs_validation' => [
'hidden_layers' => 'required|integer|min:1|max:5',
@@ -66,6 +66,15 @@ watch(selectedDatasetCopy, (newvalue) => {
if (selectedDatasetCopy && selectedDatasetCopy.defaultMaxIterations !== undefined) {
maxIterations.value = selectedDatasetCopy.defaultMaxIterations;
}
// HiddenLayers
hiddenLayers.value = props.hiddenLayers;
if (selectedDatasetCopy && selectedDatasetCopy.defaultHiddenLayers !== undefined) {
hiddenLayers.value = selectedDatasetCopy.defaultHiddenLayers;
}
hiddenLayersNeurons.value = props.hiddenLayersNeurons;
if (selectedDatasetCopy && selectedDatasetCopy.defaultHiddenLayersNeurons !== undefined) {
hiddenLayersNeurons.value = selectedDatasetCopy.defaultHiddenLayersNeurons;
}
})
const trainingId = ref<string>('');
+6 -2
View File
@@ -140,6 +140,10 @@ function perceptronTrainingEnded(data: any) {
}
const activationFunction = ref<string>('');
const isRegression = computed(
() => props.type === 'multilayer' && activationFunction.value === 'linear',
);
function perceptroninitialization(data: any) {
console.log('Perceptron training initialized:', data);
if (data.trainingId !== trainingId.value) {
@@ -216,7 +220,7 @@ function resetTraining() {
<PerceptronDecisionGraph
:cleanedDataset="cleanedDataset"
:iterations="iterations"
:is-regression="activationFunction === 'linear'"
:is-regression="isRegression"
:activation-function="
getActivationFunction(activationFunction)
"
@@ -225,7 +229,7 @@ function resetTraining() {
<div>
<PerceptronIterationsErrorsGraph
:iterations="iterations"
:is-regression="activationFunction === 'linear'"
:is-regression="isRegression"
v-if="iterations.length > 0"
/>
</div>
+2
View File
@@ -11,6 +11,8 @@ export type Dataset = {
defaultLearningRate?: number;
defaultMinError?: number;
defaultMaxIterations?: number;
defaultHiddenLayers?: number;
defaultHiddenLayersNeurons?: number;
};
export type DatasetPoint = {
@@ -0,0 +1,44 @@
<?php
namespace Tests\Unit\Events;
use App\Events\PerceptronTrainingIteration;
use Tests\TestCase;
class PerceptronTrainingIterationTest extends TestCase
{
public function test_small_networks_keep_weights_for_every_iteration(): void
{
$event = new PerceptronTrainingIteration(
iterations: [
['epoch' => 1, 'exampleIndex' => 0, 'error' => 1, 'weights' => [[[1, 2]]]],
['epoch' => 1, 'exampleIndex' => 1, 'error' => 0, 'weights' => [[[3, 4]]]],
],
sessionId: 'session',
trainingId: 'training',
);
$iterations = $event->broadcastWith()['iterations'];
$this->assertSame([[[1, 2]]], $iterations[0]['weights']);
$this->assertSame([[[3, 4]]], $iterations[1]['weights']);
}
public function test_large_networks_only_keep_the_last_iteration_weights(): void
{
$largeWeights = [[array_fill(0, config('perceptron.max_displayed_weights') + 1, 0)]];
$event = new PerceptronTrainingIteration(
iterations: [
['epoch' => 1, 'exampleIndex' => 0, 'error' => 1, 'weights' => $largeWeights],
['epoch' => 1, 'exampleIndex' => 1, 'error' => 0, 'weights' => $largeWeights],
],
sessionId: 'session',
trainingId: 'training',
);
$iterations = $event->broadcastWith()['iterations'];
$this->assertSame([], $iterations[0]['weights']);
$this->assertSame($largeWeights, $iterations[1]['weights']);
}
}