Spaces:
Sleeping
Sleeping
Upload 6 files
Browse files- README.md +11 -0
- app.py +13 -0
- inference.py +14 -0
- monthly-train.yml +34 -0
- requirements.txt +11 -0
- train_lora.py +50 -0
README.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 🤖 DeepSeek-Coder LoRA Space
|
| 2 |
+
Fine-tunes and serves `deepseek-ai/deepseek-coder-1.3b-base` using QLoRA.
|
| 3 |
+
|
| 4 |
+
## Deploy on Hugging Face Spaces
|
| 5 |
+
1. Create a new **Space** → Type: *Streamlit* → Hardware: *CPU Basic*
|
| 6 |
+
2. Upload `deepseek-lora-space.zip`
|
| 7 |
+
3. Add Secrets → `HF_TOKEN`, `WANDB_API_KEY`
|
| 8 |
+
4. Space auto-builds; open the app!
|
| 9 |
+
|
| 10 |
+
## Monthly auto-training
|
| 11 |
+
GitHub Actions retrains monthly and rebuilds the Space if accuracy improves.
|
app.py
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
from inference import generate_response
|
| 3 |
+
|
| 4 |
+
st.set_page_config(page_title="DeepSeek-Coder LoRA", page_icon="🤖")
|
| 5 |
+
st.title("🤖 DeepSeek-Coder LoRA Playground")
|
| 6 |
+
st.write("Fine-tuned on **NL2SH-ALFA** + user data using QLoRA")
|
| 7 |
+
|
| 8 |
+
prompt = st.text_area("💬 Enter natural-language command:", height=150)
|
| 9 |
+
if st.button("Generate Bash Command"):
|
| 10 |
+
with st.spinner("Thinking..."):
|
| 11 |
+
out = generate_response(prompt)
|
| 12 |
+
st.success(out)
|
| 13 |
+
st.code(out, language="bash")
|
inference.py
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from transformers import AutoTokenizer, AutoModelForCausalLM
|
| 2 |
+
from peft import PeftModel
|
| 3 |
+
|
| 4 |
+
BASE_MODEL = "deepseek-ai/deepseek-coder-1.3b-base"
|
| 5 |
+
LORA_REPO = "your-username/deepseek-lora-monthly"
|
| 6 |
+
|
| 7 |
+
tokenizer = AutoTokenizer.from_pretrained(BASE_MODEL, trust_remote_code=True)
|
| 8 |
+
base = AutoModelForCausalLM.from_pretrained(BASE_MODEL, trust_remote_code=True)
|
| 9 |
+
model = PeftModel.from_pretrained(base, LORA_REPO)
|
| 10 |
+
|
| 11 |
+
def generate_response(prompt:str)->str:
|
| 12 |
+
inputs = tokenizer(prompt, return_tensors="pt")
|
| 13 |
+
out = model.generate(**inputs, max_new_tokens=200)
|
| 14 |
+
return tokenizer.decode(out[0], skip_special_tokens=True)
|
monthly-train.yml
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: Monthly Retrain + Deploy
|
| 2 |
+
on:
|
| 3 |
+
schedule:
|
| 4 |
+
- cron: "0 3 1 * *"
|
| 5 |
+
workflow_dispatch:
|
| 6 |
+
jobs:
|
| 7 |
+
retrain-deploy:
|
| 8 |
+
runs-on: ubuntu-latest
|
| 9 |
+
steps:
|
| 10 |
+
- uses: actions/checkout@v4
|
| 11 |
+
- uses: actions/setup-python@v4
|
| 12 |
+
with: { python-version: "3.10" }
|
| 13 |
+
- run: pip install -r requirements.txt
|
| 14 |
+
- env:
|
| 15 |
+
HF_TOKEN: ${{ secrets.HF_TOKEN }}
|
| 16 |
+
WANDB_API_KEY: ${{ secrets.WANDB_API_KEY }}
|
| 17 |
+
run: python train_lora.py
|
| 18 |
+
- name: Compare & deploy if improved
|
| 19 |
+
run: |
|
| 20 |
+
new=$(python -c "import json;print(1-json.load(open('out/metrics.json')).get('eval_loss',1))")
|
| 21 |
+
old=$(python -c "import json;print(json.load(open('best_score.json')).get('best_accuracy',0))" || echo 0)
|
| 22 |
+
echo "New acc=$new | Old=$old"
|
| 23 |
+
if (( $(echo "$new>$old"|bc -l) )); then
|
| 24 |
+
echo "{"best_accuracy":$new}" > best_score.json
|
| 25 |
+
git config user.name github-actions
|
| 26 |
+
git config user.email github-actions@github.com
|
| 27 |
+
git add best_score.json && git commit -m "update best score"
|
| 28 |
+
git push
|
| 29 |
+
huggingface-cli upload ./out/lora_adapters --repo your-username/deepseek-lora-monthly --token $HF_TOKEN
|
| 30 |
+
curl -X POST -H "Authorization: Bearer $HF_TOKEN" https://huggingface.co/api/spaces/your-username/deepseek-lora-space/rebuild
|
| 31 |
+
echo "🚀 Space rebuild triggered"
|
| 32 |
+
else
|
| 33 |
+
echo "No improvement. Skip deploy."
|
| 34 |
+
fi
|
requirements.txt
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
transformers==4.46.0
|
| 2 |
+
datasets
|
| 3 |
+
accelerate
|
| 4 |
+
wandb
|
| 5 |
+
trl
|
| 6 |
+
peft
|
| 7 |
+
fastapi
|
| 8 |
+
uvicorn
|
| 9 |
+
streamlit
|
| 10 |
+
huggingface_hub
|
| 11 |
+
torch
|
train_lora.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os, json, torch, wandb
|
| 2 |
+
from transformers import (AutoModelForCausalLM, AutoTokenizer, Trainer,
|
| 3 |
+
TrainingArguments, DataCollatorForLanguageModeling)
|
| 4 |
+
from datasets import load_dataset
|
| 5 |
+
from peft import LoraConfig, get_peft_model
|
| 6 |
+
from huggingface_hub import HfApi
|
| 7 |
+
|
| 8 |
+
HF_TOKEN = os.getenv("HF_TOKEN")
|
| 9 |
+
WANDB_API_KEY = os.getenv("WANDB_API_KEY")
|
| 10 |
+
wandb.login(key=WANDB_API_KEY)
|
| 11 |
+
|
| 12 |
+
model_name = "deepseek-ai/deepseek-coder-1.3b-base"
|
| 13 |
+
dataset = load_dataset("westenfelder/NL2SH-ALFA")
|
| 14 |
+
|
| 15 |
+
tok = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
|
| 16 |
+
def tok_fn(b): return tok([f"{n} => {bsh}" for n,bsh in zip(b['nl'],b['bash'])],
|
| 17 |
+
truncation=True,padding="max_length",max_length=512)
|
| 18 |
+
train, test = dataset["train"].map(tok_fn,batched=True), dataset["test"].map(tok_fn,batched=True)
|
| 19 |
+
|
| 20 |
+
m = AutoModelForCausalLM.from_pretrained(model_name, torch_dtype=torch.float16,
|
| 21 |
+
low_cpu_mem_usage=True, device_map="auto",
|
| 22 |
+
trust_remote_code=True)
|
| 23 |
+
m.config.use_cache=False
|
| 24 |
+
for p in m.parameters(): p.requires_grad=False
|
| 25 |
+
|
| 26 |
+
cfg=LoraConfig(r=8,lora_alpha=16,target_modules=["q_proj","v_proj","k_proj","o_proj",
|
| 27 |
+
"gate_proj","down_proj","up_proj"],
|
| 28 |
+
lora_dropout=0.05,bias="none",task_type="CAUSAL_LM")
|
| 29 |
+
m=get_peft_model(m,cfg)
|
| 30 |
+
coll=DataCollatorForLanguageModeling(tokenizer=tok,mlm=False)
|
| 31 |
+
|
| 32 |
+
args=TrainingArguments(output_dir="./out",num_train_epochs=1,per_device_train_batch_size=1,
|
| 33 |
+
gradient_accumulation_steps=8,learning_rate=2e-4,fp16=True,
|
| 34 |
+
save_strategy="epoch",logging_steps=25,report_to=["wandb"])
|
| 35 |
+
t=Trainer(model=m,args=args,train_dataset=train,eval_dataset=test,data_collator=coll)
|
| 36 |
+
wandb.init(project="deepseek-qlora-monthly",name="deepseek-lite-run")
|
| 37 |
+
t.train()
|
| 38 |
+
|
| 39 |
+
metrics=t.evaluate(); acc=1-metrics.get("eval_loss",1)
|
| 40 |
+
with open("out/metrics.json","w") as f: json.dump(metrics,f)
|
| 41 |
+
wandb.log({"accuracy":acc})
|
| 42 |
+
print(f"✅ Eval accuracy {acc:.4f}")
|
| 43 |
+
|
| 44 |
+
ad="out/lora_adapters"; os.makedirs(ad,exist_ok=True)
|
| 45 |
+
m.save_pretrained(ad); tok.save_pretrained(ad)
|
| 46 |
+
artifact=wandb.Artifact("deepseek-lora-adapters","model"); artifact.add_dir(ad); wandb.log_artifact(artifact)
|
| 47 |
+
|
| 48 |
+
api=HfApi(token=HF_TOKEN)
|
| 49 |
+
api.upload_folder(folder_path=ad,repo_id="your-username/deepseek-lora-monthly",path_in_repo=".")
|
| 50 |
+
print("✅ Uploaded to HF Hub")
|