Skip to content
Back to skills

Carft Contrastive Reinforced Finetuning

ASecurity

Enhance LLM reasoning by combining contrastive learning on reasoning representations with reinforced fine-tuning, leveraging both annotated chains and unsupervised signals.

  • 6 stars
  • 0 votes
  • 0 copies
  • 3 views
  • Added September 9, 2026
ai-agentspythongogitperformance

Works with

  • cli

Security analysis

A100/100

Scanned September 9, 2026

npx -y skills add ADu2021/skillXiv --skill carft-contrastive-reinforced-finetuning --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Carft Contrastive Reinforced Finetuning?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Carft Contrastive Reinforced Finetuning
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/adu2021-carft-contrastive-reinforced-finetuning/badge)](https://www.skillsdirectory.com/skills/adu2021-carft-contrastive-reinforced-finetuning)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: carft-contrastive-reinforced-finetuning
title: "CARFT: Contrastive CoT Reinforced Fine-Tuning for LLM Reasoning"
version: 0.0.2
engine: skillxiv-v0.0.2-claude-opus-4.6
license: MIT
url: https://arxiv.org/abs/2508.15868
keywords: [contrastive-learning, chain-of-thought, reinforcement-learning, representation-learning, fine-tuning]
description: "Enhance LLM reasoning by combining contrastive learning on reasoning representations with reinforced fine-tuning, leveraging both annotated chains and unsupervised signals."
---

# CARFT: Contrastive CoT Reinforced Fine-Tuning

## Core Concept

CARFT addresses limitations in both vanilla RL (ignoring annotated reasoning) and SFT (over-relying on limited examples) by combining contrastive representation learning with reinforced fine-tuning. The approach learns discriminative representations for each chain-of-thought while designing contrastive signals to guide optimization. This dual approach stabilizes training, prevents model degradation, and achieves 10.15% performance gains with up to 30.62% efficiency improvements.

## Architecture Overview

- **Chain-of-Thought Representation Learning**: Embedding space for reasoning paths
- **Contrastive Signal Design**: Positive/negative pairs for discriminative learning
- **Reinforced Fine-Tuning**: RL objectives with contrastive regularization
- **Training Stability**: Prevents both over-fitting and catastrophic forgetting
- **Efficiency Gains**: Reduced computational cost while improving performance

## Implementation Steps

### 1. Implement CoT Representation Learner

Learn embeddings for reasoning chains:

```python
import torch
import torch.nn as nn
import torch.nn.functional as F

class CoTRepresentationLearner(nn.Module):
    """Learn representations of chain-of-thought sequences."""

    def __init__(
        self,
        hidden_size: int = 768,
        output_dim: int = 256,
        num_layers: int = 2
    ):
        super().__init__()

        # Encoder for CoT sequences
        self.encoder = nn.Sequential(
            nn.Linear(hidden_size, 512),
            nn.ReLU(),
            nn.Linear(512, output_dim),
            nn.LayerNorm(output_dim)
        )

        # Projection heads for different loss objectives
        self.contrastive_proj = nn.Linear(output_dim, output_dim)
        self.quality_proj = nn.Linear(output_dim, 64)

    def encode_cot(self, hidden_states: torch.Tensor) -> torch.Tensor:
        """
        Encode chain-of-thought from hidden states.

        hidden_states: (seq_len, hidden_size) or (batch, seq_len, hidden_size)
        """
        # Use last hidden state or mean pooling
        if hidden_states.dim() == 3:
            # Batch of sequences: use mean pooling
            pooled = torch.mean(hidden_states, dim=1)
        else:
            pooled = hidden_states[-1]  # Last token

        # Encode to representation
        representation = self.encoder(pooled)
        return representation

    def compute_contrastive_projections(
        self,
        representations: torch.Tensor  # (batch, output_dim)
    ) -> Tuple[torch.Tensor, torch.Tensor]:
        """
        Compute projections for contrastive learning.
        """
        contrastive = self.contrastive_proj(representations)
        quality = self.quality_proj(representations)
        return contrastive, quality
```

### 2. Design Contrastive Signals

Create positive/negative pairs for discriminative learning:

```python
class ContrastiveSignalDesigner:
    """Design contrastive objectives for CoT learning."""

    def __init__(self, margin: float = 0.5):
        self.margin = margin

    def create_contrastive_pairs(
        self,
        correct_cots: List[torch.Tensor],
        incorrect_cots: List[torch.Tensor],
        task_diversity: Optional[List[str]] = None
    ) -> List[Dict[str, torch.Tensor]]:
        """
        Create positive and negative pairs for contrastive learning.

        Strategies:
        - Correct vs incorrect (basic)
        - Similar reasoning, different answers (harder negatives)
        - Same task vs different task (task-specific)
        """
        pairs = []

        # Basic: correct vs incorrect
        for correct in correct_cots:
            for incorrect in incorrect_cots:
                pairs.append({
                    "anchor": correct,
                    "positive": correct,  # Same correct CoT
                    "negative": incorrect,
                    "pair_type": "basic"
                })

        # Hard negatives: correct answer, wrong reasoning path
        # (In practice: identify these from training data)

        return pairs

    def compute_triplet_loss(
        self,
        anchor_repr: torch.Tensor,
        positive_repr: torch.Tensor,
        negative_repr: torch.Tensor,
        temperature: float = 0.07
    ) -> torch.Tensor:
        """
        Triplet loss: anchor should be closer to positive than negative.
        """
        # Normalize representations
        anchor_norm = F.normalize(anchor_repr, p=2, dim=-1)
        positive_norm = F.normalize(positive_repr, p=2, dim=-1)
        negative_norm = F.normalize(negative_repr, p=2, dim=-1)

        # Compute similarities
        pos_sim = torch.mm(anchor_norm, positive_norm.t()) / temperature
        neg_sim = torch.mm(anchor_norm, negative_norm.t()) / temperature

        # Triplet objective
        loss = torch.nn.functional.softplus(neg_sim - pos_sim + self.margin).mean()
        return loss

    def compute_in_batch_negatives_loss(
        self,
        representations: torch.Tensor,  # (batch, dim)
        labels: torch.Tensor,  # (batch,) class labels
        temperature: float = 0.07
    ) -> torch.Tensor:
        """
        Compute contrastive loss using in-batch negatives.
        """
        # Normalize
        representations = F.normalize(representations, p=2, dim=-1)

        # Compute similarity matrix
        logits = torch.mm(representations, representations.t()) / temperature

        # Create mask for positives (same label)
        mask = torch.eq(labels.unsqueeze(0), labels.unsqueeze(1))
        mask.fill_diagonal_(False)  # Exclude self

        # Compute loss
        pos_logits = logits[mask].view(logits.size(0), -1)
        neg_logits = logits[~mask].view(logits.size(0), -1)

        # LogSumExp trick for numerical stability
        loss = -torch.log(
            torch.exp(pos_logits).sum(dim=-1) /
            (torch.exp(pos_logits).sum(dim=-1) + torch.exp(neg_logits).sum(dim=-1) + 1e-8)
        ).mean()

        return loss
```

### 3. Implement CARFT Objective

Combine contrastive and RL losses:

```python
class CARFTLoss(nn.Module):
    """CARFT combined contrastive and RL loss."""

    def __init__(
        self,
        cot_learner: CoTRepresentationLearner,
        contrastive_weight: float = 0.5,
        rl_weight: float = 0.5,
        temperature: float = 0.07
    ):
        super().__init__()
        self.cot_learner = cot_learner
        self.contrastive_weight = contrastive_weight
        self.rl_weight = rl_weight
        self.temperature = temperature
        self.contrastive_designer = ContrastiveSignalDesigner()

    def forward(
        self,
        model_logits: torch.Tensor,  # (batch, seq_len, vocab_size)
        hidden_states: torch.Tensor,  # (batch, seq_len, hidden_size)
        labels: torch.Tensor,  # (batch, seq_len)
        rewards: torch.Tensor,  # (batch,) or (batch, seq_len)
        annotated_cots: Optional[torch.Tensor] = None
    ) -> Tuple[torch.Tensor, Dict[str, float]]:
        """
        Compute CARFT loss combining contrastive and RL objectives.
        """

        batch_size, seq_len, vocab_size = model_logits.shape

        # 1. RL Loss (standard policy gradient with reward)
        log_probs = F.log_softmax(model_logits, dim=-1)
        selected_log_probs = log_probs.gather(-1, labels.unsqueeze(-1)).squeeze(-1)

        if rewards.dim() == 1:
            # Broadcast scalar reward to sequence
            rewards_expanded = rewards.unsqueeze(-1).expand_as(selected_log_probs)
        else:
            rewards_expanded = rewards

        rl_loss = -(selected_log_probs * rewards_expanded).mean()

        # 2. Contrastive Loss (representation learning)
        representations = self.cot_learner.encode_cot(hidden_states)
        contrastive_projs, _ = self.cot_learner.compute_contrastive_projections(representations)

        # Use rewards as proxy for correctness labels
        correctness_labels = (rewards > 0.5).long()
        contrastive_loss = self.contrastive_designer.compute_in_batch_negatives_loss(
            contrastive_projs,
            correctness_labels,
            temperature=self.temperature
        )

        # 3. Annotated CoT regularization (if available)
        regularization_loss = 0.0
        if annotated_cots is not None:
            # Encourage representations to match annotated CoTs
            annotated_reprs = self.cot_learner.encode_cot(annotated_cots)
            annotated_projs, _ = self.cot_learner.compute_contrastive_projections(annotated_reprs)

            # MSE between predicted and annotated representations
            regularization_loss = F.mse_loss(contrastive_projs, annotated_projs)

        # Combine losses
        total_loss = (
            self.rl_weight * rl_loss +
            self.contrastive_weight * contrastive_loss +
            0.1 * regularization_loss
        )

        metrics = {
            "rl_loss": rl_loss.item(),
            "contrastive_loss": contrastive_loss.item(),
            "regularization_loss": regularization_loss.item() if isinstance(regularization_loss, torch.Tensor) else regularization_loss,
            "total_loss": total_loss.item()
        }

        return total_loss, metrics
```

### 4. Implement CARFT Training Loop

Integrate components into training procedure:

```python
class CARFTTrainer:
    def __init__(
        self,
        model: torch.nn.Module,
        cot_learner: CoTRepresentationLearner,
        carft_loss: CARFTLoss,
        optimizer: torch.optim.Optimizer,
        learning_rate: float = 1e-5
    ):
        self.model = model
        self.cot_learner = cot_learner
        self.carft_loss = carft_loss
        self.optimizer = optimizer

    def train_step(
        self,
        batch_inputs: torch.Tensor,
        batch_labels: torch.Tensor,
        batch_rewards: torch.Tensor,
        annotated_cots: Optional[torch.Tensor] = None
    ) -> Dict[str, float]:
        """Execute single CARFT training step."""

        # Forward pass
        outputs = self.model(
            batch_inputs,
            output_hidden_states=True
        )
        logits = outputs.logits
        hidden_states = outputs.hidden_states[-1]  # Last layer

        # Compute CARFT loss
        loss, metrics = self.carft_loss(
            logits,
            hidden_states,
            batch_labels,
            batch_rewards,
            annotated_cots
        )

        # Optimize
        self.optimizer.zero_grad()
        loss.backward()
        torch.nn.utils.clip_grad_norm_(self.model.parameters(), 1.0)
        torch.nn.utils.clip_grad_norm_(self.cot_learner.parameters(), 1.0)
        self.optimizer.step()

        return metrics

    def train_epoch(
        self,
        train_dataloader,
        num_epochs: int = 1
    ) -> List[Dict[str, float]]:
        """Train for multiple epochs."""

        all_metrics = []

        for epoch in range(num_epochs):
            for batch in train_dataloader:
                batch_inputs = batch["input_ids"].to(self.device)
                batch_labels = batch["labels"].to(self.device)
                batch_rewards = batch["rewards"].to(self.device)
                annotated_cots = batch.get("annotated_cots")
                if annotated_cots is not None:
                    annotated_cots = annotated_cots.to(self.device)

                metrics = self.train_step(
                    batch_inputs,
                    batch_labels,
                    batch_rewards,
                    annotated_cots
                )
                all_metrics.append(metrics)

        return all_metrics
```

### 5. Validate Training with Metrics

Monitor improvement from CARFT:

```python
def evaluate_carft(
    model: torch.nn.Module,
    cot_learner: CoTRepresentationLearner,
    test_examples: List[Dict],
    baseline_model: torch.nn.Module
) -> Dict[str, float]:
    """
    Compare CARFT-trained model against baseline.
    """
    model.eval()
    baseline_model.eval()

    carft_correct = 0
    baseline_correct = 0
    carft_steps = 0
    baseline_steps = 0

    with torch.no_grad():
        for example in test_examples:
            prompt = example["prompt"]
            expected = example["expected"]

            # CARFT model
            carft_output = model.generate(prompt, max_length=500)
            carft_answer = extract_answer(carft_output)
            carft_correct += (carft_answer == expected)
            carft_steps += len(carft_output.split())

            # Baseline
            baseline_output = baseline_model.generate(prompt, max_length=500)
            baseline_answer = extract_answer(baseline_output)
            baseline_correct += (baseline_answer == expected)
            baseline_steps += len(baseline_output.split())

    carft_accuracy = carft_correct / len(test_examples)
    baseline_accuracy = baseline_correct / len(test_examples)

    return {
        "carft_accuracy": carft_accuracy,
        "baseline_accuracy": baseline_accuracy,
        "accuracy_improvement": carft_accuracy - baseline_accuracy,
        "efficiency_gain": 1.0 - (carft_steps / baseline_steps),
        "carft_avg_steps": carft_steps / len(test_examples),
        "baseline_avg_steps": baseline_steps / len(test_examples)
    }
```

## Practical Guidance

### When to Use CARFT

- Training with both annotated reasoning chains and reward signals
- Tasks where training stability is critical
- Scenarios with limited annotation but good reward signals
- Mathematical or logical reasoning tasks
- Multi-step problem solving

### When NOT to Use

- Pure supervised learning without rewards
- Minimal annotated data available
- Tasks without clear reasoning chains
- Real-time training scenarios

### Key Hyperparameters

- **contrastive_weight**: 0.3-0.7 (balance with RL)
- **rl_weight**: 0.3-0.7
- **temperature**: 0.05-0.1 (lower = sharper contrasts)
- **margin**: 0.3-0.7 (triplet loss margin)
- **learning_rate**: 1e-5 to 1e-4

### Performance Expectations

- Accuracy Improvement: +10.15%
- Efficiency Gains: Up to 30.62% cost reduction
- Training Stability: Reduced variance vs. vanilla RL
- Convergence: Typically 1-3 epochs

## Reference

Researchers. (2024). CARFT: Boosting LLM Reasoning via Contrastive CoT Reinforced Fine-Tuning. arXiv preprint arXiv:2508.15868.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.