MyVillage Project Creation: Qwen2.5-1.5B SFT v1
This model writes student team projects. Give it a short request naming an audience and a theme, for example "create a project title and description for middle schools, the theme is trials and tribulations". It replies with one age-appropriate project in a fixed Markdown format:
**Project Title: RiseUp: Turn Challenges Into Superpowers! 💪🎮**
**Project Description:**
Team up with your crew to explore how challenges, setbacks, and difficult moments can help us grow stronger! ...
Each project centers on one working technology artifact the team builds: a game, simulation, interactive tool, branching story, dashboard, chatbot, robot or simulator, and so on. The description says what the finished product does and how students know they're done. It deliberately leaves out step-by-step instructions, because the MyVillage platform generates the activities separately.
| Base model | Qwen/Qwen2.5-1.5B-Instruct |
| Fine-tuning | QLoRA supervised fine-tuning (SFT) on 900 of 1,000 request/project pairs, merged into the base model |
| Audiences | Elementary, middle school, high school, college |
| Output | **Project Title: ...** followed by **Project Description:** and 3–4 paragraphs |
| Hosted API | mjpsm/project-creation-api |
Quick start
pip install "transformers>=4.45" torch accelerate
import re
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM
MODEL_ID = "mjpsm/project-creation-qwen2.5-1.5b-sft-v1"
# Use this system prompt: it is the one the hosted API uses.
SYSTEM_PROMPT = (
"You are the MyVillage educational project creator. Given a student project request, "
"write one engaging, age-appropriate, feasible project that fits the requested subject "
"and audience. Follow the examples' Markdown structure exactly: **Project Title: ...** "
"followed by **Project Description:** and a detailed, actionable description. "
"Do not add unrelated topics."
)
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
model = AutoModelForCausalLM.from_pretrained(MODEL_ID, torch_dtype="auto", device_map="auto")
model.eval()
def generate_project(prompt: str) -> str:
messages = [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": prompt},
]
inputs = tokenizer.apply_chat_template(
messages, add_generation_prompt=True, return_tensors="pt", return_dict=True
).to(model.device)
with torch.inference_mode():
output_ids = model.generate(
**inputs,
max_new_tokens=650,
do_sample=True,
temperature=0.7,
top_p=0.9,
repetition_penalty=1.08,
)
new_tokens = output_ids[0][inputs["input_ids"].shape[-1]:]
return tokenizer.decode(new_tokens, skip_special_tokens=True).strip()
def parse_project(text: str) -> dict:
"""Split the model's Markdown into a title and a description."""
title = re.search(r"\*\*Project Title:\s*(.*?)\*\*", text, re.DOTALL | re.IGNORECASE)
desc = re.search(r"\*\*Project Description:\*\*\s*(.*)", text, re.DOTALL | re.IGNORECASE)
return {
"title": title.group(1).strip() if title else "",
"description": desc.group(1).strip() if desc else "",
}
raw = generate_project(
"create a project title and description for high school students, the theme is climate change"
)
project = parse_project(raw)
print(project["title"])
print(project["description"])
The model runs on CPU, but a full 650-token generation can take a minute or two there. With a GPU or Apple Silicon (device_map="auto" picks it up), it takes a few seconds.
Writing prompts
Name the audience and the theme. The model was trained on loosely phrased requests, so any of these work:
create a project title and description for elementary school kids the theme is articulation and learning how to readWhat would be a good project for college students learning about cybersecurity?I need a middle school project about the water cycle
Don't ask for an artifact type (such as "make it a game") unless you need one. The model chooses a suitable one for the theme and age group.
Recommended generation settings
| Setting | Value |
|---|---|
temperature |
0.7 |
top_p |
0.9 |
repetition_penalty |
1.08 |
max_new_tokens |
650 |
do_sample |
True |
Outputs typically run 1,300–1,800 characters, which fits within 650 tokens.
Hosted API
The model is served by a FastAPI app on the mjpsm/project-creation-api Space, which uses the settings above. The request body contains only the prompt.
curl -X POST https://mjpsm-project-creation-api.hf.space/predict \
-H "Content-Type: application/json" \
-d '{"prompt": "Create a science project for 5th graders about plants"}'
import requests
resp = requests.post(
"https://mjpsm-project-creation-api.hf.space/predict",
json={"prompt": "Create a science project for 5th graders about plants"},
timeout=300,
)
resp.raise_for_status()
data = resp.json()
print(data["title"])
print(data["description"])
The response contains title, description and model. The prompt must be 8–1,500 characters. The Space runs on a free CPU, so expect around 1–2 minutes per request, plus start-up time if the Space has been asleep.
Training data
The dataset contains 1,000 input/output pairs, of which 900 were used for training (see the split below):
- 6 seed projects written and approved by the MyVillage team, which set the style.
- 994 new projects written by Claude Opus 5.5 to a written specification and a fixed coverage plan. No prose templates were used. Every row passed automated format checks.
| Audience | Rows |
|---|---|
| Elementary | 250 |
| Middle school | 250 |
| High school | 300 |
| College | 200 |
Every theme and grade pair is unique, with 932 distinct themes among the new rows. The most common artifact types are simulations (207), interactive museums or maps (155), interactive tools (130), games (120) and branching stories (117). There are also dashboards, robots and simulators, AI projects, quizzes, audio tools, web apps and chatbots.
The data enforces these style rules:
- Projects are done by student teams and center on one working technology artifact.
- Descriptions have 4 paragraphs for elementary and 3 for older audiences.
- Elementary projects include a paragraph for parents and caregivers that keeps the work owned by the child. Older audiences mention parents only on family-related themes.
- There are no lists, code, rubrics, timelines or step-by-step instructions.
- Each description ends with a bold closing question.
Training procedure
The model was fine-tuned with 4-bit QLoRA using TRL's SFTTrainer on a single Google Colab Tesla T4. Loss was computed on the assistant completion only, so the model learns the project text, not the request. After training, the LoRA adapter was merged into the full-precision base model, which is the standalone model in this repo, stored in bfloat16. The unmerged adapter is in mjpsm/project-creation-qwen2.5-1.5b-sft-v1-lora.
Data split (seed 42): 900 train / 50 validation / 50 test. Only the training rows updated the model. The 50 test rows were saved separately as an unseen comparison set. Examples were formatted with the Qwen chat template: the system prompt above, the request as the user turn and the project as the assistant turn. They ranged from 407 tokens (median) to 528 tokens (max), so none were truncated.
| Hyperparameter | Value |
|---|---|
| Method | QLoRA (PEFT 0.17.1, TRL 0.23.1, Transformers 4.57.3) |
| Quantization | 4-bit NF4, double quantization, bfloat16 compute |
| LoRA rank / alpha / dropout | 16 / 32 / 0.05 |
| LoRA target modules | q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj |
| Trainable parameters | 18.5M of 1.56B (1.18%) |
| Epochs | 2 |
| Learning rate | 2e-4, cosine schedule, 5% warmup |
| Batch size | 1 per device × 8 gradient accumulation = effective 8 |
| Optimizer | paged_adamw_8bit, weight decay 0.01, max grad norm 0.3 |
| Max sequence length | 1,024 (no packing) |
| Precision | bfloat16, gradient checkpointing |
| Checkpoint selection | Best validation loss, evaluated each epoch |
| Training time | ~69 minutes (4,137 s) |
Results
| Metric | Value |
|---|---|
| Final training loss | 1.515 |
| Validation loss | 1.502 |
| Validation perplexity | 4.49 |
Loss alone doesn't show whether projects are creative, feasible and age-appropriate. Generations on held-out prompts were spot-checked for format and content, but no systematic human evaluation or comparison with the base model has been run yet.
Limitations
- Descriptions are shorter than the seeds. About 70% of the generated training rows are under 1,500 characters. The seeds are 1,700–2,300, so the model tends to write somewhat shorter projects.
- Facts aren't verified. Training rows were written without source checking. Generated projects may include wrong historical, scientific, legal or health details, especially when they name specific people, statistics or cases.
- Repeated phrasing. Openings like "Team up with your…" and "By the end, your team will have…" are common in the training data and appear often in outputs.
- The training data was not independently reviewed. It passed automated checks and spot reads, but no human reviewed every row.
- The output is not guaranteed to follow the format. Sampling can occasionally produce output the parser can't split. Check that
titleanddescriptionaren't empty, and retry if they are. - Small model. At 1.5B parameters it can drift off-theme or suggest projects that are too ambitious for the audience.
Intended use
The model is for drafting project ideas inside an educational platform, where a teacher or staff member reviews the project before students see it. It is not intended for unsupervised, student-facing use or for generating instructional steps, grading rubrics or factual reference material.