示例#1
0
 def clear_config(self):
     """
     Author: SW
     Reset the config to an empty Namespace
     :return: None
     """
     self.config = Namespace()
示例#2
0
 def __init_config(self):
     """
     Author: SW
     Writes the config directory and files into the project directory using DEEP_CONFIG
     :return: None
     """
     config = Namespace(DEEP_CONFIG)
     config_dir = "%s/%s/config" % (self.main_path, self.project_name)
     os.makedirs(config_dir, exist_ok=True)
     for key, namespace in config.get().items():
         if isinstance(namespace, Namespace):
             namespace.save("%s/%s%s" % (config_dir, key, DEEP_EXT_YAML))
示例#3
0
    def __convert(self, value, d_type, default, sub_space=None):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake

        DESCRIPTION:
        ------------
        Converts a given value to a given data type, and returns the result.
        If the value can not be converted, the given default value is returned.
        NB: If d_type is given in a list, e.g. [str], it is assume that value should be a list and each item in value
        will be converted to the given data type. If any item in the list cannot be converted, None will be returned.

        PARAMETERS:
        -----------
        :param value: the value to be converted
        :param d_type: the data type to convert the value to
        :param default: the default value to return if the current value
        :param sub_space: the list of strings that defines the current sub-space

        RETURN:
        -------
        :return: new_value
        """
        sub_space = [] if sub_space is None else sub_space
        sub_space = DEEP_CONFIG_DIVIDER.join(sub_space)

        # If the value is not set
        if value is None and default is not None:
            # Notify user that default is being used
            if default == {}:
                new_value = Namespace()
            else:
                new_value = default
                if not default == []:
                    Notification(DEEP_NOTIF_WARNING, DEEP_MSG_CONFIG_NOT_SET % (sub_space, default))
        elif d_type is dict:
            new_value = Namespace(convert_dict(value.get_all()))
        else:
            new_value = convert(value, d_type)
            if new_value is None:
                # Notify user that default is being used
                Notification(
                    DEEP_NOTIF_WARNING, DEEP_MSG_CONFIG_NOT_CONVERTED % (
                        sub_space,
                        value,
                        self.__get_dtype_name(d_type),
                        default
                    )
                )
        return new_value
示例#4
0
 def __init__(self, transform_files=None):
     super(OutputTransformer, self).__init__()
     self.output_transformer = []
     if transform_files is not None:
         for file in transform_files:
             self.output_transformer.append(Namespace(file))
         self.load_transform_functions()
示例#5
0
    def __fill_transform_list(self, config_transforms: Namespace):
        """
        AUTHORS:
        --------

        author: Alix Leroy

        DESCRIPTION:
        ------------

        Fill the list of transforms with the corresponding methods and arguments

        PARAMETERS:
        -----------

        :param transforms-> list: A list of transforms

        RETURN:
        -------

        :return: None
        """
        list_transforms = []

        for key, value in config_transforms.get().items():
            list_transforms.append([
                key,
                get_module(value, modules=DEEP_MODULE_TRANSFORMS),
                check_kwargs(get_kwargs(value.get()))
            ])
        return list_transforms
示例#6
0
def convert(value, d_type=None):
    """
    Convert a value or list of values to data type in order of preference: (float, bool, str)
    :param value: value to convert
    :param d_type: data type to convert to
    :return: converted value
    """
    if value is None:
        return None
    elif d_type is None:
        if value is None:
            return None
        elif isinstance(value, list):
            return [convert(item) for item in value]
        else:
            new_value = convert2float(value)
            if new_value is not None:
                if round(new_value, 0) == new_value:
                    return int(new_value)
                else:
                    return new_value
            if isinstance(new_value,
                          str) and new_value.lower() in ["true", "false"]:
                new_value = convert2bool(value)
                if new_value is not None:
                    return new_value
            return str(value)
    elif d_type is str:
        return str(value)
    elif d_type is int:
        return convert2int(value)
    elif d_type is float:
        return convert2float(value)
    elif d_type is bool:
        return convert2bool(value)
    elif d_type is dict:
        try:
            return convert_namespace(value)
        except AttributeError:
            return None
    elif isinstance(d_type, dict):
        new_value = {}
        for key, item in d_type.items():
            try:
                new_value[key] = convert(value[key], d_type=item)
            except KeyError:
                new_value[key] = None
            except TypeError:
                return None
        return Namespace(new_value)
    elif isinstance(d_type, list):
        value = value if isinstance(value, list) else [value]
        new_value = []
        for item in value:
            new_item = convert(item, d_type[0])
            if new_item is None:
                return None
            else:
                new_value.append(new_item)
        return new_value
示例#7
0
    def __check_entry_completeness(entry: Namespace) -> Namespace:
        """
        AUTHORS:
        --------

        :author: Alix Leroy

        DESCRIPTION:
        ------------

        Check if the dictionary formatted entry is complete.
        If not complete, fill the dictionary with default value

        PARAMETERS:
        -----------

        :param entry (Namespace): The entry to check the completeness

        RETURN:
        -------

        :return entry (Namespace): The completed entry

        RAISE:
        ------

        :raise DeepError: Raised if the path is not given
        """

        # SOURCE
        if entry.check("source", None) is False:
            Notification(DEEP_NOTIF_FATAL,
                         "The source was not specified to the following entry : %s" % str(entry.get()))

        # JOIN PATH
        if entry.check("join", None) is False:
            entry.add({"join": None}, None)

        # LOADING METHOD
        if entry.check("load_method", None) is False:
            entry.add({"load_method": "online"})

        # DATA TYPE
        if entry.check("type", None) is False:
            entry.add({"type": None})

        return entry
示例#8
0
    def load_config(self):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake

        DESCRIPTION:
        ------------
        Loads each of the config files in the config directory into self.config
        self.check_config() is called penultimately
        self.store_config() is called finally

        RETURN:
        -------
        :return: None
        """
        try:
            Notification(DEEP_NOTIF_INFO, DEEP_MSG_CONFIG_LOADING_DIR % self.config_dir)
            # If the config directory exists
            if os.path.isdir(self.config_dir):
                self.config = Namespace()
                # For each expected configuration file
                for key, file_name in DEEP_CONFIG_FILES.items():
                    config_path = "%s/%s" % (self.config_dir, file_name)
                    if os.path.isfile(config_path):
                        # Notification(DEEP_NOTIF_INFO, DEEP_MSG_CONFIG_LOADING_FILE % config_path)
                        try:
                            self.config.add({key: Namespace(config_path)})
                        except yaml.scanner.ScannerError as e:
                            file, line, column = str(e).split(", ")
                            error, file = file.split("\n")
                            file = file[5:].replace('"', "")
                            Notification(
                                DEEP_NOTIF_FATAL, "Unable to load config file : %s" % error,
                                solutions="See %s : %s : %s" % (file, line, column)
                            )
                        self.check_config(key=key)
                    else:
                        self.config = Namespace()
                        Notification(DEEP_NOTIF_FATAL, DEEP_MSG_FILE_NOT_FOUND % config_path)
                Notification(DEEP_NOTIF_SUCCESS, DEEP_MSG_CONFIG_COMPLETE)
            else:
                Notification(DEEP_NOTIF_ERROR, DEEP_MSG_DIR_NOT_FOUND % self.config_dir)
            self.store_config()
        except DeepError:
            self.sleep()
