Nous avons créé un outil pratique colt
pour écrire des paramètres d'application tels que l'apprentissage automatique.
En bref, colt
est un outil pour écrire des paramètres comme ʻAllenNLP`.
J'ai écrit "Machine learning" dans le titre, mais je pense qu'il peut être utilisé pour définir de nombreuses applications, sans se limiter à l'apprentissage automatique.
Lors de l'expérimentation de modèles d'apprentissage automatique, nous voyons souvent «argparse» et «Hydra» utilisés pour gérer les hyperparamètres. Je pense que le problème avec beaucoup de ces outils de gestion des paramètres existants est que lorsque vous effectuez un changement majeur de modèle, vous devez également modifier le processus de chargement des paramètres.
Par exemple (un exemple très agressif), SVC
de scikit-learn
J'avais l'intention d'utiliser generated / sklearn.svm.SVC.html? Highlight = svc # sklearn-svm-svc) et j'ai écrit un paramètre pour lire des paramètres tels que C
, noyau
, class_weight
dans ʻargparse. , [
RandomForestClassifier](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.RandomForestClassifier.html?highlight=randomforest#sklearn-ensemble-randomforestclassifier) Est-il nécessaire de réécrire même la pièce? De plus, si vous souhaitez définir un modèle d'ensemble tel que [
StackingClassifier`](https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.StackingClassifier.html?highlight=stacking#sklearn-ensemble-stackingclassifier) , Si vous souhaitez définir le classificateur de base et le méta-classificateur, vous vous demandez comment écrire les paramètres.
AllenNLP
L'un des moyens de résoudre ces problèmes est la ** fonction Register ** adoptée par ʻAllenNLP`, qui est un cadre d'apprentissage en profondeur pour le traitement du langage naturel. Il y a.
Ici, je vais expliquer un peu cette ** fonction de registre **. Si vous le connaissez, veuillez l'ignorer.
ʻAllenNLP` décrit les paramètres au format JSON. Voici quelques-uns des paramètres du modèle de classification des phrases:
"model": {
"type": "basic_classifier",
"text_field_embedder": {
"token_embedders": {
"tokens": {
"type": "embedding",
"embedding_dim": 10,
"trainable": true
}
}
},
"seq2vec_encoder": {
"type": "cnn",
"num_filters": 8,
"embedding_dim": 10,
"output_dim": 16
}
},
Spécifiez la classe que vous souhaitez utiliser avec type
et définissez les paramètres dans le champ du même niveau.
Regardons également le code pour basic_classifier
et cnn
. Les éléments de paramétrage correspondent aux arguments de la méthode __init__
:
@Model.register("basic_classifier")
class BasicClassifier(Model):
def __init__(
self,
...,
text_field_embedder: TextFieldEmbedder,
seq2vec_encoder: Seq2VecEncoder,
...,
) -> None:
...
@Seq2VecEncoder.register("cnn")
class CnnEncoder(Seq2VecEncoder):
def __init__(self,
embedding_dim: int,
num_filters: int,
ngram_filter_sizes: Tuple[int, ...] = (2, 3, 4, 5),
conv_layer_activation: Activation = None,
output_dim: Optional[int] = None) -> None:
Si vous enregistrez des classes avec le décorateur register
, vous pouvez spécifier ces classes à partir des paramètres.
Avec ʻAllenNLP, vous pouvez écrire les paramètres d'une classe simplement en créant une classe et
register`.
Ici, cette fonction est appelée ** fonction de registre **.
Comme la fonction Register associe une classe à ses paramètres, il n'est pas nécessaire de modifier le processus de lecture des paramètres en fonction du changement de modèle.
Vous pouvez facilement remplacer divers composants du modèle à partir des paramètres.
Pour changer le type
de seq2vec_encoder
de cnn
à lstm
, réécrivez simplement les paramètres comme suit (lstm
est déjà fourni dans ʻAllenNLP`)
"seq2vec_encoder": {
"type": "lstm",
"num_layers": 1,
"input_size": 10,
"hidden_size": 16
}
colt
colt
est un outil pour réaliser la même fonction que ** Register function ** de ʻAllenNLP. En utilisant
colt, vous pouvez facilement définir des paramètres flexibles et résistants aux changements de code comme ʻAllenNLP
.
Il implémente également certaines fonctionnalités non trouvées dans ʻAllenNLP` pour le rendre plus facile à utiliser dans plus de cas.
Voici un exemple d'utilisation de colt
:
import typing as tp
import colt
@colt.register("foo")
class Foo:
def __init__(self, message: str) -> None:
self.message = message
@colt.register("bar")
class Bar:
def __init__(self, foos: tp.List[Foo]) -> None: # ---- (*)
self.foos = foos
config = {
"@type": "bar", # `@type`Spécifiez la classe avec
"foos": [
{"message": "hello"}, #Le type ici est(*)Déduit de l'indice de type
{"message": "world"},
]
}
bar = colt.build(config) #Construire des objets à partir de la configuration
assert isinstance(bar, Bar)
print(" ".join(foo.message for foo in bar.foos)) # => "hello world"
Enregistrez la classe avec colt.register (" <identificateur de classe> ")
.
Côté paramétrage, décrivez au format {" @type ":" <identificateur de classe> ", (argument) ...}
.
Lors de la construction d'un objet à partir d'un paramètre, appelez colt.build (<setting dict>)
.
S'il n'y a pas de champ «@ type» dans le paramètre et que l'indication de type est écrite dans l'argument correspondant, l'objet est créé en fonction de l'indication de type.
Dans l'exemple ci-dessus, l'indication de type List [Foo]
est donnée à l'argument foos
de Bar
, ainsi le contenu de foos
dans config
est converti en objets de la classe Foo
.
Les indices de type ne sont pas toujours requis pour «colt».
Si vous n'utilisez pas d'indices de type, écrivez @ type
sans l'omettre.
config = {
"@type": "bar",
"foos": [
{"@type": "bar", "message": "hello"},
{"@type": "bar", "message": "world"},
]
}
S'il n'y a pas de @ type
ou d'indice de type, il est simplement traité comme dict
.
Vous pouvez également utiliser colt
pour les modèles existants inclus dans scikit-learn
etc.
Si le nom spécifié par «@ type» n'est pas «enregistré», il sera importé automatiquement.
Voici un exemple d'utilisation de StackingClassifier
de scikit-learn
:
import colt
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
config = {
"@type": "sklearn.ensemble.StackingClassifier",
"estimators": [
("rfc", { "@type": "sklearn.ensemble.RandomForestClassifier",
"n_estimators": 10 }),
("svc", { "@type": "sklearn.svm.SVC",
"gamma": "scale" }),
],
"final_estimator": {
"@type": "sklearn.linear_model.LogisticRegression",
"C": 5.0,
},
"cv": 5,
}
X, y = load_iris(return_X_y=True)
X_train, X_valid, y_train, y_valid = train_test_split(X, y)
model = colt.build(config)
model.fit(X_train, y_train)
valid_accuracy = model.score(X_valid, y_valid)
print(f"valid_accuracy: {valid_accuracy}")
Dans l'exemple ci-dessus, le modèle décrit dans config
peut être remplacé s'il a l'API de scikit-learn
.
Par exemple, pour rechercher dans la grille LGBMClassifier
avec GridSearchCV
:
config = {
"@type": "sklearn.model_selection.GridSearchCV",
"estimator": {
"@type": "lightgbm.LGBMClassifier",
"boosting_type": "gbdt",
"objective": "multiclass",
},
"param_grid": {
"n_estimators": [10, 50, 100],
"num_leaves": [16, 32, 64],
"max_depth": [-1, 4, 16],
}
}
colt
ne fournit pas de fonction pour lire les paramètres d'un fichier.
Si vous voulez lire les paramètres d'un fichier, convertissez votre format préféré tel que JSON / Jsonnet ou YAML en «dict» et transmettez-le à «colt».
Si vous vous inscrivez dans plusieurs fichiers différents, toutes les classes à utiliser au moment de «colt.build» doivent être importées.
colt
peut utiliser cold.import_modules
pour importer récursivement plusieurs modules.
Par exemple, considérez la structure de fichiers suivante:
.
|-- main.py
`- models
|-- __init__.py
|-- foo.py
`- bar.py
Disons que models / foo.py
et models / bar.py
ont respectivement la classe Foo
et la classe Bar
register
, et main.py
fait colt.build
. ..
Utilisez colt.import_modules ([" <nom du module> ", ...])
dans main.py
comme suit.
main.py
colt.import_modules(["models"])
colt.build(config)
Si vous passez une liste de noms de modules à colt.import_modules
, chaque module et ci-dessous seront importés récursivement.
Dans l'exemple ci-dessus, nous avons passé [" models "]
comme argument, donc tous les modules sous le module models
seront importés et Foo
, Bar
sera disponible.
Lors de la description des arguments positionnels dans les paramètres, spécifiez *
comme clé et passez une liste (ou taple) d'arguments positionnels comme valeur.
@colt.register("foo")
class Foo:
def __init__(self, x, y):
...
config = {"@type": "foo", "*": ["x", "y"]}
Par défaut, colt
construit un objet en passant des arguments de classe à __init__
.
Si vous souhaitez créer un objet à partir d'une méthode autre que __init__
, vous pouvez spécifier:
@colt.register("foo", constructor="build")
class FooWrapper:
@classmethod
def build(cls, *args, **kwargs) -> Foo:
...
C'est pratique lorsque vous souhaitez l'utiliser comme wrapper pour une autre classe.
Les clés spéciales telles que @ type
et * ʻutilisées par
coltpeuvent être modifiées. Par exemple, si vous voulez changer
@ type en
@et
*en
+, spécifiez-le dans
colt.build` comme argument:
colt.build(config, typekey="@", argskey="+")
Si vous souhaitez conserver les paramètres communs, utilisez ColtBuilder
.
builder = colt.ColtBuilder(typekey="@", argskey="+")
builder(config_one)
builder(config_two)
J'ai essayé la compétition Titanic de kaggle en utilisant colt
.
https://github.com/altescy/colt/tree/master/examples/titanic
De la création de fonctionnalités au modèle en utilisant pdpipe
et scikit-learn
La plupart du traitement de l'apprentissage à l'évaluation peut être défini.
Tous les paramètres sont décrits comme Jsonnet ci-dessous configs
. J'espère que cela vous sera utile lors de l'utilisation de colt
.
Nous avons présenté les fonctions et les exemples d'utilisation de colt
.
J'espère que cela vous aidera lors de l'écriture des paramètres.
De plus, la fonctionnalité de colt
est basée sur un excellent framework appelé ʻAllenNLP](https://allennlp.org/). [ʻAllenNLP
regorge d'idées utiles pour de nombreuses tâches d'apprentissage automatique ainsi que pour le traitement du langage naturel, donc si vous êtes intéressé, veuillez l'utiliser.