| name | finece-confidence |
| title | Fine-Grained Confidence Estimation During LLM Generation |
| version | 0.0.2 |
| engine | skillxiv-v0.0.2-claude-opus-4.6 |
| license | MIT |
| url | https://arxiv.org/abs/2508.12040 |
| keywords | ["confidence-estimation","uncertainty-quantification","generation-process","calibration"] |
| description | Provide continuous confidence scores throughout LLM text generation via supervised learning and backward confidence integration, enabling real-time uncertainty awareness |
Mind the Generation Process: Fine-Grained Confidence During LLM Generation
Core Concept
FineCE enables language models to assess confidence in their own text generation in real-time. The approach trains a supervised confidence predictor that can leverage future context (backward confidence integration) to improve estimates for current sequences. Unlike post-hoc confidence estimation, FineCE provides granular confidence at each position during generation, enabling applications like beam search biasing, early stopping, and uncertainty-aware retrieval.
Architecture Overview
- Continuous Confidence Prediction: Score each position during generation
- Supervised Learning: Train separate confidence prediction model
- Backward Integration: Use future context to improve current estimates
- Multiple Strategies: Three positions for confidence estimation in sequence
- Calibration-Aware: Train to avoid overconfidence in incorrect predictions
Implementation Steps
Stage 1: Design Confidence Prediction Module
Create a model to estimate generation confidence.
import torch
from torch import nn
from typing import Tuple, List
class ConfidencePredictor(nn.Module):
"""Predict confidence scores for generated text"""
def __init__(
self,
model_dim: int = 4096,
hidden_dim: int = 1024,
confidence_dim: int = 128
):
super().__init__()
self.model_dim = model_dim
self.hidden_dim = hidden_dim
self.input_proj = nn.Linear(model_dim, hidden_dim)
self.confidence_backbone = nn.Sequential(
nn.Linear(hidden_dim, hidden_dim),
nn.ReLU(),
nn.Dropout(0.1),
nn.Linear(hidden_dim, hidden_dim),
nn.ReLU(),
nn.Dropout(0.1)
)
self.confidence_head = nn.Linear(hidden_dim, 1)
def forward(
self,
hidden_state: torch.Tensor,
mask: torch.Tensor = None
) -> torch.Tensor:
"""
Predict confidence for each position.
Returns:
confidence: [batch, seq_len, 1] normalized to [0, 1]
"""
projected = .input_proj(hidden_state)
features = .confidence_backbone(projected)
logit = .confidence_head(features)
confidence = torch.sigmoid(logit)
mask :
confidence = confidence * mask.unsqueeze(-)
confidence
:
():
.predictor = predictor
.optimizer = torch.optim.Adam(predictor.parameters(), lr=lr)
() -> []:
training_data = []
gen_text, gt_text, hidden_state (
generated_texts, ground_truth, hidden_states
):
gen_tokens = gen_text.split()
gt_tokens = gt_text.split()
pos, gen_token (gen_tokens):
pos < (gt_tokens):
is_correct = gen_token == gt_tokens[pos]
:
is_correct =
label = (is_correct)
training_data.append({
: hidden_state[pos].unsqueeze(),
: label,
: pos,
: gen_text
})
training_data
() -> :
total_loss =
example batch:
hidden_state = example[]
label = torch.tensor([example[]], dtype=torch.float32)
confidence = .predictor(hidden_state)
loss = torch.nn.functional.binary_cross_entropy(
confidence,
label.unsqueeze(-)
)
total_loss += loss.item()
.optimizer.zero_grad()
loss.backward()
.optimizer.step()
total_loss / (batch)
Stage 2: Implement Backward Confidence Integration (BCI)
Use future tokens to improve current position confidence.
class BackwardConfidenceIntegrator:
"""Integrate future context to improve confidence estimates"""
def __init__(self, predictor: ConfidencePredictor):
self.predictor = predictor
def forward_confidence(
self,
hidden_states: torch.Tensor,
mask: torch.Tensor = None
) -> torch.Tensor:
"""Standard forward confidence: left-to-right"""
confidence = self.predictor(hidden_states.unsqueeze(0), mask)
return confidence.squeeze(0)
def backward_integrated_confidence(
self,
hidden_states: torch.Tensor,
mask: torch.Tensor = None
) -> torch.Tensor:
"""
BCI: Use future context to improve confidence.
Key insight: A token's correctness often becomes clear from
subsequent context. Use bidirectional information.
"""
seq_len = hidden_states.shape[0]
confidence_scores = []
for pos in range(seq_len):
current_hidden = hidden_states[pos:pos+1]
future_start = min(pos + 1, seq_len)
future_end = min(pos + 6, seq_len)
future_hidden = hidden_states[future_start:future_end]
if future_hidden.shape[] > :
combined_hidden = torch.cat([
current_hidden,
future_hidden.mean(dim=, keepdim=)
], dim=-)
combined_hidden = ._project_to_model_dim(combined_hidden)
confidence = .predictor(combined_hidden)
:
confidence = .predictor(current_hidden)
confidence_scores.append(confidence.squeeze())
bci_confidence = torch.stack(confidence_scores)
bci_confidence
() -> torch.Tensor:
tensor.shape[-] != .predictor.model_dim:
proj = nn.Linear(tensor.shape[-], .predictor.model_dim)
tensor = proj(tensor)
tensor
Stage 3: Multiple Confidence Strategies
Offer different approaches for measuring confidence.
class ConfidenceStrategies:
"""Different strategies for estimating confidence"""
@staticmethod
def strategy_1_current_only(
predictor: ConfidencePredictor,
hidden_states: torch.Tensor
) -> torch.Tensor:
"""
Strategy 1: Confidence from current position only
(Standard approach, left-to-right)
"""
confidence = predictor(hidden_states.unsqueeze(0))
return confidence.squeeze(0)
@staticmethod
def strategy_2_with_context(
predictor: ConfidencePredictor,
hidden_states: torch.Tensor,
context_window: int = 3
) -> torch.Tensor:
"""
Strategy 2: Use surrounding context (window of ±N positions)
"""
seq_len = hidden_states.shape[0]
confidence_scores = []
for pos in range(seq_len):
context_start = max(0, pos - context_window)
context_end = min(seq_len, pos + context_window + 1)
context_hidden = hidden_states[context_start:context_end]
context_mean = context_hidden.mean(dim=0, keepdim=True)
confidence = predictor(context_mean)
confidence_scores.append(confidence.squeeze())
return torch.stack(confidence_scores)
@staticmethod
def strategy_3_backward_integration() -> torch.Tensor:
integrator = BackwardConfidenceIntegrator(predictor)
integrator.backward_integrated_confidence(hidden_states)
Stage 4: Online Confidence During Generation
Compute confidence scores during decoding.
class OnlineConfidenceScorer:
"""Compute confidence scores during LLM generation"""
def __init__(
self,
language_model,
confidence_predictor: ConfidencePredictor,
strategy: str = "strategy_3_backward_integration"
):
self.lm = language_model
self.predictor = confidence_predictor
self.strategy = strategy
def generate_with_confidence(
self,
prompt: str,
max_tokens: int = 256,
temperature: float = 0.7,
confidence_threshold: float = 0.5
) -> Dict:
"""
Generate text and track confidence at each step.
Returns:
- generated_text: model output
- confidence_scores: per-token confidence
- divergence_points: where confidence drops below threshold
"""
token_ids = self.lm.tokenize(prompt)
generated_tokens = []
confidence_scores = []
hidden_states_list = []
for step in range(max_tokens):
with torch.no_grad():
outputs = self.lm.forward(
input_ids=torch.tensor(token_ids + generated_tokens).unsqueeze(0)
)
hidden_state = outputs.hidden_states[-1]
hidden_states_list.append(hidden_state[0, -1])
logits = outputs.logits[, -, :]
next_token = ._sample_token(logits, temperature)
generated_tokens.append(next_token)
(hidden_states_list) > :
all_hidden = torch.stack(hidden_states_list)
.strategy == :
confidence = ConfidenceStrategies.strategy_1_current_only(
.predictor, all_hidden
)
.strategy == :
confidence = ConfidenceStrategies.strategy_2_with_context(
.predictor, all_hidden
)
:
confidence = ConfidenceStrategies.strategy_3_backward_integration(
.predictor, all_hidden
)
current_confidence = confidence[-].item()
:
current_confidence =
confidence_scores.append(current_confidence)
current_confidence < confidence_threshold step > :
generated_text = .lm.tokenizer.decode(generated_tokens)
{
: generated_text,
: confidence_scores,
: (confidence_scores) / (confidence_scores),
: (confidence_scores) confidence_scores ,
: (generated_tokens)
}
() -> :
probs = torch.nn.functional.softmax(logits / temperature, dim=-)
torch.multinomial(probs, ).item()
Stage 5: Applications Using Confidence
Leverage confidence for downstream applications.
class ConfidenceApplications:
"""Use confidence scores for improved generation"""
def __init__(self, scorer: OnlineConfidenceScorer):
self.scorer = scorer
def biased_beam_search(
self,
prompt: str,
num_beams: int = 4,
length_penalty: float = 1.0
) -> List[Dict]:
"""
Beam search biased by confidence scores.
Hypothesis with higher average confidence are preferred.
"""
beams = [
{"text": "", "logprob": 0, "avg_confidence": 1.0}
]
for step in range(256):
candidates = []
for beam in beams:
completions = self.scorer.generate_with_confidence(
prompt + beam["text"],
max_tokens=3,
confidence_threshold=0.3
)
avg_confidence = completions["avg_confidence"]
logprob = 0
score = logprob + 0.3 * avg_confidence
candidates.append({
: beam[] + + completions[],
: score,
: avg_confidence
})
beams = (candidates, key= x: x[], reverse=)[:num_beams]
beams
() -> []:
result = .scorer.generate_with_confidence(prompt)
low_conf_threshold =
low_conf_positions = [
i i, conf (result[])
conf < low_conf_threshold
]
retrieved = []
pos low_conf_positions:
tokens_at_pos = result[].split()[pos:pos+]
query = .join(tokens_at_pos)
best_docs = ._semantic_search(query, knowledge_base, top_k=)
retrieved.append((pos, query, best_docs))
retrieved
():
docs[:top_k]
Practical Guidance
Confidence Strategies Comparison
| Strategy | Pros | Cons | Use Case |
|---|
| Current Only | Fast, simple | Limited context | Real-time systems |
| With Context | Moderate accuracy | Moderate overhead | Batch processing |
| BCI | Best accuracy | More computation | Offline generation |
Integration with Generation
- Beam Search: Weight hypotheses by confidence
- Early Stopping: Stop when confidence stabilizes
- Uncertainty Sampling: Use for active learning
- Retrieval Augmentation: Retrieve when model uncertain
Training Data
- Collect authentic model generations with ground truth labels
- Balance correct and incorrect examples
- Include diverse domains for generalization
- ~100K-1M training examples for good calibration
When to Use FineCE
- Applications requiring uncertainty awareness
- Real-time systems needing confidence bounds
- Active learning or selective prediction
- Combination with retrieval augmentation
When NOT to Use
- Latency-critical systems (adds inference cost)
- Domains with clear correctness (confidence less useful)
- Models already well-calibrated
Calibration Considerations
- Train on representative distribution
- Monitor for overconfidence on errors
- Validate on held-out test set
- Consider post-hoc calibration (temperature scaling)
Reference
Mind the Generation Process: Fine-Grained Confidence during LLM Generation. arXiv:2508.12040