Some bugfixes and misc
This commit is contained in:
@@ -5,11 +5,11 @@ namespace App\Events;
|
||||
use App\Models\ActivationsFunctions;
|
||||
use Illuminate\Broadcasting\Channel;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class PerceptronInitialization implements ShouldBroadcast
|
||||
class PerceptronInitialization implements ShouldBroadcastNow
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
|
||||
@@ -4,11 +4,11 @@ namespace App\Events;
|
||||
|
||||
use Illuminate\Broadcasting\Channel;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
|
||||
class PerceptronTrainingEnded implements ShouldBroadcast
|
||||
class PerceptronTrainingEnded implements ShouldBroadcastNow
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
|
||||
@@ -4,12 +4,12 @@ namespace App\Events;
|
||||
|
||||
use Illuminate\Broadcasting\Channel;
|
||||
use Illuminate\Broadcasting\InteractsWithSockets;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
|
||||
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
|
||||
use Illuminate\Foundation\Events\Dispatchable;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Queue\SerializesModels;
|
||||
use Illuminate\Support\Arr;
|
||||
|
||||
class PerceptronTrainingIteration implements ShouldBroadcast
|
||||
class PerceptronTrainingIteration implements ShouldBroadcastNow
|
||||
{
|
||||
use Dispatchable, InteractsWithSockets, SerializesModels;
|
||||
|
||||
@@ -39,19 +39,20 @@ class PerceptronTrainingIteration implements ShouldBroadcast
|
||||
|
||||
public function broadcastWith(): array
|
||||
{
|
||||
$weights = collect($this->iterations)
|
||||
$iterations = self::normalizeForJson($this->iterations);
|
||||
$weights = collect($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;
|
||||
$lastIterationIndex = count($iterations) - 1;
|
||||
$iterations = array_map(
|
||||
fn (array $iteration, int $index): array => $shouldBroadcastAllWeights || $index === $lastIterationIndex
|
||||
? $iteration
|
||||
: [...$iteration, 'weights' => []],
|
||||
$this->iterations,
|
||||
array_keys($this->iterations),
|
||||
$iterations,
|
||||
array_keys($iterations),
|
||||
);
|
||||
|
||||
return [
|
||||
@@ -59,4 +60,20 @@ class PerceptronTrainingIteration implements ShouldBroadcast
|
||||
'trainingId' => $this->trainingId,
|
||||
];
|
||||
}
|
||||
|
||||
public static function normalizeForJson(mixed $value): mixed
|
||||
{
|
||||
if (is_float($value) && ! is_finite($value)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! is_array($value)) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
return array_map(
|
||||
fn (mixed $item): mixed => self::normalizeForJson($item),
|
||||
$value,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ use App\Services\SynapticWeightsProvider\ISynapticWeightsProvider;
|
||||
use App\Services\SynapticWeightsProvider\RandomSynapticWeights;
|
||||
use App\Services\SynapticWeightsProvider\ZeroSynapticWeights;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class PerceptronController extends Controller
|
||||
{
|
||||
@@ -134,6 +133,11 @@ class PerceptronController extends Controller
|
||||
break;
|
||||
case 'table_2_11':
|
||||
$dataset['defaultMinError'] = 0.02;
|
||||
switch ($perceptronType) {
|
||||
case 'monolayer':
|
||||
$dataset['defaultLearningRate'] = 0.0015;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 'table_4_12':
|
||||
switch ($perceptronType) {
|
||||
@@ -145,11 +149,13 @@ class PerceptronController extends Controller
|
||||
}
|
||||
break;
|
||||
case 'table_4_17':
|
||||
$dataset['defaultMinError'] = 0.055;
|
||||
switch ($perceptronType) {
|
||||
case 'multilayer':
|
||||
$dataset['defaultLearningRate'] = 0.5;
|
||||
$dataset['defaultMinError'] = 0.08;
|
||||
$dataset['defaultLearningRate'] = 0.3;
|
||||
$dataset['defaultMaxIterations'] = 400;
|
||||
$dataset['defaultHiddenLayers'] = 2;
|
||||
$dataset['defaultHiddenLayersNeurons'] = 2;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@@ -183,9 +189,6 @@ class PerceptronController extends Controller
|
||||
$sessionId = $request->input('session_id', session()->getId());
|
||||
$trainingId = $request->input('training_id');
|
||||
|
||||
// Remove the jobs for the sessionId
|
||||
DB::table('jobs')->where('payload', 'like', '%s:9:\"sessionId\";s:40:\"'.$sessionId.'\";%')->delete();
|
||||
|
||||
// Zero initialization prevents hidden layers from receiving a gradient.
|
||||
if ($perceptronType === 'multilayer' && $weightInitMethod === 'zeros') {
|
||||
$synapticWeightsProvider = new RandomSynapticWeights;
|
||||
|
||||
@@ -20,6 +20,7 @@ class MonoLayerPerceptronTraining extends NetworkTraining
|
||||
private array $labels;
|
||||
|
||||
public ActivationsFunctions $activationFunction = ActivationsFunctions::LINEAR;
|
||||
|
||||
public ?ActivationsFunctions $presentationLayerActivationFunction = ActivationsFunctions::STEP;
|
||||
|
||||
private float $epochError;
|
||||
@@ -62,7 +63,7 @@ class MonoLayerPerceptronTraining extends NetworkTraining
|
||||
while ($nextRow = $this->datasetReader->getNextLine()) {
|
||||
$inputsForCurrentEpoch[] = $nextRow;
|
||||
$inputs = array_slice($nextRow, 0, -1);
|
||||
$correctOutput = (int) end($nextRow);
|
||||
$correctOutput = (float) end($nextRow);
|
||||
|
||||
$iterationError = $this->iterationFunction($inputs, $correctOutput);
|
||||
|
||||
@@ -108,7 +109,7 @@ class MonoLayerPerceptronTraining extends NetworkTraining
|
||||
return $condition;
|
||||
}
|
||||
|
||||
private function iterationFunction(array $inputs, int $correctOutput): array
|
||||
private function iterationFunction(array $inputs, float $correctOutput): array
|
||||
{
|
||||
$outputs = $this->network->test($inputs);
|
||||
$desiredOutput = $this->getDesiredOutputFromCorrectOutput($correctOutput);
|
||||
@@ -137,10 +138,10 @@ class MonoLayerPerceptronTraining extends NetworkTraining
|
||||
return [$updatedWeights];
|
||||
}
|
||||
|
||||
private function getDesiredOutputFromCorrectOutput(int $correctOutput): array
|
||||
private function getDesiredOutputFromCorrectOutput(float $correctOutput): array
|
||||
{
|
||||
$desiredOutput = array_fill(0, count($this->labels), -1);
|
||||
$labelIndex = Arr::first(array_keys($this->labels), fn($key) => $this->labels[$key] == $correctOutput);
|
||||
$labelIndex = Arr::first(array_keys($this->labels), fn ($key) => $this->labels[$key] == $correctOutput);
|
||||
if ($labelIndex !== null) {
|
||||
$desiredOutput[$labelIndex] = 1;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ namespace App\Models\Perceptrons;
|
||||
|
||||
class InputNeuron extends Perceptron
|
||||
{
|
||||
private float $input = 0.0;
|
||||
|
||||
public function __construct(
|
||||
) {
|
||||
parent::__construct([]);
|
||||
|
||||
@@ -8,6 +8,8 @@ class PerceptronIterationEventBuffer implements IPerceptronIterationEventBuffer
|
||||
{
|
||||
private array $data = [];
|
||||
|
||||
private ?float $lastBroadcastAt = null;
|
||||
|
||||
public function __construct(
|
||||
private string $sessionId,
|
||||
private string $trainingId,
|
||||
@@ -19,7 +21,9 @@ class PerceptronIterationEventBuffer implements IPerceptronIterationEventBuffer
|
||||
return;
|
||||
}
|
||||
|
||||
$this->waitForBroadcastInterval();
|
||||
event(new PerceptronTrainingIteration($this->data, $this->sessionId, $this->trainingId));
|
||||
$this->lastBroadcastAt = microtime(true);
|
||||
$this->data = [];
|
||||
}
|
||||
|
||||
@@ -48,8 +52,22 @@ class PerceptronIterationEventBuffer implements IPerceptronIterationEventBuffer
|
||||
private function payloadExceedsLimit(): bool
|
||||
{
|
||||
return strlen(json_encode([
|
||||
'iterations' => $this->data,
|
||||
'iterations' => PerceptronTrainingIteration::normalizeForJson($this->data),
|
||||
'trainingId' => $this->trainingId,
|
||||
], JSON_THROW_ON_ERROR)) > config('broadcasting.broadcast_max_payload_size');
|
||||
}
|
||||
|
||||
private function waitForBroadcastInterval(): void
|
||||
{
|
||||
if ($this->lastBroadcastAt === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$minimumInterval = config('perceptron.broadcast_minimum_interval_ms') / 1000;
|
||||
$remainingInterval = $minimumInterval - (microtime(true) - $this->lastBroadcastAt);
|
||||
|
||||
if ($remainingInterval > 0) {
|
||||
usleep((int) ceil($remainingInterval * 1_000_000));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ class PerceptronLimitedEpochEventBuffer implements IPerceptronIterationEventBuff
|
||||
|
||||
private bool $shouldBroadcastEpoch = false;
|
||||
|
||||
private ?float $lastBroadcastAt = null;
|
||||
|
||||
public function __construct(
|
||||
private string $sessionId,
|
||||
private string $trainingId,
|
||||
@@ -24,7 +26,9 @@ class PerceptronLimitedEpochEventBuffer implements IPerceptronIterationEventBuff
|
||||
return;
|
||||
}
|
||||
|
||||
$this->waitForBroadcastInterval();
|
||||
event(new PerceptronTrainingIteration($this->data, $this->sessionId, $this->trainingId));
|
||||
$this->lastBroadcastAt = microtime(true);
|
||||
$this->data = [];
|
||||
}
|
||||
|
||||
@@ -57,8 +61,22 @@ class PerceptronLimitedEpochEventBuffer implements IPerceptronIterationEventBuff
|
||||
private function payloadExceedsLimit(): bool
|
||||
{
|
||||
return strlen(json_encode([
|
||||
'iterations' => $this->data,
|
||||
'iterations' => PerceptronTrainingIteration::normalizeForJson($this->data),
|
||||
'trainingId' => $this->trainingId,
|
||||
], JSON_THROW_ON_ERROR)) > config('broadcasting.broadcast_max_payload_size');
|
||||
}
|
||||
|
||||
private function waitForBroadcastInterval(): void
|
||||
{
|
||||
if ($this->lastBroadcastAt === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
$minimumInterval = config('perceptron.broadcast_minimum_interval_ms') / 1000;
|
||||
$remainingInterval = $minimumInterval - (microtime(true) - $this->lastBroadcastAt);
|
||||
|
||||
if ($remainingInterval > 0) {
|
||||
usleep((int) ceil($remainingInterval * 1_000_000));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user