Cancel Training
This commit is contained in:
@@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Exceptions;
|
||||||
|
|
||||||
|
use RuntimeException;
|
||||||
|
|
||||||
|
class TrainingCancelledException extends RuntimeException
|
||||||
|
{
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use App\Events\PerceptronInitialization;
|
use App\Events\PerceptronInitialization;
|
||||||
|
use App\Exceptions\TrainingCancelledException;
|
||||||
use App\Http\Requests\RunPerceptronRequest;
|
use App\Http\Requests\RunPerceptronRequest;
|
||||||
use App\Models\NetworksTraining\ADALINEPerceptronTraining;
|
use App\Models\NetworksTraining\ADALINEPerceptronTraining;
|
||||||
use App\Models\NetworksTraining\GradientDescentPerceptronTraining;
|
use App\Models\NetworksTraining\GradientDescentPerceptronTraining;
|
||||||
@@ -18,9 +19,25 @@ use App\Services\SynapticWeightsProvider\ISynapticWeightsProvider;
|
|||||||
use App\Services\SynapticWeightsProvider\RandomSynapticWeights;
|
use App\Services\SynapticWeightsProvider\RandomSynapticWeights;
|
||||||
use App\Services\SynapticWeightsProvider\ZeroSynapticWeights;
|
use App\Services\SynapticWeightsProvider\ZeroSynapticWeights;
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Cache;
|
||||||
|
|
||||||
class PerceptronController extends Controller
|
class PerceptronController extends Controller
|
||||||
{
|
{
|
||||||
|
private function cancellationKey(string $trainingId): string
|
||||||
|
{
|
||||||
|
return "perceptron-training-cancelled:{$trainingId}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function cancel(Request $request)
|
||||||
|
{
|
||||||
|
$trainingId = $request->validate([
|
||||||
|
'training_id' => ['required', 'string', 'max:100'],
|
||||||
|
])['training_id'];
|
||||||
|
|
||||||
|
Cache::put($this->cancellationKey($trainingId), true, now()->addHour());
|
||||||
|
|
||||||
|
return response()->noContent();
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Display the specified resource.
|
* Display the specified resource.
|
||||||
*/
|
*/
|
||||||
@@ -220,6 +237,8 @@ class PerceptronController extends Controller
|
|||||||
$sessionId = $request->input('session_id', session()->getId());
|
$sessionId = $request->input('session_id', session()->getId());
|
||||||
$trainingId = $request->input('training_id');
|
$trainingId = $request->input('training_id');
|
||||||
|
|
||||||
|
Cache::forget($this->cancellationKey($trainingId));
|
||||||
|
|
||||||
// Zero initialization prevents hidden layers from receiving a gradient.
|
// Zero initialization prevents hidden layers from receiving a gradient.
|
||||||
if ($perceptronType === 'multilayer' && $weightInitMethod === 'zeros') {
|
if ($perceptronType === 'multilayer' && $weightInitMethod === 'zeros') {
|
||||||
$synapticWeightsProvider = new RandomSynapticWeights;
|
$synapticWeightsProvider = new RandomSynapticWeights;
|
||||||
@@ -236,17 +255,22 @@ class PerceptronController extends Controller
|
|||||||
$datasetReader = $this->getDataSetReader($dataSet);
|
$datasetReader = $this->getDataSetReader($dataSet);
|
||||||
|
|
||||||
$networkTraining = match ($perceptronType) {
|
$networkTraining = match ($perceptronType) {
|
||||||
'simple' => new SimpleBinaryPerceptronTraining($datasetReader, $learningRate, $maxEpochs, $synapticWeightsProvider, $iterationEventBuffer, $sessionId, $trainingId),
|
'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),
|
'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),
|
'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),
|
'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),
|
'multilayer' => new MultiLayerPerceptronTraining($datasetReader, $learningRate, $maxEpochs, $hiddenLayers, $hiddenLayersNeurons, $synapticWeightsProvider, $iterationEventBuffer, $sessionId, $trainingId, $minError, fn (): bool => connection_aborted() || Cache::has($this->cancellationKey($trainingId))),
|
||||||
default => null,
|
default => null,
|
||||||
};
|
};
|
||||||
|
|
||||||
event(new PerceptronInitialization($datasetReader->lines, $networkTraining->activationFunction, $sessionId, $trainingId));
|
event(new PerceptronInitialization($datasetReader->lines, $networkTraining->activationFunction, $sessionId, $trainingId));
|
||||||
|
|
||||||
|
try {
|
||||||
$networkTraining->start();
|
$networkTraining->start();
|
||||||
|
} catch (TrainingCancelledException) {
|
||||||
|
$networkTraining->cancel();
|
||||||
|
Cache::forget($this->cancellationKey($trainingId));
|
||||||
|
}
|
||||||
|
|
||||||
return back()->with('success', [
|
return back()->with('success', [
|
||||||
'message' => 'Training completed',
|
'message' => 'Training completed',
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use App\Models\Perceptrons\Perceptron;
|
|||||||
use App\Services\DatasetReader\IDataSetReader;
|
use App\Services\DatasetReader\IDataSetReader;
|
||||||
use App\Services\IterationEventBuffer\IPerceptronIterationEventBuffer;
|
use App\Services\IterationEventBuffer\IPerceptronIterationEventBuffer;
|
||||||
use App\Services\SynapticWeightsProvider\ISynapticWeightsProvider;
|
use App\Services\SynapticWeightsProvider\ISynapticWeightsProvider;
|
||||||
|
use Closure;
|
||||||
|
|
||||||
class ADALINEPerceptronTraining extends NetworkTraining
|
class ADALINEPerceptronTraining extends NetworkTraining
|
||||||
{
|
{
|
||||||
@@ -26,8 +27,9 @@ class ADALINEPerceptronTraining extends NetworkTraining
|
|||||||
string $sessionId,
|
string $sessionId,
|
||||||
string $trainingId,
|
string $trainingId,
|
||||||
private float $minError,
|
private float $minError,
|
||||||
|
?Closure $isCancelled = null,
|
||||||
) {
|
) {
|
||||||
parent::__construct($datasetReader, $maxEpochs, $iterationEventBuffer, $sessionId, $trainingId);
|
parent::__construct($datasetReader, $maxEpochs, $iterationEventBuffer, $sessionId, $trainingId, $isCancelled);
|
||||||
$this->perceptron = new GradientDescentPerceptron($synapticWeightsProvider->generate($datasetReader->getInputSize()));
|
$this->perceptron = new GradientDescentPerceptron($synapticWeightsProvider->generate($datasetReader->getInputSize()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use App\Models\Perceptrons\Perceptron;
|
|||||||
use App\Services\DatasetReader\IDataSetReader;
|
use App\Services\DatasetReader\IDataSetReader;
|
||||||
use App\Services\IterationEventBuffer\IPerceptronIterationEventBuffer;
|
use App\Services\IterationEventBuffer\IPerceptronIterationEventBuffer;
|
||||||
use App\Services\SynapticWeightsProvider\ISynapticWeightsProvider;
|
use App\Services\SynapticWeightsProvider\ISynapticWeightsProvider;
|
||||||
|
use Closure;
|
||||||
|
|
||||||
class GradientDescentPerceptronTraining extends NetworkTraining
|
class GradientDescentPerceptronTraining extends NetworkTraining
|
||||||
{
|
{
|
||||||
@@ -26,8 +27,9 @@ class GradientDescentPerceptronTraining extends NetworkTraining
|
|||||||
string $sessionId,
|
string $sessionId,
|
||||||
string $trainingId,
|
string $trainingId,
|
||||||
private float $minError,
|
private float $minError,
|
||||||
|
?Closure $isCancelled = null,
|
||||||
) {
|
) {
|
||||||
parent::__construct($datasetReader, $maxEpochs, $iterationEventBuffer, $sessionId, $trainingId);
|
parent::__construct($datasetReader, $maxEpochs, $iterationEventBuffer, $sessionId, $trainingId, $isCancelled);
|
||||||
$this->perceptron = new GradientDescentPerceptron($synapticWeightsProvider->generate($datasetReader->getInputSize()));
|
$this->perceptron = new GradientDescentPerceptron($synapticWeightsProvider->generate($datasetReader->getInputSize()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ use App\Services\DatasetReader\IDataSetReader;
|
|||||||
use App\Services\IterationEventBuffer\IPerceptronIterationEventBuffer;
|
use App\Services\IterationEventBuffer\IPerceptronIterationEventBuffer;
|
||||||
use App\Services\SynapticWeightsProvider\ISynapticWeightsProvider;
|
use App\Services\SynapticWeightsProvider\ISynapticWeightsProvider;
|
||||||
use App\Services\SynapticWeightsProvider\SimpleNetworkWeightsProvider;
|
use App\Services\SynapticWeightsProvider\SimpleNetworkWeightsProvider;
|
||||||
|
use Closure;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
|
|
||||||
class MonoLayerPerceptronTraining extends NetworkTraining
|
class MonoLayerPerceptronTraining extends NetworkTraining
|
||||||
@@ -35,8 +36,9 @@ class MonoLayerPerceptronTraining extends NetworkTraining
|
|||||||
string $sessionId,
|
string $sessionId,
|
||||||
string $trainingId,
|
string $trainingId,
|
||||||
private float $minError,
|
private float $minError,
|
||||||
|
?Closure $isCancelled = null,
|
||||||
) {
|
) {
|
||||||
parent::__construct($datasetReader, $maxEpochs, $iterationEventBuffer, $sessionId, $trainingId);
|
parent::__construct($datasetReader, $maxEpochs, $iterationEventBuffer, $sessionId, $trainingId, $isCancelled);
|
||||||
$this->isRegression = $datasetReader->getInputSize() === 1;
|
$this->isRegression = $datasetReader->getInputSize() === 1;
|
||||||
$networkWeightsProvider = new SimpleNetworkWeightsProvider($synapticWeightsProvider);
|
$networkWeightsProvider = new SimpleNetworkWeightsProvider($synapticWeightsProvider);
|
||||||
$this->network = new NetworkPerceptron(
|
$this->network = new NetworkPerceptron(
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ use App\Services\DatasetReader\IDataSetReader;
|
|||||||
use App\Services\IterationEventBuffer\IPerceptronIterationEventBuffer;
|
use App\Services\IterationEventBuffer\IPerceptronIterationEventBuffer;
|
||||||
use App\Services\SynapticWeightsProvider\ISynapticWeightsProvider;
|
use App\Services\SynapticWeightsProvider\ISynapticWeightsProvider;
|
||||||
use App\Services\SynapticWeightsProvider\SimpleNetworkWeightsProvider;
|
use App\Services\SynapticWeightsProvider\SimpleNetworkWeightsProvider;
|
||||||
|
use Closure;
|
||||||
use Illuminate\Support\Arr;
|
use Illuminate\Support\Arr;
|
||||||
|
|
||||||
class MultiLayerPerceptronTraining extends NetworkTraining
|
class MultiLayerPerceptronTraining extends NetworkTraining
|
||||||
@@ -37,8 +38,9 @@ class MultiLayerPerceptronTraining extends NetworkTraining
|
|||||||
string $sessionId,
|
string $sessionId,
|
||||||
string $trainingId,
|
string $trainingId,
|
||||||
private float $minError,
|
private float $minError,
|
||||||
|
?Closure $isCancelled = null,
|
||||||
) {
|
) {
|
||||||
parent::__construct($datasetReader, $maxEpochs, $iterationEventBuffer, $sessionId, $trainingId);
|
parent::__construct($datasetReader, $maxEpochs, $iterationEventBuffer, $sessionId, $trainingId, $isCancelled);
|
||||||
$this->labels = $datasetReader->getLabels();
|
$this->labels = $datasetReader->getLabels();
|
||||||
$this->isRegression = $datasetReader->getOutputSize() === 1
|
$this->isRegression = $datasetReader->getOutputSize() === 1
|
||||||
|| ($datasetReader->getOutputSize() > 2
|
|| ($datasetReader->getOutputSize() > 2
|
||||||
|
|||||||
@@ -3,9 +3,11 @@
|
|||||||
namespace App\Models\NetworksTraining;
|
namespace App\Models\NetworksTraining;
|
||||||
|
|
||||||
use App\Events\PerceptronTrainingEnded;
|
use App\Events\PerceptronTrainingEnded;
|
||||||
|
use App\Exceptions\TrainingCancelledException;
|
||||||
use App\Models\ActivationsFunctions;
|
use App\Models\ActivationsFunctions;
|
||||||
use App\Services\DatasetReader\IDataSetReader;
|
use App\Services\DatasetReader\IDataSetReader;
|
||||||
use App\Services\IterationEventBuffer\IPerceptronIterationEventBuffer;
|
use App\Services\IterationEventBuffer\IPerceptronIterationEventBuffer;
|
||||||
|
use Closure;
|
||||||
|
|
||||||
abstract class NetworkTraining
|
abstract class NetworkTraining
|
||||||
{
|
{
|
||||||
@@ -24,6 +26,7 @@ abstract class NetworkTraining
|
|||||||
protected IPerceptronIterationEventBuffer $iterationEventBuffer,
|
protected IPerceptronIterationEventBuffer $iterationEventBuffer,
|
||||||
protected string $sessionId,
|
protected string $sessionId,
|
||||||
protected string $trainingId,
|
protected string $trainingId,
|
||||||
|
protected ?Closure $isCancelled = null,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
abstract public function start(): void;
|
abstract public function start(): void;
|
||||||
@@ -50,9 +53,18 @@ abstract class NetworkTraining
|
|||||||
|
|
||||||
protected function addIterationToBuffer(float $error, array $synapticWeights)
|
protected function addIterationToBuffer(float $error, array $synapticWeights)
|
||||||
{
|
{
|
||||||
|
if ($this->isCancelled !== null && ($this->isCancelled)()) {
|
||||||
|
throw new TrainingCancelledException;
|
||||||
|
}
|
||||||
|
|
||||||
$this->iterationEventBuffer->addIteration($this->epoch, $this->datasetReader->getLastReadLineIndex(), $error, $synapticWeights);
|
$this->iterationEventBuffer->addIteration($this->epoch, $this->datasetReader->getLastReadLineIndex(), $error, $synapticWeights);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function cancel(): void
|
||||||
|
{
|
||||||
|
$this->broadcastTrainingEnded('Entraînement annulé');
|
||||||
|
}
|
||||||
|
|
||||||
public function getEpoch(): int
|
public function getEpoch(): int
|
||||||
{
|
{
|
||||||
return $this->epoch;
|
return $this->epoch;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ use App\Models\Perceptrons\SimpleBinaryPerceptron;
|
|||||||
use App\Services\DatasetReader\IDataSetReader;
|
use App\Services\DatasetReader\IDataSetReader;
|
||||||
use App\Services\IterationEventBuffer\IPerceptronIterationEventBuffer;
|
use App\Services\IterationEventBuffer\IPerceptronIterationEventBuffer;
|
||||||
use App\Services\SynapticWeightsProvider\ISynapticWeightsProvider;
|
use App\Services\SynapticWeightsProvider\ISynapticWeightsProvider;
|
||||||
|
use Closure;
|
||||||
|
|
||||||
class SimpleBinaryPerceptronTraining extends NetworkTraining
|
class SimpleBinaryPerceptronTraining extends NetworkTraining
|
||||||
{
|
{
|
||||||
@@ -28,8 +29,9 @@ class SimpleBinaryPerceptronTraining extends NetworkTraining
|
|||||||
IPerceptronIterationEventBuffer $iterationEventBuffer,
|
IPerceptronIterationEventBuffer $iterationEventBuffer,
|
||||||
string $sessionId,
|
string $sessionId,
|
||||||
string $trainingId,
|
string $trainingId,
|
||||||
|
?Closure $isCancelled = null,
|
||||||
) {
|
) {
|
||||||
parent::__construct($datasetReader, $maxEpochs, $iterationEventBuffer, $sessionId, $trainingId);
|
parent::__construct($datasetReader, $maxEpochs, $iterationEventBuffer, $sessionId, $trainingId, $isCancelled);
|
||||||
$this->perceptron = new SimpleBinaryPerceptron($synapticWeightsProvider->generate($datasetReader->getInputSize()));
|
$this->perceptron = new SimpleBinaryPerceptron($synapticWeightsProvider->generate($datasetReader->getInputSize()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useForm } from '@inertiajs/vue3';
|
import { router, useForm } from '@inertiajs/vue3';
|
||||||
import { ref, watch } from 'vue';
|
import { ref, watch } from 'vue';
|
||||||
import {
|
import {
|
||||||
Form,
|
Form,
|
||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
NativeSelect,
|
NativeSelect,
|
||||||
NativeSelectOption,
|
NativeSelectOption,
|
||||||
} from '@/components/ui/native-select';
|
} from '@/components/ui/native-select';
|
||||||
|
import { cancel } from '@/routes/perceptron';
|
||||||
import type {
|
import type {
|
||||||
Dataset,
|
Dataset,
|
||||||
InitializationMethod,
|
InitializationMethod,
|
||||||
@@ -23,8 +24,9 @@ import Card from './ui/card/Card.vue';
|
|||||||
import CardContent from './ui/card/CardContent.vue';
|
import CardContent from './ui/card/CardContent.vue';
|
||||||
import CardHeader from './ui/card/CardHeader.vue';
|
import CardHeader from './ui/card/CardHeader.vue';
|
||||||
import CardTitle from './ui/card/CardTitle.vue';
|
import CardTitle from './ui/card/CardTitle.vue';
|
||||||
import Input from './ui/input/Input.vue';
|
|
||||||
import FormError from './ui/form/FormError.vue';
|
import FormError from './ui/form/FormError.vue';
|
||||||
|
import Input from './ui/input/Input.vue';
|
||||||
|
import Spinner from './ui/spinner/Spinner.vue';
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
type: PerceptronType;
|
type: PerceptronType;
|
||||||
@@ -98,35 +100,50 @@ watch(maxIterations, (value) => {
|
|||||||
watch(selectedDatasetCopy, (newvalue) => {
|
watch(selectedDatasetCopy, (newvalue) => {
|
||||||
form.clearErrors('dataset');
|
form.clearErrors('dataset');
|
||||||
|
|
||||||
const selectedDatasetCopy = props.datasets.find(
|
const selectedDatasetCopy =
|
||||||
(dataset) => dataset.label === newvalue
|
props.datasets.find((dataset) => dataset.label === newvalue) || null;
|
||||||
) || null;
|
|
||||||
|
|
||||||
// LearningRate
|
// LearningRate
|
||||||
learningRate.value = props.defaultLearningRate;
|
learningRate.value = props.defaultLearningRate;
|
||||||
if (selectedDatasetCopy && selectedDatasetCopy.defaultLearningRate !== undefined) {
|
if (
|
||||||
|
selectedDatasetCopy &&
|
||||||
|
selectedDatasetCopy.defaultLearningRate !== undefined
|
||||||
|
) {
|
||||||
learningRate.value = selectedDatasetCopy.defaultLearningRate;
|
learningRate.value = selectedDatasetCopy.defaultLearningRate;
|
||||||
}
|
}
|
||||||
// MinError
|
// MinError
|
||||||
minError.value = props.minError;
|
minError.value = props.minError;
|
||||||
if (selectedDatasetCopy && selectedDatasetCopy.defaultMinError !== undefined) {
|
if (
|
||||||
|
selectedDatasetCopy &&
|
||||||
|
selectedDatasetCopy.defaultMinError !== undefined
|
||||||
|
) {
|
||||||
minError.value = selectedDatasetCopy.defaultMinError;
|
minError.value = selectedDatasetCopy.defaultMinError;
|
||||||
}
|
}
|
||||||
// MaxIterations
|
// MaxIterations
|
||||||
maxIterations.value = props.defaultMaxIterations;
|
maxIterations.value = props.defaultMaxIterations;
|
||||||
if (selectedDatasetCopy && selectedDatasetCopy.defaultMaxIterations !== undefined) {
|
if (
|
||||||
|
selectedDatasetCopy &&
|
||||||
|
selectedDatasetCopy.defaultMaxIterations !== undefined
|
||||||
|
) {
|
||||||
maxIterations.value = selectedDatasetCopy.defaultMaxIterations;
|
maxIterations.value = selectedDatasetCopy.defaultMaxIterations;
|
||||||
}
|
}
|
||||||
// HiddenLayers
|
// HiddenLayers
|
||||||
hiddenLayers.value = props.hiddenLayers;
|
hiddenLayers.value = props.hiddenLayers;
|
||||||
if (selectedDatasetCopy && selectedDatasetCopy.defaultHiddenLayers !== undefined) {
|
if (
|
||||||
|
selectedDatasetCopy &&
|
||||||
|
selectedDatasetCopy.defaultHiddenLayers !== undefined
|
||||||
|
) {
|
||||||
hiddenLayers.value = selectedDatasetCopy.defaultHiddenLayers;
|
hiddenLayers.value = selectedDatasetCopy.defaultHiddenLayers;
|
||||||
}
|
}
|
||||||
hiddenLayersNeurons.value = props.hiddenLayersNeurons;
|
hiddenLayersNeurons.value = props.hiddenLayersNeurons;
|
||||||
if (selectedDatasetCopy && selectedDatasetCopy.defaultHiddenLayersNeurons !== undefined) {
|
if (
|
||||||
hiddenLayersNeurons.value = selectedDatasetCopy.defaultHiddenLayersNeurons;
|
selectedDatasetCopy &&
|
||||||
|
selectedDatasetCopy.defaultHiddenLayersNeurons !== undefined
|
||||||
|
) {
|
||||||
|
hiddenLayersNeurons.value =
|
||||||
|
selectedDatasetCopy.defaultHiddenLayersNeurons;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const trainingId = ref<string>('');
|
const trainingId = ref<string>('');
|
||||||
|
|
||||||
@@ -134,7 +151,7 @@ function startTraining() {
|
|||||||
if (!selectedDatasetCopy.value) {
|
if (!selectedDatasetCopy.value) {
|
||||||
form.setError(
|
form.setError(
|
||||||
'dataset',
|
'dataset',
|
||||||
'Un dataset est nécessaire avant de lancer l\'entraînement.',
|
"Un dataset est nécessaire avant de lancer l'entraînement.",
|
||||||
);
|
);
|
||||||
console.log(form.errors);
|
console.log(form.errors);
|
||||||
return;
|
return;
|
||||||
@@ -169,6 +186,21 @@ function startTraining() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const emit = defineEmits(['update:selectedDataset', 'update:trainingId']);
|
const emit = defineEmits(['update:selectedDataset', 'update:trainingId']);
|
||||||
|
|
||||||
|
async function cancelTraining() {
|
||||||
|
form.cancel();
|
||||||
|
|
||||||
|
router.post(
|
||||||
|
cancel(),
|
||||||
|
{
|
||||||
|
training_id: trainingId.value,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
preserveScroll: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
watch(selectedDatasetCopy, (newValue) => {
|
watch(selectedDatasetCopy, (newValue) => {
|
||||||
emit('update:selectedDataset', newValue);
|
emit('update:selectedDataset', newValue);
|
||||||
});
|
});
|
||||||
@@ -182,6 +214,7 @@ watch(selectedDatasetCopy, (newValue) => {
|
|||||||
<CardContent>
|
<CardContent>
|
||||||
<Form
|
<Form
|
||||||
class="grid auto-cols-max grid-flow-row grid-cols-1 gap-4 space-y-6 md:grid-cols-2"
|
class="grid auto-cols-max grid-flow-row grid-cols-1 gap-4 space-y-6 md:grid-cols-2"
|
||||||
|
cancel-on-unmount
|
||||||
>
|
>
|
||||||
<!-- DATASET -->
|
<!-- DATASET -->
|
||||||
<FormField name="dataset">
|
<FormField name="dataset">
|
||||||
@@ -206,7 +239,12 @@ watch(selectedDatasetCopy, (newValue) => {
|
|||||||
</NativeSelectOption>
|
</NativeSelectOption>
|
||||||
</NativeSelect>
|
</NativeSelect>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormError :error="form.errors.dataset || props.errors?.selectedDatasetCopy" />
|
<FormError
|
||||||
|
:error="
|
||||||
|
form.errors.dataset ||
|
||||||
|
props.errors?.selectedDatasetCopy
|
||||||
|
"
|
||||||
|
/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
</FormField>
|
</FormField>
|
||||||
|
|
||||||
@@ -224,7 +262,9 @@ watch(selectedDatasetCopy, (newValue) => {
|
|||||||
class="cursor-pointer"
|
class="cursor-pointer"
|
||||||
>
|
>
|
||||||
<NativeSelectOption
|
<NativeSelectOption
|
||||||
v-for="method in (props.type == 'multilayer' ? ['random'] : ['zeros', 'random'])"
|
v-for="method in props.type == 'multilayer'
|
||||||
|
? ['random']
|
||||||
|
: ['zeros', 'random']"
|
||||||
v-bind:key="method"
|
v-bind:key="method"
|
||||||
:value="method"
|
:value="method"
|
||||||
>
|
>
|
||||||
@@ -236,7 +276,10 @@ watch(selectedDatasetCopy, (newValue) => {
|
|||||||
</FormField>
|
</FormField>
|
||||||
|
|
||||||
<!-- HIDDEN LAYERS -->
|
<!-- HIDDEN LAYERS -->
|
||||||
<FormField name="hidden_layers" v-if="props.type === 'multilayer'">
|
<FormField
|
||||||
|
name="hidden_layers"
|
||||||
|
v-if="props.type === 'multilayer'"
|
||||||
|
>
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Nombre de couches cachées</FormLabel>
|
<FormLabel>Nombre de couches cachées</FormLabel>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
@@ -255,9 +298,14 @@ watch(selectedDatasetCopy, (newValue) => {
|
|||||||
</FormField>
|
</FormField>
|
||||||
|
|
||||||
<!-- HIDDEN LAYERS NEURONS -->
|
<!-- HIDDEN LAYERS NEURONS -->
|
||||||
<FormField name="hidden_layers_neurons" v-if="props.type === 'multilayer'">
|
<FormField
|
||||||
|
name="hidden_layers_neurons"
|
||||||
|
v-if="props.type === 'multilayer'"
|
||||||
|
>
|
||||||
<FormItem>
|
<FormItem>
|
||||||
<FormLabel>Nombre de neurones par couche cachée</FormLabel>
|
<FormLabel
|
||||||
|
>Nombre de neurones par couche cachée</FormLabel
|
||||||
|
>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<!-- TODO : MAX input -->
|
<!-- TODO : MAX input -->
|
||||||
<Input
|
<Input
|
||||||
@@ -319,13 +367,39 @@ watch(selectedDatasetCopy, (newValue) => {
|
|||||||
@input="handleMaxIterationsInput"
|
@input="handleMaxIterationsInput"
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<div v-if="form.errors.max_iterations || props.errors.max_iterations">
|
<div
|
||||||
{{ form.errors.max_iterations || props.errors.max_iterations }}
|
v-if="
|
||||||
|
form.errors.max_iterations ||
|
||||||
|
props.errors.max_iterations
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
form.errors.max_iterations ||
|
||||||
|
props.errors.max_iterations
|
||||||
|
}}
|
||||||
</div>
|
</div>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
</FormField>
|
</FormField>
|
||||||
</Form>
|
</Form>
|
||||||
<Button variant="outline" class="cursor-pointer mt-6" @click="startTraining">Lancer</Button>
|
|
||||||
|
<Transition name="fade">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
class="mt-6 cursor-pointer"
|
||||||
|
:disabled="form.processing"
|
||||||
|
@click="startTraining"
|
||||||
|
>Lancer<Spinner v-if="form.processing" class="ml-1"
|
||||||
|
/></Button>
|
||||||
|
</Transition>
|
||||||
|
<Transition name="fade">
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
class="mt-6 ml-4 cursor-pointer"
|
||||||
|
@click="cancelTraining"
|
||||||
|
v-if="form.processing"
|
||||||
|
>Annuler</Button
|
||||||
|
>
|
||||||
|
</Transition>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
LineController,
|
LineController,
|
||||||
BarController,
|
BarController,
|
||||||
LogarithmicScale,
|
LogarithmicScale,
|
||||||
|
|
||||||
} from 'chart.js';
|
} from 'chart.js';
|
||||||
import { ArrowDown, ArrowUp } from 'lucide-vue-next';
|
import { ArrowDown, ArrowUp } from 'lucide-vue-next';
|
||||||
import { computed, nextTick, ref, watch } from 'vue';
|
import { computed, nextTick, ref, watch } from 'vue';
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
use App\Http\Controllers\PerceptronController;
|
use App\Http\Controllers\PerceptronController;
|
||||||
use Illuminate\Support\Facades\Broadcast;
|
use Illuminate\Support\Facades\Broadcast;
|
||||||
use Illuminate\Support\Facades\Route;
|
use Illuminate\Support\Facades\Route;
|
||||||
|
use Illuminate\Session\Middleware\StartSession;
|
||||||
use Inertia\Inertia;
|
use Inertia\Inertia;
|
||||||
|
|
||||||
// Route::redirect('/', '/perceptron?type=simple')->name('home');
|
// Route::redirect('/', '/perceptron?type=simple')->name('home');
|
||||||
@@ -15,6 +16,10 @@ Route::middleware('throttle:training')->post(
|
|||||||
[PerceptronController::class, 'run'],
|
[PerceptronController::class, 'run'],
|
||||||
)->name('perceptron.run');
|
)->name('perceptron.run');
|
||||||
|
|
||||||
|
Route::post('perceptron/cancel', [PerceptronController::class, 'cancel'])
|
||||||
|
->name('perceptron.cancel')
|
||||||
|
->withoutMiddleware(StartSession::class);
|
||||||
|
|
||||||
Route::resource('perceptron', PerceptronController::class)->only(['index']);
|
Route::resource('perceptron', PerceptronController::class)->only(['index']);
|
||||||
|
|
||||||
Broadcast::routes();
|
Broadcast::routes();
|
||||||
|
|||||||
Reference in New Issue
Block a user