Reasoning Distillation: DeepSeek-R1 CoT Transfer Guide

The Problem: Why Pure Reinforcement Learning Fails on Small LLMs
In modern enterprise automation, complex coding agents, and high-frequency analytical pipelines like AiFetchly, foundation models are increasingly required to solve multi-constraint algorithmic tasks: formal logic deduction, multi-step math problem solving, and complex tool calling.
The emergence of frontier reasoning models—such as OpenAI o1/o3 and DeepSeek-R1—demonstrated that allocating dynamic compute during inference time (generating long internal thinking tokens before producing a final response) allows models to self-correct, explore competing hypotheses, and solve problems previously out of reach.
However, when engineering teams attempted to reproduce these reasoning breakthroughs by applying large-scale Reinforcement Learning—such as PPO (Proximal Policy Optimization) or GRPO (Group Relative Policy Optimization)—directly to small dense foundation models (1.5B, 7B, 14B, or 32B parameters), they hit three severe architectural roadblocks:
1. The Cold-Start Exploration Bottleneck in Sub-32B Models
Reinforcement Learning relies fundamentally on stochastic policy exploration:
- For a model to receive a reward signal on challenging mathematical benchmarks (such as AIME or Olympiad-level geometry), the policy must first generate at least one trajectory that accidentally discovers the correct solution.
- Frontier foundation models with hundreds of billions of parameters (like DeepSeek-V3 671B) possess rich pre-trained representations. When sampled at temperature $T \approx 0.7$, their policy occasionally produces viable intermediate proofs.
- In contrast, smaller base models (like Qwen-2.5 7B or LLaMA-3 8B) lack the raw parameter breadth required to stumble upon multi-thousand-token deductive chains.
- On difficult problems, over $99%$ of small-model rollouts fail completely, returning zero positive reward. With zero reward gradients, reinforcement learning stalls in a state of entropy collapse.
2. Degenerate Trajectories and Reward Hacking Loops
When small models are forced to generate long chains under outcome reward incentives, they frequently exploit degenerate optimization loopholes:
- Pseudo-Reasoning Rambling: The model repeats superficial transitional phrases (e.g., “Wait, let me rethink this… On the other hand… Actually…”) dozens of times without making mathematical progress, falsely imitating contemplation to maximize length incentives.
- Hallucinated Self-Corrections: The model identifies a correct intermediate step, falsely declares it wrong, and replaces it with an incorrect calculation.
- Language Entanglement: Small models often switch spontaneously between different languages mid-thought (mixing English and Chinese syntax), degrading token coherence.
3. The Prohibitive Cluster FLOPs Tax of Online RL
Training reasoning models through online RL requires running massive GPU clusters continuously:
- Every optimization step requires sampling groups of $G = 8$ to $16$ candidate outputs per prompt, evaluating them against external code sandboxes or verifiers, computing group-relative advantages, and updating policy weights.
- Generating millions of dynamic 8,000-token rollouts on 70B+ models costs hundreds of thousands of dollars in GPU compute.
- Smaller research labs and enterprise engineering teams cannot afford multi-week cluster runs solely to train domain-specific models.
The industry required an alternative methodology: Can we bypass the multi-million-dollar RL search process by directly distilling mature reasoning trajectories into small, efficient architectures?
The Architecture: DeepSeek-R1 Reasoning Distillation Pipeline
In their seminal technical report, DeepSeek revealed a historic finding: Supervised Fine-Tuning (SFT) on curated reasoning data generated by a massive teacher model (DeepSeek-R1 671B) vastly outperforms applying pure RL from scratch to small models.
Rather than forcing a 7B or 14B model to discover reasoning primitives through brute-force trial and error, Reasoning Distillation transfers the vocabulary, syntax, and cognitive rhythm of self-reflection directly into the student model’s weight matrices.

