Text Generation
Transformers
Safetensors
English
qwen2
chat
conversational
text-generation-inference
4-bit precision
awq
Instructions to use TejasviniC/IOL_V0 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use TejasviniC/IOL_V0 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-generation", model="TejasviniC/IOL_V0") messages = [ {"role": "user", "content": "Who are you?"}, ] pipe(messages)# Load model directly from transformers import AutoTokenizer, AutoModelForCausalLM tokenizer = AutoTokenizer.from_pretrained("TejasviniC/IOL_V0") model = AutoModelForCausalLM.from_pretrained("TejasviniC/IOL_V0", device_map="auto") messages = [ {"role": "user", "content": "Who are you?"}, ] inputs = tokenizer.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=40) print(tokenizer.decode(outputs[0][inputs["input_ids"].shape[-1]:])) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use TejasviniC/IOL_V0 with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "TejasviniC/IOL_V0" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "TejasviniC/IOL_V0", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'Use Docker
docker model run hf.co/TejasviniC/IOL_V0
- SGLang
How to use TejasviniC/IOL_V0 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 "TejasviniC/IOL_V0" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "TejasviniC/IOL_V0", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }'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 "TejasviniC/IOL_V0" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "TejasviniC/IOL_V0", "messages": [ { "role": "user", "content": "What is the capital of France?" } ] }' - Docker Model Runner
How to use TejasviniC/IOL_V0 with Docker Model Runner:
docker model run hf.co/TejasviniC/IOL_V0
| import os | |
| import re | |
| import sys | |
| import json | |
| import time | |
| import logging | |
| os.environ["HF_HUB_OFFLINE"] = "1" | |
| os.environ["TRANSFORMERS_OFFLINE"] = "1" | |
| START_TIME = time.time() | |
| SOFT_LIMIT_SECONDS = 26 * 60 | |
| MODEL_ID = "." | |
| import pandas as pd | |
| import torch | |
| from transformers import AutoTokenizer, AutoModelForCausalLM | |
| logging.basicConfig( | |
| level=logging.INFO, | |
| format="%(asctime)s | %(levelname)s | %(message)s", | |
| stream=sys.stdout, | |
| force=True, | |
| ) | |
| log = logging.getLogger("iol-v1") | |
| SYSTEM = ( | |
| "You solve International Linguistics Olympiad problems by reasoning only from " | |
| "the supplied data. Read the instruction and examples carefully. Preserve every " | |
| "requested grammatical feature and output form. For translation, return the full " | |
| "translated form; for fill_blanks, return each missing form; for text_to_num, " | |
| "return digits; for num_to_text, return the complete written number form. Reason " | |
| "systematically and verify the inferred rule against the examples. Then write " | |
| "FINAL ANSWERS: exactly once, followed by one bare answer per line in query order. " | |
| "Do not number, quote, or explain the final answers. Always answer every item." | |
| ) | |
| MATCH_SYSTEM = ( | |
| "Solve this linguistic matching problem as a complete correspondence. Decompose " | |
| "recurring morphemes and compound words before matching. The numbered puzzle-language " | |
| "items must be answered in their original order using only option labels. When the " | |
| "number of labels equals the number of items, this is a one-to-one assignment: use " | |
| "every label exactly once. Resolve high-confidence pairs first, then use the global " | |
| "constraint for the remainder. Do not stop early; make a best guess for every item. " | |
| "Write FINAL ANSWERS: exactly once, followed by one uppercase label per line. Include " | |
| "no numbering, words, meanings, or commentary in the final section." | |
| ) | |
| REPAIR_SYSTEM = ( | |
| "Repair the final output of an International Linguistics Olympiad solution. Use the " | |
| "context, query, attempted solution, required count, and valid labels when supplied. " | |
| "Return exactly the required number of answers in original item order. For matching, " | |
| "return uppercase option labels only and use each label once when explicitly told the " | |
| "task is one-to-one. For text_to_num return digits; for num_to_text return complete " | |
| "written forms; for fill_blanks include every blank in order. Write FINAL ANSWERS: " | |
| "exactly once, then one bare answer per line. No reasoning or commentary." | |
| ) | |
| MARKER_RE = re.compile( | |
| r"(?im)^\s*(?:[-*•]\s*)?(?:#{1,6}\s*)?(?:\*\*)?" | |
| r"final answers?\s*:?(?:\*\*)?\s*$" | |
| ) | |
| def clean_answer_line(line): | |
| line = str(line).strip() | |
| if re.match(r"^#{1,6}\s+\S", line): | |
| return "" | |
| line = re.sub(r"^\s*\d+[.)]\s*", "", line) | |
| line = re.sub(r"^\s*[-*•]\s+", "", line).strip() | |
| if line.startswith("**") and line.endswith("**"): | |
| line = line[2:-2].strip() | |
| return line | |
| def parse_answers(text): | |
| """Parse both a normal final block and repeated per-item FINAL ANSWERS blocks.""" | |
| text = str(text) | |
| markers = list(MARKER_RE.finditer(text)) | |
| if not markers: | |
| return [] | |
| # Some models write one FINAL ANSWERS marker for every numbered item. | |
| if len(markers) > 1: | |
| answers = [] | |
| for index, marker in enumerate(markers): | |
| end = markers[index + 1].start() if index + 1 < len(markers) else len(text) | |
| for line in text[marker.end():end].splitlines(): | |
| candidate = clean_answer_line(line) | |
| if candidate: | |
| answers.append(candidate) | |
| break | |
| return answers | |
| answers = [] | |
| for line in text[markers[0].end():].splitlines(): | |
| if re.match(r"^\s*#{1,6}\s+\S", line): | |
| break | |
| candidate = clean_answer_line(line) | |
| if candidate: | |
| answers.append(candidate) | |
| return answers | |
| def numbered_context_items(context): | |
| return list(dict.fromkeys(re.findall(r"(?m)^\s*(\d+)[.)]\s+\S", str(context)))) | |
| def option_labels(context): | |
| """Extract labels such as A.-R. from a matching context, preserving order.""" | |
| labels = re.findall(r"(?m)^\s*([A-Z])\s*[.)]\s+\S", str(context)) | |
| return list(dict.fromkeys(label.upper() for label in labels)) | |
| def count_query_items(query, context="", task_type=""): | |
| query = str(query).strip() | |
| task_type = str(task_type).strip() | |
| if task_type == "match_letters": | |
| items = numbered_context_items(context) | |
| if items: | |
| return len(items) | |
| ranges = re.findall(r"\((\d+)\s*[-–—]\s*(\d+)\)", query) | |
| if ranges: | |
| start, end = map(int, ranges[-1]) | |
| if end >= start: | |
| return end - start + 1 | |
| numbered = re.findall(r"(?m)^\s*\d+[.)]\s+\S", query) | |
| if numbered: | |
| return len(numbered) | |
| blanks = re.findall(r"\((\d+)\)", query) | |
| if blanks: | |
| return len(set(blanks)) | |
| if ":" in query: | |
| body = query.split(":", 1)[1].strip() | |
| lines = [line.strip() for line in body.splitlines() if line.strip()] | |
| if len(lines) > 1: | |
| return len(lines) | |
| if len(lines) == 1: | |
| comma_items = [item.strip() for item in lines[0].split(",") if item.strip()] | |
| if len(comma_items) > 1: | |
| return len(comma_items) | |
| return 1 | |
| def normalize_matching_answers(answers): | |
| normalized = [] | |
| for answer in answers: | |
| match = re.fullmatch(r"\s*([A-Za-z])(?:[.)])?\s*", str(answer)) | |
| normalized.append(match.group(1).upper() if match else str(answer).strip().upper()) | |
| return normalized | |
| def matching_is_permutation(expected_n, labels): | |
| return len(labels) == expected_n and len(set(labels)) == expected_n | |
| def valid_matching(answers, expected_n, labels): | |
| if len(answers) != expected_n: | |
| return False | |
| if not labels: | |
| return all(re.fullmatch(r"[A-Z]", answer or "") for answer in answers) | |
| if not all(answer in labels for answer in answers): | |
| return False | |
| if matching_is_permutation(expected_n, labels): | |
| return len(set(answers)) == expected_n and set(answers) == set(labels) | |
| return True | |
| def complete_matching_permutation(answers, expected_n, labels): | |
| """Keep valid first occurrences and fill duplicates/missing slots with unused labels.""" | |
| if not matching_is_permutation(expected_n, labels): | |
| return answers | |
| completed = [] | |
| used = set() | |
| holes = [] | |
| for answer in answers[:expected_n]: | |
| answer = str(answer).strip().upper() | |
| if answer in labels and answer not in used: | |
| completed.append(answer) | |
| used.add(answer) | |
| else: | |
| holes.append(len(completed)) | |
| completed.append(None) | |
| while len(completed) < expected_n: | |
| holes.append(len(completed)) | |
| completed.append(None) | |
| unused = [label for label in labels if label not in used] | |
| for position, label in zip(holes, unused): | |
| completed[position] = label | |
| return completed | |
| def write_submission(rows): | |
| pd.DataFrame(rows, columns=["id", "pred"]).to_csv("submission.csv", index=False) | |
| def generate_text(messages, max_new_tokens): | |
| input_ids = tokenizer.apply_chat_template( | |
| messages, add_generation_prompt=True, return_tensors="pt" | |
| ).to(model.device) | |
| with torch.no_grad(): | |
| output = model.generate( | |
| input_ids, | |
| max_new_tokens=max_new_tokens, | |
| do_sample=False, | |
| use_cache=True, | |
| pad_token_id=tokenizer.eos_token_id, | |
| ) | |
| return tokenizer.decode( | |
| output[0][input_ids.shape[-1]:], skip_special_tokens=True | |
| ).strip() | |
| def validate_submission(rows, source_df): | |
| errors = [] | |
| if len(rows) != len(source_df): | |
| errors.append(f"row count {len(rows)} != {len(source_df)}") | |
| ids = [str(row["id"]) for row in rows] | |
| expected_ids = source_df["id"].astype(str).tolist() | |
| if ids != expected_ids: | |
| errors.append("IDs or row order differ from test.csv") | |
| if len(ids) != len(set(ids)): | |
| errors.append("duplicate IDs") | |
| for position, row in enumerate(rows): | |
| try: | |
| predictions = json.loads(row["pred"]) | |
| except Exception as error: | |
| errors.append(f"row {position}: invalid JSON ({error})") | |
| continue | |
| source = source_df.iloc[position] | |
| expected_n = count_query_items( | |
| source["query"], source["context"], source.get("task_type", "") | |
| ) | |
| if not isinstance(predictions, list): | |
| errors.append(f"row {position}: pred is not a list") | |
| elif len(predictions) != expected_n: | |
| errors.append(f"row {position}: {len(predictions)} != {expected_n} answers") | |
| elif not all(isinstance(answer, str) and answer != "" for answer in predictions): | |
| errors.append(f"row {position}: empty or non-string answer") | |
| return errors | |
| log.info("Loading local model") | |
| tokenizer = AutoTokenizer.from_pretrained(MODEL_ID, local_files_only=True) | |
| model = AutoModelForCausalLM.from_pretrained( | |
| MODEL_ID, | |
| torch_dtype=torch.float16, | |
| device_map="auto", | |
| local_files_only=True, | |
| ).eval() | |
| log.info("Model loaded in %.1fs", time.time() - START_TIME) | |
| df = pd.read_csv("/tmp/data/test.csv", dtype=str).fillna("") | |
| log.info("Loaded %d test rows", len(df)) | |
| # Always keep a structurally complete CSV on disk. | |
| submission_rows = [] | |
| for _, row in df.iterrows(): | |
| expected_n = count_query_items( | |
| row["query"], row["context"], row.get("task_type", "") | |
| ) | |
| labels = option_labels(row["context"]) if row.get("task_type", "") == "match_letters" else [] | |
| fallback = labels[:expected_n] if len(labels) >= expected_n else ["?"] * expected_n | |
| submission_rows.append({ | |
| "id": row["id"], | |
| "pred": json.dumps(fallback, ensure_ascii=False), | |
| }) | |
| write_submission(submission_rows) | |
| for position, (_, row) in enumerate(df.iterrows()): | |
| task_type = row.get("task_type", "") | |
| expected_n = count_query_items(row["query"], row["context"], task_type) | |
| labels = option_labels(row["context"]) if task_type == "match_letters" else [] | |
| one_to_one = task_type == "match_letters" and matching_is_permutation(expected_n, labels) | |
| elapsed = time.time() - START_TIME | |
| remaining = SOFT_LIMIT_SECONDS - elapsed | |
| if remaining > 10 * 60: | |
| main_budget = 1536 | |
| elif remaining > 5 * 60: | |
| main_budget = 768 | |
| else: | |
| main_budget = 384 | |
| log.info( | |
| "row=%d/%d type=%s expected=%d labels=%d bijection=%s elapsed=%.1fs budget=%d", | |
| position + 1, | |
| len(df), | |
| task_type, | |
| expected_n, | |
| len(labels), | |
| one_to_one, | |
| elapsed, | |
| main_budget, | |
| ) | |
| if task_type == "match_letters": | |
| user_content = ( | |
| f"CONTEXT:\n{row['context'].strip()}\n\nQUERY:\n{row['query'].strip()}\n\n" | |
| f"Required answer count: {expected_n}.\n" | |
| f"Valid labels: {', '.join(labels) if labels else 'infer from context'}." | |
| ) | |
| system_prompt = MATCH_SYSTEM | |
| else: | |
| user_content = ( | |
| f"TASK TYPE: {task_type}\n\nCONTEXT:\n{row['context'].strip()}\n\n" | |
| f"QUERY:\n{row['query'].strip()}\n\nRequired answer count: {expected_n}." | |
| ) | |
| system_prompt = SYSTEM | |
| try: | |
| raw_text = generate_text( | |
| [ | |
| {"role": "system", "content": system_prompt}, | |
| {"role": "user", "content": user_content}, | |
| ], | |
| max_new_tokens=main_budget, | |
| ) | |
| log.info("row=%d primary_raw=%r", position + 1, raw_text) | |
| answers = parse_answers(raw_text) | |
| original_count = len(answers) | |
| if task_type == "match_letters": | |
| answers = normalize_matching_answers(answers) | |
| valid = valid_matching(answers, expected_n, labels) | |
| else: | |
| valid = len(answers) == expected_n and all(str(answer).strip() for answer in answers) | |
| log.info("row=%d primary parsed=%d valid=%s", position + 1, original_count, valid) | |
| if not valid and remaining > 3 * 60: | |
| repair_content = ( | |
| f"TASK TYPE: {task_type}\nREQUIRED ANSWER COUNT: {expected_n}\n" | |
| f"ONE-TO-ONE MATCHING: {one_to_one}\n" | |
| f"VALID LABELS: {', '.join(labels)}\n\n" | |
| f"CONTEXT:\n{row['context'].strip()}\n\nQUERY:\n{row['query'].strip()}\n\n" | |
| f"ATTEMPTED SOLUTION:\n{raw_text}" | |
| ) | |
| repair_text = generate_text( | |
| [ | |
| {"role": "system", "content": REPAIR_SYSTEM}, | |
| {"role": "user", "content": repair_content}, | |
| ], | |
| max_new_tokens=768 if remaining > 8 * 60 else 384, | |
| ) | |
| log.info("row=%d repair_raw=%r", position + 1, repair_text) | |
| repaired = parse_answers(repair_text) | |
| if task_type == "match_letters": | |
| repaired = normalize_matching_answers(repaired) | |
| repaired_valid = valid_matching(repaired, expected_n, labels) | |
| else: | |
| repaired_valid = len(repaired) == expected_n and all( | |
| str(answer).strip() for answer in repaired | |
| ) | |
| log.info( | |
| "row=%d repair parsed=%d valid=%s", | |
| position + 1, | |
| len(repaired), | |
| repaired_valid, | |
| ) | |
| if repaired_valid or abs(len(repaired) - expected_n) < abs(len(answers) - expected_n): | |
| answers = repaired | |
| if task_type == "match_letters": | |
| answers = normalize_matching_answers(answers) | |
| if one_to_one and not valid_matching(answers, expected_n, labels): | |
| answers = complete_matching_permutation(answers, expected_n, labels) | |
| answers = [str(answer).strip() for answer in answers[:expected_n]] | |
| if len(answers) < expected_n: | |
| answers.extend(["?"] * (expected_n - len(answers))) | |
| answers = [answer if answer else "?" for answer in answers] | |
| except Exception as error: | |
| log.exception("row=%d failed: %s", position + 1, error) | |
| if task_type == "match_letters" and len(labels) >= expected_n: | |
| answers = labels[:expected_n] | |
| else: | |
| answers = ["?"] * expected_n | |
| if torch.cuda.is_available(): | |
| torch.cuda.empty_cache() | |
| submission_rows[position] = { | |
| "id": row["id"], | |
| "pred": json.dumps(answers, ensure_ascii=False), | |
| } | |
| log.info( | |
| "row=%d id=%s final_answers=%s", | |
| position + 1, | |
| row["id"], | |
| json.dumps(answers, ensure_ascii=False), | |
| ) | |
| write_submission(submission_rows) | |
| log.info("row=%d completed answers=%d/%d", position + 1, len(answers), expected_n) | |
| errors = validate_submission(submission_rows, df) | |
| if errors: | |
| for error in errors: | |
| log.error("validation: %s", error) | |
| raise RuntimeError("submission.csv validation failed") | |
| log.info( | |
| "submission.csv valid rows=%d total_runtime=%.1fs", | |
| len(submission_rows), | |
| time.time() - START_TIME, | |
| ) |