| <!DOCTYPE html> |
| <html lang="en" data-theme="dark"> |
| <head> |
| <meta charset="UTF-8"> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"> |
| <title>dytr Studio · Complete Multi‑Task Transformer Builder</title> |
| <link href="https://fonts.googleapis.com/css2?family=Inter:opsz,wght@14..32,400;14..32,500;14..32,600;14..32,700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet"> |
| <style> |
| * { |
| margin: 0; |
| padding: 0; |
| box-sizing: border-box; |
| -webkit-tap-highlight-color: transparent; |
| } |
| :root { |
| --bg: #0a0c12; |
| --bg2: #0f1117; |
| --bg3: #171b24; |
| --text: #eef2ff; |
| --text2: #a5b4fc; |
| --text3: #6c757d; |
| --accent: #6c63ff; |
| --accent2: #00d4ff; |
| --accent3: #ff6b6b; |
| --accent4: #00c896; |
| --border: #2a2f3f; |
| --card: #12161f; |
| --shadow: 0 8px 20px rgba(0,0,0,0.3); |
| } |
| [data-theme="light"] { |
| --bg: #f1f5f9; |
| --bg2: #ffffff; |
| --bg3: #eef2ff; |
| --text: #0f172a; |
| --text2: #334155; |
| --text3: #64748b; |
| --border: #cbd5e1; |
| --card: #ffffff; |
| --shadow: 0 4px 12px rgba(0,0,0,0.05); |
| } |
| body { |
| font-family: 'Inter', sans-serif; |
| background: var(--bg); |
| color: var(--text); |
| line-height: 1.5; |
| padding: 1rem; |
| } |
| .container { max-width: 1600px; margin: 0 auto; } |
| .header { |
| display: flex; |
| justify-content: space-between; |
| align-items: center; |
| flex-wrap: wrap; |
| margin-bottom: 1.5rem; |
| padding-bottom: 0.75rem; |
| border-bottom: 1px solid var(--border); |
| } |
| .logo h1 { font-size: 1.5rem; font-weight: 700; background: linear-gradient(135deg, var(--accent), var(--accent2)); -webkit-background-clip: text; background-clip: text; color: transparent; } |
| .logo p { font-size: 0.75rem; color: var(--text2); } |
| .theme-toggle { |
| background: var(--bg3); |
| border: 1px solid var(--border); |
| border-radius: 2rem; |
| padding: 0.4rem 1rem; |
| cursor: pointer; |
| font-weight: 500; |
| transition: 0.2s; |
| color: var(--text); |
| } |
| .builder-grid { |
| display: grid; |
| grid-template-columns: repeat(auto-fit, minmax(380px, 1fr)); |
| gap: 1.5rem; |
| } |
| .panel { |
| background: var(--bg2); |
| border: 1px solid var(--border); |
| border-radius: 1.2rem; |
| overflow: hidden; |
| box-shadow: var(--shadow); |
| } |
| .panel-header { |
| padding: 0.9rem 1.2rem; |
| background: var(--bg3); |
| border-bottom: 1px solid var(--border); |
| font-weight: 600; |
| display: flex; |
| justify-content: space-between; |
| align-items: baseline; |
| flex-wrap: wrap; |
| gap: 0.5rem; |
| } |
| .panel-body { padding: 1.2rem; } |
| [data-tip] { |
| position: relative; |
| cursor: help; |
| border-bottom: 1px dashed var(--accent2); |
| } |
| [data-tip]:before { |
| content: attr(data-tip); |
| position: absolute; |
| bottom: 130%; |
| left: 0; |
| background: var(--bg3); |
| color: var(--text2); |
| padding: 0.3rem 0.7rem; |
| border-radius: 0.6rem; |
| font-size: 0.7rem; |
| white-space: nowrap; |
| z-index: 20; |
| pointer-events: none; |
| opacity: 0; |
| transition: 0.15s; |
| box-shadow: 0 2px 8px rgba(0,0,0,0.2); |
| } |
| [data-tip]:hover:before { opacity: 1; transform: translateY(-2px); } |
| @media (max-width: 640px) { [data-tip]:before { white-space: normal; width: 180px; bottom: auto; top: 100%; left: 0; } } |
| .slider-group { margin-bottom: 1rem; } |
| .slider-label { display: flex; justify-content: space-between; font-size: 0.8rem; font-weight: 500; margin-bottom: 0.2rem; } |
| input[type="range"] { width: 100%; background: var(--bg3); height: 4px; border-radius: 4px; -webkit-appearance: none; } |
| input[type="range"]:focus { outline: none; } |
| input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; width: 16px; height: 16px; border-radius: 50%; background: var(--accent); cursor: pointer; } |
| .toggle-row { display: flex; justify-content: space-between; align-items: center; margin: 0.7rem 0; } |
| .toggle-switch { position: relative; display: inline-block; width: 44px; height: 22px; } |
| .toggle-switch input { opacity: 0; width: 0; height: 0; } |
| .toggle-knob { position: absolute; cursor: pointer; inset: 0; background-color: var(--border); border-radius: 34px; transition: 0.2s; } |
| .toggle-knob:before { content: ""; position: absolute; height: 18px; width: 18px; left: 2px; bottom: 2px; background-color: white; border-radius: 50%; transition: 0.2s; } |
| input:checked + .toggle-knob { background-color: var(--accent); } |
| input:checked + .toggle-knob:before { transform: translateX(22px); } |
| .task-card { |
| background: var(--bg3); |
| border-radius: 0.9rem; |
| padding: 0.8rem; |
| margin-bottom: 0.8rem; |
| border-left: 4px solid var(--accent); |
| } |
| .task-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.5rem; } |
| .task-name { font-weight: 700; } |
| .task-type { font-size: 0.7rem; background: var(--bg2); padding: 0.2rem 0.6rem; border-radius: 2rem; } |
| .remove-task { background: none; border: none; color: var(--accent3); cursor: pointer; font-size: 1.2rem; } |
| .form-row { margin-bottom: 0.8rem; } |
| .form-row label { display: block; font-size: 0.7rem; margin-bottom: 0.2rem; color: var(--text2); } |
| select, input, textarea { |
| width: 100%; |
| background: var(--bg); |
| border: 1px solid var(--border); |
| padding: 0.5rem 0.7rem; |
| border-radius: 0.6rem; |
| color: var(--text); |
| font-family: inherit; |
| font-size: 0.85rem; |
| } |
| pre, code { font-family: 'JetBrains Mono', monospace; font-size: 0.75rem; background: var(--bg); } |
| .code-panel pre { |
| padding: 1rem; |
| overflow-x: auto; |
| max-height: 500px; |
| background: var(--bg); |
| color: var(--text); |
| border-radius: 0.8rem; |
| } |
| .btn-copy { background: var(--accent); border: none; padding: 0.4rem 1rem; border-radius: 2rem; color: white; font-weight: 500; cursor: pointer; } |
| .badge-param { background: var(--bg3); border-radius: 2rem; padding: 0.2rem 0.7rem; font-size: 0.7rem; font-family: monospace; } |
| .info-note { background: var(--bg3); border-radius: 0.8rem; padding: 0.8rem; font-size: 0.75rem; margin-top: 0.8rem; color: var(--text2); } |
| hr { margin: 0.8rem 0; border-color: var(--border); } |
| .three-columns { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 0.8rem; } |
| @media (max-width: 700px) { .three-columns { grid-template-columns: 1fr; } body { padding: 0.8rem; } .panel-header { flex-direction: column; align-items: stretch; } } |
| </style> |
| </head> |
| <body> |
| <div class="container"> |
| <div class="header"> |
| <div class="logo"><h1>⚡ dytr Studio</h1><p>complete transformer builder · multi‑task · continual learning · LoRA · pretrained</p></div> |
| <button class="theme-toggle" id="themeButton">🌙 Dark</button> |
| </div> |
|
|
| <div class="builder-grid"> |
| <div class="panel"> |
| <div class="panel-header"><span>🧠 core architecture</span><span class="badge-param" id="paramCount">params: —</span></div> |
| <div class="panel-body"> |
| <div class="slider-group"><div class="slider-label"><span data-tip="Hidden dimension (quadratic parameter impact)">embed_dim</span><span id="val_embed_dim">256</span></div><input type="range" id="embed_dim" min="64" max="1024" step="32" value="256"></div> |
| <div class="slider-group"><div class="slider-label"><span data-tip="Number of transformer encoder layers">num_layers</span><span id="val_num_layers">6</span></div><input type="range" id="num_layers" min="2" max="24" step="1" value="6"></div> |
| <div class="slider-group"><div class="slider-label"><span data-tip="Attention heads (must divide embed_dim)">num_heads</span><span id="val_num_heads">8</span></div><input type="range" id="num_heads" min="2" max="16" step="1" value="8"></div> |
| <div class="slider-group"><div class="slider-label"><span data-tip="head_dim (auto = embed_dim/num_heads)">head_dim</span><span id="val_head_dim">32</span></div><input type="range" id="head_dim" min="8" max="128" step="8" value="32"></div> |
| <div class="slider-group"><div class="slider-label"><span data-tip="FFN inner dimension multiplier">ff_mult</span><span id="val_ff_mult">4</span></div><input type="range" id="ff_mult" min="1" max="8" step="1" value="4"></div> |
| <div class="slider-group"><div class="slider-label"><span data-tip="Maximum sequence length (O(n²) memory)">max_seq_len</span><span id="val_max_seq_len">256</span></div><input type="range" id="max_seq_len" min="64" max="1024" step="32" value="256"></div> |
| <div class="slider-group"><div class="slider-label"><span data-tip="Dropout rate for regularization">dropout</span><span id="val_dropout">0.1</span></div><input type="range" id="dropout" min="0" max="0.5" step="0.05" value="0.1"></div> |
| </div> |
| </div> |
|
|
| <div class="panel"> |
| <div class="panel-header"><span>⚙️ training & optimization</span></div> |
| <div class="panel-body"> |
| <div class="slider-group"><div class="slider-label"><span data-tip="Batch size per device">batch_size</span><span id="val_batch_size">16</span></div><input type="range" id="batch_size" min="4" max="128" step="4" value="16"></div> |
| <div class="slider-group"><div class="slider-label"><span data-tip="Learning rate (actual = value × 1e-4)">learning_rate (×1e-4)</span><span id="val_lr">3.0</span></div><input type="range" id="learning_rate" min="0.5" max="10" step="0.5" value="3.0"></div> |
| <div class="slider-group"><div class="slider-label"><span data-tip="Number of training epochs">num_train_epochs</span><span id="val_epochs">5</span></div><input type="range" id="epochs" min="1" max="30" step="1" value="5"></div> |
| <div class="slider-group"><div class="slider-label"><span data-tip="Weight decay (L2 regularization)">weight_decay</span><span id="val_weight_decay">0.01</span></div><input type="range" id="weight_decay" min="0" max="0.1" step="0.005" value="0.01"></div> |
| <div class="slider-group"><div class="slider-label"><span data-tip="Gradient clipping max norm">gradient_clip</span><span id="val_grad_clip">1.0</span></div><input type="range" id="gradient_clip" min="0.1" max="5" step="0.1" value="1.0"></div> |
| <div class="slider-group"><div class="slider-label"><span data-tip="Warmup steps for LR scheduler">warmup_steps</span><span id="val_warmup">1000</span></div><input type="range" id="warmup_steps" min="0" max="5000" step="100" value="1000"></div> |
| <div class="slider-group"><div class="slider-label"><span data-tip="Label smoothing factor">label_smoothing</span><span id="val_label_smooth">0.1</span></div><input type="range" id="label_smoothing" min="0" max="0.3" step="0.01" value="0.1"></div> |
| <div class="slider-group"><div class="slider-label"><span data-tip="Early stopping patience">patience</span><span id="val_patience">3</span></div><input type="range" id="patience" min="1" max="10" step="1" value="3"></div> |
| <div class="slider-group"><div class="slider-label"><span data-tip="Maximum learning rate (cosine scheduler)">max_learning_rate (×1e-4)</span><span id="val_max_lr">5.0</span></div><input type="range" id="max_learning_rate" min="1" max="20" step="0.5" value="5.0"></div> |
| <div class="slider-group"><div class="slider-label"><span data-tip="Minimum learning rate (cosine scheduler)">min_learning_rate (×1e-6)</span><span id="val_min_lr">1.0</span></div><input type="range" id="min_learning_rate" min="0.1" max="10" step="0.5" value="1.0"></div> |
| <div class="slider-group"><div class="slider-label"><span data-tip="Adam epsilon for numerical stability">adam_epsilon (×1e-8)</span><span id="val_adam_eps">1.0</span></div><input type="range" id="adam_epsilon" min="0.1" max="10" step="0.5" value="1.0"></div> |
| <div class="slider-group"><div class="slider-label"><span data-tip="Gradient accumulation steps">gradient_accumulation_steps</span><span id="val_grad_acc">1</span></div><input type="range" id="gradient_accumulation_steps" min="1" max="8" step="1" value="1"></div> |
| <div class="slider-group"><div class="slider-label"><span data-tip="LR scheduler type">lr_scheduler_type</span><select id="lr_scheduler_type"><option value="cosine">cosine</option><option value="linear">linear</option><option value="constant">constant</option></select></div> |
| </div> |
| </div> |
|
|
| <div class="panel"> |
| <div class="panel-header"><span>🧠 task-specific learning rates</span></div> |
| <div class="panel-body"> |
| <div class="slider-group"><div class="slider-label"><span data-tip="Learning rate multiplier for shared encoder layers">shared_lr_mult</span><span id="val_shared_lr">0.5</span></div><input type="range" id="shared_lr_mult" min="0.1" max="1.5" step="0.05" value="0.5"></div> |
| <div class="slider-group"><div class="slider-label"><span data-tip="Learning rate multiplier for task-specific heads">head_lr_mult</span><span id="val_head_lr">1.0</span></div><input type="range" id="head_lr_mult" min="0.5" max="3.0" step="0.1" value="1.0"></div> |
| <div class="slider-group"><div class="slider-label"><span data-tip="Learning rate multiplier for task decoders">decoder_lr_mult</span><span id="val_decoder_lr">1.0</span></div><input type="range" id="decoder_lr_mult" min="0.5" max="3.0" step="0.1" value="1.0"></div> |
| </div> |
| </div> |
|
|
| <div class="panel"> |
| <div class="panel-header"><span>🧠 continual learning & adapters</span></div> |
| <div class="panel-body"> |
| <div class="toggle-row"><span data-tip="Adds task‑specific bottleneck layers">use_task_adapters</span><label class="toggle-switch"><input type="checkbox" id="use_task_adapters" checked><span class="toggle-knob"></span></label></div> |
| <div class="toggle-row"><span data-tip="Rotary Position Embedding (RoPE)">use_rotary_embedding</span><label class="toggle-switch"><input type="checkbox" id="use_rotary_embedding" checked><span class="toggle-knob"></span></label></div> |
| <div class="toggle-row"><span data-tip="Elastic Weight Consolidation (EWC)">use_ewc</span><label class="toggle-switch"><input type="checkbox" id="use_ewc"><span class="toggle-knob"></span></label></div> |
| <div class="toggle-row"><span data-tip="Experience replay buffer">use_replay</span><label class="toggle-switch"><input type="checkbox" id="use_replay"><span class="toggle-knob"></span></label></div> |
| <div class="toggle-row"><span data-tip="Flash Attention (faster, lower memory)">use_flash_attention</span><label class="toggle-switch"><input type="checkbox" id="use_flash_attention"><span class="toggle-knob"></span></label></div> |
| <div class="toggle-row"><span data-tip="Gradient checkpointing (memory save)">gradient_checkpointing</span><label class="toggle-switch"><input type="checkbox" id="gradient_checkpointing"><span class="toggle-knob"></span></label></div> |
| <div class="slider-group"><div class="slider-label"><span data-tip="Adapter bottleneck dimension">adapter_bottleneck</span><span id="val_adapter_bn">64</span></div><input type="range" id="adapter_bottleneck" min="8" max="128" step="8" value="64"></div> |
| <div class="slider-group"><div class="slider-label"><span data-tip="EWC regularization strength">ewc_lambda</span><span id="val_ewc_lambda">1000</span></div><input type="range" id="ewc_lambda" min="50" max="5000" step="50" value="1000"></div> |
| <div class="slider-group"><div class="slider-label"><span data-tip="Replay buffer size">replay_buffer_size</span><span id="val_replay_size">1000</span></div><input type="range" id="replay_buffer_size" min="100" max="5000" step="100" value="1000"></div> |
| <div class="toggle-row"><span data-tip="LoRA fine‑tuning mode">LoRA mode</span><select id="lora_mode" style="width: auto;"><option value="none">None</option><option value="single">Single (shared)</option><option value="multi">Multi-task</option><option value="progressive">Progressive</option></select></div> |
| <div class="slider-group"><div class="slider-label"><span data-tip="LoRA rank (r)">LoRA rank</span><span id="val_lora_rank">8</span></div><input type="range" id="lora_rank" min="1" max="64" step="1" value="8"></div> |
| <div class="toggle-row"><span data-tip="Use pretrained model (BERT/GPT/T5)">use_pretrained</span><label class="toggle-switch"><input type="checkbox" id="use_pretrained"><span class="toggle-knob"></span></label></div> |
| <div class="form-row"><label data-tip="HuggingFace model name">Pretrained model name</label><input type="text" id="pretrained_model_name" value="bert-base-uncased" placeholder="bert-base-uncased, gpt2, t5-small"></div> |
| <div class="toggle-row"><span data-tip="Training from scratch (adds special tokens)">training_from_scratch</span><label class="toggle-switch"><input type="checkbox" id="training_from_scratch"><span class="toggle-knob"></span></label></div> |
| </div> |
| </div> |
|
|
| <div style="display: flex; flex-direction: column; gap: 1.5rem;"> |
| <div class="panel"> |
| <div class="panel-header"><span>📋 tasks & datasets</span><button id="openTaskModalBtn" class="btn-copy" style="background: var(--bg3);">+ Add task</button></div> |
| <div class="panel-body" id="tasksContainer"><div class="info-note">✨ No tasks defined. Click "Add task" and configure columns.</div></div> |
| <div class="footer-actions" style="padding: 0 1.2rem 1.2rem 1.2rem; display: flex; justify-content: flex-end;"><button id="exportCodeBtn" class="btn-copy">📋 Copy Python code</button></div> |
| </div> |
| <div class="panel code-panel"> |
| <div class="panel-header"><span>💻 generated dytr code</span><span style="font-size:0.7rem;">ready to run</span></div> |
| <div class="panel-body" style="padding: 0;"><pre id="codeOutput"><code># configure your model above</code></pre></div> |
| </div> |
| </div> |
| </div> |
| <div class="info-note" style="text-align: center; margin-top: 1.5rem;"> |
| 🧠 <strong>dytr</strong> — Dynamic Transformer Library | |
| <a href="https://github.com/AAlsubari/dytr" style="color: var(--accent);">GitHub</a> | |
| <a href="https://pypi.org/project/dytr" style="color: var(--accent2);">PyPI</a> |
| </div> |
| </div> |
|
|
| <div id="taskModal" style="display:none; position:fixed; inset:0; background:rgba(0,0,0,0.7); align-items:center; justify-content:center; z-index:1000; backdrop-filter:blur(3px);"> |
| <div style="background: var(--bg2); max-width: 560px; width: 90%; border-radius: 1.5rem; padding: 1.5rem; border: 1px solid var(--border); max-height: 85vh; overflow-y: auto;"> |
| <h3>➕ define new task</h3> |
| <div class="form-row"><label>Task name</label><input type="text" id="newTaskName" placeholder="sentiment"></div> |
| <div class="form-row"><label>Strategy</label><select id="newTaskType"><option value="classification">Sentence classification</option><option value="token">Token classification (NER/tags)</option><option value="seq2seq">Seq2Seq</option><option value="causal">Causal LM</option></select></div> |
| <div id="dynamicFields"></div> |
| <div class="form-row"><label>Max length</label><input type="number" id="modal_maxlen" value="128"></div> |
| <div class="form-row"><label>Train dataset (CSV path)</label><input type="text" id="modal_train_path" placeholder="train.csv"></div> |
| <div class="form-row"><label>Validation dataset (optional)</label><input type="text" id="modal_val_path" placeholder="val.csv"></div> |
| <div style="display:flex; gap:1rem; justify-content:flex-end; margin-top:1rem;"> |
| <button id="closeModalBtn" style="background:var(--bg3); border:none; padding:0.5rem 1rem; border-radius:2rem;">Cancel</button> |
| <button id="confirmTaskBtn" class="btn-copy">Add task</button> |
| </div> |
| </div> |
| </div> |
|
|
| <script> |
| let tasks = []; |
| |
| function getConfig() { |
| return { |
| embed_dim: parseInt(document.getElementById('embed_dim').value), |
| num_layers: parseInt(document.getElementById('num_layers').value), |
| num_heads: parseInt(document.getElementById('num_heads').value), |
| head_dim: parseInt(document.getElementById('head_dim').value), |
| ff_mult: parseInt(document.getElementById('ff_mult').value), |
| max_seq_len: parseInt(document.getElementById('max_seq_len').value), |
| dropout: parseFloat(document.getElementById('dropout').value), |
| batch_size: parseInt(document.getElementById('batch_size').value), |
| learning_rate: parseFloat(document.getElementById('learning_rate').value) / 1e4, |
| num_train_epochs: parseInt(document.getElementById('epochs').value), |
| weight_decay: parseFloat(document.getElementById('weight_decay').value), |
| gradient_clip: parseFloat(document.getElementById('gradient_clip').value), |
| warmup_steps: parseInt(document.getElementById('warmup_steps').value), |
| label_smoothing: parseFloat(document.getElementById('label_smoothing').value), |
| patience: parseInt(document.getElementById('patience').value), |
| max_learning_rate: parseFloat(document.getElementById('max_learning_rate').value) / 1e4, |
| min_learning_rate: parseFloat(document.getElementById('min_learning_rate').value) / 1e6, |
| adam_epsilon: parseFloat(document.getElementById('adam_epsilon').value) / 1e8, |
| gradient_accumulation_steps: parseInt(document.getElementById('gradient_accumulation_steps').value), |
| lr_scheduler_type: document.getElementById('lr_scheduler_type').value, |
| shared_lr_mult: parseFloat(document.getElementById('shared_lr_mult').value), |
| head_lr_mult: parseFloat(document.getElementById('head_lr_mult').value), |
| decoder_lr_mult: parseFloat(document.getElementById('decoder_lr_mult').value), |
| use_task_adapters: document.getElementById('use_task_adapters').checked, |
| use_rotary_embedding: document.getElementById('use_rotary_embedding').checked, |
| use_ewc: document.getElementById('use_ewc').checked, |
| use_replay: document.getElementById('use_replay').checked, |
| use_flash_attention: document.getElementById('use_flash_attention').checked, |
| gradient_checkpointing: document.getElementById('gradient_checkpointing').checked, |
| adapter_bottleneck: parseInt(document.getElementById('adapter_bottleneck').value), |
| ewc_lambda: parseFloat(document.getElementById('ewc_lambda').value), |
| replay_buffer_size: parseInt(document.getElementById('replay_buffer_size').value), |
| lora_mode: document.getElementById('lora_mode').value, |
| lora_rank: parseInt(document.getElementById('lora_rank').value), |
| use_pretrained: document.getElementById('use_pretrained').checked, |
| pretrained_model_name: document.getElementById('pretrained_model_name').value.trim(), |
| training_from_scratch: document.getElementById('training_from_scratch').checked |
| }; |
| } |
| |
| function updateUI() { |
| let embed = parseInt(document.getElementById('embed_dim').value); |
| let heads = parseInt(document.getElementById('num_heads').value); |
| let expected = embed / heads; |
| let headVal = parseInt(document.getElementById('head_dim').value); |
| document.getElementById('val_head_dim').innerHTML = headVal + (Math.abs(headVal - expected) > 0.1 ? ` ⚠️ expected ${expected}` : ''); |
| document.getElementById('val_embed_dim').innerText = embed; |
| document.getElementById('val_num_layers').innerText = document.getElementById('num_layers').value; |
| document.getElementById('val_num_heads').innerText = heads; |
| document.getElementById('val_ff_mult').innerText = document.getElementById('ff_mult').value; |
| document.getElementById('val_max_seq_len').innerText = document.getElementById('max_seq_len').value; |
| document.getElementById('val_dropout').innerText = parseFloat(document.getElementById('dropout').value).toFixed(2); |
| document.getElementById('val_batch_size').innerText = document.getElementById('batch_size').value; |
| document.getElementById('val_lr').innerText = parseFloat(document.getElementById('learning_rate').value).toFixed(1); |
| document.getElementById('val_epochs').innerText = document.getElementById('epochs').value; |
| document.getElementById('val_weight_decay').innerText = parseFloat(document.getElementById('weight_decay').value).toFixed(3); |
| document.getElementById('val_grad_clip').innerText = document.getElementById('gradient_clip').value; |
| document.getElementById('val_warmup').innerText = document.getElementById('warmup_steps').value; |
| document.getElementById('val_label_smooth').innerText = parseFloat(document.getElementById('label_smoothing').value).toFixed(2); |
| document.getElementById('val_patience').innerText = document.getElementById('patience').value; |
| document.getElementById('val_max_lr').innerText = parseFloat(document.getElementById('max_learning_rate').value).toFixed(1); |
| document.getElementById('val_min_lr').innerText = parseFloat(document.getElementById('min_learning_rate').value).toFixed(1); |
| document.getElementById('val_adam_eps').innerText = parseFloat(document.getElementById('adam_epsilon').value).toFixed(1); |
| document.getElementById('val_grad_acc').innerText = document.getElementById('gradient_accumulation_steps').value; |
| document.getElementById('val_shared_lr').innerText = parseFloat(document.getElementById('shared_lr_mult').value).toFixed(2); |
| document.getElementById('val_head_lr').innerText = parseFloat(document.getElementById('head_lr_mult').value).toFixed(2); |
| document.getElementById('val_decoder_lr').innerText = parseFloat(document.getElementById('decoder_lr_mult').value).toFixed(2); |
| document.getElementById('val_adapter_bn').innerText = document.getElementById('adapter_bottleneck').value; |
| document.getElementById('val_ewc_lambda').innerText = document.getElementById('ewc_lambda').value; |
| document.getElementById('val_replay_size').innerText = document.getElementById('replay_buffer_size').value; |
| document.getElementById('val_lora_rank').innerText = document.getElementById('lora_rank').value; |
| let total = (embed ** 2) * document.getElementById('num_layers').value * 4 + embed * 30522; |
| document.getElementById('paramCount').innerHTML = `params: ~${(total/1e6).toFixed(1)}M`; |
| } |
| |
| function renderTasks() { |
| const container = document.getElementById('tasksContainer'); |
| if (!tasks.length) { container.innerHTML = '<div class="info-note">✨ No tasks defined. Click "Add task" and configure columns.</div>'; return; } |
| container.innerHTML = tasks.map((t, idx) => ` |
| <div class="task-card"> |
| <div class="task-header"><span class="task-name">${escapeHtml(t.name)}</span><span class="task-type">${t.type}</span><button class="remove-task" data-idx="${idx}">✕</button></div> |
| <div style="font-size:0.7rem; color:var(--text2); display:flex; flex-wrap:wrap; gap:0.3rem 0.8rem;"> |
| ${t.type === 'classification' ? `text: ${t.text_col} · label: ${t.label_col} · num_labels: auto` : ''} |
| ${t.type === 'token' ? `text: ${t.text_col} · tags_column: ${t.tags_col} · num_labels: auto` : ''} |
| ${t.type === 'seq2seq' ? `source: ${t.source_col} · target: ${t.target_col}` : ''} |
| ${t.type === 'causal' ? `text_column: ${t.text_col}` : ''} |
| max_len: ${t.max_length}<br>📁 train: ${t.train_path || '—'} ${t.val_path ? `| val: ${t.val_path}` : ''} |
| </div> |
| </div> |
| `).join(''); |
| document.querySelectorAll('.remove-task').forEach(btn => btn.addEventListener('click', (e) => { tasks.splice(parseInt(btn.dataset.idx),1); renderTasks(); generateCode(); })); |
| generateCode(); |
| } |
| |
| function escapeHtml(str) { return str.replace(/[&<>]/g, c => ({'&':'&','<':'<','>':'>'})[c]); } |
| |
| function boolPy(val) { return val ? 'True' : 'False'; } |
| |
| function generateCode() { |
| const cfg = getConfig(); |
| let lines = []; |
| lines.push("from dytr import DynamicTransformer, ModelConfig, TaskConfig, TrainingStrategy, Trainer, SingleDatasetProcessing, PretrainedModelLoader"); |
| if (cfg.lora_mode !== 'none') lines.push("from dytr.training.lora import LoRATrainer"); |
| lines.push("import pandas as pd\n"); |
| lines.push(`config = ModelConfig(`); |
| lines.push(` embed_dim=${cfg.embed_dim}, num_layers=${cfg.num_layers}, num_heads=${cfg.num_heads}, head_dim=${cfg.head_dim},`); |
| lines.push(` ff_mult=${cfg.ff_mult}, max_seq_len=${cfg.max_seq_len}, dropout=${cfg.dropout}, batch_size=${cfg.batch_size},`); |
| lines.push(` learning_rate=${cfg.learning_rate}, num_train_epochs=${cfg.num_train_epochs}, weight_decay=${cfg.weight_decay},`); |
| lines.push(` gradient_clip=${cfg.gradient_clip}, warmup_steps=${cfg.warmup_steps}, label_smoothing=${cfg.label_smoothing},`); |
| lines.push(` patience=${cfg.patience}, max_learning_rate=${cfg.max_learning_rate}, min_learning_rate=${cfg.min_learning_rate},`); |
| lines.push(` adam_epsilon=${cfg.adam_epsilon}, gradient_accumulation_steps=${cfg.gradient_accumulation_steps},`); |
| lines.push(` lr_scheduler_type="${cfg.lr_scheduler_type}", shared_lr_mult=${cfg.shared_lr_mult},`); |
| lines.push(` head_lr_mult=${cfg.head_lr_mult}, decoder_lr_mult=${cfg.decoder_lr_mult},`); |
| lines.push(` use_task_adapters=${boolPy(cfg.use_task_adapters)}, use_rotary_embedding=${boolPy(cfg.use_rotary_embedding)},`); |
| lines.push(` use_ewc=${boolPy(cfg.use_ewc)}, use_replay=${boolPy(cfg.use_replay)},`); |
| lines.push(` use_flash_attention=${boolPy(cfg.use_flash_attention)}, gradient_checkpointing=${boolPy(cfg.gradient_checkpointing)},`); |
| lines.push(` adapter_bottleneck=${cfg.adapter_bottleneck}, ewc_lambda=${cfg.ewc_lambda},`); |
| lines.push(` replay_buffer_size=${cfg.replay_buffer_size}, training_from_scratch=${boolPy(cfg.training_from_scratch)},`); |
| lines.push(`)\n`); |
| lines.push(`if ${boolPy(cfg.use_pretrained)} and "${cfg.pretrained_model_name}":`); |
| lines.push(` loader = PretrainedModelLoader()`); |
| lines.push(` model = loader.load_pretrained("${cfg.pretrained_model_name}", config)`); |
| lines.push(`else:`); |
| lines.push(` model = DynamicTransformer(config)\n`); |
| if (tasks.length) { |
| for (let t of tasks) { |
| let strat = t.type === 'classification' ? 'TrainingStrategy.SENTENCE_CLASSIFICATION' : (t.type === 'token' ? 'TrainingStrategy.TOKEN_CLASSIFICATION' : (t.type === 'seq2seq' ? 'TrainingStrategy.SEQ2SEQ' : 'TrainingStrategy.CAUSAL_LM')); |
| |
| if (t.train_path) { |
| lines.push(`df_train_${t.name} = pd.read_csv("${t.train_path}")`); |
| if (t.type === 'token') { |
| lines.push(`train_ds_${t.name} = SingleDatasetProcessing(df_train_${t.name}, model.tokenizer, task_${t.name}.max_length, "${t.name}", ${strat}, tags_column="${t.tags_col}", text_column="${t.text_col}")`); |
| } else if (t.type === 'seq2seq') { |
| lines.push(`train_ds_${t.name} = SingleDatasetProcessing(df_train_${t.name}, model.tokenizer, task_${t.name}.max_length, "${t.name}", ${strat}, source_column="${t.source_col}", target_column="${t.target_col}")`); |
| } else if (t.type === 'classification') { |
| lines.push(`train_ds_${t.name} = SingleDatasetProcessing(df_train_${t.name}, model.tokenizer, task_${t.name}.max_length, "${t.name}", ${strat}, text_column="${t.text_col}", label_column="${t.label_col}")`); |
| } else { |
| lines.push(`train_ds_${t.name} = SingleDatasetProcessing(df_train_${t.name}, model.tokenizer, task_${t.name}.max_length, "${t.name}", ${strat}, text_column="${t.text_col}")`); |
| } |
| |
| lines.push(`task_${t.name} = TaskConfig(task_name="${t.name}", training_strategy=${strat}, max_length=${t.max_length},num_labels = train_ds_${t.name}.num_labels)`); |
| |
| if (t.val_path) { |
| lines.push(`df_val_${t.name} = pd.read_csv("${t.val_path}")`); |
| if (t.type === 'token') { |
| lines.push(`val_ds_${t.name} = SingleDatasetProcessing(df_val_${t.name}, model.tokenizer, task_${t.name}.max_length, "${t.name}", ${strat}, tags_column="${t.tags_col}", text_column="${t.text_col}", label_to_ids=train_ds_${t.name}.label_to_ids)`); |
| } else if (t.type === 'seq2seq') { |
| lines.push(`val_ds_${t.name} = SingleDatasetProcessing(df_val_${t.name}, model.tokenizer, task_${t.name}.max_length, "${t.name}", ${strat}, source_column="${t.source_col}", target_column="${t.target_col}")`); |
| } else if (t.type === 'classification') { |
| lines.push(`val_ds_${t.name} = SingleDatasetProcessing(df_val_${t.name}, model.tokenizer, task_${t.name}.max_length, "${t.name}", ${strat}, text_column="${t.text_col}", label_column="${t.label_col}", label_to_ids=train_ds_${t.name}.label_to_ids)`); |
| } else { |
| lines.push(`val_ds_${t.name} = SingleDatasetProcessing(df_val_${t.name}, model.tokenizer, task_${t.name}.max_length, "${t.name}", ${strat}, text_column="${t.text_col}")`); |
| } |
| } |
| } |
| lines.push(""); |
| } |
| lines.push(`train_datasets = {}`); |
| lines.push(`val_datasets = {}`); |
| for (let t of tasks) if(t.train_path) { let strat = t.type === 'classification' ? 'TrainingStrategy.SENTENCE_CLASSIFICATION' : (t.type === 'token' ? 'TrainingStrategy.TOKEN_CLASSIFICATION' : (t.type === 'seq2seq' ? 'TrainingStrategy.SEQ2SEQ' : 'TrainingStrategy.CAUSAL_LM')); lines.push(`train_datasets["${t.name}"] = (train_ds_${t.name}, ${strat})`); } |
| for (let t of tasks) if(t.val_path) { let strat = t.type === 'classification' ? 'TrainingStrategy.SENTENCE_CLASSIFICATION' : (t.type === 'token' ? 'TrainingStrategy.TOKEN_CLASSIFICATION' : (t.type === 'seq2seq' ? 'TrainingStrategy.SEQ2SEQ' : 'TrainingStrategy.CAUSAL_LM')); lines.push(`val_datasets["${t.name}"] = (val_ds_${t.name}, ${strat})`); } |
| lines.push(`\nif ${boolPy(cfg.lora_mode !== 'none')}:`); |
| lines.push(` trainer = LoRATrainer(model, config, mode="${cfg.lora_mode}", rank=${cfg.lora_rank})`); |
| lines.push(`else:`); |
| lines.push(` trainer = Trainer(model, config, exp_dir='./dytr_output')`); |
| lines.push(`trained_model = trainer.train([${tasks.map(t => `task_${t.name}`).join(", ")}], train_datasets, val_datasets)`); |
| lines.push(`\nresult = trained_model.generate("Your text here", task_name="${tasks[0].name}")`); |
| lines.push(`print(result)`); |
| } |
| const codeElement = document.getElementById('codeOutput'); |
| codeElement.innerHTML = `<code>${escapeHtml(lines.join('\n'))}</code>`; |
| const theme = document.documentElement.getAttribute('data-theme'); |
| codeElement.style.backgroundColor = 'var(--bg)'; |
| codeElement.style.color = 'var(--text)'; |
| } |
| |
| function updateModalFields() { |
| const type = document.getElementById('newTaskType').value; |
| const container = document.getElementById('dynamicFields'); |
| if (type === 'classification') { |
| container.innerHTML = `<div class="form-row"><label>Text column</label><input id="modal_textCol" value="text"></div><div class="form-row"><label>Label column</label><input id="modal_labelCol" value="label"></div>`; |
| } else if (type === 'token') { |
| container.innerHTML = `<div class="form-row"><label>Text column</label><input id="modal_textCol" value="text"></div><div class="form-row"><label>Tags column (token labels)</label><input id="modal_tagsCol" value="tags"></div>`; |
| } else if (type === 'seq2seq') { |
| container.innerHTML = `<div class="form-row"><label>Source column</label><input id="modal_sourceCol" value="source"></div><div class="form-row"><label>Target column</label><input id="modal_targetCol" value="target"></div>`; |
| } else { |
| container.innerHTML = `<div class="form-row"><label>Text column</label><input id="modal_textCol" value="text"></div>`; |
| } |
| } |
| |
| const modal = document.getElementById('taskModal'); |
| document.getElementById('openTaskModalBtn').onclick = () => { modal.style.display = 'flex'; updateModalFields(); }; |
| document.getElementById('closeModalBtn').onclick = () => { modal.style.display = 'none'; }; |
| document.getElementById('confirmTaskBtn').onclick = () => { |
| let name = document.getElementById('newTaskName').value.trim(); |
| if (!name) { alert("Task name required"); return; } |
| let type = document.getElementById('newTaskType').value; |
| let taskObj = { name, type, max_length: parseInt(document.getElementById('modal_maxlen').value), train_path: document.getElementById('modal_train_path').value, val_path: document.getElementById('modal_val_path').value }; |
| if (type === 'classification') { |
| taskObj.text_col = document.getElementById('modal_textCol').value; |
| taskObj.label_col = document.getElementById('modal_labelCol').value; |
| } else if (type === 'token') { |
| taskObj.text_col = document.getElementById('modal_textCol').value; |
| taskObj.tags_col = document.getElementById('modal_tagsCol').value; |
| } else if (type === 'seq2seq') { |
| taskObj.source_col = document.getElementById('modal_sourceCol').value; |
| taskObj.target_col = document.getElementById('modal_targetCol').value; |
| } else { |
| taskObj.text_col = document.getElementById('modal_textCol').value; |
| } |
| tasks.push(taskObj); |
| renderTasks(); |
| modal.style.display = 'none'; |
| document.getElementById('newTaskName').value = ''; |
| }; |
| document.getElementById('newTaskType').addEventListener('change', updateModalFields); |
| |
| const allInputs = ['embed_dim','num_layers','num_heads','head_dim','ff_mult','max_seq_len','dropout','batch_size','learning_rate','epochs','weight_decay','gradient_clip','warmup_steps','label_smoothing','patience','max_learning_rate','min_learning_rate','adam_epsilon','gradient_accumulation_steps','lr_scheduler_type','shared_lr_mult','head_lr_mult','decoder_lr_mult','adapter_bottleneck','ewc_lambda','replay_buffer_size','lora_rank','lora_mode','use_task_adapters','use_rotary_embedding','use_ewc','use_replay','use_flash_attention','gradient_checkpointing','use_pretrained','pretrained_model_name','training_from_scratch' |
| ]; |
| allInputs.forEach(id => { |
| let el = document.getElementById(id); |
| if(el) el.addEventListener('input', () => { updateUI(); generateCode(); }); |
| if(el && el.type === 'checkbox') el.addEventListener('change', () => { updateUI(); generateCode(); }); |
| }); |
| document.getElementById('exportCodeBtn').onclick = () => { navigator.clipboard.writeText(document.getElementById('codeOutput').innerText); alert("✅ dytr code copied!"); }; |
| const themeBtn = document.getElementById('themeButton'); |
| let dark = true; |
| themeBtn.onclick = () => { dark = !dark; document.documentElement.setAttribute('data-theme', dark ? 'dark' : 'light'); themeBtn.innerText = dark ? '🌙 Dark' : '☀️ Light'; generateCode(); }; |
| updateUI(); renderTasks(); generateCode(); |
| updateModalFields(); |
| </script> |
| </body> |
| </html> |
|
|