bbidpa's picture
Update README.md
469e20a verified
|
Raw
History Blame Contribute Delete
8.96 kB
---
license: mit
language:
- en
library_name: transformers
pipeline_tag: text-generation
base_model: Qwen/Qwen2.5-Coder-0.5B
tags:
- flutter
- dart
- code-generation
- qwen2
datasets:
- bbidpa/flutter-full-examples-v1
---
# Qwen2.5-Coder-0.5B-Flutter-direct
[Qwen2.5-Coder-0.5B](https://huggingface.co/Qwen/Qwen2.5-Coder-0.5B), fine-tuned to generate a **complete Flutter/Dart file in one shot** from a natural-language goal. Fine-tuned on 5M tokens of flat goal → complete-file examples ([bbidpa/flutter-full-examples-v1](https://huggingface.co/datasets/bbidpa/flutter-full-examples-v1)).
This model is part of a paired comparison studying whether small models benefit more from learning to emit a whole file at once, or from learning to build code up iteratively via small diffs. Its companion on the same base model is [Qwen2.5-Coder-0.5B-Flutter-steps](https://huggingface.co/bbidpa/Qwen2.5-Coder-0.5B-Flutter-steps). The same comparison is also run on a 100M-parameter model trained fully from scratch: [Rainbow-Pony-100M-Flutter-direct](https://huggingface.co/bbidpa/Rainbow-Pony-100m-Flutter-direct) / [-steps](https://huggingface.co/bbidpa/Rainbow-Pony-100m-Flutter-steps).
## Load it
Since Qwen2.5-Coder is a standard, already-registered `transformers` architecture, plain `AutoModel` loading works with no custom code:
```python
from transformers import AutoModelForCausalLM, AutoTokenizer
REPO = "bbidpa/Qwen2.5-Coder-0.5B-Flutter-direct"
tokenizer = AutoTokenizer.from_pretrained(REPO)
model = AutoModelForCausalLM.from_pretrained(REPO)
```
For the exact calling convention used in the examples below (and shared with the from-scratch TinyGPT models in this collection), wrap it with these two small adapters instead:
```python
import torch
import torch.nn as nn
import torch.nn.functional as F
from transformers import AutoTokenizer, AutoModelForCausalLM
DEVICE = "cuda" if torch.cuda.is_available() else "cpu"
class QwenTokenizerAdapter:
def __init__(self, model_id):
self.hf = AutoTokenizer.from_pretrained(model_id)
self.eos_id = self.hf.eos_token_id
self.bos_id = self.hf.bos_token_id if self.hf.bos_token_id is not None else self.eos_id
self.pad_id = self.hf.pad_token_id if self.hf.pad_token_id is not None else self.eos_id
self.vocab_size = len(self.hf)
self.tokenizer = self
def encode(self, text, add_special_tokens=False):
return self.hf.encode(text, add_special_tokens=add_special_tokens)
def decode(self, ids, skip_special_tokens=False):
return self.hf.decode(ids, skip_special_tokens=skip_special_tokens)
def id_to_token(self, idx):
return self.hf.convert_ids_to_tokens([int(idx)])[0]
def tokens(self, text):
return self.hf.tokenize(text)
class HFModelWrapper(nn.Module):
"""Matches TinyGPT's call convention -- model(xb, yb) -> (logits, loss),
model.generate(idx, max_new_tokens=, eos_id=, top_k=) -> full sequence."""
def __init__(self, hf_model):
super().__init__()
self.hf_model = hf_model
def forward(self, xb, yb=None):
logits = self.hf_model(input_ids=xb).logits
loss = None
if yb is not None:
loss = F.cross_entropy(
logits.view(-1, logits.size(-1)),
yb.view(-1),
ignore_index=-100,
)
return logits, loss
def generate(self, idx, max_new_tokens, eos_id=None, top_k=None, temperature=None, do_sample=None):
return self.hf_model.generate(
input_ids=idx,
max_new_tokens=max_new_tokens,
eos_token_id=eos_id,
pad_token_id=eos_id,
top_k=top_k,
do_sample=do_sample if do_sample is not None else (top_k is not None or temperature is not None),
temperature=temperature if temperature is not None else 1.0,
)
@property
def vocab_size(self):
return self.hf_model.config.vocab_size
def load_hf_checkpoint(path, device):
hf_model = AutoModelForCausalLM.from_pretrained(
path,
torch_dtype=torch.bfloat16 if torch.cuda.is_available() else torch.float32,
attn_implementation="sdpa",
).to(device)
return HFModelWrapper(hf_model).to(device)
tokenizer = QwenTokenizerAdapter(REPO)
model = load_hf_checkpoint(REPO, DEVICE).eval()
```
## Prompt format
Same tag vocabulary as the rest of this collection. `<CODE>` holds the current file contents (empty for a from-scratch generation), `<HISTORY>` holds prior steps (unused for this model's typical single-step usage), and the model completes everything after `<OUTPUT>`:
```
<GOAL>
Write a widget that displays a select button with months in it
</GOAL>
<CODE>
</CODE>
<HISTORY>
</HISTORY>
<OUTPUT>
```
## Generate
```python
def render_step_prompt_from_data(
goal: str,
code: str = "",
history: list[dict] | None = None,
action_type: str = "",
action_desc: str = "",
changes: list[dict] | None = None,
is_last_step: bool = False,
include_output: bool = False,
) -> str:
history = history or []
changes = changes or []
history_text = "\n".join(
f"<ACTION><TYPE>{h['type']}</TYPE><DESC>{h['desc']}</DESC></ACTION>"
for h in history
)
text = f"""<GOAL>
{goal}
</GOAL>
<CODE>
{code}
</CODE>
<HISTORY>
{history_text}
</HISTORY>
<OUTPUT>
"""
if include_output:
hunks = "\n".join(
f"<HUNK>\n<SEARCH>\n{h['search']}\n</SEARCH>\n<REPLACE>\n{h['replace']}\n</REPLACE>\n</HUNK>"
for h in changes
)
output = f"<ACTION><TYPE>{action_type}</TYPE><DESC>{action_desc}</DESC></ACTION>\n<CHANGES>\n{hunks}\n</CHANGES>"
if is_last_step:
output += "\n<DONE></DONE>"
text += output + "\n</OUTPUT>"
return text
def generate_output(model, tokenizer, device, prompt, max_new_tokens=300, **generate_kwargs):
prompt_ids = tokenizer.encode(prompt, add_special_tokens=False)
idx = torch.tensor([[tokenizer.bos_id] + prompt_ids], dtype=torch.long).to(device)
generated = model.generate(idx, max_new_tokens=max_new_tokens, eos_id=tokenizer.eos_id, **generate_kwargs)
text = tokenizer.decode(generated[0].tolist(), skip_special_tokens=False)
output = text.split("<OUTPUT>")[-1].split("</OUTPUT>")[0].strip()
return output
prompt = render_step_prompt_from_data(
goal="Write a widget that displays a select button with months in it",
)
text = generate_output(model, tokenizer, DEVICE, prompt, max_new_tokens=1024)
print(text)
```
### Example
**Input goal:** `Write a widget that displays a select button with months in it`
```python
test_row = {
"goal": "Write a widget that displays a select button with months in it",
"code": """""",
"history": [],
"action_type": "",
"action_desc": "",
"is_last_step": False,
"changes": [],
}
prompt = render_step_prompt_from_data(
goal=test_row['goal'],
code=test_row['code'],
history=test_row['history'],
action_type=test_row['action_type'],
action_desc=test_row['action_desc'],
changes=test_row['changes'],
is_last_step=test_row['is_last_step'],
include_output=False
)
text = generate_output(model, tokenizer, DEVICE, prompt, max_new_tokens=300)
print(text)
```
**Output:**
```
import 'package:flutter/material.dart';
class SelectMonth extends StatefulWidget {
@override
_SelectMonthState createState() => _SelectMonthState();
}
class _SelectMonthState extends State<SelectMonth> {
String? selectedMonth;
final List<String> monthNames = ['January', 'February', 'March', 'April', 'May', 'June'];
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
DropdownButton<String>(
value: selectedMonth,
items: monthNames
.map((month) => DropdownMenuItem(value: month, child: Text(month)))
.toList(),
onChanged: (val) => setState(() => selectedMonth = val),
),
Text('Selected month: ${selectedMonth ?? 'None'}'),
],
);
}
}
```
## Training details
| | |
|---|---|
| Base model | [Qwen/Qwen2.5-Coder-0.5B](https://huggingface.co/Qwen/Qwen2.5-Coder-0.5B) (~0.5B params, pretrained by Alibaba/Qwen) |
| Fine-tuning | 5M tokens, flat goal → complete-file examples |
| Tokenizer | Qwen's native BPE tokenizer, extended with structural special tokens |
## Related
- Companion model (iterative diff-based training, same base): [bbidpa/Qwen2.5-Coder-0.5B-Flutter-steps](https://huggingface.co/bbidpa/Qwen2.5-Coder-0.5B-Flutter-steps)
- Same comparison, 100M model trained from scratch: [bbidpa/Rainbow-Pony-100m-Flutter-direct](https://huggingface.co/bbidpa/Rainbow-Pony-100m-Flutter-direct)
- Training dataset: [bbidpa/flutter-full-examples-v1](https://huggingface.co/datasets/bbidpa/flutter-full-examples-v1)
- Training/eval code: [Upcoming]