Instructions to use lattice-nlp/Qwen3.5-27B_inline_coreference_resolution with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- PEFT
How to use lattice-nlp/Qwen3.5-27B_inline_coreference_resolution with PEFT:
from peft import PeftModel from transformers import AutoModelForCausalLM base_model = AutoModelForCausalLM.from_pretrained("unsloth/Qwen3.5-27B") model = PeftModel.from_pretrained(base_model, "lattice-nlp/Qwen3.5-27B_inline_coreference_resolution") - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- Unsloth Desktop
Qwen3.5-27B LoRA for coreference resolution (corefud-1-4, window 1000, 1 epoch)
This repository holds a LoRA adapter for coreference resolution. It sits on top of
unsloth/Qwen3.5-27B and was trained with Unsloth on the corefud-1-4 data with a window width
of 1000 characters for 1 epoch(s).
The model reads a text where every mention is wrapped as {___ mention}. It writes the same
text back with a numeric entity ID in place of each ___. Mentions of the same entity share
one ID, and numbering starts at 0 in each document.
Only the adapter weights are stored here. Load them on top of the base model.
Task format
Prompt template, sent as a single user message:
## Task
Replace each ___ with a numeric coreference ID.
## Rules
- Do NOT modify any other characters in the text.
- The braces { and } must remain unchanged.
- Only replace the substring ___.
- Start numbering from 0 for each document.
- Use the same ID for mentions referring to the same entity.
- Return only the modified text.
## Input
<input_placeholder>
## Output
Example input:
{___ Maria} said {___ she} was tired , so {___ {___ her} brother} drove {___ her} home .
Example output:
{0 Maria} said {0 she} was tired , so {1 {0 her} brother} drove {0 her} home .
Mentions can be nested. Zero mentions appear as the ∅ token.
Minimal Example
from unsloth import FastModel
PROMPT = '''## Task
Replace each ___ with a numeric coreference ID.
## Rules
- Do NOT modify any other characters in the text.
- The braces { and } must remain unchanged.
- Only replace the substring ___.
- Start numbering from 0 for each document.
- Use the same ID for mentions referring to the same entity.
- Return only the modified text.
## Input
<input_placeholder>
## Output
'''
model, tokenizer = FastModel.from_pretrained(
model_name="lattice-nlp/Qwen3.5-27B_inline_coreference_resolution",
max_seq_length=4090,
load_in_4bit=True,
)
FastModel.for_inference(model)
tokenizer.tokenizer.padding_side = "left"
text = "{___ Maria} said {___ she} was tired , so {___ Maria 's brother} drove {___ her} home ."
messages = [{"role": "user", "content": PROMPT.replace("<input_placeholder>", text)}]
prompt = tokenizer.apply_chat_template(
messages, tokenize=False, add_generation_prompt=True, enable_thinking=False
).replace("<think>\n\n</think>\n\n", "")
inputs = tokenizer.tokenizer(prompt, return_tensors="pt", add_special_tokens=False).to("cuda")
n_in = len(tokenizer.tokenizer(text)["input_ids"])
out = model.generate(
**inputs,
max_new_tokens=max(int(1.25 * n_in), n_in + 20),
do_sample=False,
use_cache=True,
)
print(tokenizer.batch_decode(out[:, inputs["input_ids"].shape[1]:], skip_special_tokens=True)[0])
Greedy decoding with thinking disabled matches how the adapter was evaluated.
Because the answer repeats the whole input, the output length grows with the input,
so max_new_tokens should follow the input length as above.
Full Implementation
from unsloth import FastModel
PROMPT = '''## Task
Replace each ___ with a numeric coreference ID.
## Rules
- Do NOT modify any other characters in the text.
- The braces { and } must remain unchanged.
- Only replace the substring ___.
- Start numbering from 0 for each document.
- Use the same ID for mentions referring to the same entity.
- Return only the modified text.
## Input
<input_placeholder>
## Output
'''
model, tokenizer = FastModel.from_pretrained(
model_name="lattice-nlp/Qwen3.5-27B_inline_coreference_resolution",
max_seq_length=4090,
load_in_4bit=True,
)
FastModel.for_inference(model)
tokenizer.tokenizer.padding_side = "left"
from coreference import preprocess_coreference, extract_predicted_COREF_ids_from_output
document = {
'text': 'Maria said she was tired , so her brother drove her home .',
'mentions': [
{'COREF': 'Maria', 'onset': 0, 'offset': 5, 'text': 'Maria'},
{'COREF': 'Maria', 'onset': 11, 'offset': 14, 'text': 'she'},
{'COREF': 'Maria', 'onset': 30, 'offset': 33, 'text': 'her'},
{'COREF': "Maria's Brother", 'onset': 30, 'offset': 41, 'text': 'her brother'},
{'COREF': 'Maria', 'onset': 48, 'offset': 51, 'text': 'her'}
]
}
# adding the input field
document = preprocess_coreference(document)
print(document["input"])
messages = [{"role": "user", "content": PROMPT.replace("<input_placeholder>", document["input"])}]
prompt = tokenizer.apply_chat_template(
messages, tokenize=False, add_generation_prompt=True, enable_thinking=False
).replace("<think>\n\n</think>\n\n", "")
inputs = tokenizer.tokenizer(prompt, return_tensors="pt", add_special_tokens=False).to("cuda")
n_in = len(tokenizer.tokenizer(document["input"])["input_ids"])
out = model.generate(
**inputs,
max_new_tokens=max(int(1.25 * n_in), n_in + 20),
do_sample=False,
use_cache=True,
)
output = tokenizer.batch_decode(out[:, inputs["input_ids"].shape[1]:], skip_special_tokens=True)[0]
print(output)
predicted_COREF_ids = extract_predicted_COREF_ids_from_output(document["input"], output)
assert len(predicted_COREF_ids) == len(document["mentions"])
for mention, predicted_COREF in zip(document["mentions"], predicted_COREF_ids):
mention["predicted_COREF"] = predicted_COREF
print(document["mentions"])
for cluster_ID in sorted(set([mention["predicted_COREF"] for mention in document["mentions"]])):
print(f"Cluster ID: {cluster_ID}")
cluster_mentions = [mention for mention in document["mentions"] if mention["predicted_COREF"] == cluster_ID]
for mention in cluster_mentions:
print(f" {mention}")
Greedy decoding with thinking disabled matches how the adapter was evaluated.
Because the answer repeats the whole input, the output length grows with the input,
so max_new_tokens should follow the input length as above.
Adapter
| Base model | unsloth/Qwen3.5-27B |
| Method | QLoRA (4-bit base weights during training) |
| LoRA rank / alpha | 64 / 64 |
| LoRA dropout | 0 |
| Adapter parameters | 466,911,232 |
| PEFT version | 0.21.0 |
Training
| Dataset | corefud-1-4 |
| Window width | 1000 |
| Train examples | 38,092 |
| Dev examples | 5,230 |
| Epochs | 1 |
| Optimizer steps | 596 |
| Last logged training loss | 0.0145 |
| Effective batch size | 64 (8 x 8 accumulation steps) |
| Learning rate | 2e-4, linear decay, 100 warmup steps |
| Optimizer | adamw_8bit |
| Weight decay | 0.001 |
| Max grad norm | 1.0 |
| Precision | bf16 |
| Max sequence length | 4,090 |
| Loss | computed on the assistant answer only (train_on_responses_only) |
| Thinking mode | disabled in the chat template |
| Seed | 0 |
| Hardware | 1x NVIDIA RTX 6000 Ada Generation (48 GB) |
| Software | Unsloth 2026.10.5, Transformers 5.17.0, PyTorch 2.10.0 (CUDA 12.8) |
Evaluation
Dev split of corefud-1-4 (window 1000), greedy decoding, singletons kept.
Predicted IDs are realigned to the input spans before scoring, and the score comes from the
coreference.evaluation module of the training project.
| Metric | Value |
|---|---|
| CoNLL-F1 (mean over 5,230 documents) | 91.83 |
Limitations and license
The adapter was tuned for this one prompt format. Other prompts or tasks are not covered. Long inputs mean long outputs, and the model can drop or alter text, so check that the predicted text matches the input before using the IDs.
- Downloads last month
- 25