1. Frontier Teacher Rollouts with DeepSeek-R1 (671B MoE)
The distillation process begins with a fully trained frontier reasoning teacher—DeepSeek-R1:
- Prompts spanning mathematics (MATH, GSM8K, Olympiad problems), competitive programming (Codeforces, LeetCode), and formal logic are fed into the 671B parameter teacher.
- Sampling is performed at higher temperatures ($T = 0.6 \text{ to } 0.8$) to encourage the generation of diverse reasoning paths.
- For each problem, the teacher produces long-form reasoning trajectories ranging from 2,000 to 16,000 tokens.
2. Strict Semantic Delimitation via <think> Tokens
To prevent internal reasoning tokens from entangling with user-facing answers, the distillation pipeline enforces strict token demarcation:
User: Find all real solutions to the equation x^3 - 3x = 1.
Assistant: <think>
Let the given equation be x^3 - 3x - 1 = 0.
Recall the trigonometric identity for triple angles: cos(3theta) = 4cos^3(theta) - 3cos(theta).
Notice that x^3 - 3x looks very similar if we let x = 2*cos(theta)...
Wait, let me verify if 2^3*cos^3(theta) - 3*(2*cos(theta)) works:
8*cos^3(theta) - 6*cos(theta) = 2*(4*cos^3(theta) - 3*cos(theta)) = 2*cos(3theta).
Therefore, 2*cos(3theta) = 1, which implies cos(3theta) = 1/2.
This is valid because |1/2| <= 1.
The general solutions for 3theta are:
3theta = +/- pi/3 + 2k*pi.
Thus, theta = +/- pi/9 + 2k*pi/3.
Let me test k = 0, 1, 2 to find three distinct real roots...
All three roots fall within [-2, 2].
The solutions are verified.
</think>
The real solutions to the equation are:
x_1 = 2*cos(pi/9)
x_2 = 2*cos(7*pi/9)
x_3 = 2*cos(13*pi/9) - Cognitive Isolation: The
<think>and</think>tags create a structural boundary. - Production Cleanliness: In production serving engines, developers can stream or parse the contents inside
<think>for auditing, debugging, or UI accordions, while returning only the clean text after</think>to the end user.
3. Emergent Thinking Dynamics: Verification, Backtracking, and Aha Moments
Unlike traditional Chain-of-Thought (which simply states steps linearly without reflection), distilled trajectories exhibit dynamic self-correction:
- Hypothesis Formulation: The model proposes an initial line of attack.
- Sanity Verification: The model pauses mid-derivation to test an edge case or verify sign conventions (“Wait, let me check the boundary conditions…”).
- Backtracking: Upon discovering an inconsistency, the model explicitly abandons the doomed branch (“This leads to a contradiction because x must be positive. Let me try substituting u = x + 1/x instead.”).
- Convergence: The model arrives at a verified final conclusion.
When student models are trained on hundreds of thousands of these sequences, they internalize meta-cognitive routines—learning to allocate additional tokens to verify intermediate conclusions before committing to a final answer.
Deep Dive: Filtering, SFT Loss Masking, and Secondary Alignment
Distilling reasoning is not simply a matter of scraping raw teacher outputs. Unfiltered reasoning traces contain noise, dead loops, and formatting errors that degrade student models. DeepSeek implemented a rigorous multi-stage data curation and training architecture:
1. Verifiable Multi-Stage Filtering and Loop Truncation
DeepSeek filtered multi-million token rollouts down to 800,000 pristine training traces:
- Deterministic Outcome Verification: In mathematical and coding tasks, trajectories whose final answers do not match ground truth are strictly discarded using symbolic math engines (SymPy) or automated code sandbox execution.
- Intermediate Rationality Gating: Rejection sampling ensures that trajectories that arrived at the correct answer through a “lucky guess” (flawed intermediate logic followed by an accidental recovery) are eliminated.
- Anti-Rambling & Cycle Detection: Trajectories that spend thousands of tokens caught in repetitive loops are truncated or dropped.
- Language Consistency Filters: Sequences where the model arbitrarily flips languages mid-thought are sanitized.
2. Loss-Masked SFT on Packed Long-Context Sequences
During Supervised Fine-Tuning, student models are trained using causal language modeling with strict loss masking:
$$\mathcal{L}{\text{SFT}} = - \frac{1}{\sum{t=1}^T m_t} \sum_{t=1}^T m_t \log P(x_t \mid x_{<t})$$
Where $m_t \in {0, 1}$ is a binary token mask:
- $m_t = 0$ for all prompt tokens ($x_1, \dots, x_{\text{prompt}}$). The model is not penalized for prompt token reconstruction.
- $m_t = 1$ for all thinking tokens inside
<think> ... </think>and all final answer tokens. - Sequence Packing: Because reasoning traces are long (average $4\text{k}$ to $8\text{k}$ tokens), training pipelines pack multiple conversations into contiguous $16\text{k}$ or $32\text{k}$ token contexts using FlashAttention-3, eliminating wasted padding.
3. Secondary Preference Alignment: Taming the Overthinking Tax
While distilled SFT models score exceptionally high on benchmarks, they often suffer from the “Overthinking Tax”:
- When asked a trivial question (e.g., “What is 2 + 2?” or “Summarize this email”), an SFT-only reasoning model may generate 2,000 thinking tokens overanalyzing philosophical definitions of addition.
- To correct this, the distillation pipeline concludes with a lightweight secondary RL / DPO stage:
- The model is rewarded for producing concise answers to straightforward queries without unnecessary thinking loops.
- The model is penalized if it violates user-specified formatting constraints (e.g., “Provide the answer in JSON format”).
End-to-End Implementation: Building a Reasoning Distillation Dataset Curator & Loss Masker in PyTorch
Below is a complete, runnable reference implementation demonstrating how to parse raw reasoning traces, validate <think> tags, apply prompt loss masking, and prepare PyTorch batches for reasoning SFT.
import torch
import torch.nn as nn
from typing import List, Dict, Optional
import re
class ReasoningTraceParser:
"""
Validates and extracts thinking tokens and final answers from raw teacher outputs.
Enforces strict <think> ... </think> structural bounds.
"""
def __init__(self):
self.pattern = re.compile(r"<think>(.*?)</think>(.*)", re.DOTALL)
def parse_and_validate(self, text: str) -> Optional[Dict[str, str]]:
match = self.pattern.search(text)
if not match:
return None
thinking_process = match.group(1).strip()
final_answer = match.group(2).strip()
# Quality check: reject empty thinking or empty final answer
if len(thinking_process) < 10 or len(final_answer) < 1:
return None
# Anti-rambling heuristic: check for repetitive phrase loops
sentences = [s.strip() for s in thinking_process.split('.') if len(s.strip()) > 5]
if len(sentences) > 4:
unique_ratio = len(set(sentences)) / len(sentences)
if unique_ratio < 0.5: # Over 50% repetitive sentences detected
return None
return {
"thinking": thinking_process,
"answer": final_answer,
"formatted_target": f"<think>\n{thinking_process}\n</think>\n{final_answer}"
}
class ReasoningDataCollator:
"""
Collate function for PyTorch DataLoader that applies prompt loss masking.
Gradients are computed strictly on the thinking tokens and final response.
"""
def __init__(self, pad_token_id: int = 0, ignore_index: int = -100):
self.pad_token_id = pad_token_id
self.ignore_index = ignore_index
def __call__(self, batch: List[Dict[str, List[int]]]) -> Dict[str, torch.Tensor]:
input_ids_list = []
labels_list = []
max_len = max(len(item["prompt_ids"]) + len(item["completion_ids"]) for item in batch)
for item in batch:
p_ids = item["prompt_ids"]
c_ids = item["completion_ids"]
# Full sequence: prompt + completion
full_ids = p_ids + c_ids
# Labels: mask prompt with ignore_index, supervise completion
labels = [self.ignore_index] * len(p_ids) + list(c_ids)
# Pad to max_len
padding_len = max_len - len(full_ids)
padded_input_ids = full_ids + [self.pad_token_id] * padding_len
padded_labels = labels + [self.ignore_index] * padding_len
input_ids_list.append(padded_input_ids)
labels_list.append(padded_labels)
return {
"input_ids": torch.tensor(input_ids_list, dtype=torch.long),
"labels": torch.tensor(labels_list, dtype=torch.long),
"attention_mask": (torch.tensor(input_ids_list) != self.pad_token_id).long()
}
def run_distillation_pipeline_verification():
print("=" * 70)
print("Testing Reasoning Distillation Parser and Loss Masking Collator")
print("=" * 70)
parser = ReasoningTraceParser()
# 1. Test Valid Reasoning Trajectory
valid_sample = (
"<think>\n"
"Let the variable be x.\n"
"Equation is 2x + 4 = 10.\n"
"Subtract 4 from both sides: 2x = 6.\n"
"Divide by 2: x = 3.\n"
"Wait, let me verify: 2*(3) + 4 = 10. Correct.\n"
"</think>\n"
"The solution is x = 3."
)
parsed = parser.parse_and_validate(valid_sample)
print(f"Sample 1 Validation Passed: {parsed is not None}")
if parsed:
print(f"Extracted Thinking Length: {len(parsed['thinking'])} chars")
print(f"Extracted Answer: '{parsed['answer']}'")
# 2. Test Invalid (Rambling / Looping) Trajectory
rambling_sample = (
"<think>\n"
"Wait, let me rethink this. Wait, let me rethink this.\n"
"Wait, let me rethink this. Wait, let me rethink this.\n"
"Wait, let me rethink this. Wait, let me rethink this.\n"
"</think>\n"
"Answer is 0."
)
parsed_bad = parser.parse_and_validate(rambling_sample)
print(f"Rambling Sample Caught & Rejected: {parsed_bad is None}")
# 3. Simulate SFT Batching with Loss Masking
collator = ReasoningDataCollator(pad_token_id=0, ignore_index=-100)
mock_batch = [
{
"prompt_ids": [101, 2054, 2003, 102], # 4 prompt tokens
"completion_ids": [501, 1000, 1001, 502, 2000, 103] # 6 completion tokens (<think> ... </think> ans)
},
{
"prompt_ids": [101, 2054, 102], # 3 prompt tokens
"completion_ids": [501, 1005, 502, 2001] # 4 completion tokens
}
]
tensors = collator(mock_batch)
print(f"\nBatch Input IDs Shape: {tensors['input_ids'].shape}")
print(f"Batch Labels Shape: {tensors['labels'].shape}")
print(f"Sample 0 Labels: {tensors['labels'][0].tolist()}")
print(f"Note: -100 denotes masked prompt/padding positions (zero gradient).")
print("=" * 70)
if __name__ == "__main__":
run_distillation_pipeline_verification() Production Benchmarks: Olympiad Math, Coding, and Compute Efficiency
The results published in the DeepSeek-R1 technical report established that distilled models represent a monumental shift in parameter efficiency.
1. Benchmark Accuracy Across Model Scales
All models were evaluated under identical greedy / temperature settings:
| Model Architecture | Base Pre-Trained | AIME 2024 (Math) | MATH-500 | LiveCodeBench | Codeforces Rating |
|---|---|---|---|---|---|
| OpenAI o1-mini | Proprietary | 63.6% | 90.0% | 53.8% | 1820 |
| DeepSeek-R1-Zero (Pure RL) | 671B MoE | 71.0% | 95.8% | 54.3% | 1928 |
| DeepSeek-R1 (Full Pipeline) | 671B MoE | 79.8% | 97.3% | 65.9% | 2029 |
| Qwen-2.5-32B-Instruct | 32B Dense | 36.1% | 82.7% | 34.2% | 1311 |
| R1-Distill-Qwen-1.5B | 1.5B Dense | 28.9% | 83.9% | 16.9% | 954 |
| R1-Distill-Qwen-7B | 7B Dense | 55.5% | 92.8% | 37.6% | 1489 |
| R1-Distill-Qwen-14B | 14B Dense | 69.7% | 93.9% | 53.1% | 1708 |
| R1-Distill-Qwen-32B | 32B Dense | 72.6% | 94.3% | 57.2% | 1859 |
| R1-Distill-Llama-70B | 70B Dense | 70.0% | 94.5% | 57.5% | 1876 |
- Surpassing o1-mini: At 32 billion parameters, DeepSeek-R1-Distill-Qwen-32B achieves $72.6%$ on AIME 2024, soundly beating OpenAI’s specialized o1-mini model ($63.6%$) while running entirely on open weights.
- The 14B Sweet Spot: The 14B distilled model scores $69.7%$ on AIME and $93.9%$ on MATH-500, easily fitting on a single 24GB consumer GPU (RTX 4090) while outperforming GPT-4o on competitive mathematics.
- Pure RL vs. Distillation: Attempting to train Qwen-2.5-32B from scratch using pure RL (GRPO) without teacher traces achieved only $\sim 55%$ on AIME before hitting exploration plateaus. Distillation provided a $+17.6%$ absolute accuracy leap.
2. Training Resource and Cluster Expenditure Breakdown
The economic implications of reasoning distillation are profound:
Training Compute Comparison:
1. Frontier Teacher Training (DeepSeek-R1 671B):
- Multi-stage pipeline: Cold-start SFT -> Pure RL (GRPO) -> Rejection Sampling -> Secondary RL
- Estimated Cluster Compute: Hundreds of H100 GPU-years ($2M+ expenditure)
2. Small Model Pure RL (GRPO from scratch on 32B):
- Requires generating millions of trial-and-error rollouts
- Estimated Cluster Compute: ~30,000 H100 hours (~$90k expenditure) -> Suboptimal result
3. Reasoning Model Distillation (R1-Distill-Qwen-32B):
- SFT on 800k curated teacher sequences (2 epochs)
- Estimated Cluster Compute: ~1,200 H100 hours (~$3,600 expenditure!)
- Result: State-of-the-art reasoning rivaling proprietary models! Strategic Recommendations: Deploying Distilled Reasoning Models in 2026
For AI engineers, system architects, and development teams integrating reasoning agents with platforms like AiFetchly, reasoning distillation provides a clear operational playbook:
- Deploy 14B and 32B Distill Models for Production Reasoning: If your use case requires complex structured extraction, formal logic, or Python coding, deploy
DeepSeek-R1-Distill-Qwen-14Bor32B. They deliver frontier reasoning accuracy at low inference latency. - Strip
<think>Tags in Downstream Software APIs: Use streaming regex parsers in your API gateway to catch and isolate tokens between<think>and</think>. Route the thinking tokens to internal trace logs or expandable UI accordions, while passing only clean markdown to end users. - Calibrate Thinking Budget for Latency-Sensitive Tasks: If deploying in customer-facing chatbots, append instructions like “Provide a direct, concise answer without extensive internal verification unless requested” to prevent the model from spending 20 seconds pondering simple factual queries.
- Use Distillation as the Base for Domain RLVR: If building reasoning models for proprietary domains (such as internal ERP SQL generation or specialized financial analysis), do not start RL from a base conversational checkpoint. Start with a distilled reasoning model (
R1-Distill-Qwen-32B) and apply lightweight RLVR over your internal database sandboxes.