File size: 7,799 Bytes
9f8d4a1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | #!/usr/bin/env python3
"""Fix Colab β use cloudflared for tunnel (free, no auth) + verify server starts."""
import subprocess, os, json
TOKEN = "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"
subprocess.run(["git", "clone", f"https://{TOKEN}@github.com/ticketguy/littlefig.git", "/app/littlefig"], check=True)
os.chdir("/app/littlefig")
subprocess.run(["git", "config", "user.name", "0xticketguy"], check=True)
subprocess.run(["git", "config", "user.email", "0xticketguy@harboria.dev"], check=True)
colab = {
"nbformat": 4,
"nbformat_minor": 0,
"metadata": {
"colab": {"provenance": [], "gpuType": "T4"},
"kernelspec": {"name": "python3", "display_name": "Python 3"},
"accelerator": "GPU"
},
"cells": [
{"cell_type": "markdown", "metadata": {}, "source": [
"# π Little Fig Studio\n",
"\n",
"**Train any LLM on any hardware.** Select your model, configure, launch.\n",
"\n",
"| Feature | Result |\n",
"|---|---|\n",
"| Quantization | Beats NF4 on 156/156 layers |\n",
"| GPU Speed | 7Γ faster than BnB NF4 |\n",
"| CPU Training | 1.1B model in 400MB RAM |\n",
"| Optimizer | FigMeZO (β18.6%, original research) |\n",
"\n",
"**Run all cells below β**"
]},
{"cell_type": "code", "metadata": {}, "source": [
"# Step 1: Install\n",
"!git clone https://github.com/ticketguy/littlefig.git /content/littlefig --quiet 2>/dev/null || (cd /content/littlefig && git pull --quiet)\n",
"!cd /content/littlefig && pip install -q -e \".[train]\"\n",
"!pip install -q uvicorn fastapi python-multipart websockets\n",
"\n",
"# Download cloudflared (free tunnel, no signup)\n",
"!wget -q https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-amd64 -O /usr/local/bin/cloudflared\n",
"!chmod +x /usr/local/bin/cloudflared\n",
"\n",
"import torch, sys\n",
"sys.path.insert(0, '/content/littlefig/src')\n",
"print(f'\\nβ
Installed | PyTorch {torch.__version__} | GPU: {torch.cuda.get_device_name() if torch.cuda.is_available() else \"CPU\"}')"
], "execution_count": None, "outputs": []},
{"cell_type": "code", "metadata": {}, "source": [
"# Step 2: Launch Little Fig Studio\n",
"import subprocess, time, threading, re\n",
"\n",
"# Start the web server\n",
"server = subprocess.Popen(\n",
" ['python', '-m', 'uvicorn', 'little_fig.web.server:app',\n",
" '--host', '0.0.0.0', '--port', '8888'],\n",
" cwd='/content/littlefig/src',\n",
" stdout=subprocess.PIPE, stderr=subprocess.PIPE\n",
")\n",
"time.sleep(3)\n",
"\n",
"# Check if server is running\n",
"import urllib.request\n",
"try:\n",
" urllib.request.urlopen('http://localhost:8888', timeout=2)\n",
" print('β
Server running on port 8888')\n",
"except:\n",
" # Server might return non-200 but still be alive\n",
" print('β οΈ Server may not have started correctly. Check errors below:')\n",
" try:\n",
" err = server.stderr.read(1000).decode()\n",
" print(err[:500])\n",
" except:\n",
" pass\n",
"\n",
"# Start cloudflared tunnel (free, no account needed)\n",
"tunnel = subprocess.Popen(\n",
" ['cloudflared', 'tunnel', '--url', 'http://localhost:8888'],\n",
" stdout=subprocess.PIPE, stderr=subprocess.PIPE\n",
")\n",
"time.sleep(5)\n",
"\n",
"# Read tunnel URL from stderr\n",
"tunnel_url = None\n",
"try:\n",
" output = tunnel.stderr.read(4096).decode()\n",
" urls = re.findall(r'https://[a-z0-9-]+\\.trycloudflare\\.com', output)\n",
" if urls:\n",
" tunnel_url = urls[0]\n",
"except:\n",
" pass\n",
"\n",
"if tunnel_url:\n",
" print(f'\\nπ Little Fig Studio is LIVE!')\n",
" print(f'\\n π {tunnel_url}')\n",
" print(f'\\n Open the link above in your browser.')\n",
" print(f' Select model β Configure β Train')\n",
"else:\n",
" print('\\nβ οΈ Tunnel failed. Using iframe fallback...')\n",
" from IPython.display import IFrame, display\n",
" # Try Colab proxy\n",
" from google.colab.output import eval_js\n",
" proxy_url = eval_js(\"google.colab.kernel.proxyPort(8888)\")\n",
" print(f' Try: {proxy_url}')\n",
" display(IFrame(src=str(proxy_url), width='100%', height=700))\n",
"\n",
"print('\\n Keep this cell running to keep the server alive.')"
], "execution_count": None, "outputs": []},
{"cell_type": "markdown", "metadata": {}, "source": [
"---\n",
"## Alternative: Python API (no UI)\n",
"\n",
"Change `MODEL` to any HuggingFace model."
]},
{"cell_type": "code", "metadata": {}, "source": [
"from little_fig.engine import FigModel, FigTrainer, FigTrainingConfig\n",
"\n",
"# === YOUR MODEL HERE ===\n",
"MODEL = 'TinyLlama/TinyLlama-1.1B-Chat-v1.0'\n",
"# MODEL = 'google/gemma-3-4b-it'\n",
"# MODEL = 'Qwen/Qwen2.5-1.5B'\n",
"# MODEL = 'microsoft/phi-2'\n",
"\n",
"model = FigModel.from_pretrained(MODEL, lora_r=16, lora_alpha=32, shared_codebook=True)\n",
"print(f'β
{MODEL} loaded | Trainable: {sum(p.numel() for p in model.parameters() if p.requires_grad):,}')"
], "execution_count": None, "outputs": []},
{"cell_type": "code", "metadata": {}, "source": [
"# Train\n",
"config = FigTrainingConfig(\n",
" num_epochs=1,\n",
" learning_rate=2e-4,\n",
" max_seq_length=256,\n",
" batch_size=2,\n",
" gradient_accumulation_steps=4,\n",
" logging_steps=5,\n",
" use_packing=True,\n",
")\n",
"trainer = FigTrainer(model, config)\n",
"trainer.load_dataset('tatsu-lab/alpaca', max_samples=200)\n",
"trainer.train()\n",
"model.save_adapter('./my_adapter')\n",
"print('\\nβ
Training complete! Adapter saved.')"
], "execution_count": None, "outputs": []},
{"cell_type": "markdown", "metadata": {}, "source": [
"---\n",
"*0xticketguy / Harboria Labs | AGPL-3.0*"
]}
]
}
with open("Little_Fig_Colab.ipynb", "w") as f:
json.dump(colab, f, indent=2)
subprocess.run(["git", "add", "-A"], check=True)
subprocess.run(["git", "commit", "-m",
"Fix Colab: cloudflared tunnel (free, no signup) + fallback to Colab proxy\n\n"
"- Uses cloudflared (Cloudflare's free tunnel) instead of ngrok\n"
"- No account needed, no auth token\n"
"- Falls back to google.colab.output.eval_js proxy if tunnel fails\n"
"- Checks if server is actually running before tunneling\n"
"- Shows errors if server fails to start"], check=True)
subprocess.run(["git", "push", "origin", "main"], check=True)
print("β
Colab fixed with cloudflared tunnel")
|