- Notes de publication
- Prérequis
- Installation
- Démarrage
- Projets
- Jeux de données
- Paquets ML
- Pipelines
- Compétences ML
- Journaux ML
- Document Understanding dans AI Fabric
- Guide de dépannage de base
Construire des paquets ML
Les data scientists créent des modèles pré-entraînés à l’aide de Python ou d’une plate-forme AutoML. Ces modèles sont utilisés par les développeurs RPA dans un workflow.
Tout package doit respecter un petit ensemble d'exigences. Ces exigences sont divisées entre les composants nécessaires pour servir un modèle et les composants nécessaires pour entraîner un modèle.
- Un dossier contenant un fichier main.py à la racine de ce dossier.
- Dans ce fichier, une classe appelée Main implémente au moins deux fonctions :
_init_(self)
: ne prend aucun argument et charge votre modèle et/ou les données locales du modèle (par exemple intégrations de mots).predict(self, input)
: une fonction à appeler au moment du service du modèle.
- Un fichier nommé requirements.txt avec les dépendances nécessaires pour exécuter le modèle.
predict
est utilisée comme point de terminaison du modèle.
Outre l'inférence, un package peut éventuellement être utilisé pour entraîner un modèle d'apprentissage automatique. Cela s'effectue en fournissant les éléments suivants :
- Dans le même dossier racine que le fichier main.py, fournissez un fichier nommé train.py.
- Dans ce fichier, fournissez une classe appelée Main qui implémente au moins deux fonctions : Toutes les fonctions ci-dessous, à l'exception de
_init_
, sont facultatives, mais limitent le type de pipelines pouvant être exécutés avec le package correspondant.-
_init_(self)
: ne prend aucun argument et charge votre modèle et/ou les données du modèle (par exemple intégrations de mots). -
train(self, training_directory)
: prend en tant qu'entrée un répertoire avec des données arbitrairement structurées, et exécute tout le code nécessaire pour entraîner un modèle. Cette fonction est appelée chaque fois qu'un pipeline d'entraînement est exécuté. -
c.
evaluate(self, evaluation_directory)
: prend en tant qu'entrée un répertoire avec des données arbitrairement structurées, exécute tout le code nécessaire pour évaluer un mode, et renvoie un score unique pour cette évaluation. Cette fonction est appelée chaque fois qu'un pipeline d'évaluation est exécuté. -
save(self)
: ne prend aucun argument. Cette fonction est appelée après chaque appel de la fonctiontrain
pour conserver votre modèle. -
process_data(self, input_directory)
: prend une entréeinput_directory
avec des données arbitrairement structurées. Cette fonction n'est appelée que lorsqu'un pipeline complet est exécuté. Dans l'exécution d'un pipeline complet, cette fonction peut effectuer des transformations de données arbitraires et peut fractionner les données. Plus précisément, toutes les données enregistrées dans le chemin indiqué par la variable d'environnementtraining_data_directory
seront l'entrée de la fonctiontrain
, et toutes les données enregistrées dans le chemin indiqué par la variable d'environnementevaluation_data_directory
seront l'entrée de la fonctionevaluation
ci-dessus.
-
Pour faciliter l'utilisation d'AI Fabric dans un workflow RPA, le package peut être défini comme ayant l'un de ces trois types d'entrée : Chaîne, Fichier et Fichiers (défini au moment du téléchargement du package).
json
comme type d'entrée du package.
predict
. Vous trouverez ci-dessous quelques exemples de désérialisation de données en Python :
<h1>Robot sends raw string to ML Skill Activity
# E.g. skill_input='a customer complaint'`
def predict(self, skill_input):
example = skill_input # No extra processing
# Robot sends json formatted string to ML Skill Activity
# E.g skill_input='{'email': a customer complaint', 'date': 'mm:dd:yy'}'
def predict(self, skill_input):
import json
example = json.loads(skill_input)
# Robot sends json formatted string with number array to ML Skill Activity
# E.g. skill_input='[10, 15, 20]'
def predict(self, skill_input):
import json
import numpy as np
example = np.array(json.loads(skill_input))
# Robot sends json formmatted pandas dataframe
# E.g. skill_input='{"row 1":{"col 1":"a","col 2":"b"},
# "row 2":{"col 1":"c","col 2":"d"}}'
def predict(self, skill_input):
import pandas as pd
example = pd.read_json(skill_input)</h1>
<h1>Robot sends raw string to ML Skill Activity
# E.g. skill_input='a customer complaint'`
def predict(self, skill_input):
example = skill_input # No extra processing
# Robot sends json formatted string to ML Skill Activity
# E.g skill_input='{'email': a customer complaint', 'date': 'mm:dd:yy'}'
def predict(self, skill_input):
import json
example = json.loads(skill_input)
# Robot sends json formatted string with number array to ML Skill Activity
# E.g. skill_input='[10, 15, 20]'
def predict(self, skill_input):
import json
import numpy as np
example = np.array(json.loads(skill_input))
# Robot sends json formmatted pandas dataframe
# E.g. skill_input='{"row 1":{"col 1":"a","col 2":"b"},
# "row 2":{"col 1":"c","col 2":"d"}}'
def predict(self, skill_input):
import pandas as pd
example = pd.read_json(skill_input)</h1>
predict
sous la forme d'une chaîne d'octets sérialisée. Ainsi, le RPA Developer peut définir un chemin d'accès vers un fichier, au lieu d'avoir à lire et à sérialiser le fichier dans le workflow même.
predict
. La désérialisation des données se fait également dans la fonction predict
, le cas général consistant simplement à lire les octets directement dans un objet de type fichier tel que ci-dessous :
<h1>ML Package has been uploaded with <em>file</em> as input type. The ML Skill Activity
# expects a file path. Any file type can be passed as input and it will be serialized.
def predict(self, skill_input):
import io
file_like = io.BytesIO(skill_input)</h1>
<h1>ML Package has been uploaded with <em>file</em> as input type. The ML Skill Activity
# expects a file path. Any file type can be passed as input and it will be serialized.
def predict(self, skill_input):
import io
file_like = io.BytesIO(skill_input)</h1>
Lire les octets sérialisés comme ci-dessus équivaut à ouvrir un fichier en activant l'indicateur de lecture binaire. Pour tester le modèle localement, lisez un fichier en tant que fichier binaire. Voici un exemple de lecture d'un fichier image et de test local de ce fichier :
<h1>main.py where model input is an image
class Main(object):
...
def predict(self, skill_input):
import io
from PIL import Image
image = Image.open(io.BytesIO(skill_input))
...
if__name__ == '<strong>main</strong>':
# Test the ML Package locally
with open('./image-to-test-locally.png', 'rb') as input_file:
file_bytes = input_file.read()
m = Main()
print(m.predict(file bytes))</h1>
<h1>main.py where model input is an image
class Main(object):
...
def predict(self, skill_input):
import io
from PIL import Image
image = Image.open(io.BytesIO(skill_input))
...
if__name__ == '<strong>main</strong>':
# Test the ML Package locally
with open('./image-to-test-locally.png', 'rb') as input_file:
file_bytes = input_file.read()
m = Main()
print(m.predict(file bytes))</h1>
csv
et d'utilisation d'un cadre de données pandas dans la fonction predict
:
<h1>main.py where model input is a csv file
class Main(object):
...
def predict(self, skill_input):
import pandas as pd
data frame = pd.read_csv(io.BytesIO(skill_input))
...
if name == '<strong>main</strong>':
# Test the ML Package locally
with open('./csv—to—test—locally.csv', 'rb') as input_file:
bytes = input_file.read()
m = Main()
print(m.predict(bytes))</h1>
<h1>main.py where model input is a csv file
class Main(object):
...
def predict(self, skill_input):
import pandas as pd
data frame = pd.read_csv(io.BytesIO(skill_input))
...
if name == '<strong>main</strong>':
# Test the ML Package locally
with open('./csv—to—test—locally.csv', 'rb') as input_file:
bytes = input_file.read()
m = Main()
print(m.predict(bytes))</h1>
predict
.
Une liste de fichiers peut être envoyée à une compétence. Dans le workflow, l'entrée de l'activité est une chaîne avec des chemins d'accès aux fichiers séparés par une virgule.
predict
est une liste d'octets dans laquelle chaque élément est la chaîne d'octets du fichier.
train.py
, tout pipeline exécuté peut conserver des données arbitraires appelées sortie de pipeline. Toutes les données écrites dans le chemin du répertoire à partir d'artefacts de variables d'environnement sont conservées et peuvent être affichées à tout moment en accédant à la Page Détails du Pipeline. En règle générale, tout type de graphique, toute statistique des tâches d'entraînement/évaluation peut être enregistré dans le répertoireartifacts
et est accessible depuis l'interface utilisateur à la fin de l'exécution du pipeline.
<h1>train.py where some historical plot are saved in ./artifacts directory during Full Pipeline execution
# Full pipeline (using process_data) will automatically split data.csv in 2/3 train.csv (which will be in the directory passed to the train function) and 1/3 test.csv
import pandas as pd
from sklearn.model_selection import train_test_split
class Main(object):
...
def process_data(self, data_directory):
d = pd.read_csv(os.path.join(data_directory, 'data.csv'))
d = self.clean_data(d)
d_train, d_test = train_test_split(d, test_size=0.33, random_state=42)
d_train.to_csv(os.path.join(data_directory , 'training', 'train.csv'), index=False)
d_test.to_csv (os.path.join(data__directory , 'test' , 'test.csv'), index=False)
self.save_artifacts(d_train, 'train_hist.png', os.environ["artifacts"])
self.save_artifacts(d_test, 'test_hist.png', os.environ["artifacts"])
...
def save_artifacts(self, data, file_name, artifact_directory):
plot = data.hist()
fig = plot[0][0].get_figure()
fig.savefig(os.path.join(artifact_directory, file_name))
...</h1>
<h1>train.py where some historical plot are saved in ./artifacts directory during Full Pipeline execution
# Full pipeline (using process_data) will automatically split data.csv in 2/3 train.csv (which will be in the directory passed to the train function) and 1/3 test.csv
import pandas as pd
from sklearn.model_selection import train_test_split
class Main(object):
...
def process_data(self, data_directory):
d = pd.read_csv(os.path.join(data_directory, 'data.csv'))
d = self.clean_data(d)
d_train, d_test = train_test_split(d, test_size=0.33, random_state=42)
d_train.to_csv(os.path.join(data_directory , 'training', 'train.csv'), index=False)
d_test.to_csv (os.path.join(data__directory , 'test' , 'test.csv'), index=False)
self.save_artifacts(d_train, 'train_hist.png', os.environ["artifacts"])
self.save_artifacts(d_test, 'test_hist.png', os.environ["artifacts"])
...
def save_artifacts(self, data, file_name, artifact_directory):
plot = data.hist()
fig = plot[0][0].get_figure()
fig.savefig(os.path.join(artifact_directory, file_name))
...</h1>
Lors du développement du modèle, le graphique TensorFlow doit être chargé sur le même thread que celui utilisé pour le service. Pour ce faire, le graphique par défaut doit être utilisé.
Voici un exemple incorporant les modifications nécessaires :
import tensorflow as tf
class Main(object):
def <strong>init</strong>(self):
self.graph = tf.get_default_graph() # Add this line
...
def predict(self, skill_input):
with self.graph.as_default():
...
import tensorflow as tf
class Main(object):
def <strong>init</strong>(self):
self.graph = tf.get_default_graph() # Add this line
...
def predict(self, skill_input):
with self.graph.as_default():
...
Lorsque le GPU est activé au moment de la création de la compétence, il est déployé sur une image avec le pilote NVIDIA GPU 418, CUDA Toolkit 10.0 et la bibliothèque d'exécution CUDA Deep Neural Network Library (cuDNN) 7.6.5.
IrisClassifier.sav
qui sera servi.
-
Arborescence initiale du projet (sans main.py et requirements.txt) :
IrisClassifier/ - IrisClassifier.sav
IrisClassifier/ - IrisClassifier.sav -
Exemple de main.py à ajouter au dossier racine :
from sklearn.externals import joblib import json class Main(object): def <strong>init</strong>(self): self.model = joblib.load('IrisClassifier.sav') def predict(self, X): X = json.loads(X) result = self.model.predict_proba(X) return json.dumps(result.tolist())
from sklearn.externals import joblib import json class Main(object): def <strong>init</strong>(self): self.model = joblib.load('IrisClassifier.sav') def predict(self, X): X = json.loads(X) result = self.model.predict_proba(X) return json.dumps(result.tolist()) -
Ajouter requirements.txt :
scikit-learn==0.19.0
scikit-learn==0.19.0
itsdangerous<2.1.0
Jinja2<3.0.5
Werkzeug<2.1.0
click<8.0.0
itsdangerous<2.1.0
Jinja2<3.0.5
Werkzeug<2.1.0
click<8.0.0
Pour tester cela, vous pouvez utiliser la commande suivante dans un nouvel environnement et vous assurer que toutes les bibliothèques s'installent correctement :
pip install -r requirements.txt -c constraints.txt
pip install -r requirements.txt -c constraints.txt
4. Structure finale des dossiers :
IrisClassifier/
- IrisClassifier.sav
- main.py
- requirements.txt
IrisClassifier/
- IrisClassifier.sav
- main.py
- requirements.txt
Dans cet exemple, le problème métier nécessite un réentraînement du modèle. En s'appuyant sur le package décrit ci-dessus, vous pouvez disposer des éléments suivants :
-
Arborescence du projet initial (package de service uniquement) :
IrisClassifier/ - IrisClassifier.sav - main.py - requirements.txt
IrisClassifier/ - IrisClassifier.sav - main.py - requirements.txt -
Exemple de train.py à ajouter au dossier racine :
import pandas as pd import joblib class Main(object): def <strong>init</strong>(self): self.model_path = './IrisClassifier.sav' self.model = joblib.load(self.model_path) def train(self, training_directory): (X,y) = self.load_data(os.path.join(training_directory, 'train.csv')) self.model.fit(X,y) def evaluate(self, evaluation_directory): (X,y) = self.load_data(os.path.join(evaluation_directory, 'evaluate.csv')) return self.model.score(X,y) def save(self): joblib.dump(self.model, self.model_path) def load_data(self, path): # The last column in csv file is the target column for prediction. df = pd.read_csv(path) X = df.iloc[:, :-1].get_values() y = df.iloc[:, 'y'].get_values() return X,y
import pandas as pd import joblib class Main(object): def <strong>init</strong>(self): self.model_path = './IrisClassifier.sav' self.model = joblib.load(self.model_path) def train(self, training_directory): (X,y) = self.load_data(os.path.join(training_directory, 'train.csv')) self.model.fit(X,y) def evaluate(self, evaluation_directory): (X,y) = self.load_data(os.path.join(evaluation_directory, 'evaluate.csv')) return self.model.score(X,y) def save(self): joblib.dump(self.model, self.model_path) def load_data(self, path): # The last column in csv file is the target column for prediction. df = pd.read_csv(path) X = df.iloc[:, :-1].get_values() y = df.iloc[:, 'y'].get_values() return X,y -
Modifiez le fichier requirements.txt si nécessaire :
pandas==1.0.1 scikit-learn==0.19.0
pandas==1.0.1 scikit-learn==0.19.0 -
Structure du dossier final (package) :
IrisClassifier/ - IrisClassifier.sav - main.py - requirements.txt - train.py
IrisClassifier/ - IrisClassifier.sav - main.py - requirements.txt - train.pyRemarque : ce modèle peut désormais être servi en premier et, à mesure que de nouveaux points de données entrent dans le système via Robot ou Human-in-the-Loop, des pipelines d'entraînement et d'évaluation peuvent être créés grâce à train.py.
- Structurer les paquets ML
- Composant de service
- Composant d'entraînement et d'évaluation
- Gérer les types de données
- Données de la chaîne
- Données du fichier
- Données du fichier
- Données arbitraires persistantes
- Utilisation de TensorFlow
- Informations sur l'utilisation du GPU
- Exemples
- Modèle de ML simple et prêt à l'emploi sans entraînement
- Modèle simple et prêt à l'emploi avec entraînement activé