

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

# Etapa 1: modifique seu próprio script de treinamento usando a biblioteca paralela SageMaker de modelos distribuídos
<a name="model-parallel-customize-training-script"></a>

Use esta seção para aprender a personalizar seu script de treinamento para usar os principais recursos da biblioteca de paralelismo de modelos de SageMaker IA da Amazon. *Para usar as funções e os parâmetros de API específicos da biblioteca, recomendamos que você use essa documentação junto com a [biblioteca de modelos SageMaker paralelos na documentação do SDK APIs](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smd_model_parallel.html) do PythonSageMaker .*

Os exemplos de scripts de treinamento fornecidos nessas seções são simplificados e projetados para destacar as alterações necessárias que você deve fazer para usar a biblioteca. Para end-to-end exemplos de notebooks executáveis que demonstram como usar um script de PyTorch treinamento TensorFlow ou com a biblioteca de paralelismo de SageMaker modelos, consulte. [Exemplos da biblioteca de paralelismo de modelos de SageMaker IA da Amazon v2](distributed-model-parallel-v2-examples.md)

**Topics**
+ [Divida o modelo do seu script de treinamento usando a biblioteca de SageMaker paralelismo de modelos](#model-parallel-model-splitting-using-smp-lib)
+ [Modificar um script TensorFlow de treinamento](model-parallel-customize-training-script-tf.md)
+ [Modificar um script PyTorch de treinamento](model-parallel-customize-training-script-pt.md)

## Divida o modelo do seu script de treinamento usando a biblioteca de SageMaker paralelismo de modelos
<a name="model-parallel-model-splitting-using-smp-lib"></a>

Há duas maneiras de modificar seu script de treinamento para configurar a divisão do modelo: divisão automática ou divisão manual.

### Divisão automatizada de modelos
<a name="model-parallel-automated-model-splitting"></a>

*Ao usar a biblioteca SageMaker de paralelismo de modelos, você pode aproveitar a *divisão automatizada de modelos, também conhecida como particionamento* automatizado de modelos.* A biblioteca utiliza um algoritmo de particionamento que equilibra a memória, minimiza a comunicação entre dispositivos e otimiza o desempenho. Você pode configurar o algoritmo de particionamento automático para otimizar a velocidade ou a memória. 

Também é possível usar a divisão manual do modelo. Recomendamos a divisão automatizada do modelo, a menos que você esteja muito familiarizado com a arquitetura do modelo e tenha uma boa ideia de como particionar seu modelo de forma eficiente.

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

O particionamento automático ocorre durante a primeira etapa de treinamento, quando a função decorada com `smp.step` é chamada pela primeira vez. Nesta chamada, a biblioteca primeiro constrói uma versão do modelo na RAM da CPU (para evitar limitações de memória da GPU) e, em seguida, analisa o grafo do modelo e toma uma decisão de particionamento. Com base nessa decisão, cada partição do modelo é carregada em uma GPU e somente então a primeira etapa é executada. Devido a essas etapas de análise e particionamento, a primeira etapa de treinamento pode levar mais tempo. 

Em qualquer estrutura, a biblioteca gerencia a comunicação entre dispositivos por meio de seu próprio back-end, que é otimizado para AWS infraestrutura.

O design de autopartição se adapta às características do framework, e a biblioteca realiza o particionamento no nível de granularidade que é mais natural em cada framework. Por exemplo, em TensorFlow, cada operação específica pode ser atribuída a um dispositivo diferente, enquanto em PyTorch, a atribuição é feita no nível do módulo, onde cada módulo consiste em várias operações. A seção a seguir analisa as especificidades do design em cada framework.

##### Divisão automatizada de modelos com PyTorch
<a name="model-parallel-auto-model-split-pt"></a>

Durante a primeira etapa de treinamento, a biblioteca de paralelismo de modelo internamente executa uma etapa de rastreamento destinada a construir o grafo do modelo e determinar as formas dos tensores e parâmetros. Após essa etapa de rastreamento, a biblioteca constrói uma árvore, que consiste nos objetos `nn.Module` aninhados no modelo, bem como nos dados adicionais coletados do rastreamento, como a quantidade de objetos armazenados `nn.Parameters` e o tempo de execução de cada `nn.Module`. 

Em seguida, a biblioteca percorre essa árvore a partir da raiz e executa um algoritmo de particionamento que atribui cada `nn.Module` a um dispositivo, equilibrando a carga computacional (medida pelo tempo de execução do módulo) e o uso de memória (medido pelo tamanho total armazenado de `nn.Parameter` e ativações). Se vários `nn.Modules` compartilham o mesmo `nn.Parameter`, então esses módulos são colocados no mesmo dispositivo para evitar manter várias versões do mesmo parâmetro. Assim que a decisão de particionamento é tomada, os módulos e pesos atribuídos são carregados em seus dispositivos.

Para obter instruções sobre como registrar o `smp.step` decorador em seu script PyTorch de treinamento, consulte[Divisão automatizada com PyTorch](model-parallel-customize-training-script-pt.md#model-parallel-customize-training-script-pt-16).

##### Divisão automatizada de modelos com TensorFlow
<a name="model-parallel-auto-model-split-tf"></a>

A biblioteca de paralelismo de modelos analisa os tamanhos das variáveis treináveis e a estrutura do gráfico e usa internamente um algoritmo de particionamento gráfico. Este algoritmo determina uma atribuição de dispositivo para cada operação, com o objetivo de minimizar a quantidade de comunicação necessária entre dispositivos, sujeito a duas restrições: 
+ Equilibrando o número de variáveis armazenadas em cada dispositivo.
+ Equilibrando o número de operações executadas em cada dispositivo

Se você especificar `speed` para `optimize` (nos parâmetros de paralelismo do modelo no Python SDK), a biblioteca tentará equilibrar o número de operações e objetos `tf.Variable` em cada dispositivo. Caso contrário, ele tenta equilibrar o tamanho total de `tf.Variables`.

Uma vez tomada a decisão de particionamento, a biblioteca cria uma representação serializada do subgráfico que cada dispositivo precisa executar e os importa para cada dispositivo. Durante o particionamento, a biblioteca coloca as operações que consomem o mesmo `tf.Variable` e as operações que fazem parte da mesma camada Keras no mesmo dispositivo. Também respeita as restrições de colocation impostas por. TensorFlow Isso significa que, por exemplo, se houver duas camadas Keras que compartilham um `tf.Variable`, todas as operações que fazem parte dessas camadas são colocadas em um dispositivo único.

Para obter instruções sobre como registrar o `smp.step` decorador em seu script PyTorch de treinamento, consulte[Divisão automatizada com TensorFlow](model-parallel-customize-training-script-tf.md#model-parallel-customize-training-script-tf-23).

##### Comparação da divisão automatizada de modelos entre frameworks
<a name="model-parallel-auto-model-split-comparison"></a>

Em TensorFlow, a unidade fundamental de computação é a e TensorFlow representa o modelo como um `tf.Operation` gráfico acíclico direcionado (DAG) de `tf.Operation` s e, portanto, a biblioteca de paralelismo do modelo particiona esse DAG para que cada nó vá para um dispositivo. Crucialmente, os objetos `tf.Operation` são suficientemente ricos em atributos personalizáveis e são universais no sentido de que cada modelo tem a garantia de consistir em um gráfico desses objetos. 

PyTorch por outro lado, não tem uma noção equivalente de operação que seja suficientemente rica e universal. A unidade de computação mais próxima PyTorch que tem essas características é uma`nn.Module`, que está em um nível de granularidade muito maior, e é por isso que a biblioteca faz o particionamento nesse nível em. PyTorch

### Divisão manual de modelos
<a name="model-parallel-manual-model-splitting"></a>

Se você quiser especificar manualmente como particionar seu modelo entre dispositivos, use o gerenciador de contexto do `smp.partition`. Para instruções sobre como configurar o gerenciador de contexto para particionamento manual, consulte as seguintes páginas.
+ [Divisão manual com TensorFlow](model-parallel-customize-training-script-tf.md#model-parallel-customize-training-script-tf-manual)
+ [Divisão manual com PyTorch](model-parallel-customize-training-script-pt.md#model-parallel-customize-training-script-pt-16-hvd)

Para usar essa opção depois de fazer modificações, na Etapa 2, você precisará definir e definir uma `default_partition` na classe de estimador da estrutura do SDK do Python SageMaker. `auto_partition` `False` Qualquer operação que não seja colocada explicitamente em uma partição por meio do gerenciador de contexto do `smp.partition` é executada no `default_partition`. Nesse caso, a lógica de divisão automatizada é ignorada e cada operação é colocada com base na sua especificação. Com base na estrutura gráfica resultante, a biblioteca de paralelismo de modelos cria automaticamente um cronograma de execução em pipeline.

# Modificar um script TensorFlow de treinamento
<a name="model-parallel-customize-training-script-tf"></a>

Nesta seção, você aprende a modificar scripts de TensorFlow treinamento para configurar a biblioteca de paralelismo de SageMaker modelos para particionamento automático e particionamento manual. Essa seleção de exemplos também inclui um exemplo integrado ao Horovod para modelo híbrido e paralelismo de dados.

**nota**  
Para descobrir quais TensorFlow versões são suportadas pela biblioteca, consulte[Estruturas suportadas e Regiões da AWS](distributed-model-parallel-support.md).

As modificações necessárias que você deve fazer em seu script de treinamento para usar a biblioteca estão listadas em [Divisão automatizada com TensorFlow](#model-parallel-customize-training-script-tf-23).

Para saber como modificar seu script de treinamento para usar o modelo híbrido e o paralelismo de dados com o Horovod, consulte [Divisão automatizada com TensorFlow e Horovod para modelo híbrido e paralelismo de dados](#model-parallel-customize-training-script-tf-2.3).

Se você quiser usar o particionamento manual, revise também [Divisão manual com TensorFlow](#model-parallel-customize-training-script-tf-manual). 

Os tópicos a seguir mostram exemplos de scripts de treinamento que você pode usar para configurar a biblioteca de paralelismo SageMaker de modelos da para particionamento automático e modelos de particionamento manual. TensorFlow 

**nota**  
O particionamento automático está habilitado por padrão. A menos que especificado de outra forma, os scripts de exemplo usam particionamento automático.

**Topics**
+ [Divisão automatizada com TensorFlow](#model-parallel-customize-training-script-tf-23)
+ [Divisão automatizada com TensorFlow e Horovod para modelo híbrido e paralelismo de dados](#model-parallel-customize-training-script-tf-2.3)
+ [Divisão manual com TensorFlow](#model-parallel-customize-training-script-tf-manual)
+ [Recursos de framework incompatíveis](#model-parallel-tf-unsupported-features)

## Divisão automatizada com TensorFlow
<a name="model-parallel-customize-training-script-tf-23"></a>

As seguintes alterações no script de treinamento são necessárias para executar um TensorFlow modelo com a biblioteca SageMaker de paralelismo de modelos:

1. Importe e inicialize a biblioteca com o [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. Defina um modelo Keras herdando da classe Keras Model [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) em vez da classe Keras Model. Retorne as saídas do modelo do método de chamada do objeto `smp.DistributedModel`. Esteja ciente de que qualquer tensor retornado do método de chamada será transmitido para dispositivos de paralelismo de modelo, acarretando custos de comunicação. Portanto, quaisquer tensores que não são necessários fora do método de chamada (como ativações intermediárias) não devem ser retornados.

1. Defina `drop_remainder=True` no método `tf.Dataset.batch()`. Isso é para garantir que o tamanho do lote seja sempre divisível pelo número de microlotes.

1. Semeie as operações aleatórias no pipeline de dados usando`smp.dp_rank()`, por exemplo, `shuffle(ds, seed=smp.dp_rank())` para garantir a consistência de amostras de dados GPUs que contêm diferentes partições de modelo.

1. Coloque a lógica para frente e para trás em uma step function e decore-a com `smp.step`.

1. Execute o pós-processamento nas saídas em microlotes usando 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`. A função do [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) deve ter um valor de retorno que dependa da saída de `smp.DistributedModel`.

1. Se houver uma etapa de avaliação, coloque logicamente a frente (forward) dentro de uma função decorada com `smp.step` e processe os resultados usando a [API do `StepOutput`](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/v1.2.0/smd_model_parallel_common_api.html#StepOutput).

[Para saber mais sobre a API SageMaker da biblioteca de paralelismo de modelos, consulte a documentação da API.](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smd_model_parallel.html) 

O script Python a seguir é um exemplo de script de treinamento após as alterações serem feitas.

```
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()
```

Se você terminar de preparar seu roteiro de treinamento, prossiga para [Etapa 2: Iniciar um Training Job usando o SageMaker Python SDK](model-parallel-sm-sdk.md). Se quiser executar um modelo híbrido e um trabalho de treinamento paralelo de dados, siga para a próxima seção.

## Divisão automatizada com TensorFlow e Horovod para modelo híbrido e paralelismo de dados
<a name="model-parallel-customize-training-script-tf-2.3"></a>

Você pode usar a biblioteca de paralelismo de SageMaker modelos com o Horovod para modelos híbridos e paralelismo de dados. Para ler mais sobre como a biblioteca divide um modelo para paralelismo híbrido, consulte [Paralelismo de tubulação (disponível para e) PyTorch TensorFlow](model-parallel-intro.md#model-parallel-intro-pp).

Nesta etapa, vamos nos concentrar em como modificar seu script de treinamento para adaptar a biblioteca de paralelismo de SageMaker modelos.

Para configurar adequadamente seu script de treinamento para adotar a configuração de paralelismo híbrido que você definirá em [Etapa 2: Iniciar um Training Job usando o SageMaker Python SDK](model-parallel-sm-sdk.md), utilize as funções auxiliares da biblioteca, `smp.dp_rank()` e `smp.mp_rank()`, que detectam automaticamente o rank de paralelismo de dados e o rank de paralelismo de modelo, respectivamente. 

Para encontrar todas as primitivas de MPI suportadas pela biblioteca, consulte [Noções básicas de MPI na](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/v1.2.0/smd_model_parallel_common_api.html#mpi-basics) documentação do SDK para Python SageMaker . 

As mudanças necessárias no script são:
+ Adicionando `hvd.allreduce`
+ Variáveis de transmissão após o primeiro lote, conforme exigido pela Horovod
+ Semeando, embaralhando, and/or fragmentando operações no pipeline de dados com. `smp.dp_rank()`

**nota**  
Ao usar o Horovod, você não deve solicitar diretamente `hvd.init` no seu script de treinamento. Em vez disso, você precisará `"horovod"` definir como `True` nos parâmetros do SDK `modelparallel` do SageMaker Python em. [Etapa 2: Iniciar um Training Job usando o SageMaker Python SDK](model-parallel-sm-sdk.md) Isso permite que a biblioteca inicialize internamente o Horovod com base nas atribuições de dispositivos das partições do modelo. Chamar `hvd.init()` diretamente em seu script de treinamento pode causar problemas.

**nota**  
Usar a API do `hvd.DistributedOptimizer` diretamente em seu script de treinamento pode resultar em performance e velocidade de treinamento ruins, porque a API coloca implicitamente a operação `AllReduce` dentro do `smp.step`. Recomendamos que você use a biblioteca de paralelismo de modelos com o Horovod chamando diretamente `hvd.allreduce` após a chamada `accumulate()` ou `reduce_mean()` nos gradientes retornados `smp.step`, conforme mostrado no exemplo a seguir.

[Para saber mais sobre a API SageMaker da biblioteca de paralelismo de modelos, consulte a documentação da 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))
```

## Divisão manual com TensorFlow
<a name="model-parallel-customize-training-script-tf-manual"></a>

Use gerenciadores de contexto do `smp.partition` para colocar as operações em uma partição específica. Qualquer operação não colocada em nenhum contexto `smp.partition` é colocada no `default_partition`. [Para saber mais sobre a API SageMaker da biblioteca de paralelismo de modelos, consulte a documentação da 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()
```

## Recursos de framework incompatíveis
<a name="model-parallel-tf-unsupported-features"></a>

Os seguintes TensorFlow recursos não são compatíveis com a biblioteca:
+ O `tf.GradientTape()` não tem suporte no momento. Você pode usar `Optimizer.get_gradients()` ou `Optimizer.compute_gradients()` em vez disso para calcular gradientes.
+ Atualmente, a API do `tf.train.Checkpoint.restore()` não tem suporte. Para pontos de verificação, use `smp.CheckpointManager` em vez disso, que fornece a mesma API e funcionalidade. Observe que as restaurações do ponto de verificação do `smp.CheckpointManager` devem ocorrer após a primeira etapa.

# Modificar um script PyTorch de treinamento
<a name="model-parallel-customize-training-script-pt"></a>

Nesta seção, você aprende a modificar scripts de PyTorch treinamento para configurar a biblioteca de paralelismo de SageMaker modelos para particionamento automático e particionamento manual.

**nota**  
Para descobrir quais PyTorch versões são suportadas pela biblioteca, consulte[Estruturas suportadas e Regiões da AWS](distributed-model-parallel-support.md).

**dica**  
Para exemplos de end-to-end cadernos que demonstram como usar um script de PyTorch treinamento com a biblioteca de paralelismo de SageMaker modelos, consulte. [Exemplos da biblioteca de paralelismo de modelos Amazon SageMaker AI v1](distributed-model-parallel-examples.md)

Observe que o particionamento automático está habilitado por padrão. A menos que seja especificado de outra forma, os scripts a seguir utilizam autoparticionamento. 

**Topics**
+ [Divisão automatizada com PyTorch](#model-parallel-customize-training-script-pt-16)
+ [Divisão manual com PyTorch](#model-parallel-customize-training-script-pt-16-hvd)
+ [Considerações](#model-parallel-pt-considerations)
+ [Recursos de framework incompatíveis](#model-parallel-pt-unsupported-features)

## Divisão automatizada com PyTorch
<a name="model-parallel-customize-training-script-pt-16"></a>

As seguintes alterações no script de treinamento são necessárias para executar um script de PyTorch treinamento com a biblioteca SageMaker de paralelismo de modelos da:

1. Importe e inicialize a biblioteca com o [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. Empacote o modelo com [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). Esteja ciente de que quaisquer tensores retornados pelo método `forward` do objeto `nn.Module` subjacente serão transmitidos para os dispositivos de paralelismo de modelo, incorrendo em sobrecarga de comunicação. Portanto, quaisquer tensores que não são necessários fora do método de chamada (como ativações intermediárias) não devem ser retornados.
**nota**  
Para FP16 treinamento, você precisa usar o gerenciador de contexto [smdistributed.modelparallel.torch.model\$1creation () para empacotar](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/latest/smd_model_parallel_pytorch.html) o modelo. Para obter mais informações, consulte [FP16 Treinamento com paralelismo de modelos](model-parallel-extended-features-pytorch-fp16.md).

1. Empacotar o otimizador com [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 treinamento, você precisa configurar a escala de perda estática ou dinâmica. Para obter mais informações, consulte [FP16 Treinamento com paralelismo de modelos](model-parallel-extended-features-pytorch-fp16.md).

1. Use o objeto `DistributedModel` retornado em vez de um modelo de usuário.

1. Coloque a lógica para frente e para trás em uma step function e decore-a com [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 processo ao seu próprio dispositivo por meio de `torch.cuda.set_device(smp.local_rank())`.

1. Mova os tensores de entrada para a GPU usando a API do `.to()` antes da chamada do `smp.step` (veja o exemplo abaixo).

1. Substitua o `torch.Tensor.backward` e o `torch.autograd.backward` pelo `DistributedModel.backward`.

1. Execute o pós-processamento nas saídas em microlotes usando 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. Se houver uma etapa de avaliação, coloque logicamente a frente (forward) dentro de uma função decorada com `smp.step` e processe os resultados usando a [API do `StepOutput`](https://sagemaker.readthedocs.io/en/v2.199.0/api/training/smp_versions/v1.2.0/smd_model_parallel_common_api.html#StepOutput).

1. Defina `drop_last=True` em `DataLoader`. Como alternativa, pule manualmente um lote no ciclo de treinamento se o tamanho do lote não for divisível pelo número de microlotes.

[Para saber mais sobre a API SageMaker da biblioteca de paralelismo de modelos, consulte a documentação da 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)
```

## Divisão manual com PyTorch
<a name="model-parallel-customize-training-script-pt-16-hvd"></a>

Use gerenciadores de contexto do [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 em dispositivos específicos. Qualquer operação não colocada em qualquer contexto `smp.partition` é colocada no `default_partition`. O `default_partition` precisa ser fornecido se o `auto_partition` estiver definido como `False`. Os módulos criados em um contexto `smp.partition` específico são colocados na partição correspondente.

[Para saber mais sobre a API SageMaker da biblioteca de paralelismo de modelos, consulte a documentação da 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)
```

## Considerações
<a name="model-parallel-pt-considerations"></a>

Ao configurar um script de PyTorch treinamento usando a biblioteca SageMaker de paralelismo de modelos da, você deve estar ciente do seguinte:
+ Se você estiver usando uma técnica de otimização que depende de normas de gradiente globais, por exemplo, a norma de gradiente de todo o modelo, como algumas variantes do otimizador LAMB ou o clipping global de gradiente, é necessário reunir todas as normas nas partições do modelo para garantir a correção. Você pode usar os tipos de dados básicos de comunicação da biblioteca para fazer isso.
+ Todos os argumentos do `torch.Tensor` para os métodos diretos do `nn.Modules` em seu modelo devem ser usados no cálculo da saída do módulo. Em outras palavras, a biblioteca não suporta o caso em que há um argumento do `torch.Tensor` para um módulo do qual a saída do módulo não depende.
+ O argumento para a chamada `smp.DistributedModel.backward()` deve depender de todas as saídas do modelo. Em outras palavras, não pode haver uma saída da chamada `smp.DistributedModel.forward` que não seja usada no cálculo do tensor que é alimentado na chamada `smp.DistributedModel.backward`.
+ Se houver chamadas `torch.cuda.synchronize()` em seu código, talvez seja necessário ligar `torch.cuda.set_device(smp.local_rank())` imediatamente antes da chamada de sincronização. Caso contrário, contextos CUDA desnecessários podem ser criados no dispositivo 0, o que consumirá desnecessariamente memória.
+ Dado que a biblioteca coloca `nn.Modules` em dispositivos diferentes, os módulos no modelo não devem depender de nenhum estado global que seja modificado dentro de `smp.step`. Qualquer estado que permaneça constante ao longo do treinamento, ou que seja modificado fora de `smp.step` de uma maneira que seja visível para todos os processos, é permitido.
+ Você não precisa mover o modelo para a GPU (por exemplo, usando`model.to(device)`) ao usar a biblioteca. Se você tentar mover o modelo para a GPU antes que o modelo seja particionado (antes da primeira chamada `smp.step`), a chamada de movimentação será ignorada. A biblioteca move automaticamente a parte do modelo atribuída a uma classificação para sua GPU. Quando o treinamento com a biblioteca começar, não mova o modelo para a CPU e o utilize, pois ele não terá os parâmetros corretos para módulos não atribuídos à partição mantida pelo processo. Se você quiser treinar novamente um modelo ou usá-lo para inferência sem a biblioteca depois de treiná-lo usando a biblioteca de paralelismo de modelos, a maneira recomendada é salvar o modelo completo usando nossa API de ponto de verificação e carregá-lo de volta em um módulo normal. PyTorch 
+ Se você tem uma lista de módulos de forma que a saída de um alimenta o próximo, substituir essa lista por `nn.Sequential` pode melhorar significativamente a performance.
+ A atualização dos pesos (`optimizer.step()`) precisa ocorrer fora de `smp.step`, porque é nesse momento que toda a passagem de retropropagação é concluída e os gradientes estão prontos. Ao usar um modelo híbrido com paralelismo de modelos e dados, neste ponto, também é garantido o AllReduce término dos gradientes.
+ Ao usar a biblioteca em combinação com o paralelismo de dados, certifique-se de que o número de lotes em todas as classificações paralelas de dados seja o mesmo para que você AllReduce não fique esperando por uma classificação que não esteja participando da etapa.
+ Se você iniciar um trabalho de treinamento usando um tipo de instância ml.p4d (como ml.p4d.24xlarge), é necessário definir a variável do carregador de dados `num_workers=0`. Por exemplo, é possível definir o seu `DataLoader` da seguinte forma.

  ```
  dataloader = torch.utils.data.DataLoader(
              data,
              batch_size=batch_size,
              num_workers=0,
              pin_memory=True,
              drop_last=True,
              shuffle=shuffle,
          )
  ```
+ As entradas para `smp.step` devem ser as entradas do modelo geradas pelo `DataLoader`. Isso ocorre porque divide `smp.step` internamente os tensores de entrada ao longo da dimensão do lote e os canaliza. Isso significa que passar a `DataLoader` si mesmo para a função `smp.step` para gerar as entradas internas do modelo não funciona. 

  Por exemplo, se definir um `DataLoader` da seguinte forma.

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

  Você deve acessar as entradas do modelo geradas `train_loader` e passá-las para uma função `smp.step` decorada. Não passe `train_loader` diretamente para a função `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
  ```
+ Os tensores de entrada `smp.step` devem ser movidos para o dispositivo atual usando a API do `.to()`, que deve ocorrer após a chamada `torch.cuda.set_device(local_rank())`.

  Por exemplo, é possível definir a função `train` da seguinte forma. Essa função adiciona `data` e `target` ao dispositivo atual usando a API do `.to()` antes de usar esses tensores de entrada para chamar `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()
  ```

  Os tensores de entrada para essa função `smp.set` decorada foram movidos para o dispositivo atual na função `train` acima. O modelo *não* precisa ser movido para o dispositivo atual. A biblioteca move automaticamente a parte do modelo atribuída a uma classificação para sua 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
  ```

## Recursos de framework incompatíveis
<a name="model-parallel-pt-unsupported-features"></a>

Os seguintes PyTorch recursos não são compatíveis com a biblioteca de SageMaker paralelismo de modelos da:
+ Se você usa paralelismo de dados com o [PyTorch DDP](https://pytorch.org/tutorials/intermediate/ddp_tutorial.html) nativo, o módulo [https://pytorch.org/docs/stable/generated/torch.nn.parallel.DistributedDataParallel.html](https://pytorch.org/docs/stable/generated/torch.nn.parallel.DistributedDataParallel.html)wrapper não é suportado pela biblioteca. A biblioteca gerencia internamente a integração com o PyTorch DDP, incluindo transmissão de parâmetros e gradiente. AllReduce Ao utilizar a biblioteca, os buffers do módulo são transmitidos apenas uma vez no início do treinamento. Se seu modelo tiver buffers de módulo que precisam ser sincronizados entre grupos paralelos de dados em cada etapa, você pode fazer isso por meio da API do `torch.distributed`, usando o grupo de processos que pode ser obtido por meio de `smp.get_dp_process_group()`.
+ Para treinamento de precisão mista, o módulo `apex.amp` não tem suporte. A maneira recomendada de usar a biblioteca com precisão mista automática é usar `torch.cuda.amp`, com exceção do uso de `smp.amp.GradScaler` em vez da implementação em torch.
+ `torch.jit.ScriptModules` e `ScriptFunctions` não têm suporte de `smp.DistributedModel`.
+ `apex` : `FusedLayerNorm`, `FusedAdam`, `FusedLAMB` e `FusedNovoGrad` do `apex` não têm suporte. Você pode usar as implementações de biblioteca deles por meio `smp.optimizers` e `smp.nn` APIs em vez disso.