Views
No views yet
| Attribute | Value |
|---|---|
| Base Model | Qwen/Qwen3-0.6B |
| Training Dataset | Distilled from GPT expert traces |
| Best Checkpoint | Step 410 (Epoch ~6.7) |
| Eval Accuracy | 14.75% |
| Eval Loss | 3.789 |
| Training Time | ~53 minutes (8×H100 GPUs) |
1learning_rate: 5e-6
2warmup_ratio: 0.1
3num_train_epochs: 8
4per_device_train_batch_size: 1
5gradient_accumulation_steps: 8
6max_length: 8192
7max_vars: 600
8optimizer: AdamW
9scheduler: cosine
10deepspeed: ZeRO-31from transformers import AutoTokenizer, AutoModelForCausalLM
2import torch
3import torch.nn as nn
4import re
5
6class QwenVarClassifier(nn.Module):
7 def __init__(self, base_model, max_vars=600):
8 super().__init__()
9 self.base = base_model
10 hidden_size = base_model.config.hidden_size
11 self.norm = nn.LayerNorm(hidden_size)
12 self.head = nn.Linear(hidden_size, max_vars + 1)
13
14 def forward(self, input_ids, attention_mask=None):
15 outputs = self.base(input_ids, attention_mask=attention_mask, output_hidden_states=True)
16 hidden = outputs.hidden_states[-1] # [B, seq, hidden]
17
18 # Pool at last non-pad token
19 if attention_mask is not None:
20 lengths = attention_mask.sum(dim=1) - 1
21 pooled = hidden[torch.arange(hidden.size(0)), lengths]
22 else:
23 pooled = hidden[:, -1, :]
24
25 pooled = self.norm(pooled)
26 logits = self.head(pooled)
27 return logits
28
29# Load
30tokenizer = AutoTokenizer.from_pretrained("Qwen/Qwen3-0.6B")
31base_model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-0.6B")
32model = QwenVarClassifier(base_model, max_vars=600)
33
34# Load fine-tuned weights
35state_dict = torch.load("pytorch_model.bin", map_location="cpu")
36model.load_state_dict(state_dict)
37model.eval()1def get_valid_vars(cnf_text, max_vars=600):
2 """Extract valid variable IDs from CNF text."""
3 valid = set()
4 for line in cnf_text.strip().split('\n'):
5 if line.startswith('c') or line.startswith('p'):
6 continue
7 for tok in line.split():
8 try:
9 lit = int(tok)
10 if lit != 0:
11 valid.add(abs(lit))
12 except ValueError:
13 pass
14 return valid
15
16def predict_variable(cnf_text, model, tokenizer, max_vars=600):
17 """Predict the next variable to branch on."""
18 inputs = tokenizer(cnf_text, return_tensors="pt", truncation=True, max_length=8192)
19
20 with torch.no_grad():
21 logits = model(inputs["input_ids"], inputs["attention_mask"])
22
23 # Mask invalid variables
24 valid_vars = get_valid_vars(cnf_text, max_vars)
25 mask = torch.zeros(max_vars + 1, dtype=torch.bool)
26 for v in valid_vars:
27 if 1 <= v <= max_vars:
28 mask[v] = True
29
30 logits[0, ~mask] = -1e4
31 predicted_var = logits.argmax(dim=-1).item()
32
33 return predicted_var
34
35# Example
36cnf_text = """p cnf 100 200
371 -2 3 0
38-1 4 -5 0
392 5 6 0
40"""
41
42var = predict_variable(cnf_text, model, tokenizer)
43print(f"Predicted variable: {var}")-1e41@misc{qwen-sat-varselector,
2 title={Qwen3-0.6B-SAT-VarSelector-Distilled},
3 author={Yale-ROSE},
4 year={2026},
5 publisher={Hugging Face},
6 url={https://huggingface.co/Yale-ROSE/Qwen3-0.6B-SAT-VarSelector-Distilled}
7}