示例#9
0
    def load_config(self):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake

        DESCRIPTION:
        ------------
        Loads each of the config files in the config directory into self.config
        self.check_config() is called penultimately
        self.store_config() is called finally

        RETURN:
        -------
        :return: None
        """
        Notification(DEEP_NOTIF_INFO,
                     DEEP_MSG_CONFIG_LOADING_DIR % self.config_dir)
        # If the config directory exists
        if os.path.isdir(self.config_dir):
            self.config = Namespace()
            # For each expected configuration file
            for key, file_name in DEEP_CONFIG_FILES.items():
                config_path = "%s/%s" % (self.config_dir, file_name)
                if os.path.isfile(config_path):
                    # Notification(DEEP_NOTIF_INFO, DEEP_MSG_CONFIG_LOADING_FILE % config_path)
                    self.config.add({key: Namespace(config_path)})
                    self.check_config(key=key)
                else:
                    self.config = Namespace()
                    Notification(DEEP_NOTIF_FATAL,
                                 DEEP_MSG_FILE_NOT_FOUND % config_path)
            Notification(DEEP_NOTIF_SUCCESS, DEEP_MSG_CONFIG_COMPLETE)
        else:
            Notification(DEEP_NOTIF_ERROR,
                         DEEP_MSG_DIR_NOT_FOUND % self.config_dir)
        self.store_config()
示例#10
0
 def load_config(self):
     """
     Author: SW
     Function: Checks current config path is valid, if not, user is prompted to give another
     :return: bool: True if a valid config path is set, otherwise, False
     """
     Notification(DEEP_NOTIF_INFO, DEEP_MSG_LOAD_CONFIG_START % self.config_dir)
     # If the config directory exists
     if os.path.isdir(self.config_dir):
         self.clear_config()
         # For each expected configuration file
         for key, file_name in DEEP_CONFIG_FILES.items():
             config_path = "%s/%s" % (self.config_dir, file_name)
             if os.path.isfile(config_path):
                 self.config.add({key: Namespace(config_path)})
                 Notification(DEEP_NOTIF_SUCCESS, DEEP_MSG_LOAD_CONFIG_FILE % config_path)
             else:
                 Notification(DEEP_NOTIF_ERROR, DEEP_MSG_FILE_NOT_FOUND % config_path)
         self.store_config()
     else:
         Notification(DEEP_NOTIF_ERROR, DEEP_MSG_DIR_NOT_FOUND % self.config_dir)
     #self.check_config()
     self.config.summary()
示例#11
0
    def __create_transformer(self, config_entry):
        """
        CONTRIBUTORS:
        -------------

        Creator : Alix Leroy

        DESCRIPTION:
        ------------

        Create the adequate transformer

        PARAMETERS:
        -----------

        :param config: The transformer config
        :param pointer-> bool : Whether or not the transformer points to another transformer

        RETURN:
        -------

        :return transformer: The created transformer
        """
        transformer = None

        # NONE
        if config_entry is None:
            transformer = NoTransformer()

        # POINTER
        elif self.__is_pointer(config_entry) is True:
            transformer = Pointer(
                config_entry)  # Generic Transformer as a pointer

        # TRANSFORMER
        else:
            config = Namespace(config_entry)

            # Check if a method is given by the user
            if config.check("method", None) is False:
                Notification(
                    DEEP_NOTIF_FATAL,
                    "The following transformer does not have any method specified : "
                    + str(config_entry))

            # Get the corresponding flag
            flag = get_corresponding_flag(flag_list=DEEP_LIST_TRANSFORMERS,
                                          info=config.method,
                                          fatal=False)

            #
            # Create the corresponding Transformer
            #
            try:
                # SEQUENTIAL
                if DEEP_TRANSFORMER_SEQUENTIAL.corresponds(flag):
                    transformer = Sequential(**config.get(ignore="method"))
                # ONE OF
                elif DEEP_TRANSFORMER_ONE_OF.corresponds(flag):
                    transformer = OneOf(**config.get(ignore="method"))
                # SOME OF
                elif DEEP_TRANSFORMER_SOME_OF.corresponds(flag):
                    transformer = SomeOf(**config.get(ignore="method"))
                # If the method does not exist
                else:
                    Notification(
                        DEEP_NOTIF_FATAL,
                        "Unknown transformer method specified in %s : %s" %
                        (config_entry, config.method),
                        solutions=[
                            "Ensure a valid transformer method is specified in %s"
                            % config_entry
                        ])
            except TypeError as e:
                Notification(
                    DEEP_NOTIF_FATAL,
                    "TypeError when loading transformer : %s : %s" %
                    (config_entry, e),
                    solutions=["Check the syntax of %s" % config_entry])
        return transformer
示例#12
0
 },
 "dataset": {
     "train": {
         "inputs": {
             DEEP_CONFIG_DTYPE: [{
                 "source": [str],
                 "join": [str],
                 "type": str,
                 "load_method": str
             }],
             DEEP_CONFIG_DEFAULT:
             None,
             DEEP_CONFIG_INIT: [
                 Namespace({
                     "source": DEF["SOURCE"],
                     "join": DEF["JOIN"],
                     "type": DEF["TYPE_IMG"],
                     "load_method": DEF["LOAD_METHOD"]
                 })
             ]
         },
         "labels": {
             DEEP_CONFIG_DTYPE: [{
                 "source": [str],
                 "join": [str],
                 "type": str,
                 "load_method": str
             }],
             DEEP_CONFIG_DEFAULT:
             None,
             DEEP_CONFIG_INIT: [
                 Namespace({
    def __create_transformer(self, config_entry):
        """
        CONTRIBUTORS:
        -------------

        Creator : Alix Leroy

        DESCRIPTION:
        ------------

        Create the adequate transformer

        PARAMETERS:
        -----------

        :param config: The transformer config
        :param pointer-> bool : Whether or not the transformer points to another transformer

        RETURN:
        -------

        :return transformer: The created transformer
        """
        transformer = None

        # NONE
        if config_entry is None:
            transformer = NoTransformer()

        # POINTER
        elif self.__is_pointer(config_entry) is True:
            transformer = Pointer(
                config_entry)  # Generic Transformer as a pointer

        # TRANSFORMER
        else:
            config = Namespace(config_entry)

            # Check if a method is given by the user
            if config.check("method", None) is False:
                Notification(
                    DEEP_NOTIF_FATAL,
                    "The following transformer does not have any method specified : "
                    + str(config_entry))

            # Get the corresponding flag
            flag = get_corresponding_flag(flag_list=DEEP_LIST_TRANSFORMERS,
                                          info=config.method,
                                          fatal=False)

            # Remove the method from the config
            delattr(config, 'method')

            #
            # Create the corresponding Transformer
            #

            # SEQUENTIAL
            if DEEP_TRANSFORMER_SEQUENTIAL.corresponds(flag):
                transformer = Sequential(**config.get())
            # ONE OF
            elif DEEP_TRANSFORMER_ONE_OF.corresponds(flag):
                transformer = OneOf(**config.get())
            # SOME OF
            elif DEEP_TRANSFORMER_SOME_OF.corresponds(flag):
                SomeOf(**config.get())
            # If the method does not exist
            else:
                Notification(
                    DEEP_NOTIF_FATAL,
                    "The following transformation method does not exist : " +
                    str(config.method))

        return transformer
示例#14
0
from deeplodocus.data.transform_manager import TransformManager
from deeplodocus.utils.namespace import Namespace
from deeplodocus.utils.flags import *

# Get the config for the transform managers
config_transforms = Namespace("./transforms")

# Create the transform managers
transform_manager_train = TransformManager(config_transforms.train)
#transform_manager_val = TransformManager(config_transforms.validation, write_logs=False)
#transform_manager_test = TransformManager(config_transforms.test, write_logs=False)

import time
from deeplodocus.data.dataset import Dataset
from deeplodocus.utils.types import *
from PIL import Image
import numpy as np
import cv2

inputs = []
labels = []
additional_data = []
inputs.append([r"input1.txt", r"input2.txt"])
inputs.append([r"./images", r"./images"])
labels.append([r"label1.txt", r"label2.txt"])
#labels.append(r"label3.txt")
#labels = []

additional_data.append(r"label3.txt")
#additional_data.append(r"additional_data.txt")
additional_data = []
示例#15
0
    def forward(self, x):
        im_shape = torch.tensor(x.shape[2:4], dtype=torch.float32)

        # Check input dims
        if x.ndim != 4:
            Notification(DEEP_NOTIF_FATAL, MSG_WRONG_DIMS % x.ndim)
        # Check input height and width are divisible by 32
        if not (x.shape[2] % 32 == 0 and x.shape[3] % 32 == 0):
            Notification(DEEP_NOTIF_FATAL, MSG_WRONG_SHAPE % str(x.shape))

        # BACKBONE - initial feature detection
        x = self.backbone(x)  # b x 1024 x h/32 x w/32

        # DETECTION ON LARGEST SCALE
        x = self.conv_1_1(x)  # b x 512  x h/32 x w/32
        x = self.conv_1_2(x)  # b x 512  x h/32 x w/32
        output_1 = self.conv_1_3(x)  # b x 1024 x h/32 x w/32
        output_1 = self.conv_1_4(
            output_1)  # b x 3 * (num cls + 5) x h/32 x w/32
        output_1 = self.unpack(output_1,
                               s=2)  # Unpack predictions across anchors

        # DETECTION ON MID SCALE
        x = self.conv_2_1(x)  # b x 256 x h/32 x w/32
        x = self.upsample(x)  # b x 256 x h/16 x w/16
        skip = self.backbone.skip[
            self.skip_layers[1]]  # Get skip layer from backbone
        x = torch.cat((x, skip),
                      1)  # Concatenate x with second backbone skip layer
        x = self.conv_2_2(x)  # b x 256 x h/16 x w/16
        x = self.conv_2_3(x)  # b x 256 x h/16 x w/16
        output_2 = self.conv_2_4(x)  # b x 512  x h/16 x w/16
        output_2 = self.conv_2_5(
            output_2)  # b x 3 * (num cls + 5) x h/16 x w/16
        output_2 = self.unpack(output_2,
                               s=1)  # Unpack predictions across anchors

        # DETECTION ON SMALLEST SCALE
        x = self.conv_3_1(x)  # b x 128 x h/16 x w/16
        x = self.upsample(x)  # b x 128 x h/8  x w/8
        skip = self.backbone.skip[self.skip_layers[0]]
        x = torch.cat((x, skip),
                      1)  # Concatenate x with first backbone skip layer
        x = self.conv_3_2(x)  # b x 128 x h/8  x w/8
        x = self.conv_3_3(x)  # b x 128 x h/8  x w/8
        output_3 = self.conv_3_4(x)  # b x 128 x h/8  x w/8
        output_3 = self.conv_3_5(output_3)  # b x 3 * (num cls + 5) x h/8 x w/8
        output_3 = self.unpack(output_3,
                               s=0)  # Unpack predictions across anchors
        return Namespace({
            "inference": [output_3, output_2,
                          output_1],  # Scale: [small, medium scale, large]
            "anchors":
            torch.tensor(self.anchors, dtype=torch.float32,
                         device=self.device),
            "strides":
            torch.tensor((
                im_shape[0] / output_3.shape[2],
                im_shape[0] / output_2.shape[2],
                im_shape[0] / output_1.shape[2],
            ),
                         dtype=torch.float32,
                         device=self.device)
        })
示例#16
0
class Brain(FrontalLobe):
    """
    AUTHORS:
    --------

    :author: Alix Leroy
    :author: Samuel Westlake

    DESCRIPTION:
    ------------

    A Brain class that manages the commands of the user and allows to start the training
    PUBLIC METHODS:
    ---------------
    :method wake:
    :method sleep:
    :method save_config: Save all configuration files into self.config_dir.
    :method clear_config: Reset self.config to an empty Namespace.
    :method store_config: Store a copy of self.config in self._config.
    :method restore_config: Set self.config to a copy of self._config.
    :method load_config: Load self.config from self.config_dir.
    :method check_config: Check self.config for missing parameters and set data types accordingly.
    :method clear_logs: Deletes logs that are not to be kept, as decided in the config settings.
    :method close_logs: Closes logs that are to be kept and deletes logs that are to be deleted, see config settings.
    :method ui:

    PRIVATE METHODS:
    ----------------
    :method __init__:
    :method __check_config:
    :method __convert_dtype:
    :method __convert:
    :method __on_wake:
    :method __execute_command:
    :method __preprocess_command:
    :method __illegal_command_messages:
    :method __get_command_flags:
    """

    def __init__(self, config_dir):
        """
        AUTHORS:
        --------

        :author: Alix Leroy

        DESCRIPTION:
        ------------

        Initialize a Deeplodocus Brain

        PARAMETERS:
        -----------

        :param config_path->str: The config path

        RETURN:
        -------

        :return: None
        """
        FrontalLobe.__init__(self)  # Model Manager
        self.close_logs(force=True)
        self.config_dir = config_dir
        self.config_is_complete = False
        Logo(version=__version__)
        self.visual_cortex = None
        time.sleep(0.5)                     # Wait for the UI to respond
        self.frontal_lobe = None
        self.config = None
        self._config = None
        self.load_config()
        Thalamus()                  # Initialize the Thalamus

    def wake(self):
        """
        Authors : Alix Leroy, SW
        Deeplodocus terminal commands
        :return: None
        """
        self.__on_wake()

        while True:
            command = Notification(DEEP_NOTIF_INPUT, DEEP_MSG_INSTRUCTRION).get()
            try:
                self.__execute_command(command)
            except DeepError:
                time.sleep(0.5)

    def sleep(self):
        """
        Author: SW, Alix Leroy
        Stop the interface, close logs and print good-bye message
        :return: None
        """
        # Stop the visual cortex
        if self.visual_cortex is not None:
            self.visual_cortex.stop()

        self.close_logs()
        End(error=False)

    def save_config(self):
        """
        Author: SW
        Save the config to the config folder
        :return: None
        """
        for key, namespace in self.config.get().items():
            if isinstance(namespace, Namespace):
                namespace.save("%s/%s%s" % (self.config_dir, key, DEEP_EXT_YAML))

    def clear_config(self):
        """
        Author: SW
        Reset the config to an empty Namespace
        :return: None
        """
        self.config = Namespace()

    def restore_config(self):
        """
        Author: SW
        Restore the config to the last stored version
        :return:
        """
        self.config = self._config.copy()

    def store_config(self):
        """
        Author: SW
        Saves a deep copy of the config as _config. In case the user wants to revert to previous settings
        :return: None
        """
        self._config = self.config.copy()

    def load_config(self):
        """
        Author: SW
        Function: Checks current config path is valid, if not, user is prompted to give another
        :return: bool: True if a valid config path is set, otherwise, False
        """
        Notification(DEEP_NOTIF_INFO, DEEP_MSG_LOAD_CONFIG_START % self.config_dir)
        # If the config directory exists
        if os.path.isdir(self.config_dir):
            self.clear_config()
            # For each expected configuration file
            for key, file_name in DEEP_CONFIG_FILES.items():
                config_path = "%s/%s" % (self.config_dir, file_name)
                if os.path.isfile(config_path):
                    self.config.add({key: Namespace(config_path)})
                    Notification(DEEP_NOTIF_SUCCESS, DEEP_MSG_LOAD_CONFIG_FILE % config_path)
                else:
                    Notification(DEEP_NOTIF_ERROR, DEEP_MSG_FILE_NOT_FOUND % config_path)
            self.store_config()
        else:
            Notification(DEEP_NOTIF_ERROR, DEEP_MSG_DIR_NOT_FOUND % self.config_dir)
        #self.check_config()
        self.config.summary()

    def check_config(self):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake

        DESCRIPTION SHORT:
        ------------
        Checks self.config by auto-completing missing parameters with default values and converting values to the
        required data type.
        Once check_config has been run, it can be assumed that self.config is complete.
        See self.__check_config for more details.

        RETURN:
        -------
        :return: None
        """
        self.__check_config()
        Notification(DEEP_NOTIF_SUCCESS, DEEP_MSG_CONFIG_COMPLETE)

    def clear_logs(self, force=False):
        """
        Author: SW
        Deletes logs that are not to be kept, as decided in the config settings
        :param force: bool Use if you want to force delete all logs
        :return: None
        """
        for log_type, (directory, ext) in DEEP_LOGS.items():
            # If forced or log should not be kept, delete the log
            if force or not self.config.project.logs.get(log_type):
                Logs(log_type, directory, ext).delete()

    def close_logs(self, force=False):
        """
        Author: SW
        Closes logs that are to be kept and deletes logs that are to be deleted, as decided in the config settings
        :param force: bool: Use if you want to force all logs to close (use if you don't want logs to be deleted)
        :return: None
        """
        for log_type, (directory, ext) in DEEP_LOGS.items():
            # If forced to closer or log should be kept, close the log
            # NB: config does not have to exist if force is True
            if force or self.config.project.logs.get(log_type):
                if os.path.isfile("%s/%s%s" % (directory, log_type, ext)):
                    Logs(log_type, directory, ext).close()
            else:
                Logs(log_type, directory, ext).delete()

    def ui(self):
        """
        AUTHORS:
        --------AttributeError: module 'asyncio' has no attribute 'create_task'


        :author: Alix Leroy

        DESCRIPTION:
        ------------

        Start the User Interface

        PARAMETERS:AttributeError: module 'asyncio' has no attribute 'create_tasAttributeError: module 'asyncio' has no attribute 'create_task'
k'

        -----------

        None

        RETURN:
        -------

        :return: None
        """

        if self.visual_cortex is None:
            self.visual_cortex = VisualCortex()
        else:
            Notification(DEEP_NOTIF_ERROR, "The Visual Cortex is already running.")

    def stop_ui(self):
        """
        AUTHORS:
        --------

        :author: Alix Leroy

        DESCRIPTION:
        ------------

        Stop the User Interface

        PARAMETERS:
        -----------

        None

        RETURN:
        -------

        :return: None
        """

        if self.visual_cortex is not None:
            self.visual_cortex.stop()
            self.visual_cortex = None
        else:
            Notification(DEEP_NOTIF_ERROR, "The Visual Cortex is already asleep.")

    def __check_config(self, dictionary=DEEP_CONFIG, sub_space=None):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake

        DESCRIPTION:
        ------------
        If a parameter is missing, the user is notified by a DEEP_NOTIF_WARNING with DEEP_MSG_CONFIG_NOT_FOUND.
        The missing parameter is added with the default value specified by DEEP_CONFIG and user is notified of the
        addition of the parameter by a DEEP_NOTIF_WARNING with DEE_MSG_CONFIG_ADDED.
        If a parameter is found successfully, it is converted to the data type specified by 'dtype' in DEEP_CONFIG.
        If a parameter cannot be converted to the required data type, it is replaced with the default from DEEP_CONFIG.

        PARAMETERS:
        -----------
        NB: Both parameters are only for use when check_config calls itself.
        :param dictionary: dictionary to compare self.config with.
        :param sub_space: list of strings defining the path to the current sub-space.

        RETURN:
        -------
        :return: None
        """
        sub_space = [] if sub_space is None else sub_space
        sub_space = sub_space if isinstance(sub_space, list) else [sub_space]
        for key, value in dictionary.items():
            if isinstance(value, dict):
                if "dtype" in value and "default" in value:
                    default = value["default"]
                    if self.config.check(key, sub_space=sub_space):
                        d_type = value["dtype"]
                        current = self.config.get(sub_space)[key]
                        self.config.get(sub_space)[key] = self.__convert_dtype(current,
                                                                               d_type,
                                                                               default,
                                                                               sub_space=sub_space + [key])
                    else:
                        item_path = DEEP_CONFIG_DIVIDER.join(sub_space + [key])
                        Notification(DEEP_NOTIF_WARNING, DEEP_MSG_CONFIG_ADDED % (item_path, default))
                        self.config.get(sub_space)[key] = default
                else:
                    self.__check_config(value, sub_space=sub_space + [key])

    def __convert_dtype(self, value, d_type, default, sub_space=None):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake

        DESCRIPTION:
        ------------
        Converts a given value to a given data type, and returns the result.
        If the value can not be converted, the given default value is returned.
        NB: If d_type is given in a list, e.g. [str], it is assume that value should be a list and each item in value
        will be converted to the given data type. If any item in the list cannot be converted, None will be returned.

        PARAMETERS:
        -----------
        :param value: the value to be converted
        :param d_type: the data type to convert the value to
        :param default: the default value to return if the current value
        :param sub_space: the list of strings that defines the current sub-space

        RETURN:
        -------
        :return: new_value
        """
        sub_space = [] if sub_space is None else sub_space
        if value is None:
            return None
        else:
            try:
                len(d_type)
                d_type = d_type[0]
                is_list = True
            except TypeError:
                is_list = False
            if is_list:
                new_values = []
                value = value if isinstance(value, list) else [value]
                for item in value:
                    new_item = self.__convert(item, d_type)
                    if new_item is not None:
                        new_values.append(new_item)
                    else:
                        Notification(DEEP_NOTIF_WARNING,
                                     DEEP_MSG_NOT_CONVERTED
                                     % (DEEP_CONFIG_DIVIDER.join(sub_space), new_values, d_type, default))
                        return default
                return new_values
            else:
                if d_type == dict:
                    if isinstance(value, Namespace) or value is None:
                        return value
                    else:
                        Notification(DEEP_NOTIF_WARNING, DEEP_MSG_NOT_CONVERTED % (sub_space, value, d_type, default))
                        return Namespace(default)
                else:
                    new_value = self.__convert(value, d_type)
                    if new_value is None:
                        Notification(DEEP_NOTIF_WARNING, DEEP_MSG_NOT_CONVERTED % (sub_space, value, d_type, default))
                        return default
                    else:
                        return new_value

    @staticmethod
    def __convert(value, d_type):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake

        DESCRIPTION:
        ------------
        Converts a given value to a given data type, and returns the result.
        If the value can not be converted, None is returned.

        PARAMETERS:
        -----------
        :param value: the value to be converted.
        :param d_type: the data type to convert the value to.

        RETURN:
        -------
        :return: new_value
        """
        if isinstance(dtype, int) or isinstance(dtype, float):
            try:
                return d_type(eval(value))
            except NameError:
                try:
                    return d_type(value)
                except TypeError:
                    return None
        else:
            try:
                return d_type(value)
            except TypeError:
                return None

    def __on_wake(self):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake

        DESCRIPTION:
        ------------
        Executes the list of commands in self.config.project.on_wake

        RETURN:
        -------
        :return: None
        """
        if self.config.project.on_wake is not None:
            if not isinstance(self.config.project.on_wake, list):
                self.config.project.on_wake = [self.config.project.on_wake]
            for command in self.config.project.on_wake:
                self.__execute_command(command)

    def __execute_command(self, command):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake

        DESCRIPTION:
        ------------
        Calls exec for the given command

        PARAMETERS:
        -----------
        :param command: str: the command to execute

        RETURN:
        -------
        :return: None
        """
        commands, flags = self.__preprocess_command(command)
        for command, flag in zip(commands, flags):
            if command in DEEP_EXIT_FLAGS:
                self.sleep()
            else:
                try:
                    if flag is None:
                        exec("self.%s" % command)
                    elif flag == DEEP_CMD_PRINT:
                        exec("Notification(DEEP_NOTIF_RESULT, self.%s)" % command)
                except DeepError:
                    time.sleep(0.1)

    def __preprocess_command(self, command):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake

        DESCRIPTION:
        ------------
        Pre-processes a given command for execuution.

        PARAMETERS:
        -----------
        :param command: str: the command to process.

        RETURN:
        -------
        :return: str: the command, str: any flags associated with the command.
        """
        commands = command.split(" & ")
        for command in commands:
            remove = False
            for prefix in DEEP_FILTER_STARTS_WITH:
                if command.startswith(prefix):
                    remove = True
                    break
            if not remove:
                for suffix in DEEP_FILTER_ENDS_WITH:
                    if command.endswith(suffix):
                        remove = True
            if not remove:
                for item in DEEP_FILTER:
                    if command == item:
                        remove = True
            if not remove:
                for item in DEEP_FILTER_STARTS_ENDS_WITH:
                    if command.startswith(item) and command.endswith(item):
                        remove = True
            if not remove:
                for item in DEEP_FILTER_INCLUDES:
                    if item in command:
                        remove = True
            if remove:
                commands.remove(command)
                self.__illegal_command_messages(command)
        return self.__get_command_flags(commands)

    @staticmethod
    def __illegal_command_messages(command):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake

        DESCRIPTION:
        ------------
        Explains why a given command is illegal.

        PARAMETERS:
        -----------
        :param command: str: the illegal command.

        RETURN:
        -------
        :return: None
        """
        message = (DEEP_MSG_ILLEGAL_COMMAND % command)
        if "__" in command or "._" in command or command.startswith("_"):
            message = "%s %s" % (message, DEEP_MSG_PRIVATE)
        if command == "wake()":
            message = "%s %s" % (message, DEEP_MSG_ALREADY_AWAKE)
        if command == "config.save":
            message = "%s %s" % (message, DEEP_MSG_USE_CONFIG_SAVE)
        Notification(DEEP_NOTIF_WARNING, message)

    @staticmethod
    def __get_command_flags(commands):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake

        DESCRIPTION:
        ------------
        Extracts any flags from each command in a list of commands.

        PARAMETERS:
        -----------
        :param commands: list of str: the commands to extract flags from.

        RETURN:
        -------
        :return: None
        """
        flags = [None for _ in range(len(commands))]
        for i, command in enumerate(commands):
            for flag in DEEP_CMD_FLAGS:
                if flag in command:
                    flags[i] = flag
                    commands[i] = command.replace(" %s" % flag, "")
                else:
                    flags[i] = None
        return commands, flags

    #
    # ALIASES
    #

    visual_cortex = ui
    vc = ui
    user_interface = ui
