

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

# 훈련 스크립트 내의 SageMaker 스마트 시프팅
<a name="train-smart-sifting-apply-to-script"></a>

SageMaker 스마트 시프팅 라이브러리는 [SageMaker AI 프레임워크 DLC](train-smart-sifting-what-is-supported.md#train-smart-sifting-supported-frameworks)로 패키징됩니다. 모델 훈련에 비교적 영향을 미치는 훈련 샘플에 대한 필터링 로직을 제공하며, 전체 데이터 샘플이 포함된 모델 훈련과 비교할 때 모델이 원하는 모델 정확도에 더 적은 훈련 샘플로 도달할 수 있습니다.

스마트 시프팅 도구를 훈련 스크립트에 구현하는 방법을 알아보려면 사용하는 프레임워크에 따라 다음 중 하나를 선택합니다.

**Topics**
+ [PyTorch 스크립트에 SageMaker 스마트 시프팅 적용](train-smart-sifting-apply-to-pytorch-script.md)
+ [Hugging Face Transformers 스크립트에 SageMaker 스마트 시프팅 적용](train-smart-sifting-apply-to-hugging-face-transformers-script.md)

# PyTorch 스크립트에 SageMaker 스마트 시프팅 적용
<a name="train-smart-sifting-apply-to-pytorch-script"></a>

이 지침은 훈련 스크립트를 사용하여 SageMaker 스마트 시프팅을 활성화하는 방법을 보여줍니다.

1. SageMaker 스마트 시프팅 인터페이스를 구성합니다.

   SageMaker 스마트 시프팅 라이브러리는 손실 값 감소에 미치는 영향이 적은 샘플을 필터링하는 데 도움이 되는 상대 임계값 손실 기반 샘플링 기술을 구현합니다. SageMaker 스마트 시프팅 알고리즘은 순방향 패스를 사용하여 모든 입력 데이터 샘플의 손실 값을 계산하고 이전 데이터의 손실 값에 대한 상대 백분위수를 계산합니다.

   다음 두 파라미터는 시프팅 구성 객체를 생성하기 위해 `RelativeProbabilisticSiftConfig` 클래스에 지정해야 하는 파라미터입니다.
   + `beta_value` 파라미터에 대한 훈련에 사용해야 하는 데이터의 비율을 지정합니다.
   + `loss_history_length` 파라미터와의 비교에 사용되는 샘플 수를 지정합니다.

   다음 코드 예제에서는 `RelativeProbabilisticSiftConfig` 클래스의 객체를 설정하는 방법을 보여줍니다.

   ```
   from smart_sifting.sift_config.sift_configs import (
       RelativeProbabilisticSiftConfig
       LossConfig
       SiftingBaseConfig
   )
   
   sift_config=RelativeProbabilisticSiftConfig(
       beta_value=0.5,
       loss_history_length=500,
       loss_based_sift_config=LossConfig(
            sift_config=SiftingBaseConfig(sift_delay=0)
       )
   )
   ```

   `loss_based_sift_config` 파라미터 및 관련 클래스에 대한 자세한 내용은 SageMaker 스마트 시프팅 Python SDK 참조 섹션의 [SageMaker 스마트 시프팅 구성 모듈](train-smart-sifting-pysdk-reference.md#train-smart-sifting-pysdk-base-config-modules) 섹션을 참조하세요.

   위 코드 예제의 `sift_config` 객체는 `SiftingDataloader` 클래스를 설정하는 데 4단계에서 사용됩니다.

1. (선택 사항) SageMaker 스마트 시프팅 배치 변환 클래스를 구성합니다.

   다양한 훈련 사용 사례에는 다양한 훈련 데이터 형식이 필요합니다. 다양한 데이터 형식을 고려할 때 SageMaker 스마트 시프팅 알고리즘은 특정 배치에서 시프팅을 수행하는 방법을 식별해야 합니다. 이를 해결하기 위해 SageMaker 스마트 시프팅은 배치를 효율적으로 시프팅할 수 있는 표준화된 형식으로 변환하는 데 도움이 되는 배치 변환 모듈을 제공합니다.

   1. SageMaker 스마트 시프팅은 Python 목록, 사전, 튜플 및 텐서 형식으로 훈련 데이터의 배치 변환을 처리합니다. 이러한 데이터 형식의 경우 SageMaker 스마트 시프팅은 배치 데이터 형식 변환을 자동으로 처리하며 이 단계의 나머지 부분을 건너뛸 수 있습니다. 이 단계를 건너뛰면 `SiftingDataloader` 구성에 대한 4단계에서 `SiftingDataloader`의 `batch_transforms` 파라미터를 기본값인 `None`로 둡니다.

   1. 데이터세트가 이러한 형식이 아닌 경우 이 단계의 나머지 부분으로 이동하여 `SiftingBatchTransform`를 사용하여 사용자 지정 배치 변환을 생성해야 합니다.

      데이터세트가 SageMaker 스마트 시프팅에서 지원하는 형식 중 하나에 속하지 않는 경우 오류가 발생할 수 있습니다. 이러한 데이터 형식 오류는 4단계에서 설정한 `SiftingDataloader` 클래스에 `batch_format_index` 또는 `batch_transforms` 파라미터를 추가하여 해결할 수 있습니다. 다음은 호환되지 않는 데이터 형식 및 해상도로 인한 오류의 예입니다.    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/ko_kr/sagemaker/latest/dg/train-smart-sifting-apply-to-pytorch-script.html)

      앞서 언급한 문제를 해결하려면 `SiftingBatchTransform` 모듈을 사용하여 사용자 지정 배치 변환 클래스를 생성해야 합니다. 배치 변환 클래스는 한 쌍의 변환 및 역변환 함수로 구성되어야 합니다. 함수 페어는 데이터 형식을 SageMaker 스마트 시프팅 알고리즘이 처리할 수 있는 형식으로 변환합니다. 배치 변환 클래스를 생성한 후 클래스는 4단계에서 `SiftingDataloader` 클래스에 전달할 `SiftingBatch` 객체를 반환합니다.

      다음은 `SiftingBatchTransform` 모듈의 사용자 지정 배치 변환 클래스의 예입니다.
      + 데이터 로더 청크에 입력, 마스크 및 레이블이 있는 경우 SageMaker 스마트 시프팅을 사용한 사용자 지정 목록 배치 변환 구현의 예입니다.

        ```
        from typing import Any
        
        import torch
        
        from smart_sifting.data_model.data_model_interface import SiftingBatchTransform
        from smart_sifting.data_model.list_batch import ListBatch
        
        class ListBatchTransform(SiftingBatchTransform):
            def transform(self, batch: Any):
                inputs = batch[0].tolist()
                labels = batch[-1].tolist()  # assume the last one is the list of labels
                return ListBatch(inputs, labels)
        
            def reverse_transform(self, list_batch: ListBatch):
                a_batch = [torch.tensor(list_batch.inputs), torch.tensor(list_batch.labels)]
                return a_batch
        ```
      + 역변환에 레이블이 필요하지 않은 경우 SageMaker 스마트 시프팅을 사용한 사용자 지정 목록 배치 변환 구현의 예입니다.

        ```
        class ListBatchTransformNoLabels(SiftingBatchTransform):
            def transform(self, batch: Any):
                return ListBatch(batch[0].tolist())
        
            def reverse_transform(self, list_batch: ListBatch):
                a_batch = [torch.tensor(list_batch.inputs)]
                return a_batch
        ```
      + 데이터 로더 청크에 입력, 마스크 및 레이블이 있는 경우 SageMaker 스마트 체이스팅을 사용한 사용자 지정 텐서 배치 구현의 예입니다.

        ```
        from typing import Any
        
        from smart_sifting.data_model.data_model_interface import SiftingBatchTransform
        from smart_sifting.data_model.tensor_batch import TensorBatch
        
        class TensorBatchTransform(SiftingBatchTransform):
            def transform(self, batch: Any):
                a_tensor_batch = TensorBatch(
                    batch[0], batch[-1]
                )  # assume the last one is the list of labels
                return a_tensor_batch
        
            def reverse_transform(self, tensor_batch: TensorBatch):
                a_batch = [tensor_batch.inputs, tensor_batch.labels]
                return a_batch
        ```

      `SiftingBatchTransform` 구현 배치 변환 클래스를 생성한 후 4단계에서 이 클래스를 사용하여 `SiftingDataloader` 클래스를 설정합니다. 이 가이드의 나머지 부분에서는 `ListBatchTransform` 클래스가 생성되었다고 가정합니다. 4단계에서는 이 클래스가 `batch_transforms`로 전달됩니다.

1. SageMaker 스마트 시프팅 `Loss` 인터페이스를 구현하기 위한 클래스를 생성합니다. 이 자습서에서는 클래스의 이름이 `SiftingImplementedLoss`라고 가정합니다. 이 클래스를 설정할 때는 모델 훈련 루프에서 동일한 손실 함수를 사용하는 것이 좋습니다. SageMaker 스마트 시프팅 `Loss` 구현 클래스를 생성하기 위한 다음 하위 단계를 살펴봅니다.

   1. SageMaker 스마트 시프팅은 배치에 대한 단일 손실 값을 계산하는 대신 각 훈련 데이터 샘플에 대한 손실 값을 계산합니다. SageMaker 스마트 시프팅이 동일한 손실 계산 로직을 사용하도록 하려면 손실 함수를 사용하고 훈련 샘플당 손실을 계산하는 SageMaker 스마트 시프팅 `Loss` 모듈을 사용하여 스마트 시프팅 구현 손실 함수를 생성합니다.
**작은 정보**  
SageMaker 스마트 시프팅 알고리즘은 전체 배치가 아닌 모든 데이터 샘플에서 실행되므로 축소 전략 없이 PyTorch 손실 함수를 설정하려면 초기화 함수를 추가해야 합니다.  

      ```
      class SiftingImplementedLoss(Loss):  
          def __init__(self):
              self.loss = torch.nn.CrossEntropyLoss(reduction='none')
      ```
이는 다음 코드 예제에서도 볼 수 있습니다.

   1. `original_batch`(또는 2단계에서 배치 변환을 설정한 경우 `transformed_batch`) 및 PyTorch 모델을 수락하는 손실 함수를 정의합니다. SageMaker 스마트 시프팅은 지정된 손실 함수를 감소 없이 사용하여 각 데이터 샘플에 대한 순방향 패스를 실행하여 손실 값을 평가합니다.

   다음 코드는 `SiftingImplementedLoss`라는 스마트 시프팅 구현 `Loss` 인터페이스의 예입니다.

   ```
   from typing import Any
   
   import torch
   import torch.nn as nn
   from torch import Tensor
   
   from smart_sifting.data_model.data_model_interface import SiftingBatch
   from smart_sifting.loss.abstract_sift_loss_module import Loss
   
   model=... # a PyTorch model based on torch.nn.Module
   
   class SiftingImplementedLoss(Loss):   
       # You should add the following initializaztion function 
       # to calculate loss per sample, not per batch.
       def __init__(self):
           self.loss_no_reduction = torch.nn.CrossEntropyLoss(reduction='none')
   
       def loss(
           self,
           model: torch.nn.Module,
           transformed_batch: SiftingBatch,
           original_batch: Any = None,
       ) -> torch.Tensor:
           device = next(model.parameters()).device
           batch = [t.to(device) for t in original_batch] # use this if you use original batch and skipped step 2
           # batch = [t.to(device) for t in transformed_batch] # use this if you transformed batches in step 2
   
           # compute loss
           outputs = model(batch)
           return self.loss_no_reduction(outputs.logits, batch[2])
   ```

   훈련 루프가 실제 순방향 패스에 도달하기 전에 이 시프팅 손실 계산은 각 반복에서 배치를 가져오는 데이터 로드 단계에서 수행됩니다. 그런 다음 개별 손실 값을 이전 손실 값과 비교하고 상대 백분위수는 1단계에서 설정한 `RelativeProbabilisticSiftConfig` 객체당 추정됩니다.

1. SageMaker AI `SiftingDataloader` 클래스로 PyTroch 데이터 로더를 래핑합니다.

   마지막으로 이전 단계에서 구성한 모든 SageMaker 스마트 시프팅 구현 클래스를 SageMaker AI `SiftingDataloder` 구성 클래스에 사용합니다. 이 클래스는 PyTorch [https://pytorch.org/docs/stable/data.html#torch.utils.data.DataLoader](https://pytorch.org/docs/stable/data.html#torch.utils.data.DataLoader)의 래퍼입니다. PyTorch `DataLoader`를 래핑하면 SageMaker 스마트 시프팅이 PyTorch 훈련 작업의 각 반복에서 데이터 로드의 일부로 실행되도록 등록됩니다. 다음 코드 예시는 PyTorch `DataLoader`에 SageMaker AI 데이터 시프팅을 구현하는 방법을 보여줍니다.

   ```
   from smart_sifting.dataloader.sift_dataloader import SiftingDataloader
   from torch.utils.data import DataLoader
   
   train_dataloader = DataLoader(...) # PyTorch data loader
   
   # Wrap the PyTorch data loader by SiftingDataloder
   train_dataloader = SiftingDataloader(
       sift_config=sift_config, # config object of RelativeProbabilisticSiftConfig
       orig_dataloader=train_dataloader,
       batch_transforms=ListBatchTransform(), # Optional, this is the custom class from step 2
       loss_impl=SiftingImplementedLoss(), # PyTorch loss function wrapped by the Sifting Loss interface
       model=model,
       log_batch_data=False
   )
   ```

# Hugging Face Transformers 스크립트에 SageMaker 스마트 시프팅 적용
<a name="train-smart-sifting-apply-to-hugging-face-transformers-script"></a>

SageMaker 스마트 시프팅을 Transformers `Trainer` 클래스에 구현하는 방법은 두 가지가 있습니다.

**참고**  
SageMaker 스마트 시프팅 패키지가 설치된 상태에서 PyTorch용 DLC 중 하나를 사용하는 경우 `transformers` 라이브러리를 설치해야 합니다. SageMaker AI Python SDK에서 [DLC를 확장](prebuilt-containers-extend.md)하거나 PyTorch([https://sagemaker.readthedocs.io/en/stable/frameworks/pytorch/sagemaker.pytorch.html](https://sagemaker.readthedocs.io/en/stable/frameworks/pytorch/sagemaker.pytorch.html))에 대한 훈련 작업 시작 관리자 클래스로 `requirements.txt`를 전달하여 추가 패키지를 설치할 수 있습니다.

## 간단한 설정
<a name="train-smart-sifting-apply-to-hugging-face-transformers-script-simple"></a>

SageMaker 스마트 시프팅을 Transformers `Trainer` 클래스에 구현하는 가장 간단한 방법은 `enable_sifting` 함수를 사용하는 것입니다. 이 함수는 기존 `Trainer` 객체를 수락하고 기존 `DataLoader` 객체를 `SiftingDataloader`로 래핑합니다. 동일한 훈련 객체를 계속 사용할 수 있습니다. 다음 예제 사용을 참조하세요.

```
from smart_sifting.integrations.trainer import enable_sifting
from smart_sifting.loss.abstract_sift_loss_module import Loss
from smart_sifting.sift_config.sift_configs import (
    RelativeProbabilisticSiftConfig
    LossConfig
    SiftingBaseConfig
)

class SiftingImplementedLoss(Loss):
   def loss(self, model, transformed_batch, original_batch):
        loss_fct = MSELoss(reduction="none") # make sure to set reduction to "none"
        logits = model.bert(**original_batch)
        return loss_fct(logits, original_batch.get("labels"))

sift_config = RelativeProbabilisticSiftConfig(
    beta_value=0.5,
    loss_history_length=500,
    loss_based_sift_config=LossConfig(
         sift_config=SiftingBaseConfig(sift_delay=0)
    )
)

trainer = Trainer(...)
enable_sifting(trainer, sift_config, loss=SiftingImplementedLoss()) # updates the trainer with Sifting Loss and config
trainer.train()
```

`SiftingDataloader` 클래스는 반복 가능한 데이터 로더입니다. 시프팅 중 무작위 샘플링으로 인해 결과 데이터세트의 정확한 크기를 미리 알 수 없습니다. 따라서 Hugging Face `Trainer`는 [`max_steps` 훈련 인수](https://huggingface.co/docs/transformers/main_classes/trainer#transformers.TrainingArguments.max_steps)를 예상합니다. 이 인수는 에폭 구성 파라미터 `num_train_epochs`를 재정의합니다. 원본 데이터 로더도 반복 가능했거나 훈련에서 `max_steps` 및 단일 에포크를 사용하는 경우 `SiftingDataloader`는 기존 데이터 로더와 동일하게 수행합니다. 원래 데이터 로더를 반복할 수 없거나 `max_steps`가 제공되지 않은 경우 Hugging Face Trainer는 다음과 유사한 오류 메시지를 생성할 수 있습니다.

```
args.max_steps must be set to a positive value if dataloader does not have a length,
was -1
```

이를 해결하기 위해 `enable_sifting` 함수는 선택적 `set_epochs` 파라미터를 제공합니다. 이렇게 하면 `Trainer` 클래스의 [num\$1train\$1epochs 인수](https://huggingface.co/docs/transformers/main_classes/trainer#transformers.TrainingArguments.num_train_epochs(float,)에서 제공하는 에폭 수를 사용하여 에폭으로 훈련하고 `max_steps`를 최대 시스템 정수로 설정하여 지정된 에폭이 완료될 때까지 훈련이 진행될 수 있습니다.

## 사용자 지정 설정
<a name="train-smart-sifting-apply-to-hugging-face-transformers-script-custom-trainer"></a>

SageMaker 스마트 시프팅 데이터로더의 사용자 지정 통합을 위해 사용자 지정 Hugging Face `Trainer` 클래스를 활용할 수 있습니다. `Trainer`의 하위 클래스 내에서 `get_train_dataloader()` 함수를 재정의하여 `SiftingDataloader` 클래스의 객체를 반환할 수 있습니다. 기존 사용자 지정 트레이너가 있는 사례의 경우 이 접근 방식은 침입성이 낮을 수 있지만 간단한 설정 옵션보다 코드를 변경해야 합니다. 다음은 사용자 지정 Hugging Face `Trainer` 클래스로 SageMaker 스마트 시프팅을 구현하는 예제입니다.

```
from smart_sifting.sift_config.sift_configs import (
    RelativeProbabilisticSiftConfig
    LossConfig
    SiftingBaseConfig
)
from smart_sifting.dataloader.sift_dataloader import SiftingDataloader
from smart_sifting.loss.abstract_sift_loss_module import Loss
from smart_sifting.data_model.data_model_interface import SiftingBatch, SiftingBatchTransform
from smart_sifting.data_model.list_batch import ListBatch

class SiftingListBatchTransform(SiftingBatchTransform):
    def transform(self, batch: Any):
        inputs = batch[0].tolist()
        labels = batch[-1].tolist()  # assume the last one is the list of labels
        return ListBatch(inputs, labels)

    def reverse_transform(self, list_batch: ListBatch):
        a_batch = [torch.tensor(list_batch.inputs), torch.tensor(list_batch.labels)]
        return a_batch

class SiftingImplementedLoss():
    # You should add the following initializaztion function 
    # to calculate loss per sample, not per batch.
    def __init__(self):
        self.celoss = torch.nn.CrossEntropyLoss(reduction='none')

    def loss(
        self,
        model: torch.nn.Module,
        transformed_batch: SiftingBatch,
        original_batch: Any = None,
    ) -> torch.Tensor:
        device = next(model.parameters()).device
        batch = [t.to(device) for t in original_batch]

        # compute loss
        outputs = model(batch)
        return self.celoss(outputs.logits, batch[2])

class SiftingImplementedTrainer(Trainer):
    def get_train_dataloader(self):
        dl = super().get_train_dataloader()

        sift_config = RelativeProbabilisticSiftConfig(
            beta_value=0.5,
            loss_history_length=500,
            loss_based_sift_config=LossConfig(
                sift_config=SiftingBaseConfig(sift_delay=0)
            )
        )

        return SiftingDataloader(
                sift_config=sift_config,
                orig_dataloader=dl,
                batch_transforms=SiftingListBatchTransform(),
                loss_impl=SiftingImplementedLoss(),
                model=self.model
        )
```

래핑된 `Trainer` 클래스를 사용하여 다음과 같이 객체를 생성합니다.

```
trainer = SiftingImplementedTrainer(
    model=model,
    args=training_args,
    train_dataset=small_train_dataset,
    eval_dataset=small_eval_dataset
)

trainer.train()
```