confection
? est une bibliothèque légère qui propose un système de configuration vous permettant de décrire commodément des arbres arbitraires d'objets.
La configuration est un énorme défi pour le code d'apprentissage automatique car vous pouvez exposer presque tous les détails de toute fonction en tant qu'hyperparamètre. Le paramètre que vous souhaitez exposer peut être arbitrairement loin dans votre pile d'appels, il peut donc avoir besoin de passer à travers l'API CLI ou REST, à travers un certain nombre de fonctions intermédiaires, affectant l'interface de tout le long du chemin. Et puis une fois ces paramètres ajoutés, ils deviennent difficiles à supprimer plus tard. Les valeurs par défaut deviennent également difficiles à modifier sans casser la compatibilité en arrière.
Pour résoudre ce problème, confection
propose un système de configuration qui vous permet de décrire facilement des arbres arbitraires d'objets. Les objets peuvent être créés via des appels de fonction que vous vous inscrivez à l'aide d'une syntaxe de décorateur simple. Vous pouvez même verser les fonctions que vous créez, vous permettant d'apporter des améliorations sans rompre la compatibilité. Le système de configuration le plus similaire que nous connaissons est Gin, qui utilise une syntaxe similaire, et vous permet également de relier le système de configuration aux fonctions de votre code à l'aide d'un décorateur. Le système de configuration de confection
est plus simple et met l'accent sur un flux de travail différent via un sous-ensemble de la fonctionnalité de Gin.
Pip Installer la confection
conda install -c conda-forge confection
Le système de configuration analyse un fichier .cfg
comme
[formation] patience = 10Dropout = 0.2Use_Vecteurs = false [Training.Logging] niveau = "info" [NLP] # Ceci utilise la valeur de la formation.USE_VECTORSUSUSE_VECTORS = $ {Training.Use_Vecteurs} lang = "en"
et le résout pour un Dict
:
{"Training": {"Patience": 10, "Dropout": 0.2, "use_vectors": false, "logging": {"niveau": "info"} }, "NLP": {"use_vectors": false, "lang": "en" } }
La configuration est divisée en sections, avec le nom de la section entre crochets - par exemple, [training]
. Dans les sections, les valeurs de configuration peuvent être attribuées aux touches en utilisant =
. Les valeurs peuvent également être référencées à partir d'autres sections en utilisant la notation de points et les espaces réservés indiqués par le signe dollar et les accolades bouclées. Par exemple, ${training.use_vectors}
recevra la valeur de use_vectors dans le bloc de formation. Ceci est utile pour les paramètres partagés entre les composants.
Le format de configuration a trois différences principales par rapport au configparser
intégré de Python:
Valeurs de format JSON. confection
transmet toutes les valeurs via json.loads
pour les interpréter. Vous pouvez utiliser des valeurs atomiques comme des chaînes, des flotteurs, des entiers ou des booléens, ou vous pouvez utiliser des objets complexes tels que des listes ou des cartes.
Sections structurées. confection
utilise une notation de points pour construire des sections imbriquées. Si vous avez une section nommée [section.subsection]
, confection
analysera cela dans une structure imbriquée, plaçant la sous-section dans la section.
Références aux fonctions de registre. Si une touche commence par @
, confection
interprétera sa valeur comme le nom d'un registre de fonction, chargez la fonction enregistrée pour ce nom et passe dans le reste du bloc comme arguments. Si des indices de type sont disponibles sur la fonction, les valeurs d'argument (et la valeur de retour de la fonction) seront validées contre eux. Cela vous permet d'exprimer des configurations complexes, comme un pipeline de formation où batch_size
est rempli d'une fonction qui donne des flotteurs.
Il n'y a pas de schéma prédéfini que vous devez suivre; La façon dont vous configurez les sections de niveau supérieur dépend de vous. À la fin de celui-ci, vous recevrez un dictionnaire avec les valeurs que vous pouvez utiliser dans votre script - qu'il s'agisse de fonctions initialisées complètes, ou simplement des paramètres de base.
Par exemple, disons que vous souhaitez définir un nouvel optimiseur. Vous définissez ses arguments dans config.cfg
comme tel:
[Optimizer] @Optimizers = "MY_COOL_OPTIMIZER.v1" Learn_Rate = 0.001GAMMA = 1E-8
Pour charger et analyser cette configuration à l'aide d'un registre catalogue
(installer catalogue
séparément):
Importer DataClasses de la dactylographie Union d'importation, IteableMport Catalognefrom Confection Import Registry, config # Créer un nouveau registre.Registry.Optimizers = Catalogue.Create ("Confise", "Optimizers", Entry_pointS = FALSE) # Définissez une classe d'optimiseur muette. @ dataclasses.dataclassclassclass) # MyCooloptizer: Learn_Rate: FloatGamma: [email protected] ("my_cool_optimizer.v1") def make_my_optimizer (Learn_rate: Union [float, itéable [float]], gamma: float): return myCoolOptimizer (Learn_rate, gamma) # Chargez le fichier de configuration à partir du disque, résolve (Learn_rate, Gamma) # il et récupérez l'optimiseur instancié objet.config = Config (). From_disk ("./ config.cfg") résolu = registry.Resolve (config) optimizer = résolu ["Optimizer"] # myCoolOptimizer (Learn_rate = 0.001, gamma = 1e-08)
️ ATTENTION: Type-Checkers tels quemypy
marquera l'ajout de nouveaux attributs auregistry
de cette façon - c'est-à-direregistry.new_attr = ...
- comme erreurs. En effet, un nouvel attribut est ajouté à la classe après initialisation. Si vous utilisez des TypeCheckers, vous pouvez soit ignorer cela (par exemple avec# type: ignore
pourmypy
) ou utiliser une alternative TypeSafe: au lieu deregistry.new_attr = ...
, utilisezsetattr(registry, "new_attr", ...)
.
Sous le capot, confection
consultera la fonction "my_cool_optimizer.v1"
dans le registre "Optimizers", puis l'appelez avec les arguments learn_rate
et gamma
. Si la fonction a des annotations de type, elle validera également l'entrée. Par exemple, si learn_rate
est annoté comme un flotteur et que la configuration définit une chaîne, confection
augmentera une erreur.
La documentation de THINC offre des informations supplémentaires sur le système de configuration:
blocs récursifs
Définition des arguments positionnels variables
Utilisation d'interpolation
en utilisant des registres personnalisés
Annotations de type avancé avec pydance
Utilisation de schémas de base
remplir une configuration avec des valeurs par défaut
Config
de classe Cette classe contient le modèle et la configuration de formation et peut charger et enregistrer le format de configuration de style INI de / vers une chaîne, un fichier ou des octets. La classe Config
est une sous-classe de dict
et utilise ConfigParser
de Python sous le capot.
Config.__init__
Initialisez un nouvel objet Config
avec des données facultatives.
à partir de la confiserie ConfigConfig = config ({"Training": {"Patience": 10, "Dropout": 0.2}})
Argument | Taper | Description |
---|---|---|
data | Optional[Union[Dict[str, Any], Config]] | Données facultatives pour initialiser la configuration avec. |
section_order | Optional[List[str]] | Les noms de section de niveau supérieur, dans l'ordre, ont utilisé pour trier la configuration enregistrée et chargée. Toutes les autres sections seront triées de manière alphabétique. |
is_interpolated | Optional[bool] | Si la configuration est interpolée ou si elle contient des variables. Lisez à partir des data s'il s'agit d'une instance de Config et autrement par défaut est True . |
Config.from_str
Chargez la configuration à partir d'une chaîne.
From Confection Import configConfig_str = "" "[formation] patience = 10Dropout = 0.2" "" config = config (). from_str (config_str) print (config ["Training"]) # {'patience': 10, 'dropout': 0,2}}
Argument | Taper | Description |
---|---|---|
text | str | La configuration de chaîne à charger. |
interpolate | bool | Que ce soit pour interpoler des variables comme ${section.key} . Par défaut est True . |
overrides | Dict[str, Any] | Remplacez les valeurs et les sections. Les clés sont fournies en notation DOT, par exemple "training.dropout" mappé à la valeur. |
Rendements | Config | La configuration chargée. |
Config.to_str
Chargez la configuration à partir d'une chaîne.
à partir de la confiserie ConfigConfig = config ({"Training": {"Patience": 10, "Dropout": 0.2}}) print (config.to_str ()) # '[formation] npatience = 10nndropout = 0.2'
Argument | Taper | Description |
---|---|---|
interpolate | bool | Que ce soit pour interpoler des variables comme ${section.key} . Par défaut est True . |
Rendements | str | La configuration de chaîne. |
Config.to_bytes
Sérialisez la configuration en une chaîne d'octet.
From Confpection Import configConfig = config ({"Training": {"Patience": 10, "Dropout": 0.2}}) config_bytes = config.to_bytes () print (config_bytes) # b '[formation] npatience = 10nndropout = 0.2'
Argument | Taper | Description |
---|---|---|
interpolate | bool | Que ce soit pour interpoler des variables comme ${section.key} . Par défaut est True . |
overrides | Dict[str, Any] | Remplacez les valeurs et les sections. Les clés sont fournies en notation DOT, par exemple "training.dropout" mappé à la valeur. |
Rendements | str | La configuration sérialisée. |
Config.from_bytes
Chargez la configuration à partir d'une chaîne d'octet.
From Confiction Import ConfigConfig = config ({"Training": {"Patience": 10, "Dropout": 0.2}}) config_bytes = config.to_bytes () new_config = config (). from_bytes (config_bytes)
Argument | Taper | Description |
---|---|---|
bytes_data | bool | Les données à charger. |
interpolate | bool | Que ce soit pour interpoler des variables comme ${section.key} . Par défaut est True . |
Rendements | Config | La configuration chargée. |
Config.to_disk
Sérialiser la configuration en fichier.
à partir de la confiserie ConfigConfig = config ({"Training": {"Patience": 10, "Dropout": 0.2}}) config.to_disk ("./ config.cfg")
Argument | Taper | Description |
---|---|---|
path | Union[Path, str] | Le chemin du fichier. |
interpolate | bool | Que ce soit pour interpoler des variables comme ${section.key} . Par défaut est True . |
Config.from_disk
Chargez la configuration à partir d'un fichier.
From Confiction Import configConfig = config ({"Training": {"Patience": 10, "Dropout": 0.2}}) config.to_disk ("./ config.cfg") new_config = config (). from_disk ("./ config.cfg ")
Argument | Taper | Description |
---|---|---|
path | Union[Path, str] | Le chemin du fichier. |
interpolate | bool | Que ce soit pour interpoler des variables comme ${section.key} . Par défaut est True . |
overrides | Dict[str, Any] | Remplacez les valeurs et les sections. Les clés sont fournies en notation DOT, par exemple "training.dropout" mappé à la valeur. |
Rendements | Config | La configuration chargée. |
Config.copy
Copie profonde la configuration.
Argument | Taper | Description |
---|---|---|
Rendements | Config | La configuration copiée. |
Config.interpolate
Variables interpolates comme ${section.value}
ou ${section.subsection}
et renvoyez une copie de la configuration avec des valeurs interpolées. Peut être utilisé si une configuration est chargée d' interpolate=False
, par exemple via Config.from_str
.
à partir de la confiserie ConfigConfig_str = "" "[hyper_params] dropout = 0.2 [formation] dropout = $ {hyper_params.dropout}" "" config = config (). from_str (config_str, interpolate = false) print (config ["formation"] ) # {'Dropout': '$ {hyper_params.dropout}'}} config = config.interpolate () print (config ["Training"]) # {'Dropout': 0.2}}
Argument | Taper | Description |
---|---|---|
Rendements | Config | Une copie de la configuration avec des valeurs interpolées. |
Config.merge
Deep-Merge deux objets de configuration, en utilisant la configuration actuelle comme par défaut. Merge uniquement les sections et les dictionnaires et non d'autres valeurs comme les listes. Les valeurs fournies dans les mises à jour sont écrasées dans la configuration de base, et de nouvelles valeurs ou sections sont ajoutées. Si une valeur de configuration est une variable comme ${section.key}
(par exemple, si la configuration était chargée d' interpolate=False)
, la variable est préférée , même si les mises à jour fournissent une valeur différente. Cela garantit que les références variables ne sont pas détruites par une fusion.
️ Notez que les blocs qui se réfèrent aux fonctions enregistrées à l'aide de la syntaxe@
ne sont fusionnées que si elles font référence aux mêmes fonctions. Sinon, la fusion pourrait facilement produire des configurations non valides, car différentes fonctions peuvent prendre différents arguments. Si un bloc fait référence à une fonction différente, elle est écrasée.
à partir de la confection import configBase_config_str = "" "[formation] patience = 10Dropout = 0.2" "" update_config_str = "" "[formation] dropout = 0.1max_epochs = 2000" "" base_config = config (). from_str (base_config_str) update_config = config (config (). ) .from_str (update_config_str) fusionné = Config (base_config) .Merge (update_config) imprimer (fusionné ["formation"]) # {'patience': 10, 'Dropout': 0.1, 'max_epochs': 2000}
Argument | Taper | Description |
---|---|---|
overrides | Union[Dict[str, Any], Config] | Les mises à jour pour fusionner dans la configuration. |
Rendements | Config | Une nouvelle instance de configuration contenant la configuration fusionnée. |
Argument | Taper | Description |
---|---|---|
is_interpolated | bool | Si les valeurs de configuration ont été interpolées. Par défaut est True et est défini sur False si une configuration est chargée d' interpolate=False , par exemple en utilisant Config.from_str . |