Text Generation
Transformers
Safetensors
Dutch
Chinese
gpt2
causal-lm
language-model
babylm
babylm-2026
multilingual
paradigmfinder
text-generation-inference
Instructions to use NeTSlab/gpt2_parfind_nl_zh_equal with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use NeTSlab/gpt2_parfind_nl_zh_equal with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="NeTSlab/gpt2_parfind_nl_zh_equal")# Load model directly from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained("NeTSlab/gpt2_parfind_nl_zh_equal") model = AutoModelForCausalLM.from_pretrained("NeTSlab/gpt2_parfind_nl_zh_equal") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use NeTSlab/gpt2_parfind_nl_zh_equal with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "NeTSlab/gpt2_parfind_nl_zh_equal" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "NeTSlab/gpt2_parfind_nl_zh_equal", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker
docker model run hf.co/NeTSlab/gpt2_parfind_nl_zh_equal
- SGLang
How to use NeTSlab/gpt2_parfind_nl_zh_equal with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "NeTSlab/gpt2_parfind_nl_zh_equal" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "NeTSlab/gpt2_parfind_nl_zh_equal", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "NeTSlab/gpt2_parfind_nl_zh_equal" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "NeTSlab/gpt2_parfind_nl_zh_equal", "prompt": "Once upon a time,", "max_tokens": 512, "temperature": 0.5 }' - Docker Model Runner
How to use NeTSlab/gpt2_parfind_nl_zh_equal with Docker Model Runner:
docker model run hf.co/NeTSlab/gpt2_parfind_nl_zh_equal
| # paradigm_utils.py | |
| import time | |
| from collections import defaultdict | |
| from tqdm import tqdm | |
| import os | |
| import math | |
| import json | |
| from typing import List, Tuple, Set, Dict, Any | |
| def _serialize_suffixes(sfx_set): | |
| flat = [] | |
| for s in sfx_set: | |
| if isinstance(s, tuple): | |
| base, nested = s | |
| flat.append([base, sorted(list(nested))]) # JSON-safe pair | |
| else: | |
| flat.append(s) # plain string | |
| # stable order: strings first, then pairs; then lexicographic | |
| def key(x): | |
| return (0, x) if isinstance(x, str) else (1, x[0], tuple(x[1])) | |
| return sorted(flat, key=key) | |
| def paradigms_to_json(paradigms): | |
| out = [] | |
| for stems, suffixes in paradigms: | |
| out.append({ | |
| "stems": sorted(list(stems)), | |
| "suffixes": _serialize_suffixes(suffixes), | |
| }) | |
| return out | |
| def save_paradigms_json(paradigms, path, meta=None): | |
| payload = { | |
| "schema_version": 1, | |
| "created_at": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()), | |
| "meta": meta or {}, | |
| "paradigms": paradigms_to_json(paradigms), | |
| } | |
| with open(path, "w", encoding="utf-8") as f: | |
| json.dump(payload, f, ensure_ascii=False, indent=2) | |
| def _deserialize_suffixes(sfx_list): | |
| out = set() | |
| for item in sfx_list: | |
| if isinstance(item, list): # [base, nested_list] | |
| base, nested = item | |
| out.add((base, frozenset(nested))) | |
| else: | |
| out.add(item) | |
| return out | |
| def load_paradigms_json(path): | |
| with open(path, "r", encoding="utf-8") as f: | |
| payload = json.load(f) | |
| paradigms = [] | |
| for p in payload["paradigms"]: | |
| stems = set(p["stems"]) | |
| suffixes = _deserialize_suffixes(p["suffixes"]) | |
| paradigms.append((stems, suffixes)) | |
| meta = payload.get("meta", {}) | |
| return paradigms, meta | |
| ### ----------------------------- | |
| ### 1. Extract (stem, suffix) pairs from vocabulary | |
| ### ----------------------------- | |
| def extract_stem_suffix_pairs(vocab): | |
| """Return a mapping from stems to all suffixes they occur with, including null suffix.""" | |
| stem_to_suffixes = defaultdict(set) | |
| for word in tqdm(vocab, desc="[1/7] Extracting stem-suffix pairs"): | |
| for i in range(0, len(word) + 1): # include empty suffix | |
| stem, suffix = word[:i], word[i:] | |
| stem_to_suffixes[stem].add(suffix) | |
| return stem_to_suffixes | |
| ### ----------------------------- | |
| ### 2. Group stems by shared suffix sets and normalize by common prefix | |
| ### ----------------------------- | |
| def group_stems_by_suffixes(stem_to_suffixes, min_shared_stems=2, min_suffixes=2): | |
| suffix_to_stems = defaultdict(set) | |
| for stem, suffixes in stem_to_suffixes.items(): | |
| suffix_key = frozenset(suffixes) | |
| suffix_to_stems[suffix_key].add(stem) | |
| normalized_suffix_map = defaultdict(set) | |
| for suffixes, stems in tqdm(suffix_to_stems.items(), desc="[2/7] Grouping and normalizing"): | |
| non_empty_suffixes = [s for s in suffixes if s] | |
| if len(stems) >= min_shared_stems and len(suffixes) >= min_suffixes: | |
| common_prefix = os.path.commonprefix(non_empty_suffixes) if non_empty_suffixes else "" | |
| if common_prefix: | |
| normalized_stems = {stem + common_prefix for stem in stems} | |
| adjusted_suffixes = {s[len(common_prefix):] if s.startswith(common_prefix) else s for s in suffixes} | |
| else: | |
| normalized_stems = stems | |
| adjusted_suffixes = suffixes | |
| if len(adjusted_suffixes) >= min_suffixes: | |
| suffix_key = frozenset(adjusted_suffixes) | |
| normalized_suffix_map[suffix_key].update(normalized_stems) | |
| paradigms = [(stems, set(suffixes)) for suffixes, stems in normalized_suffix_map.items()] | |
| return paradigms | |
| ### ----------------------------- | |
| ### 3. Expand stem sets based on suffix set coverage | |
| ### ----------------------------- | |
| def stem_set_expansion(paradigms, stem_to_suffixes): | |
| updated = 0 | |
| suffix_to_stems = {frozenset(suffixes): set(stems) for stems, suffixes in paradigms} | |
| for stem, suffixes in tqdm(stem_to_suffixes.items(), desc="[3/7] Expanding stem sets"): | |
| added = False | |
| for paradigm_suffixes in sorted(suffix_to_stems.keys(), key=lambda x: (-len(x), tuple(sorted(x)))): | |
| if paradigm_suffixes.issubset(suffixes): | |
| if stem not in suffix_to_stems[paradigm_suffixes]: | |
| suffix_to_stems[paradigm_suffixes].add(stem) | |
| updated += 1 | |
| added = True | |
| if not added and stem == 'design': | |
| print(f"[DEBUG] No suitable paradigm for 'design' with suffixes {suffixes}") | |
| enriched = [(stems, set(suffixes)) for suffixes, stems in suffix_to_stems.items()] | |
| print(f"✅ Added {updated} stems via stem set expansion.") | |
| return enriched | |
| ### ----------------------------- | |
| ### 4. Expand suffix sets based on partial compatibility | |
| ### ----------------------------- | |
| def harmonic_number(n): | |
| return sum(1.0 / i for i in range(1, n + 1)) | |
| def suffix_set_expansion(paradigms): | |
| base = paradigms[:] # snapshot | |
| merged = [ (set(stems), set(suffixes)) for stems, suffixes in base ] | |
| enriched_count = 0 | |
| # Iterate in a deterministic order | |
| for i, (stems_i, suffixes_i) in enumerate(sort_paradigms(merged)): | |
| for j, (stems_j, suffixes_j) in enumerate(sort_paradigms(merged)): | |
| if i == j: | |
| continue | |
| if suffixes_i > suffixes_j: | |
| intersection = stems_i & stems_j | |
| denom = max(1, len(stems_j)) # guard | |
| if (len(stems_j) - len(intersection)) < (len(stems_j) / harmonic_number(denom)): | |
| stems_i |= stems_j | |
| enriched_count += 1 | |
| # do not mutate stems_j/suffixes_j further | |
| print(f"\n✅ Enriched {enriched_count} paradigms via suffix set expansion.") | |
| # Return back in original tuple-of-sets form | |
| return [ (set(st), set(sf)) for st, sf in sort_paradigms(merged) ] | |
| ### ----------------------------- | |
| ### 5. Prune subsumed stems | |
| ### ----------------------------- | |
| def prune_subsumed_stems(paradigms): | |
| pruned_paradigms = [] | |
| for i, (stems_i, suffixes_i) in enumerate(paradigms): | |
| pruned_stems = set(stems_i) | |
| for j, (stems_j, suffixes_j) in enumerate(paradigms): | |
| if i == j: | |
| continue | |
| if suffixes_j >= suffixes_i: | |
| pruned_stems -= (stems_j & stems_i) | |
| if pruned_stems: | |
| pruned_paradigms.append((pruned_stems, suffixes_i)) | |
| print(f"✅ Pruned to {len(pruned_paradigms)} paradigms after removing subsumed stems.") | |
| return sort_paradigms(pruned_paradigms) | |
| ### ----------------------------- | |
| ### 6. Sort paradigms by size | |
| ### ----------------------------- | |
| def sort_paradigms(paradigms): | |
| """ | |
| Primary: log(len(stems)) * log(len(suffixes)) (DESC) | |
| Ties: (-len(stems), -len(suffixes), lexicographic stems, lexicographic suffix heads) | |
| """ | |
| def score(p): | |
| stems, suffixes = p | |
| if stems and suffixes: | |
| return math.log(len(stems)) * math.log(len(suffixes)) | |
| return 0.0 | |
| def tie_key(p): | |
| stems, suffixes = p | |
| sfx_heads = [] | |
| for s in suffixes: | |
| sfx_heads.append(s[0] if isinstance(s, tuple) else s) | |
| return (-len(stems), -len(suffixes), | |
| " ".join(sorted(stems)), | |
| " ".join(sorted(sfx_heads))) | |
| return sorted(paradigms, key=lambda p: (-score(p), tie_key(p))) | |
| def sort_paradigms_by_suffix_count(paradigms): | |
| def score(p): | |
| stem_count = len(p[0]) | |
| suffix_count = len(p[1]) | |
| if stem_count > 0 and suffix_count > 0: | |
| return suffix_count | |
| return 0 | |
| return sorted(paradigms, key=score, reverse=True) | |
| def nest_suffixes_from_paradigms(paradigms): | |
| print("[7/7] Nesting suffixes based on reusable paradigms...") | |
| suffix_set_index = {frozenset(suffixes): True for _, suffixes in paradigms} | |
| nested_paradigms = [] | |
| for stems, suffixes in paradigms: | |
| suffixes_list = list(suffixes) | |
| nested_suffixes = set() | |
| used = set() | |
| # deterministic nested pairing | |
| for i, s1 in enumerate(sorted(suffixes_list)): | |
| for j, s2 in enumerate(sorted(suffixes_list)): | |
| if i == j or s2 in used or not isinstance(s1, str) or not isinstance(s2, str): | |
| continue | |
| if s2.startswith(s1) and s1 != '': | |
| remainder = s2[len(s1):] | |
| if remainder and frozenset({'', remainder}) in suffix_set_index: | |
| nested_suffixes.add((s1, frozenset({'', remainder}))) | |
| used.add(s2) | |
| used.add(s1) | |
| break | |
| for s in suffixes_list: | |
| if s not in used: | |
| nested_suffixes.add(s) | |
| nested_paradigms.append((set(stems), nested_suffixes)) | |
| print(f"✅ Nested structure created for {len(nested_paradigms)} paradigms.") | |
| return sort_paradigms(nested_paradigms) | |
| def refine_nested_stem_conflicts(paradigms): | |
| """ | |
| Remove stems from higher-ranked paradigms if they are fully explained by nested structures | |
| in lower-ranked paradigms. | |
| Args: | |
| paradigms: list of (stem_set, suffix_set), where suffix_set may contain nested (str, frozenset) tuples | |
| Returns: | |
| Refined list of paradigms with redundant derived stems removed | |
| """ | |
| refined_paradigms = paradigms[:] | |
| all_suffix_sets = {frozenset(suffixes) for _, suffixes in paradigms} | |
| # Build a mapping from nested suffix sets to their parent prefixes | |
| derived_stems = set() | |
| for stems, suffixes in paradigms: | |
| for sfx in suffixes: | |
| if isinstance(sfx, tuple): | |
| base, nested_suffixes = sfx | |
| if frozenset(nested_suffixes) in all_suffix_sets: | |
| for stem in stems: | |
| derived_stems.add(stem + base) | |
| # Remove derived stems from paradigms with simple suffix sets (like ['', 's']) | |
| updated_paradigms = [] | |
| for stems, suffixes in refined_paradigms: | |
| cleaned_stems = stems - derived_stems | |
| updated_paradigms.append((cleaned_stems, suffixes)) | |
| print(f"✅ Removed {len(derived_stems)} derived stems explained by nested paradigms.") | |
| return updated_paradigms | |
| ### ----------------------------- | |
| ### 7. Segment word based on ranked paradigms | |
| ### ----------------------------- | |
| def recursive_fallback(word, suffix_set): | |
| for suffix in sorted(suffix_set, key=lambda s: -len(s)): | |
| if suffix and word.endswith(suffix): | |
| stem_candidate = word[:-len(suffix)] | |
| rest = recursive_fallback(stem_candidate, suffix_set) | |
| return rest + [suffix] | |
| return [word] # fallback to whole word if nothing matches | |
| ### ----------------------------- | |
| ### Main runner | |
| ### ----------------------------- | |
| def run_paradigm_extraction(vocab, min_shared_stems=2, min_suffixes=2, enrich_suffix_sets=True): | |
| start = time.time() | |
| stem_to_suffixes = extract_stem_suffix_pairs(vocab) | |
| paradigms = group_stems_by_suffixes(stem_to_suffixes, min_shared_stems, min_suffixes) | |
| paradigms = stem_set_expansion(paradigms, stem_to_suffixes) | |
| paradigms = sort_paradigms(paradigms) | |
| paradigms = prune_subsumed_stems(paradigms) | |
| paradigms = sort_paradigms(paradigms) | |
| paradigms = nest_suffixes_from_paradigms(paradigms) | |
| paradigms = refine_nested_stem_conflicts(paradigms) | |
| paradigms = sort_paradigms(paradigms) | |
| if enrich_suffix_sets: | |
| print("[4/7] Expanding suffix sets based on partial compatibility...") | |
| paradigms = suffix_set_expansion(paradigms) | |
| paradigms = sort_paradigms(paradigms) | |
| paradigms = prune_subsumed_stems(paradigms) | |
| paradigms = sort_paradigms(paradigms) | |
| '''# Fallback paradigm for unassigned full words | |
| vocab_words = set(vocab) | |
| assigned_words = set() | |
| for stems, suffixes in paradigms: | |
| for stem in stems: | |
| for suffix in suffixes: | |
| if isinstance(suffix, tuple): | |
| base, _ = suffix | |
| assigned_words.add(stem + base) | |
| else: | |
| assigned_words.add(stem + suffix) | |
| unassigned_words = vocab_words - assigned_words | |
| if unassigned_words: | |
| print(f"✅ {len(unassigned_words)} full words were not assigned to any paradigm, added fallback paradigm.") | |
| paradigms.append((set(unassigned_words), frozenset({""}))) | |
| paradigms = sort_paradigms(paradigms)''' | |
| print(f"\n✅ Extracted {len(paradigms)} paradigms.") | |
| print(f"⏱️ Finished in {time.time() - start:.2f} seconds.") | |
| return paradigms | |
| def segment_word_from_nested_paradigms(word, paradigms, fallback=True, top_k=300): | |
| """ | |
| Segment a word based on nested paradigms with optional fallback. | |
| Parameters: | |
| word (str): The word to segment. | |
| paradigms (list): A list of tuples (stems, suffixes) with optional nesting. | |
| fallback (bool): Whether to fall back on longest suffix match from top_k paradigms. | |
| top_k (int): Number of top paradigms to consider in fallback. | |
| Returns: | |
| List[str]: Segmented pieces of the word. | |
| """ | |
| def match_suffixes(suffixes, remainder): | |
| """Recursive helper to match nested suffix structures.""" | |
| for suffix in suffixes: | |
| if isinstance(suffix, tuple): | |
| base, nested = suffix | |
| if remainder.startswith(base): | |
| sub = remainder[len(base):] | |
| nested_result = match_suffixes(nested, sub) | |
| if nested_result is not None: | |
| return [base] + nested_result | |
| elif remainder == suffix: | |
| return [suffix] if suffix else [] | |
| return None | |
| # First pass: try full nested match | |
| for stems, suffixes in paradigms: | |
| for stem in stems: | |
| if word.startswith(stem): | |
| remainder = word[len(stem):] | |
| matched_suffix = match_suffixes(suffixes, remainder) | |
| if matched_suffix is not None: | |
| return [stem] + matched_suffix | |
| # Fallback strategy: longest suffix among top_k paradigms | |
| if fallback: | |
| seen_suffixes = set() | |
| def collect_suffixes(suffixes): | |
| for s in suffixes: | |
| if isinstance(s, tuple): | |
| seen_suffixes.add(s[0]) | |
| collect_suffixes(s[1]) | |
| else: | |
| seen_suffixes.add(s) | |
| for _, suffixes in paradigms[:top_k]: | |
| collect_suffixes(suffixes) | |
| # Try matching the longest suffix first | |
| for suffix in sorted(seen_suffixes, key=lambda s: -len(s)): | |
| if suffix and word.endswith(suffix): | |
| stem = word[:-len(suffix)] | |
| return [stem, suffix] | |
| return [word] | |
| return [word] | |
| def segment_word_from_paradigms(word, paradigms, top_k=20): | |
| """ | |
| Simpler fallback-only version: match longest suffix among top_k paradigms. | |
| Parameters: | |
| word (str): Word to segment. | |
| paradigms (list): Paradigm structures. | |
| top_k (int): How many paradigms to consider. | |
| Returns: | |
| List[str]: Segmentation result. | |
| """ | |
| candidates = paradigms[:top_k] | |
| best_split = None | |
| for stems, suffixes in candidates: | |
| for suffix in sorted(suffixes, key=lambda s: -len(s) if isinstance(s, str) else -len(s[0])): | |
| if isinstance(suffix, tuple): | |
| suffix = suffix[0] # ignore nested for fallback | |
| if word.endswith(suffix): | |
| stem_candidate = word[:-len(suffix)] if suffix else word | |
| if stem_candidate in stems: | |
| split = [stem_candidate, suffix] if suffix else [stem_candidate] | |
| if best_split is None or len(suffix) > len(best_split[-1]): | |
| best_split = split | |
| return best_split or [word] | |