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")