示例#17
0
    def __convert_dtype(self, value, d_type, default, sub_space=None):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake

        DESCRIPTION:
        ------------
        Converts a given value to a given data type, and returns the result.
        If the value can not be converted, the given default value is returned.
        NB: If d_type is given in a list, e.g. [str], it is assume that value should be a list and each item in value
        will be converted to the given data type. If any item in the list cannot be converted, None will be returned.

        PARAMETERS:
        -----------
        :param value: the value to be converted
        :param d_type: the data type to convert the value to
        :param default: the default value to return if the current value
        :param sub_space: the list of strings that defines the current sub-space

        RETURN:
        -------
        :return: new_value
        """
        sub_space = [] if sub_space is None else sub_space
        if value is None:
            return None
        else:
            try:
                len(d_type)
                d_type = d_type[0]
                is_list = True
            except TypeError:
                is_list = False
            if is_list:
                new_values = []
                value = value if isinstance(value, list) else [value]
                for item in value:
                    new_item = self.__convert(item, d_type)
                    if new_item is not None:
                        new_values.append(new_item)
                    else:
                        Notification(DEEP_NOTIF_WARNING,
                                     DEEP_MSG_NOT_CONVERTED
                                     % (DEEP_CONFIG_DIVIDER.join(sub_space), new_values, d_type, default))
                        return default
                return new_values
            else:
                if d_type == dict:
                    if isinstance(value, Namespace) or value is None:
                        return value
                    else:
                        Notification(DEEP_NOTIF_WARNING, DEEP_MSG_NOT_CONVERTED % (sub_space, value, d_type, default))
                        return Namespace(default)
                else:
                    new_value = self.__convert(value, d_type)
                    if new_value is None:
                        Notification(DEEP_NOTIF_WARNING, DEEP_MSG_NOT_CONVERTED % (sub_space, value, d_type, default))
                        return default
                    else:
                        return new_value
示例#18
0
 "inputs": {
     DEEP_CONFIG_DTYPE: [{
         "source": [str],
         "join": [str],
         "type": str,
         "load_method": str,
         "load_as": str,
         "move_axes": [int]
     }],
     DEEP_CONFIG_DEFAULT:
     None,
     DEEP_CONFIG_INIT: [
         Namespace({
             "source": DEF["SOURCE"],
             "join": DEF["JOIN"],
             "type": DEF["TYPE_IMG"],
             "load_method": DEF["LOAD_METHOD"],
             "load_as": DEF["LOAD_AS"],
             "move_axes": DEF["MOVE_AXES"]
         })
     ]
 },
 "labels": {
     DEEP_CONFIG_DTYPE: [{
         "source": [str],
         "join": [str],
         "type": str,
         "load_method": str,
         "load_as": str,
         "move_axes": [int]
     }],
     DEEP_CONFIG_DEFAULT:
示例#19
0
class Brain(FrontalLobe):
    """
    AUTHORS:
    --------

    :author: Alix Leroy
    :author: Samuel Westlake

    DESCRIPTION:
    ------------

    A Brain class that manages the commands of the user and allows to start the training

    PUBLIC METHODS:
    ---------------
    :method wake:
    :method sleep:
    :method save_config: Save all configuration files into self.config_dir.
    :method clear_config: Reset self.config to an empty Namespace.
    :method store_config: Store a copy of self.config in self._config.
    :method restore_config: Set self.config to a copy of self._config.
    :method load_config: Load self.config from self.config_dir.
    :method check_config: Check self.config for missing parameters and set data types accordingly.
    :method clear_logs: Deletes logs that are not to be kept, as decided in the config settings.
    :method close_logs: Closes logs that are to be kept and deletes logs that are to be deleted, see config settings.
    :method ui: Start the Visual Cortex of Deeplodocus

    PRIVATE METHODS:
    ----------------
    :method __init__:
    :method __check_config:
    :method __convert_dtype:
    :method __convert:
    :method __on_wake:
    :method __execute_command:
    :method __preprocess_command:
    :method __illegal_command_messages:
    :method __get_command_flags:
    :method __good_bye:
    """
    def __init__(self, config_dir):
        """
        AUTHORS:
        --------

        :author: Alix Leroy

        DESCRIPTION:
        ------------

        Initialize a Deeplodocus Brain

        PARAMETERS:
        -----------

        :param config_path->str: The config path

        RETURN:
        -------

        :return: None
        """
        self.__close_logs(force=True)
        Logo(version=__version__)
        FrontalLobe.__init__(self)  # Model Manager
        self.config_dir = config_dir
        self.visual_cortex = None
        time.sleep(0.5)  # Wait for the UI to respond
        self.config = None
        self._config = None
        self.load_config()
        self.set_device()
        Thalamus()  # Initialize the Signal Manager

    """
    "
    " Public Methods
    "
    """

    def wake(self):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake
        :author: Alix Leroy

        DESCRIPTION:
        ------------
        Deeplodocus terminal commands

        RETURN:
        -------
        :return: None
        """
        self.__on_wake()
        while True:
            try:
                command = Notification(DEEP_NOTIF_INPUT,
                                       DEEP_MSG_INSTRUCTRION).get()
            except KeyboardInterrupt:
                self.sleep()
            self.__execute_command(command)

    def sleep(self):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake
        :author: Alix Leroy

        DESCRIPTION:
        ------------
        Stop the interface, close logs and print good-bye message

        RETURN:
        -------
        :return: None
        """
        # Stop the visual cortex
        if self.visual_cortex is not None:
            self.visual_cortex.stop()
        self.__good_bye()
        self.__close_logs()
        raise SystemExit(0)

    def save_config(self):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake

        DESCRIPTION:
        ------------
        Save self.config to the config directory

        RETURN:
        -------
        :return: None
        """
        for key, namespace in self.config.get().items():
            if isinstance(namespace, Namespace):
                namespace.save("%s/%s%s" %
                               (self.config_dir, key, DEEP_EXT_YAML))

    def clear(self, force=False):
        """
        :return:
        """
        if force:
            do_clear = True
        else:
            # Ask user if they really want to clear
            while True:
                do_clear = Notification(
                    DEEP_NOTIF_INPUT,
                    "Are you sure you want to clear this session : %s ? (yes / no)"
                    % self.config.project.session).get()
                if do_clear.lower() in ["yes", "y"]:
                    do_clear = True
                    break
                elif do_clear.lower() in ["no", "n"]:
                    do_clear = False
                    break
        if do_clear:
            Notification(
                DEEP_NOTIF_INFO,
                DEEP_MSG_BRAIN_CLEAR_ALL % self.config.project.session)
            for directory in DEEP_LOG_RESULT_DIRECTORIES:
                path = "/".join((self.config.project.session, directory))
                try:
                    for file in os.listdir(path):
                        os.remove("/".join((path, file)))
                except FileNotFoundError:
                    pass
            Notification(
                DEEP_NOTIF_SUCCESS,
                DEEP_MSG_BRAIN_CLEARED_ALL % self.config.project.session)

    def clear_history(self, force=False):
        if force:
            do_clear = True
        else:
            # Ask user if they really want to clear
            while True:
                do_clear = Notification(
                    DEEP_NOTIF_INPUT,
                    "Are you sure you want to clear history from session : %s ? (yes / no)"
                    % self.config.project.session).get()
                if do_clear.lower() in ["yes", "y"]:
                    do_clear = True
                    break
                elif do_clear.lower() in ["no", "n"]:
                    do_clear = False
                    break

        if do_clear:
            Notification(
                DEEP_NOTIF_INFO,
                DEEP_MSG_BRAIN_CLEAR_HISTORY % self.config.project.session)
            path = "/".join((self.config.project.session, "history"))
            try:
                for file in os.listdir(path):
                    os.remove("/".join((path, file)))
            except FileNotFoundError:
                pass
            Notification(
                DEEP_NOTIF_SUCCESS,
                DEEP_MSG_BRAIN_CLEARED_HISTORY % self.config.project.session)
            self.load_memory()

    def clear_logs(self, force=False):
        if force:
            do_clear = True
        else:
            # Ask user if they really want to clear
            while True:
                do_clear = Notification(
                    DEEP_NOTIF_INPUT,
                    "Are you sure you want to clear logs from session : %s ? (yes / no)"
                    % self.config.project.session).get()
                if do_clear.lower() in ["yes", "y"]:
                    do_clear = True
                    break
                elif do_clear.lower() in ["no", "n"]:
                    do_clear = False
                    break

        if do_clear:
            Notification(
                DEEP_NOTIF_INFO,
                DEEP_MSG_BRAIN_CLEAR_LOGS % self.config.project.session)
            path = "/".join((self.config.project.session, "logs"))
            try:
                for file in os.listdir(path):
                    os.remove("/".join((path, file)))
            except FileNotFoundError:
                pass
            Notification(
                DEEP_NOTIF_SUCCESS,
                DEEP_MSG_BRAIN_CLEARED_LOGS % self.config.project.session)

    def restore_config(self):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake

        DESCRIPTION:
        ------------
        Restore the config to the last stored version

        RETURN:
        -------
        :return: None
        """
        self.config = self._config.copy()

    def store_config(self):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake

        DESCRIPTION:
        ------------
        Saves a deep copy of the config as _config. In case the user wants to revert to previous settings

        RETURN:
        -------
        :return: None
        """
        self._config = self.config.copy()

    def load_config(self):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake

        DESCRIPTION:
        ------------
        Loads each of the config files in the config directory into self.config
        self.check_config() is called penultimately
        self.store_config() is called finally

        RETURN:
        -------
        :return: None
        """
        Notification(DEEP_NOTIF_INFO,
                     DEEP_MSG_CONFIG_LOADING_DIR % self.config_dir)
        # If the config directory exists
        if os.path.isdir(self.config_dir):
            self.config = Namespace()
            # For each expected configuration file
            for key, file_name in DEEP_CONFIG_FILES.items():
                config_path = "%s/%s" % (self.config_dir, file_name)
                if os.path.isfile(config_path):
                    # Notification(DEEP_NOTIF_INFO, DEEP_MSG_CONFIG_LOADING_FILE % config_path)
                    self.config.add({key: Namespace(config_path)})
                    self.check_config(key=key)
                else:
                    self.config = Namespace()
                    Notification(DEEP_NOTIF_FATAL,
                                 DEEP_MSG_FILE_NOT_FOUND % config_path)
            Notification(DEEP_NOTIF_SUCCESS, DEEP_MSG_CONFIG_COMPLETE)
        else:
            Notification(DEEP_NOTIF_ERROR,
                         DEEP_MSG_DIR_NOT_FOUND % self.config_dir)
        self.store_config()

    def check_config(self, key=None):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake

        DESCRIPTION:
        ------------
        Checks self.config by auto-completing missing parameters with default values and converting values to the
        required data type.
        Once check_config has been run, it can be assumed that self.config is complete.
        See self.__check_config for more details.

        RETURN:
        -------
        :return: None
        """
        if key is None:
            self.__check_config()
            Notification(DEEP_NOTIF_SUCCESS, DEEP_MSG_CONFIG_COMPLETE)
        else:
            self.__check_config(DEEP_CONFIG[key], sub_space=key)

    def __clear_logs(self, force=False):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake

        DESCRIPTION:
        ------------
        Deletes logs that are not to be kept, as decided in the config settings

        PARAMETERS:
        -----------
        :param force: bool Use if you want to force delete all logs

        RETURN:
        -------
        :return: None
        """
        for log_type, (directory, ext) in DEEP_LOGS.items():
            # If forced or log should not be kept, delete the log
            if force or not self.config.project.logs.get(log_type):
                Logs(log_type, directory, ext).delete()

    def __close_logs(self, force=False):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake

        DESCRIPTION:
        ------------
        Closes logs that are to be kept and deletes logs that are to be deleted, as decided in the config settings

        PARAMETERS:
        -----------
        :param force: bool: Use if you want to force all logs to close (use if you don't want logs to be deleted)

        RETURN:
        -------
        :return: None
        """
        for log_type, (directory, ext) in DEEP_LOGS.items():
            # If forced to closer or log should be kept, close the log
            # NB: config does not have to exist if force is True
            if log_type == DEEP_LOG_NOTIFICATION:
                try:
                    new_directory = "/".join(
                        (get_main_path(), self.config.project.session, "logs"))
                except AttributeError:
                    new_directory = None
            else:
                new_directory = None
            if force or self.config.project.logs.get(log_type):
                if os.path.isfile("%s/%s%s" % (directory, log_type, ext)):
                    Logs(log_type, directory, ext).close(new_directory)
            else:
                Logs(log_type, directory, ext).delete()

    def ui(self):
        """
        AUTHORS:
        --------

        :author: Alix Leroy

        DESCRIPTION:
        ------------

        Start the User Interface

        PARAMETERS:
        -----------

        None

        RETURN:
        -------

        :return: None
        """

        if self.visual_cortex is None:
            self.visual_cortex = VisualCortex()
        else:
            Notification(DEEP_NOTIF_ERROR,
                         "The Visual Cortex is already running.")

    def stop_ui(self):
        """
        AUTHORS:
        --------

        :author: Alix Leroy

        DESCRIPTION:
        ------------

        Stop the User Interface

        PARAMETERS:
        -----------

        None

        RETURN:
        -------

        :return: None
        """

        if self.visual_cortex is not None:
            self.visual_cortex.stop()
            self.visual_cortex = None
        else:
            Notification(DEEP_NOTIF_ERROR,
                         "The Visual Cortex is already asleep.")

    def plot_history(self, *args, **kwargs):
        """
        :param args:
        :param kwargs:
        :return:
        """
        plot_history("/".join((self.config.project.session, "history")), *args,
                     **kwargs)

    def plot_graph(self, format="svg"):
        Graph(self.model, self.model.named_parameters())

    """
    "
    " Private Methods
    "
    """

    def __check_config(self, dictionary=DEEP_CONFIG, sub_space=None):
        """
        AUTHORS:
        --------

        :author: Samuel Westlake

        DESCRIPTION:
        ------------

        Checks the config for missing or invalid values and corrects where necessary.

        PARAMETERS:
        -----------

        :param dictionary: dictionary to check the config against.
        :param sub_space: list of strings: for internal use

        RETURN:
        -------

        :return: None
        """
        sub_space = [] if sub_space is None else sub_space
        sub_space = sub_space if isinstance(sub_space, list) else [sub_space]
        for name, value in dictionary.items():
            if isinstance(value, dict):
                keys = list(self.config.get(
                    sub_space)) if name is DEEP_CONFIG_WILDCARD else [name]
                for key in keys:
                    if DEEP_CONFIG_DTYPE in value and DEEP_CONFIG_DEFAULT in value:
                        if self.config.check(key, sub_space=sub_space):
                            cond_1 = value[DEEP_CONFIG_DTYPE] is None
                            cond_2 = self.config.get(
                                sub_space)[key] == value[DEEP_CONFIG_DEFAULT]
                            # If dtype is none or the item is already the default value, continue
                            if cond_1 or cond_2:
                                continue
                            else:
                                self.config.get(
                                    sub_space)[key] = self.__convert(
                                        self.config.get(sub_space)[key],
                                        value[DEEP_CONFIG_DTYPE],
                                        value[DEEP_CONFIG_DEFAULT],
                                        sub_space=sub_space + [key])
                        else:
                            self.__add_to_config(key,
                                                 value[DEEP_CONFIG_DEFAULT],
                                                 sub_space)
                    else:
                        self.__check_config(dictionary=value,
                                            sub_space=sub_space + [key])

    def __add_to_config(self, key, default, sub_space):
        """
        Used by self.__config() to add a (default) value to the config
        :param key:
        :param default:
        :param sub_space:
        :return:
        """
        item_path = DEEP_CONFIG_DIVIDER.join(sub_space + [key])
        default_name = {} if isinstance(default, Namespace) else default
        Notification(DEEP_NOTIF_WARNING,
                     DEEP_MSG_CONFIG_NOT_FOUND % (item_path, default_name))
        # self.config.get(sub_space)[key] = default
        self.config.add({key: default}, sub_space=sub_space)

    def __convert(self, value, d_type, default, sub_space=None):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake

        DESCRIPTION:
        ------------
        Converts a given value to a given data type, and returns the result.
        If the value can not be converted, the given default value is returned.
        NB: If d_type is given in a list, e.g. [str], it is assume that value should be a list and each item in value
        will be converted to the given data type. If any item in the list cannot be converted, None will be returned.

        PARAMETERS:
        -----------
        :param value: the value to be converted
        :param d_type: the data type to convert the value to
        :param default: the default value to return if the current value
        :param sub_space: the list of strings that defines the current sub-space

        RETURN:
        -------
        :return: new_value
        """
        sub_space = [] if sub_space is None else sub_space
        sub_space = DEEP_CONFIG_DIVIDER.join(sub_space)

        # If the value is not set
        if value is None and default is not None:
            # Notify user that default is being used
            if default == {}:
                new_value = Namespace()
            else:
                new_value = default
                if not default == []:
                    Notification(
                        DEEP_NOTIF_WARNING,
                        DEEP_MSG_CONFIG_NOT_SET % (sub_space, default))
        elif d_type is dict:
            new_value = Namespace(convert_dict(value.get_all()))
        else:
            new_value = convert(value, d_type)
            if new_value is None:
                # Notify user that default is being used
                Notification(
                    DEEP_NOTIF_WARNING, DEEP_MSG_CONFIG_NOT_CONVERTED %
                    (sub_space, value, self.__get_dtype_name(d_type), default))
        return new_value

    def __get_dtype_name(self, d_type):
        """
        :param d_type:
        :return:
        """
        if isinstance(d_type, list):
            return [self.__get_dtype_name(dt) for dt in d_type]
        elif isinstance(d_type, dict):
            return {
                key: self.__get_dtype_name(dt)
                for key, dt in d_type.items()
            }
        else:
            return d_type.__name__

    def __on_wake(self):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake

        DESCRIPTION:
        ------------
        Executes the list of commands in self.config.project.on_wake

        RETURN:
        -------
        :return: None
        """
        if self.config.project.on_wake is not None:
            for command in self.config.project.on_wake:
                Notification(DEEP_NOTIF_INFO, command)
                self.__execute_command(command)

    def __execute_command(self, command):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake

        DESCRIPTION:
        ------------
        Calls exec for the given command

        PARAMETERS:
        -----------
        :param command: str: the command to execute

        RETURN:
        -------
        :return: None
        """
        commands, flags = self.__preprocess_command(command)
        for command, flag in zip(commands, flags):
            if command in DEEP_EXIT_FLAGS:
                self.sleep()
            else:
                try:
                    if flag is None:
                        exec("self.%s" % command)
                    elif flag == DEEP_CMD_PRINT:
                        exec("Notification(DEEP_NOTIF_RESULT, self.%s)" %
                             command)
                except DeepError as e:
                    time.sleep(0.1)
                except KeyboardInterrupt:
                    self.sleep()

    def __preprocess_command(self, command):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake

        DESCRIPTION:
        ------------
        Pre-processes a given command for execuution.

        PARAMETERS:
        -----------
        :param command: str: the command to process.

        RETURN:
        -------
        :return: str: the command, str: any flags associated with the command.
        """
        commands = command.split(" & ")
        for command in commands:
            remove = False
            for prefix in DEEP_FILTER_STARTS_WITH:
                if command.startswith(prefix):
                    remove = True
                    break
            if not remove:
                for suffix in DEEP_FILTER_ENDS_WITH:
                    if command.endswith(suffix):
                        remove = True
            if not remove:
                for item in DEEP_FILTER:
                    if command == item:
                        remove = True
            if not remove:
                for item in DEEP_FILTER_STARTS_ENDS_WITH:
                    if command.startswith(item) and command.endswith(item):
                        remove = True
            if not remove:
                for item in DEEP_FILTER_INCLUDES:
                    if item in command:
                        remove = True
            if remove:
                commands.remove(command)
                self.__illegal_command_messages(command)
        return self.__get_command_flags(commands)

    @staticmethod
    def __illegal_command_messages(command):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake

        DESCRIPTION:
        ------------
        Explains why a given command is illegal.

        PARAMETERS:
        -----------
        :param command: str: the illegal command.

        RETURN:
        -------
        :return: None
        """
        message = (DEEP_MSG_ILLEGAL_COMMAND % command)
        if "__" in command or "._" in command or command.startswith("_"):
            message = "%s %s" % (message, DEEP_MSG_PRIVATE)
        if command == "wake()":
            message = "%s %s" % (message, DEEP_MSG_ALREADY_AWAKE)
        if command == "config.save":
            message = "%s %s" % (message, DEEP_MSG_USE_CONFIG_SAVE)
        Notification(DEEP_NOTIF_WARNING, message)

    @staticmethod
    def __get_command_flags(commands):
        """
        AUTHORS:
        --------
        :author: Samuel Westlake

        DESCRIPTION:
        ------------
        Extracts any flags from each command in a list of commands.

        PARAMETERS:
        -----------
        :param commands: list of str: the commands to extract flags from.

        RETURN:
        -------
        :return: None
        """
        flags = [None for _ in range(len(commands))]
        for i, command in enumerate(commands):
            for flag in DEEP_CMD_FLAGS:
                if flag in command:
                    flags[i] = flag
                    commands[i] = command.replace(" %s" % flag, "")
                else:
                    flags[i] = None
        return commands, flags

    @staticmethod
    def __good_bye():
        """
        AUTHORS:
        --------

        :author: Alix Leroy

        DESCRIPTION:
        ------------

        Display thanks message

        PARAMETERS:
        -----------

        None

        RETURN:
        -------

        :return: Universal Love <3
        """
        Notification(DEEP_NOTIF_LOVE, "=================================")
        Notification(DEEP_NOTIF_LOVE, "Thank you for using Deeplodocus !")
        Notification(DEEP_NOTIF_LOVE, "== Made by Humans with deep <3 ==")
        Notification(DEEP_NOTIF_LOVE, "=================================")

    """
    "
    " Aliases
    "
    """

    visual_cortex = ui
    vc = ui
    user_interface = ui