Predict optimal data mixture proportions for multi-domain LLM training using scaling laws that require only 10-20 small experiments. Determine which domains should contribute how much data across model sizes (186M-7B), reducing computational waste in foundation model pretraining.
Scanned 9/9/2026
Install to Claude Code
npx -y skills add ADu2021/skillXiv --skill scaling-laws-optimal-data-mixtures --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Scaling Laws Optimal Data Mixtures?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/adu2021-scaling-laws-optimal-data-mixtures)More formats (shields.io, HTML) on the badges page.
---
name: scaling-laws-optimal-data-mixtures
title: "Scaling Laws for Optimal Data Mixtures"
version: 0.0.2
engine: skillxiv-v0.0.2-claude-opus-4.6
license: MIT
url: "https://arxiv.org/abs/2507.09404"
keywords: [Scaling Laws, Data Mixtures, Multi-Domain Training, Compute Optimization, Foundation Models]
description: "Predict optimal data mixture proportions for multi-domain LLM training using scaling laws that require only 10-20 small experiments. Determine which domains should contribute how much data across model sizes (186M-7B), reducing computational waste in foundation model pretraining."
---
# Scaling Laws for Optimal Data Mixtures: Efficient Multi-Domain Foundation Model Training
Foundation models trained on diverse domains (code, math, text) must decide how much data from each domain to include. Current practice uses trial-and-error, wasting compute on suboptimal mixtures. This work proposes scaling laws that predict model loss as a function of model size (N), training tokens (D), and domain weights (h), enabling practitioners to determine optimal mixtures efficiently.
The key insight is that only 10-20 small-scale training runs are needed to fit accurate scaling laws that extrapolate to much larger models. Two law formulations are provided: additive (mixture-independent scale parameters, predicting scale-independent optimal mixtures) and joint (mixture-dependent scale parameters, predicting compute-budget-dependent optima). Both formulations have been validated across language models, multimodal models, and vision models.
## Core Concept
Multi-domain training loss can be modeled as: E + 1/∑(C_i·h_i^γ_i) + A/N^α + B/D^β, where only the bias term E depends on domain weights h. This reveals a crucial property: for additive scaling laws, optimal domain weights are compute-independent—they don't change with model size or total training budget. Only the absolute performance scales.
For joint scaling laws where scale parameters A and B themselves depend on mixture composition, optimal weights become budget-dependent. The fitting procedure uses Basin-hopping with L-BFGS to navigate the high-dimensional parameter space efficiently.
## Architecture Overview
- **Additive Scaling Law Formulation**: Loss depends on domain-weight-dependent bias term; scale parameters (A, B) are mixture-independent
- **Joint Scaling Law Formulation**: Both scale parameters and bias depend on mixture; accounts for scale-mixture interactions
- **Loss Prediction Pipeline**: Fit scaling laws to small experiments, extrapolate to large models/compute budgets
- **Optimization Framework**: Basin-hopping + L-BFGS to solve mixture optimization problem over weight simplex
- **Multi-Model Validation**: Tests on language models (186M-7B), multimodal (image+text), and vision encoders
## Implementation
### Additive Scaling Law: Mixture-Independent Scale Parameters
Model loss where domain weights affect bias term but not scaling.
```python
import numpy as np
from scipy.optimize import minimize, basinhopping
import torch
class AdditiveScalingLaw:
"""
Additive formulation: Loss = E(h) + 1/∑(Ci·hi^γi) + A/N^α + B/D^β
where E(h) is bias depending on mixture, but A and B are independent of h.
"""
def __init__(self, num_domains: int = 3):
self.num_domains = num_domains
# Parameters to fit
self.C = np.ones(num_domains) # Domain constants
self.gamma = np.ones(num_domains) # Domain exponents
self.A = 1.0 # Scale parameter for model size
self.alpha = 0.5 # Model size exponent
self.B = 1.0 # Scale parameter for tokens
self.beta = 0.5 # Token exponent
def predict_loss(self, model_size: int, tokens: int, mixture_weights: np.ndarray):
"""
Predict loss for given model size, tokens, and domain mixture.
Args:
model_size: Model parameter count N
tokens: Total training tokens D
mixture_weights: (num_domains,) domain weight distribution, sums to 1
Returns:
Predicted loss
"""
# Bias term depending on mixture
bias = 0.0
weighted_sum = 0.0
for i in range(self.num_domains):
weighted_sum += self.C[i] * (mixture_weights[i] ** self.gamma[i])
mixture_term = 1.0 / (weighted_sum + 1e-8)
bias += mixture_term
# Scale terms independent of mixture
scale_loss = self.A / (model_size ** self.alpha) + self.B / (tokens ** self.beta)
return bias + scale_loss
def fit_to_experiments(self, experiments: list):
"""
Fit scaling law to experimental data.
Args:
experiments: List of {
'model_size': N,
'tokens': D,
'mixture_weights': (num_domains,),
'loss': measured loss
}
Returns:
Fitted parameters (C, gamma, A, alpha, B, beta)
"""
def objective(params):
# Unpack parameters
C = params[:self.num_domains]
gamma = params[self.num_domains:2*self.num_domains]
A = params[2*self.num_domains]
alpha = params[2*self.num_domains + 1]
B = params[2*self.num_domains + 2]
beta = params[2*self.num_domains + 3]
# Update self
self.C = C
self.gamma = gamma
self.A = A
self.alpha = alpha
self.B = B
self.beta = beta
# Compute MSE
mse = 0.0
for exp in experiments:
predicted = self.predict_loss(
exp['model_size'],
exp['tokens'],
exp['mixture_weights']
)
mse += (predicted - exp['loss']) ** 2
return mse / len(experiments)
# Initial guess
x0 = np.concatenate([
self.C,
self.gamma,
[self.A, self.alpha, self.B, self.beta]
])
# Optimize
minimizer_kwargs = {
'method': 'L-BFGS-B',
'bounds': [(0.1, 10)] * (2*self.num_domains) + [(0.01, 100), (0.1, 2), (0.01, 100), (0.1, 2)]
}
result = basinhopping(
objective,
x0,
minimizer_kwargs=minimizer_kwargs,
niter=20,
seed=42
)
return result.fun
def find_optimal_mixture(self, model_size: int, tokens: int) -> np.ndarray:
"""
Find domain mixture that minimizes loss for given compute budget.
For additive formulation, optimal mixture is compute-independent!
Args:
model_size: Target model size (for validation)
tokens: Target training tokens (for validation)
Returns:
Optimal mixture weights (sums to 1)
"""
def objective_mixture(weights):
# Constraint: weights sum to 1
if not np.isclose(weights.sum(), 1.0):
return 1e10
# Minimize over mixture (ignoring scale terms since they don't depend on h)
weighted_sum = 0.0
for i in range(self.num_domains):
weighted_sum += self.C[i] * (weights[i] ** self.gamma[i])
# Bias term to minimize
loss = 1.0 / (weighted_sum + 1e-8)
return loss
# Constrain to simplex
from scipy.optimize import LinearConstraint
A_constraint = np.ones((1, self.num_domains))
constraint = LinearConstraint(A_constraint, [1], [1])
# Initial guess: uniform mixture
x0 = np.ones(self.num_domains) / self.num_domains
result = minimize(
objective_mixture,
x0,
method='SLSQP',
bounds=[(0, 1) for _ in range(self.num_domains)]
)
optimal = result.x / result.x.sum() # Normalize
return optimal
```
### Joint Scaling Law: Mixture-Dependent Scale Parameters
More complex formulation where scale parameters depend on mixture.
```python
class JointScalingLaw:
"""
Joint formulation: Loss = E(h) + A^h/N^α^h + B^h/D^β^h
where A, B, α, β all depend on mixture weights h.
Captures scale-mixture interactions.
"""
def __init__(self, num_domains: int = 3):
self.num_domains = num_domains
# For A term
self.C_A = np.ones(num_domains)
self.gamma_A = np.ones(num_domains)
self.alpha = 0.5
# For B term
self.C_B = np.ones(num_domains)
self.gamma_B = np.ones(num_domains)
self.beta = 0.5
# Bias term
self.C_E = np.ones(num_domains)
self.gamma_E = np.ones(num_domains)
def predict_loss(self, model_size: int, tokens: int, mixture_weights: np.ndarray):
"""
Predict loss with mixture-dependent scale parameters.
Args:
model_size: N
tokens: D
mixture_weights: (num_domains,)
Returns:
Predicted loss
"""
# A term depends on mixture
A_weighted = 0.0
for i in range(self.num_domains):
A_weighted += self.C_A[i] * (mixture_weights[i] ** self.gamma_A[i])
# B term depends on mixture
B_weighted = 0.0
for i in range(self.num_domains):
B_weighted += self.C_B[i] * (mixture_weights[i] ** self.gamma_B[i])
# Bias depends on mixture
E_term = 0.0
for i in range(self.num_domains):
E_term += self.C_E[i] * (mixture_weights[i] ** self.gamma_E[i])
# Loss prediction
loss = E_term + A_weighted / (model_size ** self.alpha) + B_weighted / (tokens ** self.beta)
return loss
def fit_to_experiments(self, experiments: list) -> float:
"""Fit joint scaling law to experiments."""
def objective(params):
# Extract parameters
C_A = params[:self.num_domains]
gamma_A = params[self.num_domains:2*self.num_domains]
C_B = params[2*self.num_domains:3*self.num_domains]
gamma_B = params[3*self.num_domains:4*self.num_domains]
C_E = params[4*self.num_domains:5*self.num_domains]
gamma_E = params[5*self.num_domains:6*self.num_domains]
alpha = params[6*self.num_domains]
beta = params[6*self.num_domains + 1]
# Update
self.C_A = C_A
self.gamma_A = gamma_A
self.C_B = C_B
self.gamma_B = gamma_B
self.C_E = C_E
self.gamma_E = gamma_E
self.alpha = alpha
self.beta = beta
# MSE
mse = 0.0
for exp in experiments:
predicted = self.predict_loss(
exp['model_size'],
exp['tokens'],
exp['mixture_weights']
)
mse += (predicted - exp['loss']) ** 2
return mse / len(experiments)
x0 = np.concatenate([
self.C_A, self.gamma_A,
self.C_B, self.gamma_B,
self.C_E, self.gamma_E,
[self.alpha, self.beta]
])
minimizer_kwargs = {
'method': 'L-BFGS-B',
'bounds': [(0.1, 10)] * (6*self.num_domains) + [(0.1, 2), (0.1, 2)]
}
result = basinhopping(
objective,
x0,
minimizer_kwargs=minimizer_kwargs,
niter=20
)
return result.fun
def find_optimal_mixture(
self,
model_size: int,
tokens: int,
optimization_target: str = 'loss'
) -> np.ndarray:
"""
Find optimal mixture for specific compute budget (compute-dependent).
Args:
model_size: Target model size N
tokens: Target tokens D
optimization_target: 'loss' or 'efficiency'
Returns:
Optimal mixture weights for this budget
"""
def objective_mixture(weights):
if not np.isclose(weights.sum(), 1.0):
return 1e10
loss = self.predict_loss(model_size, tokens, weights)
return loss
x0 = np.ones(self.num_domains) / self.num_domains
from scipy.optimize import LinearConstraint
A_constraint = np.ones((1, self.num_domains))
constraint = LinearConstraint(A_constraint, [1], [1])
result = minimize(
objective_mixture,
x0,
method='SLSQP',
bounds=[(0, 1) for _ in range(self.num_domains)]
)
return result.x / result.x.sum()
```
### Experimental Design: Small-Scale Experiments for Law Fitting
Design efficient small experiments to fit scaling laws.
```python
class ScalingLawExperimentDesigner:
"""Design efficient experiments for fitting scaling laws."""
@staticmethod
def generate_experiment_grid(
model_sizes: list,
token_counts: list,
mixture_points: list,
num_domains: int = 3
) -> list:
"""
Generate grid of experiments to fit scaling laws efficiently.
Args:
model_sizes: Model sizes to test (e.g., [186M, 370M, 750M, 1.5B])
token_counts: Token counts to test (e.g., [1B, 5B, 10B, 50B])
mixture_points: Mixture weight vectors (e.g., uniform, domain-heavy)
num_domains: Number of domains
Returns:
List of experiment configs
"""
experiments = []
for model_size in model_sizes:
for tokens in token_counts:
for mixture in mixture_points:
# Validate mixture
if not np.isclose(sum(mixture), 1.0):
mixture = np.array(mixture) / sum(mixture)
experiments.append({
'model_size': model_size,
'tokens': tokens,
'mixture_weights': mixture,
'loss': None # To be filled by actual training
})
return experiments
@staticmethod
def recommend_efficient_grid(num_domains: int = 3):
"""Recommend efficient experimental grid (10-20 runs only)."""
model_sizes = [186_000_000, 370_000_000, 750_000_000] # 3 sizes
token_counts = [1_000_000_000, 10_000_000_000] # 2 token budgets
# Mixture points: uniform + domain-heavy variants
mixtures = [
[1/num_domains] * num_domains # Uniform
]
# Add domain-heavy points
for i in range(num_domains):
mix = [0.1] * num_domains
mix[i] = 0.7
mix = [m / sum(mix) for m in mix] # Normalize
mixtures.append(mix)
return {
'model_sizes': model_sizes,
'token_counts': token_counts,
'mixtures': mixtures
}
```
### End-to-End Workflow: From Experiments to Optimal Mixture
Complete pipeline for determining optimal training mixture.
```python
def determine_optimal_mixture_for_production(
train_losses: list,
target_model_size: int,
target_tokens: int,
num_domains: int = 3,
use_joint: bool = False
) -> dict:
"""
End-to-end: fit scaling law and find optimal mixture.
Args:
train_losses: Results from small-scale experiments
target_model_size: Production model size to optimize for
target_tokens: Production training budget
num_domains: Number of domains in training data
use_joint: Use joint (True) or additive (False) formulation
Returns:
{'optimal_mixture': weights, 'predicted_loss': loss, 'law_fit_error': mre}
"""
# Choose formulation
if use_joint:
law = JointScalingLaw(num_domains)
else:
law = AdditiveScalingLaw(num_domains)
# Fit to experimental data
fit_error = law.fit_to_experiments(train_losses)
print(f"Scaling law fit error (MSE): {fit_error:.6f}")
# Find optimal mixture for target compute
optimal_mixture = law.find_optimal_mixture(target_model_size, target_tokens)
# Predict loss with optimal mixture
predicted_loss = law.predict_loss(target_model_size, target_tokens, optimal_mixture)
print(f"\nOptimal mixture for {target_model_size/1e6:.0f}M model, {target_tokens/1e9:.0f}B tokens:")
for i, weight in enumerate(optimal_mixture):
print(f" Domain {i}: {weight:.1%}")
print(f"Predicted loss: {predicted_loss:.4f}")
# Extrapolation confidence
mean_relative_error = fit_error # Simplified; in practice compute MRE
return {
'optimal_mixture': optimal_mixture,
'predicted_loss': predicted_loss,
'law_fit_error': fit_error,
'extrapolation_confidence': 'high' if fit_error < 0.02 else 'medium'
}
# Example usage
sample_experiments = [
{'model_size': 186_000_000, 'tokens': 1_000_000_000, 'mixture_weights': [0.33, 0.33, 0.34], 'loss': 3.521},
{'model_size': 186_000_000, 'tokens': 10_000_000_000, 'mixture_weights': [0.33, 0.33, 0.34], 'loss': 3.201},
{'model_size': 750_000_000, 'tokens': 1_000_000_000, 'mixture_weights': [0.33, 0.33, 0.34], 'loss': 3.156},
{'model_size': 750_000_000, 'tokens': 10_000_000_000, 'mixture_weights': [0.33, 0.33, 0.34], 'loss': 2.834},
# ... more experiments
]
result = determine_optimal_mixture_for_production(
sample_experiments,
target_model_size=7_000_000_000,
target_tokens=1_000_000_000_000,
num_domains=3,
use_joint=False
)
```
## Practical Guidance
### Key Hyperparameters & Methodology
| Parameter | Value | Notes |
|-----------|-------|-------|
| Minimum Experiments | 10-20 | Each requires full pretraining; 10 experiments sufficient for 3-domain problems |
| Model Sizes | 186M, 370M, 750M (baseline), 1.7B | Doubling strategy reveals exponential trends |
| Token Budgets | 1B, 5B, 10B, 50B | Test different scales of compute |
| Domain Mixtures | Uniform + domain-heavy | 3-5 mixture points sufficient |
| Basin-hopping Iterations | 20 | Balance between optimization quality and speed |
| Optimizer | L-BFGS-B | Robust for parameter fitting |
| Constraint Type | Simplex (weights sum to 1) | Ensures valid probability distribution |
### When to Use
- Planning foundation model pretraining across multiple domains
- Determining optimal code/math/text ratios for LLM training
- Allocating compute budgets across multimodal training (image/text/video)
- Testing whether mixture optimization is worth additional experiments
- Predicting loss for unseen model sizes or compute budgets
### When NOT to Use
- Domains with very different natures (few samples extrapolate poorly)
- Scenarios where domain interactions are complex and non-factorizable
- Production environments where even 10 small experiments are too expensive
- Tasks already having established conventions (follow best practices instead)
### Common Pitfalls
- **Too few experiments**: <5 runs lead to poor parameter estimation; stick to 10+
- **Skipping intermediate scales**: Using only 186M and 7B without 750M loses information about scaling behavior
- **Ignoring mixture diversity**: Testing only uniform and single-domain-heavy limits law quality; vary gradually
- **Wrong formulation choice**: Additive assumes scale-mixture independence; joint is more flexible but needs more data
- **Over-fitting to experiments**: Don't use outlier experiments; validate for data quality before fitting
- **Ignoring compute-dependence**: For joint formulation, optimal mixture changes with budget; compute separately per target
### Expected Performance
- **Mean Relative Error**: <2% when extrapolating to 2-3x larger models (186M → 750M)
- **Extrapolation range**: Reliable up to ~7B parameters from ~750M baseline experiments
- **Mixture convergence**: Optimal weights typically converge with 50-200K total training tokens analyzed
## Reference
Chen, Y., Wang, X., Liu, S., et al. (2024). Scaling Laws for Optimal Data Mixtures. arXiv preprint arXiv:2507.09404.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!