aurora

Форк
0
/
trainer.py 
97 строк · 4.1 Кб
1
import os
2
import json
3
import torch
4
import numpy as np
5
import torch.nn as nn
6
from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Union
7
from transformers import Seq2SeqTrainer
8

9
from llmtuner.extras.constants import IGNORE_INDEX
10
from llmtuner.extras.logging import get_logger
11

12
if TYPE_CHECKING:
13
    from transformers.trainer import PredictionOutput
14

15

16
logger = get_logger(__name__)
17

18

19
class CustomSeq2SeqTrainer(Seq2SeqTrainer):
20
    r"""
21
    Inherits PeftTrainer to compute generative metrics such as BLEU and ROUGE.
22
    """
23

24
    def prediction_step(
25
        self,
26
        model: nn.Module,
27
        inputs: Dict[str, Union[torch.Tensor, Any]],
28
        prediction_loss_only: bool,
29
        ignore_keys: Optional[List[str]] = None,
30
    ) -> Tuple[Optional[float], Optional[torch.Tensor], Optional[torch.Tensor]]:
31
        r"""
32
        Removes the prompt part in the generated tokens.
33

34
        Subclass and override to inject custom behavior.
35
        """
36
        labels = inputs["labels"].detach().clone() if "labels" in inputs else None # backup labels
37
        if self.args.predict_with_generate:
38
            assert self.tokenizer.padding_side == "left", "This method only accepts left-padded tensor."
39
            prompt_len, label_len = inputs["input_ids"].size(-1), inputs["labels"].size(-1)
40
            if prompt_len > label_len:
41
                inputs["labels"] = self._pad_tensors_to_target_len(inputs["labels"], inputs["input_ids"])
42
            if label_len > prompt_len: # truncate the labels instead of padding the inputs (llama2 fp16 compatibility)
43
                inputs["labels"] = inputs["labels"][:, :prompt_len]
44

45
        loss, generated_tokens, _ = super().prediction_step( # ignore the returned labels (may be truncated)
46
            model, inputs, prediction_loss_only=prediction_loss_only, ignore_keys=ignore_keys
47
        )
48
        if generated_tokens is not None and self.args.predict_with_generate:
49
            generated_tokens[:, :prompt_len] = self.tokenizer.pad_token_id
50
            generated_tokens = generated_tokens.contiguous()
51

52
        return loss, generated_tokens, labels
53

54
    def _pad_tensors_to_target_len(
55
        self,
56
        src_tensor: torch.Tensor,
57
        tgt_tensor: torch.Tensor
58
    ) -> torch.Tensor:
59
        r"""
60
        Pads the tensor to the same length as the target tensor.
61
        """
62
        assert self.tokenizer.pad_token_id is not None, "Pad token is required."
63
        padded_tensor = self.tokenizer.pad_token_id * torch.ones_like(tgt_tensor)
64
        padded_tensor[:, -src_tensor.shape[-1]:] = src_tensor # adopt left-padding
65
        return padded_tensor.contiguous() # in contiguous memory
66

67
    def save_predictions(
68
        self,
69
        predict_results: "PredictionOutput"
70
    ) -> None:
71
        r"""
72
        Saves model predictions to `output_dir`.
73

74
        A custom behavior that not contained in Seq2SeqTrainer.
75
        """
76
        if not self.is_world_process_zero():
77
            return
78

79
        output_prediction_file = os.path.join(self.args.output_dir, "generated_predictions.jsonl")
80
        logger.info(f"Saving prediction results to {output_prediction_file}")
81

82
        labels = np.where(predict_results.label_ids != IGNORE_INDEX, predict_results.label_ids, self.tokenizer.pad_token_id)
83
        preds = np.where(predict_results.predictions != IGNORE_INDEX, predict_results.predictions, self.tokenizer.pad_token_id)
84

85
        for i in range(len(preds)):
86
            pad_len = np.nonzero(preds[i] != self.tokenizer.pad_token_id)[0]
87
            if len(pad_len):
88
                preds[i] = np.concatenate((preds[i][pad_len[0]:], preds[i][:pad_len[0]]), axis=-1) # move pad token to last
89

90
        decoded_labels = self.tokenizer.batch_decode(labels, skip_special_tokens=True, clean_up_tokenization_spaces=False)
91
        decoded_preds = self.tokenizer.batch_decode(preds, skip_special_tokens=True, clean_up_tokenization_spaces=True)
92

93
        with open(output_prediction_file, "w", encoding="utf-8") as writer:
94
            res: List[str] = []
95
            for label, pred in zip(decoded_labels, decoded_preds):
96
                res.append(json.dumps({"label": label, "predict": pred}, ensure_ascii=False))
97
            writer.write("\n".join(res))
98

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.