- Notas relacionadas
- Antes de empezar
- Primeros pasos
- Proyectos
- Conjuntos de datos
- Paquetes ML
- Procesos
- Habilidades ML
- Logs de ML
- Document Understanding en AI Center
- Tutorial
- Guía básica de resolución de problemas
Creación de paquetes ML
Los científicos de datos construyen modelos preentrenados utilizando Python o utilizando una plataforma AutoML. Los desarrolladores de RPA son los que consumirán estos modelos dentro de un flujo de trabajo.
Un paquete debe cumplir con un pequeño conjunto de requisitos. Estos requisitos se dividen entre los componentes necesarios para servir un modelo y los componentes necesarios para entrenar un modelo.
- Una carpeta que contenga un archivo main.py en la raíz de esa carpeta.
- En este archivo, una clase llamada Main que implemente al menos dos funciones:
__init__(self)
: no tiene argumento y carga tu modelo y los datos locales para el modelo (por ejemplo, inserción de palabras).predict(self, input)
: una función a la que se llamará en el momento del servicio del modelo y que devuelve una cadena.
- Un archivo llamado requirements.txt con dependencias necesarias para ejecutar el modelo.
predict
se utiliza como punto de conexión del modelo.
- En la misma carpeta raíz, con el archivo main.py, establece un archivo llamado train.py.
- En este archivo, establece una clase llamada Main que implemente al menos cuatro funciones. Todas las siguientes funciones excepto
__init__
, son opcionales, pero limitan el tipo de procesos que pueden ejecutarse con el paquete correspondiente.__init__(self)
: no tiene argumento y carga tu modelo y los datos para el modelo (por ejemplo, inserción de palabras).train(self, training_directory)
: toma como input un directorio con datos estructurados de forma arbitraria; ejecuta todo el código necesario para entrenar un modelo. Esta función se llama cuando se ejecuta un proceso de entrenamiento.evaluate(self, evaluation_directory)
: toma como input un directorio con datos estructurados de forma arbitraria; ejecuta todo el código necesario para evaluar un modo y devuelve una única puntuación para esa evaluación. Esta función se llama cuando se ejecuta un proceso de evaluación.save(self)
: no tiene argumento. Esta función se llama después de cada llamada de la funcióntrain
para mantener tu modelo.process_data(self, input_directory)
: toma un inputinput_directory
con datos estructurados de forma arbitraria. Esta función solo se llama cuando se ejecuta un proceso completo. En la ejecución de un proceso completo, esta función puede realizar transformaciones de datos arbitrarias y puede dividir datos. En concreto, cualquier dato guardado en la ruta a la que apunta la variable de entornotraining_data_directory
es el input a la funcióntrain
, y cualquier dato guardado en la ruta a la que apunta la variable de entornoevaluation_data_directory
es el input a la funciónevaluation
anterior.
Para hacer que AI Center sea más fácil de usar en un flujo de trabajo de RPA, el paquete puede disponer de uno de los tres tipos de input: String, File y Files (establecido durante el tiempo de carga del paquete).
json
como tipo de input del paquete.
predict
. A continuación se muestran varios ejemplos útiles para deserializar los datos en Python:
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)
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)
predict
como una cadena de bytes serializada. Así, el desarrollador de RPA puede pasar una ruta a un archivo, en lugar de tener que leer y serializar el archivo en el propio flujo de trabajo.
predict
. La deserialización de los datos también se realiza en la función predict
: el caso general es simplemente leer los bytes directamente en un objeto similar a un archivo de la siguiente manera:
ML Package has been uploaded with *file* 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)
ML Package has been uploaded with *file* 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)
La lectura de los bytes serializados como se ve anteriormente es equivalente a abrir un archivo con la marca binaria de lectura activada. Para probar el modelo localmente, lee un archivo como archivo binario. A continuación, se muestra un ejemplo de lectura de un archivo de imagen y su prueba de forma local:
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__ == '_main_':
# 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))
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__ == '_main_':
# 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))
csv
y la utilización de una trama de datos Pandas en la función predict
:
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 == '_main_':
# 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))
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 == '_main_':
# 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))
predict
.
Puede enviarse una lista de archivos a una habilidad. Dentro del flujo de trabajo, el input a la actividad es una cadena con rutas a los archivos, separadas por una coma.
predict
es una lista de bytes en los que cada elemento de la lista es la cadena de bytes del archivo.
train.py
, cualquier proceso ejecutado puede generar datos arbitrarios, llamados output del proceso. Cualquier dato que se escriba en la ruta del directorio desde los artefactos de la variable de entorno persiste y puede emerger en cualquier momento yendo a la página Detalles del proceso. Normalmente, cualquier tipo de gráfico, estadísticas de los trabajos de entrenamiento/evaluación, puede guardarse en el directorio artifacts
y se puede acceder a ello desde la IU al final de la ejecución del proceso.
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))
...
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))
...
Durante el desarrollo del modelo, el gráfico de TensorFlow debe cargarse en el mismo hilo que se utilizó para el servicio. Para ello, debe utilizarse el gráfico predeterminado.
A continuación se muestra un ejemplo con las modificaciones necesarias:
import tensorflow as tf
class Main(object):
def __init__(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 __init__(self):
self.graph = tf.get_default_graph() # Add this line
...
def predict(self, skill_input):
with self.graph.as_default():
...
Cuando la GPU se habilita en el momento de la creación de la habilidad, se implementa en una imagen con el controlador de GPU NVIDIA 418, CUDA Toolkit 10.0 y la biblioteca de runtime CUDA Deep Neural Network Library (cuDNN) 7.6.5.
IrisClassifier.sav
serializado que se servirá.
- Árbol de proyecto inicial (sin main.py y requirements.txt):
IrisClassifier/ - IrisClassifier.sav
IrisClassifier/ - IrisClassifier.sav - main.py de muestra que se añadirá a la carpeta raíz:
from sklearn.externals import joblib import json class Main(object): def __init__(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 __init__(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()) - Añade requirements.txt:
scikit-learn==0.19.0
scikit-learn==0.19.0Nota: Hay algunas restricciones que deben respetarse en las bibliotecas pip. Asegúrate de que puedes instalar bibliotecas bajo los siguientes archivos de restricción:Para comprobarlo, puedes utilizar el siguiente comando en un entorno nuevo y asegurarte de que todas las bibliotecas están correctamente instaladas: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.0pip install -r requirements.txt -c constraints.txt
pip install -r requirements.txt -c constraints.txt - Estructura de carpeta final:
IrisClassifier/ - IrisClassifier.sav - main.py - requirements.txt
IrisClassifier/ - IrisClassifier.sav - main.py - requirements.txt
En este ejemplo, el problema de la empresa requiere que el modelo se reentrene. Al desarrollar sobre el paquete descrito anteriormente, es posible que experimentes lo siguiente:
- Árbol de proyecto inicial (paquete solo de servicio):
IrisClassifier/ - IrisClassifier.sav - main.py - requirements.txt
IrisClassifier/ - IrisClassifier.sav - main.py - requirements.txt - train.py de muestra para añadir a la carpeta raíz:
import pandas as pd import joblib class Main(object): def __init__(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 __init__(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 - Edita requirements.txt si es necesario:
pandas==1.0.1 scikit-learn==0.19.0
pandas==1.0.1 scikit-learn==0.19.0 - Estructura de carpeta final (paquete):
IrisClassifier/ - IrisClassifier.sav - main.py - requirements.txt - train.py
IrisClassifier/ - IrisClassifier.sav - main.py - requirements.txt - train.pyAviso: Este modelo ahora puede servirse primero y, conforme van entrando al sistema nuevos puntos de datos a través del UiPath Robot o "persona en el ciclo", los procesos de entrenamiento y de evaluación pueden crearse aprovechando train.py.
- Estructurar paquetes ML
- Servicio de componentes
- Componente de entrenamiento y evaluación
- Gestión de tipos de datos
- Datos de String
- Datos de File
- Datos de Files
- Datos arbitrarios persistentes
- Utilizando TensorFlow
- Información sobre el uso de la GPU
- Ejemplos
- Modelo ML simple listo para servir sin entrenamiento
- Modelo sencillo listo para servir con entrenamiento habilitado