

Las traducciones son generadas a través de traducción automática. En caso de conflicto entre la traducción y la version original de inglés, prevalecerá la version en inglés.

# Paso 1: modifique su propio script de entrenamiento utilizando SageMaker la biblioteca paralela de modelos distribuidos
<a name="model-parallel-customize-training-script"></a>

Utilice esta sección para aprender a personalizar su guion de entrenamiento para utilizar las funciones principales de la biblioteca de paralelismo de modelos de SageMaker IA de Amazon. Para utilizar las funciones y los parámetros de la API específicos de la biblioteca, le recomendamos que utilice esta documentación junto con la [biblioteca de modelos SageMaker paralelos](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smd_model_parallel.html) de la documentación APIs del SDK de *SageMaker Python*.

Los ejemplos de scripts de entrenamiento proporcionados en estas secciones están simplificados y diseñados para resaltar los cambios necesarios que debe realizar para utilizar la biblioteca. Para ver end-to-end ejemplos de cuadernos ejecutables que muestran cómo utilizar un script TensorFlow o un script de PyTorch entrenamiento con la biblioteca de paralelismo de SageMaker modelos, consulte. [Ejemplos de la biblioteca de paralelismo de modelos Amazon SageMaker AI v2](distributed-model-parallel-v2-examples.md)

