# Construcción de modelos para TF2
[TOC]
El proceso de entrenamiento de un modelo de ML utilizando la librería Keras provista por Tensorflow está basado en las clases:
- **TFKerasModel**
- **TFKerasTrainerConfig**
- **TFKerasTrainer**
El ejemplo completo de implementación puede encontrarse en [News example](LINK).
## Model
**Define la arquitectura del modelo a ser construido.**
Todo modelo a ser administrado dentro del API CONABIO ML debe cumplir los siguientes lineamientos:
1. Deben ser subclase de [TFKerasModel](LINK). Lo que implica la obligatoria implementación de la función `create_model` y opcionalmente (si se desea un manejo interno especial) de `create` teniendo cuidado de enlazar a su clase padre.
```python
class ModelName(TFKerasModel):
@classmethod
def create(cls: TFKerasModel.ModelType,
model_config: {
}, **kwargs) -> TFKerasModel.ModelType:
[ OPTIONAL HANDLING ]
return cls(model=model_name,
model_config=model_config)
@classmethod
def create_model(cls, model_config):
MANDATORY
[ . . . ]
```
2. El modelo puede utilizar libremente todos tipos definidos en [tf.keras](https://www.tensorflow.org/api_docs/python/tf/keras), inclusive los módulos en [TFHub](https://www.tensorflow.org/hub). Sin embargo, la funcion `create_model` debe regresar este modelo.
```python
@classmethod
def create_model(cls, model_config):
[ model building ]
return model
```
3. Para un manejo modular y un reporte adecuado del modelo se aconseja que TODAS las opciones de configuración sean definidas en el parámetro model_config al momento de su creación.
```python
model = ModelName({
"model_name": {
"layer":{
"embedding_layer": {[ url, type, ... ]},
"dense_layer":{[units, activation, ... ]}
}
}
})
```
### Pipeline
Para defininir un modelo del tipo TFKerasModel en un pipeline se debe agregar un proceso apuntando a la función de clase `create` del modelo a construir y definir la configuración del modelo. Como se muestra:
```python
[ . . . ]
.add_process(name="create_NNLM_Classifier",
action=NNLM_Classifier.create,
args={
"model_config": {
[ . . . ]
}
})
[ . . . ]
```
### Implementación
La implementación completa necesaria para construir un modelo en TFKeras y administrarlo por medio del pipeline se muestra a continuación:
**Pipeline**
```python
pipeline = Pipeline()\
[. . . ]
.add_process(name="create_NNLM_Classifier",
action=NNLM_Classifier.create,
args={
"model_config": {
"NNLM_Classifier": {
"layers": {
"embedding_layer": {
"url": "https://tfhub.dev/google/nnlm-en-dim128-with-normalization/2"
},
"dense_layer_0":{
"activation": "relu",
"units": 50
},
"dense_layer_1":{
"activation": "sigmoid",
"units": 20
},
}
}
}
})
```
**Model definition**
```python
class NNLM_Classifier(TFKerasModel):
@classmethod
def create_model(cls, model_config):
hub_layer = tf_hub.KerasLayer(model_config["embedding_layer"]["url"],
input_shape=model_config["input_shape"],
dtype=tf.string)
model = tf.keras.Sequential()
model.add(hub_layer)
model.add(tf.keras.layers.Dense(
model_config["dense_layer_0"]["units"],
activation=model_config["dense_layer_0"]["activation"]))
model.add(tf.keras.layers.Dense(
model_config["dense_layer_0"]["units"],
activation=activation=model_config["dense_layer_0"]["activation"]))
return model
```
## Trainerconfig
**Define el ambiente de ejecución, así como las variables de control para el entrenamiento del modelo.**
Para crear un ambiente de ejecución se debe utilizar la clase [TFTrainerConfig](LINK) por medio del método `create`, cuya firma es:
```python
class TFKerasTrainerConfig(CBTrainerConfig):
@classmethod
def create(cls: CBTrainerConfig.TrainerConfigType,
config: dict = {
[ . . . ]
}) -> CBTrainerConfig.TrainerConfigType:
[ . . . ]
```
Como se muestra:
```python
trainer_config = TFKerasTrainerConfig.create(config={
'callbacks':{},
'strategy':{}
})
```
Existen 2 variables de control a aplicarse en un modelo a ser entrenado: los reportes de evolución del modelo y la estrategia en la que el modelo se entrenará.
### Reportes de evolución (Callbacks)
Las variables de reporte están basadas en los [callbacks de ejecución de tf.Keras](https://www.tensorflow.org/api_docs/python/tf/keras/callbacks).
Se definen en el parámetro `callbacks` en el diccionario de configuración `config`.
Se deben deben configurar las variables de interés de cada reporte a realizarse. Se muestran los valores por defecto de los callbacks definidos:
`checkpoint`
Basado en [ModelCheckpoint](https://www.tensorflow.org/api_docs/python/tf/keras/callbacks/ModelCheckpoint). Guarda el modelo de acuerdo a criterios establecidos.
```python
CHECKPOINT_CALLBACK: {
'filepath': {
'type': str,
'optional': False
},
'monitor': {
'type': str,
'default': 'val_loss'
},
'verbose': {
'type': int,
'default': 1
},
'save_best_only': {
'type': bool,
'default': True
},
'save_weights_only': {
'type': bool,
'default': False
},
'mode': {
'type': str,
'default': 'auto'
},
'save_freq': {
'type': str,
'default': "epoch"
}
}
```
`tensorboard`
Basado en [Tersorboard](https://www.tensorflow.org/api_docs/python/tf/keras/callbacks/TensorBoard). Reporta a Tensorboard el estado del modelo.
```python
TENSORBOARD_CALLBACK: {
'log_dir': {
'type': str,
'optional': False
},
'histogram_freq': {
'type': int,
'default': 0
},
'profile_batch': {
'type': int,
'default': 2
},
'write_graph': {
'type': bool,
'default': True
},
'write_images': {
'type': bool,
'default': False
},
'embeddings_freq': {
'type': int,
'default': 0
},
'update_freq': {
'type': str,
'default': 'epoch'
}
}
```
`learningrate_scheduler`
Basado en [LearningRateScheduler](https://www.tensorflow.org/api_docs/python/tf/keras/callbacks/LearningRateScheduler). Define la función de control de learning rate.
```python
LR_CALLBACK: {
'verbose': {
'type': int,
'default': 1
},
'scheduler':{
'type': Callable,
'optional': False
}
}
```
### Estrategia de entrenamiento.
Administra la manera en la que el entrenamiento se realizará, está basada en las [estrategias de entrenamiento](https://www.tensorflow.org/guide/distributed_training) de TF.
Se definen en el parámetro `strategy` en el diccionario de configuración `config`.
`mirrored_strategy`
La estategia [mirroredstrategy](https://www.tensorflow.org/guide/distributed_training#mirroredstrategy) esta disponible y se debendefinir los dispositivos a utilizar en la estrategia, en caso de `None` todos los dispositivos disponibles serán utilizados.
```python
MIRROREDSTRATEGY: {
'devices': {
'type': list,
'default': None
}
}
```
### Pipeline
Para administrar un modelo en el ambiente de ejecución TFKerasTrainerConfig por medio del pipeline solo es necesario configurar el proceso relacionado apuntando a la función de clase `create`. Como se muestra a continuación:
```python
.add_process(name="tfkeras_trainer_cfg",
action=TFKerasTrainerConfig.create,
args={
"config": {
"callbacks": {
CHECKPOINT_CALLBACK: {
"filepath": os.path.join(results_path, "checkpoints"),
"save_best_only": True
},
TENSORBOARD_CALLBACK: {
"log_dir": os.path.join(results_path, "tb_logs")
}
},
'strategy':{
MIRROREDSTRATEGY: {
"devices": ["GPU:0"]
}
}
}
})
```
## Trainer
**Utilizando un ambiente de ejecución (TFTrainerConfig) se entrena un modelo (TFKerasModel) con un dataset del tipo [Dataset](LINK).**
Para entrenar un modelo del API CONABIO-ML se debe utilizar un entrenador *(trainer)*. Para modelos basados en `tf.keras` que sean subclase de `TFKerasModel` se utiliza la clase [TFKerasTrainer](LINK) que hereda de la clase [Trainer](LINK) por medio de su método de clase `train`, que a continuación se describe:
```python
class TFKerasTrainer(Trainer):
@classmethod
def train(cls,
dataset: Dataset.DatasetType,
model: TFKerasModel.ModelType,
execution_config: TrainerConfig.TrainerConfigType,
train_config: dict = {}) -> Model.ModelType:
[ . . . ]
```
### Recursos necesarios
Para entrenar un modelo los siguientes recursos son necesarios:
1. **dataset.** Debe ser del tipo [Dataset](LINK) y tener definidos por lo menos los fields `item` y `label`. El entrenamiento se realiza sobre las particiones `train` y se utiliza la particion `validation` (opcionalmente), para control de evolución. Si el dataset *no está particionado** se utiliza completamente como partición `train`.
2. **model.** Debe ser del tipo [TFKerasModel](LINK) con el método `create_model` definido. Véase [TFKerasModel](https://hackmd.io/h9FjIdt-Sz6dW54pWd6T0w#Model).
3. **execution_config**. Debe ser del tipo [TFTrainerConfig](LINK). Véase [TFTrainerConfig](https://hackmd.io/h9FjIdt-Sz6dW54pWd6T0w#Trainerconfig).
### Configuración de entrenamiento
Adicionalmente, se tiene que indicar la configuración del experimento a realizar. Esto se realiza por medio del diccionario de configuración `train_config`.
```python
'train_config': {
[model_name]: {
'optimizer': {
[optimizer_name]: {
'learning_rate': {
'constant': {
[learning_rate_config]
}
}
}
},
'loss': {
[loss_name]: { [loss_config] }
},
'epochs': int,
"metrics": [metrics],
'batch_size': int
},
'dataset_handling': {
"item_type": tf.DType,
"label_type": tf.DType,
"labels_as_categorical": {
"labelset": [labels]
}
}
}
```
**model_name**: Indica la configuración del modelo. El nombre debe coincidir con el modelo definido (Véase [definición de modelo](https://hackmd.io/h9FjIdt-Sz6dW54pWd6T0w#Model)). Los parámetros a definir son:
1. **optimizer**: Optimizador a utilizarse. Véase [Optimizadores disponibles](LINK)
- **learning_rate**: Learning rate aplicado al optimizador. Véase [Configuración de learning rate](LINK)
2. **loss**: Función de pérdida. Véase [Funciones de pérdida disponibles](LINK)
3. **epochs**. Épocas de entrenamiento.
4. **metrics**: Métricas a calcular. Véase [Métricas disponibles](LINK)
5. **batch_size**. Tamaño de batch de entrenamiento.
**dataset_handling**: Indica los parámetros de manejo del dataset a la hora de ser manejado por el entrenador.
1. **item_type**: Tipo de dato esperado para el campo `item` del dataset.
2. **label_type**: Tipo de dato esperado para el campo `label` del dataset.
3. **labels_as_categorical**: Si el campo `label` no es un entero, se debe indicar su tratamiento como tal.
- **labelset**: (Opcional) Lista de clases disponibles en el campo `label`. Si se indica `None`, se intentarán deducir los valores posibles de la partición `train`.
Se presenta un ejemplo de la implementación de un entrenado TFKerasTrainer:
```python
dataset = Dataset.from_[TYPE]
model = ModelName({"model_name": { [model_config] } })
trainer_config = TFKerasTrainerConfig.create(config={ [trainer_config] })
train_config = { [ train_config ] }
model_trained = TFKerasTrainer.train(dataset,
model,
trainer_config,
train_config)
```
### Pipeline
Para entrenar un modelo utilizando el entrenador TFKerasTrainer por medio del pipeline se debe utilizar el método de clase `train` utilizando los recursos descritos. Como se muestra a continuación:
```python
[ . . . ]
.add_process(name="tfkeras_trainer_cfg", action=TFKerasTrainerConfig.create, [ . . . ] )
.add_process(name="from_folder_news", action=Dataset.from_folder, [ . . . ] )
.add_process(name="create_NNLM_Classifier", action=NNLM_Classifier.create, [ . . . ] )
.add_process(name="train_NNLM_CLassifier",
action=TFKerasTrainer.train,
inputs_from_processes=["from_folder_news",
"create_NNLM_Classifier",
"tfkeras_trainer_cfg"],
reportable=True,
args={
'train_config': {
'NNLM_Classifier': {
'optimizer': {
'adam': {
'learning_rate': {
'constant': {
'learning_rate': 0.001,
}
}
}
},
'loss': {
'categorical_crossentropy': {}
},
'epochs': 2,
"metrics": ["accuracy"],
'batch_size': 64
},
'dataset_handling': {
"item_type": tf.string,
"label_type": tf.int64,
"labels_as_categorical": {
"labelset": ['talk.politics.mideast',
[ . . . ]
]
}
}
}
})
[ . . . ]
```
## Diagrama
Esquemáticamente el funcionamiento de este proceso se muestra en la figura siguiente:
