Text Classification
Transformers
Safetensors
English
modernbert
lean
lean4
theorem-proving
formal-verification
encoder
text-embeddings-inference
Instructions to use EPFL-LARA/lean-encoder-modernbert-large with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use EPFL-LARA/lean-encoder-modernbert-large with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-classification", model="EPFL-LARA/lean-encoder-modernbert-large")# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModelForSequenceClassification tokenizer = AutoTokenizer.from_pretrained("EPFL-LARA/lean-encoder-modernbert-large") model = AutoModelForSequenceClassification.from_pretrained("EPFL-LARA/lean-encoder-modernbert-large", device_map="auto") - Notebooks
- Google Colab
- Kaggle
File size: 4,293 Bytes
1b6fcc6 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | #!/usr/bin/env python3
"""Predict whether Lean source code compiles with a trained classifier."""
from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path
import torch
from transformers import AutoModelForSequenceClassification, AutoTokenizer
from typing import Any, Sequence
DEFAULT_CACHE_DIR = None
DEFAULT_CLASSIFIER_OUTPUT = 'EPFL-LARA/lean-encoder-modernbert-large'
def encode_head_tail(
tokenizer: Any,
texts: Sequence[str],
*,
max_length: int,
head_fraction: float = 0.25,
) -> dict[str, torch.Tensor]:
"""Tokenize, retaining the beginning and end when a source is too long."""
if not 0.0 < head_fraction < 1.0:
raise ValueError("head_fraction must be between 0 and 1")
payload_budget = max_length - tokenizer.num_special_tokens_to_add(pair=False)
if payload_budget <= 0:
raise ValueError("max_length is smaller than the tokenizer's special tokens")
head_tokens = max(1, round(payload_budget * head_fraction))
tail_tokens = payload_budget - head_tokens
# A few compiler_data rows are over a million characters. Bound tokenizer
# memory with a generous character pre-slice, then perform the exact slice
# in token space below.
prepared_texts: list[str] = []
head_character_budget = max(2_048, head_tokens * 8)
tail_character_budget = max(2_048, tail_tokens * 8)
for text in texts:
if len(text) > head_character_budget + tail_character_budget:
text = (
text[:head_character_budget]
+ "\n-- middle omitted for classifier context window --\n"
+ text[-tail_character_budget:]
)
prepared_texts.append(text)
tokenized = tokenizer(
prepared_texts,
add_special_tokens=False,
truncation=False,
return_attention_mask=False,
verbose=False,
)["input_ids"]
features: list[dict[str, list[int]]] = []
for input_ids in tokenized:
if len(input_ids) > payload_budget:
input_ids = input_ids[:head_tokens] + input_ids[-tail_tokens:]
with_special_tokens = tokenizer.build_inputs_with_special_tokens(input_ids)
features.append(
{
"input_ids": with_special_tokens,
"attention_mask": [1] * len(with_special_tokens),
}
)
return tokenizer.pad(
features,
padding=True,
pad_to_multiple_of=8,
return_tensors="pt",
)
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("path", nargs="?", help="Lean file; omit to read stdin")
parser.add_argument("--model", default=DEFAULT_CLASSIFIER_OUTPUT)
parser.add_argument("--cache-dir", default=DEFAULT_CACHE_DIR)
parser.add_argument("--max-length", type=int, default=8192)
parser.add_argument("--head-fraction", type=float, default=0.25)
args = parser.parse_args()
source_code = (
Path(args.path).read_text(encoding="utf-8") if args.path else sys.stdin.read()
)
if not source_code.strip():
parser.error("Lean source is empty")
tokenizer = AutoTokenizer.from_pretrained(args.model, cache_dir=args.cache_dir)
model = AutoModelForSequenceClassification.from_pretrained(
args.model,
cache_dir=args.cache_dir,
dtype=torch.bfloat16 if torch.cuda.is_available() else torch.float32,
attn_implementation="sdpa",
)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device).eval()
inputs = encode_head_tail(
tokenizer,
[source_code],
max_length=args.max_length,
head_fraction=args.head_fraction,
)
inputs = {key: value.to(device) for key, value in inputs.items()}
with torch.inference_mode():
probabilities = model(**inputs).logits.float().softmax(dim=-1)[0].cpu()
valid_probability = float(probabilities[1])
print(
json.dumps(
{
"is_valid": valid_probability >= 0.5,
"valid_probability": valid_probability,
"invalid_probability": float(probabilities[0]),
},
indent=2,
)
)
if __name__ == "__main__":
main()
|