Files
DataPipeline/pipeline/processors/dpo.py
T

80 lines
2.6 KiB
Python

"""DPO preference learning data processor."""
from typing import Any, Dict, List, Optional
import torch
from torch import Tensor
from pipeline.tokenize import AutoTokenizer
from pipeline.strategies import PromptStrategy, ChatMLStrategy
from pipeline.processors.base import BaseProcessor, ProcessorSchema, encode_with_mask
from pipeline.processors.factory import ProcessorFactory
@ProcessorFactory.register("dpo")
class DPOProcessor(BaseProcessor):
"""DPO (Direct Preference Optimization) data processor.
Processes query, chosen, and rejected responses for preference learning.
Input schema:
- query: str - User query/prompt
- chosen: str - Preferred assistant response
- rejected: str - Dispreferred assistant response
Output schema:
- chosen: int32 tensor - Token IDs for preferred response
- chosen_mask: bool tensor - True for response tokens
- rejected: int32 tensor - Token IDs for dispreferred response
- rejected_mask: bool tensor - True for response tokens
"""
def __init__(
self,
tokenizer: AutoTokenizer,
strategy: Optional[PromptStrategy] = None,
):
self.tokenizer = tokenizer
self.strategy = strategy or ChatMLStrategy(tokenizer)
@property
def schema(self) -> ProcessorSchema:
return ProcessorSchema(
input_fields={
"query": str,
"chosen": str,
"rejected": str,
},
output_fields={
"chosen": torch.int32,
"chosen_mask": torch.bool,
"rejected": torch.int32,
"rejected_mask": torch.bool,
},
)
def process(self, input_dict: Dict[str, Any]) -> Dict[str, Tensor]:
query_tokens = self.tokenizer.encode(input_dict["query"])
chosen_tokens = self.tokenizer.encode(input_dict["chosen"])
rejected_tokens = self.tokenizer.encode(input_dict["rejected"])
prompt = self.strategy.assemble_prompt(query_tokens)
chosen_t, chosen_m = encode_with_mask(
prompt, self.strategy.assemble_response(chosen_tokens)
)
rejected_t, rejected_m = encode_with_mask(
prompt, self.strategy.assemble_response(rejected_tokens)
)
return {
"chosen": chosen_t,
"chosen_mask": chosen_m,
"rejected": rejected_t,
"rejected_mask": rejected_m,
}
@property
def output_keys(self) -> List[str]:
return ["chosen", "chosen_mask", "rejected", "rejected_mask"]