From 59e3f40095eba7b541b0553c5a048e36dfe94f95 Mon Sep 17 00:00:00 2001 From: Sonja Galovic Date: Sat, 19 Mar 2022 19:56:01 +0100 Subject: Add-model izmene. Obrnuta pozicija trening i test skupa i dodato input dugme za rucni unos. Ulazne kolone sve cekirane i po potrebi disabled. --- frontend/src/app/_data/Model.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'frontend/src/app/_data/Model.ts') diff --git a/frontend/src/app/_data/Model.ts b/frontend/src/app/_data/Model.ts index a891c10c..a038325e 100644 --- a/frontend/src/app/_data/Model.ts +++ b/frontend/src/app/_data/Model.ts @@ -12,7 +12,7 @@ export default class Model { public columnToPredict: string = '', public randomOrder: boolean = true, public randomTestSet: boolean = true, - public randomTestSetDistribution: number = 0.10, //0.1-0.9 (10% - 90%) + public randomTestSetDistribution: number = 10, //0.1-0.9 (10% - 90%) JESTE OVDE ZAKUCANO 10, AL POSLATO JE KAO 0.1 BACK-U // Neural net training settings public type: ANNType = ANNType.FullyConnected, -- cgit v1.2.3 From 02362378a6b0a7b2db6b7fb2ba09cf529b292508 Mon Sep 17 00:00:00 2001 From: Nevena Bojovic Date: Sat, 19 Mar 2022 22:39:12 +0100 Subject: Proveravanje hiperparametara mreze uradjeno. --- backend/api/api/Controllers/ModelController.cs | 2 ++ backend/api/api/Models/Model.cs | 2 ++ backend/api/api/Services/IModelService.cs | 1 + backend/api/api/Services/ModelService.cs | 12 ++++++- frontend/src/app/_data/Model.ts | 48 +++++++++++++++++++++++--- 5 files changed, 60 insertions(+), 5 deletions(-) (limited to 'frontend/src/app/_data/Model.ts') diff --git a/backend/api/api/Controllers/ModelController.cs b/backend/api/api/Controllers/ModelController.cs index 1d03d924..a4fa99c4 100644 --- a/backend/api/api/Controllers/ModelController.cs +++ b/backend/api/api/Controllers/ModelController.cs @@ -86,6 +86,8 @@ namespace api.Controllers [Authorize(Roles = "User")] public ActionResult Post([FromBody] Model model) { + if (_modelService.CheckHyperparameters(model.inputNeurons, model.hiddenLayerNeurons, model.hiddenLayers, model.outputNeurons) == false) + return BadRequest("Bad parameters!"); var existingModel = _modelService.GetOneModel(model.username, model.name); if (existingModel != null) diff --git a/backend/api/api/Models/Model.cs b/backend/api/api/Models/Model.cs index dfc4336a..52516cd9 100644 --- a/backend/api/api/Models/Model.cs +++ b/backend/api/api/Models/Model.cs @@ -36,6 +36,8 @@ namespace api.Models public int hiddenLayerNeurons { get; set; } public int hiddenLayers { get; set; } public int batchSize { get; set; } + // na izlazu je moguce da bude vise neurona (klasifikacioni problem sa vise od 2 klase) + public int outputNeurons { get; set; } public string inputLayerActivationFunction { get; set; } public string hiddenLayerActivationFunction { get; set; } public string outputLayerActivationFunction { get; set; } diff --git a/backend/api/api/Services/IModelService.cs b/backend/api/api/Services/IModelService.cs index c1931ffa..887be4ae 100644 --- a/backend/api/api/Services/IModelService.cs +++ b/backend/api/api/Services/IModelService.cs @@ -11,6 +11,7 @@ namespace api.Services Model Create(Model model); void Update(string username, string name, Model model); void Delete(string username, string name); + bool CheckHyperparameters(int inputNeurons, int hiddenLayerNeurons, int hiddenLayers, int outputNeurons); } } diff --git a/backend/api/api/Services/ModelService.cs b/backend/api/api/Services/ModelService.cs index 2ba3c54d..3d5c3b3e 100644 --- a/backend/api/api/Services/ModelService.cs +++ b/backend/api/api/Services/ModelService.cs @@ -7,7 +7,6 @@ namespace api.Services { public class ModelService : IModelService { - private readonly IMongoCollection _model; public ModelService(IUserStoreDatabaseSettings settings, IMongoClient mongoClient) @@ -46,6 +45,17 @@ namespace api.Services { _model.ReplaceOne(model => model.username == username && model.name == name, model); } + // + public bool CheckHyperparameters(int inputNeurons, int hiddenLayerNeurons, int hiddenLayers, int outputNeurons) + { + if (hiddenLayers <= 0 || hiddenLayerNeurons <= 0) + return false; + if (hiddenLayers > inputNeurons) + return false; + if (hiddenLayerNeurons <= 2 * inputNeurons || hiddenLayerNeurons <= (2 / 3) * inputNeurons + outputNeurons || (hiddenLayerNeurons <= Math.Max(inputNeurons, outputNeurons) && hiddenLayerNeurons >= Math.Min(inputNeurons, outputNeurons))) + return true; + return false; + } } } diff --git a/frontend/src/app/_data/Model.ts b/frontend/src/app/_data/Model.ts index a891c10c..594bf129 100644 --- a/frontend/src/app/_data/Model.ts +++ b/frontend/src/app/_data/Model.ts @@ -39,21 +39,61 @@ export enum ANNType { // removeOutliers export enum Encoding { Label = 'label', - OneHot = 'one hot' + OneHot = 'one hot', + BackwardDifference = 'backward difference', + BaseN = 'baseN', + Binary = 'binary', + CatBoost = 'cat boost', + Count = 'count', + GLMM = 'glmm', + Hashing = 'hashing', + Helmert = 'helmert', + JamesStein = 'james stein', + LeaveOneOut = 'leave one out', + MEstimate = 'MEstimate', + Ordinal = 'ordinal', + Sum = 'sum', + Polynomial = 'polynomial', + Target = 'target', + WOE = 'woe', + Quantile = 'quantile' } export enum ActivationFunction { + // linear + Binary_Step = 'binaryStep', + Linear = 'linear', + // non-linear Relu = 'relu', + Leaky_Relu = 'leakyRelu', + Parameterised_Relu = 'parameterisedRelu', + Exponential_Linear_Unit = 'exponentialLinearUnit', + Swish = 'swish', Sigmoid = 'sigmoid', Tanh = 'tanh', - Linear = 'linear' + Softmax = 'softmax' } export enum LossFunction { + // binary classification loss functions BinaryCrossEntropy = 'binary_crossentropy', - MeanSquaredError = 'mean_squared_error' + HingeLoss = 'hinge_loss', + // multi-class classiication loss functions + CategoricalCrossEntropy = 'categorical_crossentropy', + KLDivergence = 'kullback_leibler_divergence', + // regression loss functions + MeanSquaredError = 'mean_squared_error', + MeanAbsoluteError = 'mean_absolute_error', + HuberLoss = 'Huber', } export enum Optimizer { - Adam = 'adam' + Adam = 'Adam', + Adadelta = 'Adadelta', + Adagrad = 'Adagrad', + Ftrl = 'Ftrl', + Nadam = 'Nadam', + SGD = 'SGD', + SGDMomentum = 'SGDMomentum', + RMSprop = 'RMSprop' } \ No newline at end of file -- cgit v1.2.3 From efecf70b6f54560269c3ee8211ea6456c0481e69 Mon Sep 17 00:00:00 2001 From: Sonja Galovic Date: Sun, 20 Mar 2022 23:37:41 +0100 Subject: Add-model strana. Dodavanje modela uz postojeci dataset ili uz kreiranje novog dataseta. Servis za uzimanje korisnikovih datasetova iz baze. Izmenjen randomTestSetDistribution. --- frontend/src/app/_data/Model.ts | 2 +- .../item-dataset/item-dataset.component.html | 2 +- .../app/_pages/add-model/add-model.component.css | 17 +++ .../app/_pages/add-model/add-model.component.html | 87 +++++++++-- .../app/_pages/add-model/add-model.component.ts | 167 +++++++++++++++++++-- frontend/src/app/_services/models.service.ts | 4 + 6 files changed, 254 insertions(+), 25 deletions(-) (limited to 'frontend/src/app/_data/Model.ts') diff --git a/frontend/src/app/_data/Model.ts b/frontend/src/app/_data/Model.ts index a038325e..810b347d 100644 --- a/frontend/src/app/_data/Model.ts +++ b/frontend/src/app/_data/Model.ts @@ -12,7 +12,7 @@ export default class Model { public columnToPredict: string = '', public randomOrder: boolean = true, public randomTestSet: boolean = true, - public randomTestSetDistribution: number = 10, //0.1-0.9 (10% - 90%) JESTE OVDE ZAKUCANO 10, AL POSLATO JE KAO 0.1 BACK-U + public randomTestSetDistribution: number = 0.1, //0.1-0.9 (10% - 90%) JESTE OVDE ZAKUCANO 10, AL POSLATO JE KAO 0.1 BACK-U // Neural net training settings public type: ANNType = ANNType.FullyConnected, diff --git a/frontend/src/app/_elements/item-dataset/item-dataset.component.html b/frontend/src/app/_elements/item-dataset/item-dataset.component.html index cf39a125..46840cdd 100644 --- a/frontend/src/app/_elements/item-dataset/item-dataset.component.html +++ b/frontend/src/app/_elements/item-dataset/item-dataset.component.html @@ -2,7 +2,7 @@
{{dataset.name}}
-
+

{{dataset.description}}

diff --git a/frontend/src/app/_pages/add-model/add-model.component.css b/frontend/src/app/_pages/add-model/add-model.component.css index 4bf569cc..6d961287 100644 --- a/frontend/src/app/_pages/add-model/add-model.component.css +++ b/frontend/src/app/_pages/add-model/add-model.component.css @@ -15,4 +15,21 @@ #wrapper { color: #003459; +} + +.btnType1 { + background-color: #003459; + color: white; +} +.btnType2 { + background-color: white; + color: #003459; + border-color: #003459; +} +.selectedDatasetClass { + /*border-color: 2px solid #003459;*/ + background-color: lightblue; +} +ul li:hover { + background-color: lightblue; } \ No newline at end of file diff --git a/frontend/src/app/_pages/add-model/add-model.component.html b/frontend/src/app/_pages/add-model/add-model.component.html index 98cd204b..33066f80 100644 --- a/frontend/src/app/_pages/add-model/add-model.component.html +++ b/frontend/src/app/_pages/add-model/add-model.component.html @@ -6,7 +6,7 @@
-
+

Nov model:

@@ -26,20 +26,87 @@
-
-

Izvor podataka:

- +
+ +
+

Izvor podataka:

+
+
+ +

ili

+ +
+ + + + +
+
+
    +
  • + +
  • +
+
+
+ + +
-
-
+ + +
+

+ Izabrali ste dataset: {{this.selectedDataset.name}} +

+
+
+

Izaberite ulazne kolone:

+
+
+
+   + +
+
+
+
+

Izaberite izlaznu kolonu:

+
+
+
+   + +
+
+
+
+
+ + + +
+

Izaberite ulazne kolone:


  + id="cb_{{item}}" name="cbsNew" checked [disabled]="this.selectedOutputColumnVal == item">  @@ -52,7 +119,7 @@
  + id="rb_{{item}}" name="rbsNew" (change)="this.selectedOutputColumnVal = item">  @@ -221,7 +288,7 @@
-
@@ -248,7 +315,7 @@
trening + [disabled]="!newModel.randomTestSet" [(ngModel)]="tempTestSetDistribution"> test
diff --git a/frontend/src/app/_pages/add-model/add-model.component.ts b/frontend/src/app/_pages/add-model/add-model.component.ts index 6e9c95ca..7bfb7204 100644 --- a/frontend/src/app/_pages/add-model/add-model.component.ts +++ b/frontend/src/app/_pages/add-model/add-model.component.ts @@ -4,6 +4,7 @@ import { ANNType, Encoding, ActivationFunction, LossFunction, Optimizer } from ' import { DatasetLoadComponent } from 'src/app/_elements/dataset-load/dataset-load.component'; import { ModelsService } from 'src/app/_services/models.service'; import shared from 'src/app/Shared'; +import Dataset from 'src/app/_data/Dataset'; @Component({ @@ -28,54 +29,129 @@ export class AddModelComponent implements OnInit { selectedOutputColumnVal: string = ''; + showMyDatasets: boolean = true; + myDatasets?: Dataset[]; + existingDatasetSelected: boolean = false; + selectedDataset?: Dataset; + + tempTestSetDistribution: number = 90; + constructor(private models: ModelsService) { this.newModel = new Model(); + + this.models.getMyDatasets().subscribe((datasets) => { + this.myDatasets = datasets; + }); } ngOnInit(): void { + (document.getElementById("btnMyDataset")).focus(); + } + + viewMyDatasetsForm() { + this.showMyDatasets = true; + this.resetSelectedDataset(); + this.datasetLoaded = false; + this.resetCbsAndRbs(); + } + viewNewDatasetForm() { + this.showMyDatasets = false; + this.resetSelectedDataset(); + this.resetCbsAndRbs(); } addModel() { - this.saveModel(false); //trajno cuvanje + if (!this.showMyDatasets) + this.saveModelWithNewDataset(); + else + this.saveModelWithExistingDataset(); } trainModel() { - this.saveModel(true).subscribe((modelId: any) => { + this.saveModelWithNewDataset().subscribe((modelId: any) => { if (modelId) this.models.trainModel(modelId); }); //privremeno cuvanje modela => vraca id sacuvanog modela koji cemo da treniramo sad } - saveModel(temporary: boolean): any { + saveModelWithNewDataset(): any { + this.getCheckedInputCols(); this.getCheckedOutputCol(); + if (this.validationInputsOutput()) { console.log('ADD MODEL: STEP 1 - UPLOAD FILE'); if (this.datasetLoadComponent) { + this.models.uploadData(this.datasetLoadComponent.files[0]).subscribe((file) => { console.log('ADD MODEL: STEP 2 - ADD DATASET WITH FILE ID ' + file._id); if (this.datasetLoadComponent) { this.datasetLoadComponent.dataset.fileId = file._id; this.datasetLoadComponent.dataset.username = shared.username; + this.models.addDataset(this.datasetLoadComponent.dataset).subscribe((dataset) => { console.log('ADD MODEL: STEP 3 - ADD MODEL WITH DATASET ID ', dataset._id); this.newModel.datasetId = dataset._id; - this.newModel.randomTestSetDistribution = 1 - Math.round(this.newModel.randomTestSetDistribution / 100 * 10) / 10; + + //da se doda taj dataset u listu postojecih, da bude izabran + this.refreshMyDatasetList(); + this.showMyDatasets = true; + this.selectThisDataset(dataset); + + this.newModel.randomTestSetDistribution = 1 - Math.round(this.tempTestSetDistribution / 100 * 10) / 10; + this.tempTestSetDistribution = 90; this.newModel.username = shared.username; + this.models.addModel(this.newModel).subscribe((response) => { console.log('ADD MODEL: DONE! REPLY:\n', response); - }); - }); - } + }, (error) => { + alert("Model sa unetim nazivom već postoji u Vašoj kolekciji.\nPromenite naziv modela i nastavite sa kreiranim datasetom."); + }); //kraj addModel subscribe + }, (error) => { + alert("Dataset sa unetim nazivom već postoji u Vašoj kolekciji.\nIzmenite naziv ili iskoristite postojeći dataset."); + }); //kraj addDataset subscribe + } //kraj treceg ifa + }, (error) => { + //alert("greska uploadData"); + }); //kraj uploadData subscribe + + } //kraj drugog ifa + } //kraj prvog ifa + } + + saveModelWithExistingDataset(): any { + + if (this.selectedDataset) { //dataset je izabran + this.getCheckedInputCols(); + this.getCheckedOutputCol(); + + if (this.validationInputsOutput()) { + this.newModel.datasetId = this.selectedDataset._id; + + this.newModel.randomTestSetDistribution = 1 - Math.round(this.tempTestSetDistribution / 100 * 10) / 10; + this.tempTestSetDistribution = 90; + this.newModel.username = shared.username; + + this.models.addModel(this.newModel).subscribe((response) => { + console.log('ADD MODEL: DONE! REPLY:\n', response); + }, (error) => { + alert("Model sa unetim nazivom već postoji u Vašoj kolekciji.\nPromenite naziv modela i nastavite sa kreiranim datasetom."); }); } } + else { + alert("Molimo Vas da izaberete neki dataset iz kolekcije."); + } } getCheckedInputCols() { this.newModel.inputColumns = []; - let checkboxes = document.getElementsByName("cbs"); - + let checkboxes: any; + if (this.showMyDatasets) + checkboxes = document.getElementsByName("cbsExisting"); + else + checkboxes = document.getElementsByName("cbsNew"); + for (let i = 0; i < checkboxes.length; i++) { let thatCb = checkboxes[i]; if (thatCb.checked == true && thatCb.disabled == false) @@ -85,7 +161,11 @@ export class AddModelComponent implements OnInit { } getCheckedOutputCol() { this.newModel.columnToPredict = ''; - let radiobuttons = document.getElementsByName("rbs"); + let radiobuttons: any; + if (this.showMyDatasets) + radiobuttons = document.getElementsByName("rbsExisting"); + else + radiobuttons = document.getElementsByName("rbsNew"); for (let i = 0; i < radiobuttons.length; i++) { let thatRb = radiobuttons[i]; @@ -98,15 +178,15 @@ export class AddModelComponent implements OnInit { } validationInputsOutput(): boolean { if (this.newModel.inputColumns.length == 0 && this.newModel.columnToPredict == '') { - alert("Molimo Vas da izaberete ulazne i izlazne kolone za mrežu.") + alert("Molimo Vas da izaberete ulazne i izlazne kolone za mrežu."); return false; } else if (this.newModel.inputColumns.length == 0) { - alert("Molimo Vas da izaberete ulaznu kolonu/kolone za mrežu.") + alert("Molimo Vas da izaberete ulaznu kolonu/kolone za mrežu."); return false; } else if (this.newModel.columnToPredict == '') { - alert("Molimo Vas da izaberete izlaznu kolonu za mrežu.") + alert("Molimo Vas da izaberete izlaznu kolonu za mrežu."); return false; } for (let i = 0; i < this.newModel.inputColumns.length; i++) { @@ -119,4 +199,65 @@ export class AddModelComponent implements OnInit { return true; } + selectThisDataset(dataset: Dataset) { + this.selectedDataset = dataset; + this.existingDatasetSelected = true; + + /*let datasets = document.getElementsByClassName("usersDataset") as HTMLCollection; + for (let i = 0; i < datasets.length; i++) { + if (datasets[i]._id == dataset._id) + }*/ + + this.resetCbsAndRbs(); + } + + resetSelectedDataset(): boolean { + this.existingDatasetSelected = false; + this.selectedDataset = undefined; + return true; + } + resetCbsAndRbs(): boolean { + this.uncheckRbs(); + this.checkAllCbs(); + return true; + } + checkAllCbs() { + let checkboxes: any; + //if (this.showMyDatasets) + checkboxes = document.getElementsByName("cbsExisting"); + //else + //checkboxes = document.getElementsByName("cbsNew"); + + for (let i = 0; i < checkboxes.length; i++) { + (checkboxes[i]).checked = true; + (checkboxes[i]).disabled = false; + } + + checkboxes = document.getElementsByName("cbsNew"); + for (let i = 0; i < checkboxes.length; i++) { + (checkboxes[i]).checked = true; + (checkboxes[i]).disabled = false; + } + } + uncheckRbs() { + this.selectedOutputColumnVal = ''; + let radiobuttons: any; + //if (this.showMyDatasets) + radiobuttons = document.getElementsByName("rbsExisting"); + //else + //radiobuttons = document.getElementsByName("rbsNew"); + + for (let i = 0; i < radiobuttons.length; i++) + (radiobuttons[i]).checked = false; + radiobuttons = document.getElementsByName("rbsNew"); + for (let i = 0; i < radiobuttons.length; i++) + (radiobuttons[i]).checked = false; + } + + refreshMyDatasetList() { + this.models.getMyDatasets().subscribe((datasets) => { + this.myDatasets = datasets; + }); + } + } diff --git a/frontend/src/app/_services/models.service.ts b/frontend/src/app/_services/models.service.ts index 8299016b..30d63956 100644 --- a/frontend/src/app/_services/models.service.ts +++ b/frontend/src/app/_services/models.service.ts @@ -38,4 +38,8 @@ export class ModelsService { trainModel(modelId: string): Observable { return this.http.post(`${API_SETTINGS.apiURL}/model/train`, modelId, { headers: this.authService.authHeader() }); } + + getMyDatasets(): Observable { + return this.http.get(`${API_SETTINGS.apiURL}/dataset/mydatasets`, { headers: this.authService.authHeader() });//responsetype text da l treba?? + } } -- cgit v1.2.3