From a656366935cfccdc810370b9e050bff737ef5d93 Mon Sep 17 00:00:00 2001 From: wassname <1103714+wassname@users.noreply.github.com> Date: Thu, 16 Oct 2025 15:22:49 +0800 Subject: [PATCH] log predictions --- README.md | 2 +- docs/mjc_research_journal.md | 280 ++++++++++++++++++++++++++++++ nbs/05_backprop.py | 324 ++++++++++++++++++++++++++++++++++- pyproject.toml | 1 + src/data/__init__.py | 2 +- src/simple_icm.py | 40 ++++- uv.lock | 269 +++++++++++++++++++++++++++++ 7 files changed, 905 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index a012f35..88ff7d5 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ Usage ```py # make sure you OPENROUTER_API_KEY is set in your .env file uv sync -uv run nbs/simple_icm.py +uv run src/simple_icm.py ``` ## Results diff --git a/docs/mjc_research_journal.md b/docs/mjc_research_journal.md index 2d95d36..dda77c6 100644 --- a/docs/mjc_research_journal.md +++ b/docs/mjc_research_journal.md @@ -64,3 +64,283 @@ Theory clarification (in Analysis section): - Epistemic = ensemble variance (model uncertainty) ? - Aleatoric = consistency failures (data ambiguity) ? - Evidence weights = structural confidence (relationship strength) ? + + +# 2025-10-16 13:57:48 + +## Idea context + + Absolutely, that clarification makes total sense—it streamlines the backprop idea significantly and keeps things focused on what you're trying to achieve (e.g., propagating evidence and consistency for unsupervised labels, inspired by ICM and your graph/rollout notes). Let me confirm I understand your setup, then break down how to implement it, compare it to graphs, and refine the complexity/gain ratings based on this "LLM-as-prior-provider" approach. This keeps the LLM out of the optimization loop (smart, since most LLMs like Llama or Claude aren't easily differentiable), treating it as a fixed oracle for generating initial priors or prediction tuples upfront. + + ### Confirmed Understanding of Your Backprop Setup + - **Core Components**: + - **Learnable Labels**: These are the only trainable parameters (e.g., soft probabilities for each example's label, like [prob_yes, prob_no]). + - **Loss Function**: Something "weird" (custom) computed over n-shot examples and prediction tuples. For instance, the loss could measure mutual predictability: For each tuple (a set of n-shot context labels + a target prediction), compute how well the predicted label matches the "true" (learnable) one, perhaps using cross-entropy or ranking losses. This encourages coherence across the dataset. + - **LLM's Role**: The LLM provides fixed priors (e.g., initial logprob-based scores like -(logprob_neg - logprob_pos) for each label) and/or generates the prediction tuples (e.g., by querying the LLM once to get few-shot predictions for various contexts). These are pre-computed and not updated during backprop—the LLM isn't in the graph or optimization. + - **No LLM in the Graph**: Optimization is just over the small set of labels, using gradients from the loss to update them iteratively. This is efficient for small graphs (e.g., 100-1000 examples) and aligns with your idea of propagating confidence (e.g., if a label leads to more consistent predictions, it gets reinforced via the loss). + + This is reminiscent of techniques in papers like CCS (Contrast-Consistent Search) or even Fabien's probe experiments, where labels are optimized for internal consistency without external supervision. Your twist (using n-shot tuples and logprob rankings as priors) could make it more robust to outdated rollouts or scattered samples. + + ### How This Backprop Approach Works (Pros/Cons vs. Graphs) + - **High-Level Flow**: + 1. **Pre-Compute from LLM**: Use the LLM to generate: + - Priors: For each example, get logprobs for "yes" vs. "no" (or positive/negative), compute scores like score = logprob_pos - logprob_neg (positive favors "yes"). Treat these as initial values or regularization terms— they're rankings, not calibrated probs, as you noted. + - Prediction Tuples: Generate a bunch of n-shot contexts (e.g., sample subsets of examples, feed to LLM as few-shot prompts, get predicted labels/probs for a target example). This creates a dataset of tuples like (context_labels, target_prediction). + 2. **Define Learnable Labels**: Initialize a tensor of soft labels (e.g., from priors). + 3. **Custom Loss**: For each tuple, plug in the current learnable labels (for the context) and compare to the LLM's pre-computed prediction (for the target). Loss could be: + - Predictability term: Cross-entropy between predicted prob and learnable target label. + - Consistency term: Penalize inconsistencies (e.g., if labels violate logical rules). + - Prior term: KL divergence or L2 to the LLM priors, to anchor optimization. + - Your propagation idea: Add a term that rewards labels leading to "more confident/consistent" downstream predictions (e.g., lower entropy in tuples that depend on it). + 4. **Backprop and Optimize**: Run gradient descent on the labels to minimize the total loss. Since the graph is small, it converges fast. + + - **Pros**: + - Flexible for your "weird" losses (e.g., incorporating rollout datedness or graph weights as factors in the loss). + - Handles soft labels and rankings naturally (e.g., use pairwise ranking losses like margin loss on logprob differences to avoid calibration issues). + - Efficient: No LLM calls during training—just math on pre-computed data. + + - **Cons vs. Explicit Graphs**: + - Less interpretable than a graph (harder to visualize dependencies), but more automated (gradients handle propagation implicitly). + - If dependencies are sparse/simple, graphs (with BP) might be overkill but easier to debug. Backprop shines if you want to learn extra params (e.g., evidence weights) or handle non-linear losses. + + - **Is This Reinventing Graphs?**: Partially—it's a differentiable analog. The n-shot tuples implicitly define a graph (contexts as "neighbors," predictions as edge messages), and backprop propagates evidence like BP does. But you're not explicitly building/maintaining a graph structure, so it's a hybrid: graph-inspired but optimization-focused. Not reinventing—more like adapting (e.g., similar to how GNNs turn graphs into backprop-able nets). If you find backprop getting messy, fallback to explicit graphs is easy. + + ### Implementation Suggestions + Here's a quick PyTorch sketch to get you started. Assume you have pre-computed `priors` (list of scores) and `tuples` (list of dicts with 'context_indices', 'target_index', 'llm_pred_prob' for yes/no). + + ```python + import torch + import torch.nn.functional as F + + # Setup + num_labels = 100 # Number of examples/labels + labels = torch.nn.Parameter(torch.randn(num_labels, 2)) # Learnable logits [yes, no] per label + priors = torch.tensor([precomputed_scores]) # Shape: (num_labels, 2), from LLM logprobs + tuples = [...] # List of {'context_indices': [i,j,k], 'target_index': m, 'llm_pred': [prob_yes, prob_no]} + + # Custom loss function + def coherence_loss(labels, tuples, priors, alpha=0.1, beta=0.1): + loss = 0.0 + labels_soft = F.softmax(labels, dim=1) # Soft probs + + # Predictability over tuples + for t in tuples: + # Simplified: Average context labels as "input" (or use more complex aggregation) + context_avg = labels_soft[t['context_indices']].mean(dim=0) + target_prob = labels_soft[t['target_index']] + pred_loss = F.cross_entropy(context_avg.unsqueeze(0), target_prob.unsqueeze(0)) # Or ranking loss + # Reward consistency/confidence: e.g., lower entropy if this label boosts downstream + entropy_penalty = -torch.sum(target_prob * torch.log(target_prob)) # Lower is more confident + loss += pred_loss + beta * entropy_penalty + + # Prior regularization (e.g., treat as soft targets) + prior_loss = F.kl_div(F.log_softmax(labels, dim=1), priors.softmax(dim=1), reduction='batchmean') + + # Add consistency constraints (e.g., logical rules) + # consistency_loss = ... (custom, e.g., penalize if label_i + label_j >1 for mutex pairs) + + return loss / len(tuples) + alpha * prior_loss # + consistency_loss + + # Optimize (use 2nd-order as you suggested for small size) + optimizer = torch.optim.LBFGS([labels], lr=0.1) # Or Adam for first-order + for epoch in range(10): # LBFGS often converges in few steps + def closure(): + optimizer.zero_grad() + loss = coherence_loss(labels, tuples, priors) + loss.backward() + return loss + optimizer.step(closure) + print(f"Epoch {epoch}: Loss {closure().item()}") + + # Final labels: argmax or softmax + final_labels = torch.argmax(F.softmax(labels, dim=1), dim=1) + ``` + + - **Tweaks**: + - **For Rankings/Calibration**: Replace cross-entropy with a ranking loss (e.g., `torch.nn.MarginRankingLoss` on logprob differences) to treat LLM outputs as rankings. + - **Learning Weights**: Add learnable params like `evidence_weights = torch.nn.Parameter(torch.ones(num_evidence_types))` and multiply them into the loss terms. + - **Efficiency**: With num_labels=100 and 1000 tuples, this runs in seconds on CPU. L-BFGS is perfect for small params (as you said). + - **Landmark Calibration**: Post-optimization, use a few "landmark" examples (e.g., known easy/hard ones) to scale the final probs. + + ### Updated Ratings (Complexity and Expected Gain) + Adjusted for this simplified backprop (no LLM in the loop): + - **Complexity: Medium** (Down from High—pre-computing makes it easier, but custom loss debugging adds some work. ~1-2 hours to prototype if you're PyTorch-familiar.) + - **Expected Gain: Medium-High** (Same as before—could outperform simple accumulation on fuzzy tasks like TruthfulQA by learning nuanced propagations. Matches Fabien's ~100% PGR potential if your priors capture salient concepts. Gains depend on how well tuples cover dependencies; test vs. baseline ICM.) + + This setup feels like a great balance—powerful enough for your ideas without overcomplicating. If it works on a small test (e.g., 20 examples from the GitHub repo), scale it up! What dataset are you thinking of using first, or do you want help refining the loss function? 😊 + + ---- + + Below, I'll address each part of your query step by step, building on our discussion. I'll start with explanations for landmark calibration, pairwise ranking losses, and the consistency measures (with learnable weights). Then, I'll provide a full example code snippet for the loss function, incorporating all of this. The code expands on my previous PyTorch sketch, making it more concrete and tailored to your ideas (e.g., n-shot prediction tuples, logprob ratios as priors, multiple consistency terms with weights). + + This setup assumes: + - You have pre-computed data from the LLM: `priors` (logprob-based scores/ratios for each label) and `tuples` (n-shot contexts with LLM-generated predictions). + - Labels are learnable parameters (e.g., logits for yes/no). + - Optimization is over these labels to minimize a custom loss that encourages coherence, using gradients for propagation. + + The result is an efficient, backprop-based label optimizer that's lightweight (runs fast on small datasets) and aligns with ICM-style unsupervised elicitation. + + ### 1. Landmark Calibration for Logprob Ratios as Priors + Landmark calibration is a way to adjust raw LLM logprobs (which are often miscalibrated, as discussed in the LessWrong thread) using a few "landmark" examples with known properties (e.g., easy/true cases where you expect high confidence, or hard/false ones for low confidence). This turns uncalibrated logprobs into more reliable priors before optimization. It's not strictly necessary (you can skip it and rely on rankings), but it helps if you want priors to act like soft probabilities. + + - **How to Do It Pre-Optimization**: + 1. Select 5-20 landmark examples (e.g., from your dataset or synthetic ones: obvious "yes" math problems from GSM8K for high prob_yes, common misconceptions from TruthfulQA for low). + 2. Query the LLM for logprobs on these. + 3. Fit a simple calibrator: E.g., temperature scaling (find a temp `T` that minimizes cross-entropy on landmarks) or Platt scaling (linear transform: scaled_logit = a * logit + b). + 4. Apply to all logprob ratios: prior_score = (logprob_pos - logprob_neg) / T (or whatever your ratio is). + 5. Convert to soft priors: prior_probs = softmax([prior_score, -prior_score]) for [yes, no]. + + - **Integration as Priors in PyTorch**: + - These calibrated ratios become fixed tensors (not parameters)—you'll use them in a regularization term (e.g., KL loss) to pull the learnable labels toward them. + - **Will KL Loss Make This Happen End-to-End?** Yes! By adding a KL divergence term in the loss (as in my previous sketch), the optimization will naturally balance the priors with other terms (e.g., coherence). No need to make priors learnable—they're anchors. During backprop, gradients from KL will propagate to update labels toward calibrated values. If you want to learn how much to trust priors, add a learnable weight (e.g., `alpha` in the loss) and optimize it too (via hyperparam sweep or as a parameter). + + - **When to Skip**: If treating logprobs as rankings (via pairwise losses—see below), calibration is less critical. Just use raw differences as relative strengths. + + Example calibration code (pre-optimization): + ```python + import torch + import torch.nn.functional as F + + # Assume landmarks: list of (logprob_pos, logprob_neg, true_label) # true_label=1 for yes + def calibrate_temperature(logprobs_pos, logprobs_neg, true_labels, temps=[0.5, 1.0, 2.0]): + best_temp, best_loss = None, float('inf') + for T in temps: + scaled_logits = torch.tensor([(p - n) / T for p, n in zip(logprobs_pos, logprobs_neg)]) + preds = F.softmax(scaled_logits.unsqueeze(1), dim=1)[:, 0] # Prob yes (assuming binary) + loss = F.binary_cross_entropy(preds, torch.tensor(true_labels).float()) + if loss < best_loss: + best_temp, best_loss = T, loss + return best_temp + + # Apply to all priors + temp = calibrate_temperature(landmark_pos, landmark_neg, landmark_true) + priors = torch.tensor([(p - n) / temp for p, n in zip(all_logprobs_pos, all_logprobs_neg)]) # Shape: (num_labels,) + priors = F.softmax(torch.stack([priors, -priors], dim=1), dim=1) # To [prob_yes, prob_no] + ``` + + ### 2. Pairwise Ranking Losses (e.g., Margin Loss on Logprob Differences) + Pairwise ranking losses treat logprobs as relative rankings (e.g., "is yes better than no?") rather than absolute probabilities, avoiding calibration issues entirely. This is reliable because LLM logprobs are better for comparisons (as you noted—they're often used for ranking preferences in RLHF). + + - **How It Works**: + - Instead of cross-entropy (which assumes calibrated probs), you define pairs of options and penalize if the ranking doesn't match expectations. + - Use `torch.nn.MarginRankingLoss` (or `torch.nn.PairwiseMarginRankingLoss`): It takes two scores (e.g., score_yes and score_no) and a target (1 if yes > no, -1 if no > yes, 0 if tie). Loss = max(0, -target * (score1 - score2) + margin). This enforces a margin between better/worse options. + - **What Are the Pairs?**: + - **Per-Label Pairs**: For each label, pair its "yes" vs. "no" logprob differences (e.g., from priors or tuple predictions). Target=1 if the learnable label leans yes (e.g., labels_soft[:,0] > 0.5). + - **Across-Tuple Pairs**: For a prediction tuple, pair the LLM's predicted prob_yes vs. prob_no, and compare to the learnable target label. Or pair different tuples' predictions to enforce mutual predictability (e.g., "if context A predicts yes, it should rank higher than context B predicting no"). + - **Propagation Pairs**: To capture "downstream consistency," pair a label's score with aggregated scores from dependent tuples (e.g., if this label is in many contexts, ensure its ranking boosts overall coherence). + + - **Why Avoid Calibration Issues?**: It only cares about order (e.g., yes ranks above no by at least margin=1.0), not absolute values. Great for your logprob ratios. + + In code, it'll be a term in the loss (see full example below). + + ### 3. Measures of Consistency with Learnable/Hyperparam Weights + Yes, modularizing the loss into weighted consistency measures is a smart way to prevent "cheating" (e.g., superficial solutions, as in ICM's logical constraints). You can make weights learnable (as parameters) for end-to-end adaptation, or sweep them as hyperparameters (safer if worried about overfitting/cheating). Start with 3-5 measures, weighted by a vector (e.g., [w_direct, w_downstream, w_mutual]). + + - **Suggested Measures** (with your ideas incorporated): + - **Direct Consistency**: Penalizes labels that flip-flop (e.g., variance across similar tuples). Weight: High if you have noisy priors. + - **Downstream Consistency/Contribution**: Measures how much a label improves predictions in dependent tuples (e.g., lower loss/entropy when this label is in the context). This propagates "if this label led to more confident predictions" as you described. + - **Mutual Predictability**: As in ICM/Fabien's work—how well one label predicts another (e.g., cross-entropy between predicted and target in tuples). + - **Others to Consider**: + - **Logical Consistency**: Penalize violations of rules (e.g., mutex labels can't both be yes). + - **Prior Fidelity**: KL to calibrated priors (as above). + - **Entropy/Confidence**: Reward low-entropy (confident) labels, but only if they contribute to coherence. + + - **Learnable Weights?**: Yes—make them parameters (e.g., `weights = torch.nn.Parameter(torch.ones(3))`) and include in optimization. Or sweep (e.g., grid search [0.1, 0.5, 1.0] per weight) to avoid cheating. Learning is efficient for small #weights. + + ### 4. Full Example Code for Loss (and Optimization) + Here's an integrated PyTorch example. It includes landmark calibration (pre-step), pairwise ranking loss, multiple consistency measures with learnable weights, and LBFGS for fast convergence (2-5x faster than Adam on small problems, as you referenced—great for <1000 labels). + + ```python + import torch + import torch.nn as nn + import torch.nn.functional as F + + # Pre-compute calibrated priors (from landmark calibration, as above) + # Assume priors: torch.Tensor (num_labels, 2) # [prob_yes, prob_no] + # tuples: list of dicts, e.g., {'context_indices': [0,1,2], 'target_index': 3, 'llm_pred': [0.7, 0.3]} + + # Setup learnables + num_labels = len(priors) + labels = nn.Parameter(torch.randn(num_labels, 2)) # Logits [yes, no] + consistency_weights = nn.Parameter(torch.ones(3)) # Learnable: [w_direct, w_downstream, w_mutual] + + # Custom loss function + def coherence_loss(labels, tuples, priors, margin=1.0): + labels_soft = F.softmax(labels, dim=1) # Soft probs [num_labels, 2] + weights = F.softplus(consistency_weights) # Ensure positive + loss = 0.0 + + # Measure 1: Direct Consistency (e.g., low variance across tuples for same target) + direct_loss = 0.0 + for target in set(t['target_index'] for t in tuples): # Group by target + target_preds = torch.stack([labels_soft[target] for t in tuples if t['target_index'] == target]) + direct_loss += target_preds.var(dim=0).mean() # Variance penalty + direct_loss /= num_labels or 1 + + # Measure 2: Downstream Consistency (how much label contributes to low-entropy downstream) + downstream_loss = 0.0 + for t in tuples: + context_soft = labels_soft[t['context_indices']].mean(dim=0) # Aggregated context + target_soft = labels_soft[t['target_index']] + entropy = -torch.sum(target_soft * torch.log(target_soft + 1e-8)) # Lower is better + downstream_loss += entropy # Or use as reward (negative) + downstream_loss /= len(tuples) or 1 + + # Measure 3: Mutual Predictability (cross-entropy between context avg and target) + mutual_loss = 0.0 + for t in tuples: + context_soft = labels_soft[t['context_indices']].mean(dim=0).unsqueeze(0) + target_soft = labels_soft[t['target_index']].unsqueeze(0) + mutual_loss += F.cross_entropy(context_soft, target_soft) + mutual_loss /= len(tuples) or 1 + + # Combine weighted consistencies + consistency_loss = (weights[0] * direct_loss + weights[1] * downstream_loss + weights[2] * mutual_loss) / weights.sum() + + # Pairwise Ranking Loss (on logprob differences, e.g., per-tuple pairs) + ranking_loss = 0.0 + rank_loss_fn = nn.MarginRankingLoss(margin=margin) + for t in tuples: + # Pair: LLM pred_yes vs. pred_no; target=1 if learnable leans yes + score_yes = torch.tensor(t['llm_pred'][0]).log() - torch.tensor(t['llm_pred'][1]).log() # Logprob diff + score_no = -score_yes # Opposite + target = 1 if labels_soft[t['target_index'], 0] > 0.5 else -1 + ranking_loss += rank_loss_fn(score_yes, score_no, torch.tensor(target)) + ranking_loss /= len(tuples) or 1 + + # Prior Regularization (KL to calibrated priors) + prior_loss = F.kl_div(F.log_softmax(labels, dim=1), priors, reduction='batchmean') + + # Total loss + loss = consistency_loss + 0.5 * ranking_loss + 0.1 * prior_loss # Tune coefficients + return loss + + # Optimize with LBFGS for fast convergence + optimizer = torch.optim.LBFGS([labels, consistency_weights], lr=0.1, max_iter=20) + for epoch in range(10): + def closure(): + optimizer.zero_grad() + loss = coherence_loss(labels, tuples, priors) + loss.backward() + return loss + optimizer.step(closure) + print(f"Epoch {epoch}: Loss {closure().item()}") + + # Final: argmax labels + final_labels = torch.argmax(F.softmax(labels, dim=1), dim=1) + ``` + + - **Notes on the Code**: + - **Customization**: Add more measures (e.g., logical constraints as `if label_i >0.5 and label_j >0.5: penalty +=1`). Tune margins/coeffs. + - **Efficiency**: LBFGS converges 2-5x faster (often in 5-20 steps) on small setups. If learnable weights cause issues (cheating), fix them and sweep. + - **Testing**: Run on a small subset (e.g., 10 labels, 50 tuples) to debug. + + This should give you a solid starting point—flexible, incorporates your ideas, and ties back to the paper's coherence maximization. If you test it and share results (or need tweaks, like adding more terms), let me know! 😊 + + +## Further specific implementation details + + +We can take `nbs/05_backprop.py` which loads `Path("outputs/icm/evidence_test_predictions.jsonl")` which are the LLM predictions over TruthfulQA. Now we can keep it simple, and keep the loss function flexible and hackable (without being defensive about expections ,we can fix them instead of worry about them). + +So first lets plan, if you took at `nbs/05_backprop.py` you see it loads the LLM predictions, and then creates a `tuples` list of dicts with keys. Could you strip out what we don't need, and instead add this pytorch backprop idea, with multiple things wighted in the loss functions? How would you do it, high level? diff --git a/nbs/05_backprop.py b/nbs/05_backprop.py index 1560072..11d5b96 100644 --- a/nbs/05_backprop.py +++ b/nbs/05_backprop.py @@ -12,10 +12,12 @@ import numpy as np import pandas as pd from loguru import logger from collections import defaultdict +import torch +import torch.nn as nn +import torch.nn.functional as F +import torch.optim as optim -logger.info("Imports complete") - # %% [code] # Load TruthfulQA data with labels from src.data.truthfulqa import load_truthfulqa @@ -32,13 +34,18 @@ data[0] # %% # Save predictions as JSONL -output_path = Path("../outputs/icm/evidence_test_predictions.jsonl") - - +output_path = Path("outputs/icm/evidence_test_predictions.jsonl") preds = list(srsly.read_jsonl(output_path)) df_preds = pd.DataFrame(preds) preds[0] + +# replace with outputs. +output_path = Path("./outputs/icm/truthfulqa/icm_final_labels.parquet") +# Index(['uid', 'prompt', 'vanilla_label', 'consistency_id', 'consistency_key', 'label', 'score'], +df_preds = pd.read_parquet(output_path) +df_preds + # {'target_uid': 20, # 'target_idx': 20, # 'score': 0.9999999999991981, @@ -52,4 +59,309 @@ preds[0] # ... (more context entries) # ], # 'variations': {'reversed': False, 'reordered': True}} -# %% +# %% [code] +# Prep data for backprop + +# Create DF from original data for joining +df_data = pd.DataFrame(data) +df_data.set_index('uid', inplace=True) + +# Extract unique uids (assuming all from data) +unique_uids = sorted(df_data.index.tolist()) +num_labels = len(unique_uids) +uid_to_idx = {uid: idx for idx, uid in enumerate(unique_uids)} + +# Compute priors: avg raw_logprob_diff per target_uid +priors_diff = defaultdict(list) +for pred in preds: + target_uid = pred['target_uid'] + diff = pred['raw_logprob_diff'] + priors_diff[target_uid].append(diff) + +# Average diffs, default to 0 if no preds +# FIXME should we say mean /std +avg_diffs = {uid: np.mean(priors_diff.get(uid, [0.0])) / (1+np.std(priors_diff.get(uid, [1.0]))) for uid in unique_uids} +scale = 10.0 # Normalize large logprobs +prior_logits = torch.tensor([[ -d / scale, d / scale ] for d in avg_diffs.values()]) # [logit_0, logit_1] +# priors = F.softmax(prior_logits, dim=1) # Soft priors [num_labels, 2] + +priors = prior_logits + +# Build tuples: subsample to 500 for speed +tuples = [] +for pred in preds: # Subsample + context_uids = [c['uid'] for c in pred['context']] + valid_context = [u for u in context_uids if u in uid_to_idx] # Filter valid + if len(valid_context) > 0 and pred['target_uid'] in uid_to_idx: + tuples.append({ + 'context_uids': valid_context, + 'target_uid': pred['target_uid'], + 'llm_pred_diff': pred['raw_logprob_diff'], + 'llm_pred_score': pred['score'] # Proxy for prob_1 + }) + +# Join with original data for consistency_id (add to tuples or separate) +# For now, create consistency_groups: dict of lists of uids per consistency_id +consistency_groups = defaultdict(list) +for uid, row in df_data.iterrows(): + consistency_groups[row['consistency_id']].append(uid) + +print(f"Num labels: {num_labels}, Num tuples: {len(tuples)}") +print(f"Sample prior: {priors[0]}") +print(f"Sample tuple: {tuples[0] if tuples else 'None'}") +# %% [code] +# Define learnables + +# Learnable labels: logits for binary [0,1] per uid +labels = nn.Parameter(prior_logits) + +# Fixed weights for loss terms (hackable: adjust here) +loss_weights = { + 'mutual': 1.0, + 'ranking': 0.5, + 'prior': 0.1, + 'direct': 0.5, + 'entropy': 0.1 +} + +print(f"Labels shape: {labels.shape}") +print(f"Loss weights: {loss_weights}") +# %% [code] +# Define modular loss function + +def coherence_loss(labels, tuples, priors, consistency_groups, uid_to_idx, loss_weights, scale=1000.0, verbose=False): + """ + Custom loss for unsupervised label optimization. + + Combines multiple terms to encourage coherence: + - Mutual Predictability: Context labels should predict target (CE loss). + - Pairwise Ranking: Align learned rankings with LLM logprob diffs. + - Prior KL: Anchor to LLM priors. + - Direct Consistency: Low variance within groups. + - Entropy: Encourage confident (low-entropy) labels. + + Weighted sum for flexibility; adjust loss_weights dict to tune. + """ + # FIXME learning weightson the loss can lead to rewards hacking, e.g. learn 1 for easy loss, and 0 for hard ones + soft_labels = F.softmax(labels, dim=1) # [num_labels, 2] + rank_loss_fn = nn.MarginRankingLoss(margin=1.0) + total_loss = 0.0 + num_tuples = len(tuples) + terms = {} + + # Build graph: lists for directed edges (context -> target) with weights + # No extra deps; use loop-based aggregation for small num_labels (~800) + num_nodes = soft_labels.shape[0] + weighted_context = torch.zeros_like(soft_labels) # [num_nodes, 2] + degrees = torch.zeros(num_nodes) # For normalization + + for t in tuples: + target_idx = uid_to_idx[t['target_uid']] + context_indices = torch.tensor([uid_to_idx[u] for u in t['context_uids']]) + if len(context_indices) == 0: + continue + + # Offline weighting: closeness to majority (L2 dist to mean context soft) + context_soft_local = soft_labels[context_indices] # [n_context, 2] + majority = context_soft_local.mean(dim=0) + dists = torch.norm(context_soft_local - majority.unsqueeze(0), dim=1) + weights = 1.0 / (dists + 1e-5) # Higher for closer + weights = weights / weights.sum() # Normalize + + # Aggregate: weighted sum to target + weighted_context[target_idx] += (soft_labels[context_indices] * weights.unsqueeze(1)).sum(dim=0) + degrees[target_idx] += 1.0 # Count incoming (simple, since weights normalized per tuple) + + # Normalize (avg if degrees >0) + mask = degrees > 0 + weighted_context[mask] /= degrees[mask].unsqueeze(1) + + # Updated Mutual: Use weighted_context for CE + mutual_loss = 0.0 + for t in tuples: + target_idx = uid_to_idx[t['target_uid']] + if degrees[target_idx] == 0: + continue + context_agg = weighted_context[target_idx] + target_soft = soft_labels[target_idx] + + # Forward + mutual_loss += F.cross_entropy(context_agg.unsqueeze(0), target_soft.unsqueeze(0)) + + # Reverse + mutual_loss += F.cross_entropy(target_soft.unsqueeze(0), context_agg.unsqueeze(0)) + terms['mutual'] = mutual_loss / max(num_tuples, 1) / 2 + + # Pairwise Ranking: Enforce ranking on learnable diff vs LLM pred diff + # Intuition: LLM logprobs are better for relative rankings than absolute probs; ensure learned prob ranking matches LLM's scaled logprob diff. + # Simple English: "The LLM ranked 'yes' higher than 'no' for this example—make sure your learned label agrees on which is stronger, with a safety margin to avoid ties. Like forcing your guesses to match the model's confidence order, not exact numbers." + ranking_loss = 0.0 + for t in tuples: + target_idx = uid_to_idx[t['target_uid']] + llm_diff = t['llm_pred_diff'] / scale + score1 = soft_labels[target_idx, 1] # Prob 1 + score2 = soft_labels[target_idx, 0] # Prob 0 + target_rank = 1 if llm_diff > 0 else -1 + if target_rank == -1: + ranking_loss += rank_loss_fn(score2, score1, torch.tensor(1.0)) + else: + ranking_loss += rank_loss_fn(score1, score2, torch.tensor(1.0)) + terms['ranking'] = ranking_loss / max(num_tuples, 1) + + # Prior KL: Pull toward priors + # Intuition: Anchor learned labels to fixed LLM priors (averaged logprob diffs) via KL on logits to prevent drift from model's initial biases. + # Simple English: "Don't stray too far from the model's original hunches (its logprob biases for each example). Pull labels back toward these starting points gently, like a rubber band keeping you grounded in what the model already 'knows'." + prior_loss = F.kl_div(F.log_softmax(labels, dim=1), priors, reduction='batchmean') + terms['prior'] = prior_loss + + # Direct Consistency: Penalize variance within consistency groups + # Intuition: Labels in the same group (e.g., related questions via consistency_id) should agree; penalize soft label variance for local stability. + # Simple English: "Related examples (like paraphrases) should have similar labels—don't let them vary wildly. Average their probabilities and punish if they're all over the place, ensuring the model doesn't contradict itself on similar stuff." + direct_loss = 0.0 + num_groups = 0 + for group_uids in consistency_groups.values(): + group_indices = [uid_to_idx.get(u) for u in group_uids if u in uid_to_idx] + if len(group_indices) > 1: + group_soft = soft_labels[torch.tensor(group_indices)] + direct_loss += group_soft.var(dim=0).mean() + num_groups += 1 + terms['direct'] = direct_loss / max(num_groups, 1) + + # Entropy: Penalize high entropy in targets (encourage confident labels) + # Intuition: Reward low-entropy (decisive) labels for targets, proxying downstream confidence from coherent propagation. + # Simple English: "Make labels decisive (mostly yes or no, not 50/50 unsure). For each target, calculate how 'spread out' its probability is and add a small penalty if it's too wishy-washy—pushes toward bold, consistent choices that build confidence across predictions." + entropy_loss = 0.0 + for t in tuples: + target_idx = uid_to_idx[t['target_uid']] + target_soft = soft_labels[target_idx] + entropy = -(target_soft * torch.log(target_soft + 1e-8)).sum() + entropy_loss += entropy + terms['entropy'] = entropy_loss / max(num_tuples, 1) + + # New: Reward context for good evidence + reward_loss = 0.0 + for t in tuples: + target_idx = uid_to_idx[t['target_uid']] + context_indices = torch.tensor([uid_to_idx[u] for u in t['context_uids']]) + if len(context_indices) == 0: + continue + + target_soft = soft_labels[target_idx] + target_entropy = -(target_soft * torch.log(target_soft + 1e-8)).sum() + reward = 1.0 / (target_entropy + 1e-5) # Higher for confident target + + context_soft = soft_labels[context_indices] + context_entropy = -(context_soft * torch.log(context_soft + 1e-8)).sum(dim=1).mean() + reward_loss += -reward * context_entropy # Reward low context entropy + terms['reward'] = reward_loss / max(num_tuples, 1) + + # Weighted sum (include 'reward') + weighted_loss = sum(loss_weights.get(k, 0.0) * terms[k] for k in terms) + total_loss = weighted_loss / (sum(loss_weights.values()) + loss_weights.get('reward', 0.0) or 1e-5) + + # For hacking: print terms + if torch.is_grad_enabled() and verbose: + print(f"Loss terms: { {k: v.item() if hasattr(v, 'item') else v for k,v in terms.items()} }") + + return total_loss + +# Test with dummy +dummy_loss = coherence_loss(labels, tuples[:1], priors, consistency_groups, uid_to_idx, loss_weights) +print(f"Sample loss: {dummy_loss.item()}") +# %% [code] + +def run_backprop_experiment(labels, tuples, priors, consistency_groups, uid_to_idx, loss_weights, df_data, df_preds, unique_uids, avg_diffs): + """ + Run backprop experiment with given weights, return metrics. + """ + # Copy labels + current_labels = labels.clone().detach().requires_grad_(True) + + # optimizer = optim.LBFGS([current_labels], lr=0.1, max_iter=20) + optimizer = optim.AdamW([current_labels], lr=0.1) + losses = [] + epochs = 10 + + for epoch in tqdm(range(epochs), desc="Optimizing"): + def closure(): + optimizer.zero_grad() + loss = coherence_loss(current_labels, tuples, priors, consistency_groups, uid_to_idx, loss_weights, verbose=False) + loss.backward() + return loss + loss_val = optimizer.step(closure) + losses.append(loss_val.item()) + + # Post-process + final_soft = F.softmax(current_labels, dim=1) + final_hard = torch.argmax(final_soft, dim=1).cpu().numpy() + + # Output DF in memory + output_data = [] + for uid in unique_uids: + idx = uid_to_idx[uid] + row = df_data.loc[uid].to_dict() + row['uid'] = uid + row['learned_soft_0'] = float(final_soft[idx, 0].detach()) + row['learned_soft_1'] = float(final_soft[idx, 1].detach()) + row['learned_hard'] = int(final_hard[idx]) + row['prior_diff'] = avg_diffs.get(uid, 0.0) + output_data.append(row) + + df_output = pd.DataFrame(output_data) + acc = (df_output['learned_hard'] == df_output['vanilla_label']).mean() if 'vanilla_label' in df_output.columns else 0.0 + + # LLM acc + llm_acc = 0.0 + if not df_preds.empty and 'target_uid' in df_preds.columns and 'vanilla_label' in df_data.columns: + df_preds_local = df_preds.copy() + df_preds_local['hard_llm_pred'] = (df_preds_local['raw_logprob_diff'] > 0).astype(int) + common_preds = df_preds_local.merge(df_data.reset_index()[['uid', 'vanilla_label']], left_on='target_uid', right_on='uid', how='inner') + if not common_preds.empty: + llm_acc = (common_preds['hard_llm_pred'] == common_preds['vanilla_label']).mean() + + # ICM corr + icm_corr = 0.0 + output_dir = Path("outputs/backprop") + icm_path = output_dir.parent / "icm/truthfulqa/icm_final_labels.parquet" + if icm_path.exists(): + df_icm = pd.read_parquet(icm_path) + if 'uid' in df_icm.columns and 'label' in df_icm.columns: + df_icm.set_index('uid', inplace=True) + common_uids = set(df_output['uid']).intersection(df_icm.index) + if common_uids and len(common_uids) > 1: + backprop_hard_common = df_output[df_output['uid'].isin(common_uids)]['learned_hard'].values + icm_labels_common = df_icm.loc[list(common_uids), 'label'].values + icm_corr = np.corrcoef(backprop_hard_common, icm_labels_common)[0, 1] + + return { + 'acc': acc, + 'icm_corr': icm_corr, + 'final_loss': losses[-1] if losses else 0.0, + 'llm_acc': llm_acc + } + +# %% [code] + +# Experiment with loss weights: Loop over variations, print key results + +# Baseline weights +base_weights = { + 'mutual': 1.0, + 'ranking': 0.5, + 'prior': 0.1, + 'direct': 0.5, + 'entropy': 0.1, + 'reward': 0.2 +} + +# Example: Vary mutual weight (one at a time, as suggested) +mutual_variations = [0.1, 0.5, 1.0, 2.0] +results = {} + +for mw in mutual_variations: + weights = base_weights.copy() + weights['mutual'] = mw + print(f"\n--- Testing mutual_weight = {mw} ---") + res = run_backprop_experiment(labels, tuples, priors, consistency_groups, uid_to_idx, weights, df_data, df_preds, unique_uids, avg_diffs) + results[mw] = res + print(f"Mutual {mw}: Acc {res['acc']:.4f}, ICM Corr {res['icm_corr']:.4f}, Final Loss {res['final_loss']:.4f}, LLM Acc {res['llm_acc']:.4f}") diff --git a/pyproject.toml b/pyproject.toml index 6192b30..a9cf3fe 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,6 +40,7 @@ dependencies = [ "tenacity>=9.1.2", "termcolor>=3.1.0", "tiktoken>=0.11.0", + "torch>=2.9.0", "tqdm>=4.67.1", "trueskill>=0.4.5", "typer[all]>=0.19.2", diff --git a/src/data/__init__.py b/src/data/__init__.py index fadcc98..8e2b941 100644 --- a/src/data/__init__.py +++ b/src/data/__init__.py @@ -10,7 +10,7 @@ def is_consistent(group_uids, demos): # Get labeled items only labeled = [(uid, demos[uid]['label'], demos[uid]['consistency_key']) - for uid in group_uids if demos[uid]['label'] is not None] + for uid in group_uids if demos[uid].get('label', None) is not None] if len(labeled) < 2: return True # Can't be inconsistent with <2 labels diff --git a/src/simple_icm.py b/src/simple_icm.py index 7808b99..b1f7b14 100644 --- a/src/simple_icm.py +++ b/src/simple_icm.py @@ -19,7 +19,7 @@ from dataclasses import dataclass, asdict import dotenv from loguru import logger from openrouter_wrapper.logprobs import openrouter_completion_wlogprobs, get_logprobs_choices, LogprobsNotSupportedError # User's wrapper -from typing import List, Optional, Tuple, Callable, Literal +from typing import List, Optional, Tuple, Callable, Literal, Any import asyncio from aiocache import cached from itertools import combinations @@ -79,6 +79,15 @@ class Config: out_dir: Path = Path("./outputs/icm") # Directory to save outputs +@dataclass +class PredictionLog: + uid: str + target: int + score: float + pred_label: bool + context: List[List[Any]] + + import simple_parsing C: Config = simple_parsing.parse(Config) @@ -140,6 +149,13 @@ logger.info("Initialized labels: {}", {k: v['pred_label'] for k, v in demonstrat # %% [code] # Predict label using in-context prompting +@dataclass +class PredictionLog: + uid: str + target: int + score: float + pred_label: bool + context: List[List[PredictionLog]] def print_messages(messages): return "\n".join([f"**{m['role'].upper()}**: {m['content']}" for m in messages]) @@ -224,11 +240,15 @@ Reasoning for UID {example_uid}, labelled {len(labeled)}: logger.warning(f"Choices not returned for UID {example_uid}, may indicate model confusion. choice_logp={choice_logp}. Instead we got these top logprobs: {top_logp} and \nmessages: ...`{print_messages(messages)[-90:]}`\nthis output:`{model_response}`") score = choice_logp["A"] - choice_logp["B"] predicted = 1 if score > 0 else 0 - return predicted, float(score) + + context = [PredictionLog(uid=demo['uid'], target=demo['prompt'], score=demo['score'], pred_label=demo['pred_label'], context=[]) for demo in relevant_demos] + pred_log = PredictionLog(uid=example_uid, target=predicted, score=float(score), pred_label=bool(predicted), context=context) + + return predicted, float(score), pred_log except Exception as e: raise e logger.exception(f"API error: {e}") - return random.choice([0, 1]), 0.0 + return random.choice([0, 1]), 0.0, None # %% [code] @@ -424,13 +444,19 @@ async def run_icm(demonstrations, config=C): tasks = [predict_label(uid, current_labeled, config, verbose=verbose, all_demos=demonstrations) for uid in candidate_uids] results = await asyncio.gather(*tasks) + + with open(out_dir / "predictions.jsonl", "a") as f: + for _, _, pred_log in results: + if pred_log is not None: + json.dump(asdict(pred_log), f) + f.write('\n') # Evaluate each candidate's energy delta best_uid = None best_delta = float('-inf') best_temp_demos = None - for uid, (new_label, score) in zip(candidate_uids, results): + for uid, (new_label, score, _) in zip(candidate_uids, results): temp_demos = deepcopy(demonstrations) temp_demos[uid]['pred_label'] = new_label temp_demos[uid]['score'] = score @@ -475,6 +501,8 @@ async def run_icm(demonstrations, config=C): logger.info("Stopping early.") except asyncio.CancelledError: logger.info("Asyncio task cancelled.") + + return demonstrations, energies, accuracies @@ -482,7 +510,7 @@ async def run_icm(demonstrations, config=C): # Run the algorithm try: final_demos, energies, accuracies = asyncio.run(run_icm(demonstrations, C)) -except Exception as e: +except (asyncio.CancelledError, KeyboardInterrupt) as e: logger.exception(f"Error during ICM run: {e}") final_demos = demonstrations energies = [] @@ -502,6 +530,7 @@ logger.info("Inconsistencies: {}", final_metrics['num_inconsistent']) df = pd.DataFrame(final_demos).T df.to_parquet(out_dir / "icm_final_labels.parquet") + df_labeled = df.dropna(subset='pred_label').sort_values(by='score', key=np.abs, ascending=False) df_labeled_disagreed = df_labeled[df_labeled['vanilla_label'] != df_labeled['pred_label']] @@ -512,6 +541,7 @@ for uid, row in df_labeled_disagreed.iterrows(): print(f"\n## Candidate: {row['prompt']}\nICM Set: {'A' if row['pred_label']==1 else 'B'}, Vanilla Set: {'A' if row['vanilla_label']==1 else 'B'}, score={row['score']}\n") print(f"\nFinal labeled examples saved to {out_dir / 'icm_final_labels.parquet'}") +print(f"Predictions log saved to {out_dir / 'predictions.jsonl'}") # %% [code] # Simple visualization (requires matplotlib) diff --git a/uv.lock b/uv.lock index 97325c0..dad920d 100644 --- a/uv.lock +++ b/uv.lock @@ -1833,6 +1833,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/29/40/646448b5ad66efec097471bd5ab25f5b08360e3f34aecbe5c4fcc6845c01/mistralai-1.9.10-py3-none-any.whl", hash = "sha256:cf0a2906e254bb4825209a26e1957e6e0bacbbe61875bd22128dc3d5d51a7b0a", size = 440538, upload-time = "2025-09-02T07:44:37.5Z" }, ] +[[package]] +name = "mpmath" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e0/47/dd32fa426cc72114383ac549964eecb20ecfd886d1e5ccf5340b55b02f57/mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f", size = 508106, upload-time = "2023-03-07T16:47:11.061Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/43/e3/7d92a15f894aa0c9c4b49b8ee9ac9850d6e63b03c9c32c0367a13ae62209/mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c", size = 536198, upload-time = "2023-03-07T16:47:09.197Z" }, +] + [[package]] name = "multidict" version = "6.6.4" @@ -1971,6 +1980,34 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195, upload-time = "2024-01-21T14:25:17.223Z" }, ] +[[package]] +name = "networkx" +version = "3.4.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11' and sys_platform == 'linux'", + "python_full_version < '3.11' and sys_platform != 'linux'", +] +sdist = { url = "https://files.pythonhosted.org/packages/fd/1d/06475e1cd5264c0b870ea2cc6fdb3e37177c1e565c43f56ff17a10e3937f/networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1", size = 2151368, upload-time = "2024-10-21T12:39:38.695Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b9/54/dd730b32ea14ea797530a4479b2ed46a6fb250f682a9cfb997e968bf0261/networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f", size = 1723263, upload-time = "2024-10-21T12:39:36.247Z" }, +] + +[[package]] +name = "networkx" +version = "3.5" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.12' and sys_platform == 'linux'", + "python_full_version >= '3.12' and sys_platform != 'linux'", + "python_full_version == '3.11.*' and sys_platform == 'linux'", + "python_full_version == '3.11.*' and sys_platform != 'linux'", +] +sdist = { url = "https://files.pythonhosted.org/packages/6c/4f/ccdb8ad3a38e583f214547fd2f7ff1fc160c43a75af88e6aec213404b96a/networkx-3.5.tar.gz", hash = "sha256:d4c6f9cf81f52d69230866796b82afbccdec3db7ae4fbd1b65ea750feed50037", size = 2471065, upload-time = "2025-05-29T11:35:07.804Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/8d/776adee7bbf76365fdd7f2552710282c79a4ead5d2a46408c9043a2b70ba/networkx-3.5-py3-none-any.whl", hash = "sha256:0030d386a9a06dee3565298b4a734b68589749a544acbb6c412dc9e2489ec6ec", size = 2034406, upload-time = "2025-05-29T11:35:04.961Z" }, +] + [[package]] name = "nodeenv" version = "1.9.1" @@ -2133,6 +2170,140 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/af/11/0cc63f9f321ccf63886ac203336777140011fb669e739da36d8db3c53b98/numpy-2.3.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:2e267c7da5bf7309670523896df97f93f6e469fb931161f483cd6882b3b1a5dc", size = 12971844, upload-time = "2025-09-09T15:58:57.359Z" }, ] +[[package]] +name = "nvidia-cublas-cu12" +version = "12.8.4.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/61/e24b560ab2e2eaeb3c839129175fb330dfcfc29e5203196e5541a4c44682/nvidia_cublas_cu12-12.8.4.1-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:8ac4e771d5a348c551b2a426eda6193c19aa630236b418086020df5ba9667142", size = 594346921, upload-time = "2025-03-07T01:44:31.254Z" }, +] + +[[package]] +name = "nvidia-cuda-cupti-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f8/02/2adcaa145158bf1a8295d83591d22e4103dbfd821bcaf6f3f53151ca4ffa/nvidia_cuda_cupti_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea0cb07ebda26bb9b29ba82cda34849e73c166c18162d3913575b0c9db9a6182", size = 10248621, upload-time = "2025-03-07T01:40:21.213Z" }, +] + +[[package]] +name = "nvidia-cuda-nvrtc-cu12" +version = "12.8.93" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/6b/32f747947df2da6994e999492ab306a903659555dddc0fbdeb9d71f75e52/nvidia_cuda_nvrtc_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:a7756528852ef889772a84c6cd89d41dfa74667e24cca16bb31f8f061e3e9994", size = 88040029, upload-time = "2025-03-07T01:42:13.562Z" }, +] + +[[package]] +name = "nvidia-cuda-runtime-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0d/9b/a997b638fcd068ad6e4d53b8551a7d30fe8b404d6f1804abf1df69838932/nvidia_cuda_runtime_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:adade8dcbd0edf427b7204d480d6066d33902cab2a4707dcfc48a2d0fd44ab90", size = 954765, upload-time = "2025-03-07T01:40:01.615Z" }, +] + +[[package]] +name = "nvidia-cudnn-cu12" +version = "9.10.2.21" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cublas-cu12", marker = "sys_platform == 'linux'" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/51/e123d997aa098c61d029f76663dedbfb9bc8dcf8c60cbd6adbe42f76d049/nvidia_cudnn_cu12-9.10.2.21-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:949452be657fa16687d0930933f032835951ef0892b37d2d53824d1a84dc97a8", size = 706758467, upload-time = "2025-06-06T21:54:08.597Z" }, +] + +[[package]] +name = "nvidia-cufft-cu12" +version = "11.3.3.83" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-nvjitlink-cu12", marker = "sys_platform == 'linux'" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/1f/13/ee4e00f30e676b66ae65b4f08cb5bcbb8392c03f54f2d5413ea99a5d1c80/nvidia_cufft_cu12-11.3.3.83-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4d2dd21ec0b88cf61b62e6b43564355e5222e4a3fb394cac0db101f2dd0d4f74", size = 193118695, upload-time = "2025-03-07T01:45:27.821Z" }, +] + +[[package]] +name = "nvidia-cufile-cu12" +version = "1.13.1.3" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bb/fe/1bcba1dfbfb8d01be8d93f07bfc502c93fa23afa6fd5ab3fc7c1df71038a/nvidia_cufile_cu12-1.13.1.3-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1d069003be650e131b21c932ec3d8969c1715379251f8d23a1860554b1cb24fc", size = 1197834, upload-time = "2025-03-07T01:45:50.723Z" }, +] + +[[package]] +name = "nvidia-curand-cu12" +version = "10.3.9.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/aa/6584b56dc84ebe9cf93226a5cde4d99080c8e90ab40f0c27bda7a0f29aa1/nvidia_curand_cu12-10.3.9.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:b32331d4f4df5d6eefa0554c565b626c7216f87a06a4f56fab27c3b68a830ec9", size = 63619976, upload-time = "2025-03-07T01:46:23.323Z" }, +] + +[[package]] +name = "nvidia-cusolver-cu12" +version = "11.7.3.90" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-cublas-cu12", marker = "sys_platform == 'linux'" }, + { name = "nvidia-cusparse-cu12", marker = "sys_platform == 'linux'" }, + { name = "nvidia-nvjitlink-cu12", marker = "sys_platform == 'linux'" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/48/9a13d2975803e8cf2777d5ed57b87a0b6ca2cc795f9a4f59796a910bfb80/nvidia_cusolver_cu12-11.7.3.90-py3-none-manylinux_2_27_x86_64.whl", hash = "sha256:4376c11ad263152bd50ea295c05370360776f8c3427b30991df774f9fb26c450", size = 267506905, upload-time = "2025-03-07T01:47:16.273Z" }, +] + +[[package]] +name = "nvidia-cusparse-cu12" +version = "12.5.8.93" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nvidia-nvjitlink-cu12", marker = "sys_platform == 'linux'" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/f5/e1854cb2f2bcd4280c44736c93550cc300ff4b8c95ebe370d0aa7d2b473d/nvidia_cusparse_cu12-12.5.8.93-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:1ec05d76bbbd8b61b06a80e1eaf8cf4959c3d4ce8e711b65ebd0443bb0ebb13b", size = 288216466, upload-time = "2025-03-07T01:48:13.779Z" }, +] + +[[package]] +name = "nvidia-cusparselt-cu12" +version = "0.7.1" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/79/12978b96bd44274fe38b5dde5cfb660b1d114f70a65ef962bcbbed99b549/nvidia_cusparselt_cu12-0.7.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:f1bb701d6b930d5a7cea44c19ceb973311500847f81b634d802b7b539dc55623", size = 287193691, upload-time = "2025-02-26T00:15:44.104Z" }, +] + +[[package]] +name = "nvidia-nccl-cu12" +version = "2.27.5" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6e/89/f7a07dc961b60645dbbf42e80f2bc85ade7feb9a491b11a1e973aa00071f/nvidia_nccl_cu12-2.27.5-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ad730cf15cb5d25fe849c6e6ca9eb5b76db16a80f13f425ac68d8e2e55624457", size = 322348229, upload-time = "2025-06-26T04:11:28.385Z" }, +] + +[[package]] +name = "nvidia-nvjitlink-cu12" +version = "12.8.93" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f6/74/86a07f1d0f42998ca31312f998bd3b9a7eff7f52378f4f270c8679c77fb9/nvidia_nvjitlink_cu12-12.8.93-py3-none-manylinux2010_x86_64.manylinux_2_12_x86_64.whl", hash = "sha256:81ff63371a7ebd6e6451970684f916be2eab07321b73c9d244dc2b4da7f73b88", size = 39254836, upload-time = "2025-03-07T01:49:55.661Z" }, +] + +[[package]] +name = "nvidia-nvshmem-cu12" +version = "3.3.20" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/6c/99acb2f9eb85c29fc6f3a7ac4dccfd992e22666dd08a642b303311326a97/nvidia_nvshmem_cu12-3.3.20-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d00f26d3f9b2e3c3065be895e3059d6479ea5c638a3f38c9fec49b1b9dd7c1e5", size = 124657145, upload-time = "2025-08-04T20:25:19.995Z" }, +] + +[[package]] +name = "nvidia-nvtx-cu12" +version = "12.8.90" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/eb/86626c1bbc2edb86323022371c39aa48df6fd8b0a1647bc274577f72e90b/nvidia_nvtx_cu12-12.8.90-py3-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5b17e2001cc0d751a5bc2c6ec6d26ad95913324a4adb86788c944f8ce9ba441f", size = 89954, upload-time = "2025-03-07T01:42:44.131Z" }, +] + [[package]] name = "omegaconf" version = "2.3.0" @@ -3452,6 +3623,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/dd/44/4356cc64246ba7b2b920f7c97a85c3c52748e213e250b512ee8152eb559d/sentry_sdk-2.39.0-py2.py3-none-any.whl", hash = "sha256:ba655ca5e57b41569b18e2a5552cb3375209760a5d332cdd87c6c3f28f729602", size = 370851, upload-time = "2025-09-25T09:15:36.35Z" }, ] +[[package]] +name = "setuptools" +version = "80.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, +] + [[package]] name = "shellingham" version = "1.5.4" @@ -3607,6 +3787,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/58/f8/e2cca22387965584a409795913b774235752be4176d276714e15e1a58884/starlette-0.27.0-py3-none-any.whl", hash = "sha256:918416370e846586541235ccd38a474c08b80443ed31c578a418e2209b3eef91", size = 66978, upload-time = "2023-05-16T10:59:53.927Z" }, ] +[[package]] +name = "sympy" +version = "1.14.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mpmath" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/83/d3/803453b36afefb7c2bb238361cd4ae6125a569b4db67cd9e79846ba2d68c/sympy-1.14.0.tar.gz", hash = "sha256:d3d3fe8df1e5a0b42f0e7bdf50541697dbe7d23746e894990c030e2b05e72517", size = 7793921, upload-time = "2025-04-27T18:05:01.611Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a2/09/77d55d46fd61b4a135c444fc97158ef34a095e5681d0a6c10b75bf356191/sympy-1.14.0-py3-none-any.whl", hash = "sha256:e091cc3e99d2141a0ba2847328f5479b05d94a6635cb96148ccb3f34671bd8f5", size = 6299353, upload-time = "2025-04-27T18:04:59.103Z" }, +] + [[package]] name = "tabulate" version = "0.9.0" @@ -3718,6 +3910,67 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6e/c2/61d3e0f47e2b74ef40a68b9e6ad5984f6241a942f7cd3bbfbdbd03861ea9/tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc", size = 14257, upload-time = "2024-11-27T22:38:35.385Z" }, ] +[[package]] +name = "torch" +version = "2.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "fsspec" }, + { name = "jinja2" }, + { name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "networkx", version = "3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "nvidia-cublas-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cuda-cupti-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cuda-nvrtc-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cuda-runtime-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cudnn-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cufft-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cufile-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-curand-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cusolver-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cusparse-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-cusparselt-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nccl-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nvjitlink-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nvshmem-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "nvidia-nvtx-cu12", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "setuptools", marker = "python_full_version >= '3.12'" }, + { name = "sympy" }, + { name = "triton", marker = "platform_machine == 'x86_64' and sys_platform == 'linux'" }, + { name = "typing-extensions" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/bb/86/245c240d2138c17ed572c943c289056c2721abab70810d772c6bf5495b28/torch-2.9.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:030bbfe367379ae6a4ae4042b6c44da25383343b8b3c68abaa9c7231efbaf2dd", size = 104213554, upload-time = "2025-10-15T15:45:59.798Z" }, + { url = "https://files.pythonhosted.org/packages/58/1d/fd1e88ae0948825efcab7dd66d12bec23f05d4d38ed81573c8d453c14c06/torch-2.9.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:51cb63902182a78e90886e8068befd8ea102af4b00e420263591a3d70c7d3c6c", size = 899795167, upload-time = "2025-10-15T15:47:12.695Z" }, + { url = "https://files.pythonhosted.org/packages/63/5a/496197b45c14982bef4e079b24c61dc108e3ab0d0cc9718dba9f54f45a46/torch-2.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:3f6aad4d2f0ee2248bac25339d74858ff846c3969b27d14ac235821f055af83d", size = 109310314, upload-time = "2025-10-15T15:46:16.633Z" }, + { url = "https://files.pythonhosted.org/packages/58/b0/2b4e647b0fc706e88eb6c253d05511865578f5f67b55fad639bf3272a4a1/torch-2.9.0-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:413e1654c9203733138858780e184d9fc59442f0b3b209e16f39354eb893db9b", size = 74452019, upload-time = "2025-10-15T15:46:04.296Z" }, + { url = "https://files.pythonhosted.org/packages/58/fe/334225e6330e672b36aef23d77451fa906ea12881570c08638a91331a212/torch-2.9.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:c596708b5105d0b199215acf0c9be7c1db5f1680d88eddadf4b75a299259a677", size = 104230578, upload-time = "2025-10-15T15:46:08.182Z" }, + { url = "https://files.pythonhosted.org/packages/05/cc/49566caaa218872ec9a2912456f470ff92649894a4bc2e5274aa9ef87c4a/torch-2.9.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:51de31219c97c51cf4bf2be94d622e3deb5dcc526c6dc00e97c17eaec0fc1d67", size = 899815990, upload-time = "2025-10-15T15:48:03.336Z" }, + { url = "https://files.pythonhosted.org/packages/74/25/e9ab21d5925b642d008f139d4a3c9664fc9ee1faafca22913c080cc4c0a5/torch-2.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:dd515c70059afd95f48b8192733764c08ca37a1d19803af6401b5ecad7c8676e", size = 109313698, upload-time = "2025-10-15T15:46:12.425Z" }, + { url = "https://files.pythonhosted.org/packages/b3/b7/205ef3e94de636feffd64b28bb59a0dfac0771221201b9871acf9236f5ca/torch-2.9.0-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:614a185e4986326d526a91210c8fc1397e76e8cfafa78baf6296a790e53a9eec", size = 74463678, upload-time = "2025-10-15T15:46:29.779Z" }, + { url = "https://files.pythonhosted.org/packages/d1/d3/3985739f3b8e88675127bf70f82b3a48ae083e39cda56305dbd90398fec0/torch-2.9.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:e5f7af1dc4c0a7c4a260c2534f41ddaf209714f7c89145e644c44712fbd6b642", size = 104107898, upload-time = "2025-10-15T15:46:20.883Z" }, + { url = "https://files.pythonhosted.org/packages/a5/4b/f4bb2e6c25d0272f798cd6d7a04ed315da76cec68c602d87040c7847287f/torch-2.9.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:01cff95ecd9a212ea2f141db28acccdceb6a4c54f64e6c51091146f5e2a772c6", size = 899738273, upload-time = "2025-10-15T15:50:04.188Z" }, + { url = "https://files.pythonhosted.org/packages/66/11/c1c5ba6691cda6279087c35bd626536e4fd29521fe740abf5008377a9a02/torch-2.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:4582b162f541651f0cb184d3e291c05c2f556c7117c64a9873e2ee158d40062b", size = 109280887, upload-time = "2025-10-15T15:46:26.228Z" }, + { url = "https://files.pythonhosted.org/packages/dd/5f/b85bd8c05312d71de9402bf5868d217c38827cfd09d8f8514e5be128a52b/torch-2.9.0-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:33f58e9a102a91259af289d50525c30323b5c9ae1d31322b6447c0814da68695", size = 74478983, upload-time = "2025-10-15T15:46:39.406Z" }, + { url = "https://files.pythonhosted.org/packages/c2/1c/90eb13833cdf4969ea9707586d7b57095c3b6e2b223a7256bf111689bcb8/torch-2.9.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:c30a17fc83eeab346913e237c64b15b5ba6407fff812f6c541e322e19bc9ea0e", size = 104111330, upload-time = "2025-10-15T15:46:35.238Z" }, + { url = "https://files.pythonhosted.org/packages/0e/21/2254c54b8d523592c25ef4434769aa23e29b1e6bf5f4c0ad9e27bf442927/torch-2.9.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:8f25033b8667b57857dfd01458fbf2a9e6a6df1f8def23aef0dc46292f6aa642", size = 899750243, upload-time = "2025-10-15T15:48:57.459Z" }, + { url = "https://files.pythonhosted.org/packages/b7/a5/5cb94fa4fd1e78223455c23c200f30f6dc10c6d4a2bcc8f6e7f2a2588370/torch-2.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:d037f1b4ffd25013be4a7bf3651a0a910c68554956c7b2c92ebe87c76475dece", size = 109284513, upload-time = "2025-10-15T15:46:45.061Z" }, + { url = "https://files.pythonhosted.org/packages/66/e8/fc414d8656250ee46120b44836ffbb3266343db424b3e18ca79ebbf69d4f/torch-2.9.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e4e5b5cba837a2a8d1a497ba9a58dae46fa392593eaa13b871c42f71847503a5", size = 74830362, upload-time = "2025-10-15T15:46:48.983Z" }, + { url = "https://files.pythonhosted.org/packages/ed/5f/9474c98fc5ae0cd04b9466035428cd360e6611a86b8352a0fc2fa504acdc/torch-2.9.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:64693568f5dc4dbd5f880a478b1cea0201cc6b510d91d1bc54fea86ac5d1a637", size = 104144940, upload-time = "2025-10-15T15:47:29.076Z" }, + { url = "https://files.pythonhosted.org/packages/2d/5a/8e0c1cf57830172c109d4bd6be2708cabeaf550983eee7029291322447a0/torch-2.9.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:f8ed31ddd7d10bfb3fbe0b9fe01b1243577f13d75e6f4a0839a283915ce3791e", size = 899744054, upload-time = "2025-10-15T15:48:29.864Z" }, + { url = "https://files.pythonhosted.org/packages/6d/28/82c28b30fcb4b7c9cdd995763d18bbb830d6521356712faebbad92ffa61d/torch-2.9.0-cp313-cp313t-win_amd64.whl", hash = "sha256:eff527d4e4846e6f70d2afd8058b73825761203d66576a7e04ea2ecfebcb4ab8", size = 109517546, upload-time = "2025-10-15T15:47:33.395Z" }, + { url = "https://files.pythonhosted.org/packages/ff/c3/a91f96ec74347fa5fd24453fa514bc61c61ecc79196fa760b012a1873d96/torch-2.9.0-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:f8877779cf56d1ce431a7636703bdb13307f5960bb1af49716d8b179225e0e6a", size = 74480732, upload-time = "2025-10-15T15:47:38.002Z" }, + { url = "https://files.pythonhosted.org/packages/5c/73/9f70af34b334a7e0ef496ceec96b7ec767bd778ea35385ce6f77557534d1/torch-2.9.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7e614fae699838038d888729f82b687c03413c5989ce2a9481f9a7e7a396e0bb", size = 74433037, upload-time = "2025-10-15T15:47:41.894Z" }, + { url = "https://files.pythonhosted.org/packages/b7/84/37cf88625901934c97109e583ecc21777d21c6f54cda97a7e5bbad1ee2f2/torch-2.9.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:dfb5b8cd310ba3436c7e14e8b7833ef658cf3045e50d2bdaed23c8fc517065eb", size = 104116482, upload-time = "2025-10-15T15:47:46.266Z" }, + { url = "https://files.pythonhosted.org/packages/56/8e/ca8b17866943a8d4f4664d402ea84210aa274588b4c5d89918f5caa24eec/torch-2.9.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:b3d29524993a478e46f5d598b249cd824b7ed98d7fba538bd9c4cde6c803948f", size = 899746916, upload-time = "2025-10-15T15:50:40.294Z" }, + { url = "https://files.pythonhosted.org/packages/43/65/3b17c0fbbdab6501c5b320a52a648628d0d44e7379f64e27d9eef701b6bf/torch-2.9.0-cp314-cp314-win_amd64.whl", hash = "sha256:71c7578984f5ec0eb645eb4816ac8435fcf3e3e2ae1901bcd2f519a9cafb5125", size = 109275151, upload-time = "2025-10-15T15:49:20.715Z" }, + { url = "https://files.pythonhosted.org/packages/83/36/74f8c051f785500396e42f93542422422dfd874a174f21f8d955d36e5d64/torch-2.9.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:71d9309aee457bbe0b164bce2111cd911c4ed4e847e65d5077dbbcd3aba6befc", size = 74823353, upload-time = "2025-10-15T15:49:16.59Z" }, + { url = "https://files.pythonhosted.org/packages/62/51/dc3b4e2f9ba98ae27238f0153ca098bf9340b2dafcc67fde645d496dfc2a/torch-2.9.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:c08fb654d783899e204a32cca758a7ce8a45b2d78eeb89517cc937088316f78e", size = 104140340, upload-time = "2025-10-15T15:50:19.67Z" }, + { url = "https://files.pythonhosted.org/packages/c0/8d/b00657f8141ac16af7bb6cda2e67de18499a3263b78d516b9a93fcbc98e3/torch-2.9.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:ec8feb0099b2daa5728fbc7abb0b05730fd97e0f359ff8bda09865aaa7bd7d4b", size = 899731750, upload-time = "2025-10-15T15:49:36.673Z" }, + { url = "https://files.pythonhosted.org/packages/fc/29/bd361e0cbb2c79ce6450f42643aaf6919956f89923a50571b0ebfe92d142/torch-2.9.0-cp314-cp314t-win_amd64.whl", hash = "sha256:695ba920f234ad4170c9c50e28d56c848432f8f530e6bc7f88fcb15ddf338e75", size = 109503850, upload-time = "2025-10-15T15:50:24.118Z" }, +] + [[package]] name = "tornado" version = "6.5.2" @@ -3758,6 +4011,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" }, ] +[[package]] +name = "triton" +version = "3.5.0" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/eb/09e31d107a5d00eb281aa7e6635ca463e9bca86515944e399480eadb71f8/triton-3.5.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5d3b3d480debf24eaa739623c9a42446b0b77f95593d30eb1f64cd2278cc1f0", size = 170333110, upload-time = "2025-10-13T16:37:49.588Z" }, + { url = "https://files.pythonhosted.org/packages/3d/78/949a04391c21956c816523678f0e5fa308eb5b1e7622d88c4e4ef5fceca0/triton-3.5.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f34bfa21c5b3a203c0f0eab28dcc1e49bd1f67d22724e77fb6665a659200a4ec", size = 170433488, upload-time = "2025-10-13T16:37:57.132Z" }, + { url = "https://files.pythonhosted.org/packages/f5/3a/e991574f3102147b642e49637e0281e9bb7c4ba254edb2bab78247c85e01/triton-3.5.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9e71db82261c4ffa3921cd050cd5faa18322d2d405c30eb56084afaff3b0833", size = 170476535, upload-time = "2025-10-13T16:38:05.18Z" }, + { url = "https://files.pythonhosted.org/packages/6c/29/10728de8a6e932e517c10773486b8e99f85d1b1d9dd87d9a9616e1fef4a1/triton-3.5.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e6bb9aa5519c084a333acdba443789e50012a4b851cd486c54f0b8dc2a8d3a12", size = 170487289, upload-time = "2025-10-13T16:38:11.662Z" }, + { url = "https://files.pythonhosted.org/packages/5c/38/db80e48b9220c9bce872b0f616ad0446cdf554a40b85c7865cbca99ab3c2/triton-3.5.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c83f2343e1a220a716c7b3ab9fccfcbe3ad4020d189549200e2d2e8d5868bed9", size = 170577179, upload-time = "2025-10-13T16:38:17.865Z" }, + { url = "https://files.pythonhosted.org/packages/ff/60/1810655d1d856c9a4fcc90ee8966d85f552d98c53a6589f95ab2cbe27bb8/triton-3.5.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:da0fa67ccd76c3dcfb0bffe1b1c57c685136a6bd33d141c24d9655d4185b1289", size = 170487949, upload-time = "2025-10-13T16:38:24.881Z" }, + { url = "https://files.pythonhosted.org/packages/fb/b7/1dec8433ac604c061173d0589d99217fe7bf90a70bdc375e745d044b8aad/triton-3.5.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:317fe477ea8fd4524a6a8c499fb0a36984a56d0b75bf9c9cb6133a1c56d5a6e7", size = 170580176, upload-time = "2025-10-13T16:38:31.14Z" }, +] + [[package]] name = "trueskill" version = "0.4.5" @@ -3850,6 +4117,7 @@ dependencies = [ { name = "tenacity" }, { name = "termcolor" }, { name = "tiktoken" }, + { name = "torch" }, { name = "tqdm" }, { name = "trueskill" }, { name = "typer" }, @@ -3897,6 +4165,7 @@ requires-dist = [ { name = "tenacity", specifier = ">=9.1.2" }, { name = "termcolor", specifier = ">=3.1.0" }, { name = "tiktoken", specifier = ">=0.11.0" }, + { name = "torch", specifier = ">=2.9.0" }, { name = "tqdm", specifier = ">=4.67.1" }, { name = "trueskill", specifier = ">=0.4.5" }, { name = "typer", extras = ["all"], specifier = ">=0.19.2" },