**Topics**
+ [Divida el modelo de su guion de entrenamiento mediante la biblioteca de modelos de paralelismo SageMaker](#model-parallel-model-splitting-using-smp-lib)
+ [Modifica un script de entrenamiento TensorFlow](model-parallel-customize-training-script-tf.md)
+ [Modifique un guion PyTorch de entrenamiento](model-parallel-customize-training-script-pt.md)

## Divida el modelo de su guion de entrenamiento mediante la biblioteca de modelos de paralelismo SageMaker
<a name="model-parallel-model-splitting-using-smp-lib"></a>

Existen dos formas de modificar el script de entrenamiento para configurar la división del modelo: la división automática o la división manual.

### División automatizada de modelos
<a name="model-parallel-automated-model-splitting"></a>

*Al utilizar SageMaker la biblioteca de paralelismo de modelos, puede aprovechar la división *automática de modelos, también conocida como partición automática de modelos*.* La biblioteca utiliza un algoritmo de partición que equilibra la memoria, minimiza la comunicación entre dispositivos y optimiza el rendimiento. Puede configurar el algoritmo de partición automatizado para optimizar la velocidad o la memoria. 

Alternativamente, puede utilizar la división manual de modelos. Recomendamos la división automática de modelos, a menos que esté muy familiarizado con la arquitectura del modelo y tenga una buena idea de cómo particionar su modelo de manera eficiente.

#### Funcionamiento
<a name="model-parallel-automated-model-splitting-how-it-works"></a>

La partición automática se produce durante el primer paso de entrenamiento, cuando la función decorada por `smp.step` se llama por primera vez. Durante esta llamada, la biblioteca construye primero una versión del modelo en la RAM de la CPU (para evitar limitaciones de memoria de la GPU) y, a continuación, analiza el gráfico del modelo y toma una decisión de partición. En base a esta decisión, cada partición de modelo se carga en una GPU y solo entonces se ejecuta el primer paso. Debido a estos pasos de análisis y partición, el primer paso de entrenamiento podría llevar más tiempo. 

En cualquiera de los dos marcos, la biblioteca gestiona la comunicación entre los dispositivos a través de su propio backend, que está optimizado para la infraestructura. AWS 

El diseño de partición automática se adapta a las características del marco y la biblioteca realiza la partición a un nivel de granularidad más natural en cada marco. Por ejemplo TensorFlow, en cada operación específica se puede asignar a un dispositivo diferente, mientras que en PyTorch, la asignación se realiza a nivel de módulo, donde cada módulo consta de múltiples operaciones. En la siguiente sección se revisan los detalles del diseño en cada marco.

##### División automática del modelo con PyTorch
<a name="model-parallel-auto-model-split-pt"></a>

Durante el primer paso de entrenamiento, la biblioteca de paralelismo de modelos ejecuta internamente un paso de trazado destinado a construir el gráfico del modelo y determinar las formas de los tensores y parámetros. Tras este paso de rastreo, la biblioteca construye un árbol, que consiste en el anidado de objetos `nn.Module` del modelo, así como datos adicionales recopilados a partir del rastreo, como la cantidad de `nn.Parameters` almacenados, y tiempo de ejecución para cada `nn.Module`. 

A continuación, la biblioteca atraviesa este árbol desde la raíz y ejecuta un algoritmo de partición que asigna a cada `nn.Module` a un dispositivo que equilibra la carga computacional (medida por el tiempo de ejecución del módulo) y el uso de la memoria (medida por el total tamaño y activaciones de `nn.Parameter` totales almacenadas). Si múltiples `nn.Modules` comparten el mismo `nn.Parameter`, estos módulos se colocan en el mismo dispositivo para evitar mantener varias versiones del mismo parámetro. Una vez tomada la decisión de particionar, los módulos y pesos asignados se cargan en sus dispositivos.

Para obtener instrucciones sobre cómo registrar al `smp.step` decorador en su guion de PyTorch formación, consulte. [División automática con PyTorch](model-parallel-customize-training-script-pt.md#model-parallel-customize-training-script-pt-16)

##### División automática de modelos con TensorFlow
<a name="model-parallel-auto-model-split-tf"></a>

La biblioteca de paralelismo de modelos analiza los tamaños de las variables que pueden entrenarse y la estructura del gráfico, y utiliza internamente un algoritmo de partición de gráficos. Este algoritmo presenta una asignación de dispositivos para cada operación, con el objetivo de minimizar la cantidad de comunicación necesaria entre los dispositivos, sujeto a dos restricciones: 
+ Equilibrio del número de variables almacenadas en cada dispositivo
+ Equilibrio del número de operaciones ejecutadas en cada dispositivo

Si especifica `speed` en `optimize` (en los parámetros paralelos del modelo en el Python SDK), la biblioteca intenta equilibrar el número de operaciones y objetos `tf.Variable` de cada dispositivo. De lo contrario, intenta equilibrar el tamaño total de `tf.Variables`.

Una vez tomada la decisión de particionar, la biblioteca crea una representación serializada del subgráfico que cada dispositivo necesita ejecutar e importa en cada dispositivo. Durante la partición, la biblioteca coloca operaciones que consumen el mismo `tf.Variable` y operaciones que forman parte de la misma capa de Keras en el mismo dispositivo. También respeta las restricciones de colocación impuestas por. TensorFlow Esto significa que, por ejemplo, si hay dos capas Keras que comparten un `tf.Variable`, todas las operaciones que forman parte de estas capas se colocan en un solo dispositivo.

Para obtener instrucciones sobre cómo inscribir al `smp.step` decorador en su guion de PyTorch formación, consulte. [División automática con TensorFlow](model-parallel-customize-training-script-tf.md#model-parallel-customize-training-script-tf-23)

##### Comparación del modelo automatizado dividido entre marcos
<a name="model-parallel-auto-model-split-comparison"></a>

En TensorFlow, la unidad fundamental de cálculo es a y TensorFlow representa el modelo como un `tf.Operation` grafo acíclico dirigido (DAG) de `tf.Operation` s y, por lo tanto, la biblioteca de paralelismo de modelos divide este DAG para que cada nodo vaya a un dispositivo. Y lo que es más importante, los objetos `tf.Operation` son lo suficientemente ricos con atributos personalizables y son universales en el sentido de que cada modelo está garantizado por un gráfico de dichos objetos. 

PyTorch por otro lado, no tiene una noción de operación equivalente que sea lo suficientemente rica y universal. La unidad de cálculo más cercana PyTorch que tiene estas características es una`nn.Module`, que se encuentra en un nivel de granularidad mucho más alto, y es por eso que la biblioteca realiza particiones a este nivel en. PyTorch

### División manual de modelos
<a name="model-parallel-manual-model-splitting"></a>

Si desea especificar manualmente cómo particionar su modelo entre dispositivos, use el administrador de contexto `smp.partition`. Para obtener instrucciones acerca de cómo configurar el administrador de contexto para la partición manual, consulte las siguientes páginas.
+ [Dividir manualmente con TensorFlow](model-parallel-customize-training-script-tf.md#model-parallel-customize-training-script-tf-manual)
+ [Dividir manualmente con PyTorch](model-parallel-customize-training-script-pt.md#model-parallel-customize-training-script-pt-16-hvd)

Para usar esta opción después de realizar modificaciones, en el paso 2, tendrás que configurar y definir `auto_partition` a `False` `default_partition` en la clase de estimador del framework del SDK de SageMaker Python. Cualquier operación que no se coloque explícitamente en una partición a través del gestor de contextos de `smp.partition` se ejecuta en el `default_partition`. En este caso, se omite la lógica de división automatizada y cada operación se realiza según su especificación. En función de la estructura gráfica resultante, la biblioteca de paralelismo de modelos crea automáticamente una programación de ejecución canalizada.

# Modifica un script de entrenamiento TensorFlow
<a name="model-parallel-customize-training-script-tf"></a>

En esta sección, aprenderá a modificar los scripts de TensorFlow entrenamiento para configurar la biblioteca de paralelismo del SageMaker modelo para el particionamiento automático y el particionamiento manual. Esta selección de ejemplos incluye también un ejemplo integrado con Horovod para modelos híbridos y paralelismo de datos.

**nota**  
Para saber qué TensorFlow versiones son compatibles con la biblioteca, consulte. [Marcos compatibles y Regiones de AWS](distributed-model-parallel-support.md)

Las modificaciones necesarias que debe realizar en el script de entrenamiento para utilizar la biblioteca se enumeran en [División automática con TensorFlow](#model-parallel-customize-training-script-tf-23).

Para obtener información sobre cómo modificar el script de entrenamiento para utilizar el modelo híbrido y el paralelismo de datos con Horovod, consulte [División automática con Horovod para el paralelismo de datos TensorFlow y modelos híbridos](#model-parallel-customize-training-script-tf-2.3).

Si quiere usar particiones manuales, revise también [Dividir manualmente con TensorFlow](#model-parallel-customize-training-script-tf-manual). 

Los siguientes temas muestran ejemplos de scripts de entrenamiento que puede usar para configurar la biblioteca de paralelismo SageMaker de modelos para modelos de particionamiento automático y particionamiento manual. TensorFlow 

**nota**  
La partición automática está habilitada de forma predeterminada. A menos que se especifique lo contrario, los scripts de ejemplo utilizan la partición automática.

**Topics**
+ [División automática con TensorFlow](#model-parallel-customize-training-script-tf-23)
+ [División automática con Horovod para el paralelismo de datos TensorFlow y modelos híbridos](#model-parallel-customize-training-script-tf-2.3)
+ [Dividir manualmente con TensorFlow](#model-parallel-customize-training-script-tf-manual)
+ [Características del marco no compatibles](#model-parallel-tf-unsupported-features)

## División automática con TensorFlow
<a name="model-parallel-customize-training-script-tf-23"></a>

Se requieren los siguientes cambios en el script de entrenamiento para ejecutar un TensorFlow modelo con SageMaker la biblioteca de paralelismo de modelos:

1. Importe e inicialice la biblioteca con [https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/v1.2.0/smd_model_parallel_common_api.html#smp.init](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/v1.2.0/smd_model_parallel_common_api.html#smp.init).

1. Definir el modelo de Keras que se hereda de [https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/v1.2.0/smd_model_parallel_tensorflow.html](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/v1.2.0/smd_model_parallel_tensorflow.html) en lugar de la clase de modelo Keras. Devolver las salidas del modelo desde el método de llamada del objeto `smp.DistributedModel`. Tenga en cuenta que los tensores devueltos del método de llamada se transmitirán a través de dispositivos de paralelismo de modelos, lo que supondrá una sobrecarga de comunicación, por lo que no se debe devolver los tensores que no sean necesarios fuera del método de llamada (como las activaciones intermedias).

1. Establezca `drop_remainder=True` en el método `tf.Dataset.batch()`. Esto sirve para garantizar que el tamaño del lote sea siempre divisible por el número de microlotes.

1. Inserte las operaciones aleatorias en la canalización de datos`smp.dp_rank()`, por ejemplo, `shuffle(ds, seed=smp.dp_rank())` para garantizar la coherencia de las muestras de datos entre las GPUs que se encuentran distintas particiones de modelos.

1. Coloque la lógica hacia adelante y hacia atrás en una función de paso y decórela con `smp.step`.

1. Realice un procesamiento posterior en las salidas de los microlotes mediante los métodos [https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/v1.2.0/smd_model_parallel_common_api.html#StepOutput](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/v1.2.0/smd_model_parallel_common_api.html#StepOutput) tales como `reduce_mean`. La función [https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/v1.2.0/smd_model_parallel_common_api.html#smp.init](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/v1.2.0/smd_model_parallel_common_api.html#smp.init) debe tener un valor devuelto que depende de la salida de `smp.DistributedModel`.

1. Si hay algún paso de evaluación, coloque de manera similar la lógica de avance dentro de una función decorada `smp.step` y procese posteriormente las salidas utilizando la [API `StepOutput`](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/v1.2.0/smd_model_parallel_common_api.html#StepOutput).

[Para obtener más información sobre la API SageMaker de la biblioteca de paralelismo de modelos de la API, consulte la documentación de la API.](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smd_model_parallel.html) 

El siguiente script de Python es un ejemplo de un script de entrenamiento después de realizar los cambios.

```
import tensorflow as tf

# smdistributed: Import TF2.x API
import smdistributed.modelparallel.tensorflow as smp

# smdistributed: Initialize
smp.init()

# Download and load MNIST dataset.
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data(
    "MNIST-data-%d" % smp.rank()
)
x_train, x_test = x_train / 255.0, x_test / 255.0

# Add a channels dimension
x_train = x_train[..., tf.newaxis]
x_test = x_test[..., tf.newaxis]

# smdistributed: If needed, seed the shuffle with smp.dp_rank(), and drop_remainder
# in batching to make sure batch size is always divisible by number of microbatches
train_ds = (
    tf.data.Dataset.from_tensor_slices((x_train, y_train))
    .shuffle(10000, seed=smp.dp_rank())
    .batch(256, drop_remainder=True)
)

# smdistributed: Define smp.DistributedModel the same way as Keras sub-classing API 
class MyModel(smp.DistributedModel):
    def __init__(self):
        super(MyModel, self).__init__()
        # define layers

    def call(self, x, training=None):
        # define forward pass and return the model output

model = MyModel()

loss_object = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
optimizer = tf.keras.optimizers.Adam()
train_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name="train_accuracy")

# smdistributed: Define smp.step. Return any tensors needed outside
@smp.step
def get_grads(images, labels):
    predictions = model(images, training=True)
    loss = loss_object(labels, predictions)

    grads = optimizer.get_gradients(loss, model.trainable_variables)
    return grads, loss, predictions


@tf.function
def train_step(images, labels):
    gradients, loss, predictions = get_grads(images, labels)

    # smdistributed: Accumulate the gradients across microbatches
    gradients = [g.accumulate() for g in gradients]
    optimizer.apply_gradients(zip(gradients, model.trainable_variables))

    # smdistributed: Merge predictions and average losses across microbatches
    train_accuracy(labels, predictions.merge())
    return loss.reduce_mean()


for epoch in range(5):
    # Reset the metrics at the start of the next epoch
    train_accuracy.reset_states()
    for images, labels in train_ds:
        loss = train_step(images, labels)
    accuracy = train_accuracy.result()
```

Si ha terminado de preparar el script de entrenamiento, continúe con [Paso 2: Inicie un trabajo de formación con el SDK de SageMaker Python](model-parallel-sm-sdk.md). Si desea ejecutar un trabajo de entrenamiento paralelo de datos y modelo híbrido, proceda con la siguiente sección.

## División automática con Horovod para el paralelismo de datos TensorFlow y modelos híbridos
<a name="model-parallel-customize-training-script-tf-2.3"></a>

Puede utilizar la biblioteca de paralelismo de SageMaker modelos con Horovod para el paralelismo de datos y modelos híbridos. Para obtener más información sobre cómo la biblioteca divide un modelo para el paralelismo híbrido, consulte [PyTorch TensorFlowParalelismo de canalización (disponible para y)](model-parallel-intro.md#model-parallel-intro-pp).

En este paso, nos centramos en cómo modificar el guion de entrenamiento para adaptar la biblioteca de paralelismo del modelo. SageMaker

Para configurar correctamente su script de entrenamiento para que recoja la configuración de paralelismo híbrido que utilizará en [Paso 2: Inicie un trabajo de formación con el SDK de SageMaker Python](model-parallel-sm-sdk.md), utilice las funciones auxiliares de la biblioteca, `smp.dp_rank()` y `smp.mp_rank()`, que detectan automáticamente el rango de paralelismo de datos y el rango de paralelismo de modelos, respectivamente. 

Para encontrar todas las primitivas de MPI que admite la biblioteca, consulte [Conceptos básicos de MPI en la documentación](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/v1.2.0/smd_model_parallel_common_api.html#mpi-basics) del SDK de SageMaker Python. 

Los cambios principales necesarios en el script son:
+ Añadir `hvd.allreduce`
+ Variables de radiodifusión después del primer lote, según lo requerido por Horovod
+ Sembrando las operaciones de and/or fragmentación aleatoria en la canalización de datos con. `smp.dp_rank()`

**nota**  
Cuando utilice Horovod, no debe llamar directamente `hvd.init` en su script de entrenamiento. En su lugar, tendrás que `"horovod"` configurarlo `True` en los `modelparallel` parámetros del SDK de SageMaker Python en[Paso 2: Inicie un trabajo de formación con el SDK de SageMaker Python](model-parallel-sm-sdk.md). Esto permite que la biblioteca inicialice Horovod internamente en función de las asignaciones de dispositivos de las particiones del modelo. Llamar `hvd.init()` directamente a su script de entrenamiento puede provocar problemas.

**nota**  
El uso de la API `hvd.DistributedOptimizer` directamente en el script de entrenamiento puede provocar un rendimiento y una velocidad de entrenamiento deficientes, ya que la API incluye implícitamente la operación `AllReduce` en `smp.step`. Le recomendamos utilizar la biblioteca de paralelismo de modelos con Horovod llamando `hvd.allreduce` directamente después de llamar a `accumulate()` o `reduce_mean()` o en los gradientes devueltos por `smp.step`, como se mostrará en el siguiente ejemplo.

[Para obtener más información sobre la API SageMaker de la biblioteca de paralelismo de modelos de la API, consulta la documentación de la API.](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smd_model_parallel.html)

```
import tensorflow as tf
import horovod.tensorflow as hvd

# smdistributed: Import TF2.x API 
import smdistributed.modelparallel.tensorflow as smp

# smdistributed: Initialize
smp.init()

# Download and load MNIST dataset.
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data(
    "MNIST-data-%d" % smp.rank()
)
x_train, x_test = x_train / 255.0, x_test / 255.0

# Add a channels dimension
x_train = x_train[..., tf.newaxis]
x_test = x_test[..., tf.newaxis]

# smdistributed: Seed the shuffle with smp.dp_rank(), and drop_remainder
# in batching to make sure batch size is always divisible by number of microbatches
train_ds = (
    tf.data.Dataset.from_tensor_slices((x_train, y_train))
    .shuffle(10000, seed=smp.dp_rank())
    .batch(256, drop_remainder=True)
)

# smdistributed: Define smp.DistributedModel the same way as Keras sub-classing API 
class MyModel(smp.DistributedModel):
    def __init__(self):
        super(MyModel, self).__init__()
        # define layers

    def call(self, x, training=None):
        # define forward pass and return model outputs


model = MyModel()

loss_object = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
optimizer = tf.keras.optimizers.Adam()
train_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name="train_accuracy")

# smdistributed: Define smp.step. Return any tensors needed outside
@smp.step
def get_grads(images, labels):
    predictions = model(images, training=True)
    loss = loss_object(labels, predictions)

    grads = optimizer.get_gradients(loss, model.trainable_variables)
    return grads, loss, predictions


@tf.function
def train_step(images, labels, first_batch):
    gradients, loss, predictions = get_grads(images, labels)

    # smdistributed: Accumulate the gradients across microbatches
    # Horovod: AllReduce the accumulated gradients
    gradients = [hvd.allreduce(g.accumulate()) for g in gradients]
    optimizer.apply_gradients(zip(gradients, model.trainable_variables))

    # Horovod: Broadcast the variables after first batch 
    if first_batch:
        hvd.broadcast_variables(model.variables, root_rank=0)
        hvd.broadcast_variables(optimizer.variables(), root_rank=0)

    # smdistributed: Merge predictions across microbatches
    train_accuracy(labels, predictions.merge())
    return loss.reduce_mean()


for epoch in range(5):
    # Reset the metrics at the start of the next epoch
    train_accuracy.reset_states()

    for batch, (images, labels) in enumerate(train_ds):
        loss = train_step(images, labels, tf.constant(batch == 0))
```

## Dividir manualmente con TensorFlow
<a name="model-parallel-customize-training-script-tf-manual"></a>

Uso de gestores de contexto de `smp.partition` para colocar las operaciones en una partición específica. Toda operación no colocada en ningún contexto `smp.partition` se colocará en `default_partition`. [Para obtener más información sobre la API SageMaker de la biblioteca de paralelismo de modelos de esta, consulta la documentación de la API.](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smd_model_parallel.html) 

```
import tensorflow as tf

# smdistributed: Import TF2.x API.
import smdistributed.modelparallel.tensorflow as smp

# smdistributed: Initialize
smp.init()

# Download and load MNIST dataset.
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data(
    "MNIST-data-%d" % smp.rank()
)
x_train, x_test = x_train / 255.0, x_test / 255.0

# Add a channels dimension
x_train = x_train[..., tf.newaxis]
x_test = x_test[..., tf.newaxis]

# smdistributed: If needed, seed the shuffle with smp.dp_rank(), and drop_remainder
# in batching to make sure batch size is always divisible by number of microbatches.
train_ds = (
    tf.data.Dataset.from_tensor_slices((x_train, y_train))
    .shuffle(10000, seed=smp.dp_rank())
    .batch(256, drop_remainder=True)
)

# smdistributed: Define smp.DistributedModel the same way as Keras sub-classing API.
class MyModel(smp.DistributedModel):
    def __init__(self):
         # define layers

    def call(self, x):
        with smp.partition(0):
            x = self.layer0(x)
        with smp.partition(1):
            return self.layer1(x)


model = MyModel()

loss_object = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
optimizer = tf.keras.optimizers.Adam()
train_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(name="train_accuracy")

# smdistributed: Define smp.step. Return any tensors needed outside
@smp.step
def get_grads(images, labels):
    predictions = model(images, training=True)
    loss = loss_object(labels, predictions)

    grads = optimizer.get_gradients(loss, model.trainable_variables)
    return grads, loss, predictions


@tf.function
def train_step(images, labels):
    gradients, loss, predictions = get_grads(images, labels)

    # smdistributed: Accumulate the gradients across microbatches
    gradients = [g.accumulate() for g in gradients]
    optimizer.apply_gradients(zip(gradients, model.trainable_variables))

    # smdistributed: Merge predictions and average losses across microbatches
    train_accuracy(labels, predictions.merge())
    return loss.reduce_mean()


for epoch in range(5):
    # Reset the metrics at the start of the next epoch
    train_accuracy.reset_states()
    for images, labels in train_ds:
        loss = train_step(images, labels)
    accuracy = train_accuracy.result()
```

## Características del marco no compatibles
<a name="model-parallel-tf-unsupported-features"></a>

La biblioteca no admite las siguientes TensorFlow funciones:
+ Actualmente `tf.GradientTape()` no es compatible. Puede usar `Optimizer.get_gradients()` o `Optimizer.compute_gradients()` en lugar de gradiente informáticos.
+ Actualmente, la API `tf.train.Checkpoint.restore()` no es compatible. Para los puntos de control, utilice `smp.CheckpointManager` en su lugar, que proporciona la misma API y funcionalidad. Tenga en cuenta que las restauraciones del punto de control con `smp.CheckpointManager` deben realizarse después del primer paso.

# Modifique un guion PyTorch de entrenamiento
<a name="model-parallel-customize-training-script-pt"></a>

En esta sección, aprenderá a modificar los scripts de PyTorch entrenamiento para configurar la biblioteca de paralelismo del SageMaker modelo para el particionamiento automático y el particionamiento manual.

**nota**  
Para saber qué PyTorch versiones son compatibles con la biblioteca, consulte. [Marcos compatibles y Regiones de AWS](distributed-model-parallel-support.md)

**sugerencia**  
Para ver ejemplos de end-to-end cuadernos que muestran cómo utilizar un guion de PyTorch entrenamiento con la biblioteca de SageMaker modelos de paralelismo, consulte. [Ejemplos de la biblioteca de paralelismo de modelos Amazon SageMaker AI v1](distributed-model-parallel-examples.md)

Tenga en cuenta que la partición automática está habilitada de forma predeterminada. A menos que se especifique lo contrario, los siguientes scripts utilizan la partición automática. 

**Topics**
+ [División automática con PyTorch](#model-parallel-customize-training-script-pt-16)
+ [Dividir manualmente con PyTorch](#model-parallel-customize-training-script-pt-16-hvd)
+ [Consideraciones](#model-parallel-pt-considerations)
+ [Características del marco no compatibles](#model-parallel-pt-unsupported-features)

## División automática con PyTorch
<a name="model-parallel-customize-training-script-pt-16"></a>

Se requieren los siguientes cambios en el guion de entrenamiento para ejecutar un guion de PyTorch entrenamiento con SageMaker la biblioteca de paralelismo de modelos:

1. Importe e inicialice la biblioteca con [https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/v1.2.0/smd_model_parallel_common_api.html#smp.init](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/v1.2.0/smd_model_parallel_common_api.html#smp.init).

1. Encapsule el modelo con [https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/v1.2.0/smd_model_parallel_pytorch.html#smp.DistributedModel](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/v1.2.0/smd_model_parallel_pytorch.html#smp.DistributedModel). Tenga en cuenta que los tensores devueltos por el método `forward` del objeto subyacente se transmitirán a través de dispositivos paralelos al modelo, lo que generará una sobrecarga de comunicación, por lo que no se deben devolver los tensores que no sean necesarios fuera del método de llamada (como activaciones intermedias).
**nota**  
Para el FP16 entrenamiento, debe usar el administrador de contexto [smdistributed.modelparallel.torch.model\$1creation](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/latest/smd_model_parallel_pytorch.html) () para empaquetar el modelo. Para obtener más información, consulte [FP16 Entrenamiento con paralelismo de modelos](model-parallel-extended-features-pytorch-fp16.md).

1. Encapsule el optimizador con [https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/v1.2.0/smd_model_parallel_pytorch.html#smp.DistributedOptimizer](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/v1.2.0/smd_model_parallel_pytorch.html#smp.DistributedOptimizer).
**nota**  
Para FP16 el entrenamiento, debe configurar el escalado de pérdidas estático o dinámico. Para obtener más información, consulte [FP16 Entrenamiento con paralelismo de modelos](model-parallel-extended-features-pytorch-fp16.md).

1. Usa el objeto `DistributedModel` devuelto en lugar de un modelo de usuario.

1. Coloque la lógica hacia adelante y hacia atrás en una función de paso y decórela con [https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/v1.2.0/smd_model_parallel_common_api.html#smp.init](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/v1.2.0/smd_model_parallel_common_api.html#smp.init).

1. Restrinja cada proceso a su propio dispositivo mediante `torch.cuda.set_device(smp.local_rank())`.

1. Mueva los tensores de entrada a la GPU mediante la API `.to()` antes de la llamada `smp.step` (véase el ejemplo a continuación).

1. Sustituya `torch.Tensor.backward` y `torch.autograd.backward` por `DistributedModel.backward`.

1. Realice un procesamiento posterior en las salidas de los microlotes mediante los métodos [https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/v1.2.0/smd_model_parallel_common_api.html#StepOutput](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/v1.2.0/smd_model_parallel_common_api.html#StepOutput) como `reduce_mean`.

1. Si hay algún paso de evaluación, coloque de manera similar la lógica de avance dentro de la función decorada `smp.step` y procese posteriormente las salidas utilizando la [API `StepOutput`](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/v1.2.0/smd_model_parallel_common_api.html#StepOutput).

1. Establezca `drop_last=True` en `DataLoader`. Alternativamente, omita manualmente un lote en el ciclo de entrenamiento si el tamaño del lote no es divisible por el número de microlotes.

[Para obtener más información sobre la API SageMaker de la biblioteca de paralelismo de modelos de la API, consulte la documentación de la API.](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smd_model_parallel.html) 

```
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchnet.dataset import SplitDataset
from torchvision import datasets

import smdistributed.modelparallel.torch as smp

class GroupedNet(nn.Module):
    def __init__(self):
        super(GroupedNet, self).__init__()
        # define layers

    def forward(self, x):
        # define forward pass and return model outputs


# smdistributed: Define smp.step. Return any tensors needed outside.
@smp.step
def train_step(model, data, target):
    output = model(data)
    loss = F.nll_loss(output, target, reduction="mean")
    model.backward(loss)
    return output, loss


def train(model, device, train_loader, optimizer):
    model.train()
    for batch_idx, (data, target) in enumerate(train_loader):
        # smdistributed: Move input tensors to the GPU ID used by the current process,
        # based on the set_device call.
        data, target = data.to(device), target.to(device)
        optimizer.zero_grad()
        # Return value, loss_mb is a StepOutput object
        _, loss_mb = train_step(model, data, target)

        # smdistributed: Average the loss across microbatches.
        loss = loss_mb.reduce_mean()

        optimizer.step()

# smdistributed: initialize the backend
smp.init()

# smdistributed: Set the device to the GPU ID used by the current process.
# Input tensors should be transferred to this device.
torch.cuda.set_device(smp.local_rank())
device = torch.device("cuda")

# smdistributed: Download only on a single process per instance.
# When this is not present, the file is corrupted by multiple processes trying
# to download and extract at the same time
dataset = datasets.MNIST("../data", train=True, download=False)

# smdistributed: Shard the dataset based on data-parallel ranks
if smp.dp_size() > 1:
    partitions_dict = {f"{i}": 1 / smp.dp_size() for i in range(smp.dp_size())}
    dataset = SplitDataset(dataset, partitions=partitions_dict)
    dataset.select(f"{smp.dp_rank()}")

# smdistributed: Set drop_last=True to ensure that batch size is always divisible
# by the number of microbatches
train_loader = torch.utils.data.DataLoader(dataset, batch_size=64, drop_last=True)

model = GroupedNet()
optimizer = optim.Adadelta(model.parameters(), lr=4.0)

# smdistributed: Use the DistributedModel container to provide the model
# to be partitioned across different ranks. For the rest of the script,
# the returned DistributedModel object should be used in place of
# the model provided for DistributedModel class instantiation.
model = smp.DistributedModel(model)
optimizer = smp.DistributedOptimizer(optimizer)

train(model, device, train_loader, optimizer)
```

## Dividir manualmente con PyTorch
<a name="model-parallel-customize-training-script-pt-16-hvd"></a>

Utilice los gestores de contexto de [https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/v1.2.0/smd_model_parallel_pytorch.html#smp.DistributedOptimizer](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/v1.2.0/smd_model_parallel_pytorch.html#smp.DistributedOptimizer) para colocar módulos en dispositivos específicos. Todo módulo no colocado en ningún contexto `smp.partition` se colocará en `default_partition`. El `default_partition` debe proporcionarse si `auto_partition` está establecido en `False`. Los módulos que se crean dentro de un determinado contexto `smp.partition` se colocan en la partición correspondiente.

[Para obtener más información sobre la API SageMaker de la biblioteca de paralelismo de modelos de esta, consulta la documentación de la API.](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smd_model_parallel.html) 

```
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchnet.dataset import SplitDataset
from torchvision import datasets

import smdistributed.modelparallel.torch as smp

class GroupedNet(nn.Module):
    def __init__(self):
        super(GroupedNet, self).__init__()
        with smp.partition(0):
            # define child modules on device 0
        with smp.partition(1):
            # define child modules on device 1

    def forward(self, x):
        # define forward pass and return model outputs


# smdistributed: Define smp.step. Return any tensors needed outside.
@smp.step
def train_step(model, data, target):
    output = model(data)
    loss = F.nll_loss(output, target, reduction="mean")
    model.backward(loss)
    return output, loss


def train(model, device, train_loader, optimizer):
    model.train()
    for batch_idx, (data, target) in enumerate(train_loader):
        # smdistributed: Move input tensors to the GPU ID used by the current process,
        # based on the set_device call.
        data, target = data.to(device), target.to(device)
        optimizer.zero_grad()
        # Return value, loss_mb is a StepOutput object
        _, loss_mb = train_step(model, data, target)

        # smdistributed: Average the loss across microbatches.
        loss = loss_mb.reduce_mean()

        optimizer.step()

# smdistributed: initialize the backend
smp.init()

# smdistributed: Set the device to the GPU ID used by the current process.
# Input tensors should be transferred to this device.
torch.cuda.set_device(smp.local_rank())
device = torch.device("cuda")

# smdistributed: Download only on a single process per instance.
# When this is not present, the file is corrupted by multiple processes trying
# to download and extract at the same time
dataset = datasets.MNIST("../data", train=True, download=False)

# smdistributed: Shard the dataset based on data-parallel ranks
if smp.dp_size() > 1:
    partitions_dict = {f"{i}": 1 / smp.dp_size() for i in range(smp.dp_size())}
    dataset = SplitDataset(dataset, partitions=partitions_dict)
    dataset.select(f"{smp.dp_rank()}")

# smdistributed: Set drop_last=True to ensure that batch size is always divisible
# by the number of microbatches
train_loader = torch.utils.data.DataLoader(dataset, batch_size=64, drop_last=True)

model = GroupedNet()
optimizer = optim.Adadelta(model.parameters(), lr=4.0)

# smdistributed: Use the DistributedModel container to provide the model
# to be partitioned across different ranks. For the rest of the script,
# the returned DistributedModel object should be used in place of
# the model provided for DistributedModel class instantiation.
model = smp.DistributedModel(model)
optimizer = smp.DistributedOptimizer(optimizer)

train(model, device, train_loader, optimizer)
```

## Consideraciones
<a name="model-parallel-pt-considerations"></a>

Al configurar un script de PyTorch entrenamiento mediante SageMaker la biblioteca de paralelismo de modelos, debe tener en cuenta lo siguiente:
+ Si utiliza una técnica de optimización que se basa en normas de degradado globales, por ejemplo, una norma de degradado de todo el modelo, como algunas variantes del optimizador LAMB o el recorte de degradado global, debe recopilar todas las normas en las particiones del modelo para que sean correctas. Puede utilizar los tipos de datos básicos de comunicación de la biblioteca para hacerlo.
+ Todos los argumentos `torch.Tensor` a los métodos de reenvío del modelo `nn.Modules` deben utilizarse en el cálculo de la salida del módulo. En otras palabras, la biblioteca no admite ese caso en el que hay un argumento `torch.Tensor` a un módulo del que no depende la salida del módulo.
+ El argumento a la llamada `smp.DistributedModel.backward()` debe depender de todas las salidas del modelo. En otras palabras, no puede haber una salida de la llamada `smp.DistributedModel.forward` que no se utilice en el cálculo del tensor que se introduce en la llamada `smp.DistributedModel.backward`.
+ Si hay llamadas `torch.cuda.synchronize()` en su código, es posible que tenga que llamar `torch.cuda.set_device(smp.local_rank())` inmediatamente antes de la llamada de sincronización. De lo contrario, se podrían crear contextos CUDA innecesarios en el dispositivo 0, que consumirá memoria innecesariamente.
+ Desde que la biblioteca coloca `nn.Modules` en distintos dispositivos, los módulos del modelo no deben depender de ningún estado global modificado en `smp.step`. Cualquier estado que permanezca fijo durante todo el entrenamiento o que se modifique fuera de `smp.step` de forma visible para todos los procesos, está permitido.
+ No es necesario mover el modelo a la GPU (por ejemplo, usando `model.to(device)`) al utilizar la biblioteca. Si intenta mover el modelo a la GPU antes de particionar el modelo (antes de la primera llamada `smp.step`), se ignora la llamada de movimiento. La biblioteca mueve automáticamente la parte del modelo asignada a un rango a su GPU. Una vez que comience el entrenamiento con la biblioteca, no mueva el modelo a la CPU y lo utilice, ya que no tendrá parámetros correctos para los módulos no asignados a la partición que tiene el proceso. Si quieres volver a entrenar un modelo o usarlo para realizar inferencias sin la biblioteca después de haberlo entrenado con la biblioteca de paralelismo de modelos, la forma recomendada es guardar el modelo completo con nuestra API de puntos de control y volver a cargarlo en un módulo normal. PyTorch 
+ Si tiene una lista de módulos de modo que la salida de uno alimenta a otro, reemplazar esa lista por `nn.Sequential` puede mejorar significativamente el rendimiento.
+ La actualización de peso (`optimizer.step()`) tiene que ocurrir fuera de `smp.step`porque es cuando se hace todo el paso hacia atrás y los gradientes están listos. Cuando se utiliza un modelo híbrido con paralelismo de modelos y datos, en este punto también se garantiza que los gradientes finalizarán. AllReduce 
+ Cuando utilice la biblioteca en combinación con el paralelismo de datos, asegúrese de que el número de lotes en todos los rangos paralelos de datos sea el mismo para que AllReduce no se quede esperando a que un rango no participe en el paso.
+ Si lanza un trabajo de entrenamiento utilizando un tipo de instancia ml.p4d (como ml.p4d.24xlarge), debe establecer la variable del cargador de datos `num_workers=0`. Por ejemplo, puede definir su `DataLoader` de la siguiente manera:

  ```
  dataloader = torch.utils.data.DataLoader(
              data,
              batch_size=batch_size,
              num_workers=0,
              pin_memory=True,
              drop_last=True,
              shuffle=shuffle,
          )
  ```
+ Las entradas para `smp.step` deben ser las entradas de modelo generadas por `DataLoader`. Esto se debe a que `smp.step` divide internamente los tensores de entrada a lo largo de la dimensión del lote y los canaliza. Esto significa que pasar `DataLoader` a la `smp.step` para generar las entradas del modelo en el interior no funciona. 

  Por ejemplo, si define un `DataLoader` de la siguiente manera:

  ```
  train_loader = torch.utils.data.DataLoader(dataset, batch_size=64, drop_last=True)
  ```

  Debe acceder a las entradas del modelo generadas por `train_loader` y pasarlos a una función decorada por `smp.step`. No pase `train_loader` directamente a la función `smp.step`.

  ```
  def train(model, device, train_loader, optimizer):
      model.train()
      for batch_idx, (data, target) in enumerate(train_loader):
          ...
          _, loss_mb = train_step(model, data, target)
          ...
  
  @smp.step
  def train_step(model, data, target):
      ...
      return output, loss
  ```
+ Los tensores de entrada a `smp.step` debe, moverse al dispositivo actual mediante la API `.to()`, que debe tener lugar después de la llamada `torch.cuda.set_device(local_rank())`.

  Por ejemplo, puede utilizar la función `train` de la siguiente manera. Esta función añade `data` y `target` al dispositivo actual utilizando la API `.to()` antes de usar esos tensores de entrada para llamar `train_step`.

  ```
  def train(model, device, train_loader, optimizer):
      model.train()
      for batch_idx, (data, target) in enumerate(train_loader):
          # smdistributed: Move input tensors to the GPU ID used by the current process,
          # based on the set_device call.
          data, target = data.to(device), target.to(device)
          optimizer.zero_grad()
          # Return value, loss_mb is a StepOutput object
          _, loss_mb = train_step(model, data, target)
  
          # smdistributed: Average the loss across microbatches.
          loss = loss_mb.reduce_mean()
  
          optimizer.step()
  ```

  Los tensores de entrada para esta función decorado por `smp.set` se ha movido al dispositivo actual en la función `train` anterior. El modelo *no* debe moverse al dispositivo actual. La biblioteca mueve automáticamente la parte del modelo asignada a un rango a su GPU.

  ```
  @smp.step
  def train_step(model, data, target):
      output = model(data)
      loss = F.nll_loss(output, target, reduction="mean")
      model.backward(loss)
      return output, loss
  ```

## Características del marco no compatibles
<a name="model-parallel-pt-unsupported-features"></a>

La biblioteca de paralelismo de modelos de la biblioteca de paralelismo de modelos no admite las siguientes PyTorch funciones: SageMaker
+ Si utiliza el paralelismo de datos con el [PyTorch DDP](https://pytorch.org/tutorials/intermediate/ddp_tutorial.html) nativo, la biblioteca no admite el módulo [https://pytorch.org/docs/stable/generated/torch.nn.parallel.DistributedDataParallel.html](https://pytorch.org/docs/stable/generated/torch.nn.parallel.DistributedDataParallel.html)contenedor. La biblioteca gestiona internamente la integración con el PyTorch DDP, incluida la transmisión de parámetros y el gradiente. AllReduce Cuando se utiliza la biblioteca, los búferes de módulo solo se transmiten una vez al comienzo del entrenamiento. Si el modelo tiene búferes de módulo que deben sincronizarse entre los grupos paralelos de datos en cada paso, puede hacerlo a través de la API `torch.distributed`, utilizando el grupo de procesos que se puede obtener mediante `smp.get_dp_process_group()`.
+ Para un entrenamiento de precisión mixta, el módulo `apex.amp` no es compatible. La forma recomendada de utilizar la biblioteca con precisión mixta automática es utilizar `torch.cuda.amp`, con la excepción de utilizar `smp.amp.GradScaler` en lugar de la aplicación en antorcha.
+ `torch.jit.ScriptModules` o `ScriptFunctions` no son compatibles con `smp.DistributedModel`.
+ `apex` : `FusedLayerNorm`, `FusedAdam`, `FusedLAMB` y `FusedNovoGrad` de `apex` no son compatibles. Puede utilizar las implementaciones de la biblioteca de principio a fin `smp.optimizers` y `smp.nn` APIs en su lugar.