Vervollständigen Sie YAML-Inhalte automatisch mit Python

Zusammenfassung dieses Artikels

Sie können einige Einstellungen in eine YAML-Datei schreiben und als Referenz aus Python laden. Besonders im Bereich des maschinellen Lernens habe ich viele Eindrücke.

Das Ergebnis des Ladens ist jedoch ein Wörterbuchobjekt, dessen Schlüsselname und hierarchische Struktur in der YAML-Datei visuell bestätigt werden müssen. Ich konnte die YAML-Überprüfungsarbeit während des Codierens nicht ertragen.

Dieser Artikel ist eine der Möglichkeiten, dies für Personen zu tun, die ** config in einer YAML-Datei definieren möchten und dieses Element während der Python-Implementierung automatisch vervollständigt wird ** </ font> Ist vorgestellt.

Den Code finden Sie hier [https://github.com/Nkriskeeic/configer]. Dieser Code ist modular aufgebaut und kann mit pip installiert werden.

Beschreiben Sie den Einstellungswert in der YAML-Datei

Schauen wir uns zunächst ein Beispiel für das Schreiben von Einstellungswerten in eine YAML-Datei an.

config.yml


model:
    in_channels: 3
    n_blocks: 10
    block:
        channels: 64
        activation: relu
    out_channels: 1

Ich denke, dass die Einstellungswerte in der YAML-Datei oft hierarchisch beschrieben werden, wie oben gezeigt. Wenn Sie dies aus einem Python-Skript lesen, wird es möglicherweise etwas anders geschrieben, aber ich denke, es wird ungefähr so aussehen.

main.py


config = yaml.safe_load('./config.yml')
model = Model(
    in_channels = config['model']['in_channels'],
    out_channels = config['model']['out_channels'],
    n_blocks = config['model']['n_blobks'],
    block_channels = config['model']['block']['channels'],
    ...
)

Erstens konnte ich es nicht ertragen, diesen ** Wörterbuchschlüsselnamen ** hart zu codieren. Zweitens konnte ich es für die in YAML definierte hierarchische Struktur nicht ertragen, in die YAML-Datei zu gehen, um mich daran zu erinnern, welche Werte in welcher Hierarchie definiert wurden.

Im Idealfall ** Wenn Sie die Konfiguration in der YAML-Datei definieren, werden die in YAML festgelegten Elemente auch während der Implementierung im Python-Skript automatisch vervollständigt **.

main.py[Ideal]


config = get_config('./config.yml')
model = Model(
    in_channels = config.model.in_channels,
    out_channels = config.model.out_channels, # <-Der Punktzugriff wird automatisch abgeschlossen. Ich möchte, dass Sie den Typ überprüfen

In YACS wird die Vorlage der YAML-Datei vom Python-Skript definiert, sodass ich denke, dass es möglich ist, den Inhalt von YAML durch automatische Vervollständigung im Python-Skript auszugeben. Es wurde jedoch nicht durch mein PyCharm ergänzt.

yacs


from yacs.config import CfgNode as CN

_C = CN()

_C.MODEL = CN()
_C.MODEL.IN_CHANNELS = 3

def get_cfg_defaults():
  return _C.clone()

config = get_cfg_defaults()
config.MODEL.IN_CHANNELS # <--Nicht automatisch ergänzt

Daher habe ich beschlossen, ein eigenes Framework zu erstellen. ** Wenn Sie config in der YAML-Datei definieren, werden die in YAML festgelegten Elemente auch während der Implementierung im Python-Skript automatisch vervollständigt.

Generieren Sie das entsprechende Python-Skript aus der YAML-Datei

Erstens: ** Wenn eine Python-Datei mit demselben Inhalt automatisch aus der YAML-Datei generiert werden kann, kann sie bei der Implementierung von ** </ font> automatisch unter Bezugnahme auf die Python-Datei abgeschlossen werden. Ich tat. Das ist das Bild.

config.yml


hoge: piyo

YAML-> Python-Konvertierung

config.py


hoge: str = 'piyo'

Bei der obigen einfachen Konvertierung fiel es mir jedoch schwer, die hierarchische Struktur in YAML unter Python auszudrücken.

Aus diesem Grund habe ich beschlossen, es etwas komplizierter zu gestalten und damit umzugehen, indem ** alle hierarchischen Strukturen in Datenklassen umgewandelt werden **.

config.yml


model:
    in_channels: 3
    n_blocks: 10
    block:
        channels: 64
        activation: relu
    out_channels: 1

YAML-> Python-Konvertierung

config.py


@dataclass
class ModelBlock:
    channels: int = 64
    activation: str = 'relu'

@dataclass
class Model:
    in_channels: int = 3
    n_blocks: int = 10
    block: ModelBlock = ModelBlock()
    out_channels: int = 1

@dataclass
class Config:
    model: Model = Model()

Config().model.block.channels  # <-Alles kann ergänzt werden

Der Grund für die Verwendung der Datenklasse besteht darin, die Anzahl der Beschreibungen aufgrund der automatischen Generierung magischer Methoden zu verringern und versehentliche Änderungen an Elementvariablen durch Setzen von "eingefroren = Wahr" zu verhindern. Ich versuche auch, Typanmerkungen zu generieren. Dies wird rekursiv implementiert. Gefällt mir.

Allein damit konvertiere ich nur die YAML-Datei in ein Python-Skript, aber da ich die Konfiguration klassifizieren konnte, möchte ich sie generieren, nachdem ich einige praktische Methoden hinzugefügt habe, die sich auf die Einstellung beziehen.

Es schien schmerzhaft zu sein, die Generierung nur mit String-Verkettung zu schreiben, daher entschied ich mich für die Verwendung eines Python-Skriptgenerierungsmoduls von Drittanbietern, prestring. tat.

Ich habe es mit [Like this] implementiert (https://github.com/Nkriskeeic/configer/blob/master/configer/template/template.py). Generieren Sie eine config.py, während Sie mehrere Dateien kombinieren Es ist ein Bild zu tun.

config.yml


model:
    in_channels: 3
    n_blocks: 10
    block:
        channels: 64
        activation: relu
    out_channels: 1

YAML-> Python-Konvertierung

config.py


@dataclass
class ModelBlock:
    channels: int = 64
    activation: str = 'relu'

@dataclass
class Model:
    in_channels: int = 3
    n_blocks: int = 10
    block: ModelBlock = ModelBlock()
    out_channels: int = 1

@dataclass
class Config:
    model: Model = Model()

    def some_cool_method():
        ...

class ConfigGenerator:
    def generate():
        ...
        return Config()

Die Klasse "Config" ist für die Pflege des Inhalts von YAML verantwortlich. Der Grund für das Erstellen der "ConfigGenerator" -Klasse besteht darin, dass beim tatsächlichen Lesen des Einstellungswerts aus der YAML-Datei überprüft werden musste, ob er mit der aktuellen "Config" -Klasse inkonsistent war und ob der Typ unterschiedlich war.

Wenn Sie config in der Zieldatei ** YAML definieren, werden die in YAML festgelegten Elemente auch während der Implementierung im Python-Skript automatisch vervollständigt (indem der Inhalt der YAML-Datei in die Python-Klasse konvertiert wird) ** Dinge sind jetzt möglich.

main.py


config = ConfigGenerator().generate()
model = Model(
    in_channels = config.model.in_channels,
    out_channels = config.model.out_channels, # <-Der Punktzugriff wird automatisch abgeschlossen und es werden auch Typanmerkungen angezeigt

Es gibt jedoch eine Einschränkung, dass ** wenn Sie eine YAML-Datei schreiben, Sie den Befehl drücken müssen, um sie vom Terminal aus in ein Python-Skript zu konvertieren **.

Wenn Sie nicht in 1 Sekunde zur Tippfehler- oder YAML-Datei wechseln müssen, befinden Sie sich im akzeptablen Bereich und es ist in Ordnung.

Zusatzfunktionen

Da config zu einer Datenklasse gemacht wurde, hielt ich es für zweckmäßig, verschiedene Klassenmethoden durch automatische Generierung hinzuzufügen.

Funktion zum Einstellen des Werts überschreiben

Wenn der Einstellungswert im Experiment häufig geändert wird, gibt es eine Szene wie "Die Standardeinstellung wird in" default.yml "beschrieben, und einige Werte werden in" exp1.yml "aktualisiert". herauskommen. Um die Sichtbarkeit zu verbessern, "Schreiben Sie die Standardeinstellung in" default.yml ", überschreiben Sie die Modelleinstellung mit" model.yml "und überschreiben Sie die Datensatzeinstellung mit" dataset.yml ". Es gibt auch Szenen.

Zu jener Zeit

main.py


config = ConfigGenerator() \
    .update_by(['exp1.yml']) \
    .generate()
config = ConfigGenerator() \
    .update_by(['model.yml', 'dataset.yml']) \
    .generate()

Ich habe beschlossen, eine solche Funktion zu "Config Generator" hinzuzufügen, da dies nach Möglichkeit praktisch wäre. Für die von update_by übergebene YAML müssen Sie sie jedoch nur als Wörterbuch laden, den Typ und den Variablennamen überprüfen und den entsprechenden Wert überschreiben.

Vorerst habe ich es möglich gemacht, mehrere YAML-Dateien gleichzeitig zu empfangen. Wenn ich jedoch versuche, denselben Einstellungswert mit einem anderen Wert in der jeweils anderen Datei zu überschreiben, wird ein Fehler ausgegeben.

Druckfunktion

Indem Sie die eingestellten Werte bei der Ausführung des Skripts leicht lesbar anzeigen, können Sie unerwartete Unfälle vermeiden.

Ich habe es so angezeigt.

python


config = ConfigGenerator() \
    .update_by(['model.yml']) \
    .update_by(['exp01.yml']) \
    .generate()

config.pprint(wait_yes=True)  # <-Verhindern Sie die Ausführung von Code, es sei denn, Sie überprüfen die Anzeige und drücken JA

Ausgabeergebnis

default from /config/default.yml model:     in_channels: 3     n_blocks: 20 (default 10, changed by /config/model.yml)     block:         channels: 32 (default 64, changed by /config/exp01.yml)         activation: relu     out_channels: 1

Ich habe versucht, beim Aktualisieren vom Standardwert mit einer Datei eine Warnmeldung auszugeben. Auf diese Weise können Sie sofort feststellen, wenn Sie den Code mit einer Einstellung ausführen, die sich von der geplanten Einstellung unterscheidet.

Recommended Posts