Skip to content
Back to skills

Clipo Contrastive Policy Optimization

ASecurity

Augment verifiable reward RL (RLVR) with contrastive learning to generate dense auxiliary rewards. Enforce proximity among correct reasoning trajectories in embedding space while suppressing errors, amplifying invariant reasoning patterns.

  • 6 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 9, 2026
toolspythongogit

Works with

  • cli

Security analysis

A100/100

Scanned September 9, 2026

npx -y skills add ADu2021/skillXiv --skill clipo-contrastive-policy-optimization --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Clipo Contrastive Policy Optimization?

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

Security grade badge for Clipo Contrastive Policy Optimization
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/adu2021-clipo-contrastive-policy-optimization/badge)](https://www.skillsdirectory.com/skills/adu2021-clipo-contrastive-policy-optimization)

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: clipo-contrastive-policy-optimization
title: "CLIPO: Contrastive Learning in Policy Optimization Generalizes RLVR"
version: 0.0.2
engine: skillxiv-v0.0.2-claude-opus-4.6
license: MIT
url: "https://arxiv.org/abs/2603.10101"
keywords: [RLVR, Contrastive Learning, Policy Optimization, Reasoning, Dense Rewards]
description: "Augment verifiable reward RL (RLVR) with contrastive learning to generate dense auxiliary rewards. Enforce proximity among correct reasoning trajectories in embedding space while suppressing errors, amplifying invariant reasoning patterns."
---

# Technique: Dense Contrastive Rewards for Reasoning Trajectory Clustering

Sparse verifiable rewards (binary success/failure) provide limited training signal for complex reasoning tasks. CLIPO adds **contrastive learning** as an auxiliary objective: it embeds reasoning trajectories in latent space and applies InfoNCE loss to cluster correct responses together while repelling errors.

The insight is that successful reasoning paths share consistent underlying logic structures. By enforcing this structure in embedding space, contrastive learning acts as a denoising mechanism, amplifying invariant reasoning patterns while suppressing spurious shortcuts and hallucinations.

## Core Concept

CLIPO extends RLVR policy optimization algorithms (GRPO, GSPO, DAPO, GMPO) by introducing a lightweight contrastive head and auxiliary reward:

1. **Contrastive Head**: Projects reasoning trajectories to embedding space
2. **InfoNCE Loss**: Treats correct responses as positives, incorrect as negatives
3. **Dense Auxiliary Reward**: Converted contrastive loss to reward signal
4. **Combined Loss**: Final reward = verifiable reward + contrastive reward

This dual signal prevents optimization collapse on narrow heuristics while maintaining grounding in task-specific verifiable rewards.

## Architecture Overview

- **Trajectory encoder**: Linear or small MLP embedding trajectories
- **Contrastive head**: Projects to (typically) 256-512 dimensional embedding space
- **InfoNCE comparator**: Computes similarity matrices and contrastive loss
- **Reward converter**: Translates contrastive loss to auxiliary signal
- **Main policy**: Unchanged from baseline RLVR method

## Implementation Steps

### Step 1: Build Trajectory Encoder and Contrastive Head

Create embeddings for reasoning trajectories by processing token hidden states.

```python
import torch
import torch.nn as nn

class TrajectoryContrastiveHead(nn.Module):
    def __init__(self, hidden_dim, embedding_dim=256, projection_dim=128):
        super().__init__()
        # Encode trajectory via mean pooling + projection
        self.projection = nn.Linear(hidden_dim, projection_dim)
        self.contrastive_head = nn.Sequential(
            nn.Linear(projection_dim, embedding_dim),
            nn.ReLU(),
            nn.Linear(embedding_dim, projection_dim)
        )

    def forward(self, hidden_states):
        """
        hidden_states: (batch_size, seq_len, hidden_dim)
        returns: (batch_size, projection_dim) embeddings
        """
        # Mean pooling over sequence dimension
        trajectory_repr = hidden_states.mean(dim=1)  # (batch, hidden_dim)

        # Project through network
        projected = self.projection(trajectory_repr)
        embedding = self.contrastive_head(projected)

        return embedding
```

### Step 2: Compute InfoNCE Contrastive Loss

Within each batch, group by correctness and compute contrastive pairs.

```python
def infonce_loss(embeddings, labels, temperature=0.1):
    """
    InfoNCE loss for trajectory embeddings.

    embeddings: (batch_size, embedding_dim)
    labels: (batch_size,) binary correctness labels
    temperature: temperature parameter for softmax
    """
    batch_size = embeddings.shape[0]

    # Normalize embeddings
    embeddings = torch.nn.functional.normalize(embeddings, dim=1)

    # Compute similarity matrix
    similarity_matrix = torch.mm(embeddings, embeddings.t()) / temperature

    # Create positive and negative masks
    labels_expanded = labels.unsqueeze(1)
    positive_mask = (labels_expanded == labels_expanded.t()).float()

    # Set diagonal (self-similarity) to 0 for positive mask
    positive_mask.fill_diagonal_(0)

    # Negative mask is complement
    negative_mask = 1.0 - positive_mask
    negative_mask.fill_diagonal_(0)

    # InfoNCE: log(exp(sim_pos) / sum(exp(sim_neg)))
    exp_sim = torch.exp(similarity_matrix)

    # Sum of positive similarities per row
    pos_sum = (exp_sim * positive_mask).sum(dim=1, keepdim=True)

    # Sum of negative similarities per row
    neg_sum = (exp_sim * negative_mask).sum(dim=1, keepdim=True)

    # InfoNCE loss (avoiding division by zero)
    infonce = -torch.log(
        (pos_sum + 1e-8) / (pos_sum + neg_sum + 1e-8)
    )

    return infonce.mean()
```

### Step 3: Convert Contrastive Loss to Auxiliary Reward

Transform contrastive objective into a dense reward signal that complements verifiable reward.

```python
def contrastive_reward(
    embeddings,
    labels,
    verifiable_rewards,
    contrastive_weight=0.5,
    temperature=0.1
):
    """
    Compute combined reward: verifiable + contrastive auxiliary.

    Returns dense reward per trajectory.
    """
    batch_size = embeddings.shape[0]

    # Normalize embeddings
    embeddings_norm = torch.nn.functional.normalize(embeddings, dim=1)

    # Compute similarity matrix
    similarity_matrix = torch.mm(embeddings_norm, embeddings_norm.t()) / temperature

    # Create positive mask (other correct trajectories)
    labels_expanded = labels.unsqueeze(1)
    positive_mask = (labels_expanded == labels_expanded.t()).float()
    positive_mask.fill_diagonal_(0)

    # Average positive similarity per trajectory
    pos_similarities = (similarity_matrix * positive_mask).sum(dim=1) / (
        positive_mask.sum(dim=1) + 1e-8
    )

    # Average negative similarity per trajectory
    negative_mask = 1.0 - positive_mask
    negative_mask.fill_diagonal_(0)
    neg_similarities = (similarity_matrix * negative_mask).sum(dim=1) / (
        negative_mask.sum(dim=1) + 1e-8
    )

    # Contrastive reward: pull positives, push negatives
    contrastive_reward_signal = pos_similarities - neg_similarities

    # Combine with verifiable reward
    total_reward = (
        verifiable_rewards +
        contrastive_weight * contrastive_reward_signal
    )

    return total_reward, contrastive_reward_signal
```

### Step 4: Integrate into RLVR Training Loop

Extend baseline policy optimization with contrastive auxiliary objective.

```python
def train_step_with_clipo(
    model,
    input_ids,
    verifiable_rewards,
    contrastive_head,
    policy_optimizer,
    contrastive_weight=0.5,
    temperature=0.1
):
    """
    Single training step combining RLVR with contrastive learning.
    """
    # Forward pass through model
    outputs = model(
        input_ids,
        output_hidden_states=True
    )

    # Extract trajectory embeddings
    hidden_states = outputs.hidden_states[-1]
    trajectory_embeddings = contrastive_head(hidden_states)

    # Compute correctness labels (binarize verifiable rewards)
    correctness_labels = (verifiable_rewards > 0).long()

    # Compute combined rewards
    total_rewards, contrastive_signal = contrastive_reward(
        trajectory_embeddings,
        correctness_labels,
        verifiable_rewards,
        contrastive_weight=contrastive_weight,
        temperature=temperature
    )

    # Policy gradient: GRPO style (placeholder)
    log_probs = outputs.logits.log_softmax(dim=-1)
    baseline = total_rewards.mean()
    advantages = total_rewards - baseline

    policy_loss = -(log_probs * advantages.unsqueeze(-1)).mean()

    # Backward pass
    policy_loss.backward()
    policy_optimizer.step()

    return {
        'policy_loss': policy_loss.item(),
        'contrastive_signal_mean': contrastive_signal.mean().item(),
        'total_reward_mean': total_rewards.mean().item()
    }
```

## Practical Guidance

**When to Use:**
- Complex reasoning tasks (MATH, GSM8K, competition-level problems)
- Distributions with spurious correlations that mislead optimization
- Scenarios where verifiable rewards alone lead to hallucinations
- Tasks requiring robust generalization to perturbed inputs

**When NOT to Use:**
- Simple classification with clean, unambiguous labels
- When correct solutions form disconnected regions (contrastive smoothness harmful)
- Extreme computational budget constraints (adds embedding computation)

**Hyperparameter Tuning:**
- **contrastive_weight**: 0.3-1.0; balance with task difficulty
- **temperature**: 0.05-0.2; lower sharpens contrastive distinctions
- **embedding_dim**: 128-512 depending on trajectory complexity
- **batch size**: Larger batches provide more negative samples

**Common Pitfalls:**
- Weight too high, overshadowing verifiable signals (verify with ablations)
- Temperature too low causing training instability (increase if loss oscillates)
- Insufficient positive pairs early in training (consider warm-up scheduling)
- Embedding space not well-aligned with task semantics

## Reference

[CLIPO paper on arXiv](https://arxiv.org/abs/2603.10101)

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…