Repository: mlgym/mlgym (language: python)

Issue:
Dev



Discussion / hints:

Fix patch:
diff --git a/.gitignore b/.gitignore
index 40fecb18..c479bf82 100644
--- a/.gitignore
+++ b/.gitignore
@@ -128,4 +128,4 @@ event_storage
 *.whl
 *.arrow
 transformer/
-
+core.*
\ No newline at end of file
diff --git a/example/bert/run.py b/example/bert/run.py
index cb25ffb4..0669168b 100644
--- a/example/bert/run.py
+++ b/example/bert/run.py
@@ -1,4 +1,3 @@
-
 from bert_lm_blueprint import BERTLMBluePrint
 from ml_gym.cmd_entrypoint.cmd import get_args, run
 
diff --git a/example/bert/run_config.yml b/example/bert/run_config.yml
index 38cde87f..b7961732 100644
--- a/example/bert/run_config.yml
+++ b/example/bert/run_config.yml
@@ -3,7 +3,7 @@ run_configuration:
   config:
     num_epochs: 1000 # Number of epochs
     num_batches_per_epoch: 100
-    gs_config_path: /scratch/max/mlgym/example/bert/bert_lm_config.yml
+    gs_config_path: ./bert_lm_config.yml
 
 environment:
   type: accelerate # multiprocessing,  main_process, accelerate
diff --git a/example/cnn_ddp/conv_net.py b/example/cnn_ddp/conv_net.py
index 189b176f..68e2319e 100644
--- a/example/cnn_ddp/conv_net.py
+++ b/example/cnn_ddp/conv_net.py
@@ -41,10 +41,13 @@ def forward_impl(self, inputs: torch.Tensor) -> Dict[str, torch.Tensor]:
         output = F.dropout(output, p=0.25, training=True)
 
         output = output.view(inputs.shape[0], -1)
-        output = self.fc_layers[0](output)
-        output = F.relu(output)
-        output = F.dropout(output, p=0.5, training=True)
-        output = self.fc_layers[1](output)
+
+        for layer in self.fc_layers[:-1]:
+            output = layer(output)
+            output = F.relu(output)
+            output = F.dropout(output, p=0.5, training=True)
+
+        output = self.fc_layers[-1](output)
 
         return {self.prediction_publication_key: output}
 
diff --git a/example/cnn_ddp/run_config.yml b/example/cnn_ddp/run_config.yml
index 2c6ee53e..63560d6c 100644
--- a/example/cnn_ddp/run_config.yml
+++ b/example/cnn_ddp/run_config.yml
@@ -3,7 +3,7 @@ run_configuration:
   config:
     num_epochs: 10 # Number of epochs
     # num_batches_per_epoch: 100
-    gs_config_path: /scratch/max/mlgym/example/cnn_ddp/cnn_experiment_config.yml
+    gs_config_path: ./cnn_experiment_config.yml
 
 environment:
   type: accelerate # multiprocessing,  main_process, accelerate
diff --git a/example/cnn_ddp/train_cnn_accelerate.sh b/example/cnn_ddp/train_cnn_accelerate.sh
index 6f0ec452..3b523c86 100644
--- a/example/cnn_ddp/train_cnn_accelerate.sh
+++ b/example/cnn_ddp/train_cnn_accelerate.sh
@@ -2,4 +2,5 @@
 #!/bin/sh
 
 
-accelerate launch --multi_gpu --num_processes=8 --gpu_ids 0,1,2,3,4,5,6,7 run.py --config_path /scratch/max/mlgym/example/cnn_ddp/run_config.yml
+accelerate launch --multi_gpu --gpu_ids "0,1,3" --num_processes=3  \
+                /scratch/max/mlgym/example/cnn_ddp/run.py --config_path /scratch/max/mlgym/example/cnn_ddp/run_config.yml
diff --git a/example/cnn_zero_stage_3/ac_config.yaml b/example/cnn_zero_stage_3/ac_config.yaml
new file mode 100644
index 00000000..0b61e4c1
--- /dev/null
+++ b/example/cnn_zero_stage_3/ac_config.yaml
@@ -0,0 +1,18 @@
+compute_environment: LOCAL_MACHINE
+deepspeed_config:
+  deepspeed_config_file: /scratch/max/mlgym/example/cnn_zero_stage_3/ds_config.json
+  zero3_init_flag: true
+distributed_type: DEEPSPEED
+downcast_bf16: "no"
+dynamo_backend: "NO"
+fsdp_config: {}
+machine_rank: 0
+main_training_function: main
+megatron_lm_config: {}
+num_machines: 1
+num_processes: 2
+rdzv_backend: static
+same_network: true
+use_cpu: false
+gpu_ids: "0,1"
+
diff --git a/example/cnn_zero_stage_3/cnn_experiment_config.yml b/example/cnn_zero_stage_3/cnn_experiment_config.yml
new file mode 100644
index 00000000..2a77b6dd
--- /dev/null
+++ b/example/cnn_zero_stage_3/cnn_experiment_config.yml
@@ -0,0 +1,267 @@
+global_config:
+  storage_connector_path: &storage_path_anchor ./file_storage/
+  seed: &seed_value 2
+  target_key: &target_key_anchor target_key
+  model_prediction_key: &model_prediction_key_anchor model_prediction_key
+  postprocessing_argmax_key: &postprocessing_argmax_key_anchor postprocessing_argmax_key
+
+dataset_repository:
+  component_type_key: DATASET_REPOSITORY
+  variant_key: DEFAULT
+  config:
+    storage_connector_path: *storage_path_anchor
+
+dataset_iterators:
+  component_type_key: DATASET_ITERATORS
+  variant_key: DEFAULT
+  requirements:
+    - name: repository
+      component_name: dataset_repository
+  config:
+    dataset_identifier: mnist
+    split_configs:
+      - split: train
+      - split: test
+
+splitted_dataset_iterators:
+  component_type_key: SPLITTED_DATASET_ITERATORS
+  variant_key: RANDOM
+  requirements:
+    - name: iterators
+      component_name: dataset_iterators
+      subscription:
+        - train
+        - test
+  config:
+    split_configs:
+      train:
+        train: 0.7
+        val: 0.3
+    seed: 2
+
+data_collator:
+  component_type_key: DATA_COLLATOR
+  variant_key: DEFAULT
+  config:
+    collator_type:
+      injectable:
+        id: id_conv_mnist_standard_collator
+    collator_params:
+      target_publication_key: *target_key_anchor
+
+data_loaders:
+  component_type_key: DATA_LOADER
+  variant_key: DEFAULT
+  requirements:
+    - name: iterators
+      component_name: splitted_dataset_iterators
+      subscription: [train, val, test]
+    - name: data_collator
+      component_name: data_collator
+  config:
+    batch_size: 100
+    weigthed_sampling_split_name: train
+    seeds:
+      train: 0
+      val: 1
+      test: 2
+
+model_registry:
+  component_type_key: MODEL_REGISTRY
+  variant_key: DEFAULT
+
+model:
+  component_type_key: MODEL
+  variant_key: DEFAULT
+  requirements:
+    - name: model_registry
+      component_name: model_registry
+      subscription: conv_net
+  config:
+    model_definition:
+      layer_config:
+        - params:
+            in_channels: 1
+            kernel_size: 3
+            out_channels: 32
+            stride: 1
+          type: conv
+        - params:
+            in_channels: 32
+            kernel_size: 3
+            out_channels: 64
+            stride: 1
+          type: conv
+        - params:
+            in_features: 9216
+            out_features: 128
+          type: fc
+        - params:
+            in_features: 128
+            out_features: 30000
+          type: fc
+        # - params:
+        #     in_features: 30000
+        #     out_features: 30000
+        #   type: fc
+        # - params:
+        #     in_features: 30000
+        #     out_features: 30000
+        #   type: fc
+        # - params:
+        #     in_features: 30000
+        #     out_features: 30000
+        #   type: fc
+        - params:
+            in_features: 30000
+            out_features: 10
+          type: fc
+    prediction_publication_keys:
+      prediction_publication_key: *model_prediction_key_anchor
+    seed: *seed_value
+
+optimizer:
+  component_type_key: OPTIMIZER
+  variant_key: DEFAULT
+  config:
+    optimizer_key: ADAM
+    params:
+      lr: 
+        sweep: absolute
+        values: [0.001] # [1, 0.1, 0.01, 0.001, 0.0001]
+
+lr_scheduler:
+  component_type_key: LR_SCHEDULER
+  variant_key: DEFAULT
+  config:
+    lr_scheduler_key: dummy
+
+loss_function_registry:
+  component_type_key: LOSS_FUNCTION_REGISTRY
+  variant_key: DEFAULT
+
+metric_registry:
+  component_type_key: METRIC_REGISTRY
+  variant_key: DEFAULT
+
+prediction_postprocessing_registry:
+  component_type_key: PREDICTION_POSTPROCESSING_REGISTRY
+  variant_key: DEFAULT
+
+train_component:
+  component_type_key: TRAIN_COMPONENT
+  variant_key: ACCELERATE
+  requirements:
+    - name: loss_function_registry
+      component_name: loss_function_registry
+    - name: prediction_postprocessing_registry
+      component_name: prediction_postprocessing_registry
+  config:
+    loss_fun_config:
+      prediction_subscription_key: *model_prediction_key_anchor
+      target_subscription_key: *target_key_anchor
+      key: CrossEntropyLoss
+      tag: cross_entropy_loss
+
+trainer:
+  component_type_key: TRAINER
+  variant_key: ACCELERATE
+  requirements:
+    - name: train_component
+      component_name: train_component
+    - name: model
+      component_name: model
+      subscription: null
+    - name: data_loaders
+      component_name: data_loaders
+      subscription: train
+
+eval_component:
+  component_type_key: EVAL_COMPONENT
+  variant_key: ACCELERATE
+  requirements:
+    - name: model
+      component_name: model
+      subscription: null
+    - name: data_loaders
+      component_name: data_loaders
+      subscription: [train, val, test]
+    - name: loss_function_registry
+      component_name: loss_function_registry
+    - name: metric_registry
+      component_name: metric_registry
+    - name: prediction_postprocessing_registry
+      component_name: prediction_postprocessing_registry
+  config:
+    cpu_target_subscription_keys:
+      - *target_key_anchor
+    cpu_prediction_subscription_keys:
+      - *postprocessing_argmax_key_anchor
+      - *model_prediction_key_anchor
+    post_processors_config:
+      - key: "ARG_MAX"
+        prediction_subscription_key: *model_prediction_key_anchor
+        prediction_publication_key: *postprocessing_argmax_key_anchor
+    metrics_config:
+      - key: F1_SCORE
+        params:
+          average: macro
+        prediction_subscription_key: *postprocessing_argmax_key_anchor
+        target_subscription_key: *target_key_anchor
+        tag: F1_SCORE_macro
+      - key: PRECISION
+        params:
+          average: macro
+        prediction_subscription_key: *postprocessing_argmax_key_anchor
+        target_subscription_key: *target_key_anchor
+        tag: PRECISION_macro
+      - key: RECALL
+        params:
+          average: macro
+        prediction_subscription_key: *postprocessing_argmax_key_anchor
+        target_subscription_key: *target_key_anchor
+        tag: RECALL_macro
+    loss_funs_config:
+      - prediction_subscription_key: *model_prediction_key_anchor
+        target_subscription_key: *target_key_anchor
+        key: CrossEntropyLoss
+        tag: cross_entropy_loss
+
+evaluator:
+  component_type_key: EVALUATOR
+  variant_key: ACCELERATE
+  requirements:
+    - name: eval_component
+      component_name: eval_component
+
+early_stopping_strategy_registry:
+  component_type_key: EARLY_STOPPING_STRATEGY_REGISTRY
+  variant_key: DEFAULT
+
+early_stopping_strategy:
+  component_type_key: EARLY_STOPPING_STRATEGY
+  variant_key: DEFAULT
+  requirements:
+    - name: early_stopping_strategy_registry
+      component_name: early_stopping_strategy_registry
+  config:
+    early_stopping_key: LAST_K_EPOCHS_IMPROVEMENT_STRATEGY
+    early_stopping_config:
+      min_relative_improvement: 0.00001
+      epochs_window: 5
+      split_name: val
+      monitoring_key: "F1_SCORE_macro"
+      is_increase_task: true
+
+checkpointing_strategy_registry:
+  component_type_key: CHECKPOINTING_STRATEGY_REGISTRY
+  variant_key: DEFAULT
+
+checkpointing_strategy:
+  component_type_key: CHECKPOINTING_STRATEGY
+  variant_key: DEFAULT
+  requirements:
+    - name: checkpointing_strategy_registry
+      component_name: checkpointing_strategy_registry
+  config:
+    checkpointing_key: SAVE_LAST_EPOCH_ONLY_CHECKPOINTING_STRATEGY
diff --git a/example/cnn_zero_stage_3/conv_net.py b/example/cnn_zero_stage_3/conv_net.py
new file mode 100644
index 00000000..68e2319e
--- /dev/null
+++ b/example/cnn_zero_stage_3/conv_net.py
@@ -0,0 +1,55 @@
+from ml_gym.models.nn.net import NNModel
+from typing import Dict
+from torch import nn
+import torch
+import torch.nn.functional as F
+
+
+class ConvNet(NNModel):
+
+    def __init__(self, prediction_publication_key: str, layer_config: Dict, seed: int = 0):
+        super().__init__(seed=seed)
+        self.prediction_publication_key = prediction_publication_key
+        self.conv_layers = nn.ModuleList([])
+        self.fc_layers = nn.ModuleList([])
+        for layer in layer_config:
+            if layer["type"] == "conv":
+                self.conv_layers.append(ConvNet.create_conv_layer_from_config(layer["params"]))
+            elif layer["type"] == "fc":
+                self.fc_layers.append(ConvNet.create_fc_layer_from_config(layer["params"]))
+
+    @staticmethod
+    def create_conv_layer_from_config(layer_dict) -> nn.Module:
+        return nn.Conv2d(in_channels=layer_dict["in_channels"],
+                         out_channels=layer_dict["out_channels"],
+                         kernel_size=layer_dict["kernel_size"],
+                         stride=layer_dict["stride"])
+
+    @staticmethod
+    def create_fc_layer_from_config(layer_dict) -> nn.Module:
+        return nn.Linear(in_features=layer_dict["in_features"],
+                         out_features=layer_dict["out_features"])
+
+    def forward_impl(self, inputs: torch.Tensor) -> Dict[str, torch.Tensor]:
+        output = inputs
+        output = self.conv_layers[0](output)
+        output = F.relu(output)
+
+        output = self.conv_layers[1](output)
+        output = F.relu(output)
+        output = F.max_pool2d(output, 2, 2)
+        output = F.dropout(output, p=0.25, training=True)
+
+        output = output.view(inputs.shape[0], -1)
+
+        for layer in self.fc_layers[:-1]:
+            output = layer(output)
+            output = F.relu(output)
+            output = F.dropout(output, p=0.5, training=True)
+
+        output = self.fc_layers[-1](output)
+
+        return {self.prediction_publication_key: output}
+
+    def forward(self, inputs: torch.Tensor) -> Dict[str, torch.Tensor]:
+        return self.forward_impl(inputs)
diff --git a/example/cnn_zero_stage_3/conv_net_blueprint.py b/example/cnn_zero_stage_3/conv_net_blueprint.py
new file mode 100644
index 00000000..ee740104
--- /dev/null
+++ b/example/cnn_zero_stage_3/conv_net_blueprint.py
@@ -0,0 +1,71 @@
+from typing import Dict, List, Any
+from ml_gym.modes import RunMode
+import torch
+from ml_gym.blueprints.constructables import ModelRegistryConstructable
+from ml_gym.blueprints.blue_prints import BluePrint
+from ml_gym.batching.batch import DatasetBatch
+from dataclasses import dataclass
+from ml_gym.blueprints.component_factory import ComponentFactory, Injector
+from ml_gym.data_handling.postprocessors.collator import Collator
+from conv_net import ConvNet
+
+
+@dataclass
+class MNISTCollator(Collator):
+    target_publication_key: str = None
+
+    def __call__(self, batch: List[torch.Tensor]):
+        """
+        :param batch: batch format [no_samples, height, width, channels]
+        :return:
+        """
+        # batch contains a list of tuples of structure (sequence, target)
+        inputs = [item[0].to(self.device) for item in batch]
+        inputs = torch.stack(inputs)
+        # transform into vector
+        # inputs = inputs.view(inputs.shape[0], -1)
+        # transform into CHW matrix
+        # inputs = inputs.permute(0, 3, 1, 2)
+        inputs = inputs.reshape(-1, 1, 28, 28)
+        targets_tensor = torch.tensor([item[1] for item in batch]).to(inputs[0].device)
+        target_partitions = {self.target_publication_key: targets_tensor}
+        return DatasetBatch(targets=target_partitions, tags=None, samples=inputs)
+
+
+@dataclass
+class MyModelRegistryConstructable(ModelRegistryConstructable):
+    def _construct_impl(self):
+        super()._construct_impl()
+        self.model_registry.add_class("conv_net", ConvNet)
+        return self.model_registry
+
+
+class ConvNetBluePrint(BluePrint):
+    def __init__(self, run_mode: RunMode, config: Dict, grid_search_id: str,
+                 experiment_id: str, external_injection: Dict[str, Any] = None, warm_start_epoch: int = 0):
+        super().__init__(run_mode, config, grid_search_id, experiment_id, external_injection, warm_start_epoch)
+
+    @staticmethod
+    def construct_components(config: Dict, component_names: List[str], device: torch.device,
+                             external_injection: Dict[str, Any] = None) -> Dict[str, Any]:
+        if external_injection is not None:
+            injection_mapping = {"id_conv_mnist_standard_collator": MNISTCollator,
+                                 "id_computation_device": device,
+                                 **external_injection}
+            injector = Injector(injection_mapping, raise_mapping_not_found=True)
+
+        else:
+            injection_mapping = {"id_conv_mnist_standard_collator": MNISTCollator}
+            injector = Injector(injection_mapping, raise_mapping_not_found=False)
+
+        component_factory = ComponentFactory(injector)
+        component_factory.register_component_type("MODEL_REGISTRY", "DEFAULT", MyModelRegistryConstructable)
+
+        components = component_factory.build_components_from_config(config, component_names)
+        return components
+
+    def construct(self, device: torch.device = None) -> Dict[str, Any]:
+        component_names = ["model", "trainer", "optimizer", "lr_scheduler", "evaluator", "early_stopping_strategy", "checkpointing_strategy"]
+        components = ConvNetBluePrint.construct_components(self.config, component_names, device, self.external_injection)
+
+        return components
diff --git a/example/cnn_zero_stage_3/ds_config.json b/example/cnn_zero_stage_3/ds_config.json
new file mode 100644
index 00000000..c502a389
--- /dev/null
+++ b/example/cnn_zero_stage_3/ds_config.json
@@ -0,0 +1,20 @@
+{
+    "bf16": {
+        "enabled": false 
+    },
+    "zero_optimization": {
+        "stage": 3,
+        "stage3_gather_16bit_weights_on_model_save": false,
+        "offload_optimizer": {
+            "device": "none"
+        },
+        "offload_param": {
+            "device": "none"
+        }
+    },
+    "gradient_clipping": 1.0,
+    "train_batch_size": "auto",
+    "train_micro_batch_size_per_gpu": "auto",
+    "gradient_accumulation_steps": 1,
+    "steps_per_print": 2000000
+}
\ No newline at end of file
diff --git a/example/cnn_zero_stage_3/run.py b/example/cnn_zero_stage_3/run.py
new file mode 100644
index 00000000..9cdd525b
--- /dev/null
+++ b/example/cnn_zero_stage_3/run.py
@@ -0,0 +1,8 @@
+
+from conv_net_blueprint import ConvNetBluePrint
+from ml_gym.cmd_entrypoint.cmd import get_args, run
+
+if __name__ == '__main__':
+    blueprint_class = ConvNetBluePrint
+    config_path = get_args()
+    run(blueprint_class=blueprint_class, run_configuration_file_path=config_path)
diff --git a/example/cnn_zero_stage_3/run_config.yml b/example/cnn_zero_stage_3/run_config.yml
new file mode 100644
index 00000000..974cce66
--- /dev/null
+++ b/example/cnn_zero_stage_3/run_config.yml
@@ -0,0 +1,14 @@
+run_configuration:
+  type: train # train, warmstart
+  config:
+    num_epochs: 10 # Number of epochs
+    # num_batches_per_epoch: 100
+    gs_config_path: /scratch/max/mlgym/example/cnn_zero_stage_3/cnn_experiment_config.yml
+
+environment:
+  type: accelerate # multiprocessing,  main_process, accelerate
+
+logging:
+  websocket_logging_servers: # List of websocket logging servers, e.g., http://127.0.0.1:9090 http://127.0.0.1:8080
+    - http://127.0.0.1:5002
+  gs_rest_api_endpoint: http://127.0.0.1:5001 # Endpoint for the grid search API, e.g., http://127.0.0.1:8080
diff --git a/example/cnn_zero_stage_3/train_cnn_accelerate.sh b/example/cnn_zero_stage_3/train_cnn_accelerate.sh
new file mode 100644
index 00000000..947b743f
--- /dev/null
+++ b/example/cnn_zero_stage_3/train_cnn_accelerate.sh
@@ -0,0 +1,6 @@
+ 
+#!/bin/sh
+
+
+accelerate launch --config_file /scratch/max/mlgym/example/cnn_zero_stage_3/ac_config.yaml \
+                /scratch/max/mlgym/example/cnn_zero_stage_3/run.py --config_path /scratch/max/mlgym/example/cnn_zero_stage_3/run_config.yml
diff --git a/example/grid_search_example/conv_net.py b/example/grid_search_example/conv_net.py
index 189b176f..68e2319e 100644
--- a/example/grid_search_example/conv_net.py
+++ b/example/grid_search_example/conv_net.py
@@ -41,10 +41,13 @@ def forward_impl(self, inputs: torch.Tensor) -> Dict[str, torch.Tensor]:
         output = F.dropout(output, p=0.25, training=True)
 
         output = output.view(inputs.shape[0], -1)
-        output = self.fc_layers[0](output)
-        output = F.relu(output)
-        output = F.dropout(output, p=0.5, training=True)
-        output = self.fc_layers[1](output)
+
+        for layer in self.fc_layers[:-1]:
+            output = layer(output)
+            output = F.relu(output)
+            output = F.dropout(output, p=0.5, training=True)
+
+        output = self.fc_layers[-1](output)
 
         return {self.prediction_publication_key: output}
 
diff --git a/example/grid_search_example/run_config.yml b/example/grid_search_example/run_config.yml
index 22c1fd62..d7c9fc2b 100644
--- a/example/grid_search_example/run_config.yml
+++ b/example/grid_search_example/run_config.yml
@@ -1,17 +1,17 @@
 run_configuration:
   type: train # train, warmstart
   config:
-    num_epochs: 10 # Number of epochs
-    gs_config_path: /scratch/max/mlgym/example/grid_search_example/gs_config.yml
+    num_epochs: 50 # Number of epochs
+    num_batches_per_epoch: 100
+    gs_config_path: ./gs_config.yml
 
 environment:
   type: multiprocessing # multiprocessing,  main_process, accelerate
   config:
-    process_count: 1 # Max. number of processes running at a time.
-    computation_device_ids: [4] # Indices of GPUs to distribute the GS over
+    process_count: 3 # Max. number of processes running at a time.
+    computation_device_ids: [0, 1, 5] # Indices of GPUs to distribute the GS over
 
 logging:
   websocket_logging_servers: # List of websocket logging servers, e.g., http://127.0.0.1:9090 http://127.0.0.1:8080
     - http://127.0.0.1:5002
-  gs_rest_api_endpoint: http://127.0.0.1:5001 # Endpoint for the grid search API, e.g., http://127.0.0.1:8080
-
+  gs_rest_api_endpoint: http://127.0.0.1:5001 # Endpoint for the grid search API, e.g., http://127.0.0.1:8080
\ No newline at end of file
diff --git a/example/grid_search_example/train_gs_mnist_conv_net_websocket.sh b/example/grid_search_example/train_gs_mnist_conv_net_websocket.sh
index 008d1ba9..faf35e71 100644
--- a/example/grid_search_example/train_gs_mnist_conv_net_websocket.sh
+++ b/example/grid_search_example/train_gs_mnist_conv_net_websocket.sh
@@ -2,9 +2,4 @@
 #!/bin/sh
 
 
-python run.py --process_count 21 \
-              --num_epochs 100 \
-              --websocket_logging_servers http://127.0.0.1:5002 \
-              --gs_rest_api_endpoint http://127.0.0.1:5001 \
-              train \
-              --gs_config_path gs_config.yml
+python run.py --config_path run_config.yml
diff --git a/src/ml_board/README.md b/src/ml_board/README.md
index 20087454..1b926acd 100644
--- a/src/ml_board/README.md
+++ b/src/ml_board/README.md
@@ -70,12 +70,40 @@ payload:
 }
 ```
 
+**Model Card**
+
+Fetch System details like CPU & GPU for model card.
+
+_GET /system-info/<grid_search_id>/<experiment_id>_
+
+```json
+{
+    "platform": <Operating system>,
+    "platform-release": <OS version>,
+    "architecture": <system architecture ex: AMD64>,
+    "processor": <processor name>,
+    "ram": <ram in GB>,
+    "python-version": <version>,
+    "python-packages": <List of pip packages>,
+    "CUDNN_version":<cudnn version>,
+    "num_cuda_device": <number of cuda devices>,
+    "cuda_device_list": [
+        {
+            "name": <name of GPU>,
+            "multi_proc_count": <Processor count of GPU>,
+            "total_memory": <Total GPU memory in GB>
+        }
+    ]
+}
+```
+
 **Experiments**
 
 _GET /grid_searches/<grid_search_id>/experiments_
 
 TODO need to check "experiments" in URL
 
+TODO need to check "experiments" in URL  
 ```json
 [
     {
@@ -95,15 +123,15 @@ Available <checkpoint_resource> = [model, optimizer, stateful_component, lr_sche
 
 Get all Checkpoint names for single experiment:
 
-_GET /checkpoints/<grid_search_id>/<experiment_id>_
+_GET /checkpoint_list/<grid_search_id>/<experiment_id>_
 
-_Ex: GET /checkpoints/2023-04-12--23-42-17/0_
+_Ex: GET /checkpoint_list/2023-04-12--23-42-17/0_
 
 Get all Checkpoint names for single epoch in an experiment:
 
-_GET /checkpoints/<grid_search_id>/<experiment_id>/<checkpoint_id>_
+_GET /checkpoint_list/<grid_search_id>/<experiment_id>/<checkpoint_id>_
 
-_Ex: GET /checkpoints/2023-04-12--23-42-17/0/0_
+_Ex: GET /checkpoint_list/2023-04-12--23-42-17/0/0_
 
 Return:
 ```json
@@ -157,6 +185,17 @@ _DELETE /checkpoints/<grid_search_id><experiment_id>/<checkpoint_id>/<checkpoint
 
 _Ex: DELETE /checkpoints/2023-04-12--23-42-17/0/0/model_
 
+*PUT /checkpoints/<grid_search_id><experiment_id>/<checkpoint_id>/<model, optimizer, lr_scheduler, stateful_component>*
+```json
+{
+        "<model, optimizer, lr_scheduler, stateful_component>": <binary stream>,
+        "chunk_id": <chunk_id>,
+        "num_chunks": <num_chunks>
+```
+
+*DELETE /checkpoints/<grid_search_id><experiment_id>/<checkpoint_id>*
+
+
 ## Websocket API
 
 Every event message has the following structure:
@@ -284,6 +323,12 @@ metric scores of a model at a specific epoch.
 
 # Implementation idea:
 
+**Checkpointing (legacy)**:
+
+After each epoch and if condition is fulfilled (based on strategy), the model is binarized and sent to the server as a checkpoint.
+
+Create checkpoint:
+
 Add subscribers to trainer, evaluator and gymjob. We need to inject them via
 For trainer and evaluator we add the subscribers within the blueprints. E.g., trainer.add_subscriber(subscriber)
 
diff --git a/src/ml_board/backend/dummy_server/dummy_server.py b/src/ml_board/backend/dummy_server/dummy_server.py
index ffc95b52..7d11c802 100644
--- a/src/ml_board/backend/dummy_server/dummy_server.py
+++ b/src/ml_board/backend/dummy_server/dummy_server.py
@@ -151,7 +151,7 @@ def terminate(text:str) -> None:
         # run the Server
         WebSocketWrapper(
             flask_app=create_flask_server(),
-            host="localhost",
+            host="127.0.0.1",
             port=args.get('port', 7000),
             async_mode=None,
             message_delay=float(args.get('delay', 0.1)),  # in seconds
diff --git a/src/ml_board/backend/restful_api/data_access.py b/src/ml_board/backend/restful_api/data_access.py
index 9c45efc4..bf0cabcb 100644
--- a/src/ml_board/backend/restful_api/data_access.py
+++ b/src/ml_board/backend/restful_api/data_access.py
@@ -4,6 +4,7 @@
 import re
 import shutil
 from typing import Dict, List
+from fastapi import UploadFile
 from ml_gym.error_handling.exception import InvalidPathError
 import json
 from ml_board.backend.restful_api.data_models import RawTextFile, CheckpointResource, ExperimentStatus
@@ -13,7 +14,6 @@
 class DataAccessIF(ABC):
     """
     DataAccessIF class
-
     Declare Abstract methods to be used in FileDataAccess Class.
     """
 
@@ -42,21 +42,17 @@ def get_checkpoint_list(self, grid_search_id: str, experiment_id: str) -> List[D
         raise NotImplementedError
 
     @abstractmethod
-    def get_checkpoint_resource(
-        self, grid_search_id: str, experiment_id: str, epoch: str, checkpoint_resource: CheckpointResource
-    ) -> Generator:
+    def get_checkpoint_resource(self, grid_search_id: str, experiment_id: str, epoch: str,
+                                checkpoint_resource: str) -> Generator:
         raise NotImplementedError
 
     @abstractmethod
-    def add_checkpoint_resource(
-        self, grid_search_id: str, experiment_id: str, epoch: str, checkpoint_resource: CheckpointResource, payload_pickle: bytes
-    ) -> None:
+    def add_checkpoint_resource(self, grid_search_id: str, experiment_id: str, epoch: str, checkpoint_file: UploadFile) -> None:
         raise NotImplementedError
 
     @abstractmethod
     def delete_checkpoint_resource(
-        self, grid_search_id: str, experiment_id: str, epoch: str, checkpoint_resource: CheckpointResource
-    ) -> None:
+        self, grid_search_id: str, experiment_id: str, epoch: str, checkpoint_resource: str) -> None:
         raise NotImplementedError
 
     @abstractmethod
@@ -67,12 +63,11 @@ def delete_checkpoints(self, grid_search_id: str, experiment_id: str, epoch: str
     def get_checkpoint_dict_epoch(self, grid_search_id: str, experiment_id: str, epoch: str) -> List[Dict]:
         raise NotImplementedError
 
-
 class FileDataAccess(DataAccessIF):
     """
     FileDataAccess Class
-
-    :params: DataAccessIF object
+    :params: 
+        DataAccessIF object
 
     The rest server uses this class to use methods to access event storage files.
     Used to add new files, delete current files and fetch current files.
@@ -104,10 +99,8 @@ def iterfile(file_path: str):
     def get_experiment_statuses(self, grid_search_id: str) -> List[ExperimentStatus]:
         """
         Fetch experiment status for a Grid Search ID.
-
         :params:
              grid_search_id (str): Grid Search ID
-
         :returns: List - experiment_statuses
         """
 
@@ -163,12 +156,11 @@ def load_experiment_config(top_level_logging_path: str, grid_search_id: str, exp
     def add_raw_config_to_grid_search(self, grid_search_id: str, config_name: str, config_file: RawTextFile) -> None:
         """
         Add Config for a Grid Search ID to event storage
-
+        
         :params:
-             grid_search_id (str): Grid Search ID
-             config_name (str): Name of Configuration file
-             config_file (RawTextFile) : RawTextFile Object
-
+            - grid_search_id (str): Grid Search ID
+            - config_name (str): Name of Configuration file
+            - config_file (RawTextFile) : RawTextFile Object
         """
         requested_full_path = os.path.realpath(os.path.join(self.top_level_logging_path, str(grid_search_id), config_name))
 
@@ -184,11 +176,10 @@ def add_config_to_experiment(self, grid_search_id: str, experiment_id: str, conf
         Add experiment config given the experiment ID & grid search ID to event storage.
 
         :params:
-             grid_search_id (str): Grid Search ID
-             experiment_id (str): Experiment ID
-             config_name (str): Name of Configuration file
-             config (RawTextFile) : RawTextFile Object
-
+            - grid_search_id (str): Grid Search ID
+            - experiment_id (str): Experiment ID
+            - config_name (str): Name of Configuration file
+            - config (RawTextFile) : RawTextFile Object
         """
         requested_full_path = os.path.realpath(
             os.path.join(self.top_level_logging_path, str(grid_search_id), str(experiment_id), config_name)
@@ -207,8 +198,8 @@ def get_grid_config(self, grid_search_id: str, config_name: str) -> Generator:
         Fetch grid config for a Grid Search ID from the event storage.
 
         :params:
-             grid_search_id (str): Grid Search ID
-             config_name (str): Name of Configuration file
+            - grid_search_id (str): Grid Search ID
+            - config_name (str): Name of Configuration file
 
         :returns: bytes response of YML file
         """
@@ -224,12 +215,12 @@ def get_grid_config(self, grid_search_id: str, config_name: str) -> Generator:
 
     def get_experiment_config(self, grid_search_id: str, experiment_id: str, config_name: str) -> Generator:
         """
-        `Fetch experiment config given the experiment ID & grid search ID from event storage.
+        Fetch experiment config given the experiment ID & grid search ID from event storage.
 
         :params:
-             grid_search_id (str): Grid Search ID
-             experiment_id (str): Experiment ID
-             config_name (str): Name of Configuration file
+            - grid_search_id (str): Grid Search ID
+            - experiment_id (str): Experiment ID
+            - config_name (str): Name of Configuration file
 
         :returns: bytes response of JSON file
         """
@@ -251,9 +242,9 @@ def get_checkpoint_dict_epoch(self, grid_search_id: str, experiment_id: str, epo
         given the epoch, experiment ID & grid search ID.
 
         :params:
-             grid_search_id (str): Grid Search ID
-             experiment_id (str): Experiment ID
-             epoch (str): Epoch number
+            - grid_search_id (str): Grid Search ID
+            - experiment_id (str): Experiment ID
+            - epoch (str): Epoch number
 
         :returns: List of Checkpoint file names in an epoch
         """
@@ -267,7 +258,7 @@ def get_checkpoint_dict_epoch(self, grid_search_id: str, experiment_id: str, epo
             files = FileDataAccess.get_checkpoint_files(requested_full_path, base_path=self.top_level_logging_path)
             for file_num in range(len(files)):
                 split = os.path.normpath(files[file_num]).split(os.sep)
-                checkpoints.append(os.path.basename(split[-1]).split(".")[0])
+                checkpoints.append(os.path.basename(split[-1]))
             response.append({"experiment_id": experiment_id, "epoch": epoch, "checkpoints": checkpoints})
             return response
 
@@ -276,11 +267,11 @@ def get_checkpoint_dict_epoch(self, grid_search_id: str, experiment_id: str, epo
 
     def get_checkpoint_list(self, grid_search_id: str, experiment_id) -> List[Dict]:
         """
-        `Fetch all checkpoint resource pickle file names given the experiment ID & grid search ID from event storage.
+        Fetch all checkpoint resource pickle file names given the experiment ID & grid search ID from event storage.
 
         :params:
-             grid_search_id (str): Grid Search ID
-             experiment_id (str): Experiment ID
+            - grid_search_id (str): Grid Search ID
+            - experiment_id (str): Experiment ID
 
         :returns: List of Checkpoint file names in an experiment
         """
@@ -298,9 +289,9 @@ def get_checkpoint_list(self, grid_search_id: str, experiment_id) -> List[Dict]:
                     response.append({"experiment_id": experiment_id, "epoch": last_epoch, "checkpoints": checkpoints})
                     last_epoch = epoch
                     checkpoints = []
-                    checkpoints.append(os.path.basename(split[-1]).split(".")[0])
+                    checkpoints.append(os.path.basename(split[-1]))
                 else:
-                    checkpoints.append(os.path.basename(split[-1]).split(".")[0])
+                    checkpoints.append(os.path.basename(split[-1]))
 
             response.append({"experiment_id": experiment_id, "epoch": epoch, "checkpoints": checkpoints})
             return response
@@ -309,22 +300,21 @@ def get_checkpoint_list(self, grid_search_id: str, experiment_id) -> List[Dict]:
             raise InvalidPathError(f"File path {requested_full_path} is not safe.")
 
     def get_checkpoint_resource(
-        self, grid_search_id: str, experiment_id: str, epoch: str, checkpoint_resource: CheckpointResource
+        self, grid_search_id: str, experiment_id: str, epoch: str, checkpoint_resource: str
     ) -> Generator:
         """
-        `Fetch checkpoint resource pickle file given the experiment ID & grid search ID from event storage.
+        Fetch checkpoint resource pickle file given the experiment ID & grid search ID from event storage.
 
         :params:
-             grid_search_id (str): Grid Search ID
-             experiment_id (str): Experiment ID
-             epoch (str): Epoch number
-             checkpoint_resource (CheckpointResource) : CheckpointResource type
+            - grid_search_id (str): Grid Search ID
+            - experiment_id (str): Experiment ID
+            - epoch (str): Epoch number
+            - checkpoint_resource (CheckpointResource) : CheckpointResource type
 
         :returns: bytes response of pickle file
         """
-        requested_full_path = os.path.realpath(
-            os.path.join(self.top_level_logging_path, str(grid_search_id), str(experiment_id), str(epoch), f"{checkpoint_resource}.pickle")
-        )
+        requested_full_path = os.path.realpath(os.path.join(self.top_level_logging_path, str(grid_search_id), str(experiment_id),
+                                                            str(epoch), checkpoint_resource))
         if FileDataAccess.is_safe_path(base_dir=self.top_level_logging_path, requested_path=requested_full_path):
             if not os.path.isfile(requested_full_path):
                 raise InvalidPathError(f"Resource {requested_full_path} not found.")
@@ -334,30 +324,27 @@ def get_checkpoint_resource(
         else:
             raise InvalidPathError(f"File path {requested_full_path} is not safe.")
 
-    def add_checkpoint_resource(
-        self, grid_search_id: str, experiment_id: str, epoch: str, checkpoint_resource: CheckpointResource, payload_pickle: bytes
-    ) -> None:
+    def add_checkpoint_resource(self, grid_search_id: str, experiment_id: str, epoch: str, checkpoint_file: UploadFile) -> None:
         """
         Add a checkpoint resource pickle file given the epoch, experiment ID & grid search ID to event storage.
 
         :params:
-             grid_search_id (str): Grid Search ID
-             experiment_id (str): Experiment ID
-             epoch (str): Epoch number
-             checkpoint_resource (CheckpointResource) : CheckpointResource type
-             payload_pickle (bytes): Pickle file to be added
+            - grid_search_id (str): Grid Search ID
+            - experiment_id (str): Experiment ID
+            - epoch (str): Epoch number
+            - checkpoint_resource (CheckpointResource) : CheckpointResource type
+            - payload_pickle (bytes): Pickle file to be added
 
         :returns: Pickle file Stream response
         """
-
-        requested_full_path = os.path.realpath(
-            os.path.join(self.top_level_logging_path, str(grid_search_id), str(experiment_id), str(epoch), f"{checkpoint_resource}.pickle")
-        )
+        file_name = checkpoint_file.filename
+        file_path = os.path.join(self.top_level_logging_path, str(grid_search_id), str(experiment_id), str(epoch), file_name)
+        requested_full_path = os.path.realpath(file_path)
 
         if FileDataAccess.is_safe_path(base_dir=self.top_level_logging_path, requested_path=requested_full_path):
             os.makedirs(os.path.dirname(requested_full_path), exist_ok=True)
             with open(requested_full_path, "wb") as fd:
-                fd.write(payload_pickle)
+                shutil.copyfileobj(checkpoint_file.file, fd)
         else:
             raise InvalidPathError(f"File path {requested_full_path} is not safe.")
 
@@ -365,44 +352,39 @@ def delete_checkpoints(self, grid_search_id: str, experiment_id: str, epoch: str
         """
         Delete checkpoint FOLDER From the event storage
         given the epoch, experiment ID & grid search ID.
-
         :params:
-             grid_search_id (str): Grid Search ID
-             experiment_id (str): Experiment ID
-             epoch (str): Epoch number
+            - grid_search_id (str): Grid Search ID
+            - experiment_id (str): Experiment ID
+            - epoch (str): Epoch number
         """
 
-        requested_full_path = os.path.realpath(
-            os.path.join(self.top_level_logging_path, str(grid_search_id), str(experiment_id), str(epoch))
-        )
+        requested_full_path = os.path.realpath(os.path.join(self.top_level_logging_path, str(grid_search_id),
+                                                            str(experiment_id), str(epoch)))
 
         if FileDataAccess.is_safe_path(base_dir=self.top_level_logging_path, requested_path=requested_full_path):
             shutil.rmtree(requested_full_path)
         else:
-            raise FileNotFoundError(f"Folder in path {requested_full_path} not found.")
+            raise InvalidPathError(f"The path {requested_full_path} is not safe.")
 
-    def delete_checkpoint_resource(
-        self, grid_search_id: str, experiment_id: str, epoch: str, checkpoint_resource: CheckpointResource
-    ) -> None:
+    def delete_checkpoint_resource(self, grid_search_id: str, experiment_id: str, epoch: str,
+                                   checkpoint_resource: str) -> None:
         """
         Delete checkpoint resource pickle file from the event storage
         given the epoch, experiment ID & grid search ID.
-
         :params:
-             grid_search_id (str): Grid Search ID
-             experiment_id (str): Experiment ID
-             epoch (str): Epoch number
-             checkpoint_resource (CheckpointResource) : CheckpointResource type
+            - grid_search_id (str): Grid Search ID
+            - experiment_id (str): Experiment ID
+            - epoch (str): Epoch number
+            - checkpoint_resource (CheckpointResource) : CheckpointResource type
         """
 
         folder_path = os.path.realpath(os.path.join(self.top_level_logging_path, str(grid_search_id), str(experiment_id), str(epoch)))
-        requested_full_path = os.path.realpath(
-            os.path.join(self.top_level_logging_path, str(grid_search_id), str(experiment_id), str(epoch), f"{checkpoint_resource}.pickle")
-        )
+        requested_full_path = os.path.realpath(os.path.join(self.top_level_logging_path, str(grid_search_id), str(experiment_id),
+                                                            str(epoch), checkpoint_resource))
 
         if FileDataAccess.is_safe_path(base_dir=self.top_level_logging_path, requested_path=requested_full_path):
             os.remove(requested_full_path)
             if len([name for name in os.listdir(folder_path) if os.path.isfile(os.path.join(folder_path, name))]) == 0:
                 os.rmdir(folder_path)
         else:
-            raise FileNotFoundError(f"File in path {requested_full_path} not found.")
+            raise InvalidPathError(f"Path {requested_full_path} is not safe.")
diff --git a/src/ml_board/backend/restful_api/data_models.py b/src/ml_board/backend/restful_api/data_models.py
index 238f63dc..32410129 100644
--- a/src/ml_board/backend/restful_api/data_models.py
+++ b/src/ml_board/backend/restful_api/data_models.py
@@ -19,8 +19,10 @@ class ExperimentStatus(BaseModel):
     experiment_config: Dict
 
 
+# TODO Check if Enum is still needed
 class CheckpointResource(str, Enum):
     model = "model"
     optimizer = "optimizer"
     lr_scheduler = "lr_scheduler"
     stateful_components = "stateful_components"
+    accelerate = "accelerate_zip"
diff --git a/src/ml_board/backend/restful_api/restful_api_server.py b/src/ml_board/backend/restful_api/restful_api_server.py
index b9900242..30b878c9 100644
--- a/src/ml_board/backend/restful_api/restful_api_server.py
+++ b/src/ml_board/backend/restful_api/restful_api_server.py
@@ -1,11 +1,11 @@
-import base64
-from fastapi import FastAPI, File
+from fastapi import FastAPI, UploadFile
 from fastapi import status, HTTPException
 from fastapi.responses import StreamingResponse
 from ml_board.backend.restful_api.data_access import DataAccessIF
-from ml_gym.error_handling.exception import InvalidPathError
-from ml_board.backend.restful_api.data_models import RawTextFile, CheckpointResource
+from ml_gym.error_handling.exception import InvalidPathError, SystemInfoFetchError
+from ml_board.backend.restful_api.data_models import FileFormat, RawTextFile, CheckpointResource
 from typing import Callable
+from fastapi.middleware.cors import CORSMiddleware
 
 # from fastapi.staticfiles import StaticFiles
 
@@ -13,12 +13,19 @@
 class RestfulAPIServer:
     """
     RestAPI Server class
-
     Creates FastAPI Server Object with HTTP RestAPIs for grid search and checkpoint communication.
     """
 
     def __init__(self, data_access: DataAccessIF):
         self.app = FastAPI(port=8080)
+        origins = ["*"]
+        self.app.add_middleware(
+        CORSMiddleware,
+        allow_origins=origins,
+        allow_credentials=True,
+        allow_methods=["*"],
+        allow_headers=["*"],
+        )
         self.data_access = data_access
         self.app.add_api_route(path="/grid_searches/{grid_search_id}/experiments", methods=["GET"], endpoint=self.get_experiment_statuses)
         self.app.add_api_route(
@@ -45,7 +52,7 @@ def __init__(self, data_access: DataAccessIF):
             endpoint=self.get_checkpoint_resource,
         )
         self.app.add_api_route(
-            path="/checkpoints/{grid_search_id}/{experiment_id}/{epoch}/{checkpoint_resource}",
+            path="/checkpoints/{grid_search_id}/{experiment_id}/{epoch}",
             methods=["POST"],
             endpoint=self.add_checkpoint_resource,
         )
@@ -59,16 +66,19 @@ def __init__(self, data_access: DataAccessIF):
             methods=["DELETE"],
             endpoint=self.delete_checkpoint_resource,
         )
+        self.app.add_api_route(
+            path="/system-info/{grid_search_id}/{experiment_id}",
+            methods=["GET"],
+            endpoint=self.get_system_info,
+        )
 
         # self.app.mount("/", StaticFiles(directory="/home/mluebberin/repositories/github/private_workspace/mlgym/src/ml_board/frontend/dashboard/build/", html=True), name="static")
 
     def get_experiment_statuses(self, grid_search_id: str):
         """
         ``HTTP GET`` Experiment Status for a Grid Search ID.
-
         :params:
              grid_search_id (str): Grid Search ID
-
         :returns: JSON object - experiment_statuses
         """
         try:
@@ -81,11 +91,10 @@ def get_experiment_config(self, grid_search_id: str, experiment_id: str, config_
         """
         ``HTTP GET`` Fetch specific experiment config
           given the experiment ID & grid search ID.
-
         :params:
-             grid_search_id (str): Grid Search ID
-             experiment_id (str): Experiment ID
-             config_name (str): Name of Configuration file
+            - grid_search_id (str): Grid Search ID
+            - experiment_id (str): Experiment ID
+            - config_name (str): Name of Configuration file
 
         :returns: JSON stream response
         """
@@ -101,10 +110,9 @@ def get_experiment_config(self, grid_search_id: str, experiment_id: str, config_
     def get_grid_config(self, grid_search_id: str, config_name: str):
         """
         ``HTTP GET`` Fetch grid config for a Grid Search ID.
-
         :params:
-             grid_search_id (str): Grid Search ID
-             config_name (str): Name of Configuration file
+            - grid_search_id (str): Grid Search ID
+            - config_name (str): Name of Configuration file
 
         :returns: YML stream response
         """
@@ -129,12 +137,10 @@ def get_grid_config(self, grid_search_id: str, config_name: str):
     def add_raw_config_to_grid_search(self, grid_search_id: str, config_name: str, config_file: RawTextFile):
         """
         ``HTTP PUT`` Add Config for a Grid Search ID
-
         :params:
-             grid_search_id (str): Grid Search ID
-             config_name (str): Name of Configuration file
-             config_file (RawTextFile) : RawTextFile Object
-
+            - grid_search_id (str): Grid Search ID
+            - config_name (str): Name of Configuration file
+            - config_file (RawTextFile) : RawTextFile Object
         """
         try:
             self.data_access.add_raw_config_to_grid_search(grid_search_id=grid_search_id, config_name=config_name, config_file=config_file)
@@ -148,13 +154,11 @@ def add_config_to_experiment(self, grid_search_id: str, experiment_id: str, conf
         """
         ``HTTP PUT`` Add specific experiment config
           given the experiment ID & grid search ID.
-
         :params:
-             grid_search_id (str): Grid Search ID
-             experiment_id (str): Experiment ID
-             config_name (str): Name of Configuration file
-             config (RawTextFile) : RawTextFile Object
-
+            - grid_search_id (str): Grid Search ID
+            - experiment_id (str): Experiment ID
+            - config_name (str): Name of Configuration file
+            - config (RawTextFile) : RawTextFile Object
         """
         try:
             self.data_access.add_config_to_experiment(
@@ -170,11 +174,10 @@ def get_checkpoint_dict_epoch(self, grid_search_id: str, experiment_id: str, epo
         """
         ``HTTP GET`` Fetch all checkpoint resource pickle files
           given the epoch, experiment ID & grid search ID.
-
         :params:
-             grid_search_id (str): Grid Search ID
-             experiment_id (str): Experiment ID
-             epoch (str): Epoch number
+            - grid_search_id (str): Grid Search ID
+            - experiment_id (str): Experiment ID
+            - epoch (str): Epoch number
 
         :returns: List of Checkpoints
         """
@@ -193,10 +196,9 @@ def get_checkpoint_list(self, grid_search_id: str, experiment_id: str):
         """
         ``HTTP GET`` Fetch all checkpoint resource pickle files
           given the epoch, experiment ID & grid search ID.
-
         :params:
-             grid_search_id (str): Grid Search ID
-             experiment_id (str): Experiment ID
+            - grid_search_id (str): Grid Search ID
+            - experiment_id (str): Experiment ID
 
         :returns: List of checkpoints
         """
@@ -208,16 +210,15 @@ def get_checkpoint_list(self, grid_search_id: str, experiment_id: str):
                 status_code=status.HTTP_403_FORBIDDEN, detail="Provided invalid parameters for fetching checkpoint list."
             ) from e
 
-    def get_checkpoint_resource(self, grid_search_id: str, experiment_id: str, epoch: str, checkpoint_resource: CheckpointResource):
+    def get_checkpoint_resource(self, grid_search_id: str, experiment_id: str, epoch: str, checkpoint_resource: str):
         """
         ``HTTP GET`` Fetch checkpoint resource pickle file
           given the experiment ID & grid search ID.
-
         :params:
-             grid_search_id (str): Grid Search ID
-             experiment_id (str): Experiment ID
-             epoch (str): Epoch number
-             checkpoint_resource (CheckpointResource) : CheckpointResource type
+            - grid_search_id (str): Grid Search ID
+            - experiment_id (str): Experiment ID
+            - epoch (str): Epoch number
+            - checkpoint_resource (CheckpointResource) : CheckpointResource type
 
         :returns: Pickle file Stream response
         """
@@ -230,71 +231,83 @@ def get_checkpoint_resource(self, grid_search_id: str, experiment_id: str, epoch
         except InvalidPathError as e:
             raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Provided invalid parameters for checkpoint resource.") from e
 
-    def delete_checkpoint_resource(self, grid_search_id: str, experiment_id: str, epoch: str, checkpoint_resource: CheckpointResource):
+    def delete_checkpoint_resource(self, grid_search_id: str, experiment_id: str, epoch: str, checkpoint_resource: str):
         """
         ``HTTP DELETE`` Delete checkpoint resource pickle file
           given the epoch, experiment ID & grid search ID.
-
         :params:
-             grid_search_id (str): Grid Search ID
-             experiment_id (str): Experiment ID
-             epoch (str): Epoch number
-             checkpoint_resource (CheckpointResource) : CheckpointResource type
+            - grid_search_id (str): Grid Search ID
+            - experiment_id (str): Experiment ID
+            - epoch (str): Epoch number
+            - checkpoint_resource (CheckpointResource) : CheckpointResource type
         """
         try:
-            self.data_access.delete_checkpoint_resource(
-                grid_search_id=grid_search_id, experiment_id=experiment_id, epoch=epoch, checkpoint_resource=checkpoint_resource
-            )
-
+            self.data_access.delete_checkpoint_resource(grid_search_id=grid_search_id, experiment_id=experiment_id,
+                                                        epoch=epoch, checkpoint_resource=checkpoint_resource)
+        except FileNotFoundError as e:
+            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
+                                detail=f"Checkpoint resource {grid_search_id}/{experiment_id}/{epoch}/{checkpoint_resource} not found.") from e
         except InvalidPathError as e:
-            raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Provided invalid parameters for checkpoint resource.") from e
+            raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,
+                                detail=f"Provided invalid parameters for checkpoint resource {grid_search_id}/{experiment_id}/{epoch}/{checkpoint_resource}.") from e
 
     def delete_checkpoints(self, grid_search_id: str, experiment_id: str, epoch: str):
         """
         ``HTTP DELETE`` Delete checkpoint resource pickle file
           given the epoch, experiment ID & grid search ID.
-
         :params:
-             grid_search_id (str): Grid Search ID
-             experiment_id (str): Experiment ID
-             epoch (str): Epoch number
+            - grid_search_id (str): Grid Search ID
+            - experiment_id (str): Experiment ID
+            - epoch (str): Epoch number
         """
         try:
             self.data_access.delete_checkpoints(grid_search_id=grid_search_id, experiment_id=experiment_id, epoch=epoch)
-
+        except FileNotFoundError as e:
+            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
+                                detail=f"Checkpoint resource {grid_search_id}/{experiment_id}/{epoch} not found.") from e
         except InvalidPathError as e:
-            raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Provided invalid parameters for checkpoint resource.") from e
+            raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,
+                                detail=f"Provided invalid parameters for checkpoint resource {grid_search_id}/{experiment_id}/{epoch}.") from e
 
-    def add_checkpoint_resource(
-        self, grid_search_id: str, experiment_id: str, epoch: str, checkpoint_resource: CheckpointResource, file: bytes = File(...)
-    ):
+    def add_checkpoint_resource(self, grid_search_id: str, experiment_id: str, epoch: str, checkpoint_file: UploadFile):
         """
         ``HTTP POST`` Add a checkpoint resource pickle file
           given the epoch, experiment ID & grid search ID.
-
         :params:
-             grid_search_id (str): Grid Search ID
-             experiment_id (str): Experiment ID
-             epoch (str): Epoch number
-             checkpoint_resource (CheckpointResource) : CheckpointResource type
-             file (bytes): Pickle file to be added
+            - grid_search_id (str): Grid Search ID
+            - experiment_id (str): Experiment ID
+            - epoch (str): Epoch number
+            - checkpoint_resource (CheckpointResource) : CheckpointResource type
+            - file (bytes): Pickle file to be added
+        """
+        try:
+            self.data_access.add_checkpoint_resource(grid_search_id=grid_search_id,
+                                                     experiment_id=experiment_id,
+                                                     epoch=epoch,
+                                                     checkpoint_file=checkpoint_file)
+        except InvalidPathError as e:
+            raise HTTPException(status_code=status.HTTP_403_FORBIDDEN,
+                                detail=f"Provided invalid payload or grid_search_id {grid_search_id}, experiment_id {experiment_id} or epoch {epoch}.",
+                                ) from e
+    
+    def get_system_info(self, grid_search_id: str, experiment_id: str):
+        """
+        ``HTTP GET`` Fetch System Information for model card.
+        :params:
+            - grid_search_id (str): Grid Search ID
+            - experiment_id (str): Experiment ID
+            - config_name (str): Name of Configuration file
 
-        :returns: Pickle file Stream response
+        :returns: JSON object - System Information of host machine (CPU & GPU)
         """
         try:
-            payload_pickle = base64.b64decode(file)
-            self.data_access.add_checkpoint_resource(
-                grid_search_id=grid_search_id,
-                experiment_id=experiment_id,
-                epoch=epoch,
-                checkpoint_resource=checkpoint_resource,
-                payload_pickle=payload_pickle,
+            file_generator = self.data_access.get_experiment_config(
+                grid_search_id=grid_search_id, experiment_id=experiment_id, config_name="system_info"
             )
-        except InvalidPathError as e:
-            raise HTTPException(
-                status_code=status.HTTP_403_FORBIDDEN,
-                detail=f"Provided invalid payload or grid_search_id {grid_search_id}, experiment_id {experiment_id} or epoch {epoch}.",
-            ) from e
+            response = StreamingResponse(file_generator, media_type="application/json")
+            return response
+        except SystemInfoFetchError as e:
+            raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail=f"Error while fetching server system information") from e
 
     def run_server(self, application_server_callable: Callable):
-        application_server_callable(app=self.app)
+        application_server_callable(app=self.app)
\ No newline at end of file
diff --git a/src/ml_board/frontend/Dashboard/package-lock.json b/src/ml_board/frontend/Dashboard/package-lock.json
index b0614fa8..f299a4fc 100644
--- a/src/ml_board/frontend/Dashboard/package-lock.json
+++ b/src/ml_board/frontend/Dashboard/package-lock.json
@@ -16,9 +16,12 @@
         "@testing-library/jest-dom": "^5.16.5",
         "@testing-library/react": "^13.4.0",
         "@testing-library/user-event": "^13.5.0",
+        "@textea/json-viewer": "^2.16.2",
         "ag-grid-community": "^28.2.1",
         "ag-grid-react": "^28.2.1",
+        "axios": "^1.3.4",
         "history": "^4.7.2",
+        "moment": "^2.29.4",
         "react": "^18.2.0",
         "react-chartjs-2": "^5.1.0",
         "react-dom": "^18.2.0",
@@ -1814,9 +1817,9 @@
       }
     },
     "node_modules/@babel/runtime": {
-      "version": "7.20.13",
-      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz",
-      "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==",
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz",
+      "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==",
       "dependencies": {
         "regenerator-runtime": "^0.13.11"
       },
@@ -2147,12 +2150,11 @@
       }
     },
     "node_modules/@emotion/babel-plugin": {
-      "version": "11.10.5",
-      "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.5.tgz",
-      "integrity": "sha512-xE7/hyLHJac7D2Ve9dKroBBZqBT7WuPQmWcq7HSGb84sUuP4mlOWoB8dvVfD9yk5DHkU1m6RW7xSoDtnQHNQeA==",
+      "version": "11.10.6",
+      "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.6.tgz",
+      "integrity": "sha512-p2dAqtVrkhSa7xz1u/m9eHYdLi+en8NowrmXeF/dKtJpU8lCWli8RUAati7NcSl0afsBott48pdnANuD0wh9QQ==",
       "dependencies": {
         "@babel/helper-module-imports": "^7.16.7",
-        "@babel/plugin-syntax-jsx": "^7.17.12",
         "@babel/runtime": "^7.18.3",
         "@emotion/hash": "^0.9.0",
         "@emotion/memoize": "^0.8.0",
@@ -2163,9 +2165,6 @@
         "find-root": "^1.1.0",
         "source-map": "^0.5.7",
         "stylis": "4.1.3"
-      },
-      "peerDependencies": {
-        "@babel/core": "^7.0.0"
       }
     },
     "node_modules/@emotion/babel-plugin/node_modules/escape-string-regexp": {
@@ -2218,12 +2217,12 @@
       "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA=="
     },
     "node_modules/@emotion/react": {
-      "version": "11.10.5",
-      "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.10.5.tgz",
-      "integrity": "sha512-TZs6235tCJ/7iF6/rvTaOH4oxQg2gMAcdHemjwLKIjKz4rRuYe1HJ2TQJKnAcRAfOUDdU8XoDadCe1rl72iv8A==",
+      "version": "11.10.6",
+      "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.10.6.tgz",
+      "integrity": "sha512-6HT8jBmcSkfzO7mc+N1L9uwvOnlcGoix8Zn7srt+9ga0MjREo6lRpuVX0kzo6Jp6oTqDhREOFsygN6Ew4fEQbw==",
       "dependencies": {
         "@babel/runtime": "^7.18.3",
-        "@emotion/babel-plugin": "^11.10.5",
+        "@emotion/babel-plugin": "^11.10.6",
         "@emotion/cache": "^11.10.5",
         "@emotion/serialize": "^1.1.1",
         "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0",
@@ -2232,13 +2231,9 @@
         "hoist-non-react-statics": "^3.3.1"
       },
       "peerDependencies": {
-        "@babel/core": "^7.0.0",
         "react": ">=16.8.0"
       },
       "peerDependenciesMeta": {
-        "@babel/core": {
-          "optional": true
-        },
         "@types/react": {
           "optional": true
         }
@@ -2262,26 +2257,22 @@
       "integrity": "sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA=="
     },
     "node_modules/@emotion/styled": {
-      "version": "11.10.5",
-      "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.10.5.tgz",
-      "integrity": "sha512-8EP6dD7dMkdku2foLoruPCNkRevzdcBaY6q0l0OsbyJK+x8D9HWjX27ARiSIKNF634hY9Zdoedh8bJCiva8yZw==",
+      "version": "11.10.6",
+      "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.10.6.tgz",
+      "integrity": "sha512-OXtBzOmDSJo5Q0AFemHCfl+bUueT8BIcPSxu0EGTpGk6DmI5dnhSzQANm1e1ze0YZL7TDyAyy6s/b/zmGOS3Og==",
       "dependencies": {
         "@babel/runtime": "^7.18.3",
-        "@emotion/babel-plugin": "^11.10.5",
+        "@emotion/babel-plugin": "^11.10.6",
         "@emotion/is-prop-valid": "^1.2.0",
         "@emotion/serialize": "^1.1.1",
         "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0",
         "@emotion/utils": "^1.2.0"
       },
       "peerDependencies": {
-        "@babel/core": "^7.0.0",
         "@emotion/react": "^11.0.0-rc.0",
         "react": ">=16.8.0"
       },
       "peerDependenciesMeta": {
-        "@babel/core": {
-          "optional": true
-        },
         "@types/react": {
           "optional": true
         }
@@ -2332,11 +2323,6 @@
         "url": "https://opencollective.com/eslint"
       }
     },
-    "node_modules/@eslint/eslintrc/node_modules/argparse": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
-      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
-    },
     "node_modules/@eslint/eslintrc/node_modules/globals": {
       "version": "13.20.0",
       "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
@@ -2351,17 +2337,6 @@
         "url": "https://github.com/sponsors/sindresorhus"
       }
     },
-    "node_modules/@eslint/eslintrc/node_modules/js-yaml": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
-      "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
-      "dependencies": {
-        "argparse": "^2.0.1"
-      },
-      "bin": {
-        "js-yaml": "bin/js-yaml.js"
-      }
-    },
     "node_modules/@eslint/eslintrc/node_modules/type-fest": {
       "version": "0.20.2",
       "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
@@ -2418,6 +2393,14 @@
         "node": ">=8"
       }
     },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+      "dependencies": {
+        "sprintf-js": "~1.0.2"
+      }
+    },
     "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": {
       "version": "5.3.1",
       "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
@@ -2438,6 +2421,18 @@
         "node": ">=8"
       }
     },
+    "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": {
+      "version": "3.14.1",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+      "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+      "dependencies": {
+        "argparse": "^1.0.7",
+        "esprima": "^4.0.0"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
     "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": {
       "version": "5.0.0",
       "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
@@ -3161,15 +3156,15 @@
       "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A=="
     },
     "node_modules/@mui/base": {
-      "version": "5.0.0-alpha.117",
-      "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.117.tgz",
-      "integrity": "sha512-3GlRSZdSrvDQ4k03dSV2rM+97JbNWimFOqGsE7n7Mi8WuBSYCgnPe56bQp3E5cShOrTn11dGH8FRCmVMcCEXqQ==",
+      "version": "5.0.0-alpha.123",
+      "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.123.tgz",
+      "integrity": "sha512-pxzcAfET3I6jvWqS4kijiLMn1OmdMw+mGmDa0SqmDZo3bXXdvLhpCCPqCkULG3UykhvFCOcU5HclOX3JCA+Zhg==",
       "dependencies": {
-        "@babel/runtime": "^7.20.7",
+        "@babel/runtime": "^7.21.0",
         "@emotion/is-prop-valid": "^1.2.0",
         "@mui/types": "^7.2.3",
-        "@mui/utils": "^5.11.7",
-        "@popperjs/core": "^2.11.6",
+        "@mui/utils": "^5.11.13",
+        "@popperjs/core": "^2.11.7",
         "clsx": "^1.2.1",
         "prop-types": "^15.8.1",
         "react-is": "^18.2.0"
@@ -3198,9 +3193,9 @@
       "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
     },
     "node_modules/@mui/core-downloads-tracker": {
-      "version": "5.11.8",
-      "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.11.8.tgz",
-      "integrity": "sha512-n/uJRIwZAaJaROaOA4VzycxDo27cusnrRzfycnAkAP5gBndwOJQ1CXjd1Y7hJe5eorj/ukixC7IZD+qCClMCMg==",
+      "version": "5.11.15",
+      "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.11.15.tgz",
+      "integrity": "sha512-Q0e2oBsjHyIWWj1wLzl14btunvBYC0yl+px7zL9R69tF87uenj6q72ieS369BJ6jxYpJwvXfR6/f+TC+ZUsKKg==",
       "funding": {
         "type": "opencollective",
         "url": "https://opencollective.com/mui"
@@ -3232,16 +3227,16 @@
       }
     },
     "node_modules/@mui/material": {
-      "version": "5.11.8",
-      "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.11.8.tgz",
-      "integrity": "sha512-MpIVmtj9VJBhPHvPWoMkfCPpmVGXT4q43PtCJsdKIdc7W9/nG3Kpqw2oWyw+UxG5xG7eLhmfRFGPKvj4/WopEQ==",
-      "dependencies": {
-        "@babel/runtime": "^7.20.7",
-        "@mui/base": "5.0.0-alpha.117",
-        "@mui/core-downloads-tracker": "^5.11.8",
-        "@mui/system": "^5.11.8",
+      "version": "5.11.15",
+      "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.11.15.tgz",
+      "integrity": "sha512-E5RbLq9/OvRKmGyeZawdnmFBCvhKkI/Zqgr0xFqW27TGwKLxObq/BreJc6Uu5Sbv8Fjj34vEAbRx6otfOyxn5w==",
+      "dependencies": {
+        "@babel/runtime": "^7.21.0",
+        "@mui/base": "5.0.0-alpha.123",
+        "@mui/core-downloads-tracker": "^5.11.15",
+        "@mui/system": "^5.11.15",
         "@mui/types": "^7.2.3",
-        "@mui/utils": "^5.11.7",
+        "@mui/utils": "^5.11.13",
         "@types/react-transition-group": "^4.4.5",
         "clsx": "^1.2.1",
         "csstype": "^3.1.1",
@@ -3281,12 +3276,12 @@
       "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
     },
     "node_modules/@mui/private-theming": {
-      "version": "5.11.7",
-      "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.11.7.tgz",
-      "integrity": "sha512-XzRTSZdc8bhuUdjablTNv3kFkZ/XIMlKkOqqJCU0G8W3tWGXpau2DXkafPd1ddjPhF9zF3qLKNGgKCChYItjgA==",
+      "version": "5.11.13",
+      "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.11.13.tgz",
+      "integrity": "sha512-PJnYNKzW5LIx3R+Zsp6WZVPs6w5sEKJ7mgLNnUXuYB1zo5aX71FVLtV7geyPXRcaN2tsoRNK7h444ED0t7cIjA==",
       "dependencies": {
-        "@babel/runtime": "^7.20.7",
-        "@mui/utils": "^5.11.7",
+        "@babel/runtime": "^7.21.0",
+        "@mui/utils": "^5.11.13",
         "prop-types": "^15.8.1"
       },
       "engines": {
@@ -3307,11 +3302,11 @@
       }
     },
     "node_modules/@mui/styled-engine": {
-      "version": "5.11.8",
-      "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.11.8.tgz",
-      "integrity": "sha512-iSpZp9AoeictsDi5xAQ4PGXu7mKtQyzMl7ZaWpHIGMFpsNnfY3NQNg+wkj/gpsAZ+Zg+IIyD+t+ig71Kr9fa0w==",
+      "version": "5.11.11",
+      "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.11.11.tgz",
+      "integrity": "sha512-wV0UgW4lN5FkDBXefN8eTYeuE9sjyQdg5h94vtwZCUamGQEzmCOtir4AakgmbWMy0x8OLjdEUESn9wnf5J9MOg==",
       "dependencies": {
-        "@babel/runtime": "^7.20.7",
+        "@babel/runtime": "^7.21.0",
         "@emotion/cache": "^11.10.5",
         "csstype": "^3.1.1",
         "prop-types": "^15.8.1"
@@ -3338,15 +3333,15 @@
       }
     },
     "node_modules/@mui/system": {
-      "version": "5.11.8",
-      "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.11.8.tgz",
-      "integrity": "sha512-zhroUcxAw2x/dISBJKhGbD70DOYCwMFRo7o/LUYTiUfQkfmLhRfEf1bopWgY9nYstn7QOxOq9fA3aR3pHrUTbw==",
+      "version": "5.11.15",
+      "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.11.15.tgz",
+      "integrity": "sha512-vCatoWCTnAPquoNifHbqMCMnOElEbLosVUeW0FQDyjCq+8yMABD9E6iY0s14O7iq1wD+qqU7rFAuDIVvJ/AzzA==",
       "dependencies": {
-        "@babel/runtime": "^7.20.7",
-        "@mui/private-theming": "^5.11.7",
-        "@mui/styled-engine": "^5.11.8",
+        "@babel/runtime": "^7.21.0",
+        "@mui/private-theming": "^5.11.13",
+        "@mui/styled-engine": "^5.11.11",
         "@mui/types": "^7.2.3",
-        "@mui/utils": "^5.11.7",
+        "@mui/utils": "^5.11.13",
         "clsx": "^1.2.1",
         "csstype": "^3.1.1",
         "prop-types": "^15.8.1"
@@ -3390,11 +3385,11 @@
       }
     },
     "node_modules/@mui/utils": {
-      "version": "5.11.7",
-      "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.11.7.tgz",
-      "integrity": "sha512-8uyNDeVHZA804Ego20Erv8TpxlbqTe/EbhTI2H1UYr4/RiIbBprat8W4Qqr2UQIsC/b3DLz+0RQ6R/E5BxEcLA==",
+      "version": "5.11.13",
+      "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.11.13.tgz",
+      "integrity": "sha512-5ltA58MM9euOuUcnvwFJqpLdEugc9XFsRR8Gt4zZNb31XzMfSKJPR4eumulyhsOTK1rWf7K4D63NKFPfX0AxqA==",
       "dependencies": {
-        "@babel/runtime": "^7.20.7",
+        "@babel/runtime": "^7.21.0",
         "@types/prop-types": "^15.7.5",
         "@types/react-is": "^16.7.1 || ^17.0.0",
         "prop-types": "^15.8.1",
@@ -3526,9 +3521,9 @@
       }
     },
     "node_modules/@popperjs/core": {
-      "version": "2.11.6",
-      "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz",
-      "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw==",
+      "version": "2.11.7",
+      "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.7.tgz",
+      "integrity": "sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw==",
       "funding": {
         "type": "opencollective",
         "url": "https://opencollective.com/popperjs"
@@ -4084,6 +4079,23 @@
         "@testing-library/dom": ">=7.21.4"
       }
     },
+    "node_modules/@textea/json-viewer": {
+      "version": "2.16.2",
+      "resolved": "https://registry.npmjs.org/@textea/json-viewer/-/json-viewer-2.16.2.tgz",
+      "integrity": "sha512-ZPRNpcLJ+hOO6C8tzkQvltRSp7Ol73j8oJ1+w5mWVWn+JR1QqzZJJgBqnNZvs3S1h/jJAjwyeZUVlb0VtIJcvg==",
+      "dependencies": {
+        "@emotion/react": "^11.10.6",
+        "@emotion/styled": "^11.10.6",
+        "@mui/material": "^5.11.14",
+        "clsx": "^1.2.1",
+        "copy-to-clipboard": "^3.3.3",
+        "zustand": "^4.3.6"
+      },
+      "peerDependencies": {
+        "react": "^17 || ^18",
+        "react-dom": "^17 || ^18"
+      }
+    },
     "node_modules/@tootallnate/once": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
@@ -5326,12 +5338,9 @@
       "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
     },
     "node_modules/argparse": {
-      "version": "1.0.10",
-      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
-      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
-      "dependencies": {
-        "sprintf-js": "~1.0.2"
-      }
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
     },
     "node_modules/aria-query": {
       "version": "5.1.3",
@@ -5515,6 +5524,29 @@
         "node": ">=4"
       }
     },
+    "node_modules/axios": {
+      "version": "1.3.4",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz",
+      "integrity": "sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==",
+      "dependencies": {
+        "follow-redirects": "^1.15.0",
+        "form-data": "^4.0.0",
+        "proxy-from-env": "^1.1.0"
+      }
+    },
+    "node_modules/axios/node_modules/form-data": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+      "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+      "dependencies": {
+        "asynckit": "^0.4.0",
+        "combined-stream": "^1.0.8",
+        "mime-types": "^2.1.12"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
     "node_modules/axobject-query": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz",
@@ -6412,6 +6444,14 @@
       "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
       "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
     },
+    "node_modules/copy-to-clipboard": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz",
+      "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==",
+      "dependencies": {
+        "toggle-selection": "^1.0.6"
+      }
+    },
     "node_modules/core-js": {
       "version": "3.27.2",
       "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.27.2.tgz",
@@ -8111,11 +8151,6 @@
         "url": "https://github.com/chalk/ansi-styles?sponsor=1"
       }
     },
-    "node_modules/eslint/node_modules/argparse": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
-      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
-    },
     "node_modules/eslint/node_modules/chalk": {
       "version": "4.1.2",
       "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -8180,17 +8215,6 @@
         "node": ">=8"
       }
     },
-    "node_modules/eslint/node_modules/js-yaml": {
-      "version": "4.1.0",
-      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
-      "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
-      "dependencies": {
-        "argparse": "^2.0.1"
-      },
-      "bin": {
-        "js-yaml": "bin/js-yaml.js"
-      }
-    },
     "node_modules/eslint/node_modules/supports-color": {
       "version": "7.2.0",
       "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -12107,12 +12131,11 @@
       "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
     },
     "node_modules/js-yaml": {
-      "version": "3.14.1",
-      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
-      "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+      "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
       "dependencies": {
-        "argparse": "^1.0.7",
-        "esprima": "^4.0.0"
+        "argparse": "^2.0.1"
       },
       "bin": {
         "js-yaml": "bin/js-yaml.js"
@@ -12654,6 +12677,14 @@
         "mkdirp": "bin/cmd.js"
       }
     },
+    "node_modules/moment": {
+      "version": "2.29.4",
+      "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
+      "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
+      "engines": {
+        "node": "*"
+      }
+    },
     "node_modules/ms": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -14593,6 +14624,11 @@
         "node": ">= 0.10"
       }
     },
+    "node_modules/proxy-from-env": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+      "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
+    },
     "node_modules/psl": {
       "version": "1.9.0",
       "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
@@ -16346,6 +16382,14 @@
         "node": ">=4.0.0"
       }
     },
+    "node_modules/svgo/node_modules/argparse": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+      "dependencies": {
+        "sprintf-js": "~1.0.2"
+      }
+    },
     "node_modules/svgo/node_modules/css-select": {
       "version": "2.1.0",
       "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz",
@@ -16391,6 +16435,18 @@
       "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
       "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w=="
     },
+    "node_modules/svgo/node_modules/js-yaml": {
+      "version": "3.14.1",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+      "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+      "dependencies": {
+        "argparse": "^1.0.7",
+        "esprima": "^4.0.0"
+      },
+      "bin": {
+        "js-yaml": "bin/js-yaml.js"
+      }
+    },
     "node_modules/svgo/node_modules/nth-check": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
@@ -16625,6 +16681,11 @@
         "node": ">=8.0"
       }
     },
+    "node_modules/toggle-selection": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
+      "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ=="
+    },
     "node_modules/toidentifier": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
@@ -17993,6 +18054,29 @@
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
       }
+    },
+    "node_modules/zustand": {
+      "version": "4.3.7",
+      "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.3.7.tgz",
+      "integrity": "sha512-dY8ERwB9Nd21ellgkBZFhudER8KVlelZm8388B5nDAXhO/+FZDhYMuRnqDgu5SYyRgz/iaf8RKnbUs/cHfOGlQ==",
+      "dependencies": {
+        "use-sync-external-store": "1.2.0"
+      },
+      "engines": {
+        "node": ">=12.7.0"
+      },
+      "peerDependencies": {
+        "immer": ">=9.0",
+        "react": ">=16.8"
+      },
+      "peerDependenciesMeta": {
+        "immer": {
+          "optional": true
+        },
+        "react": {
+          "optional": true
+        }
+      }
     }
   },
   "dependencies": {
@@ -19183,9 +19267,9 @@
       }
     },
     "@babel/runtime": {
-      "version": "7.20.13",
-      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz",
-      "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==",
+      "version": "7.21.0",
+      "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz",
+      "integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==",
       "requires": {
         "regenerator-runtime": "^0.13.11"
       }
@@ -19359,12 +19443,11 @@
       "requires": {}
     },
     "@emotion/babel-plugin": {
-      "version": "11.10.5",
-      "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.5.tgz",
-      "integrity": "sha512-xE7/hyLHJac7D2Ve9dKroBBZqBT7WuPQmWcq7HSGb84sUuP4mlOWoB8dvVfD9yk5DHkU1m6RW7xSoDtnQHNQeA==",
+      "version": "11.10.6",
+      "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.6.tgz",
+      "integrity": "sha512-p2dAqtVrkhSa7xz1u/m9eHYdLi+en8NowrmXeF/dKtJpU8lCWli8RUAati7NcSl0afsBott48pdnANuD0wh9QQ==",
       "requires": {
         "@babel/helper-module-imports": "^7.16.7",
-        "@babel/plugin-syntax-jsx": "^7.17.12",
         "@babel/runtime": "^7.18.3",
         "@emotion/hash": "^0.9.0",
         "@emotion/memoize": "^0.8.0",
@@ -19420,12 +19503,12 @@
       "integrity": "sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA=="
     },
     "@emotion/react": {
-      "version": "11.10.5",
-      "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.10.5.tgz",
-      "integrity": "sha512-TZs6235tCJ/7iF6/rvTaOH4oxQg2gMAcdHemjwLKIjKz4rRuYe1HJ2TQJKnAcRAfOUDdU8XoDadCe1rl72iv8A==",
+      "version": "11.10.6",
+      "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.10.6.tgz",
+      "integrity": "sha512-6HT8jBmcSkfzO7mc+N1L9uwvOnlcGoix8Zn7srt+9ga0MjREo6lRpuVX0kzo6Jp6oTqDhREOFsygN6Ew4fEQbw==",
       "requires": {
         "@babel/runtime": "^7.18.3",
-        "@emotion/babel-plugin": "^11.10.5",
+        "@emotion/babel-plugin": "^11.10.6",
         "@emotion/cache": "^11.10.5",
         "@emotion/serialize": "^1.1.1",
         "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0",
@@ -19452,12 +19535,12 @@
       "integrity": "sha512-zxRBwl93sHMsOj4zs+OslQKg/uhF38MB+OMKoCrVuS0nyTkqnau+BM3WGEoOptg9Oz45T/aIGs1qbVAsEFo3nA=="
     },
     "@emotion/styled": {
-      "version": "11.10.5",
-      "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.10.5.tgz",
-      "integrity": "sha512-8EP6dD7dMkdku2foLoruPCNkRevzdcBaY6q0l0OsbyJK+x8D9HWjX27ARiSIKNF634hY9Zdoedh8bJCiva8yZw==",
+      "version": "11.10.6",
+      "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.10.6.tgz",
+      "integrity": "sha512-OXtBzOmDSJo5Q0AFemHCfl+bUueT8BIcPSxu0EGTpGk6DmI5dnhSzQANm1e1ze0YZL7TDyAyy6s/b/zmGOS3Og==",
       "requires": {
         "@babel/runtime": "^7.18.3",
-        "@emotion/babel-plugin": "^11.10.5",
+        "@emotion/babel-plugin": "^11.10.6",
         "@emotion/is-prop-valid": "^1.2.0",
         "@emotion/serialize": "^1.1.1",
         "@emotion/use-insertion-effect-with-fallbacks": "^1.0.0",
@@ -19501,11 +19584,6 @@
         "strip-json-comments": "^3.1.1"
       },
       "dependencies": {
-        "argparse": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
-          "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
-        },
         "globals": {
           "version": "13.20.0",
           "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz",
@@ -19514,14 +19592,6 @@
             "type-fest": "^0.20.2"
           }
         },
-        "js-yaml": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
-          "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
-          "requires": {
-            "argparse": "^2.0.1"
-          }
-        },
         "type-fest": {
           "version": "0.20.2",
           "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
@@ -19561,6 +19631,14 @@
         "resolve-from": "^5.0.0"
       },
       "dependencies": {
+        "argparse": {
+          "version": "1.0.10",
+          "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+          "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+          "requires": {
+            "sprintf-js": "~1.0.2"
+          }
+        },
         "camelcase": {
           "version": "5.3.1",
           "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
@@ -19575,6 +19653,15 @@
             "path-exists": "^4.0.0"
           }
         },
+        "js-yaml": {
+          "version": "3.14.1",
+          "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+          "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+          "requires": {
+            "argparse": "^1.0.7",
+            "esprima": "^4.0.0"
+          }
+        },
         "locate-path": {
           "version": "5.0.0",
           "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
@@ -20117,15 +20204,15 @@
       "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A=="
     },
     "@mui/base": {
-      "version": "5.0.0-alpha.117",
-      "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.117.tgz",
-      "integrity": "sha512-3GlRSZdSrvDQ4k03dSV2rM+97JbNWimFOqGsE7n7Mi8WuBSYCgnPe56bQp3E5cShOrTn11dGH8FRCmVMcCEXqQ==",
+      "version": "5.0.0-alpha.123",
+      "resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.123.tgz",
+      "integrity": "sha512-pxzcAfET3I6jvWqS4kijiLMn1OmdMw+mGmDa0SqmDZo3bXXdvLhpCCPqCkULG3UykhvFCOcU5HclOX3JCA+Zhg==",
       "requires": {
-        "@babel/runtime": "^7.20.7",
+        "@babel/runtime": "^7.21.0",
         "@emotion/is-prop-valid": "^1.2.0",
         "@mui/types": "^7.2.3",
-        "@mui/utils": "^5.11.7",
-        "@popperjs/core": "^2.11.6",
+        "@mui/utils": "^5.11.13",
+        "@popperjs/core": "^2.11.7",
         "clsx": "^1.2.1",
         "prop-types": "^15.8.1",
         "react-is": "^18.2.0"
@@ -20139,9 +20226,9 @@
       }
     },
     "@mui/core-downloads-tracker": {
-      "version": "5.11.8",
-      "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.11.8.tgz",
-      "integrity": "sha512-n/uJRIwZAaJaROaOA4VzycxDo27cusnrRzfycnAkAP5gBndwOJQ1CXjd1Y7hJe5eorj/ukixC7IZD+qCClMCMg=="
+      "version": "5.11.15",
+      "resolved": "https://registry.npmjs.org/@mui/core-downloads-tracker/-/core-downloads-tracker-5.11.15.tgz",
+      "integrity": "sha512-Q0e2oBsjHyIWWj1wLzl14btunvBYC0yl+px7zL9R69tF87uenj6q72ieS369BJ6jxYpJwvXfR6/f+TC+ZUsKKg=="
     },
     "@mui/icons-material": {
       "version": "5.11.0",
@@ -20152,16 +20239,16 @@
       }
     },
     "@mui/material": {
-      "version": "5.11.8",
-      "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.11.8.tgz",
-      "integrity": "sha512-MpIVmtj9VJBhPHvPWoMkfCPpmVGXT4q43PtCJsdKIdc7W9/nG3Kpqw2oWyw+UxG5xG7eLhmfRFGPKvj4/WopEQ==",
-      "requires": {
-        "@babel/runtime": "^7.20.7",
-        "@mui/base": "5.0.0-alpha.117",
-        "@mui/core-downloads-tracker": "^5.11.8",
-        "@mui/system": "^5.11.8",
+      "version": "5.11.15",
+      "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.11.15.tgz",
+      "integrity": "sha512-E5RbLq9/OvRKmGyeZawdnmFBCvhKkI/Zqgr0xFqW27TGwKLxObq/BreJc6Uu5Sbv8Fjj34vEAbRx6otfOyxn5w==",
+      "requires": {
+        "@babel/runtime": "^7.21.0",
+        "@mui/base": "5.0.0-alpha.123",
+        "@mui/core-downloads-tracker": "^5.11.15",
+        "@mui/system": "^5.11.15",
         "@mui/types": "^7.2.3",
-        "@mui/utils": "^5.11.7",
+        "@mui/utils": "^5.11.13",
         "@types/react-transition-group": "^4.4.5",
         "clsx": "^1.2.1",
         "csstype": "^3.1.1",
@@ -20178,36 +20265,36 @@
       }
     },
     "@mui/private-theming": {
-      "version": "5.11.7",
-      "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.11.7.tgz",
-      "integrity": "sha512-XzRTSZdc8bhuUdjablTNv3kFkZ/XIMlKkOqqJCU0G8W3tWGXpau2DXkafPd1ddjPhF9zF3qLKNGgKCChYItjgA==",
+      "version": "5.11.13",
+      "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.11.13.tgz",
+      "integrity": "sha512-PJnYNKzW5LIx3R+Zsp6WZVPs6w5sEKJ7mgLNnUXuYB1zo5aX71FVLtV7geyPXRcaN2tsoRNK7h444ED0t7cIjA==",
       "requires": {
-        "@babel/runtime": "^7.20.7",
-        "@mui/utils": "^5.11.7",
+        "@babel/runtime": "^7.21.0",
+        "@mui/utils": "^5.11.13",
         "prop-types": "^15.8.1"
       }
     },
     "@mui/styled-engine": {
-      "version": "5.11.8",
-      "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.11.8.tgz",
-      "integrity": "sha512-iSpZp9AoeictsDi5xAQ4PGXu7mKtQyzMl7ZaWpHIGMFpsNnfY3NQNg+wkj/gpsAZ+Zg+IIyD+t+ig71Kr9fa0w==",
+      "version": "5.11.11",
+      "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.11.11.tgz",
+      "integrity": "sha512-wV0UgW4lN5FkDBXefN8eTYeuE9sjyQdg5h94vtwZCUamGQEzmCOtir4AakgmbWMy0x8OLjdEUESn9wnf5J9MOg==",
       "requires": {
-        "@babel/runtime": "^7.20.7",
+        "@babel/runtime": "^7.21.0",
         "@emotion/cache": "^11.10.5",
         "csstype": "^3.1.1",
         "prop-types": "^15.8.1"
       }
     },
     "@mui/system": {
-      "version": "5.11.8",
-      "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.11.8.tgz",
-      "integrity": "sha512-zhroUcxAw2x/dISBJKhGbD70DOYCwMFRo7o/LUYTiUfQkfmLhRfEf1bopWgY9nYstn7QOxOq9fA3aR3pHrUTbw==",
+      "version": "5.11.15",
+      "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.11.15.tgz",
+      "integrity": "sha512-vCatoWCTnAPquoNifHbqMCMnOElEbLosVUeW0FQDyjCq+8yMABD9E6iY0s14O7iq1wD+qqU7rFAuDIVvJ/AzzA==",
       "requires": {
-        "@babel/runtime": "^7.20.7",
-        "@mui/private-theming": "^5.11.7",
-        "@mui/styled-engine": "^5.11.8",
+        "@babel/runtime": "^7.21.0",
+        "@mui/private-theming": "^5.11.13",
+        "@mui/styled-engine": "^5.11.11",
         "@mui/types": "^7.2.3",
-        "@mui/utils": "^5.11.7",
+        "@mui/utils": "^5.11.13",
         "clsx": "^1.2.1",
         "csstype": "^3.1.1",
         "prop-types": "^15.8.1"
@@ -20220,11 +20307,11 @@
       "requires": {}
     },
     "@mui/utils": {
-      "version": "5.11.7",
-      "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.11.7.tgz",
-      "integrity": "sha512-8uyNDeVHZA804Ego20Erv8TpxlbqTe/EbhTI2H1UYr4/RiIbBprat8W4Qqr2UQIsC/b3DLz+0RQ6R/E5BxEcLA==",
+      "version": "5.11.13",
+      "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.11.13.tgz",
+      "integrity": "sha512-5ltA58MM9euOuUcnvwFJqpLdEugc9XFsRR8Gt4zZNb31XzMfSKJPR4eumulyhsOTK1rWf7K4D63NKFPfX0AxqA==",
       "requires": {
-        "@babel/runtime": "^7.20.7",
+        "@babel/runtime": "^7.21.0",
         "@types/prop-types": "^15.7.5",
         "@types/react-is": "^16.7.1 || ^17.0.0",
         "prop-types": "^15.8.1",
@@ -20302,9 +20389,9 @@
       }
     },
     "@popperjs/core": {
-      "version": "2.11.6",
-      "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.6.tgz",
-      "integrity": "sha512-50/17A98tWUfQ176raKiOGXuYpLyyVMkxxG6oylzL3BPOlA6ADGdK7EYunSa4I064xerltq9TGXs8HmOk5E+vw=="
+      "version": "2.11.7",
+      "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.7.tgz",
+      "integrity": "sha512-Cr4OjIkipTtcXKjAsm8agyleBuDHvxzeBoa1v543lbv1YaIwQjESsVcmjiWiPEbC1FIeHOG/Op9kdCmAmiS3Kw=="
     },
     "@reduxjs/toolkit": {
       "version": "1.9.2",
@@ -20660,6 +20747,19 @@
         "@babel/runtime": "^7.12.5"
       }
     },
+    "@textea/json-viewer": {
+      "version": "2.16.2",
+      "resolved": "https://registry.npmjs.org/@textea/json-viewer/-/json-viewer-2.16.2.tgz",
+      "integrity": "sha512-ZPRNpcLJ+hOO6C8tzkQvltRSp7Ol73j8oJ1+w5mWVWn+JR1QqzZJJgBqnNZvs3S1h/jJAjwyeZUVlb0VtIJcvg==",
+      "requires": {
+        "@emotion/react": "^11.10.6",
+        "@emotion/styled": "^11.10.6",
+        "@mui/material": "^5.11.14",
+        "clsx": "^1.2.1",
+        "copy-to-clipboard": "^3.3.3",
+        "zustand": "^4.3.6"
+      }
+    },
     "@tootallnate/once": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz",
@@ -21665,12 +21765,9 @@
       "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
     },
     "argparse": {
-      "version": "1.0.10",
-      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
-      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
-      "requires": {
-        "sprintf-js": "~1.0.2"
-      }
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
+      "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
     },
     "aria-query": {
       "version": "5.1.3",
@@ -21796,6 +21893,28 @@
       "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.6.3.tgz",
       "integrity": "sha512-/BQzOX780JhsxDnPpH4ZiyrJAzcd8AfzFPkv+89veFSr1rcMjuq2JDCwypKaPeB6ljHp9KjXhPpjgCvQlWYuqg=="
     },
+    "axios": {
+      "version": "1.3.4",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-1.3.4.tgz",
+      "integrity": "sha512-toYm+Bsyl6VC5wSkfkbbNB6ROv7KY93PEBBL6xyDczaIHasAiv4wPqQ/c4RjoQzipxRD2W5g21cOqQulZ7rHwQ==",
+      "requires": {
+        "follow-redirects": "^1.15.0",
+        "form-data": "^4.0.0",
+        "proxy-from-env": "^1.1.0"
+      },
+      "dependencies": {
+        "form-data": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+          "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+          "requires": {
+            "asynckit": "^0.4.0",
+            "combined-stream": "^1.0.8",
+            "mime-types": "^2.1.12"
+          }
+        }
+      }
+    },
     "axobject-query": {
       "version": "3.1.1",
       "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.1.1.tgz",
@@ -22480,6 +22599,14 @@
       "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
       "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
     },
+    "copy-to-clipboard": {
+      "version": "3.3.3",
+      "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz",
+      "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==",
+      "requires": {
+        "toggle-selection": "^1.0.6"
+      }
+    },
     "core-js": {
       "version": "3.27.2",
       "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.27.2.tgz",
@@ -23389,11 +23516,6 @@
             "color-convert": "^2.0.1"
           }
         },
-        "argparse": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
-          "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
-        },
         "chalk": {
           "version": "4.1.2",
           "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -23434,14 +23556,6 @@
           "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
           "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
         },
-        "js-yaml": {
-          "version": "4.1.0",
-          "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
-          "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
-          "requires": {
-            "argparse": "^2.0.1"
-          }
-        },
         "supports-color": {
           "version": "7.2.0",
           "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
@@ -26584,12 +26698,11 @@
       "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
     },
     "js-yaml": {
-      "version": "3.14.1",
-      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
-      "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+      "version": "4.1.0",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
+      "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
       "requires": {
-        "argparse": "^1.0.7",
-        "esprima": "^4.0.0"
+        "argparse": "^2.0.1"
       }
     },
     "jsdom": {
@@ -26990,6 +27103,11 @@
         "minimist": "^1.2.6"
       }
     },
+    "moment": {
+      "version": "2.29.4",
+      "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
+      "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w=="
+    },
     "ms": {
       "version": "2.1.2",
       "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -28204,6 +28322,11 @@
         }
       }
     },
+    "proxy-from-env": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
+      "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
+    },
     "psl": {
       "version": "1.9.0",
       "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
@@ -29473,6 +29596,14 @@
         "util.promisify": "~1.0.0"
       },
       "dependencies": {
+        "argparse": {
+          "version": "1.0.10",
+          "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+          "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+          "requires": {
+            "sprintf-js": "~1.0.2"
+          }
+        },
         "css-select": {
           "version": "2.1.0",
           "resolved": "https://registry.npmjs.org/css-select/-/css-select-2.1.0.tgz",
@@ -29514,6 +29645,15 @@
             }
           }
         },
+        "js-yaml": {
+          "version": "3.14.1",
+          "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
+          "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
+          "requires": {
+            "argparse": "^1.0.7",
+            "esprima": "^4.0.0"
+          }
+        },
         "nth-check": {
           "version": "1.0.2",
           "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
@@ -29686,6 +29826,11 @@
         "is-number": "^7.0.0"
       }
     },
+    "toggle-selection": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz",
+      "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ=="
+    },
     "toidentifier": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
@@ -30720,6 +30865,14 @@
       "version": "0.1.0",
       "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
       "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q=="
+    },
+    "zustand": {
+      "version": "4.3.7",
+      "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.3.7.tgz",
+      "integrity": "sha512-dY8ERwB9Nd21ellgkBZFhudER8KVlelZm8388B5nDAXhO/+FZDhYMuRnqDgu5SYyRgz/iaf8RKnbUs/cHfOGlQ==",
+      "requires": {
+        "use-sync-external-store": "1.2.0"
+      }
     }
   }
 }
diff --git a/src/ml_board/frontend/Dashboard/package.json b/src/ml_board/frontend/Dashboard/package.json
index 2ff6e28a..07afde86 100644
--- a/src/ml_board/frontend/Dashboard/package.json
+++ b/src/ml_board/frontend/Dashboard/package.json
@@ -11,9 +11,12 @@
     "@testing-library/jest-dom": "^5.16.5",
     "@testing-library/react": "^13.4.0",
     "@testing-library/user-event": "^13.5.0",
+    "@textea/json-viewer": "^2.16.2",
     "ag-grid-community": "^28.2.1",
     "ag-grid-react": "^28.2.1",
+    "axios": "^1.3.4",
     "history": "^4.7.2",
+    "moment": "^2.29.4",
     "react": "^18.2.0",
     "react-chartjs-2": "^5.1.0",
     "react-dom": "^18.2.0",
diff --git a/src/ml_board/frontend/Dashboard/src/app/ApiMaster.tsx b/src/ml_board/frontend/Dashboard/src/app/ApiMaster.tsx
new file mode 100644
index 00000000..99c0445c
--- /dev/null
+++ b/src/ml_board/frontend/Dashboard/src/app/ApiMaster.tsx
@@ -0,0 +1,33 @@
+export const defaultGridSearchConfigFileName = "grid_search_config";
+export const defaultExperimentConfigFileName = "experiment_config";
+
+const GRID_SEARCH_BASE_URL = "/grid_searches/<grid_search_id>";
+const CHECKPOINT_BASE_URL = "/checkpoints/<grid_search_id>/<experiment_id>/<checkpoint_id>";
+const CHECKPOINT_LIST_BASE_URL = "/checkpoint_list/<grid_search_id>/<experiment_id>";
+const MODEL_CARDS_BASE_URL = "/system-info/<grid_search_id>";
+
+let api = {
+    // following API to PUT config file for the whole grid search
+    gridsearch_config_file: GRID_SEARCH_BASE_URL + "/" + defaultGridSearchConfigFileName,
+
+    // following API to PUT config file for a selected experiment
+    experiment_config_file: GRID_SEARCH_BASE_URL + "/<experiment_id>/" + defaultExperimentConfigFileName,
+
+    // following API to get all the experiments of a grid search
+    experiments: GRID_SEARCH_BASE_URL + "/experiments",
+
+    // following API to GET data of all checkpoints of a selected experiment
+    checkpoint_list: CHECKPOINT_LIST_BASE_URL,
+
+    // following API to GET all data of a selected checkpoint
+    selected_checkpoint_list: CHECKPOINT_LIST_BASE_URL + "/<checkpoint_id>",
+    
+    // following APIs to GET, POST & DELETE data individually for checkpoints
+    // <checkpoint_resource> can be: model, optimizer, stateful_component, lr_scheduler
+    checkpoint_resource: CHECKPOINT_BASE_URL + "/<checkpoint_resource>",
+
+    // following API to GET system details like CPU & GPU for model card
+    model_card_sys_info: MODEL_CARDS_BASE_URL + "/<experiment_id>",
+}
+
+export default api;
\ No newline at end of file
diff --git a/src/ml_board/frontend/Dashboard/src/app/App.tsx b/src/ml_board/frontend/Dashboard/src/app/App.tsx
index f76483a8..418628b8 100644
--- a/src/ml_board/frontend/Dashboard/src/app/App.tsx
+++ b/src/ml_board/frontend/Dashboard/src/app/App.tsx
@@ -1,7 +1,7 @@
 import React, { useEffect, useState } from 'react';
 import { Route, Routes, useLocation, useSearchParams } from 'react-router-dom';
 import { upsertCharts } from '../redux/charts/chartsSlice';
-import { incrementReceivedMsgCount, setLastPing, setSocketConnection, setThroughput } from '../redux/status/statusSlice';
+import { incrementReceivedMsgCount, setGridSearchId, setLastPing, setRestApiUrl, setSocketConnection, setThroughput } from '../redux/status/statusSlice';
 import { upsertManyRows } from '../redux/table/tableSlice';
 import { DataToRedux } from '../worker_socket/DataTypes';
 import { useAppDispatch } from './hooks';
@@ -123,6 +123,10 @@ export default function App() {
                 dispatch(setThroughput(data.status["throughput"]));
             } else if (data.status["isSocketConnected"] !== undefined) {
                 dispatch(setSocketConnection(data.status["isSocketConnected"]));
+                if (data.status["isSocketConnected"]) {
+                    dispatch(setGridSearchId(data.status["gridSearchId"]));
+                    dispatch(setRestApiUrl(data.status["restApiUrl"]));
+                }
                 setConnectionSnackBar({
                     isOpen: true,
                     connection: data.status["isSocketConnected"]
@@ -179,7 +183,7 @@ export default function App() {
             {
                 // Floating Action Button (FAB) added for filter popup
                 // Show filter - FAB only if valid url is there. Else hide the button (Just as mentioned above - for the case of TopBar). Also hide it when user is on Settings Page (As - not needed to do filter when viewing/inserting/updating configurations)
-                urls.includes(location.pathname.split("/")[1]) && location.pathname.split("/")[1] !== RoutesMapping["Settings"].url ?
+                (urls.includes(location.pathname.split("/")[1]) && location.pathname.split("/")[1] !== RoutesMapping["Settings"].url) && (location.pathname.split("/")[1] !== RoutesMapping["ExperimentPage"].url) ?
                     <div className={styles.fab}>
                         <Fab
                             variant="extended"
diff --git a/src/ml_board/frontend/Dashboard/src/app/RoutesMapping.tsx b/src/ml_board/frontend/Dashboard/src/app/RoutesMapping.tsx
index 3e1513cf..c8cfa841 100644
--- a/src/ml_board/frontend/Dashboard/src/app/RoutesMapping.tsx
+++ b/src/ml_board/frontend/Dashboard/src/app/RoutesMapping.tsx
@@ -1,10 +1,10 @@
 import Graphs from '../components/graphs/Graphs';
 import Dashboard from '../components/dashboard/Dashboard';
-import Settings from '../components/settings/Settings';
 import PageNotFound from '../components/error/PageNotFound';
 import DashboardIcon from '@mui/icons-material/Dashboard';
 import AutoGraphIcon from '@mui/icons-material/AutoGraph';
 import SettingsIcon from '@mui/icons-material/Settings';
+import ExperimentPage from '../components/experimentPage/ExperimentPage';
 
 interface RoutesMappingInterface {
     // Object's Key name will be the name shown in Menu List
@@ -29,6 +29,12 @@ export const RoutesMapping:RoutesMappingInterface = {
         showInMenu: true,
         menuIcon: <DashboardIcon/>
     },
+    ExperimentPage: {
+        url: "experiment",
+        component: <ExperimentPage/>,
+        showInMenu: false,
+        menuIcon: null
+    },
     Graphs: {
         url: "analysisboard",
         component: <Graphs />,
diff --git a/src/ml_board/frontend/Dashboard/src/components/configPopup/ConfigPopup.tsx b/src/ml_board/frontend/Dashboard/src/components/configPopup/ConfigPopup.tsx
index e5f1bdd4..3417aa4a 100644
--- a/src/ml_board/frontend/Dashboard/src/components/configPopup/ConfigPopup.tsx
+++ b/src/ml_board/frontend/Dashboard/src/components/configPopup/ConfigPopup.tsx
@@ -47,11 +47,13 @@ const ConfigPopup: React.FC<FuncProps> = (props) => {
         setConfigTextState({ ...configTextState, [key]: text });
     }
 
+    // regular expression in replace function replaces all the trailing backslashes and then stores the url in redux as during actual API call, we are appending the full api path with the main url
+
     function submitData() {
         let settingConfigs = {
             gridSearchId: configTextState.gridSearchId,
-            socketConnectionUrl: configTextState.socketConnectionUrl,
-            restApiUrl: configTextState.restApiUrl
+            socketConnectionUrl: configTextState.socketConnectionUrl.replace(/\/+$/, ''),
+            restApiUrl: configTextState.restApiUrl.replace(/\/+$/, '')
         }      
         setOpen(false);
         props.validateConfigs(true);
@@ -60,8 +62,8 @@ const ConfigPopup: React.FC<FuncProps> = (props) => {
 
     function validateData() {
         let gridSearchId = configTextState.gridSearchId;
-        let socketConnectionUrl = configTextState.socketConnectionUrl;
-        let restApiUrl = configTextState.restApiUrl;
+        let socketConnectionUrl = configTextState.socketConnectionUrl.replace(/\/+$/, '');
+        let restApiUrl = configTextState.restApiUrl.replace(/\/+$/, '');
         let isDataInValid = true;
 
         // basic validation check: if any values are typed by user, then enable submit button or else keep it disabled - so that empty values are not sent for socket connection request
diff --git a/src/ml_board/frontend/Dashboard/src/components/dashboard/Dashboard.tsx b/src/ml_board/frontend/Dashboard/src/components/dashboard/Dashboard.tsx
index c73f6d9d..be26acbd 100644
--- a/src/ml_board/frontend/Dashboard/src/components/dashboard/Dashboard.tsx
+++ b/src/ml_board/frontend/Dashboard/src/components/dashboard/Dashboard.tsx
@@ -2,7 +2,37 @@ import { useAppSelector } from "../../app/hooks";
 import { selectFilter } from "../../redux/status/statusSlice";
 import { selectAllRows } from "../../redux/table/tableSlice";
 import Table from "./table/Table";
+import { Toolbar } from '@mui/material';
 
+export interface TableRow {
+  // Job
+  job_id: string; // format <grid_search_id>-<job index>
+  job_type: string; // <CALC, TERMINATE>
+  job_status: string; // <INIT, RUNNING, DONE>
+  starting_time: number;
+  finishing_time: number;
+  error: string;
+  stacktrace: string;
+  device: string;
+  // Experiment
+  experiment_id: number;
+  model_status?: string;   // <TRAINING, EVALUATING>,
+  current_split?: string;
+  splits?: string[]; //e.g.: ["train", "val", "test"],
+  num_epochs?: number;
+  current_epoch?: number;
+  num_batches?: number;
+  current_batch?: number;
+  // special Experiment keys for "latest_split_metric"
+  F1?: string;
+  Precision?: string;
+  Recall?: string;
+  // calculations
+  epoch_progress?: number;
+  batch_progress?: number;
+  // TODO: maybe get color???
+  color?: string;
+}
 
 export default function Dashboard() {
   // filter them based on the regEx in the status slice
@@ -11,11 +41,20 @@ export default function Dashboard() {
   const rows = useAppSelector(selectAllRows);
   const colNames: string[] = [];
 
+  // Table should consist of these columns for minimized view. To get detailed view, user can click on the row and see the job + experiment details:
+  // const colNames = ["experiment_id", "job_status", "starting_time", "finishing_time",
+  // "model_status", "epoch_progress", "batch_progress"];
+
   // TODO: get them from the Redux store better, otherwise this checks the first row ONLY!!!
   // getting the columns' headers dynamically
   if (rows.length > 1) {
     colNames.push(...Object.keys(rows[0]).filter((colName: string) => re.test(colName)));
   }
 
-  return (<Table colNames={colNames} rows={rows} />);
+  return (
+    <div>
+      <Toolbar />
+      <Table colNames={colNames} rows={rows} />
+    </div>
+  );
 }
\ No newline at end of file
diff --git a/src/ml_board/frontend/Dashboard/src/components/dashboard/table/Table.tsx b/src/ml_board/frontend/Dashboard/src/components/dashboard/table/Table.tsx
index a0c6ed04..edcec1e1 100644
--- a/src/ml_board/frontend/Dashboard/src/components/dashboard/table/Table.tsx
+++ b/src/ml_board/frontend/Dashboard/src/components/dashboard/table/Table.tsx
@@ -1,9 +1,9 @@
-import { Toolbar } from '@mui/material';
-import { CellClickedEvent } from 'ag-grid-community';
+import { RowDoubleClickedEvent } from 'ag-grid-community';
 import 'ag-grid-community/styles/ag-grid.css'; // Core grid CSS, always needed
 import 'ag-grid-community/styles/ag-theme-alpine.css'; // Optional theme CSS
 import { AgGridReact } from "ag-grid-react";
 import { useCallback, useMemo } from 'react';
+import { useNavigate } from 'react-router-dom';
 // styles
 import styles from './Table.module.css';
 
@@ -12,6 +12,8 @@ interface columnDefinition { field: string; }
 // TODO: Maybe merge Table and Dashboard?
 export default function Table({ colNames, rows }: { colNames: string[], rows: any[] }) {
 
+  const navigate = useNavigate();
+
   // change the array of strings to array of colum definitions
   const colDefs: columnDefinition[] = colNames.map(
     (colName: string) => ({
@@ -21,38 +23,30 @@ export default function Table({ colNames, rows }: { colNames: string[], rows: an
 
   const defaultColDef = useMemo(() => ({ resizable: true, sortable: true, filter: true }), []);
 
-  const onCellClicked = useCallback((event: CellClickedEvent) => { console.log(event) }, []);
+  const onRowDoubleClicked = useCallback((event: RowDoubleClickedEvent) => {
+    const selectedRowData = event.api.getSelectedRows()[0];
+    navigate({
+      pathname: '/experiment',
+      search: '?experiment_id=' + selectedRowData.experiment_id,
+    })
+  }, []);
+
+  // set background colour for every row based on the rowIndex, as it is the same as experiment_id. BUT this looks bad, should be using CSS classes?
+  // const getRowStyle = ({ rowIndex }: RowClassParams): RowStyle => { return { background: `hsl(${rowIndex * 137.5},75%,50%)` }; };
 
   return (
     <div className="ag-theme-alpine" id={styles.ag_grid_container_table}>
-      <Toolbar />
+      {/* NOTE: https://www.ag-grid.com/react-data-grid/row-styles/ */}
       <AgGridReact
         defaultColDef={defaultColDef}
-        // {/* provide column definitions */}
         columnDefs={colDefs}
-        // {/* specify auto group column definition */}
-        // autoGroupColumnDef={this.autoGroupColumnDef}
-        // {/* row data provided via props from the file store */}
         rowData={rows}
-        // // enable tree data
-        // treeData={true}
-        // // {/* return tree hierarchy from supplied data */}
-        // getDataPath={data => data.filePath}
-        // // {/* expand tree by default */}
-        // groupDefaultExpanded={-1}
-        // // {/* fit grid columns */}
         onGridReady={params => params.api.sizeColumnsToFit()}
-        // // {/* provide context menu callback */}
-        // getContextMenuItems={this.getContextMenuItems}
-        // // {/* provide row drag end callback */}
-        // onRowDragEnd={this.onRowDragEnd}
-        // // {/* return id required for tree data and immutable data */}
         getRowId={(params: any) => params.data.job_id}
-        // // {/* specify our FileCellRenderer component */}
-        // components={this.components}
+        rowSelection={"multiple"}
+        onRowDoubleClicked={onRowDoubleClicked}
+        rowStyle={{ cursor: "pointer" }}
         animateRows={true} // Optional - set to 'true' to have rows animate when sorted
-        rowSelection="multiple"
-        onCellClicked={onCellClicked}
       >
       </AgGridReact>
     </div>
diff --git a/src/ml_board/frontend/Dashboard/src/components/error/PageNotFound.tsx b/src/ml_board/frontend/Dashboard/src/components/error/PageNotFound.tsx
index 0fbe7542..737a610b 100644
--- a/src/ml_board/frontend/Dashboard/src/components/error/PageNotFound.tsx
+++ b/src/ml_board/frontend/Dashboard/src/components/error/PageNotFound.tsx
@@ -1,5 +1,3 @@
-import Box from '@mui/material/Box';
-
 // Error 404 Page to show if the entered URL is not valid
 function PageNotFound() {
     return(
diff --git a/src/ml_board/frontend/Dashboard/src/components/experimentPage/CheckpointConfigurations/CheckpointConfigurations.module.css b/src/ml_board/frontend/Dashboard/src/components/experimentPage/CheckpointConfigurations/CheckpointConfigurations.module.css
new file mode 100644
index 00000000..595270c9
--- /dev/null
+++ b/src/ml_board/frontend/Dashboard/src/components/experimentPage/CheckpointConfigurations/CheckpointConfigurations.module.css
@@ -0,0 +1,26 @@
+.textfield_cardcontent_checkpoint_config {
+    display: flex;
+    flex-direction: row;
+    justify-content: center;
+    align-items: center;
+}
+
+.checkpoint_data_resources {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: center;
+}
+
+.checkpoint_data_resources_main_card {
+    margin-bottom: 10px;
+    border-radius: 15px;
+}
+
+.error_text {
+    font-family: sans-serif;
+    color: red;
+    font-weight: bold;
+    text-align: center;
+    font-size: 15px;
+}
\ No newline at end of file
diff --git a/src/ml_board/frontend/Dashboard/src/components/experimentPage/CheckpointConfigurations/CheckpointConfigurations.tsx b/src/ml_board/frontend/Dashboard/src/components/experimentPage/CheckpointConfigurations/CheckpointConfigurations.tsx
new file mode 100644
index 00000000..7aa14d54
--- /dev/null
+++ b/src/ml_board/frontend/Dashboard/src/components/experimentPage/CheckpointConfigurations/CheckpointConfigurations.tsx
@@ -0,0 +1,192 @@
+import { Grid, Card, CardContent, IconButton, Box, LinearProgress, FormControl, FormHelperText, InputLabel, MenuItem, Select } from '@mui/material';
+import { Download } from '@mui/icons-material';
+import { useEffect, useState } from 'react';
+import axios from 'axios';
+import api from '../../../app/ApiMaster';
+import { useAppSelector } from "../../../app/hooks";
+import { getGridSearchId, getRestApiUrl } from '../../../redux/status/statusSlice';
+import styles from './CheckpointConfigurations.module.css';
+
+interface CheckpointDataInterface {
+    "experiment_id": string,
+    "epoch": string,
+    "checkpoints": Array<string>
+}
+
+export default function CheckpointConfigurations({experimentIdProp} : {experimentIdProp: string}) {
+
+    const [selectedCheckpointIndex, setSelectedCheckpointIndex] = useState(0);
+    const [checkpointResourceNames, setCheckpointResourceNames] = useState(Array<string>);
+    const [checkpointData, setCheckpointData] = useState(Array<CheckpointDataInterface>);
+    const [error, setError] = useState("");
+    const [errorInGettingResource, setErrorInGettingResource] = useState("");
+    const [isLoading, setIsLoading] = useState(false);
+    const [isLoadingResource, setIsLoadingResource] = useState(false);
+
+    const grid_search_id = useAppSelector(getGridSearchId);
+    const rest_api_url = useAppSelector(getRestApiUrl);
+
+    useEffect(() => {
+        if(experimentIdProp) {
+            getAllCheckpoints();
+        }
+    },[experimentIdProp]);
+
+    function getAllCheckpoints() {
+        let all_checkpoints = api.checkpoint_list.replace("<grid_search_id>", grid_search_id);
+        all_checkpoints = all_checkpoints.replace("<experiment_id>", experimentIdProp);
+
+        axios.get(rest_api_url + all_checkpoints).then((response) => {
+            console.log("Got response from checkpoint_list API: ", response);
+            if (response.status === 200) {
+                let resp_data = response.data;
+                setCheckpointData(resp_data);
+                // selecting all the resource names to display for the first default index 
+                setCheckpointResourceNames(resp_data[0].checkpoints);
+            }
+            else {
+                setError("Error occured / No checkpoints available");
+            }
+            setIsLoading(false);
+        })
+        .catch((error) => {
+            console.log("Error in checkpoint_list: ", error);
+            setIsLoading(false);
+            setError("Error occured / No checkpoints available");
+        });
+    }
+
+    function getCheckpointResource(resourceName: string) {
+        let checkpoint_resource = api.checkpoint_resource.replace("<grid_search_id>", grid_search_id);
+        checkpoint_resource = checkpoint_resource.replace("<experiment_id>", experimentIdProp);
+        checkpoint_resource = checkpoint_resource.replace("<checkpoint_id>", checkpointData[selectedCheckpointIndex].epoch.toString());
+        checkpoint_resource = checkpoint_resource.replace("<checkpoint_resource>", resourceName);
+
+        setErrorInGettingResource("");
+        setIsLoadingResource(true);
+
+        axios.get(rest_api_url + checkpoint_resource).then((response) => {
+            console.log("Got response from checkpoint_resource API: ", response);
+            if (response.status === 200) {
+                downloadFile(resourceName, new Blob([response.data]));
+            }
+            else {
+                setErrorInGettingResource("Oops! an error occurred in getting & downloading checkpoint resource data")
+            }
+            setIsLoadingResource(false);
+        })
+        .catch((error) => {
+            console.log("Error in checkpoint_resource API: ", error);
+            setIsLoadingResource(false);
+            setErrorInGettingResource("Oops! an error occurred in getting & downloading checkpoint resource data")
+        });
+    }
+
+    function downloadFile(resourceName: string, fileData: Blob) {
+        const url = window.URL.createObjectURL(fileData!);
+        const a = document.createElement('a');
+        a.href = url;
+        a.download = resourceName+"_checkpoint_"+checkpointData[selectedCheckpointIndex].epoch.trim().toString()+"_experiemnt_"+experimentIdProp+".pickle";
+        document.body.appendChild(a);
+        a.click();
+        document.body.removeChild(a);
+    }
+
+    return(
+        <Grid container spacing={{ xs: 2, sm: 2, md: 2, lg: 2 }}>
+            <Grid item={true} xs={12} sm={12} md={12} lg={12}>
+                <Box className={styles.textfield_cardcontent_checkpoint_config}>
+                    <FormControl fullWidth={true} error={error.length > 0}>
+                        <InputLabel id="demo-simple-select-helper-label">Select Checkpoint Id</InputLabel>
+                        <Select
+                            labelId="demo-simple-select-helper-label"
+                            id="demo-simple-select-helper"
+                            value={selectedCheckpointIndex}
+                            label="Select Checkpoint Id"
+                            onChange={(e)=>{
+                                let index = Number(e.target.value);
+                                setSelectedCheckpointIndex(index);
+                                setCheckpointResourceNames(checkpointData[index].checkpoints);
+                            }}
+                            MenuProps={{ style: { maxHeight: "250px" } }} // have to keep style here. keeping it in css file is not working for this
+                        >
+                            {
+                                checkpointData.length > 0 ?
+                                checkpointData.map((chkpt_obj, index) => 
+                                    <MenuItem key={index} value={index.toString()}>
+                                        {chkpt_obj.epoch}
+                                    </MenuItem>
+                                )
+                                :
+                                null
+                            }
+                        </Select>
+                        {
+                            error.length > 0 ?
+                            <FormHelperText>
+                                {error}
+                            </FormHelperText>
+                            :
+                            null
+                        }
+                    </FormControl>
+                </Box>
+            </Grid>
+            {
+                isLoading ?
+                <Grid item={true} xs={12} sm={12} md={12} lg={12}>
+                    <Box>
+                        <LinearProgress />
+                    </Box>
+                </Grid>
+                :
+                null
+            }
+            {
+                !isLoading && error.length === 0 && checkpointResourceNames.length > 0 ?
+                <Grid item={true} xs={12} sm={12} md={12} lg={12}>
+                    {
+                        checkpointResourceNames.map((resourceName, index) => {
+                            return(
+                                <Card className={styles.checkpoint_data_resources_main_card} key={index}>
+                                    <CardContent className={styles.checkpoint_data_resources}>
+                                        <div>
+                                            {resourceName}
+                                        </div>
+                                        <IconButton 
+                                            size="small"
+                                            onClick={()=>getCheckpointResource(resourceName)}
+                                            disabled={isLoadingResource}
+                                        >
+                                            <Download /> 
+                                        </IconButton>
+                                    </CardContent>
+                                </Card>
+                            );
+                        })
+                    }
+                    {
+                        isLoadingResource ?
+                        <Grid item={true} xs={12} sm={12} md={12} lg={12}>
+                            <Box>
+                                <LinearProgress />
+                            </Box>
+                        </Grid>
+                        :
+                        null
+                    }
+                    {
+                        errorInGettingResource.length > 0 ?
+                        <div className={styles.error_text}>
+                            {errorInGettingResource}
+                        </div>
+                        :
+                        null
+                    }
+                </Grid>
+                :
+                null
+            }
+        </Grid>
+    );
+}
\ No newline at end of file
diff --git a/src/ml_board/frontend/Dashboard/src/components/experimentPage/ExperimentConfigurations/ExperimentConfigurations.module.css b/src/ml_board/frontend/Dashboard/src/components/experimentPage/ExperimentConfigurations/ExperimentConfigurations.module.css
new file mode 100644
index 00000000..0ddb85d5
--- /dev/null
+++ b/src/ml_board/frontend/Dashboard/src/components/experimentPage/ExperimentConfigurations/ExperimentConfigurations.module.css
@@ -0,0 +1,16 @@
+.textfield_cardcontent_experiment_config {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: center;
+}
+
+.heading_style {
+    font-family: sans-serif;
+}
+
+.error_text {
+    font-family: sans-serif;
+    color: red;
+    font-size: 20px;
+}
\ No newline at end of file
diff --git a/src/ml_board/frontend/Dashboard/src/components/experimentPage/ExperimentConfigurations/ExperimentConfigurations.tsx b/src/ml_board/frontend/Dashboard/src/components/experimentPage/ExperimentConfigurations/ExperimentConfigurations.tsx
new file mode 100644
index 00000000..ac2cc0df
--- /dev/null
+++ b/src/ml_board/frontend/Dashboard/src/components/experimentPage/ExperimentConfigurations/ExperimentConfigurations.tsx
@@ -0,0 +1,125 @@
+import { Grid, Card, CardContent, TextField, IconButton, Switch, FormControlLabel, Box, LinearProgress } from '@mui/material';
+import { Send, Download } from '@mui/icons-material';
+import { JsonViewer } from '@textea/json-viewer';
+import { useEffect, useState } from 'react';
+import axios from 'axios';
+import api, { defaultExperimentConfigFileName } from '../../../app/ApiMaster';
+import { useAppSelector } from "../../../app/hooks";
+import { getGridSearchId, getRestApiUrl } from '../../../redux/status/statusSlice';
+import styles from './ExperimentConfigurations.module.css';
+
+export default function ExperimentConfigurations({experimentIdProp} : {experimentIdProp: string}) {
+    
+    const [experimentConfigFileObject, setExperimentConfigFileObject] = useState({});
+    const [error, setError] = useState("");
+    const [isLoading, setIsLoading] = useState(false);
+    const [showHideData, setShowHideData] = useState(false);
+    const grid_search_id = useAppSelector(getGridSearchId);
+    const rest_api_url = useAppSelector(getRestApiUrl);
+
+    useEffect(() => {
+        if(experimentIdProp) {
+            let experiment_config_file = api.experiment_config_file.replace("<grid_search_id>", grid_search_id);
+            experiment_config_file = experiment_config_file.replace("<experiment_id>", experimentIdProp);
+            
+            setError("");
+            setShowHideData(false);
+            setIsLoading(true);
+    
+            axios.get(rest_api_url + experiment_config_file).then((response) => {
+                console.log("Got response from experiment_config API: ", response);
+                if (response.status === 200) {
+                    setExperimentConfigFileObject(response.data);
+                    setShowHideData(true);
+                }
+                else {
+                    setError("Oops! an error occurred");
+                }
+                setIsLoading(false);
+            })
+            .catch((error) => {
+                console.log("Error in experiment_config_file: ", error);
+                setIsLoading(false);
+                setError("Oops! an error occurred");
+            });
+        }
+    },[experimentIdProp]);
+
+    function downloadFile() {
+        if(experimentIdProp) {
+            const dataStr = JSON.stringify(experimentConfigFileObject, null, 2);
+            const dataUri = 'data:application/json;charset=utf-8,'+ encodeURIComponent(dataStr);
+            const linkElement = document.createElement("a");
+            linkElement.setAttribute('href', dataUri);
+            linkElement.setAttribute('download', defaultExperimentConfigFileName.trim()+"_experiment_"+experimentIdProp+".json");
+            linkElement.click();
+        }
+    }
+
+    return(
+        <Grid container spacing={{ xs: 2, sm: 2, md: 2, lg: 2 }}>
+            <Grid item={true} xs={12} sm={12} md={12} lg={12}>
+                <Box className={styles.textfield_cardcontent_experiment_config}>
+                    <h2 className={styles.heading_style}>Experiment Configuration File</h2>
+                    <div>
+                        {
+                            !isLoading && error.length === 0 && Object.keys(experimentConfigFileObject).length > 0 ?
+                            <IconButton 
+                                size="large"
+                                onClick={()=>downloadFile()}
+                            >
+                                <Download /> 
+                            </IconButton>
+                            :
+                            null
+                        }
+                        {
+                            !isLoading && error.length === 0 && Object.keys(experimentConfigFileObject).length > 0 ?
+                            <FormControlLabel
+                                control={
+                                    <Switch
+                                        checked={showHideData}
+                                        color="primary"
+                                        onChange={()=>setShowHideData(!showHideData)}
+                                    />
+                                }
+                                label={"View/Hide"}
+                            />
+                            :
+                            null
+                        }
+                    </div>
+                </Box>
+            </Grid>
+            {
+                isLoading ?
+                <Grid item={true} xs={12} sm={12} md={12} lg={12}>
+                    <Box>
+                        <LinearProgress />
+                    </Box>
+                </Grid>
+                :
+                null
+            }
+            {
+                !isLoading && error.length === 0 && Object.keys(experimentConfigFileObject).length > 0 && showHideData ?
+                <Grid item={true} xs={12} sm={12} md={12} lg={12}>
+                    <Card>
+                        <CardContent>
+                            <JsonViewer value={experimentConfigFileObject}/>
+                        </CardContent>
+                    </Card>
+                </Grid>
+                :
+                !isLoading && error.length !== 0 ?
+                <Grid item={true} xs={12} sm={12} md={12} lg={12}>
+                    <Box className={styles.error_text}>
+                        Error Occured In Getting Experiment Configuration File!
+                    </Box>
+                </Grid>
+                :
+                null
+            }
+        </Grid>
+    );
+}
\ No newline at end of file
diff --git a/src/ml_board/frontend/Dashboard/src/components/experimentPage/ExperimentDetails/CardDetails.tsx b/src/ml_board/frontend/Dashboard/src/components/experimentPage/ExperimentDetails/CardDetails.tsx
new file mode 100644
index 00000000..027b3dd8
--- /dev/null
+++ b/src/ml_board/frontend/Dashboard/src/components/experimentPage/ExperimentDetails/CardDetails.tsx
@@ -0,0 +1,28 @@
+import styles from '../ExperimentPage.module.css';
+import { Card, CardContent } from '@mui/material';
+import { AnyKeyValuePairsInterface } from '../ExperimentPage';
+
+export function CardDetails({cardTitle, contentObj} : {cardTitle:string, contentObj: AnyKeyValuePairsInterface}) {
+
+    return(
+        <Card className={styles.card}>
+            <CardContent>
+                <div className={styles.card_content_typography}>
+                    {cardTitle}
+                </div>
+                {
+                    Object.keys(contentObj).map((content) => 
+                        <div className={styles.cardcontent} key={content}>
+                            <div className={styles.cardcontent_key}>
+                                {content}
+                            </div>
+                            <div className={styles.cardcontent_value}>
+                                {contentObj[content]}
+                            </div>
+                        </div>
+                    )
+                }
+            </CardContent>
+        </Card>
+    );
+}
\ No newline at end of file
diff --git a/src/ml_board/frontend/Dashboard/src/components/experimentPage/ExperimentDetails/ExperimentDetails.tsx b/src/ml_board/frontend/Dashboard/src/components/experimentPage/ExperimentDetails/ExperimentDetails.tsx
new file mode 100644
index 00000000..dbc4b9cf
--- /dev/null
+++ b/src/ml_board/frontend/Dashboard/src/components/experimentPage/ExperimentDetails/ExperimentDetails.tsx
@@ -0,0 +1,128 @@
+import { Card, CardContent, Grid } from '@mui/material';
+import moment from 'moment';
+import { useState } from 'react';
+import { AnyKeyValuePairsInterface } from '../ExperimentPage';
+import styles from '../ExperimentPage.module.css';
+import { CardDetails } from './CardDetails';
+
+interface return_obj_interface {
+    [key: string]: string
+}
+
+export function ExperimentDetails({ selectedExperiment }: { selectedExperiment: AnyKeyValuePairsInterface }) {
+
+    const [showMore, setShowMore] = useState(false);
+
+    const conditional_render_exp_overview = () => ({
+        "Experiment ID": selectedExperiment.experiment_id,
+        "Job Type": selectedExperiment.job_type ?? "--",
+        "Device": selectedExperiment.device ?? "--"
+    });
+
+    function conditional_render_exp_state() {
+        const return_obj: return_obj_interface = {};
+
+        if(selectedExperiment.hasOwnProperty("error") && selectedExperiment.error !== null) {
+            return_obj["Job Status"] = "FAILED";
+        }
+        else if(selectedExperiment.job_status === "DONE") {
+            return_obj["Job Status"] = "COMPLETED";
+        }
+        else if(selectedExperiment.job_status === "INIT") {
+            return_obj["Job Status"] = "INITIALIZING";
+        }
+        else if(selectedExperiment.job_status) {
+            return_obj["Job Status"] = selectedExperiment.job_status;
+        }
+        else {
+            return_obj["Job Status"] = "--";
+        }
+
+        return_obj["Model Status"] = selectedExperiment.model_status ?? "--";
+
+        return return_obj;
+    }
+
+    function conditional_render_exp_date_time() {
+        const return_obj: return_obj_interface = {};
+
+        if(selectedExperiment.starting_time && selectedExperiment.starting_time !== -1) {
+            return_obj["Start"] = moment(new Date(selectedExperiment.starting_time * 1000)).format("YYYY-MM-DD hh:MM:SS");
+        }
+        else {
+            return_obj["Start"] = "--";
+        }
+
+        if(selectedExperiment.finishing_time && selectedExperiment.finishing_time !== -1) {
+            return_obj["End"] = moment(new Date(selectedExperiment.finishing_time * 1000)).format("YYYY-MM-DD hh:MM:SS");
+        }
+        else {
+            return_obj["End"] = "--";
+        }
+
+        return return_obj;
+    }
+
+    return (
+        <>
+            <Grid container rowSpacing={1} spacing={{ xs: 1, md: 2 }}>
+                <Grid item={true} xs={12} sm={12} md={4}>
+                    <CardDetails
+                        cardTitle='Overview'
+                        contentObj={conditional_render_exp_overview()}
+                    />
+                </Grid>
+                <Grid item={true} xs={12} sm={12} md={4}>
+                    <CardDetails
+                        cardTitle='Times'
+                        contentObj={conditional_render_exp_date_time()}
+                    />
+                </Grid>
+                <Grid item={true} xs={12} sm={12} md={4}>
+                    <CardDetails
+                        cardTitle='State'
+                        contentObj={conditional_render_exp_state()}
+                    />
+                </Grid>
+            </Grid>
+            {
+                selectedExperiment.error && <div className={styles.error_card}>
+                    <Card className={styles.card}>
+                        <CardContent>
+                            <div className={styles.card_content_typography_error} >
+                                Error
+                            </div>
+                            <div className={styles.cardcontent_key}>
+                                {selectedExperiment.error}
+                            </div>
+                            {
+                                selectedExperiment.stacktrace && <div>
+                                    <br />
+                                    <div className={styles.card_content_typography} >
+                                        Stacktrace
+                                    </div>
+                                    <div className={styles.cardcontent_key}>
+                                        {
+                                            showMore ?
+                                                selectedExperiment.stacktrace
+                                                :
+                                                selectedExperiment.stacktrace.substring(0, 100) + "..."
+                                        }
+                                        <span
+                                            onClick={() => setShowMore(!showMore)}
+                                            className={styles.show_more_text}
+                                        >
+                                            {
+                                                showMore ? "show less" : "show more"
+                                            }
+                                        </span>
+                                    </div>
+                                </div>
+                            }
+                        </CardContent>
+                    </Card>
+                </div>
+            }
+        </>
+    );
+}
diff --git a/src/ml_board/frontend/Dashboard/src/components/experimentPage/ExperimentPage.module.css b/src/ml_board/frontend/Dashboard/src/components/experimentPage/ExperimentPage.module.css
new file mode 100644
index 00000000..85c25baf
--- /dev/null
+++ b/src/ml_board/frontend/Dashboard/src/components/experimentPage/ExperimentPage.module.css
@@ -0,0 +1,152 @@
+.cardview {
+    display: flex;
+    flex-direction: row;
+    gap: 10px;
+}
+
+.cardcontent {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    margin-top: 5px;
+    margin-bottom: 10px;
+}
+
+.cardcontent_typography {
+    display: flex;
+    flex-direction: row;
+    gap: 10px;
+}
+
+.accrodian_typography {
+    display: flex;
+    flex-direction: row;
+    margin-left: 15px;
+    margin-bottom: 15px;
+}
+
+.main {
+    padding-bottom: 100px;
+}
+
+/* .main_heading {
+    padding: 20px;
+    font-size: 25px;
+    font-weight: bold;
+    margin: auto;
+    text-align: center;
+    font-family: sans-serif;
+} */
+
+.accordian_heading {
+    font-weight: bold !important;
+    font-size: 20px;
+    font-family: sans-serif;
+}
+
+.card {
+    width: 100%;
+    height: 100%;
+}
+
+.card_download_btn {
+    width: 100%;
+}
+
+.error_card {
+    margin-top: 10px;
+}
+
+.expand_more_icon {
+    font-size: 0.9rem !important;
+}
+
+.show_more_text {
+    cursor: pointer;
+    color: #36A2EB;
+    font-family: sans-serif;
+}
+
+.donought_container {
+    display: flex;
+    justify-content: center;
+}
+
+.card_content_typography {
+    color: gray;
+    margin-bottom: 10px;
+    font-family: sans-serif;
+}
+
+.card_content_typography_error {
+    font-weight: bold !important;
+    color: red;
+    font-family: sans-serif;
+}
+
+.cardcontent_key {
+    font-family: sans-serif;
+}
+
+.cardcontent_textfiled {
+    background-color: #36A2EB;
+    margin-top: 5px;
+    margin-bottom: 10px;
+}
+
+.textfiled_cardcontent {
+    display: flex;
+    flex-direction: row;
+    margin-top: 5px;
+    margin-bottom: 10px;
+}
+
+.cardcontent_value {
+    font-weight: bold;
+    color: #36A2EB;
+    font-family: sans-serif;
+}
+
+.grid_card { 
+    box-shadow: 0px 1px 1px 2px rgba(97, 95, 95, 0.23) !important;
+    margin-bottom: 20px;
+    padding: 5px;
+    display: flex;
+}
+
+.graphs_chart_container {
+    position: relative;
+    margin: auto;
+    height: 80vh;
+    width: 100%;
+}
+
+.loading_bar_wrap {
+    width: 100%;
+}
+
+.switch_container {
+    display: block;
+    margin-left: 20px;
+}
+
+.error_text_no_data_1 {
+    font-family: sans-serif;
+    color: red;
+    font-weight: bold;
+    font-size: 25px;
+}
+
+.error_text_no_data_2 {
+    font-family: sans-serif;
+    font-size: 20px;
+    margin-top: 10px;
+}
+
+.extra_text_container {
+    display: flex;
+    flex-direction: column;
+    justify-content: center;
+    align-items: center;
+    margin-top: 30px;
+}
\ No newline at end of file
diff --git a/src/ml_board/frontend/Dashboard/src/components/experimentPage/ExperimentPage.tsx b/src/ml_board/frontend/Dashboard/src/components/experimentPage/ExperimentPage.tsx
new file mode 100644
index 00000000..6f5308eb
--- /dev/null
+++ b/src/ml_board/frontend/Dashboard/src/components/experimentPage/ExperimentPage.tsx
@@ -0,0 +1,160 @@
+import { Toolbar, styled, AccordionProps, AccordionSummaryProps, Card, CardContent, Box, Grid } from '@mui/material';
+import { useEffect, useState } from 'react';
+import { useSearchParams } from 'react-router-dom';
+import { useAppSelector } from "../../app/hooks";
+import { selectRowById } from '../../redux/table/tableSlice';
+import ArrowForwardIosSharpIcon from '@mui/icons-material/ArrowForwardIosSharp';
+import MuiAccordion from '@mui/material/Accordion';
+import MuiAccordionSummary from '@mui/material/AccordionSummary';
+import MuiAccordionDetails from '@mui/material/AccordionDetails';
+import styles from './ExperimentPage.module.css';
+import styles_graphs from "../graphs/Graphs.module.css";
+import Graph from "../graphs/Graph";
+import CheckpointConfigurations from './CheckpointConfigurations/CheckpointConfigurations';
+import ExperimentConfigurations from './ExperimentConfigurations/ExperimentConfigurations';
+import ModelCards from './ModelCards/ModelCards';
+import { isConnected } from "../../redux/status/statusSlice";
+import { ExperimentDetails } from './ExperimentDetails/ExperimentDetails';
+import { ExperimentProgress } from './ExperimentProgress/ExperimentProgress';
+import { selectChartsByExperimentId } from '../../redux/charts/chartsSlice';
+
+export interface AnyKeyValuePairsInterface {
+    [key: string]: any
+}
+var anyObj: AnyKeyValuePairsInterface = {}
+
+const Accordion = styled((props: AccordionProps) => (
+    <MuiAccordion disableGutters elevation={0} square {...props} />))(() => ({
+    '&:not(:last-child)': {
+        borderBottom: 0,
+    },
+    '&:before': {
+        display: 'none',
+    }
+}));
+  
+const AccordionSummary = styled((props: AccordionSummaryProps) => (
+    <MuiAccordionSummary
+      expandIcon={<ArrowForwardIosSharpIcon className={styles.expand_more_icon} />}
+      {...props}
+    />
+  ))(({ theme }) => ({
+    flexDirection: 'row-reverse',
+    '& .MuiAccordionSummary-expandIconWrapper.Mui-expanded': {
+      transform: 'rotate(90deg)',
+    },
+    '& .MuiAccordionSummary-content': {
+      marginLeft: theme.spacing(1),
+    },
+}));
+  
+const AccordionDetails = styled(MuiAccordionDetails)(({ theme }) => ({
+    paddingTop: theme.spacing(0),
+}));
+
+function ExperimentPage() {
+    const [searchParams, setSearchParams] = useSearchParams();
+    let experiment_id = searchParams.get("experiment_id") as string;
+    const [selectedExperiment, setSelectedExperiment] = useState(anyObj)
+    const filteredExp = useAppSelector(state => selectRowById(state, experiment_id));
+    const selectedExpGraphs = useAppSelector(state => selectChartsByExperimentId(state, experiment_id))
+    const isSocketConnected = useAppSelector(isConnected);
+
+    useEffect(() => {
+        console.log("filteredExp: ",filteredExp);
+        if (filteredExp) {
+            setSelectedExperiment(filteredExp);
+        }
+    },[filteredExp]);
+
+    return(
+        <div className={styles.main}>
+            <Toolbar />
+            {
+                filteredExp && isSocketConnected ?
+                <>
+                    <Accordion defaultExpanded={true}>
+                        <AccordionSummary>
+                            <div className={styles.accordian_heading}>Details</div>
+                        </AccordionSummary>
+                        <AccordionDetails className={styles.accordian_details}>
+                            <ExperimentDetails selectedExperiment={selectedExperiment}/>
+                        </AccordionDetails>
+                    </Accordion>
+                    <Accordion defaultExpanded={true}>
+                        <AccordionSummary aria-controls="panel2d-content" id="panel2d-header">
+                            <div className={styles.accordian_heading}>Progress</div>
+                        </AccordionSummary>
+                        <AccordionDetails>
+                            <ExperimentProgress selectedExperiment={selectedExperiment}/>
+                        </AccordionDetails>
+                    </Accordion>
+                    <Accordion defaultExpanded={true}>
+                        <AccordionSummary aria-controls="panel2d-content" id="panel2d-header">
+                            <div className={styles.accordian_heading}>Model Cards</div>
+                        </AccordionSummary>
+                        <AccordionDetails>
+                            <ModelCards experimentIdProp={experiment_id.toString()}/>
+                        </AccordionDetails>
+                    </Accordion>
+                    {
+                        filteredExp && filteredExp.hasOwnProperty("experiment_id") ?
+                        <Accordion defaultExpanded={true}>
+                            <AccordionSummary aria-controls="panel2d-content" id="panel2d-header">
+                                <div className={styles.accordian_heading}>Configurations</div>
+                            </AccordionSummary>
+                            <AccordionDetails>
+                                <Grid container spacing={{ xs: 2, sm: 2, md: 2, lg: 2 }}>
+                                    <Grid item={true} xs={12} sm={12} md={3}>
+                                        <CheckpointConfigurations experimentIdProp={filteredExp!.experiment_id.toString()}/>
+                                    </Grid>
+                                    <Grid item={true} xs={12} sm={12} md={9}>
+                                        <ExperimentConfigurations experimentIdProp={filteredExp!.experiment_id.toString()}/>
+                                    </Grid>
+                                </Grid>
+                            </AccordionDetails>
+                        </Accordion>
+                        :
+                        null
+                    }
+                    <Accordion defaultExpanded={true}>
+                        <AccordionSummary>
+                            <div className={styles.accordian_heading}>Losses & Metrics</div>
+                        </AccordionSummary>
+                        <AccordionDetails>
+                            {
+                                Object.keys(selectedExpGraphs).length > 0 ?
+                                <Grid container rowSpacing={1} spacing={{ xs: 2, md: 3 }} className={styles_graphs.grid_container}>
+                                    {
+                                        Object.keys(selectedExpGraphs).map((chart_id) => 
+                                            <Graph 
+                                                key={chart_id.toString()} 
+                                                chart_id={chart_id.toString()} 
+                                                exp_id={selectedExpGraphs[chart_id].exp_id.toString()}
+                                                exp_data={selectedExpGraphs[chart_id].data}
+                                            />
+                                        )
+                                    }
+                                </Grid>
+                                :
+                                <Box className={styles_graphs.no_data_to_viz}>
+                                    --- No Data To Visualize ---
+                                </Box>
+                            }
+                        </AccordionDetails>
+                    </Accordion>
+                </>
+                :
+                isSocketConnected ?
+                <div className={styles.extra_text_container}>
+                    <div className={styles.error_text_no_data_1}> No Data Available </div>
+                    <div className={styles.error_text_no_data_2}> (Please wait, experiment details might be loading...) </div>
+                </div>
+                :
+                null
+            }
+        </div>
+    )
+}
+
+export default ExperimentPage;
\ No newline at end of file
diff --git a/src/ml_board/frontend/Dashboard/src/components/experimentPage/ExperimentProgress/ExperimentProgress.tsx b/src/ml_board/frontend/Dashboard/src/components/experimentPage/ExperimentProgress/ExperimentProgress.tsx
new file mode 100644
index 00000000..f8df9d0a
--- /dev/null
+++ b/src/ml_board/frontend/Dashboard/src/components/experimentPage/ExperimentProgress/ExperimentProgress.tsx
@@ -0,0 +1,102 @@
+import styles from '../ExperimentPage.module.css';
+import { Card, CardContent, Grid } from '@mui/material';
+import HalfDonoughtGraph from '../HalfDonoughtGraph/HalfDonoughtGraph';
+import { AnyKeyValuePairsInterface } from '../ExperimentPage';
+
+export function ExperimentProgress({selectedExperiment} : {selectedExperiment: AnyKeyValuePairsInterface }) {
+
+    return (
+        <Grid container rowSpacing={1} spacing={{ xs: 1, md: 2 }}>
+            <Grid item={true} xs={12} sm={12} md={6}>
+                <Card className={styles.card}>
+                    <CardContent>
+                        <div className={styles.card_content_typography} >
+                            <div className={styles.cardcontent_typography}>
+                                <div>
+                                    Epoch Details: 
+                                </div>
+                                {
+                                    selectedExperiment.hasOwnProperty("current_epoch") && selectedExperiment.hasOwnProperty("num_epochs") ?
+                                    <div>
+                                        {selectedExperiment.current_epoch} / {selectedExperiment.num_epochs}
+                                    </div>
+                                    :
+                                    <div>--</div>
+                                }
+                            </div>
+                        </div>
+                        <div className={styles.donought_container}>
+                            {
+                                selectedExperiment.hasOwnProperty("current_epoch") ?
+                                <HalfDonoughtGraph 
+                                    graph_data={
+                                        [
+                                            selectedExperiment.epoch_progress,
+                                            (1-selectedExperiment.epoch_progress)
+                                        ]
+                                    }
+                                    label_data={
+                                        [
+                                            selectedExperiment.epoch_progress*100+"%",
+                                            (1-selectedExperiment.epoch_progress)*100+"%"
+                                        ]
+                                    }
+                                />
+                                :
+                                <HalfDonoughtGraph 
+                                    graph_data={[0,100]}
+                                    label_data={["--","--"]}
+                                />
+                            }
+                        </div>
+                    </CardContent>
+                </Card>
+            </Grid>
+            <Grid item={true} xs={12} sm={12} md={6}>
+                <Card className={styles.card}>
+                    <CardContent>
+                        <div className={styles.card_content_typography} >
+                            <div className={styles.cardcontent_typography}>
+                                <div>
+                                    Batch Details: 
+                                </div>
+                                {
+                                    selectedExperiment.hasOwnProperty("current_batch") && selectedExperiment.hasOwnProperty("num_batches") ?
+                                    <div>
+                                        {selectedExperiment.current_batch} / {selectedExperiment.num_batches}
+                                    </div>
+                                    :
+                                    <div>--</div>
+                                }
+                            </div>
+                        </div>
+                        <div className={styles.donought_container}>
+                            {
+                                selectedExperiment.hasOwnProperty("batch_progress") && selectedExperiment.batch_progress ?
+                                <HalfDonoughtGraph
+                                    graph_data={
+                                        [
+                                            selectedExperiment.batch_progress,
+                                            1-selectedExperiment.batch_progress
+                                        ]
+                                    }
+                                    label_data={
+                                        [
+                                            selectedExperiment.batch_progress*100+"%",
+                                            (1-selectedExperiment.batch_progress)*100+"%"
+                                        ]
+                                    }
+                                />
+                                :
+                                <HalfDonoughtGraph 
+                                    graph_data={[0,100]}
+                                    label_data={["--","--"]}
+                                />
+                            }
+                        </div>
+                    </CardContent>
+                </Card>
+            </Grid>
+        </Grid>
+    );
+}
\ No newline at end of file
diff --git a/src/ml_board/frontend/Dashboard/src/components/experimentPage/HalfDonoughtGraph/HalfDonoughtGraph.module.css b/src/ml_board/frontend/Dashboard/src/components/experimentPage/HalfDonoughtGraph/HalfDonoughtGraph.module.css
new file mode 100644
index 00000000..e5d8315a
--- /dev/null
+++ b/src/ml_board/frontend/Dashboard/src/components/experimentPage/HalfDonoughtGraph/HalfDonoughtGraph.module.css
@@ -0,0 +1,4 @@
+.donought {
+    max-height: 250px !important;
+    max-width: 250px !important;
+}
\ No newline at end of file
diff --git a/src/ml_board/frontend/Dashboard/src/components/experimentPage/HalfDonoughtGraph/HalfDonoughtGraph.tsx b/src/ml_board/frontend/Dashboard/src/components/experimentPage/HalfDonoughtGraph/HalfDonoughtGraph.tsx
new file mode 100644
index 00000000..b5189d5d
--- /dev/null
+++ b/src/ml_board/frontend/Dashboard/src/components/experimentPage/HalfDonoughtGraph/HalfDonoughtGraph.tsx
@@ -0,0 +1,74 @@
+
+import { Doughnut } from 'react-chartjs-2';
+import styles from './HalfDonoughtGraph.module.css';
+import { Chart as ChartJS, Filler, ArcElement, Tooltip, Legend } from 'chart.js';
+ChartJS.register(
+    ArcElement,
+    Tooltip,
+    Legend,
+    Filler
+);
+
+interface HalfDonoughtGraphDataProps {
+    graph_data: Array<number>;
+    label_data: Array<string>;
+}
+
+const HalfDonoughtGraph: React.FC<HalfDonoughtGraphDataProps> = (props) => {
+    
+    return (
+        <Doughnut
+            className={styles.donought}
+            data={{
+                labels: props.label_data,
+                datasets: [
+                    {
+                        data: props.graph_data,
+                        backgroundColor: [
+                            "#36A2EB",
+                            "transparent"
+                        ],
+                        borderColor: "#D1D6DC",
+                        borderWidth: 1,
+                    },
+                ],
+            }}
+            options={{
+                animation: {
+                    duration: 0,
+                    easing: 'linear'
+                },
+                plugins: {
+                    legend: {
+                        display: false
+                    },
+                    tooltip: {
+                        enabled: false
+                    }
+                },
+                rotation: -90,
+                circumference: 180,
+                cutout: "70%",
+                maintainAspectRatio: true,
+                responsive: true
+            }}
+            plugins={[{
+                id: "textCenter",
+                beforeDraw: (chart) => {
+                    const {ctx, data} = chart;
+                    let text:any = "--"; // have to use 'any' type here as charts -> data.labels have type 'unknown[]'. So taking data.lables[0] is also unknown.
+                    if (data.labels) {
+                        text = data.labels[0];
+                    }
+                    ctx.font = 'bolder 40px sans-serif';
+                    ctx.fillStyle = '#36A2EB';
+                    ctx.textAlign = 'center';
+                    ctx.fillText(text, chart.getDatasetMeta(0).data[0].x, chart.getDatasetMeta(0).data[0].y);
+                    ctx.save();  
+                }
+            }]}
+        />        
+    );
+}
+
+export default HalfDonoughtGraph;
\ No newline at end of file
diff --git a/src/ml_board/frontend/Dashboard/src/components/experimentPage/ModelCards/ModelCardCudaList.tsx b/src/ml_board/frontend/Dashboard/src/components/experimentPage/ModelCards/ModelCardCudaList.tsx
new file mode 100644
index 00000000..c6c0d321
--- /dev/null
+++ b/src/ml_board/frontend/Dashboard/src/components/experimentPage/ModelCards/ModelCardCudaList.tsx
@@ -0,0 +1,112 @@
+import Table from '@mui/material/Table';
+import TableBody from '@mui/material/TableBody';
+import TableCell, { tableCellClasses } from '@mui/material/TableCell';
+import TableContainer from '@mui/material/TableContainer';
+import TableHead from '@mui/material/TableHead';
+import TableRow from '@mui/material/TableRow';
+import Paper from '@mui/material/Paper';
+import { cudaDeviceListInterface } from './ModelCards';
+import { Box, Card, CardContent, TableFooter, TablePagination } from '@mui/material';
+import styles from './ModelCards.module.css';
+import { useState } from 'react';
+import { styled } from '@mui/material/styles';
+
+const StyledTableCell = styled(TableCell)(({ theme }) => ({
+    [`&.${tableCellClasses.head}`]: {
+      backgroundColor: theme.palette.common.black,
+      color: theme.palette.common.white,
+    }
+}));
+
+const StyledTableRow = styled(TableRow)(({ theme }) => ({
+    '&:nth-of-type(odd)': {
+      backgroundColor: theme.palette.action.hover,
+    },
+    // hide last border
+    '&:last-child td, &:last-child th': {
+      border: 0,
+    },
+}));
+
+export default function ModelCardCudaList({cardTitle, cudaDeviceList} : {cardTitle: string, cudaDeviceList: Array<cudaDeviceListInterface>}) {
+
+    const [page, setPage] = useState(0);
+    const [rowsPerPage, setRowsPerPage] = useState(5);
+    const handleChangePage = (event: unknown, newPage: number) => {
+        setPage(newPage);
+    };
+    const handleChangeRowsPerPage = (event: React.ChangeEvent<HTMLInputElement>) => {
+        setRowsPerPage(parseInt(event.target.value, 10));
+        setPage(0);
+    };
+
+    return(
+        <Box>
+            <div className={styles.model_card_content_typography}>
+                {cardTitle}
+            </div>
+            {
+                cudaDeviceList.length > 0 ?
+                <TableContainer component={Paper}>
+                    <Table size="small" aria-label="a dense table">
+                        <TableHead>
+                            <TableRow className={styles.table_header_bg}>
+                                <StyledTableCell>
+                                    GPU Name
+                                </StyledTableCell>
+                                <StyledTableCell>
+                                    Processor Count Of GPU
+                                </StyledTableCell>
+                                <StyledTableCell>
+                                    GPU Memory&nbsp;(GB)
+                                </StyledTableCell>
+                            </TableRow>
+                        </TableHead>
+                        <TableBody>
+                            {
+                                (rowsPerPage > 0 ? cudaDeviceList.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
+                                :
+                                cudaDeviceList
+                                ).map((row, index) => (
+                                    <StyledTableRow key={index}>
+                                        <TableCell>
+                                            {row.name}
+                                        </TableCell>
+                                        <TableCell>
+                                            {row.multi_proc_count}
+                                        </TableCell>
+                                        <TableCell>
+                                            {row.total_memory}
+                                        </TableCell>
+                                    </StyledTableRow>
+                                ))
+                            }
+                        </TableBody>
+                        <TableFooter>
+                            <TableRow>
+                                <TablePagination
+                                    rowsPerPageOptions={[5, 10, 25, { label: 'All', value: -1 }]}
+                                    count={cudaDeviceList.length}
+                                    rowsPerPage={rowsPerPage}
+                                    page={page}
+                                    onPageChange={handleChangePage}
+                                    onRowsPerPageChange={handleChangeRowsPerPage}
+                                />
+                            </TableRow>
+                        </TableFooter>
+                    </Table>
+                </TableContainer>
+                :
+                <Card>
+                    <CardContent>
+                        <div className={styles.cardcontent_model_cards}>
+                            <div className={styles.loading_text}>
+                                No Data Available
+                            </div>
+                        </div>
+                    </CardContent>
+                </Card>
+            }
+        </Box>
+    );
+}
\ No newline at end of file
diff --git a/src/ml_board/frontend/Dashboard/src/components/experimentPage/ModelCards/ModelCardPythonPackagesList.tsx b/src/ml_board/frontend/Dashboard/src/components/experimentPage/ModelCards/ModelCardPythonPackagesList.tsx
new file mode 100644
index 00000000..6d55b9ee
--- /dev/null
+++ b/src/ml_board/frontend/Dashboard/src/components/experimentPage/ModelCards/ModelCardPythonPackagesList.tsx
@@ -0,0 +1,102 @@
+import Table from '@mui/material/Table';
+import TableBody from '@mui/material/TableBody';
+import TableCell, { tableCellClasses } from '@mui/material/TableCell';
+import TableContainer from '@mui/material/TableContainer';
+import TableHead from '@mui/material/TableHead';
+import TableRow from '@mui/material/TableRow';
+import Paper from '@mui/material/Paper';
+import { Box, Card, CardContent, TableFooter, TablePagination } from '@mui/material';
+import styles from './ModelCards.module.css';
+import { useState } from 'react';
+import { styled } from '@mui/material/styles';
+import { pythonPackagesListInterface } from './ModelCards';
+
+const StyledTableCell = styled(TableCell)(({ theme }) => ({
+    [`&.${tableCellClasses.head}`]: {
+      backgroundColor: theme.palette.common.black,
+      color: theme.palette.common.white,
+    }
+}));
+
+const StyledTableRow = styled(TableRow)(({ theme }) => ({
+    '&:nth-of-type(odd)': {
+      backgroundColor: theme.palette.action.hover,
+    },
+    // hide last border
+    '&:last-child td, &:last-child th': {
+      border: 0,
+    },
+}));
+
+export default function ModelCardCudaList({cardTitle, pythonPackagesList} : {cardTitle: string, pythonPackagesList: Array<pythonPackagesListInterface>}) {
+
+    const [page, setPage] = useState(0);
+    const [rowsPerPage, setRowsPerPage] = useState(5);
+    const handleChangePage = (event: unknown, newPage: number) => {
+        setPage(newPage);
+    };
+    const handleChangeRowsPerPage = (event: React.ChangeEvent<HTMLInputElement>) => {
+        setRowsPerPage(parseInt(event.target.value, 10));
+        setPage(0);
+    };
+
+    return(
+        <Box>
+            <div className={styles.model_card_content_typography}>
+                {cardTitle}
+            </div>
+            {
+                pythonPackagesList.length > 0 ?
+                <TableContainer component={Paper}>
+                    <Table size="small" aria-label="a dense table">
+                        <TableHead>
+                            <TableRow>
+                                <StyledTableCell>Package Name</StyledTableCell>
+                                <StyledTableCell>Package Version</StyledTableCell>
+                            </TableRow>
+                        </TableHead>
+                        <TableBody>
+                            {
+                                (rowsPerPage > 0 ? pythonPackagesList.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
+                                :
+                                pythonPackagesList
+                                ).map((row, index) => (
+                                    <StyledTableRow key={index}>
+                                        <TableCell>
+                                            {row.name}
+                                        </TableCell>
+                                        <TableCell>
+                                            {row.version}
+                                        </TableCell>
+                                    </StyledTableRow>
+                                ))
+                            }
+                        </TableBody>
+                        <TableFooter>
+                            <TableRow>
+                                <TablePagination
+                                    rowsPerPageOptions={[5, 10, 25, { label: 'All', value: -1 }]}
+                                    count={pythonPackagesList.length}
+                                    rowsPerPage={rowsPerPage}
+                                    page={page}
+                                    onPageChange={handleChangePage}
+                                    onRowsPerPageChange={handleChangeRowsPerPage}
+                                />
+                            </TableRow>
+                        </TableFooter>
+                    </Table>
+                </TableContainer>
+                :
+                <Card>
+                    <CardContent>
+                        <div className={styles.cardcontent_model_cards}>
+                            <div className={styles.loading_text}>
+                                No Data Available
+                            </div>
+                        </div>
+                    </CardContent>
+                </Card>
+            }
+        </Box>
+    );
+}
\ No newline at end of file
diff --git a/src/ml_board/frontend/Dashboard/src/components/experimentPage/ModelCards/ModelCards.module.css b/src/ml_board/frontend/Dashboard/src/components/experimentPage/ModelCards/ModelCards.module.css
new file mode 100644
index 00000000..d0c3ad14
--- /dev/null
+++ b/src/ml_board/frontend/Dashboard/src/components/experimentPage/ModelCards/ModelCards.module.css
@@ -0,0 +1,35 @@
+.cardcontent_model_cards {
+    display: flex;
+    flex-direction: row;
+    justify-content: center;
+    align-items: center;
+}
+
+.error_text {
+    font-family: sans-serif;
+    color: red;
+    font-weight: bold;
+    font-size: 25px;
+}
+
+.loading_text {
+    font-family: sans-serif;
+    font-size: 20px;
+    margin-top: 10px;
+}
+
+.model_card_content_typography {
+    color: gray;
+    margin-bottom: 10px;
+    font-family: sans-serif;
+}
+
+.table_header_bg {
+    background-color: rgb(147, 147, 147);
+    color: white;
+}
+
+.table_header_text {
+    color: white;
+    font-weight: bold;
+}
\ No newline at end of file
diff --git a/src/ml_board/frontend/Dashboard/src/components/experimentPage/ModelCards/ModelCards.tsx b/src/ml_board/frontend/Dashboard/src/components/experimentPage/ModelCards/ModelCards.tsx
new file mode 100644
index 00000000..9f2585d1
--- /dev/null
+++ b/src/ml_board/frontend/Dashboard/src/components/experimentPage/ModelCards/ModelCards.tsx
@@ -0,0 +1,124 @@
+import { Grid, Card, CardContent } from '@mui/material';
+import { useEffect, useState } from 'react';
+import axios from 'axios';
+import api from '../../../app/ApiMaster';
+import { useAppSelector } from "../../../app/hooks";
+import { getGridSearchId, getRestApiUrl } from '../../../redux/status/statusSlice';
+import styles from './ModelCards.module.css';
+import { AnyKeyValuePairsInterface } from '../ExperimentPage';
+import { CardDetails } from '../ExperimentDetails/CardDetails';
+import ModelCardCudaList from './ModelCardCudaList';
+import ModelCardPythonPackagesList from './ModelCardPythonPackagesList';
+
+export interface pythonPackagesListInterface {
+    "name": string,
+    "version": string
+}
+
+export interface cudaDeviceListInterface {
+    "name": string,
+    "multi_proc_count": string,
+    "total_memory": string
+}
+let sysInfoAnyKeyObj:AnyKeyValuePairsInterface = {};
+
+export default function ModelCards({experimentIdProp} : {experimentIdProp: string}) {
+
+    const grid_search_id = useAppSelector(getGridSearchId);
+    const rest_api_url = useAppSelector(getRestApiUrl);
+    const [error, setError] = useState("");
+    const [isLoading, setIsLoading] = useState(false);
+    const[sysInfoBasicData, setSysInfoBasicData] = useState(sysInfoAnyKeyObj);
+    const[sysInfoCudaDevicesData, setSysInfoCudaDevicesData] = useState(Array<cudaDeviceListInterface>);
+    const[sysInfoPythonPackages, setSysInfoPythonPackages] = useState([]);
+
+
+    useEffect(() => {
+        if(experimentIdProp) {
+            getSysInfo();
+        }
+    },[experimentIdProp]);
+
+    function getSysInfo() {
+        let model_card_sys_info = api.model_card_sys_info.replace("<grid_search_id>", grid_search_id);
+        model_card_sys_info = model_card_sys_info.replace("<experiment_id>", experimentIdProp);
+
+        setError("");
+        setIsLoading(true);
+
+        axios.get(rest_api_url + model_card_sys_info).then((response) => {
+            console.log("Got response from model_card_sys_info API: ", response);
+            if (response.status === 200) {
+                let resp_data = response.data;
+                Object.keys(resp_data).map((sysInfoKeyName) => {
+                    if(sysInfoKeyName === "cuda_device_list") {
+                        setSysInfoCudaDevicesData(resp_data[sysInfoKeyName]);
+                    }
+                    else if(sysInfoKeyName === "python-packages") {
+                        setSysInfoPythonPackages(resp_data[sysInfoKeyName])
+                    }
+                    else {
+                        sysInfoBasicData[sysInfoKeyName] = resp_data[sysInfoKeyName];
+                    }
+                });
+                setSysInfoBasicData(sysInfoBasicData);
+            }
+            else {
+                setError("Error occured / No system info available");
+            }
+            setIsLoading(false);
+        })
+        .catch((error) => {
+            console.log("Error in model_card_sys_info: ", error);
+            setIsLoading(false);
+            setError("Error occured / No system info available");
+        });
+    }
+
+    return(
+        <Grid container spacing={{ xs: 2, sm: 2, md: 2, lg: 2 }}>
+            <Grid item={true} xs={12} sm={12} md={12} lg={12}>
+            {
+                isLoading ?
+                <Card className={styles.cardcontent_model_cards}>
+                    <CardContent>
+                        <div className={styles.loading_text}> 
+                            Please wait, loading model cards...
+                        </div>
+                    </CardContent>
+                </Card>
+                :
+                error.length > 0 ?
+                <Card className={styles.cardcontent_model_cards}>
+                    <CardContent>
+                        <div className={styles.error_text}> 
+                            {error}
+                        </div>
+                    </CardContent>
+                </Card>
+                :
+                <Grid container rowSpacing={1} spacing={{ xs: 1, md: 2 }}>
+                    <Grid item={true} xs={12} sm={12} md={4}>
+                        <CardDetails
+                            cardTitle="System Info"
+                            contentObj={sysInfoBasicData}
+                        />
+                    </Grid>
+                    <Grid item={true} xs={12} sm={12} md={4}>
+                        <ModelCardCudaList 
+                            cardTitle="Cuda Devices List" 
+                            cudaDeviceList={sysInfoCudaDevicesData}
+                        />
+                    </Grid>
+                    <Grid item={true} xs={12} sm={12} md={4}>
+                        <ModelCardPythonPackagesList 
+                            cardTitle="Python Packages List" 
+                            pythonPackagesList={sysInfoPythonPackages}
+                        />
+                    </Grid>
+                </Grid>
+            }
+            </Grid>
+        </Grid>
+    );
+}
\ No newline at end of file
diff --git a/src/ml_board/frontend/Dashboard/src/components/graphs/Graph.tsx b/src/ml_board/frontend/Dashboard/src/components/graphs/Graph.tsx
index 4404a81a..36a79f24 100644
--- a/src/ml_board/frontend/Dashboard/src/components/graphs/Graph.tsx
+++ b/src/ml_board/frontend/Dashboard/src/components/graphs/Graph.tsx
@@ -3,28 +3,43 @@ import { ChartData, ChartOptions } from "chart.js";
 import { Line } from "react-chartjs-2";
 import { useAppSelector } from "../../app/hooks";
 import { selectChartLabelsById, selectExperimentsPerChartById } from "../../redux/charts/chartsSlice";
-import { selectColorMap } from "../../redux/status/statusSlice";
 // styles
 import styles from "./Graphs.module.css";
 
+const selectColor = (index: number): string => `hsl(${index * 137.5},75%,50%)`;
+
 // https://www.chartjs.org/docs/latest/general/data-structures.html
 
-export default function Graph({ chart_id }: { chart_id: string }) {
+export default function Graph({ chart_id, exp_id, exp_data }: { chart_id: string, exp_id?:string, exp_data?: Array<number> }) {
 
     const chartLabels = useAppSelector(state => selectChartLabelsById(state, chart_id));
     const experimentsDict = useAppSelector(state => selectExperimentsPerChartById(state, chart_id));
-    const colors = useAppSelector(selectColorMap);
 
     // prepare data (Warning Looping!)
     const data: ChartData<"line"> = {
-        labels: chartLabels, // the X-axis:Array<number>
-        datasets: !experimentsDict ? [] :
-            // loop over the experiments in the ChartF
+        // labels = the X-axis:Array<number>
+        labels: 
+            exp_id && exp_data ?
+            Array.from({ length: exp_data.length }, (_, i) => i)
+            :
+            chartLabels, 
+        datasets: 
+            exp_id && exp_data ?
+            [{
+                label: "experiment_" + exp_id, // exp_name
+                data: exp_data, // exp_values:Array<number>, Y-axis, same size as X-axis
+                backgroundColor: selectColor(Number(exp_id)),
+                borderColor: selectColor(Number(exp_id)),
+            }]
+            :
+            !experimentsDict ? 
+            [] 
+            :
             Object.values(experimentsDict).map(exp => ({
                 label: "experiment_" + exp!.exp_id, // exp_name
                 data: exp!.data, // exp_values:Array<number>, Y-axis, same size as X-axis
-                backgroundColor: colors[exp!.exp_id],
-                borderColor: colors[exp!.exp_id],
+                backgroundColor: selectColor(exp!.exp_id),
+                borderColor: selectColor(exp!.exp_id),
             })),
     };
 
@@ -40,14 +55,14 @@ export default function Graph({ chart_id }: { chart_id: string }) {
                 pointRadius:0,
                 // showLine: false,
                 // // Automatic data decimation during draw happens if these 3 values are left as default!
-                // tension:0,
+                // tension:0, // 0 for straight lines otherwise curvy lines
                 // stepped:false,
                 // borderDash:[],
             }
         },
         plugins: {
             title: {
-                text: chart_id,
+                text: chart_id.toLowerCase().split("_").join(" "),
                 display: true,
                 color: 'black',
                 font: {
diff --git a/src/ml_board/frontend/Dashboard/src/components/settings/GridSearchConfigurations/GridSearchConfigurations.module.css b/src/ml_board/frontend/Dashboard/src/components/settings/GridSearchConfigurations/GridSearchConfigurations.module.css
new file mode 100644
index 00000000..46a91563
--- /dev/null
+++ b/src/ml_board/frontend/Dashboard/src/components/settings/GridSearchConfigurations/GridSearchConfigurations.module.css
@@ -0,0 +1,14 @@
+.textfield_cardcontent_grid_search_config {
+    display: flex;
+    flex-direction: row;
+    justify-content: space-between;
+    align-items: center;
+}
+
+.yaml_content_overflow {
+    overflow: auto
+}
+
+.heading_style {
+    font-family: sans-serif;
+}
\ No newline at end of file
diff --git a/src/ml_board/frontend/Dashboard/src/components/settings/GridSearchConfigurations/GridSearchConfigurations.tsx b/src/ml_board/frontend/Dashboard/src/components/settings/GridSearchConfigurations/GridSearchConfigurations.tsx
new file mode 100644
index 00000000..855cb56b
--- /dev/null
+++ b/src/ml_board/frontend/Dashboard/src/components/settings/GridSearchConfigurations/GridSearchConfigurations.tsx
@@ -0,0 +1,115 @@
+import { Grid, Card, CardContent, IconButton, Switch, FormControlLabel, Box, LinearProgress } from '@mui/material';
+import { Download } from '@mui/icons-material';
+import { useEffect, useState } from 'react';
+import axios from 'axios';
+import api, { defaultGridSearchConfigFileName } from '../../../app/ApiMaster';
+import { useAppSelector } from "../../../app/hooks";
+import { getGridSearchId, getRestApiUrl } from '../../../redux/status/statusSlice';
+import styles from './GridSearchConfigurations.module.css';
+
+export default function GridSearchConfigurations() {
+    
+    const [yamlString, setYamlString] = useState("");
+    const [error, setError] = useState("");
+    const [isLoading, setIsLoading] = useState(false);
+    const [showHideData, setShowHideData] = useState(false);
+    const grid_search_id = useAppSelector(getGridSearchId);
+    const rest_api_url = useAppSelector(getRestApiUrl);
+
+    useEffect(() => {
+        let grid_search_config_url = api.gridsearch_config_file.replace("<grid_search_id>", grid_search_id);
+
+        setError("");
+        setShowHideData(false);
+        setIsLoading(true);
+        
+        axios.get(rest_api_url+grid_search_config_url).then((response) => {
+            console.log("Got response from grid_search_config_file API: ", response);
+            if(response.status === 200) {
+                setYamlString(response.data.trim());
+                setShowHideData(true);
+            }
+            else {
+                setError("Oops! an error occurred");
+            }
+            setIsLoading(false);
+        })
+        .catch((error) => {
+            console.log("Error in grid_search_config_file: ", error);
+            setIsLoading(false);
+            setError("Oops! an error occurred");
+        });
+
+    },[]);
+
+    function downloadFile() {
+        const blob = new Blob([yamlString], { type: 'text/yaml' });
+        const url = window.URL.createObjectURL(blob!);
+        const a = document.createElement('a');
+        a.href = url;
+        a.download = defaultGridSearchConfigFileName+".yml";
+        document.body.appendChild(a);
+        a.click();
+        document.body.removeChild(a);
+    }
+
+    return(
+        <Grid container spacing={{ xs: 2, sm: 2, md: 2, lg: 2 }}>
+            <Grid item={true} xs={12} sm={12} md={12} lg={12}>
+                <Box className={styles.textfield_cardcontent_grid_search_config}>
+                    <h2 className={styles.heading_style}>Grid Search Configuration</h2>
+                    <div>
+                    {
+                        !isLoading && error.length === 0 && yamlString.length > 0 ?
+                        <IconButton 
+                            size="large"
+                            onClick={()=>downloadFile()}
+                        >
+                            <Download /> 
+                        </IconButton>
+                        :
+                        null
+                    }
+                    {
+                        !isLoading && error.length === 0 && yamlString.length > 0 ?
+                        <FormControlLabel
+                            control={
+                                <Switch
+                                    checked={showHideData}
+                                    color="primary"
+                                    onChange={()=>setShowHideData(!showHideData)}
+                                />
+                            }
+                            label={"View/Hide"}
+                        />
+                        :
+                        null
+                    }
+                    </div>
+                </Box>
+            </Grid>
+            {
+                isLoading ?
+                <Grid item={true} xs={12} sm={12} md={12} lg={12}>
+                    <Box>
+                        <LinearProgress />
+                    </Box>
+                </Grid>
+                :
+                null
+            }
+            {
+                !isLoading && error.length === 0 && Object.keys(yamlString).length > 0 && showHideData ?
+                <Grid item={true} xs={12} sm={12} md={12} lg={12}>
+                    <Card>
+                        <CardContent className={styles.yaml_content_overflow}>
+                            <pre>{yamlString}</pre>
+                        </CardContent>
+                    </Card>
+                </Grid>
+                :
+                null
+            }
+        </Grid>
+    );
+}
\ No newline at end of file
diff --git a/src/ml_board/frontend/Dashboard/src/components/settings/SelectExperimentDropdown/SelectExperimentDropdown.module.css b/src/ml_board/frontend/Dashboard/src/components/settings/SelectExperimentDropdown/SelectExperimentDropdown.module.css
new file mode 100644
index 00000000..d69d2c93
--- /dev/null
+++ b/src/ml_board/frontend/Dashboard/src/components/settings/SelectExperimentDropdown/SelectExperimentDropdown.module.css
@@ -0,0 +1,10 @@
+.heading_style {
+    font-family: sans-serif;
+}
+
+.textfield_cardcontent_select_experiment {
+    display: flex;
+    flex-direction: row;
+    justify-content: center;
+    align-items: center;
+}
\ No newline at end of file
diff --git a/src/ml_board/frontend/Dashboard/src/components/settings/SelectExperimentDropdown/SelectExperimentDropdown.tsx b/src/ml_board/frontend/Dashboard/src/components/settings/SelectExperimentDropdown/SelectExperimentDropdown.tsx
new file mode 100644
index 00000000..c680448a
--- /dev/null
+++ b/src/ml_board/frontend/Dashboard/src/components/settings/SelectExperimentDropdown/SelectExperimentDropdown.tsx
@@ -0,0 +1,129 @@
+import { getGridSearchId, getRestApiUrl } from '../../../redux/status/statusSlice';
+import api from '../../../app/ApiMaster';
+import axios from 'axios';
+import { useEffect, useState } from 'react';
+import { useAppSelector } from "../../../app/hooks";
+import { Grid, Box, LinearProgress, Button } from '@mui/material';
+import FormHelperText from '@mui/material/FormHelperText';
+import FormControl from '@mui/material/FormControl';
+import Select from '@mui/material/Select';
+import InputLabel from '@mui/material/InputLabel';
+import MenuItem from '@mui/material/MenuItem';
+import SendIcon from '@mui/icons-material/Send';
+import styles from './SelectExperimentDropdown.module.css';
+import { useNavigate } from 'react-router-dom';
+import { AnyKeyValuePairsInterface } from '../../experimentPage/ExperimentPage';
+
+export default function SelectExperimentDropdown() {
+    
+    const [experimentIdsInDropdown, setExperimentIdsInDropdown] = useState(Array<string>);
+    const [selectedExperiment, setSelectedExperiment] = useState("");
+    const [error, setError] = useState("");
+    const [isLoading, setIsLoading] = useState(false);
+    const grid_search_id = useAppSelector(getGridSearchId);
+    const rest_api_url = useAppSelector(getRestApiUrl);
+    const navigate = useNavigate();
+
+    useEffect(() => {
+
+        setError("");
+        setIsLoading(true);
+
+        let experiments_url = api.experiments.replace("<grid_search_id>", grid_search_id);
+        axios.get(rest_api_url + experiments_url).then((response) => {
+            console.log("Got response from experiments API: ", response);
+            if(response.status === 200) {
+                if (response.data.length > 0) {
+                    let experimentIdsInDropdown:Array<string> = [];
+                    response.data.map((exp_data:AnyKeyValuePairsInterface ) => {
+                        experimentIdsInDropdown.push(exp_data.experiment_id.toString());
+                    });
+                    experimentIdsInDropdown.sort();
+                    setExperimentIdsInDropdown(experimentIdsInDropdown);
+                    setSelectedExperiment(experimentIdsInDropdown[0]);
+                }
+                else {
+                    setError("No Experiments Found!");
+                }
+            }
+            else {
+                setError("Oops! an error occurred");
+            }
+            setIsLoading(false);
+        })
+        .catch((error) => {
+            console.log("Error in experiments API: ", error);
+            setIsLoading(false);
+            setError("Oops! an error occurred");
+        });
+    },[]);
+
+    function goToSelectedExperiment() {
+        if (selectedExperiment !== "") {
+            navigate({
+                pathname: '/experiment',
+                search: '?experiment_id='+selectedExperiment,
+            });
+        }
+    }
+
+    function setSelectedExpValue(value: string) {
+        setSelectedExperiment(value);
+    }
+
+    return(
+        <div>
+            <h2 className={styles.heading_style}>Experiment Details</h2>
+            <Grid container spacing={{ xs: 2, sm: 2, md: 2, lg: 2 }}>
+                <Grid item={true} xs={12} sm={12} md={12} lg={12}>
+                    <Box className={styles.textfield_cardcontent_select_experiment}>
+                        <FormControl fullWidth={true} error={error.length > 0}>
+                            <InputLabel id="demo-simple-select-helper-label">Experiment Id</InputLabel>
+                            <Select
+                                labelId="demo-simple-select-helper-label"
+                                id="demo-simple-select-helper"
+                                value={selectedExperiment}
+                                label="Experiment Id"
+                                onChange={(e)=>setSelectedExpValue(e.target.value)}
+                                MenuProps={{ style: { maxHeight: "250px" } }} // have to keep style here. keeping it in css file is not working for this
+                            >
+                                {
+                                    experimentIdsInDropdown.map((exp_id)=> 
+                                        <MenuItem key={exp_id} value={exp_id}>{exp_id}</MenuItem>
+                                    )
+                                }
+                            </Select>
+                            {
+                                error.length > 0 ?
+                                <FormHelperText>
+                                    {error}
+                                </FormHelperText>
+                                :
+                                null
+                            }
+                        </FormControl>
+                        <Button 
+                            variant="contained" 
+                            size="large" 
+                            endIcon={<SendIcon />}
+                            onClick={()=>goToSelectedExperiment()}
+                            disabled={isLoading || error.length > 0}
+                        >
+                            
+                        </Button>
+                    </Box>
+                </Grid>
+                {
+                    isLoading ?
+                    <Grid item={true} xs={12} sm={12} md={12} lg={12}>
+                        <Box>
+                            <LinearProgress />
+                        </Box>
+                    </Grid>
+                    :
+                    null
+                }
+            </Grid>
+        </div>
+    );
+}
\ No newline at end of file
diff --git a/src/ml_board/frontend/Dashboard/src/components/settings/Settings.module.css b/src/ml_board/frontend/Dashboard/src/components/settings/Settings.module.css
index 1b828db8..dc38e952 100644
--- a/src/ml_board/frontend/Dashboard/src/components/settings/Settings.module.css
+++ b/src/ml_board/frontend/Dashboard/src/components/settings/Settings.module.css
@@ -2,10 +2,14 @@
     display: flex;
     flex-direction: column;
     align-items: center;
-    padding-top: 5%;
+    padding-top: 2%;
 }
 
-.settings_text_box {
+.settings_text_box_full_width {
+    width: 100%;
+}
+
+.settings_text_box_less_width {
     width: 60%;
 }
 
@@ -14,6 +18,31 @@
     flex-direction: row;
     align-items: center;
     justify-content: center;
-    width: 60%;
-    gap: 40px
+    width: 100%;
+    gap: 40px;
+    margin-top: 20px;
+    margin-bottom: 40px;
+}
+
+.grid_container_basic_fields {
+    padding-left: 30px;
+    padding-right: 30px;
+}
+
+.grid_item_basic_fields {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    margin-bottom: 20px;
+}
+
+.grid_search_config_contianer {
+    padding-left: 30px;
+    padding-right: 30px;
+    display: flex;
+    flex-direction: column;
+}
+
+.heading_style {
+    font-family: sans-serif;
 }
\ No newline at end of file
diff --git a/src/ml_board/frontend/Dashboard/src/components/settings/Settings.tsx b/src/ml_board/frontend/Dashboard/src/components/settings/Settings.tsx
index 1e0cbe6f..0595b9e4 100644
--- a/src/ml_board/frontend/Dashboard/src/components/settings/Settings.tsx
+++ b/src/ml_board/frontend/Dashboard/src/components/settings/Settings.tsx
@@ -1,14 +1,19 @@
-import { Box, Button, TextField, Toolbar } from "@mui/material";
+import { Box, Button, TextField, Toolbar, Grid } from "@mui/material";
 import { useCallback, useEffect, useState } from 'react';
 import DeleteIcon from '@mui/icons-material/Delete';
 import SendIcon from '@mui/icons-material/Send';
 import { settingConfigsInterface } from "../../app/App";
+import { isConnected } from "../../redux/status/statusSlice";
+import { useAppSelector } from "../../app/hooks";
+import GridSearchConfigurations from "./GridSearchConfigurations/GridSearchConfigurations";
+import SelectExperimentDropdown from "./SelectExperimentDropdown/SelectExperimentDropdown";
 // styles
 import styles from "./Settings.module.css";
 
 export const defaultGridSearchIdHelperText = "eg: 2022-11-06--17-59-10";
 export const defaultSocketConnectionUrlHelperText = "eg: http://127.0.0.1:5002";
 export const defaultRestApiUrlHelperText = "eg: http://127.0.0.1:5001";
+
 export interface FuncProps {
     validateConfigs(value:boolean): void;
     setConfigData(configData:settingConfigsInterface): void;
@@ -17,6 +22,8 @@ export interface FuncProps {
 // Settings file and Config popup file (except render part) might look exactly the same for now. But Settigns will have more functionality later. So we will add more things in Settings which will make it different from popup file.
 const Settings: React.FC<FuncProps> = (props) => {
 
+    const isSocketConnected = useAppSelector(isConnected);
+
     const [configTextState, setConfigTextState] = useState({
         gridSearchId: "",
         socketConnectionUrl: "",
@@ -78,61 +85,79 @@ const Settings: React.FC<FuncProps> = (props) => {
         <Box>
             <Toolbar/>
             <Box className={styles.settings_main_box}>
-                <TextField
-                    id="outlined-multiline-flexible"
-                    label="Grid Search-id"
-                    placeholder="Enter grid search-id here!..."
-                    value={configTextState.gridSearchId}
-                    onChange={(e)=>changeText("gridSearchId", e.target.value)}
-                    className={styles.settings_text_box}
-                    helperText={
-                        defaultGridSearchIdHelperText
-                    }
-                />
-                <br/>
-                <TextField
-                    id="outlined-multiline-flexible"
-                    label="Socket Connection URL"
-                    placeholder="Enter Socker Connection URL here!..."
-                    value={configTextState.socketConnectionUrl}
-                    onChange={(e)=>changeText("socketConnectionUrl", e.target.value)}
-                    className={styles.settings_text_box}
-                    helperText={
-                        defaultSocketConnectionUrlHelperText
-                    }
-                />
-                <br/>
-                <TextField
-                    id="outlined-multiline-flexible"
-                    label="Rest API URL"
-                    placeholder="Enter rest API URL here!..."
-                    value={configTextState.restApiUrl}
-                    onChange={(e)=>changeText("restApiUrl", e.target.value)}
-                    className={styles.settings_text_box}
-                    helperText={
-                        defaultRestApiUrlHelperText
-                    }
-                />
-                <br/>
-                <Box className={styles.setting_form_btns_box}>
-                    <Button 
-                        variant="outlined" 
-                        size="large"
-                        startIcon={<DeleteIcon />}
-                        onClick={()=>clearAllText()}
-                    >
-                        Clear
-                    </Button>
-                    <Button 
-                        variant="contained" 
-                        size="large" 
-                        endIcon={<SendIcon />}
-                        onClick={()=>submitData()}
-                        disabled={validateData()}
-                    >
-                        Save
-                    </Button>
+                <Grid container rowSpacing={1} rowGap={3} spacing={{ xs: 1, md: 2, lg: 2 }} className={styles.grid_container_basic_fields}>
+                    <Grid item={true} xs={12} sm={12} md={12} lg={isSocketConnected?4:12} className={styles.grid_item_basic_fields}>
+                        <TextField
+                            id="outlined-multiline-flexible"
+                            label="Grid Search-id"
+                            placeholder="Enter grid search-id here!..."
+                            value={configTextState.gridSearchId}
+                            onChange={(e)=>changeText("gridSearchId", e.target.value)}
+                            className={isSocketConnected?styles.settings_text_box_full_width:styles.settings_text_box_less_width}
+                            helperText={defaultGridSearchIdHelperText}
+                            fullWidth={isSocketConnected?true:false}
+                        />
+                    </Grid>
+                    <Grid item={true} xs={12} sm={12} md={12} lg={isSocketConnected?4:12} className={styles.grid_item_basic_fields}>
+                        <TextField
+                            id="outlined-multiline-flexible"
+                            label="Socket Connection URL"
+                            placeholder="Enter Socker Connection URL here!..."
+                            value={configTextState.socketConnectionUrl}
+                            onChange={(e)=>changeText("socketConnectionUrl", e.target.value)}
+                            className={isSocketConnected?styles.settings_text_box_full_width:styles.settings_text_box_less_width}
+                            helperText={defaultSocketConnectionUrlHelperText}
+                            fullWidth={isSocketConnected?true:false}
+                        />
+                    </Grid>
+                    <Grid item={true} xs={12} sm={12} md={12} lg={isSocketConnected?4:12} className={styles.grid_item_basic_fields}>
+                        <TextField
+                            id="outlined-multiline-flexible"
+                            label="Rest API URL"
+                            placeholder="Enter rest API URL here!..."
+                            value={configTextState.restApiUrl}
+                            onChange={(e)=>changeText("restApiUrl", e.target.value)}
+                            className={isSocketConnected?styles.settings_text_box_full_width:styles.settings_text_box_less_width}
+                            helperText={defaultRestApiUrlHelperText}
+                            fullWidth={isSocketConnected?true:false}
+                        />
+                    </Grid>
+                </Grid>
+            </Box>
+            {
+                isSocketConnected ?
+                <Box className={styles.grid_search_config_contianer}>
+                    <SelectExperimentDropdown />
+                </Box>
+                :
+                null
+            }
+            {
+                isSocketConnected ?
+                <Box className={styles.grid_search_config_contianer}>
+                    <GridSearchConfigurations />
                 </Box>
+                :
+                null
+            }
+            <Box className={styles.setting_form_btns_box}>
+                <Button 
+                    variant="outlined" 
+                    size="large"
+                    startIcon={<DeleteIcon />}
+                    onClick={()=>clearAllText()}
+                >
+                    Clear
+                </Button>
+                <Button 
+                    variant="contained" 
+                    size="large" 
+                    endIcon={<SendIcon />}
+                    onClick={()=>submitData()}
+                    disabled={validateData()}
+                >
+                    Save
+                </Button>
             </Box>
         </Box>
     )
diff --git a/src/ml_board/frontend/Dashboard/src/components/topbar-with-drawer/TopBarWithDrawer.module.css b/src/ml_board/frontend/Dashboard/src/components/topbar-with-drawer/TopBarWithDrawer.module.css
index a3a304ed..7f6b4baf 100644
--- a/src/ml_board/frontend/Dashboard/src/components/topbar-with-drawer/TopBarWithDrawer.module.css
+++ b/src/ml_board/frontend/Dashboard/src/components/topbar-with-drawer/TopBarWithDrawer.module.css
@@ -27,6 +27,7 @@
 }
 .app_bar_right_corner_logo { 
     color: black !important;
+    margin-right: -20px !important;
 }
 .logo_inside_menu { 
     padding-top: 10px;
diff --git a/src/ml_board/frontend/Dashboard/src/redux/charts/chartsSlice.ts b/src/ml_board/frontend/Dashboard/src/redux/charts/chartsSlice.ts
index 2082fbb7..c4680bbe 100644
--- a/src/ml_board/frontend/Dashboard/src/redux/charts/chartsSlice.ts
+++ b/src/ml_board/frontend/Dashboard/src/redux/charts/chartsSlice.ts
@@ -33,13 +33,13 @@ export const chartsSlice = createSlice({
             // TODO: avoid this big loop !!!
             for (const chartUpdate of payload) {
                 const { chart_id, exp_id, epoch, score } = chartUpdate;
-                if (state.ids.includes(chart_id)) {
+                if (chart_id in state.entities) { //if (state.entities[chart_id] !== undefined)
                     const chart = state.entities[chart_id] as Chart;
                     // update X-axis
-                    if (!chart.x_axis.includes(epoch))
+                    if (!(epoch in chart.x_axis)) // if (chart.x_axis[epoch] != epoch)
                         chart.x_axis.push(epoch)
-                    // if experiment exist push the score otherwise add it as new
-                    if (chart.experiments.ids.includes(exp_id)) {
+                    // if experiment exists, push the score, otherwise add it as new
+                    if (exp_id in chart.experiments.entities) { //if (chart.experiments.entities[exp_id] !== undefined)
                         (chart.experiments.entities[exp_id] as Experiment).data.push(score);
                     } else {
                         chart.experiments = experimentsAdapter.addOne(chart.experiments, {
@@ -69,7 +69,16 @@ export const { upsertCharts } = chartsSlice.actions;
 // TODO: memoize these selectors
 export const selectChartLabelsById = (state: RootState, chart_id: string) => state.charts.entities[chart_id]?.x_axis ?? [];
 export const selectExperimentsPerChartById = (state: RootState, chart_id: string) => state.charts.entities[chart_id]?.experiments.entities ?? {};
-
+export const selectChartsByExperimentId = (state: RootState, exp_id: string) =>{
+    const allExp: {[key: string]: any} = {};
+    for (const chart_id in state.charts.entities) {
+        const experiments = state.charts.entities[chart_id]?.experiments.entities ?? {};
+        if(experiments[exp_id]) {
+            allExp[chart_id] = experiments[exp_id];
+        }
+    }
+    return allExp;
+}
 
 // create a set of memoized selectors
 export const {
diff --git a/src/ml_board/frontend/Dashboard/src/redux/status/statusSlice.ts b/src/ml_board/frontend/Dashboard/src/redux/status/statusSlice.ts
index 0854755b..cb9eaf01 100644
--- a/src/ml_board/frontend/Dashboard/src/redux/status/statusSlice.ts
+++ b/src/ml_board/frontend/Dashboard/src/redux/status/statusSlice.ts
@@ -1,5 +1,4 @@
 import { createSlice, PayloadAction } from '@reduxjs/toolkit';
-import { upsertCharts } from '../charts/chartsSlice';
 import { RootState } from '../store';
 
 // TODO: ASK MAX, renaming to GlobalConfigSlice
@@ -11,8 +10,8 @@ export interface StatusState {
   received_msg_count: number;
   throughput: number;
   grid_search_id: string;
-  color_map: { [expID: string]: string }; // expID mapped to a color
   metric_loss: Array<string>;
+  rest_api_url: string;
 }
 
 const initialState: StatusState = {
@@ -23,8 +22,8 @@ const initialState: StatusState = {
   received_msg_count: 0,
   throughput: 0,
   grid_search_id: "",
-  color_map: {},
-  metric_loss: [] //TODO: redundant??
+  metric_loss: [], //TODO: redundant??
+  rest_api_url: ""
 };
 
 export const statusSlice = createSlice({
@@ -52,33 +51,39 @@ export const statusSlice = createSlice({
     setGridSearchId: (state, action: PayloadAction<string>) => {
       state.grid_search_id = action.payload;
     },
+    setRestApiUrl: (state, action: PayloadAction<string>) => {
+      state.rest_api_url = action.payload;
+    },
     // ASK MAX: To be used if we want to save the Metric or Losses key here for the table
     // I stopped from doing so because then function is going to be called every evaluation_result message!!!
     upsertMetricOrLoss: (state, { payload }: PayloadAction<string[]>) => {
       state.metric_loss.push(...payload);
     }
-  }, extraReducers(builder) {
-    builder.addCase(upsertCharts, (state, { payload }) => {
-      // NOTE: very important to notice here that +4 increment
-      // because in the testing file every evaluation_result held 4 values for the same experiment
-      // this might not be true with other data
-      // TODO:
-      for (let i = 0; i < payload.length; i+=4) {
-        if (!state.color_map.hasOwnProperty(payload[i].exp_id)) {
-          // one can only hope that it doesn't produce a blue blue blue blue blue... pattern :')
-          state.color_map[payload[i].exp_id] = `#${Math.floor(Math.random() * 16777215).toString(16)}`;
-        }
-      }
-    })
-  },
+  }, 
+  // extraReducers(builder) {
+  //   builder.addCase(upsertCharts, (state, { payload }) => {
+  //     // NOTE: very important to notice here that +4 increment
+  //     // because in the testing file every evaluation_result held 4 values for the same experiment
+  //     // this might not be true with other data
+  //     for (let i = 0; i < payload.length; i+=4) {
+  //       if (!state.color_map.hasOwnProperty(payload[i].exp_id)) {
+  //         // one can only hope that it doesn't produce a blue blue blue blue blue... pattern :')
+  //         state.color_map[payload[i].exp_id] = `#${Math.floor(Math.random() * 16777215).toString(16)}`;
+  //       }
+  //     }
+  //   })
+  // },
 });
 
-export const { changeFilter, changeTab, setSocketConnection, setLastPing, incrementReceivedMsgCount, setThroughput } = statusSlice.actions;
+export const { changeFilter, changeTab, setSocketConnection, setLastPing, incrementReceivedMsgCount, setThroughput, setGridSearchId, setRestApiUrl } = statusSlice.actions;
+
 export const selectFilter = (state: RootState) => state.status.currentFilter;
 export const selectTab = (state: RootState) => state.status.idTab;
 export const isConnected = (state: RootState) => state.status.wsConnected;
 export const getLastPing = (state: RootState) => state.status.ping;
 export const getReceivevMsgCount = (state: RootState) => state.status.received_msg_count;
 export const getThroughput = (state: RootState) => state.status.throughput;
-export const selectColorMap = (state: RootState) => state.status.color_map;
+export const getGridSearchId = (state: RootState) => state.status.grid_search_id;
+export const getRestApiUrl = (state: RootState) => state.status.rest_api_url;
+
 export default statusSlice.reducer;
diff --git a/src/ml_board/frontend/Dashboard/src/redux/table/tableSlice.ts b/src/ml_board/frontend/Dashboard/src/redux/table/tableSlice.ts
index cde5ea3a..11c8ee9c 100644
--- a/src/ml_board/frontend/Dashboard/src/redux/table/tableSlice.ts
+++ b/src/ml_board/frontend/Dashboard/src/redux/table/tableSlice.ts
@@ -38,13 +38,6 @@ const rowsAdapter = createEntityAdapter<Row>({
     sortComparer: ({ experiment_id: id1 }: Row, { experiment_id: id2 }: Row) => id1 - id2
 });
 
-// interface RowsState {
-//     // The unique IDs of each Row.
-//     ids: [];
-//     // A lookup table mapping Rows' IDs to the corresponding Row objects
-//     entities: {};
-// }
-
 const initialState: EntityState<Row> = rowsAdapter.getInitialState({});
 
 export const tableSlice = createSlice({
diff --git a/src/ml_board/frontend/Dashboard/src/worker_socket/DataTypes.ts b/src/ml_board/frontend/Dashboard/src/worker_socket/DataTypes.ts
index e28416da..10f789d0 100644
--- a/src/ml_board/frontend/Dashboard/src/worker_socket/DataTypes.ts
+++ b/src/ml_board/frontend/Dashboard/src/worker_socket/DataTypes.ts
@@ -14,6 +14,11 @@ export interface DataFromSocket extends JSON {
     }
 }
 
+export interface BufferedDataFromSocket extends JSON {
+    event_id: string,
+    data: Array<DataFromSocket>
+}
+
 export interface DataToRedux {
     tableData: Row[],
     chartsUpdates: ChartUpdate[],
diff --git a/src/ml_board/frontend/Dashboard/src/worker_socket/MainThreadCallbacks.ts b/src/ml_board/frontend/Dashboard/src/worker_socket/MainThreadCallbacks.ts
index b89a8fcc..6ebd220f 100644
--- a/src/ml_board/frontend/Dashboard/src/worker_socket/MainThreadCallbacks.ts
+++ b/src/ml_board/frontend/Dashboard/src/worker_socket/MainThreadCallbacks.ts
@@ -1,4 +1,4 @@
-import { DataFromSocket, DataToRedux } from "./DataTypes";
+import { BufferedDataFromSocket, DataFromSocket, DataToRedux } from "./DataTypes";
 import { MLGYM_EVENT } from "./EventsTypes";
 import handleEvaluationResultData from "./event_handlers/EvaluationResultHandler";
 import handleExperimentStatusData from "./event_handlers/ExperimentStatusHandler";
@@ -17,6 +17,7 @@ const MapEventToProcess: { [event: string]: (output: DataToRedux, input: JSON) =
     },
     [MLGYM_EVENT.EXPERIMENT_CONFIG]: (dataToRedux: DataToRedux, data: JSON): void => console.log("Exp config found"),
     [MLGYM_EVENT.EXPERIMENT_STATUS]: (dataToRedux: DataToRedux, data: JSON): void => { dataToRedux.tableData.push(handleExperimentStatusData(data)) },
+    // [MLGYM_EVENT.BATCHED_EVENTS]: (dataToRedux: DataToRedux, data: JSON): void => { dataToRedux.tableData.push(handleJobStatusData(data)) },
 };
 
 
@@ -28,11 +29,25 @@ export const updateMainThreadCallback = (bufferedSocketData: Array<JSON>) => {
         chartsUpdates: []
     };
     // loop over all incoming data from socket
-    for (const data of bufferedSocketData) {
-        // parse data from socket then extract event_type and payload
-        const { data: { event_type, payload } } = data as DataFromSocket;
-        // process the payload and load it into the DataToRedux object
-        MapEventToProcess[event_type as keyof typeof MapEventToProcess](bufferedDataToRedux, payload);
+    for (const bfrdata of bufferedSocketData) {
+        let data_from_socket = bfrdata as DataFromSocket | BufferedDataFromSocket;
+        // handling batched events coming from socket itself
+        if(data_from_socket.event_id === "batched_events") {
+            const buffered_data =  data_from_socket as BufferedDataFromSocket;
+            // treating batched events as normal buffered events from web workers (like the else part of this function)
+            for(const iterated_buffer_data of buffered_data["data"]) {
+                // parse data from socket then extract event_type and payload
+                const { data: { event_type, payload } } = iterated_buffer_data as DataFromSocket;
+                // process the payload and load it into the DataToRedux object
+                MapEventToProcess[event_type as keyof typeof MapEventToProcess](bufferedDataToRedux, payload);
+            }
+        }
+        else {
+            // parse data from socket then extract event_type and payload
+            const { data: { event_type, payload } } = data_from_socket as DataFromSocket;
+            // process the payload and load it into the DataToRedux object
+            MapEventToProcess[event_type as keyof typeof MapEventToProcess](bufferedDataToRedux, payload);
+        }
     }
     // sending Data to the Main thread to store it in Redux
     postMessage(bufferedDataToRedux);
@@ -43,8 +58,8 @@ export const pingMainThreadCallback = (ping: number) => {
     postMessage({ status: { ping } } as DataToRedux);
 };
 
-export const connectionMainThreadCallback = (isSocketConnected: boolean) => {
-    postMessage({ status: { isSocketConnected } } as DataToRedux);
+export const connectionMainThreadCallback = (isSocketConnected: boolean, gridSearchId?: string, restApiUrl?: string) => {
+    postMessage({ status: { isSocketConnected, gridSearchId, restApiUrl } } as DataToRedux);
 };
 
 export const msgCounterIncMainThreadCallback = () => {
diff --git a/src/ml_board/frontend/Dashboard/src/worker_socket/WorkerSocket.ts b/src/ml_board/frontend/Dashboard/src/worker_socket/WorkerSocket.ts
index ad3352c9..78a6b12e 100644
--- a/src/ml_board/frontend/Dashboard/src/worker_socket/WorkerSocket.ts
+++ b/src/ml_board/frontend/Dashboard/src/worker_socket/WorkerSocket.ts
@@ -2,7 +2,6 @@ import socketIO, { Socket } from 'socket.io-client';
 import { settingConfigsInterface } from '../app/App';
 import { connectionMainThreadCallback, msgCounterIncMainThreadCallback, pingMainThreadCallback, throughputMainThreadCallback, updateMainThreadCallback } from './MainThreadCallbacks';
 
-
 // ========================= variables ============================//
 let socket: Socket; // 'let' to initialize on funciton call
 // Ping to measure Round Trip Time (RTT)
@@ -20,9 +19,9 @@ let buffering_interval: NodeJS.Timer;
 
 // =~=~=~=~=~=~=~=~=~=~=~=~=~= ~WebSocket~ =~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=//
 const initSocket = (settingConfigs: settingConfigsInterface) => {
+    console.log("WebSocket initializing...");
     socket = socketIO(settingConfigs.socketConnectionUrl, { autoConnect: true });
-    console.log("WebSocket initialized");
-    socket.on('connect', () => onConnect(socket, settingConfigs.gridSearchId));
+    socket.on('connect', () => onConnect(socket, settingConfigs.gridSearchId, settingConfigs.restApiUrl));
     socket.on('disconnect', onDisconnect);
     socket.on('connect_error', onError);
     socket.on('mlgym_event', process_mlgym_event);
@@ -31,14 +30,14 @@ const initSocket = (settingConfigs: settingConfigsInterface) => {
 
 
 // ========================= connection events ============================//
-const onConnect = (socket: Socket, runId: string) => {
+const onConnect = (socket: Socket, gridSearchId: string, restApiUrl: string) => {
     //NOTE: for testing with the dummy_server.py set runId = "mlgym_event_subscribers";
     // Max added bug report here: https://github.com/mlgym/mlgym/issues/134
-    socket.emit('join', { rooms: [runId] });
+    socket.emit('join', { rooms: [gridSearchId] });
     // start periodic server pining
     pinging_interval = setInterval(send_ping_to_websocket_server, period * 1000, socket);
     // flag main thread that connection is on
-    connectionMainThreadCallback(true);
+    connectionMainThreadCallback(true, gridSearchId, restApiUrl);
     // start periodic buffer flushing
     buffering_interval = setInterval(() => { bufferQueue.length > 0 && flushBufferingWindow() }, BUFFER_WINDOW_LIMIT_IN_SECONDS * 1000);
 };
@@ -47,7 +46,6 @@ const onDisconnect = (reason: Socket.DisconnectReason) => stop(reason);
 
 const onError = (err: Error) => stop(err);
 
-
 // ========================= data driven events ============================//
 const process_mlgym_event = (msg: JSON) => {
     // TODO: maybe here instead of just pushing, insert based on the "event_id" or "creation_ts"
diff --git a/src/ml_board/frontend/Dashboard/src/worker_socket/event_handlers/evaluationResultDataHandler.tsx b/src/ml_board/frontend/Dashboard/src/worker_socket/event_handlers/evaluationResultDataHandler.tsx
new file mode 100644
index 00000000..10447ba9
--- /dev/null
+++ b/src/ml_board/frontend/Dashboard/src/worker_socket/event_handlers/evaluationResultDataHandler.tsx
@@ -0,0 +1,243 @@
+export interface evalResultCustomData {
+    grid_search_id: string | null, //TODO: move it to the statusSlice?
+    experiments: {
+        [key: string]: {
+            data: {
+                labels: Array<number>,
+                datasets: Array<{
+                    exp_id: number,
+                    label: string,
+                    data: Array<number>,
+                    fill: Boolean,
+                    backgroundColor: string,
+                    borderColor: string,
+                    tension: number, // to give smoothness to the line curves
+                    pointRadius: Number, // radius of the label tag
+                    pointHitRadius: Number, // on hover:: change of data point radius size
+                    pointHoverRadius: Number // radius of mouse to show the label values when mouse is near a datapoint
+                }>
+            },
+            options: {
+                animation: {
+                    duration: number,
+                    easing: string
+                }
+                responsive: Boolean,
+                maintainAspectRatio: Boolean,
+                plugins: {
+                    title: {
+                        display: Boolean,
+                        text: string,
+                        color: string,
+                        font: {
+                            weight: string,
+                            size: Number
+                        }
+                    },
+                    legend: {
+                        display: true,
+                        labels: {
+                            usePointStyle: boolean,
+                            pointStyle: string
+                        }
+                    }
+                }
+            },
+            ids_to_track_and_find_exp_id: Array<number>
+        }
+    },
+    colors_mapped_to_exp_id: {
+        [key: number]: string
+    }
+}
+
+export interface EvaluationResultPayload {
+    epoch: number,
+    grid_search_id: string,
+    experiment_id: number,
+    metric_scores: Array<{
+        metric: string,
+        split: string,
+        score: number
+    }>,
+    loss_scores: Array<{
+        loss: string,
+        split: string,
+        score: number
+    }>
+}
+
+export default function handleEvaluationResultData(evalResultCustomData: evalResultCustomData, evalResultSocketData: EvaluationResultPayload) {
+    let exp = undefined;
+    if (evalResultCustomData.grid_search_id !== null) {
+        exp = evalResultCustomData.experiments;
+    }
+    else {
+        evalResultCustomData.grid_search_id = evalResultSocketData.grid_search_id;
+        exp = {}
+    }
+
+    if (evalResultCustomData.colors_mapped_to_exp_id[evalResultSocketData.experiment_id] === undefined) {
+        let random_color = getRandomColor();
+        evalResultCustomData.colors_mapped_to_exp_id[evalResultSocketData.experiment_id] = random_color;
+    }
+
+    for (let i = 0; i < evalResultSocketData.loss_scores.length; i++) {
+        let d = evalResultSocketData.loss_scores[i]
+        if (exp[d.split + "_" + d.loss] === undefined) {
+            exp[d.split + "_" + d.loss] = {
+                data: {
+                    labels: [],
+                    datasets: []
+                },
+                options: {
+                    animation: {
+                        duration: 300,
+                        easing: 'linear'
+                    },
+                    responsive: true,
+                    maintainAspectRatio: false,
+                    plugins: {
+                        title: {
+                            display: true,
+                            text: (d.split + " " + d.loss.split("_").join(" ")).toLowerCase(),
+                            color: 'black',
+                            font: {
+                                weight: 'bold',
+                                size: 20
+                            }
+                        },
+                        legend: {
+                            display: true,
+                            labels: {
+                                usePointStyle: true,
+                                pointStyle: 'circle'
+                            }
+                        }
+                    }
+                },
+                ids_to_track_and_find_exp_id: []
+            }
+        }
+
+        let prevIndex = null;
+        if (exp[d.split + "_" + d.loss].ids_to_track_and_find_exp_id.includes(evalResultSocketData.experiment_id)) {
+            prevIndex = exp[d.split + "_" + d.loss].ids_to_track_and_find_exp_id.indexOf(evalResultSocketData.experiment_id)
+        }
+        else {
+            exp[d.split + "_" + d.loss].ids_to_track_and_find_exp_id.push(evalResultSocketData.experiment_id);
+        }
+
+        if (!exp[d.split + "_" + d.loss].data.labels.includes(evalResultSocketData.epoch)) {
+            exp[d.split + "_" + d.loss].data.labels.push(evalResultSocketData.epoch);
+        }
+
+        if (prevIndex !== null) {
+            exp[d.split + "_" + d.loss].data.datasets[prevIndex].data = [...exp[d.split + "_" + d.loss].data.datasets[prevIndex].data, d.score]
+        }
+        else {
+            exp[d.split + "_" + d.loss].data.datasets.push({
+                exp_id: evalResultSocketData.experiment_id,
+                label: "experiment_" + evalResultSocketData.experiment_id.toString(),
+                data: [d.score],
+                fill: false,
+                backgroundColor: evalResultCustomData.colors_mapped_to_exp_id[evalResultSocketData.experiment_id],
+                borderColor: evalResultCustomData.colors_mapped_to_exp_id[evalResultSocketData.experiment_id],
+                tension: 0,
+                pointRadius: 3,
+                pointHitRadius: 20,
+                pointHoverRadius: 12
+            });
+        }
+        exp[d.split + "_" + d.loss].data.datasets.sort((a, b) => (a.exp_id > b.exp_id) ? 1 : -1)
+        exp[d.split + "_" + d.loss].ids_to_track_and_find_exp_id.sort((a, b) => (a > b) ? 1 : -1)
+    }
+
+    for (let i = 0; i < evalResultSocketData.metric_scores.length; i++) {
+        let d = evalResultSocketData.metric_scores[i]
+        if (exp[d.split + "_" + d.metric] === undefined) {
+            exp[d.split + "_" + d.metric] = {
+                data: {
+                    labels: [],
+                    datasets: []
+                },
+                options: {
+                    animation: {
+                        duration: 300,
+                        easing: 'linear'
+                    },
+                    responsive: true,
+                    maintainAspectRatio: false,
+                    plugins: {
+                        title: {
+                            display: true,
+                            text: (d.split + " " + d.metric.split("_").join(" ")).toLowerCase(),
+                            color: 'black',
+                            font: {
+                                weight: 'bold',
+                                size: 20
+                            }
+                        },
+                        legend: {
+                           display: true,
+                           labels: {
+                                usePointStyle: true,
+                                pointStyle: 'circle'
+                            }
+                        }
+                    }
+                },
+                ids_to_track_and_find_exp_id: []
+            }
+        }
+
+        let prevIndex = null;
+        if (exp[d.split + "_" + d.metric].ids_to_track_and_find_exp_id.includes(evalResultSocketData.experiment_id)) {
+            prevIndex = exp[d.split + "_" + d.metric].ids_to_track_and_find_exp_id.indexOf(evalResultSocketData.experiment_id)
+        }
+        else {
+            exp[d.split + "_" + d.metric].ids_to_track_and_find_exp_id.push(evalResultSocketData.experiment_id);
+        }
+
+        if (!exp[d.split + "_" + d.metric].data.labels.includes(evalResultSocketData.epoch)) {
+            exp[d.split + "_" + d.metric].data.labels.push(evalResultSocketData.epoch);
+        }
+
+        if (prevIndex !== null) {
+            exp[d.split + "_" + d.metric].data.datasets[prevIndex].data = [...exp[d.split + "_" + d.metric].data.datasets[prevIndex].data, d.score]
+        }
+        else {
+            exp[d.split + "_" + d.metric].data.datasets.push({
+                exp_id: evalResultSocketData.experiment_id,
+                label: "experiment_" + evalResultSocketData.experiment_id.toString(),
+                data: [d.score],
+                fill: false,
+                backgroundColor: evalResultCustomData.colors_mapped_to_exp_id[evalResultSocketData.experiment_id],
+                borderColor: evalResultCustomData.colors_mapped_to_exp_id[evalResultSocketData.experiment_id],
+                tension: 0,
+                pointRadius: 3,
+                pointHitRadius: 20,
+                pointHoverRadius: 12
+            });
+        }
+
+        exp[d.split + "_" + d.metric].data.datasets.sort((a, b) => (a.exp_id > b.exp_id) ? 1 : -1)
+        exp[d.split + "_" + d.metric].ids_to_track_and_find_exp_id.sort((a, b) => (a > b) ? 1 : -1)
+    }
+
+    evalResultCustomData.experiments = exp;
+    // console.log("In Handle Exp evalResultCustomData = ",evalResultCustomData);
+
+    return evalResultCustomData;
+
+}
+
+// TODO: should be moved to the statusSlice maybe ?
+export function getRandomColor() {
+    let letters = '0123456789ABCDEF'.split('');
+    let color = '#';
+    for (let i = 0; i < 6; i++) {
+        color += letters[Math.floor(Math.random() * 16)];
+    }
+    return color;
+}
\ No newline at end of file
diff --git a/src/ml_gym/blueprints/blue_prints.py b/src/ml_gym/blueprints/blue_prints.py
index a07e1510..58f19414 100644
--- a/src/ml_gym/blueprints/blue_prints.py
+++ b/src/ml_gym/blueprints/blue_prints.py
@@ -11,6 +11,16 @@ class BluePrint(ABC):
     def __init__(self, run_mode: RunMode, config: Dict[str, Any], grid_search_id: str,
                  experiment_id: str, external_injection: Dict[str, Any] = None,
                  warm_start_epoch: int = 0):
+        """
+        Initalize BluePrint class.
+        :params:
+           - run_mode (RunMode): Create config to run from scratch or do a warm start.
+           - config (Dict[str, Any]): This is a dictionary having the configuration keys.
+           - grid_search_id (str): Grid Search ID created for the run.
+           - experiment_id (str): Experminet Number of the model for which blueprint is created.
+           - external_injection (Dict[str, Any]): TO DO
+           - warm_start_epoch (int): epoch number to warm start from.
+        """ 
 
         self.run_mode = run_mode
         self.config = config
@@ -37,6 +47,19 @@ def create_blueprint(blue_print_class: Type["BluePrint"],
                          grid_search_id: str,
                          external_injection: Dict[str, Any] = None,
                          warm_start_epoch: int = 0) -> List["BluePrint"]:
+        """
+        Function to create a blue print Dictionary
+        :params:
+           - blue_print_class (Type["BluePrint"]): Class call for BluePrint.
+           - run_mode (RunMode): Create config to run from scratch or do a warm start.
+           - experiment_config (Dict[str, Any]): This is a dictionary having the configuration keys.
+           - grid_search_id (str): Grid Search ID created for the run.
+           - experiment_id (str): Experminet Number of the model for which blueprint is created.
+           - external_injection (Dict[str, Any]): TO DO
+           - warm_start_epoch (int): epoch number to warm start from.
+        
+        :returns: blue_print(List["BluePrint"]) : List of blueprint objects.
+        """
 
         blue_print = blue_print_class(grid_search_id=grid_search_id,
                                       experiment_id=experiment_id,
diff --git a/src/ml_gym/blueprints/constructables.py b/src/ml_gym/blueprints/constructables.py
index 42ea6410..cb30a26b 100644
--- a/src/ml_gym/blueprints/constructables.py
+++ b/src/ml_gym/blueprints/constructables.py
@@ -56,6 +56,10 @@ def get_subscription(self) -> Union[Dict, List, Any]:
 
 @dataclass
 class ComponentConstructable(ABC):
+    """
+    ComponentConstructable is an Abstract class which is used to create all the other constructable calsses.
+    The abstract class allows the other Constructables to maintain a common single structure to be used to access the classes.
+    """
     component_identifier: str = ""
     constructed: Any = None
     requirements: Dict[str, Requirement] = field(default_factory=dict)
@@ -82,6 +86,10 @@ def has_requirement(self, name: str) -> bool:
 
 @dataclass
 class DatasetRepositoryConstructable(ComponentConstructable):
+    """
+    DatasetRepositoryConstructable class initializes DatasetRepository & StorageConnectorFactory object from datastack library
+    to be used for accessing data for models used in MlGym.
+    """
     storage_connector_path: str = ""
 
     def _construct_impl(self) -> DatasetRepository:
@@ -93,6 +101,10 @@ def _construct_impl(self) -> DatasetRepository:
 
 @dataclass
 class DatasetIteratorConstructable(ComponentConstructable):
+    """
+    DatasetIteratorConstructable class is used to make the dataset iterable
+    to be used for accessing specific split for models used in MlGym.
+    """
     dataset_identifier: str = ""
     split_configs: Dict[str, Any] = field(default_factory=dict)
 
@@ -112,6 +124,10 @@ def _construct_impl(self) -> Dict[str, InformedDatasetIteratorIF]:
 
 @dataclass
 class DatasetIteratorSplitsConstructable(ComponentConstructable):
+    """
+    DatasetIteratorSplitsConstructable class is used to make the dataset iterable.
+    to be used for accessing all data splits for models used in MlGym.
+    """
     split_configs: Dict = None
     seed: int = 1
     stratified: bool = False
@@ -125,6 +141,10 @@ def _construct_impl(self) -> Dict[str, InformedDatasetIteratorIF]:
 
 @dataclass
 class CombinedDatasetIteratorConstructable(ComponentConstructable):
+    """
+    CombinedDatasetIteratorConstructable class is used to get combined itterators for the dataset by 
+    combining iterators from old splits and getting new iterators for new splits.
+    """
     combine_configs: Dict = None
 
     def _construct_impl(self) -> Dict[str, InformedDatasetIteratorIF]:
@@ -137,7 +157,9 @@ def _construct_impl(self) -> Dict[str, InformedDatasetIteratorIF]:
 
 @dataclass
 class InMemoryDatasetIteratorConstructable(ComponentConstructable):
-
+    """
+    InMemoryDatasetIteratorConstructable class is used to load a given iterator into memory to speed up the iteration.
+    """
     def _construct_impl(self) -> Dict[str, InformedDatasetIteratorIF]:
         dataset_iterators_dict = self.get_requirement("iterators")
         return {name: ModelGymInformedIteratorFactory.get_in_memory_iterator(self.component_identifier, iterator)
@@ -146,6 +168,9 @@ def _construct_impl(self) -> Dict[str, InformedDatasetIteratorIF]:
 
 @dataclass
 class ShuffledDatasetIteratorConstructable(ComponentConstructable):
+    """
+    ShuffledDatasetIteratorConstructable class is used to get randomly shuffled iterators usefull for large datasets.
+    """
     seeds: Dict[str, Any] = field(default_factory=dict)
     applicable_splits: List[str] = field(default_factory=list)
 
@@ -158,6 +183,9 @@ def _construct_impl(self) -> Dict[str, InformedDatasetIteratorIF]:
 
 @dataclass
 class FilteredLabelsIteratorConstructable(ComponentConstructable):
+    """
+    FilteredLabelsIteratorConstructable class is used to get an iterator which can iterate through filtered labels in the dataset.
+    """
     filtered_labels: List[Any] = field(default_factory=list)
     applicable_splits: List[str] = field(default_factory=list)
 
@@ -170,6 +198,9 @@ def _construct_impl(self) -> Dict[str, DatasetIteratorIF]:
 
 @dataclass
 class IteratorViewConstructable(ComponentConstructable):
+    """
+    IteratorViewConstructable class is used to create a view on an iterator for accessing elements of a given split only.
+    """
     split_indices: Dict[str, List[int]] = field(default_factory=dict)
     view_tags: Dict[str, Any] = field(default_factory=dict)
     applicable_split: str = ""
@@ -191,6 +222,9 @@ def _construct_impl(self) -> Dict[str, DatasetIteratorIF]:
 
 @dataclass
 class MappedLabelsIteratorConstructable(ComponentConstructable):
+    """
+    MappedLabelsIteratorConstructable class is used to get an iterator which can iterate through mapped labels in the dataset.
+    """
     mappings: Dict[str, Union[List[int], int]] = field(default_factory=dict)
     applicable_splits: List[str] = field(default_factory=list)
 
@@ -203,6 +237,9 @@ def _construct_impl(self) -> Dict[str, DatasetIteratorIF]:
 
 @dataclass
 class FeatureEncodedIteratorConstructable(ComponentConstructable):
+    """
+    FeatureEncodedIteratorConstructable class is used to get an iterator which can iterate through encoded fetures of a dataset.
+    """
     applicable_splits: List[str] = field(default_factory=list)
     feature_encoding_configs: Dict = field(default_factory=Dict)
 
@@ -215,6 +252,10 @@ def _construct_impl(self) -> Dict[str, DatasetIteratorIF]:
 
 @dataclass
 class OneHotEncodedTargetsIteratorConstructable(ComponentConstructable):
+    """
+    OneHotEncodedTargetsIteratorConstructable class is used to get an iterator which can iterate 
+    through one hot encoded target vector.
+    """
     applicable_splits: List[str] = field(default_factory=list)
     target_vector_size: int = 0
 
@@ -227,6 +268,10 @@ def _construct_impl(self) -> Dict[str, DatasetIteratorIF]:
 
 @dataclass
 class DataCollatorConstructable(ComponentConstructable):
+    """
+    DataCollatorConstructable class is used to collate data for TrainBatch
+    TO DO.
+    """
     collator_params: Dict = field(default_factory=Dict)
     collator_type: Type[Collator] = None
 
@@ -236,6 +281,9 @@ def _construct_impl(self) -> Callable:
 
 @dataclass
 class DeprecatedDataLoadersConstructable(ComponentConstructable):
+    """
+    DeprecatedDataLoadersConstructable class is used to get the spliited data based on the wighted sampling. (DEPRECATED)
+    """
     batch_size: int = 1
     weigthed_sampling_split_name: str = None
     label_pos: int = 2
@@ -257,6 +305,9 @@ def _construct_impl(self) -> DatasetLoader:
 
 @dataclass
 class DataLoadersConstructable(ComponentConstructable):
+    """
+    DataLoadersConstructable class is used to get the spliited data based on the sampling stratergy.
+    """
     batch_size: int = 1
     sampling_strategies: Dict[str, Any] = field(default_factory=dict)
     drop_last: bool = False
@@ -273,6 +324,10 @@ def _construct_impl(self) -> DatasetLoader:
 
 @dataclass
 class OptimizerConstructable(ComponentConstructable):
+    """
+    OptimizerConstructable class is used to create an object of Optimizer Adapter based on what optimizer is
+    to be used as per the config of MlGym Job.
+    """
     optimizer_key: str = ""
     params: Dict[str, Any] = field(default_factory=dict)
 
@@ -282,6 +337,10 @@ def _construct_impl(self) -> OptimizerAdapter:
 
 @dataclass
 class LRSchedulerConstructable(ComponentConstructable):
+    """
+    LRSchedulerConstructable class is used to create an object of LRScheduler Adapter based on what shedule of learning rate is
+    to be used as per the config of MlGym Job.
+    """
     lr_scheduler_key: str = ""
     params: Dict[str, Any] = field(default_factory=dict)
 
@@ -291,6 +350,10 @@ def _construct_impl(self) -> LRSchedulerAdapter:
 
 @dataclass
 class OptimizerBundleConstructable(ComponentConstructable):
+    """
+    OptimizerBundleConstructable class is used to create an object of Optimizer Bundle containing
+    all optimizers with registered optimizer params.
+    """
 
     optimizers_config: Dict[str, Any] = field(default_factory=list)
     # {
@@ -312,6 +375,9 @@ def _construct_impl(self) -> OptimizerAdapter:
 
 @dataclass
 class ModelRegistryConstructable(ComponentConstructable):
+    """
+    ModelRegistryConstructable class is used to create a ClassRegistry object for model.
+    """
     model_registry: ClassRegistry = None
 
     def _construct_impl(self):
@@ -321,6 +387,9 @@ def _construct_impl(self):
 
 @dataclass
 class LossFunctionRegistryConstructable(ComponentConstructable):
+    """
+    LossFunctionRegistryConstructable class is used to create a ClassRegistry object for all available Loss Functions.
+    """
     class LossKeys:
         LPLoss = "LPLoss"
         LPPredictionLoss = "LPPredictionLoss"
@@ -349,6 +418,9 @@ def _construct_impl(self):
 
 @dataclass
 class MetricFunctionRegistryConstructable(ComponentConstructable):
+    """
+    MetricFunctionRegistryConstructable class is used to create a ClassRegistry object for all available Evaluation Metrics.
+    """
     class MetricKeys:
         F1_SCORE = "F1_SCORE"
         ACCURACY = "ACCURACY"
@@ -406,6 +478,10 @@ def _construct_impl(self):
 
 @dataclass
 class PredictionPostProcessingRegistryConstructable(ComponentConstructable):
+    """
+    PredictionPostProcessingRegistryConstructable class is used to create a ClassRegistry object for 
+    all available Prediction Functions used in post processing.
+    """
     class FunctionKeys:
         SOFT_MAX = "SOFT_MAX"
         ARG_MAX = "ARG_MAX"
@@ -431,6 +507,10 @@ def _construct_impl(self):
 
 @dataclass
 class ModelConstructable(ComponentConstructable):
+    """
+    ModelConstructable class is used to construct a Neural Net model based on the
+    params in the model registry.
+    """
     model_type: str = ""
     model_definition: Dict[str, Any] = field(default_factory=dict)
     seed: int = None
@@ -444,6 +524,10 @@ def _construct_impl(self) -> NNModel:
 
 @dataclass
 class TrainComponentConstructable(ComponentConstructable):
+    """
+    TrainComponentConstructable class is used to construct a TrainComponent
+    used when there is only one CPU or GPU to train model.
+    """
     loss_fun_config: Dict = field(default_factory=dict)
     post_processors_config: List[Dict] = field(default_factory=list)
     show_progress: bool = False
@@ -462,6 +546,10 @@ def _construct_impl(self) -> TrainComponent:
 
 @dataclass
 class AccelerateTrainComponentConstructable(ComponentConstructable):
+    """
+    AccelerateTrainComponentConstructable class is used to construct a AccelerateTrainComponent
+    used when there are multiple GPUs to train model.
+    """
     loss_fun_config: Dict = field(default_factory=dict)
     post_processors_config: List[Dict] = field(default_factory=list)
 
@@ -479,7 +567,9 @@ def _construct_impl(self) -> AccelerateTrainComponent:
 
 @dataclass
 class TrainerConstructable(ComponentConstructable):
-
+    """
+    TrainerConstructable creates a Trainer object containing functions used to train the torch Neural Net model on CPU.
+    """
     def _construct_impl(self) -> Trainer:
         train_loader: DatasetLoader = self.get_requirement("data_loaders")
         train_component: TrainComponent = self.get_requirement("train_component")
@@ -489,7 +579,10 @@ def _construct_impl(self) -> Trainer:
 
 @dataclass
 class AccelerateTrainerConstructable(ComponentConstructable):
-
+    """
+    AccelerateTrainerConstructable creates a AccelerateTrainer object containing functions 
+    used to train the torch Neural Net model on GPU.
+    """
     def _construct_impl(self) -> AccelerateTrainer:
         train_loader: DatasetLoader = self.get_requirement("data_loaders")
         train_component: TrainComponent = self.get_requirement("train_component")
@@ -499,6 +592,10 @@ def _construct_impl(self) -> AccelerateTrainer:
 
 @dataclass
 class EvalComponentConstructable(ComponentConstructable):
+    """
+    EvalComponentConstructable creates a EvalComponent object containing functions 
+    used to evaluate the torch Neural Net model on CPU.
+    """
     metrics_config: List = field(default_factory=list)
     loss_funs_config: List = field(default_factory=list)
     post_processors_config: List[Dict] = field(default_factory=list)
@@ -539,7 +636,10 @@ def _construct_impl(self) -> EvalComponent:
 
 @dataclass
 class EvaluatorConstructable(ComponentConstructable):
-
+    """
+    EvaluatorConstructable creates a Evaluator object containing functions 
+    used to evaluate the torch Neural Net model on CPU.
+    """
     def _construct_impl(self) -> Evaluator:
         eval_component: EvalComponent = self.get_requirement("eval_component")
         evaluator = Evaluator(eval_component)
@@ -548,6 +648,10 @@ def _construct_impl(self) -> Evaluator:
 
 @dataclass
 class AccelerateEvalComponentConstructable(ComponentConstructable):
+    """
+    AccelerateEvalComponentConstructable creates a AccelerateEvalComponent object containing functions 
+    used to evaluate the torch Neural Net model on GPU.
+    """
     metrics_config: List = field(default_factory=list)
     loss_funs_config: List = field(default_factory=list)
     post_processors_config: List[Dict] = field(default_factory=list)
@@ -587,6 +691,10 @@ def _construct_impl(self) -> AccelerateEvalComponent:
 
 @dataclass
 class AccelerateEvaluatorConstructable(ComponentConstructable):
+    """
+    AccelerateEvaluatorConstructable creates a AccelerateEvaluator object containing functions 
+    used to evaluate the torch Neural Net model on GPU.
+    """
 
     def _construct_impl(self) -> AccelerateEvaluator:
         eval_component: AccelerateEvalComponent = self.get_requirement("eval_component")
@@ -596,6 +704,9 @@ def _construct_impl(self) -> AccelerateEvaluator:
 
 @dataclass
 class EarlyStoppingRegistryConstructable(ComponentConstructable):
+    """
+    EarlyStoppingRegistryConstructable creates a ClassRegistry object for all available Early Stopping Stratergies.
+    """
     class StrategyKeys:
         LAST_K_EPOCHS_IMPROVEMENT_STRATEGY = "LAST_K_EPOCHS_IMPROVEMENT_STRATEGY"
 
@@ -613,6 +724,9 @@ def _construct_impl(self):
 
 @dataclass
 class EarlyStoppingStrategyConstructable(ComponentConstructable):
+    """
+    EarlyStoppingStrategyConstructable initializes the EarlyStoppingIF  for all available Early Stopping Stratergies.
+    """
     early_stopping_config: Dict = field(default_factory=dict)
     early_stopping_key: str = ""
 
@@ -624,6 +738,9 @@ def _construct_impl(self) -> EarlyStoppingIF:
 
 @dataclass
 class CheckpointingRegistryConstructable(ComponentConstructable):
+    """
+    CheckpointingRegistryConstructable creates a ClassRegistry object for all available Checkpointing Stratergies.
+    """
     class StrategyKeys:
         SAVE_LAST_EPOCH_ONLY_CHECKPOINTING_STRATEGY = "SAVE_LAST_EPOCH_ONLY_CHECKPOINTING_STRATEGY"
         SAVE_ALL_CHECKPOINTING_STRATEGY = "SAVE_ALL_CHECKPOINTING_STRATEGY"
@@ -644,6 +761,9 @@ def _construct_impl(self) -> ClassRegistry:
 
 @dataclass
 class CheckpointingStrategyConstructable(ComponentConstructable):
+    """
+    CheckpointingStrategyConstructable initializes the CheckpointingIF for all available Checkpointing Stratergies.
+    """
     checkpointing_config: Dict = field(default_factory=dict)
     checkpointing_key: str = ""
 
diff --git a/src/ml_gym/checkpointing/checkpoint_factory.py b/src/ml_gym/checkpointing/checkpoint_factory.py
index 1108e9a5..ca2dc044 100644
--- a/src/ml_gym/checkpointing/checkpoint_factory.py
+++ b/src/ml_gym/checkpointing/checkpoint_factory.py
@@ -3,6 +3,10 @@
 
 
 class CheckpointingStrategyFactory:
+    """
+    Checkpointing Stratergy Class used for finding what stratergy to use for 
+    creating checkpoints for the experiments while running MlGym Job.
+    """
     @staticmethod
     def get_save_last_epoch_only_checkpointing_strategy() -> CheckpointingIF:
         strategy = SaveLastEpochOnlyCheckpointingStrategy()
diff --git a/src/ml_gym/checkpointing/checkpointing.py b/src/ml_gym/checkpointing/checkpointing.py
index fda0fac8..533a7ee0 100644
--- a/src/ml_gym/checkpointing/checkpointing.py
+++ b/src/ml_gym/checkpointing/checkpointing.py
@@ -7,11 +7,17 @@
 
 @dataclass
 class CheckpointingInstruction:
+    """
+    Instruction to save and delete checkpoints.
+    """
     save_current: bool = False
     checkpoints_to_delete: List[int] = field(default_factory=list)
 
 
 class CheckpointingIF(StatefulComponent):
+    """
+    Checkpoint Interface to get checkpoint instruction.
+    """
     @abstractmethod
     def get_model_checkpoint_instruction(self, current_epoch: int, num_epochs: int,
                                          evaluation_result: EvaluationBatchResult) -> CheckpointingInstruction:
@@ -19,6 +25,9 @@ def get_model_checkpoint_instruction(self, current_epoch: int, num_epochs: int,
 
 
 class Checkpointing(CheckpointingIF):
+    """
+    Checkpoint class to get checkpoint instruction.
+    """
     def __init__(self, checkpointing_strategy: CheckpointingIF):
         self.checkpointing_strategy = checkpointing_strategy
 
@@ -29,21 +38,49 @@ def get_model_checkpoint_instruction(self, current_epoch: int, num_epochs: int,
 
 
 class SaveLastEpochOnlyCheckpointingStrategy(CheckpointingIF):
+    """
+    Class for Save Last Epoch only Checkpointing Stratergy.
+    """
     def __init__(self):
         pass
 
     def get_model_checkpoint_instruction(self, current_epoch: int, num_epochs: int,
                                          evaluation_result: EvaluationBatchResult) -> CheckpointingInstruction:
+        """
+        Fetch Checkpoint Instruction 
+
+        :params:
+           - current_epoch (int): Current epoch number for cerating checkpoints.
+           - num_epochs (int): Number of epochs to be trained.
+           - evaluation_result (EvaluationBatchResult): Evaluation results of batches trained on.
+           
+        :returns:
+            CheckpointingInstruction: Instruction to save and delete checkpoints.
+        """
         checkpoints_to_delete = [current_epoch-1] if current_epoch > 0 else []
         return CheckpointingInstruction(save_current=True, checkpoints_to_delete=checkpoints_to_delete)
 
 
 class SaveAllCheckpointingStrategy(CheckpointingIF):
+    """
+    Class for Save All Checkpointing Stratergy.
+    """
     def __init__(self):
         pass
 
     def get_model_checkpoint_instruction(self, current_epoch: int, num_epochs: int,
                                          evaluation_result: EvaluationBatchResult) -> CheckpointingInstruction:
+        """
+        Fetch Checkpoint Instruction 
+
+        :params:
+           - current_epoch (int): Current epoch number for cerating checkpoints.
+           - num_epochs (int): Number of epochs to be trained.
+           - evaluation_result (EvaluationBatchResult): Evaluation results of batches trained on.
+
+        :returns:
+            CheckpointingInstruction: Instruction to save and delete checkpoints.
+        """
         return CheckpointingInstruction(save_current=True, checkpoints_to_delete=[])
 
 # class RegularIntervalCheckpoint(Checkpointing):
diff --git a/src/ml_gym/cmd_entrypoint/cmd.py b/src/ml_gym/cmd_entrypoint/cmd.py
index 726376ec..e3010ab6 100644
--- a/src/ml_gym/cmd_entrypoint/cmd.py
+++ b/src/ml_gym/cmd_entrypoint/cmd.py
@@ -8,6 +8,7 @@
 from ml_gym.persistency.logging import MLgymStatusLoggerCollectionConstructable, LoggerConstructableIF, MLgymStatusLoggerConfig, \
     MLgymStatusLoggerTypes
 from ml_gym.modes import RunMode, ValidationMode
+from ml_gym.util.util import SystemEnv
 from ml_gym.validation.validator_factory import get_validator
 from ml_gym.io.config_parser import YAMLConfigLoader
 from typing import Callable, List, Tuple, Type, Dict, Union
@@ -37,6 +38,14 @@ class AccelerateEnvironmentConfig:
 
 @dataclass
 class TrainRunConfiguration:
+    """
+    Class to store configuration to initiate training of a model.
+    :params:
+       - num_epochs(int): number of epochs to be trained to.
+       - gs_config_path (str): Path ro the gs_config file.
+       - validation_config_path : Path ro the validation_strategy_config file.
+       - num_batches_per_epoch (int): numner of batches to be trained per epoch.
+    """
     num_epochs: int
     gs_config_path: str
     validation_config_path = None
@@ -45,6 +54,13 @@ class TrainRunConfiguration:
 
 @dataclass
 class WarmStartRunConfiguration:
+    """
+    Class to store configuration to warm start a model in mlGym.
+    :params:
+       - grid_search_id (str): Grid Search ID created for the run.
+       - num_epochs(int): number of epochs to be trained to.
+       - num_batches_per_epoch (int): numner of batches to be trained per epoch.
+    """
     gridsaerch_id: str
     num_epochs: int
     num_batches_per_epoch: int = None
@@ -52,6 +68,12 @@ class WarmStartRunConfiguration:
 
 @dataclass
 class LoggingConfiguration:
+    """
+    Class to store endpint configuration used for logging.
+    :params:
+       - websocket_logging_servers(List[str]): Endpoint for Websocket Server.
+       - gs_rest_api_endpoint (str): Endpoint for RESTApi .
+    """
     websocket_logging_servers: List[str]
     gs_rest_api_endpoint: str
 
@@ -63,6 +85,19 @@ def get_gym_from_environment_config(env_config: Union[MultiProcessingEnvironment
                                     num_epochs: int,
                                     num_batches_per_epoch: int = None,
                                     accelerator: Accelerator = None) -> Gym:
+    """
+    Create Gym class object from the run configuration
+    :params:
+       - env_config (Union[..]): Contains the environment config objects for number of processors and
+        devices which are to be used to train the model.
+       - logger_collection_constructable (LoggerConstructableIF): Logging interface
+       - gs_restful_api_client_constructable (GridSearchAPIClientConstructableIF): Interface to initiate GridSearchAPIClient
+       - num_epochs(int): number of epochs to be trained to.
+       - num_batches_per_epoch (int): numner of batches to be trained per epoch.
+       - accelerator (Accelerator): Accelerator object used for distributed training over multiple GPUs
+
+    :returns: gym(Gym): Gym class object
+    """
 
     if isinstance(env_config, MainProcessEnvironmentConfig):
         gym = GymFactory.get_sequential_gym(logger_collection_constructable=logger_collection_constructable,
@@ -89,6 +124,12 @@ def get_gym_from_environment_config(env_config: Union[MultiProcessingEnvironment
 
 
 def get_logger_constructable(websocket_logging_servers: List) -> LoggerConstructableIF:
+    """
+    Initiate MLgymStatusLoggerIF to be used to store logs for events during the running of experiments.
+    :params:
+        websocket_logging_servers (List): Webscoket server to be used to store logs.
+    :returns:  logger_collection_constructable (LoggerConstructableIF): Initiated Logging interface
+    """
     websocket_logging_servers = [(f"{protocol}:{ip}", int(port)) for protocol, ip, port in [
         connection.split(":") for connection in websocket_logging_servers]]
 
@@ -99,24 +140,55 @@ def get_logger_constructable(websocket_logging_servers: List) -> LoggerConstruct
 
 
 def get_grid_search_restful_api_client_constructable(endpoint: str) -> GridSearchAPIClientConstructableIF:
+    """
+    Initiate MLgymStatusLoggerIF to be used to store logs for events during the running of experiments.
+    :params:
+        endpoint (str): Endpoint URL for RESTful API Server.
+    :returns:  client_constructable (GridSearchAPIClientConstructableIF): Initiated Grid Search API Client interface for performing REST calls.
+    """
     client_config = GridSearchAPIClientConfig(api_client_type=GridSearchAPIClientType.GRID_SEARCH_RESTFUL_API_CLIENT,
                                               api_client_config={"endpoint": endpoint})
     client_constructable = GridSearchAPIClientConstructable(client_config)
     return client_constructable
 
 
-def entry_train(gridsearch_id: str, blueprint_class: Type[BluePrint], gym: Gym, gs_config_path: str,
+def entry_train(gridsearch_id: str, blueprint_class: Type[BluePrint], gym: Gym, gs_config_path: str, run_config_path: str,
                 validation_strategy_config_path: str, gs_restful_api_client_constructable: GridSearchAPIClientConstructableIF,
                 accelerator: Accelerator = None):
-
-    def log_configs(gs_config_string: str, validation_strategy_config_raw_string: str,
+    """
+    Create Gym class object from the run configuration
+    :params:
+       - grid_search_id (int): Grid Search ID created for the run.
+       - blueprint_class (Type[BluePrint]): Blueprint class object having all the components for the GymJob.
+       - gym (Gym): Gym class object.
+       - gs_config_path (str): Path ro the gs_config file.
+       - validation_strategy_config_path (str): Path ro the validation_strategy_config file.
+       - gs_restful_api_client_constructable (GridSearchAPIClientConstructableIF): Initiated Grid Search
+       - API Client interface for performing REST calls.
+       - accelerator (Accelerator): Accelerator object used for distributed training over multiple GPUs
+    """
+
+    def log_configs(gs_config_string: str, run_config_string: str, validation_strategy_config_raw_string: str,
                     gs_restful_api_client_constructable: GridSearchAPIClientConstructableIF, accelerator: Accelerator = None):
+        """
+        Log the configuration files in event_storage which are being used to run Gym Model.
+        :params:
+           - gs_config_path (str): Path ro the gs_config file.
+           - validation_strategy_config_path (str): Path ro the validation_strategy_config file.
+           - gs_restful_api_client_constructable (GridSearchAPIClientConstructableIF): Initiated Grid Search
+           - API Client interface for performing REST calls.
+           - accelerator (Accelerator): Accelerator object used for distributed training over multiple GPUs
+    """
         if accelerator is None or accelerator.is_main_process:
             gs_api_client = gs_restful_api_client_constructable.construct()
             gs_api_client.add_config_string(grid_search_id=gridsearch_id,
                                             file_format=FileFormat.YAML,
                                             config_name="grid_search_config.yml",
                                             config=gs_config_string)
+            gs_api_client.add_config_string(grid_search_id=gridsearch_id, 
+                                            file_format=FileFormat.YAML, 
+                                            config_name="run_config.yml", 
+                                            config=run_config_string)
 
             if validation_strategy_config_raw_string is not None:
                 gs_api_client.add_config_string(grid_search_id=gridsearch_id,
@@ -127,9 +199,13 @@ def log_configs(gs_config_string: str, validation_strategy_config_raw_string: st
                 gs_api_client.add_config_string(grid_search_id=blueprint.grid_search_id, config_name="experiment_config.json",
                                                 config=json.dumps(blueprint.config), experiment_id=blueprint.experiment_id,
                                                 file_format=FileFormat.JSON)
+                gs_api_client.add_config_string(grid_search_id=blueprint.grid_search_id, config_name="system_info.json",
+                                                config=json.dumps(SystemEnv.create_system_info()), experiment_id=blueprint.experiment_id,
+                                                file_format=FileFormat.JSON)
 
     gs_config_string = Path(gs_config_path).read_text()
     gs_config = YAMLConfigLoader.load_string(gs_config_string)
+    run_config_string = Path(run_config_path).read_text()
 
     if validation_strategy_config_path is not None:
         validation_strategy_config_string = Path(validation_strategy_config_path).read_text()
@@ -148,14 +224,24 @@ def log_configs(gs_config_string: str, validation_strategy_config_raw_string: st
                                              blue_print_type=blueprint_class,
                                              gs_config=gs_config)
 
-    log_configs(gs_config_string=gs_config_string, validation_strategy_config_raw_string=validation_strategy_config_string,
-                gs_restful_api_client_constructable=gs_restful_api_client_constructable, accelerator=accelerator)
+    log_configs(gs_config_string=gs_config_string, run_config_string=run_config_string,      validation_strategy_config_raw_string=validation_strategy_config_string,
+    gs_restful_api_client_constructable=gs_restful_api_client_constructable, accelerator=accelerator)
 
     gym.run(blueprints)
 
 
 def entry_warm_start(blueprint_class: Type[BluePrint], gym: Gym, grid_search_id: int,
                      gs_restful_api_client_constructable: GridSearchAPIClientConstructableIF, num_epochs: int):
+    """
+    Create Gym class object from the run configuration
+    :params:
+       - blueprint_class (Type[BluePrint]): Blueprint class object having all the components for the GymJob.
+       - gym (Gym): Gym class object
+       - grid_search_id (int): Grid Search ID created for the run.
+       - gs_restful_api_client_constructable (GridSearchAPIClientConstructableIF): Initiated Grid Search
+       - API Client interface for performing REST calls.
+       - num_epochs(int): number of epochs to be trained to.
+    """
 
     gs_api_client = gs_restful_api_client_constructable.construct()
     experiment_statuses = gs_api_client.get_experiment_statuses(grid_search_id)
@@ -172,6 +258,10 @@ def entry_warm_start(blueprint_class: Type[BluePrint], gym: Gym, grid_search_id:
 
 
 def get_args() -> Tuple[Callable, Dict]:
+    """
+    Fetch run_config given as an argument while running run.py
+    :returns:  args (Tuple[Callable, Dict]): run_config passes with --config_path.
+    """
     parser = argparse.ArgumentParser(description='Run a grid search on CPUs or distributed over multiple GPUs')
 
     parser.add_argument('--config_path', type=str, required=True, help='Path to the run configuration file')
@@ -183,6 +273,17 @@ def get_args() -> Tuple[Callable, Dict]:
 def parse_run_configuration(run_configuration_file_path: str) -> Tuple[Union[TrainRunConfiguration, WarmStartRunConfiguration],
                                                                        Union[MultiProcessingEnvironmentConfig, AccelerateEnvironmentConfig,
                                                                        MainProcessEnvironmentConfig], LoggingConfiguration]:
+    """
+    Parsing run_config.yml file to create configs needed for mlGym to run experiments.
+    :params:
+        run_configuration_file_path (str): Path ro the run_config file.
+    :returns:  
+       - run_config (Union[..]): Tran Config object from run_config yml file.
+       - environment_config (Union[..]): Contains the environment config objects for number of processors and
+        devices which are to be used to train the model.
+       - logging_config (LoggingConfiguration): Websocket and Restful API Server endpoints.
+    """
+
     with open(run_configuration_file_path, "r") as fp:
         run_configuration_dict = yaml.safe_load(fp)
 
@@ -208,6 +309,15 @@ def parse_run_configuration(run_configuration_file_path: str) -> Tuple[Union[Tra
 
 
 def get_logging_constructables(logging_config: LoggingConfiguration) -> Tuple[LoggerConstructableIF, GridSearchAPIClientConstructableIF]:
+    """
+    Parsing run_config.yml file to create configs needed for mlGym to run experiments.
+    :params:
+        logging_config (LoggingConfiguration): Websocket and Restful API Server endpoints.
+    
+    :returns:  
+        Tuple[(GridSearchAPIClientConstructableIF): Initiated Grid Search API Client interface for performing REST calls.
+         (LoggerConstructableIF): Initiated Logging interface]
+    """
     # get logger constructables
     logger_collection_constructable = get_logger_constructable(logging_config.websocket_logging_servers)
     gs_restful_api_client_constructable = get_grid_search_restful_api_client_constructable(endpoint=logging_config.gs_rest_api_endpoint)
@@ -215,7 +325,13 @@ def get_logging_constructables(logging_config: LoggingConfiguration) -> Tuple[Lo
 
 
 def run(blueprint_class: BluePrint, run_configuration_file_path):
-
+    """
+    Parsing run_config.yml file to create configs needed for mlGym to run experiments.
+    :params:
+       - blueprint_class (BluePrint): Object of blueprint Class used for creating all the components for the GymJob.
+       - run_configuration_file_path (str): Path ro the run_config file.
+    
+    """
     run_config, env_config, logging_config = parse_run_configuration(run_configuration_file_path=run_configuration_file_path)
 
     logger_collection_constructable, gs_restful_api_client_constructable = get_logging_constructables(logging_config)
@@ -229,9 +345,9 @@ def run(blueprint_class: BluePrint, run_configuration_file_path):
     if isinstance(run_config, TrainRunConfiguration):
         gridsearch_id = datetime.now().strftime("%Y-%m-%d--%H-%M-%S")
         entry_train(gridsearch_id=gridsearch_id, blueprint_class=blueprint_class, gym=gym, gs_config_path=run_config.gs_config_path,
-                    validation_strategy_config_path=run_config.validation_config_path,
+                    run_config_path=run_configuration_file_path, validation_strategy_config_path=run_config.validation_config_path,
                     gs_restful_api_client_constructable=gs_restful_api_client_constructable,
                     accelerator=accelerator)
     elif isinstance(run_config, WarmStartRunConfiguration):
         entry_warm_start(blueprint_class=blueprint_class, gym=gym, grid_search_id=run_config.gridsaerch_id,
-                         gs_restful_api_client_constructable=gs_restful_api_client_constructable, num_epochs=run_config.num_epochs)
+                         gs_restful_api_client_constructable=gs_restful_api_client_constructable, num_epochs=run_config.num_epochs)
\ No newline at end of file
diff --git a/src/ml_gym/data_handling/dataset_loader.py b/src/ml_gym/data_handling/dataset_loader.py
index 78fa0a79..2ca35ab3 100644
--- a/src/ml_gym/data_handling/dataset_loader.py
+++ b/src/ml_gym/data_handling/dataset_loader.py
@@ -13,11 +13,27 @@
 
 
 class DatasetLoaderFactory:
+    """
+    Class containing methedolgies to load dataset in the MlGym job to be worked on.
+    """
 
     @staticmethod
-    def get_splitted_data_loaders_deprecated(dataset_splits: Dict[str, InformedDatasetIteratorIF], batch_size: int, collate_fn: Callable = None,
-                                             weigthed_sampling_split_name: str = None, label_pos: int = 2, seeds: Dict[str, int] = None,
-                                             drop_last: bool = False) -> Dict[str, "DatasetLoader"]:
+    def get_splitted_data_loaders_deprecated(dataset_splits: Dict[str, InformedDatasetIteratorIF], batch_size: int, collate_fn: Callable = None, weigthed_sampling_split_name: str = None, label_pos: int = 2, seeds: Dict[str, int] = None,drop_last: bool = False
+    ) -> Dict[str, "DatasetLoader"]:
+        """
+        Get the spliited data based on the wighted sampling. (DEPRECATED)
+        :params:
+            - dataset_splits (Dict[str, InformedDatasetIteratorIF]): List of splits of the dataset to be made.
+            - batch_size (int): Batch size for the data set.
+            - collate_fn (Callable): TO DO
+            - weigthed_sampling_split_name (str): Weighted sampling to be used for the splits.
+            - label_pos (int): param for random generator.
+            - seeds (Dict[str, int]): Seeds for random sampler.
+            - drop_last (bool): TO DO
+
+        :return:
+            data_loaders (Dict[str, "DatasetLoader"]): Data loaded based on the splits and sampling stratergy.
+        """
         seeds = {} if seeds is None else seeds
         # NOTE: Weighting is only applied to the split specified by `weigthed_sampling_split_name`.
         data_loaders = {}
@@ -38,6 +54,18 @@ def get_splitted_data_loaders_deprecated(dataset_splits: Dict[str, InformedDatas
     @staticmethod
     def get_splitted_data_loaders(dataset_splits: Dict[str, InformedDatasetIteratorIF], batch_size: int, collate_fn: Callable = None,
                                   drop_last: bool = False, sampling_strategies: Dict[str, Any] = None) -> Dict[str, "DatasetLoader"]:
+        """
+        Get the spliited data based on the sampling stratergy.
+        :params:
+            - dataset_splits (Dict[str, InformedDatasetIteratorIF]): List of splits of the dataset to be made.
+            - batch_size (int): Batch size for the data set.
+            - collate_fn (Callable): TO DO
+            - drop_last (bool): TO DO
+            - sampling_strategies (Dict[str, Any]): What type of sampling stratergy to be used for the splits.
+
+        :return:
+            data_loaders (Dict[str, "DatasetLoader"]): Data loaded based on the splits and sampling stratergy.
+        """
         data_loaders = {}
         for split_name, dataset_split in dataset_splits.items():
             if split_name in sampling_strategies:
@@ -97,11 +125,27 @@ def get_weighted_sampler(dataset: InformedDatasetIteratorIF, label_pos: int = 2,
 
     @staticmethod
     def get_random_sampler(dataset: InformedDatasetIteratorIF, seed: int = 0) -> Sampler:
+        """
+        Create sequential sample on the dataset.
+        :params:
+            - dataset (InformedDatasetIteratorIF): Dataset
+            - seed (int): Seed for the generator
+            
+        :return:
+            RandomSampler object created on the dataset to provide randomly generated samples.
+        """
         rnd_generator = torch.Generator().manual_seed(seed) if seed is not None else None
         return RandomSampler(data_source=dataset, generator=rnd_generator)
 
     @staticmethod
     def get_sequential_sampler(dataset: InformedDatasetIteratorIF) -> Sampler:
+        """
+        Create sequential sample on the dataset.
+        :params:
+            dataset (InformedDatasetIteratorIF): Dataset
+        :return:
+            SequentialSampler object created on the dataset to provide sequential samples.
+        """
         return SequentialSampler(data_source=dataset)
 
 
@@ -119,6 +163,9 @@ def dataset_tag(self) -> str:
 
 
 class DatasetLoader(DatsetLoaderMetaInfoIF, DataLoader):
+    """
+    Data Set loader class. Uses the toech class DataLaoder to load data for mlgym model which is iterable.
+    """
     def __init__(self, dataset_iterator: InformedDatasetIteratorIF, batch_size: int, sampler: Sampler,
                  collate_fn: Collator = None, drop_last: bool = False):
         super().__init__(dataset=dataset_iterator, sampler=sampler, batch_size=batch_size, collate_fn=collate_fn, drop_last=drop_last)
diff --git a/src/ml_gym/data_handling/postprocessors/collator.py b/src/ml_gym/data_handling/postprocessors/collator.py
index 8265ea46..13d6b5f6 100644
--- a/src/ml_gym/data_handling/postprocessors/collator.py
+++ b/src/ml_gym/data_handling/postprocessors/collator.py
@@ -6,7 +6,9 @@
 
 @dataclass
 class Collator(Callable):
-
+    """
+    To DO
+    """
     device: torch.device = field(default_factory=lambda: torch.device("cpu"))
 
     @abstractmethod
diff --git a/src/ml_gym/data_handling/postprocessors/factory.py b/src/ml_gym/data_handling/postprocessors/factory.py
index 3cb75c4d..44927711 100644
--- a/src/ml_gym/data_handling/postprocessors/factory.py
+++ b/src/ml_gym/data_handling/postprocessors/factory.py
@@ -9,9 +9,22 @@
 
 
 class ModelGymInformedIteratorFactory(InformedDatasetFactory):
-
+    """
+    ModelGymInformedIteratorFactory contains all the methods to create iterators which
+    allows to loop through the dataset in multiple ways.
+    """
     @staticmethod
     def get_mapped_labels_iterator(identifier: str, iterator: DatasetIteratorIF, mappings: Dict) -> InformedDatasetIteratorIF:
+        """
+        Get the iterator that can iterate through mapped labels in the dataset.
+        :params:
+            - identifier (str): Tag used as an identifier for the dataset.
+            - iterator (DatasetIteratorIF): Dataset Iterator Interface object.
+            - mappings (Dict): Mapping of labels to iterators.
+
+        :return:
+            InformedDatasetIteratorIF: Initialized Interface containing dataset iterators.
+        """
         label_mapper_post_processor = LabelMapperPostProcessor(mappings=mappings,
                                                                target_position=iterator.dataset_meta.target_pos,
                                                                tag_position=iterator.dataset_meta.tag_pos)
@@ -21,6 +34,16 @@ def get_mapped_labels_iterator(identifier: str, iterator: DatasetIteratorIF, map
     @staticmethod
     def get_filtered_labels_iterator(identifier: str, iterator: InformedDatasetIteratorIF,
                                      filtered_labels: List[Any]) -> InformedDatasetIteratorIF:
+        """
+        Get the iterator that can iterate through filtered labels in the dataset.
+        :params:
+            - identifier (str): Tag used as an identifier for the dataset.
+            - iterator (InformedDatasetIteratorIF): Dataset Iterator Interface object.
+            - filtered_labels (List[Any]): List of filtered labels in the dataset.
+
+        :return:
+            InformedDatasetIteratorIF: Initialized Interface containing dataset iterators.
+        """
         valid_indices = [i for i in range(len(iterator)) if iterator[i][iterator.dataset_meta.target_pos] in filtered_labels]
         meta = MetaFactory.get_dataset_meta_from_existing(iterator.dataset_meta, identifier=identifier)
         return InformedDatasetFactory.get_dataset_iterator_view(iterator, meta, valid_indices)
@@ -28,6 +51,17 @@ def get_filtered_labels_iterator(identifier: str, iterator: InformedDatasetItera
     @staticmethod
     def get_iterator_view(identifier: str, iterator: InformedDatasetIteratorIF, selection_fun: Callable[[DatasetIteratorIF], List[int]],
                           view_tags: Dict[str, Any]) -> InformedDatasetIteratorIF:
+        """
+        Get the iterator used for accessing elements of a given split only.
+        :params:
+            - identifier (str): Tag used as an identifier for the dataset.
+            - iterator (InformedDatasetIteratorIF): Dataset Iterator Interface object.
+            - selection_fun (Callable[[DatasetIteratorIF]): Callable function
+            - view_tags (Dict[str, Any]): View tags used as an identifier.
+
+        :return:
+            InformedDatasetIteratorIF: Initialized Interface containing dataset iterators.
+        """
         valid_indices = selection_fun(iterator)
         # valid_indices = list(np.argwhere(valid_mask).flatten())
         meta = MetaFactory.get_dataset_meta_from_existing(iterator.dataset_meta, identifier=identifier)
@@ -36,6 +70,16 @@ def get_iterator_view(identifier: str, iterator: InformedDatasetIteratorIF, sele
     @staticmethod
     def get_feature_encoded_iterators(identifier: str, iterators: Dict[str, InformedDatasetIteratorIF],
                                       feature_encoding_configs: Dict[str, List[Any]]) -> Dict[str, DatasetIteratorIF]:
+        """
+        Get the iterator which can iterate through encoded fetures of a dataset.
+        :params:
+            - identifier (str): Tag used as an identifier for the dataset.
+            - iterators (Dict[str, InformedDatasetIteratorIF]): Dictionary mapping from iterator_name -> split_name -> iterator
+            - feature_encoding_configs (Dict[str, List[Any]]): Dictionary containing feature encoding configs.
+
+        :return:
+             Dict[str, DatasetIteratorIF]: Dictionary containing name of iterator and intialzied DatasetIteratorIF object.
+        """
         sample_position = list(iterators.items())[0][1].dataset_meta.sample_pos
         feature_encoder_post_processor = FeatureEncoderPostProcessor(
             sample_position=sample_position, feature_encoding_configs=feature_encoding_configs)
@@ -48,6 +92,16 @@ def get_feature_encoded_iterators(identifier: str, iterators: Dict[str, Informed
     @staticmethod
     def get_one_hot_encoded_target_iterators(identifier: str, iterators: Dict[str, InformedDatasetIteratorIF],
                                              target_vector_size: int) -> Dict[str, DatasetIteratorIF]:
+        """
+        Get the iterator which can iterate through one hot encoded target vector of a dataset.
+        :params:
+            - identifier (str): Tag used as an identifier for the dataset.
+            - iterators (Dict[str, InformedDatasetIteratorIF]): Dictionary mapping from iterator_name -> split_name -> iterator
+            - target_vector_size (int): Size of target vector.
+
+        :return:
+             Dict[str, DatasetIteratorIF]: Dictionary containing name of iterator and intialzied DatasetIteratorIF object.
+        """
         target_position = list(iterators.items())[0][1].dataset_meta.target_pos
         postprocessor = OneHotEncodedTargetPostProcessor(target_vector_size=target_vector_size, target_position=target_position)
         return {name: InformedDatasetFactory.get_dataset_iterator(PostProcessedDatasetIterator(iterator, postprocessor), MetaFactory.get_dataset_meta_from_existing(iterator.dataset_meta, identifier=identifier))
@@ -55,15 +109,16 @@ def get_one_hot_encoded_target_iterators(identifier: str, iterators: Dict[str, I
 
     @staticmethod
     def get_combined_iterators(identifier: str, iterators: Dict[str, Dict[str, InformedDatasetIteratorIF]], combine_configs: Dict) -> Dict[str, InformedDatasetIteratorIF]:
-        """Combines iterators.
+        """
+        Combines iterators.
 
-        Args:
-            identifier (str):
+        params:
+            identifier (str): Tag used as an identifier for the dataset.
             iterators (Dict[str, Dict[str, InformedDatasetIteratorIF]]): Dictionary mapping from iterator_name -> split_name -> iterator
-            combine_configs (Dict):
+            combine_configs (Dict): Configuration instructing combination of iterators.
 
-        Returns:
-            Dict[str, InformedDatasetIteratorIF]:
+        :return:
+            Dict[str, InformedDatasetIteratorIF]: Dictionary containing name of iterator and intialzied DatasetIteratorIF object.
         """
 
         def get_iterators_to_be_combined(iterators: Dict[str, Dict[str, InformedDatasetIteratorIF]], split_config: List):
@@ -81,6 +136,19 @@ def get_iterators_to_be_combined(iterators: Dict[str, Dict[str, InformedDatasetI
     @staticmethod
     def get_splitted_iterators(identifier: str, iterators: Dict[str, InformedDatasetIteratorIF], seed: int,
                                stratified: bool, split_config: Dict) -> Dict[str, InformedDatasetIteratorIF]:
+        """
+        Get Splits iterators.
+
+        params:
+           - identifier (str): Tag used as an identifier for the dataset.
+           - iterators (Dict[str, Dict[str, InformedDatasetIteratorIF]]): Dictionary mapping from iterator_name -> split_name -> iterator
+           - seed (int): Seed for random generator.
+           - stratified (bool): Whether splits should be stratified.
+           - split_config (Dict): Configuration containing split of iterators.
+
+        :return:
+            Dict[str, InformedDatasetIteratorIF]: Dictionary containing name of iterator and intialzied DatasetIteratorIF object.
+        """
         def _split(iterator: InformedDatasetIteratorIF, seed: int, split_config: Dict) -> Dict[str, InformedDatasetIteratorIF]:
             names = list(split_config.keys())
             ratios = list(split_config.values())
@@ -107,10 +175,31 @@ def _split(iterator: InformedDatasetIteratorIF, seed: int, split_config: Dict) -
 
     @staticmethod
     def get_in_memory_iterator(identifier: str, iterator: InformedDatasetIteratorIF) -> InformedDatasetIteratorIF:
+        """
+        Get iterator in memory.
+
+        params:
+           - identifier (str): Tag used as an identifier for the dataset.
+           - iterator (InformedDatasetIteratorIF): Dataset Iterator Interface object.
+
+        :return:
+            InformedDatasetIteratorIF:  intialzied InformedDatasetIteratorIF object in memory.
+        """
         meta = MetaFactory.get_dataset_meta_from_existing(iterator.dataset_meta, identifier=identifier)
         return InformedDatasetFactory.get_in_memory_dataset_iterator(iterator, meta)
 
     @staticmethod
     def get_shuffled_iterator(identifier: str, iterator: InformedDatasetIteratorIF, seed: int) -> InformedDatasetIteratorIF:
+        """
+        Get iterator shuffled.
+
+        params:
+           - identifier (str): Tag used as an identifier for the dataset.
+           - iterator (InformedDatasetIteratorIF): Dataset Iterator Interface object.
+           - seed (int): Random seed.
+
+        :return:
+            InformedDatasetIteratorIF:  intialzied InformedDatasetIteratorIF object.
+        """
         meta = MetaFactory.get_dataset_meta_from_existing(iterator.dataset_meta, identifier=identifier)
         return InformedDatasetFactory.get_shuffled_dataset_iterator(iterator, meta, seed)
\ No newline at end of file
diff --git a/src/ml_gym/error_handling/exception.py b/src/ml_gym/error_handling/exception.py
index d661f954..7cd9d255 100644
--- a/src/ml_gym/error_handling/exception.py
+++ b/src/ml_gym/error_handling/exception.py
@@ -134,3 +134,7 @@ class EarlyStoppingCriterionFulfilledError(Exception):
 class GymError(Exception):
     """Raised when an error occurs within the gym or during gym instantiation."""
     pass
+
+class SystemInfoFetchError(Exception):
+    """Raised when an error occurs during fetching system information."""
+    pass
diff --git a/src/ml_gym/gym/evaluators/accelerate_evaluator.py b/src/ml_gym/gym/evaluators/accelerate_evaluator.py
index 4136f1f2..143c3586 100644
--- a/src/ml_gym/gym/evaluators/accelerate_evaluator.py
+++ b/src/ml_gym/gym/evaluators/accelerate_evaluator.py
@@ -21,7 +21,19 @@ def __init__(self, eval_component: "AccelerateEvalComponent"):
 
     def evaluate(self, model: NNModel, accelerator: Accelerator, epoch_result_callback_fun: Callable = None,
                  batch_processed_callback_fun: Callable = None) -> List[EvaluationBatchResult]:
-        model = model.eval()
+        """
+        Evaulate torch NN Model.
+
+        :params:
+           - model (NNModel): Torch Neural Network module
+           - accelerator (Accelerator): Accelerator object used for distributed training over multiple GPUs.
+           - epoch_result_callback_fun (Callable): numner of batches to be trained.
+           - batch_processed_callback_fun (Callable): Batch number for which details to be logged.
+
+        :returns:
+            evaluation_batch_results (List[EvaluationBatchResult]): Evaluation results of batches trained on.
+        """
+        model.eval()
 
         # returns a EvaluationBatchResult for each split
         evaluation_batch_results = self.eval_component.evaluate(model=model, accelerator=accelerator,
@@ -55,11 +67,37 @@ def __init__(self, inference_component: InferenceComponent, post_processors: Dic
 
     def evaluate(self, model: NNModel, accelerator: Accelerator, epoch_result_callback_fun: Callable = None,
                  batch_processed_callback_fun: Callable = None) -> List[EvaluationBatchResult]:
+        """
+        Evaulate torch NN Model.
+
+        :params:
+           - model (NNModel): Torch Neural Network module.
+           - accelerator (Accelerator): Accelerator object used for distributed training over multiple GPUs.
+           - epoch_result_callback_fun (Callable): numner of batches to be trained.
+           - batch_processed_callback_fun (Callable): Batch number for which details to be logged.
+
+        :returns:
+            evaluation_batch_results (List[EvaluationBatchResult]): Evaluation results of batches trained on.
+        """
         return [self.evaluate_dataset_split(model, split_name, loader, accelerator, epoch_result_callback_fun, batch_processed_callback_fun) for split_name, loader in self.dataset_loaders.items()]
 
     def evaluate_dataset_split(self, model: NNModel, split_name: str,
                                dataset_loader: DatasetLoader, accelerator: Accelerator, epoch_result_callback_fun: Callable = None,
                                batch_processed_callback_fun: Callable = None) -> EvaluationBatchResult:
+        """
+        Evaulate torch NN Model on specific split of Data.
+
+        :params:
+           - model (NNModel): Torch Neural Network module.
+           - split_name (str): Name of split of Dataset being evaluated.
+           - dataset_loader (DatasetLoader): Obhect of DatasetLoader used to load Data to be trained on.
+           - accelerator (Accelerator): Accelerator object used for distributed training over multiple GPUs.
+           - epoch_result_callback_fun (Callable): numner of batches to be trained.
+           - batch_processed_callback_fun (Callable): Batch number for which details to be logged.
+
+        :returns:
+            evaluation_result (EvaluationBatchResult): Evaluation results of batches trained on.
+        """
         post_processors = self.post_processors[split_name] + self.post_processors["default"]
 
         # calc losses
@@ -131,14 +169,47 @@ def evaluate_dataset_split(self, model: NNModel, split_name: str,
 
     def _get_metric_fun(self, identifier: str, target_subscription: Enum, prediction_subscription: Enum,
                         metric_fun: Callable, params: Dict[str, Any]) -> Metric:
+        """
+        Creating Metric object to be used for calcualting Metrics for the model.
+
+        :params:
+           - identifier (str): Torch Neural Network module.
+           - target_subscription (Enum): Target Subscription key.
+           - prediction_subscription (Enum): Prediction Subscription key.
+           - metric_fun (Callable): Function to calculate Metric.
+           - params (Dict[str, Any]): Parameters for metric calcualtion.
+
+        :returns:
+            Metric object (Metric)
+        """
         return Metric(identifier, target_subscription, prediction_subscription, metric_fun, params)
 
     def forward_batch(self, dataset_batch: DatasetBatch, model: NNModel,
                       postprocessors: List[PredictPostProcessingIF]) -> InferenceResultBatch:
+        """
+        NN Model predict on dataset batch.
+
+        :params:
+           - dataset_batch (DatasetBatch): Train Dataset.
+           - model (NNModel): Torch Neural Network module.
+           - postprocessors (List[PredictPostProcessingIF]): TODO
+
+        :returns:
+            inference_result_batch (InferenceResultBatch): Predicttion performed on the model.
+        """
         inference_result_batch = self.inference_component.predict(model, dataset_batch, postprocessors)
         return inference_result_batch
 
     def _calculate_metric_scores(self, inference_batch: InferenceResultBatch, split_metrics: List[Metric]) -> Dict[str, List[float]]:
+        """
+        Calcualtion of metric scores on the splits of data set.
+
+        :params:
+           - inference_batch (InferenceResultBatch): Predicttion performed on the model.
+           - split_metrics (List[Metric]): Metrics for each split of data.
+        :returns:
+            metric_scores (Dict[str, List[float]]): Metric scores for splits.
+        """
         metric_scores = {}
         for metric in split_metrics:
             try:
@@ -148,6 +219,15 @@ def _calculate_metric_scores(self, inference_batch: InferenceResultBatch, split_
         return metric_scores
 
     def _calculate_loss_scores(self, forward_batch: InferenceResultBatch, split_loss_funs: Dict[str, Loss]) -> Dict[str, List[float]]:
+        """
+        Calcualtion of loss scores on the splits of data set.
+
+        :params:
+           - forward_batch (InferenceResultBatch): Predicttion performed on the model.
+           - split_loss_funs (Dict[str, Loss]): Loss functions for splits.
+        :returns:
+            loss_scores (Dict[str, Loss]): Loss scores for splits.
+        """
         loss_scores = {}
         for loss_key, loss_fun in split_loss_funs.items():
             try:
@@ -158,6 +238,15 @@ def _calculate_loss_scores(self, forward_batch: InferenceResultBatch, split_loss
         return loss_scores
 
     def _get_batch_loss(self, loss_fun: Loss, forward_batch: InferenceResultBatch) -> List[torch.Tensor]:
+        """
+        Evaulate torch NN Model on specific split of Data.
+
+        :params:
+           - loss_fun (Loss): Loss function.
+           - forward_batch (InferenceResultBatch): Predicttion performed on the model.
+        :returns:
+            loss (List[torch.Tensor]): Loss list for batch.
+        """
         loss = loss_fun(forward_batch)
         loss = [loss.sum()]
         return loss
diff --git a/src/ml_gym/gym/evaluators/evaluator.py b/src/ml_gym/gym/evaluators/evaluator.py
index 1e639745..13b3e38e 100644
--- a/src/ml_gym/gym/evaluators/evaluator.py
+++ b/src/ml_gym/gym/evaluators/evaluator.py
@@ -71,11 +71,37 @@ def __init__(self, inference_component: InferenceComponent, post_processors: Dic
 
     def evaluate(self, model: NNModel, device: torch.device, epoch_result_callback_fun: Callable = None,
                  batch_processed_callback_fun: Callable = None) -> List[EvaluationBatchResult]:
+        """
+        Evaulate torch NN Model.
+
+        :params:
+           - model (NNModel): Torch Neural Network module.
+           - device (torch.device): Torch device either CPUs or a specified GPU.
+           - epoch_result_callback_fun (Callable): numner of batches to be trained.
+           - batch_processed_callback_fun (Callable): Batch number for which details to be logged.
+
+        :returns:
+            evaluation_result (List[EvaluationBatchResult]): Evaluation results of batches trained on.
+        """
         return [self.evaluate_dataset_split(model, device, split_name, loader, epoch_result_callback_fun, batch_processed_callback_fun) for split_name, loader in self.dataset_loaders.items()]
 
     def evaluate_dataset_split(self, model: NNModel, device: torch.device, split_name: str,
                                dataset_loader: DatasetLoader, epoch_result_callback_fun: Callable = None,
                                batch_processed_callback_fun: Callable = None) -> EvaluationBatchResult:
+        """
+        Evaulate torch NN Model on specific split of Data.
+
+        :params:
+           - model (NNModel): Torch Neural Network module.
+           - device (torch.device): Torch device either CPUs or a specified GPU.
+           - split_name (str): Name of split of Dataset being evaluated.
+           - dataset_loader (DatasetLoader): Obhect of DatasetLoader used to load Data to be trained on.
+           - epoch_result_callback_fun (Callable): numner of batches to be trained.
+           - batch_processed_callback_fun (Callable): Batch number for which details to be logged.
+
+        :returns:
+            evaluation_result (EvaluationBatchResult): Evaluation results of batches trained on.
+        """
         dataset_loader.device = device
         dataset_loader_iterator = tqdm.tqdm(dataset_loader, desc=f"Evaluating {dataset_loader.dataset_name} - {split_name}") if self.show_progress else dataset_loader
         post_processors = self.post_processors[split_name] + self.post_processors["default"]
@@ -137,15 +163,50 @@ def evaluate_dataset_split(self, model: NNModel, device: torch.device, split_nam
 
     def _get_metric_fun(self, identifier: str, target_subscription: Enum, prediction_subscription: Enum,
                         metric_fun: Callable, params: Dict[str, Any]) -> Metric:
+        """
+        Creating Metric object to be used for calcualting Metrics for the model.
+
+        :params:
+           - identifier (str): Torch Neural Network module.
+           - target_subscription (Enum): Target Subscription key.
+           - prediction_subscription (Enum): Prediction Subscription key.
+           - metric_fun (Callable): Function to calculate Metric.
+           - params (Dict[str, Any]): Parameters for metric calcualtion.
+
+        :returns:
+            Metric object (Metric)
+        """
         return Metric(identifier, target_subscription, prediction_subscription, metric_fun, params)
 
     def forward_batch(self, dataset_batch: DatasetBatch, model: NNModel, device: torch.device, postprocessors: List[PredictPostProcessingIF]) -> InferenceResultBatch:
+        """
+        NN Model predict on dataset batch.
+
+        :params:
+           - dataset_batch (DatasetBatch): Train Dataset.
+           - model (NNModel): Torch Neural Network module.
+           - device (torch.device): Torch device either CPUs or a specified GPU.
+           - postprocessors (List[PredictPostProcessingIF]): TODO
+
+        :returns:
+            inference_result_batch (InferenceResultBatch): Predicttion performed on the model.
+        """
         model = model.to(device)
         dataset_batch.to(device)
         inference_result_batch = self.inference_component.predict(model, dataset_batch, postprocessors)
         return inference_result_batch
 
     def _calculate_metric_scores(self, inference_batch: InferenceResultBatch, split_metrics: List[Metric]) -> Dict[str, List[float]]:
+        """
+        Calcualtion of metric scores on the splits of data set.
+
+        :params:
+           - inference_batch (InferenceResultBatch): Predicttion performed on the model.
+           - split_metrics (List[Metric]): Metrics for each split of data.
+
+        :returns:
+            metric_scores (Dict[str, List[float]]): Metric scores for splits.
+        """
         metric_scores = {}
         for metric in split_metrics:
             try:
@@ -155,6 +216,16 @@ def _calculate_metric_scores(self, inference_batch: InferenceResultBatch, split_
         return metric_scores
 
     def _calculate_loss_scores(self, forward_batch: InferenceResultBatch, split_loss_funs: Dict[str, Loss]) -> Dict[str, List[float]]:
+        """
+        Calcualtion of loss scores on the splits of data set.
+
+        :params:
+           - forward_batch (InferenceResultBatch): Predicttion performed on the model.
+           - split_loss_funs (Dict[str, Loss]): Loss functions for splits.
+
+        :returns:
+            loss_scores (Dict[str, Loss]): Loss scores for splits.
+        """
         loss_scores = {}
         for loss_key, loss_fun in split_loss_funs.items():
             try:
@@ -165,6 +236,16 @@ def _calculate_loss_scores(self, forward_batch: InferenceResultBatch, split_loss
         return loss_scores
 
     def _get_batch_loss(self, loss_fun: Loss, forward_batch: InferenceResultBatch) -> List[float]:
+        """
+        Evaulate torch NN Model on specific split of Data.
+
+        :params:
+           - loss_fun (Loss): Loss function.
+           - forward_batch (InferenceResultBatch): Predicttion performed on the model.
+           
+        :returns:
+            loss (List[torch.Tensor]): Loss list for batch.
+        """
         loss = loss_fun(forward_batch)
         loss = [loss.sum().detach().item()]
         return loss
diff --git a/src/ml_gym/gym/gym.py b/src/ml_gym/gym/gym.py
index 58d81abf..f646683e 100644
--- a/src/ml_gym/gym/gym.py
+++ b/src/ml_gym/gym/gym.py
@@ -17,16 +17,37 @@
 
 
 class Gym(ABC):
+    """
+    Gym Class skeleton to initialize Gym Job
+    """
     def __init__(self, logger_collection_constructable: MLgymStatusLoggerCollectionConstructable):
+        """
+        Executes the jobs. Note that this function blocks until all jobs have been executed!
+        :params:
+            blueprints (List[BluePrint]): List of Blueprint class objects.
+        """
         self.job_status_logger = JobStatusLogger(logger_collection_constructable.construct())
 
+
     @abstractmethod
     def run(self, blueprints: List[BluePrint]):
-        """Executes the jobs. Note that this function blocks until all jobs have been executed!
+        """
+        Executes the jobs. Note that this function blocks until all jobs have been executed!
+        :params:
+            blueprints (List[BluePrint]): List of Blueprint class objects.
         """
         raise NotImplementedError
 
     def get_jobs_from_blueprints(self, blueprints: List[BluePrint], exec_fun: Callable) -> List[Job]:
+        """
+        Executes the jobs. Note that this function blocks until all jobs have been executed!
+        :params:
+           - blueprints (List[BluePrint]): List of Blueprint class objects.
+           - exec_fun (Callable): Callable function instance
+        
+        :returns:
+            jobs (List[Job]): Number of jobs created to run the mlgym model.
+        """
         jobs = []
         for job_id, blueprint in enumerate(blueprints):
             job = Job(job_id=f"{blueprint.grid_search_id}-{job_id}", fun=exec_fun, blueprint=blueprint)
@@ -39,6 +60,10 @@ def get_jobs_from_blueprints(self, blueprints: List[BluePrint], exec_fun: Callab
 
 
 class ParallelSingleNodeGym(Gym):
+    """
+    Class to run jobs in parallel. Inititated based on the GymType.
+    This class is used when we have more than one node.
+    """
     def __init__(self, logger_collection_constructable: MLgymStatusLoggerCollectionConstructable,
                  exec_fun: Callable, process_count: int = 1, device_ids: List[int] = None):
         super().__init__(logger_collection_constructable)
@@ -56,6 +81,10 @@ def run(self, blueprints: List[BluePrint]):
 
 
 class SequentialGym(Gym):
+    """
+    Class to run jobs in Sequence. Inititated based on the GymType.
+    This class is used when we have only one node.
+    """
     def __init__(self, logger_collection_constructable: MLgymStatusLoggerCollectionConstructable,
                  exec_fun: Callable, device_id: int = None):
         super().__init__(logger_collection_constructable)
@@ -77,11 +106,19 @@ def work(self, job: Job):
 
 
 class GymType(Enum):
+    """
+    GymType to tell what Gym class to run.
+    :params:
+        Enum: Enumeration label. 
+    """
     SEQUENTIAL_GYM = SequentialGym
     PARALLEL_SINGLE_NODE_GYM = ParallelSingleNodeGym
 
 
 class GymFactory:
+    """
+    GymFactory is a class which contains all of the methods which initialzie what type of job to run for the mlgym model.
+    """
 
     @staticmethod
     def get_sequential_gym(logger_collection_constructable: MLgymStatusLoggerCollectionConstructable,
@@ -89,6 +126,18 @@ def get_sequential_gym(logger_collection_constructable: MLgymStatusLoggerCollect
                            num_epochs: int, device_id: int = None,
                            num_batches_per_epoch: int = None,
                            accelerator: Accelerator = None) -> Gym:
+        """
+        Function to create a Gym Job for Sequential form of processing.
+        :params:
+           - logger_collection_constructable (MLgymStatusLoggerCollectionConstructable): Logging interface
+           - gs_restful_api_client_constructable (GridSearchAPIClientConstructableIF): Interface to initiate GridSearchAPIClient
+           - num_epochs(int): number of epochs to be trained to.
+           - device_id(int): Device name to run model job on.
+           - num_batches_per_epoch (int): numner of batches to be trained per epoch.
+           - accelerator (Accelerator): Accelerator object used for distributed training over multiple GPUs
+
+        :returns: gym(Gym): Gym class object
+        """       
         if accelerator is not None:
             exec_fun = partial(GymFactory._run_accelerate_gym_job, logger_collection_constructable=logger_collection_constructable,
                                gs_restful_api_client_constructable=gs_restful_api_client_constructable,
@@ -109,6 +158,19 @@ def get_parallel_single_node_gym(logger_collection_constructable: MLgymStatusLog
                                      gs_restful_api_client_constructable: GridSearchAPIClientConstructable,
                                      num_epochs: int, process_count: int = 1, device_ids: List[int] = None,
                                      num_batches_per_epoch: int = None) -> Gym:
+        """
+        Function to create a Gym Job for parallel form of processing.
+        :params:
+           - logger_collection_constructable (MLgymStatusLoggerCollectionConstructable): Logging interface
+           - gs_restful_api_client_constructable (GridSearchAPIClientConstructableIF): Interface to initiate GridSearchAPIClient
+           - num_epochs(int): number of epochs to be trained to.
+           - process_count(int): How may processes will the model be running on.
+           - device_ids(List[int]): Device name to run model job on.
+           - num_batches_per_epoch (int): numner of batches to be trained per epoch.
+           - accelerator (Accelerator): Accelerator object used for distributed training over multiple GPUs
+
+        :returns: gym(Gym): Gym class object
+        """  
 
         exec_fun = partial(GymFactory._run_standard_gym_job, logger_collection_constructable=logger_collection_constructable,
                            gs_restful_api_client_constructable=gs_restful_api_client_constructable,
@@ -122,10 +184,23 @@ def _run_standard_gym_job(blueprint: BluePrint, device: torch.device, num_epochs
                               logger_collection_constructable: MLgymStatusLoggerCollectionConstructable,
                               gs_restful_api_client_constructable: GridSearchAPIClientConstructable,
                               num_batches_per_epoch: int = None):
+        """
+        Function to run a standard Gym job.
+        :params:
+           - blueprint (BluePrint): Gym Job object.
+           - device (torch.device): CPU or GPU type pf device for the job to run in.
+           - num_epochs(int): number of epochs to be trained to.
+           - logger_collection_constructable (MLgymStatusLoggerCollectionConstructable): Logging interface
+           - gs_restful_api_client_constructable (GridSearchAPIClientConstructableIF): Interface to initiate GridSearchAPIClient
+           - num_batches_per_epoch (int): numner of batches to be trained per epoch.
+
+        :returns: gym(Gym): Gym class object
+        """ 
         gym_job = GymJobFactory.get_gym_job_from_blueprint(blueprint, device=device, num_epochs=num_epochs,
                                                            logger_collection_constructable=logger_collection_constructable,
                                                            gs_restful_api_client_constructable=gs_restful_api_client_constructable,
                                                            num_batches_per_epoch=num_batches_per_epoch)
+
         return gym_job.execute(device=device)
 
     @staticmethod
@@ -133,10 +208,22 @@ def _run_accelerate_gym_job(blueprint: BluePrint, num_epochs: int,
                                 logger_collection_constructable: MLgymStatusLoggerCollectionConstructable,
                                 gs_restful_api_client_constructable: GridSearchAPIClientConstructable,
                                 accelerator: Accelerator, num_batches_per_epoch: int = None):
+        """
+        Function to run a Accelerate Gym job used to run model on different nodes.
+        :params:
+           - blueprint (BluePrint): Gym Job object.
+           - num_epochs(int): number of epochs to be trained to.
+           - logger_collection_constructable (MLgymStatusLoggerCollectionConstructable): Logging interface.
+           - gs_restful_api_client_constructable (GridSearchAPIClientConstructableIF): Interface to initiate GridSearchAPIClient.
+           - accelerator (Accelerator): Accelerator object used for distributed training over multiple GPUs.
+           - num_batches_per_epoch (int): numner of batches to be trained per epoch.
+
+        :returns: gym(Gym): Gym class object
+        """ 
         gym_job = GymJobFactory.get_accelerate_gymjob_from_blueprint(blueprint,
                                                                      num_epochs=num_epochs,
                                                                      logger_collection_constructable=logger_collection_constructable,
                                                                      gs_restful_api_client_constructable=gs_restful_api_client_constructable,
                                                                      num_batches_per_epoch=num_batches_per_epoch,
                                                                      accelerator=accelerator)
-        return gym_job.execute()
+        return gym_job.execute()
\ No newline at end of file
diff --git a/src/ml_gym/gym/gym_jobs/accelerate_gym_job.py b/src/ml_gym/gym/gym_jobs/accelerate_gym_job.py
index c1c628df..e9580c23 100644
--- a/src/ml_gym/gym/gym_jobs/accelerate_gym_job.py
+++ b/src/ml_gym/gym/gym_jobs/accelerate_gym_job.py
@@ -18,6 +18,9 @@
 
 
 class AccelerateGymJob(AbstractGymJob):
+    """
+    Accelerate Gym Job class used for running job on multiple GPUs.
+    """
 
     def __init__(self, experiment_status_logger: ExperimentStatusLogger, gs_api_client: GridSearchAPIClientIF,
                  grid_search_id: str, experiment_id: int, run_mode: RunMode, num_epochs: int,
@@ -40,6 +43,14 @@ def execute(self):
         self._experiment_status_logger.disconnect()
 
     def _evaluation_step(self, current_epoch: int) -> List[EvaluationBatchResult]:
+        """ 
+        Evaluating the model.
+
+        :params:
+            current_epoch (int): Current epoch number for cerating checkpoints.
+        :returns:
+            evaluation_results (List[EvaluationBatchResult]): Object storing entire evaluation infotmation.
+        """
         partial_batch_processed_callback = partial(self.batch_processed_callback, num_epochs=self.num_epochs,
                                                    current_epoch=current_epoch,
                                                    experiment_status_logger=self._experiment_status_logger)
@@ -54,27 +65,34 @@ def _evaluation_step(self, current_epoch: int) -> List[EvaluationBatchResult]:
         return evaluation_results
 
     def _execute_train(self):
+        """ 
+        Execute training of the model.
+        """
         self.optimizer.register_model_params(model_params=dict(self.model.named_parameters()))
         self.lr_scheduler.register_optimizer(optimizer=self.optimizer)
 
-        self.model, self.optimizer, self.trainer, self.evaluator, self.lr_scheduler, train_loader = self.accelerator.prepare(self.model,
-                                                                                                                             self.optimizer,
-                                                                                                                             self.trainer,
-                                                                                                                             self.evaluator,
-                                                                                                                             self.lr_scheduler,
-                                                                                                                             self.trainer.train_loader)
+        eval_loader_keys, eval_loaders_list = zip(*self.evaluator.eval_component.dataset_loaders.items())
+
+        self.model, self.optimizer, self.lr_scheduler, train_loader, *eval_acc_loaders_list = self.accelerator.prepare(self.model,
+                                                                                                                       self.optimizer,
+                                                                                                                       self.lr_scheduler,
+                                                                                                                       self.trainer.train_loader,
+                                                                                                                       *eval_loaders_list)
+
+        eval_loaders = {k: v for k, v in zip(eval_loader_keys, eval_acc_loaders_list)}
+
         self.trainer.train_loader = DatasetLoaderFactory.get_data_loader_shard_wrapper(data_loader_shard=train_loader,
                                                                                        dataset_name=self.trainer.train_loader.dataset_name,
                                                                                        dataset_tag=self.trainer.train_loader.dataset_tag)
 
         self.evaluator.eval_component.dataset_loaders = {key: DatasetLoaderFactory.get_data_loader_shard_wrapper(
-            data_loader_shard=self.accelerator.prepare(data_loader),
+            data_loader_shard=eval_loaders[key],
             dataset_name=data_loader.dataset_name,
             dataset_tag=data_loader.dataset_tag) for key, data_loader in self.evaluator.eval_component.dataset_loaders.items()}
 
         partial_batch_done_callback = partial(self.batch_processed_callback, experiment_status_logger=self._experiment_status_logger)
         def evaluation_step_routine(current_epoch: int): return self._evaluation_step(current_epoch=current_epoch)
-        partial_train_epoch_done_callback = partial(self.train_epoch_done_callback, evaluation_step_routine=evaluation_step_routine, 
+        partial_train_epoch_done_callback = partial(self.train_epoch_done_callback, evaluation_step_routine=evaluation_step_routine,
                                                     accelerator=self.accelerator)
 
         model = self.trainer.train(num_epochs=self.num_epochs, model=self.model, optimizer=self.optimizer,
@@ -84,6 +102,9 @@ def evaluation_step_routine(current_epoch: int): return self._evaluation_step(cu
         self.accelerator.free_memory()
 
     def _execute_warm_start(self):
+        """ 
+        Execute warm start of the model from an epoch.
+        """
         if self.current_epoch > 0:
             model_state = pickle.loads(self.gs_api_client.get_checkpoint_resource(grid_search_id=self.grid_search_id,
                                                                                   experiment_id=self.experiment_id,
diff --git a/src/ml_gym/gym/gym_jobs/gym_job.py b/src/ml_gym/gym/gym_jobs/gym_job.py
index c24aa393..3ffbe6eb 100644
--- a/src/ml_gym/gym/gym_jobs/gym_job.py
+++ b/src/ml_gym/gym/gym_jobs/gym_job.py
@@ -1,5 +1,8 @@
 from abc import abstractmethod
+import os
+import pickle
 from typing import Callable, List
+from ml_board.backend.restful_api.data_models import CheckpointResource
 from ml_gym.batching.batch import EvaluationBatchResult
 from ml_gym.checkpointing.checkpointing import CheckpointingIF, CheckpointingInstruction
 from ml_gym.early_stopping.early_stopping_strategies import EarlyStoppingIF
@@ -16,9 +19,14 @@
 from ml_gym.persistency.logging import ExperimentStatusLogger
 import torch
 from accelerate import Accelerator
+import shutil
+import tempfile
 
 
 class AbstractGymJob(StatefulComponent):
+    """
+    Class contating all running and config information for Gym Job.
+    """
 
     def __init__(self, experiment_status_logger: ExperimentStatusLogger, gs_api_client: GridSearchAPIClientIF,
                  grid_search_id: str, experiment_id: int, run_mode: RunMode, num_epochs: int,
@@ -60,33 +68,63 @@ def __init__(self, experiment_status_logger: ExperimentStatusLogger, gs_api_clie
     def execute(self, device: torch.device):
         raise NotImplementedError
 
-    def run_checkpointing(self, checkpoint_instruction: CheckpointingInstruction, current_epoch: int):
+    def run_checkpointing(self, checkpoint_instruction: CheckpointingInstruction, current_epoch: int, accelerator: Accelerator = None):
         """
         Create and delete checkpoints for each epoch in experiments.
 
         :params:
-            checkpoint_instruction: CheckpointingInstruction object
+           - checkpoint_instruction (CheckpointingInstruction): CheckpointingInstruction object.
+           - current_epoch (int): Current epoch number for cerating checkpoints.
         """
-
         if checkpoint_instruction.save_current:
-            payload_dict = {
-                "epoch": current_epoch,
-                "model": self.model.state_dict(),
-                "optimizer": self.optimizer.state_dict(),
-                "lr_scheduler": self.lr_scheduler.state_dict(),
-                "stateful_components": self.get_state(),
-            }
 
-            self.gs_api_client.add_checkpoint_resource(
-                grid_search_id=self.grid_search_id, experiment_id=self.experiment_id, payload=payload_dict
-            )
+            if accelerator is not None:
+                global_rank = accelerator.process_index
+                # TODO replace with an in-memory file system solution
+                with tempfile.TemporaryDirectory() as tmpdirname:
+                    root_dir = os.path.join(tmpdirname, f"epoch_{current_epoch}/rank_{global_rank}")
+                    checkpoint_file_name = f"checkpoint_rank_{global_rank}"
+                    checkpoint_path = os.path.join(root_dir, f"rank_{global_rank}/")
+                    accelerator.save_state(output_dir=checkpoint_path)
+                    shutil.make_archive(base_name=os.path.join(root_dir, checkpoint_file_name), format='zip', root_dir=checkpoint_path)
+                    with open(os.path.join(root_dir, f"{checkpoint_file_name}.zip"), 'rb') as fd:
+                        self.gs_api_client.add_checkpoint_resource(grid_search_id=self.grid_search_id, experiment_id=self.experiment_id,
+                                                                   epoch=current_epoch, payload_stream=fd,
+                                                                   custom_file_name=f"{checkpoint_file_name}.zip")
+
+            else:
+                payload_dict = {
+                    CheckpointResource.model: pickle.dumps(self.model.state_dict()),
+                    CheckpointResource.optimizer: pickle.dumps(self.optimizer.state_dict()),
+                    CheckpointResource.lr_scheduler: pickle.dumps(self.lr_scheduler.state_dict()),
+                    CheckpointResource.stateful_components: pickle.dumps(self.get_state())
+                }
+
+                for checkpoint_resource_key, checkpoint_resource_stream in payload_dict.items():
+                    self.gs_api_client.add_checkpoint_resource(grid_search_id=self.grid_search_id, experiment_id=self.experiment_id,
+                                                               epoch=current_epoch, payload_stream=checkpoint_resource_stream,
+                                                               custom_file_name=f"{checkpoint_resource_key}.pickle")
 
-        for epoch in checkpoint_instruction.checkpoints_to_delete:
-            self.gs_api_client.delete_checkpoints(grid_search_id=self.grid_search_id, experiment_id=self.experiment_id, epoch=epoch)
+        if accelerator is None or accelerator is not None and accelerator.is_main_process:
+            for epoch in checkpoint_instruction.checkpoints_to_delete:
+                self.gs_api_client.delete_checkpoints(grid_search_id=self.grid_search_id, experiment_id=self.experiment_id, epoch=epoch)
 
     @staticmethod
     def batch_processed_callback(status: str, experiment_status_logger: ExperimentStatusLogger, num_batches: int,
                                  current_batch: int, splits: List[str], current_split: str, num_epochs: int, current_epoch: int):
+        """
+        Log experiment details for processed batch of data.
+
+        :params:
+           - status (str): CheckpointingInstruction object.
+           - experiment_status_logger (ExperimentStatusLogger): Epoch/Experiment number for cerating checkpoints.
+           - num_batches (int): numner of batches to be trained.
+           - current_batch (int): Batch number for which details to be logged.
+           - splits (List[str]): Splits list for the data
+           - current_split (str): Current split of the data.
+           - num_epochs(int): number of epochs to be trained to.
+           - current_epoch (int): Current epoch number.
+        """
         if (current_batch % max(1, int(num_batches/10))) == 0:  # TODO make update period configurable
             experiment_status_logger.log_experiment_status(status=status,
                                                            num_epochs=num_epochs,
@@ -99,18 +137,36 @@ def batch_processed_callback(status: str, experiment_status_logger: ExperimentSt
     @staticmethod
     def epoch_result_callback(experiment_status_logger: ExperimentStatusLogger, evaluation_result: EvaluationBatchResult,
                               current_epoch: int):
+        """
+        Log evaluation details for an epoch.
+
+        :params:
+           - experiment_status_logger (ExperimentStatusLogger): Epoch/Experiment number for cerating checkpoints.
+           - evaluation_result (EvaluationBatchResult): Object storing entire epoch infotmation.
+           - current_epoch (int): Current epoch number.
+        """
         experiment_status_logger.log_evaluation_results(evaluation_result, current_epoch)
 
     def train_epoch_done_callback(self, num_epochs: int, current_epoch: int, model: NNModel, evaluation_step_routine: Callable,
                                   accelerator: Accelerator = None):
+        """
+        Log evaluation details for an epoch.
+
+        :params:
+           - num_epochs (int): Number of epochs to be trained.
+           - current_epoch (int): Current epoch number.
+           - model (NNModel): Torch Neural Network module.
+           - evaluation_step_routine (Callable): Epoch/Experiment number for cerating checkpoints.
+           - accelerator (Accelerator): Accelerator object used for distributed training over multiple GPUs.
+        """
         evaluation_results = evaluation_step_routine(current_epoch=current_epoch)
         if current_epoch > 0:
             self.lr_scheduler.step()
-        if accelerator is None or accelerator is not None and accelerator.is_main_process:
-            checkpointing_instruction = self.checkpointing_strategy.get_model_checkpoint_instruction(num_epochs=num_epochs,
-                                                                                                     current_epoch=current_epoch,
-                                                                                                     evaluation_result=evaluation_results)
-            self.run_checkpointing(checkpointing_instruction, current_epoch=current_epoch)
+        checkpointing_instruction = self.checkpointing_strategy.get_model_checkpoint_instruction(num_epochs=num_epochs,
+                                                                                                 current_epoch=current_epoch,
+                                                                                                 evaluation_result=evaluation_results)
+        self.run_checkpointing(checkpointing_instruction, current_epoch=current_epoch, accelerator=accelerator)
+
         if self.early_stopping_strategy.is_stopping_criterion_fulfilled(current_epoch=current_epoch,
                                                                         evaluation_results=evaluation_results):
             raise EarlyStoppingCriterionFulfilledError
diff --git a/src/ml_gym/gym/gym_jobs/gym_job_factory.py b/src/ml_gym/gym/gym_jobs/gym_job_factory.py
index 94034f78..dd36f698 100644
--- a/src/ml_gym/gym/gym_jobs/gym_job_factory.py
+++ b/src/ml_gym/gym/gym_jobs/gym_job_factory.py
@@ -9,12 +9,25 @@
 
 
 class GymJobFactory:
+    """
+    Class used to create GymJob to work on single or multiple CPU/GPU.
+    """
 
     @staticmethod
     def get_gym_job_from_blueprint(blueprint: BluePrint, device: torch.device, num_epochs: int,
                                    logger_collection_constructable: MLgymStatusLoggerCollectionConstructable,
                                    gs_restful_api_client_constructable: GridSearchAPIClientConstructable,
                                    num_batches_per_epoch: int = None) -> AbstractGymJob:
+        """
+        Create Gym Job to be used on single CPU or GPU.
+        :params:
+           - blueprint (BluePrint): Blueprint class object having all the components for the GymJob.
+           - device (torch.device): Torch device either CPUs or a specified GPU.
+           - num_epochs(int): number of epochs to be trained to.
+           - logger_collection_constructable (LoggerConstructableIF): Logging interface
+           - gs_restful_api_client_constructable (GridSearchAPIClientConstructableIF): Interface to initiate GridSearchAPIClient
+           - num_batches_per_epoch (int): Number of batches to be trained per epoch.
+        """ 
         components = blueprint.construct(device)
 
         logger_collection = logger_collection_constructable.construct()
@@ -39,6 +52,16 @@ def get_accelerate_gymjob_from_blueprint(blueprint: BluePrint, num_epochs: int,
                                              gs_restful_api_client_constructable: GridSearchAPIClientConstructable,
                                              accelerator: Accelerator,
                                              num_batches_per_epoch: int = None) -> AbstractGymJob:
+        """
+        Create Gym Job to be used on multiple GPUs using Accelerate.
+        :params:
+           - blueprint (BluePrint): Blueprint class object having all the components for the GymJob.
+           - num_epochs(int): number of epochs to be trained to.
+           - logger_collection_constructable (LoggerConstructableIF): Logging interface
+           - gs_restful_api_client_constructable (GridSearchAPIClientConstructableIF): Interface to initiate GridSearchAPIClient
+           - accelerator (Accelerator): Accelerator object used for distributed training over multiple GPUs.
+           - num_batches_per_epoch (int): Number of batches to be trained per epoch.
+        """ 
         components = blueprint.construct()
 
         logger_collection = logger_collection_constructable.construct()
diff --git a/src/ml_gym/gym/gym_jobs/standard_gym_job.py b/src/ml_gym/gym/gym_jobs/standard_gym_job.py
index 86f0fbad..503554e7 100644
--- a/src/ml_gym/gym/gym_jobs/standard_gym_job.py
+++ b/src/ml_gym/gym/gym_jobs/standard_gym_job.py
@@ -18,6 +18,9 @@
 
 
 class StandardGymJob(AbstractGymJob):
+    """
+    Standard Gym Job class used for running job on single CPU or GPU.
+    """
 
     def __init__(self, experiment_status_logger: ExperimentStatusLogger, gs_api_client: GridSearchAPIClientIF,
                  grid_search_id: str, experiment_id: int, run_mode: RunMode, num_epochs: int,
@@ -33,13 +36,21 @@ def __init__(self, experiment_status_logger: ExperimentStatusLogger, gs_api_clie
     def execute(self, device: torch.device):
         """ Executes the job
 
-        Args:
-            device: torch device either CPUs or a specified GPU
+        :params:
+            device (torch.device): torch device either CPUs or a specified GPU
         """
         self._execution_method(device)
         self._experiment_status_logger.disconnect()
 
     def _train_step(self, device: torch.device) -> NNModel:
+        """ 
+        Training the model.
+
+        :params:
+            device (torch.device): torch device either CPUs or a specified GPU
+        :returns:
+            model (NNModel): Neural Net torch model. 
+        """
         partial_batch_processed_callback = partial(AbstractGymJob.batch_processed_callback, num_epochs=self.num_epochs,
                                                    experiment_status_logger=self._experiment_status_logger)
         model = self.trainer.train_epoch(self.model, self.optimizer, device,
@@ -47,6 +58,16 @@ def _train_step(self, device: torch.device) -> NNModel:
         return model
 
     def _evaluation_step(self, current_epoch: int, device: torch.device) -> List[EvaluationBatchResult]:
+        """ 
+        Evaluating the model.
+
+        :params:
+           - current_epoch (int): Current epoch number for cerating checkpoints.
+           - device (torch.device): torch device either CPUs or a specified GPU
+
+        :returns:
+            evaluation_results (EvaluationBatchResult): Object storing entire evaluation infotmation.
+        """
         partial_batch_processed_callback = partial(AbstractGymJob.batch_processed_callback, num_epochs=self.num_epochs,
                                                    current_epoch=current_epoch,
                                                    experiment_status_logger=self._experiment_status_logger)
@@ -61,6 +82,12 @@ def _evaluation_step(self, current_epoch: int, device: torch.device) -> List[Eva
         return evaluation_results
 
     def _execute_train(self, device: torch.device):
+        """ 
+        Execute training of the model.
+
+        :params:
+            device (torch.device): torch device either CPUs or a specified GPU
+        """
         self.optimizer.register_model_params(model_params=dict(self.model.named_parameters()))
         self.lr_scheduler.register_optimizer(optimizer=self.optimizer)
 
@@ -77,6 +104,13 @@ def evaluation_step_routine(current_epoch: int): return self._evaluation_step(de
             print(f"Early stopping criterion matched. Stopping training.")
 
     def _execute_warm_start(self, device: torch.device, warm_start_epoch: int):
+        """ 
+        Execute warm start of the model from an epoch.
+
+        :params:
+           - device (torch.device): torch device either CPUs or a specified GPU.
+           - warm_start_epoch (int): Epoch to start Training from.
+        """
         model_state = pickle.loads(self.gs_api_client.get_checkpoint_resource(grid_search_id=self.grid_search_id,
                                                                               experiment_id=self.experiment_id,
                                                                               checkpoint_id=warm_start_epoch,
diff --git a/src/ml_gym/gym/inference_component.py b/src/ml_gym/gym/inference_component.py
index eda5934b..07faf85f 100644
--- a/src/ml_gym/gym/inference_component.py
+++ b/src/ml_gym/gym/inference_component.py
@@ -13,6 +13,17 @@ def __init__(self, no_grad=True):
         self.no_grad = no_grad
 
     def predict(self, model: NNModel, batch: DatasetBatch, post_processors: List[PredictPostProcessingIF] = None) -> InferenceResultBatch:
+        """
+        Perform prediction on the torch NN Model.
+
+        :params:
+           - model (NNModel): Torch Neural Network module.
+           - batch (DatasetBatch): Train Dataset.
+           - post_processors (List[PredictPostProcessingIF]): Batch number for which details to be logged.
+           
+        :returns:
+            result_batch (InferenceResultBatch): Predicttion performed on the model.
+        """
         post_processors = post_processors if post_processors is not None else []
         if self.no_grad:
             with torch.no_grad():
diff --git a/src/ml_gym/gym/post_processing.py b/src/ml_gym/gym/post_processing.py
index bc7124ca..94286011 100644
--- a/src/ml_gym/gym/post_processing.py
+++ b/src/ml_gym/gym/post_processing.py
@@ -5,6 +5,9 @@
 
 
 class PredictPostProcessingIF(ABC):
+    """
+    Interface to perform prediction on the torch NN Model for the entire btach.
+    """
 
     @abstractmethod
     def postprocess(self, result_batch: InferenceResultBatch) -> InferenceResultBatch:
@@ -12,6 +15,9 @@ def postprocess(self, result_batch: InferenceResultBatch) -> InferenceResultBatc
 
 
 class PredictPostProcessing(PredictPostProcessingIF):
+    """
+    Class providing function to perform prediction on the torch NN Model for the entire btach.
+    """
 
     def __init__(self, postprocessing_impl: PredictPostProcessingIF):
         self.postprocessing_impl = postprocessing_impl
@@ -23,28 +29,53 @@ def postprocess(self, result_batch: InferenceResultBatch) -> InferenceResultBatc
 # Postprocessing Implementations
 
 class SoftmaxPostProcessorImpl(PredictPostProcessingIF):
+    """
+    Class to perform prediction on the torch NN Model for the entire btach using SoftMax.
+    """
     def __init__(self, prediction_subscription_key: str, prediction_publication_key: str):
         self.prediction_subscription_key = prediction_subscription_key
         self.prediction_publication_key = prediction_publication_key
 
     def postprocess(self, result_batch: InferenceResultBatch) -> InferenceResultBatch:
+        """
+        Perform prediction on the torch NN Model for the entire btach using SoftMax.
+
+        :params:
+            result_batch (InferenceResultBatch): Predicttion performed on the model.
+        :returns:
+            result_batch (InferenceResultBatch): Predicttion performed on the model.
+        """
         predictions = nn.Softmax(dim=1)(result_batch.get_predictions(self.prediction_subscription_key))
         result_batch.add_predictions(key=self.prediction_publication_key, predictions=predictions)
         return result_batch
 
 
 class ArgmaxPostProcessorImpl(PredictPostProcessingIF):
+    """
+    Class to perform prediction on the torch NN Model for the entire btach using ArgMax.
+    """
     def __init__(self, prediction_subscription_key: str, prediction_publication_key: str):
         self.prediction_subscription_key = prediction_subscription_key
         self.prediction_publication_key = prediction_publication_key
 
     def postprocess(self, result_batch: InferenceResultBatch) -> InferenceResultBatch:
+        """
+        Perform prediction on the torch NN Model for the entire btach using ArgMax.
+
+        :params:
+            result_batch (InferenceResultBatch): Predicttion performed on the model.
+        :returns:
+            result_batch (InferenceResultBatch): Predicttion performed on the model.
+        """
         predictions = torch.argmax(result_batch.get_predictions(self.prediction_subscription_key), dim=1)
         result_batch.add_predictions(key=self.prediction_publication_key, predictions=predictions)
         return result_batch
 
 
 class MaxOrMinPostProcessorImpl(PredictPostProcessingIF):
+    """
+    Class to perform prediction on the torch NN Model for the entire btach using Max and Min.
+    """
     def __init__(self, prediction_subscription_key: str, prediction_publication_key: str, agg_fun: str):
         self.prediction_subscription_key = prediction_subscription_key
         self.prediction_publication_key = prediction_publication_key
@@ -56,18 +87,37 @@ def __init__(self, prediction_subscription_key: str, prediction_publication_key:
             raise NotImplementedError("agg_fun={agg_fun} is not an applicable parameter")
 
     def postprocess(self, result_batch: InferenceResultBatch) -> InferenceResultBatch:
+        """
+        Perform prediction on the torch NN Model for the entire btach using Max and Min.
+
+        :params:
+            result_batch (InferenceResultBatch): Predicttion performed on the model.
+        :returns:
+            result_batch (InferenceResultBatch): Predicttion performed on the model.
+        """
         predictions = self.agg_fun(result_batch.get_predictions(self.prediction_subscription_key), dim=1)[0]
         result_batch.add_predictions(key=self.prediction_publication_key, predictions=predictions)
         return result_batch
 
 
 class BinarizationPostProcessorImpl(PredictPostProcessingIF):
+    """
+    Class to perform prediction on the torch NN Model for the entire btach using Zero Like Binarizaton.
+    """
     def __init__(self, prediction_subscription_key: str, prediction_publication_key: str, threshold=0.5):
         self.prediction_subscription_key = prediction_subscription_key
         self.prediction_publication_key = prediction_publication_key
         self.threshold = threshold
 
     def postprocess(self, result_batch: InferenceResultBatch) -> InferenceResultBatch:
+        """
+        Perform prediction on the torch NN Model for the entire btach using Zero Like Binarizaton.
+
+        :params:
+            result_batch (InferenceResultBatch): Predicttion performed on the model.
+        :returns:
+            result_batch (InferenceResultBatch): Predicttion performed on the model.
+        """
         predictions = result_batch.get_predictions(self.prediction_subscription_key)
         binarized_outputs = torch.zeros_like(predictions).int()
         binarized_outputs[predictions > self.threshold] = 1
@@ -76,11 +126,22 @@ def postprocess(self, result_batch: InferenceResultBatch) -> InferenceResultBatc
 
 
 class SigmoidalPostProcessorImpl(PredictPostProcessingIF):
+    """
+    Class to perform prediction on the torch NN Model for the entire btach using Sigmoid.
+    """
     def __init__(self, prediction_subscription_key: str, prediction_publication_key: str, threshold=0.5):
         self.prediction_subscription_key = prediction_subscription_key
         self.prediction_publication_key = prediction_publication_key
 
     def postprocess(self, result_batch: InferenceResultBatch) -> InferenceResultBatch:
+        """
+        Perform prediction on the torch NN Model for the entire btach using Sigmoid.
+
+        :params:
+            result_batch (InferenceResultBatch): Predicttion performed on the model.
+        :returns:
+            result_batch (InferenceResultBatch): Predicttion performed on the model.
+        """
         predictions = result_batch.get_predictions(self.prediction_subscription_key)
         sigmoidal_predictions = torch.sigmoid(predictions)
         result_batch.add_predictions(key=self.prediction_publication_key, predictions=sigmoidal_predictions)
diff --git a/src/ml_gym/gym/predict_postprocessing_component.py b/src/ml_gym/gym/predict_postprocessing_component.py
index b202295a..c5a7d747 100644
--- a/src/ml_gym/gym/predict_postprocessing_component.py
+++ b/src/ml_gym/gym/predict_postprocessing_component.py
@@ -7,6 +7,16 @@ class PredictPostprocessingComponent:
 
     @staticmethod
     def post_process(result_batch: InferenceResultBatch, post_processors: List[PredictPostProcessingIF]) -> InferenceResultBatch:
+        """
+        Perform prediction on the torch NN Model for the entire btach.
+
+        :params:
+           - result_batch (InferenceResultBatch): Predicttion performed on the model.
+           - post_processors (List[PredictPostProcessingIF]): Batch number for which details to be logged.
+           
+        :returns:
+            result_batch (InferenceResultBatch): Predicttion performed on the model.
+        """
         for post_processor in post_processors:
             result_batch = post_processor.postprocess(result_batch)
         return result_batch
diff --git a/src/ml_gym/gym/trainers/accelerate_trainer.py b/src/ml_gym/gym/trainers/accelerate_trainer.py
index 913d58a8..f7aa0d51 100644
--- a/src/ml_gym/gym/trainers/accelerate_trainer.py
+++ b/src/ml_gym/gym/trainers/accelerate_trainer.py
@@ -14,6 +14,9 @@
 
 
 class AccelerateTrainComponent(StatefulComponent):
+    """
+    AccelerateTrainComponent class used when there are multiple GPUs to train model.
+    """
     def __init__(self, inference_component: InferenceComponent, post_processors: List[PredictPostProcessingIF],
                  loss_fun: Loss):
         self.loss_fun = loss_fun
@@ -21,6 +24,18 @@ def __init__(self, inference_component: InferenceComponent, post_processors: Lis
         self.post_processors = post_processors
 
     def _train_batch(self, accelerator: Accelerator, batch: DatasetBatch, model: NNModel, optimizer: OptimizerAdapter) -> NNModel:
+        """
+        Train torch NN Model with a batch.
+
+        :params:
+           - batch (DatasetBatch): Train Dataset.
+           - model (NNModel): Torch Neural Network module.
+           - optimizer (OptimizerAdapter): Object of OptimizerAdapter used to initaite optimizer for model.
+           - device (torch.device): Torch device either CPUs or a specified GPU.
+
+        :returns:
+            model (NNModel): Torch Neural Network module.
+        """
         model.zero_grad()
         loss = self.calc_loss(model, batch).sum()
 
@@ -48,6 +63,24 @@ def _train_batch(self, accelerator: Accelerator, batch: DatasetBatch, model: NNM
     def train(self, model: NNModel, optimizer: OptimizerAdapter, dataloader: DatasetLoader,
               accelerator: Accelerator, batch_done_callback_fun: Callable, epoch_done_callback_fun: Callable,
               num_epochs: int, num_batches_per_epoch: int = None) -> NNModel:
+        """
+        Train torch NN Model.
+
+        :params:
+           - model (NNModel): Torch Neural Network module.
+           - optimizer (OptimizerAdapter): Object of OptimizerAdapter used to initaite optimizer for model.
+           - dataloader (DatasetLoader): Obhect of DatasetLoader used to load Data to be trained on.
+           - accelerator (Accelerator): Accelerator object used for distributed training over multiple GPUs.
+           - batch_done_callback_fun (Callable): Batch number for which details to be logged.
+           - epoch_done_callback_fun (Callable): numner of batches to be trained.
+           - num_epochs(int): number of epochs to be trained to.
+           - num_batches_per_epoch (int): numner of batches to be trained per epoch.
+
+        :returns:
+            model (NNModel): Torch Neural Network module.
+        """
+
+        model.train()
 
         if num_batches_per_epoch is None:
             num_batches_per_epoch = len(dataloader)
@@ -69,16 +102,29 @@ def train(self, model: NNModel, optimizer: OptimizerAdapter, dataloader: Dataset
                                         current_epoch=current_epoch)
             if (batch_id + 1) % num_batches_per_epoch == 0:  # when epoch done
                 epoch_done_callback_fun(num_epochs=num_epochs, current_epoch=current_epoch, model=model, accelerator=accelerator)
-
+                model.train()
         return model
 
     def calc_loss(self, model: NNModel, batch: DatasetBatch) -> torch.Tensor:
+        """
+        Valvulate loss given the loss function.
+
+        :params:
+           - model (NNModel): Torch Neural Network module.
+           - batch (DatasetBatch); Batch of data for which loss is to be calcualted.
+
+        :returns:
+            loss (List[torch.Tensor]): Loss list for batch.
+        """
         forward_batch = self.inference_component.predict(batch=batch, model=model, post_processors=self.post_processors)
         loss = self.loss_fun(forward_batch)
         return loss
 
 
 class AccelerateTrainer:
+    """
+    Trainer class contains functions used to train the torch Neural Net model on GPU
+    """
     def __init__(self, train_component: AccelerateTrainComponent, train_loader: DatasetLoader):
         self.train_component = train_component
         self.train_loader = train_loader
@@ -86,8 +132,21 @@ def __init__(self, train_component: AccelerateTrainComponent, train_loader: Data
     def train(self, num_epochs: int, model: NNModel, optimizer: OptimizerAdapter,
               batch_done_callback_fun: Callable, epoch_done_callback: Callable, accelerator: Accelerator,
               num_batches_per_epoch: int = None) -> NNModel:
-
-        model = model.train()
+        """
+        Train torch NN Model.
+
+        :params:
+           - num_epochs (int): Number of epochs to be trained.
+           - model (NNModel): Torch Neural Network module.
+           - optimizer (OptimizerAdapter): Object of OptimizerAdapter used to initaite optimizer for model.
+           - batch_done_callback_fun (Callable): Batch number for which details to be logged.
+           - epoch_done_callback (Callable): numner of batches to be trained.
+           - accelerator (Accelerator): Accelerator object used for distributed training over multiple GPUs.
+           - num_batches_per_epoch (int): number of batches to be trained per epoch.
+           
+        :returns:
+            model (NNModel): Torch Neural Network module.
+        """
 
         # accelerate_train_loader = accelerator.prepare(self.train_loader)
 
diff --git a/src/ml_gym/gym/trainers/standard_trainer.py b/src/ml_gym/gym/trainers/standard_trainer.py
index e4361707..4f57b2d4 100644
--- a/src/ml_gym/gym/trainers/standard_trainer.py
+++ b/src/ml_gym/gym/trainers/standard_trainer.py
@@ -13,6 +13,9 @@
 
 
 class TrainComponent(StatefulComponent):
+    """
+    TrainComponent class used when there is only one CPU or GPU to train model.
+    """
     def __init__(self, inference_component: InferenceComponent, post_processors: List[PredictPostProcessingIF],
                  loss_fun: Loss):
         self.loss_fun = loss_fun
@@ -20,6 +23,18 @@ def __init__(self, inference_component: InferenceComponent, post_processors: Lis
         self.post_processors = post_processors
 
     def _train_batch(self, batch: DatasetBatch, model: NNModel, optimizer: OptimizerAdapter, device: torch.device):
+        """
+        Train torch NN Model with a batch.
+
+        :params:
+           - batch (DatasetBatch): Train Dataset
+           - model (NNModel): Torch Neural Network module.
+           - optimizer (OptimizerAdapter): Object of OptimizerAdapter used to initaite optimizer for model.
+           - device (torch.device): Torch device either CPUs or a specified GPU.
+
+        :returns:
+            model (NNModel): Torch Neural Network module.
+        """
         model = model.to(device)
         batch.to(device)
         model.zero_grad()
@@ -31,6 +46,21 @@ def _train_batch(self, batch: DatasetBatch, model: NNModel, optimizer: Optimizer
     def train(self, model: NNModel, optimizer: OptimizerAdapter, dataloader: DatasetLoader, device: torch.device,
               batch_done_callback_fun: Callable, epoch_done_callback_fun: Callable,
               num_epochs: int, num_batches_per_epoch: int = None) -> NNModel:
+        """
+        Train torch NN Model.
+
+        :params:
+           - model (NNModel): Torch Neural Network module.
+           - optimizer (OptimizerAdapter): Object of OptimizerAdapter used to initaite optimizer for model.
+           - dataloader (DatasetLoader): Obhect of DatasetLoader used to load Data to be trained on.
+           - device (torch.device): Torch device either CPUs or a specified GPU.
+           - batch_done_callback_fun (Callable): Batch number for which details to be logged.
+           - epoch_done_callback_fun (Callable): numner of batches to be trained.
+
+        :returns:
+            model (NNModel): Torch Neural Network module.
+        """
+        model.train()
 
         if num_batches_per_epoch is None:
             num_batches_per_epoch = len(dataloader)
@@ -54,16 +84,30 @@ def train(self, model: NNModel, optimizer: OptimizerAdapter, dataloader: Dataset
 
             if (batch_id + 1) % num_batches_per_epoch == 0:  # when epoch done
                 epoch_done_callback_fun(num_epochs=num_epochs, current_epoch=current_epoch, model=model)
+                model.train()
 
         return model
 
     def calc_loss(self, model: NNModel, batch: DatasetBatch) -> torch.Tensor:
+        """
+        Valvulate loss given the loss function.
+
+        :params:
+           - model (NNModel): Torch Neural Network module
+           - batch (DatasetBatch); Batch of data for which loss is to be calcualted.
+
+        :returns:
+            loss (List[torch.Tensor]): Loss list for batch.
+        """
         forward_batch = self.inference_component.predict(batch=batch, model=model, post_processors=self.post_processors)
         loss = self.loss_fun(forward_batch)
         return loss
 
 
 class Trainer:
+    """
+    Trainer class contains functions used to train the torch Neural Net model on CPU.
+    """
     def __init__(self, train_component: TrainComponent, train_loader: DatasetLoader):
         self.train_component = train_component
         self.train_loader = train_loader
@@ -71,8 +115,22 @@ def __init__(self, train_component: TrainComponent, train_loader: DatasetLoader)
     def train(self, num_epochs: int, model: NNModel, optimizer: OptimizerAdapter, device: torch.device,
               batch_done_callback_fun: Callable, epoch_done_callback: Callable,
               num_batches_per_epoch: int = None) -> NNModel:
+        """
+        Train torch NN Model.
+
+        :params:
+           - num_epochs (int): Number of epochs to be trained.
+           - model (NNModel): Torch Neural Network module.
+           - optimizer (OptimizerAdapter): Object of OptimizerAdapter used to initaite optimizer for model.
+           - device (torch.device): Torch device either CPUs or a specified GPU.
+           - batch_done_callback_fun (Callable): Batch number for which details to be logged.
+           - epoch_done_callback (Callable): numner of batches to be trained.
+           - num_batches_per_epoch (int): number of batches to be trained per epoch.
+           
+        :returns:
+            model (NNModel): Torch Neural Network module.
+        """
 
-        model = model.train()
 
         model = self.train_component.train(model=model, optimizer=optimizer, dataloader=self.train_loader, device=device,
                                            batch_done_callback_fun=batch_done_callback_fun, epoch_done_callback_fun=epoch_done_callback,
diff --git a/src/ml_gym/gym/worker.py b/src/ml_gym/gym/worker.py
index 5f58a3e5..ed527657 100644
--- a/src/ml_gym/gym/worker.py
+++ b/src/ml_gym/gym/worker.py
@@ -3,6 +3,9 @@
 
 
 class WorkerIF(ABC):
+    """
+    Worker Interface
+    """
 
     @abstractmethod
     def work(job: AbstractGymJob):
@@ -10,6 +13,9 @@ def work(job: AbstractGymJob):
 
 
 class Worker(WorkerIF):
+    """
+    Worker class providing function to run gym job.
+    """
 
     def __init__(self):
         pass
diff --git a/src/ml_gym/io/config_parser.py b/src/ml_gym/io/config_parser.py
index f5fce80c..0d28322f 100644
--- a/src/ml_gym/io/config_parser.py
+++ b/src/ml_gym/io/config_parser.py
@@ -3,6 +3,9 @@
 
 
 class YAMLConfigLoader:
+    """
+    Load Yaml files and unpack configuration.
+    """
 
     @staticmethod
     def load(path: str):
diff --git a/src/ml_gym/loss_functions/loss_factory.py b/src/ml_gym/loss_functions/loss_factory.py
index 79387bfe..a3db9553 100644
--- a/src/ml_gym/loss_functions/loss_factory.py
+++ b/src/ml_gym/loss_functions/loss_factory.py
@@ -4,10 +4,28 @@
 
 
 class LossFactory:
+    """
+    Class containing all loss functions to be used by MlGym job models.
+    """
 
     @staticmethod
     def get_lp_loss(target_subscription_key: str, prediction_subscription_key: str, root: int = 1, exponent: int = 2,
                     class_selection_fun_params: Dict = None, average_batch_loss: bool = True, tag: str = "") -> Loss:
+        """
+        Get Lp Loss object from params. 
+
+        :params:
+           - target_subscription_key (str): Loss function.
+           - prediction_subscription_key (str): Predicttion performed on the model.
+           - root (int): Root Value in Loss equation.
+           - exponent (int): Exponent value in Loss equation.
+           - class_selection_fun_params (Dict): TO DO
+           - average_batch_loss (bool): Average Loss value for the batch of data.
+           - tag (str): Label to be tagged with the loss object. 
+
+        :returns:
+            LPLoss: Object of LPLoss.
+        """
         sample_selection_fun = BatchFilter.get_class_selection_fun(
             **class_selection_fun_params) if class_selection_fun_params is not None else None
         return LPLoss(target_subscription_key, prediction_subscription_key, root, exponent, sample_selection_fun, tag, average_batch_loss)
@@ -20,12 +38,34 @@ def get_lp_loss(target_subscription_key: str, prediction_subscription_key: str,
 
     @staticmethod
     def get_cross_entropy_loss(target_subscription_key: str, prediction_subscription_key: str, tag: str = "") -> Loss:
+        """
+        Get Cross Entropy Loss Object from params.
+
+        :params:
+           - target_subscription_key (str): Loss function.
+           - prediction_subscription_key (str): Predicttion performed on the model.
+           - tag (str): Label to be tagged with the loss object. 
+
+        :returns:
+            CrossEntropyLoss: Object of CrossEntropyLoss.
+        """
         return CrossEntropyLoss(target_subscription_key=target_subscription_key,
                                 prediction_subscription_key=prediction_subscription_key,
                                 tag=tag)
 
     @staticmethod
     def get_nll_loss(target_subscription_key: str, prediction_subscription_key: str, tag: str = "") -> Loss:
+        """
+        Get Negative log Likelihood Loss Object from params.
+
+        :params:
+           - target_subscription_key (str): Loss function.
+           - prediction_subscription_key (str): Predicttion performed on the model.
+           - tag (str): Label to be tagged with the loss object. 
+
+        :returns:
+            NLLLoss: Object of NLLLoss.
+        """
         return NLLLoss(target_subscription_key=target_subscription_key,
                        prediction_subscription_key=prediction_subscription_key,
                        tag=tag)
@@ -33,6 +73,19 @@ def get_nll_loss(target_subscription_key: str, prediction_subscription_key: str,
     @staticmethod
     def get_bce_with_logits_loss(target_subscription_key: str, prediction_subscription_key: str, tag: str = "",
                                  average_batch_loss: bool = True, flatten_predictions: bool = False) -> Loss:
+        """
+        Get BCEWithLogitsLoss Object (cross entropy loss that comes inside a sigmoid function) from params.
+
+        :params:
+           - target_subscription_key (str): Loss function.
+           - prediction_subscription_key (str): Predicttion performed on the model.
+           - tag (str): Label to be tagged with the loss object.
+           - average_batch_loss (bool): Average Loss value for the batch of data.
+           - flatten_predictions (bool): Flatten the layer to get predictions.
+           
+        :returns:
+            BCEWithLogitsLoss: Object of BCEWithLogitsLoss.
+        """
         return BCEWithLogitsLoss(target_subscription_key=target_subscription_key,
                                  prediction_subscription_key=prediction_subscription_key,
                                  average_batch_loss=average_batch_loss,
diff --git a/src/ml_gym/loss_functions/loss_functions.py b/src/ml_gym/loss_functions/loss_functions.py
index 600fe1f6..2aad13a9 100644
--- a/src/ml_gym/loss_functions/loss_functions.py
+++ b/src/ml_gym/loss_functions/loss_functions.py
@@ -40,6 +40,9 @@ def __call__(self, eval_batch: InferenceResultBatch) -> torch.Tensor:
 
 
 class LPLoss(Loss):
+    """
+    TO DO
+    """
     def __init__(self, target_subscription_key: str, prediction_subscription_key: str, root: int = 1, exponent: int = 2,
                  sample_selection_fun: Callable[[InferenceResultBatch], List[bool]] = None,
                  tag: str = "", average_batch_loss: bool = True, avg_per_feature_loss: bool = False):
@@ -96,6 +99,9 @@ def __call__(self, forward_batch: InferenceResultBatch) -> torch.Tensor:
 
 
 class CrossEntropyLoss(Loss):
+    """
+    Class to perform Cross Entropy Loss on parameters.
+    """
 
     def __init__(self, target_subscription_key: str, prediction_subscription_key: str, tag: str = "", average_batch_loss: bool = True):
         super().__init__(tag)
@@ -134,6 +140,9 @@ def __call__(self, inference_result_batch: InferenceResultBatch) -> torch.Tensor
 
 
 class BCEWithLogitsLoss(Loss):
+    """
+    Class to perform BCE With Logits Loss (cross entropy loss that comes inside a sigmoid function) from parameters.
+    """
     def __init__(self, target_subscription_key: str, prediction_subscription_key: str, tag: str = "", average_batch_loss: bool = True,
                  flatten_predictions: bool = False):
         super().__init__(tag)
diff --git a/src/ml_gym/persistency/io.py b/src/ml_gym/persistency/io.py
index e46fa962..9985caa9 100644
--- a/src/ml_gym/persistency/io.py
+++ b/src/ml_gym/persistency/io.py
@@ -1,10 +1,7 @@
 from abc import abstractmethod
-import base64
 from dataclasses import dataclass
 from enum import Enum
-import pickle
 from typing import Dict, List
-from ml_gym.persistency.logging import ExperimentStatusLogger
 import requests
 from http import HTTPStatus
 from ml_gym.error_handling.exception import NetworkError, DataIntegrityError
@@ -28,10 +25,10 @@ def add_config_string(self, grid_search_id: str, config_name: str, config: Dict,
     def get_validation_config(self, grid_search_id: str):
         raise NotImplementedError
 
-    def get_checkpoint_resource(self, grid_search_id: str, experiment_id: str, checkpoint_id: int, checkpoint_resource: CheckpointResource):
+    def get_checkpoint_resource(self, grid_search_id: str, experiment_id: str, checkpoint_id: int, checkpoint_resource: str):
         raise NotImplementedError
 
-    def add_checkpoint_resource(self, grid_search_id: str, experiment_id: str, payload: Dict):
+    def add_checkpoint_resource(self, grid_search_id: str, experiment_id: str, payload: Dict, custom_file_name: str):
         raise NotImplementedError
 
     def delete_checkpoints(self, grid_search_id: str, experiment_id: str, epoch: int):
@@ -46,7 +43,6 @@ def get_unfinished_experiments(self, grid_search_id: str):
     def get_experiment_statuses(self, grid_search_id: str) -> List[ExperimentStatus]:
         raise NotImplementedError
 
-
 class GridSearchRestfulAPIClient(GridSearchAPIClientIF):
     """
     GridSearchRestfulAPIClient class
@@ -92,18 +88,17 @@ def _get_binary_resource(url) -> bytes:
         else:
             return response.content
 
-    def _post_binary_resource(url: str, payload: bytes) -> Dict:
+    def _post_binary_resource(url: str, file_name: str, payload_stream: bytes) -> Dict:
         """
         ``HTTP POST Call`` Send bytes data.
 
         :params:
              url (str): HTTP request URL
+             file_name (str): Name of the file to be posted
              payload (bytes); pickle dump to be sent
         """
-        data = base64.b64encode(payload)
-        response = requests.post(
-            url=url, data={"data": data, "msg": "insert checkpoint", "type": "multipart/form-data"}, files={"file": data}
-        )
+        response = requests.post(url=url, files={"checkpoint_file": (file_name, payload_stream)})
+
         if response.status_code != HTTPStatus.OK:
             raise NetworkError(f"Server responded with error code {response.status_code}")
 
@@ -115,7 +110,9 @@ def _del_binary_resource(url: str) -> Dict:
              url (str): HTTP request URL
         """
         response = requests.delete(url=url)
-        if response.status_code != HTTPStatus.OK:
+        if response.status_code == HTTPStatus.NOT_FOUND:
+            print(f"Resource {url} not found")
+        elif response.status_code != HTTPStatus.OK:
             raise NetworkError(f"Server responded with error code {response.status_code}")
 
     def _put_raw_text_file_resource(url: str, payload: Dict) -> Dict:
@@ -147,9 +144,8 @@ def get_config(self, grid_search_id: str, config_name: str) -> str:
     #     url = f"{self.endpoint}/grid_searches/{grid_search_id}/gs_config"
     #     return GridSearchRestfulAPIClient._put_raw_text_file_resource(url, grid_search_config)
 
-    def add_config_string(
-        self, grid_search_id: str, config_name: str, config: str, file_format: FileFormat, experiment_id: int = None
-    ) -> Dict:
+    def add_config_string(self, grid_search_id: str, config_name: str, config: str, file_format: FileFormat,
+                          experiment_id: int = None) -> Dict:
         """
         ``HTTP PUT Call Request`` Add configuration
           given the grid search ID over HTTP call.
@@ -209,7 +205,7 @@ def get_full_checkpoint(self, grid_search_id: str, experiment_id: str, checkpoin
         url = f"{self.endpoint}/checkpoints/{grid_search_id}/{experiment_id}/{checkpoint_id}"
         return GridSearchRestfulAPIClient._get_json_resource(url)
 
-    def get_checkpoint_resource(self, grid_search_id: str, experiment_id: str, checkpoint_id: int, checkpoint_resource: CheckpointResource):
+    def get_checkpoint_resource(self, grid_search_id: str, experiment_id: str, checkpoint_id: int, checkpoint_resource: str):
         """
         ``HTTP GET Call Request`` Fetch checkpoint resource
           given the grid search ID, experiment ID & checkpoint ID over HTTP call.
@@ -218,14 +214,15 @@ def get_checkpoint_resource(self, grid_search_id: str, experiment_id: str, check
              grid_search_id (str): Grid Search ID
              experiment_id (str): Experiment ID
              checkpoint_id (int): Checkpoint ID
-             checkpoint_resource (CheckpointResource) : CheckpointResource type
+             checkpoint_resource (str): Filename of the checkpoint resource
 
         :returns: bytes pickel data
         """
         url = f"{self.endpoint}/checkpoints/{grid_search_id}/{experiment_id}/{checkpoint_id}/{checkpoint_resource}"
         return GridSearchRestfulAPIClient._get_binary_resource(url)
 
-    def add_checkpoint_resource(self, grid_search_id: str, experiment_id: str, payload: Dict):
+    def add_checkpoint_resource(self, grid_search_id: str, experiment_id: str, epoch: int,
+                                payload_stream: bytes, custom_file_name: str):
         """
         ``HTTP POST Call Request`` Send all checkpoint resource pickle files
           given the epoch, experiment ID & grid search ID over HTTP call.
@@ -233,20 +230,13 @@ def add_checkpoint_resource(self, grid_search_id: str, experiment_id: str, paylo
         :params:
              grid_search_id (str): Grid Search ID
              experiment_id (str): Experiment ID
-             payload (Dict): Dictionary containing CheckpointResource bytes array
+             epoch (int): Current epoch
+             payload_stream (bytes): Bytes stream containing CheckpointResource 
+             custom_file_name (str): File name of the checkpoint resource
         """
 
-        chekpoint_resources = [
-            CheckpointResource.model,
-            CheckpointResource.lr_scheduler,
-            CheckpointResource.optimizer,
-            CheckpointResource.stateful_components,
-        ]
-
-        for checkpoint in chekpoint_resources:
-            url = f"{self.endpoint}/checkpoints/{grid_search_id}/{experiment_id}/{payload['epoch']}/{checkpoint}"
-            payload_pick = pickle.dumps(payload[f"{checkpoint}"])
-            GridSearchRestfulAPIClient._post_binary_resource(url, payload_pick)
+        url = f"{self.endpoint}/checkpoints/{grid_search_id}/{experiment_id}/{epoch}"
+        GridSearchRestfulAPIClient._post_binary_resource(url, file_name=custom_file_name, payload_stream=payload_stream)
 
     def delete_checkpoints(self, grid_search_id: str, experiment_id: str, epoch: int):
         """
@@ -268,8 +258,6 @@ def get_experiment_statuses(self, grid_search_id: str) -> List[ExperimentStatus]
 
         :params:
              grid_search_id (str): Grid Search ID
-             experiment_id (str): Experiment ID
-             epoch (int): Epoch
 
         :returns: experiment status List
         """
diff --git a/src/ml_gym/persistency/logging.py b/src/ml_gym/persistency/logging.py
index 93dd30ff..a76c3da6 100644
--- a/src/ml_gym/persistency/logging.py
+++ b/src/ml_gym/persistency/logging.py
@@ -6,7 +6,7 @@
 from ml_gym.io.websocket_client import ClientFactory, BufferedClient
 import time
 import torch
-import pickle
+import io
 import math
 
 
@@ -111,6 +111,19 @@ def __init__(self, logger: MLgymStatusLoggerIF) -> None:
 
     def log_job_status(self, job_id: str, job_type: JobType, status: JobStatus, grid_search_id: str, experiment_id: str,
                        starting_time: int, finishing_time: int, error: str = "", stacktrace: str = ""):
+        """
+        Method to log job status to event storage.
+        :param:
+           - job_id (str): Job id.
+           - job_type (JobType): Job type object.
+           - status (JobStatus): Job status object.
+           - grid_search_id (str): Grid search id.
+           - experiment_id (str): Experiment id.
+           - starting_time (int): Job starting time.
+           - finishing_time (int): Job finishing time.
+           - error (str): Error message.
+           - stacktrace (str): Stacktrace.
+        """
         message = {"event_type": "job_status", "creation_ts": get_timestamp()}
         payload = {"job_id": job_id, "job_type": job_type.value, "status": status.value, "grid_search_id": grid_search_id,
                    "experiment_id": experiment_id, "starting_time": starting_time, "finishing_time": finishing_time, "error": error,
@@ -119,6 +132,14 @@ def log_job_status(self, job_id: str, job_type: JobType, status: JobStatus, grid
         self._logger.log_raw_message(raw_log_message=message)
 
     def log_experiment_config(self, grid_search_id: str, experiment_id: str, job_id: str, config: Dict[str, Any]):
+        """
+        Method to log Experiment Config to event storage.
+        :param:
+           - grid_search_id (str): Grid search id.
+           - experiment_id (str): Experiment id.
+           - job_id (str): Job id.
+           - config (Dict[str, Any]): Experiment config.
+        """
         message = {"event_type": "experiment_config", "creation_ts": get_timestamp()}
         payload = {"grid_search_id": grid_search_id, "experiment_id": experiment_id, "job_id": job_id, "config": config}
         message["payload"] = payload
@@ -137,6 +158,17 @@ def __init__(self, logger: MLgymStatusLoggerIF, experiment_id: str, grid_search_
 
     def log_experiment_status(self, status: str, num_epochs: int, current_epoch: int, splits: List[str], current_split: str,
                               num_batches: int, current_batch: int):
+        """
+        Method to log Experiment Status to event storage.
+        :param:
+           - status (str): Experiment Status.
+           - num_epochs (int): Number of epochs.
+           - current_epoch (int): Current epoch.
+           - splits (List[str]): List of splits.
+           - current_split (str): Current split.
+           - num_batches (int): Number of batches.
+           - current_batch (int): Current batch.
+        """
         message = {"event_type": "experiment_status", "creation_ts": get_timestamp()}
         payload = {"grid_search_id": self._grid_search_id, "experiment_id": self._experiment_id, "status": status, "num_epochs": num_epochs, "current_epoch": current_epoch,
                    "splits": splits, "current_split": current_split, "num_batches": num_batches, "current_batch": current_batch}
@@ -144,6 +176,12 @@ def log_experiment_status(self, status: str, num_epochs: int, current_epoch: int
         self._logger.log_raw_message(raw_log_message=message)
 
     def log_evaluation_results(self, eval_result: "EvaluationBatchResult", epoch: int):
+        """
+        Method to log Evaluation results to event storage.
+        :param:
+           - eval_result (EvaluationBatchResult): Evaluation results.
+           - epoch (int): Current epoch.
+        """
         message = {"event_type": "evaluation_result", "creation_ts": get_timestamp()}
         metric_scores = [{"metric": metric_key, "split": eval_result.split_name, "score": metric_score[0]}
                          for metric_key, metric_score in eval_result.metrics.items()]
@@ -154,7 +192,7 @@ def log_evaluation_results(self, eval_result: "EvaluationBatchResult", epoch: in
         payload["loss_scores"] = loss_scores
         message["payload"] = payload
         self._logger.log_raw_message(raw_log_message=message)
-
+        
     def disconnect(self):
         self._logger.disconnect()
 
diff --git a/src/ml_gym/util/devices.py b/src/ml_gym/util/devices.py
index feb089e6..7d22a434 100644
--- a/src/ml_gym/util/devices.py
+++ b/src/ml_gym/util/devices.py
@@ -6,7 +6,7 @@
 
 
 def get_devices(gpu_device_ids: List[int] = None) -> List[torch.device]:
-    if gpu_device_ids is None:
+    if gpu_device_ids is None or not gpu_device_ids:
         print("WARNING: No cuda devices specified. Falling back to CPUs.")   # TODO Introduce proper logging...
         return [torch.device("cpu")]
     if torch.cuda.is_available():  # if we got some GPUs
@@ -14,7 +14,3 @@ def get_devices(gpu_device_ids: List[int] = None) -> List[torch.device]:
     else:
         print("WARNING: No cuda devices available. Falling back to CPUs.")   # TODO Introduce proper logging...
         return [torch.device("cpu")]
-
-
-if __name__ == "__main__":
-    print(get_devices())
diff --git a/src/ml_gym/util/util.py b/src/ml_gym/util/util.py
index 9ae165f7..65f4c3eb 100644
--- a/src/ml_gym/util/util.py
+++ b/src/ml_gym/util/util.py
@@ -16,8 +16,47 @@
 from ml_gym.gym.post_processing import PredictPostProcessingIF
 import tqdm
 from ml_gym.gym.gym_jobs.standard_gym_job import AbstractGymJob
+from ml_gym.error_handling.exception import SystemInfoFetchError
 from data_stack.dataset.iterator import InformedDatasetIteratorIF
+import platform
+import torch
+import psutil
+import pkg_resources
+
 
+class SystemEnv:
+    @staticmethod
+    def create_system_info() -> Dict:
+        """
+        Fetch System Information for model card.
+
+        :returns: Dict- System Information of host machine (CPU & GPU)
+        """
+        try:
+            info = {}
+            info["platform"] = platform.system()
+            info["platform-release"] = platform.release()
+            info["architecture"] = platform.machine()
+            info["processor"] = platform.processor()
+            info["ram"] = str(round(psutil.virtual_memory().total / (1024.0**3))) + " GB"
+            info["python-version"] = platform.python_version()
+            info["python-packages"] = [{"name":p.project_name, "version": p.version} for p in pkg_resources.working_set]
+            if torch.cuda.is_available():
+                info["CUDNN_version"] = torch.backends.cudnn.version()
+                info["num_cuda_device"] = torch.cuda.device_count()
+                dev_list = []
+                for i in range(torch.cuda.device_count()):
+                    dev_list.append(
+                        {
+                            "name": torch.cuda.get_device_name(i),
+                            "multi_proc_count": torch.cuda.get_device_properties(i).multi_processor_count,
+                            "total_memory": f"{round(torch.cuda.get_device_properties(i).total_memory / 1e9, 2)} GB",
+                        }
+                    )
+                info["cuda_device_list"] = dev_list
+            return info
+        except Exception as e:
+            raise SystemInfoFetchError(f"Unable to fetch System Info") from e
 
 class ExportedModel:
     def __init__(self, model: NNModel, post_processors: List[PredictPostProcessingIF], model_path: str = None, device: torch.device = None):
diff --git a/src/setup.py b/src/setup.py
index 9bb7698a..99d4f5b2 100644
--- a/src/setup.py
+++ b/src/setup.py
@@ -35,7 +35,8 @@
         "flask-socketio",
         "datasets",
         "transformers",
-        "accelerate"
+        "accelerate",
+        "fs"
     ],
     python_requires=">=3.7",
     include_package_data=True,


Test patch:
diff --git a/example/cnn_zero_stage_3/ds_test.py b/example/cnn_zero_stage_3/ds_test.py
new file mode 100644
index 00000000..8d0e687b
--- /dev/null
+++ b/example/cnn_zero_stage_3/ds_test.py
@@ -0,0 +1,11 @@
+from accelerate import Accelerator
+from accelerate.state import AcceleratorState
+
+
+def main():
+    accelerator = Accelerator()
+    accelerator.print(f"{AcceleratorState()}")
+
+
+if __name__ == "__main__":
+    main()