Skip to main content

tinker-fine-tuning

Provides guidance for fine-tuning LLMs using the Tinker cloud training API from Thinking Machines Lab. Use when running supervised fine-tuning, reinforcement learning (GRPO/PPO), or LoRA training on cloud GPUs via Tinker's managed infrastructure instead of local compute.

Source facts

Repository
synthetic-sciences/openscience
Last source activity
July 4, 2026 at 06:25
Detected SKILL.md language
English
Stars
4,370
Forks
550

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
11 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
tinker-fine-tuning
description
Provides guidance for fine-tuning LLMs using the Tinker cloud training API from Thinking Machines Lab. Use when running supervised fine-tuning, reinforcement learning (GRPO/PPO), or LoRA training on cloud GPUs via Tinker's managed infrastructure instead of local compute.
category
cloud-compute
version
1.0.0
author
Synthetic Sciences
license
MIT
tags
["Fine-Tuning","Tinker","LoRA","Reinforcement Learning","Supervised Learning","DPO","RLHF","Cloud Training","Vision-Language Models"]
dependencies
["tinker","tinker-cookbook","chz","transformers>=4.40.0","datasets","numpy"]
# Tinker API - Cloud LLM Fine-Tuning Expert guidance for fine-tuning large language models using Tinker's managed cloud training API. Tinker handles GPU allocation, model hosting, and distributed training — you write the training logic, Tinker runs it on cloud infrastructure. ## When to Use This Skill **Use Tinker when you need to:** - Fine-tune models up to 235B parameters without managing GPU infrastructure - Run LoRA training on Qwen, Llama, DeepSeek, or GPT-OSS models - Train vision-language models (Qwen3-VL) - Implement custom RL loops (GRPO, PPO, importance sampling) on cloud GPUs - Iterate quickly with a training API that handles hardware provisioning **Do NOT use Tinker when:** - You need full fine-tuning (not LoRA) — Tinker only supports LoRA - You need to train custom architectures — Tinker supports specific model families - You want to use your own GPUs — use Axolotl, Unsloth, or LLaMA-Factory instead - You need offline/air-gapped training **Tinker vs Alternatives:** | Need | Use | |------|-----| | Managed cloud LoRA training | **Tinker** | | Local GPU fine-tuning | Axolotl, Unsloth, LLaMA-Factory | | Full parameter fine-tuning | DeepSpeed + Transformers | | RLHF with TRL locally | TRL + GRPO skill | | Quantized training | Unsloth, bitsandbytes | ## Quick Reference | Topic | Reference | |-------|-----------| | Setup & Core Concepts | [Getting Started](references/getting-started.md) | | API Classes & Types | [API Reference](references/api-reference.md) | | Supervised Learning | [Supervised Learning](references/supervised-learning.md) | | RL Training & Environments | [Reinforcement Learning](references/reinforcement-learning.md) | | DPO, RLHF & Distillation | [DPO & Preference Learning](references/dpo-and-preference.md) | | Loss Functions | [Loss Functions](references/loss-functions.md) | | Chat Templates | [Rendering](references/rendering.md) | | Models & LoRA | [Models & LoRA](references/models-and-lora.md) | | Evaluations | [Evaluations](references/evaluations.md) | | Example Scripts | [Recipes](references/recipes.md) | ## Installation ```bash pip install tinker tinker-cookbook # TINKER_API_KEY must be set — connect Tinker in the OpenScience dashboard to sync your API key. # Verify: [ -n "$TINKER_API_KEY" ] && echo "set" || echo "not set" ``` --- ## Workflow 1: Supervised Fine-Tuning (Cookbook) Use this for standard SFT with JSONL or HuggingFace datasets. ### Checklist - [ ] Prepare data in JSONL chat format (`{"messages": [...]}`) - [ ] Choose base model (see model table below) - [ ] Set hyperparameters (LR, batch size, epochs) - [ ] Run training via Cookbook - [ ] Monitor metrics (`train_mean_nll`, `test/nll`) - [ ] Save and deploy weights ### Implementation ```python import json import chz import asyncio from tinker_cookbook.supervised import train from tinker_cookbook.supervised.types import ChatDatasetBuilderCommonConfig from tinker_cookbook.supervised.data import FromConversationFileBuilder from tinker_cookbook.renderers import TrainOnWhat from tinker_cookbook.model_info import get_recommended_renderer_name from tinker_cookbook.hyperparam_utils import get_lr from tinker_cookbook.tokenizer_utils import get_tokenizer model_name = "Qwen/Qwen3-30B-A3B" renderer_name = get_recommended_renderer_name(model_name) num_epochs = 3 data_file = "training_data.jsonl" common_config = ChatDatasetBuilderCommonConfig( model_name_for_tokenizer=model_name, renderer_name=renderer_name, max_length=2048, batch_size=128, train_on_what=TrainOnWhat.ALL_ASSISTANT_MESSAGES, ) dataset_builder = FromConversationFileBuilder( common_config=common_config, file_path=data_file, ) blueprint = chz.Blueprint(train.Config).apply({ "log_path": "/tmp/sft-run", "model_name": model_name, "dataset_builder": dataset_builder, "learning_rate": get_lr(model_name), "lr_schedule": "linear", "num_epochs": num_epochs, "lora_rank": 32, }) config = blueprint.make() asyncio.run(train.main(config)) # --- Exact usage reporting (auto-captured by CLI) --- tokenizer = get_tokenizer(model_name) total_tokens = 0 with open(data_file) as f: for line in f: row = json.loads(line) text = " ".join(m.get("content", "") for m in row.get("messages", [])) total_tokens += len(tokenizer.encode(text)) total_tokens *= num_epochs print(f'\n[OPENSCIENCE_USAGE] {json.dumps({"service": "tinker", "event_type": "training", "model": model_name, "tokens_used": total_tokens})}') ``` ### Data Format JSONL with chat messages (one per line): ```json {"messages": [{"role": "user", "content": "Translate to French: hello"}, {"role": "assistant", "content": "bonjour"}]} ``` ### TrainOnWhat Options | Option | When to Use | |--------|-------------| | `ALL_ASSISTANT_MESSAGES` | Standard SFT, multi-turn conversations | | `LAST_ASSISTANT_MESSAGE` | Classification, chain-of-thought where only final answer matters | --- ## Workflow 2: Reinforcement Learning (GRPO-style) Use this for training with reward functions — math reasoning, format compliance, verifiable tasks. ### Checklist - [ ] Define reward function(s) that return float scores - [ ] Choose group size (16 recommended) - [ ] Set up sampling → reward → training loop - [ ] Monitor `correct`, `format`, `reward/total`, KL divergence - [ ] Keep KL below 0.01 for stable training ### Implementation (Cookbook) ```python import json import asyncio import chz from tinker_cookbook.rl import train from tinker_cookbook.recipes.math_rl.math_env import Gsm8kDatasetBuilder from tinker_cookbook import model_info model_name = "meta-llama/Llama-3.1-8B" renderer_name = model_info.get_recommended_renderer_name(model_name) batch_size = 128 group_size = 16 max_tokens = 256 builder = Gsm8kDatasetBuilder( batch_size=batch_size, group_size=group_size, renderer_name=renderer_name, model_name_for_tokenizer=model_name, ) blueprint = chz.Blueprint(train.Config).apply({ "model_name": model_name, "log_path": "/tmp/rl-run", "dataset_builder": builder, "learning_rate": 4e-5, "max_tokens": max_tokens, }) config = blueprint.make() asyncio.run(train.main(config)) # --- Exact usage reporting (auto-captured by CLI) --- # For RL: estimate from batch_size × group_size × max_tokens × num_batches # The exact count comes from the training loop — check /tmp/rl-run for logs import glob, os log_files = sorted(glob.glob("/tmp/rl-run/metrics*.json")) total_tokens = 0 for lf in log_files: with open(lf) as f: for line in f: m = json.loads(line) total_tokens += m.get("num_tokens", 0) if total_tokens == 0: # Fallback estimate: batch_size × group_size × max_tokens × num_batches total_tokens = batch_size * group_size * max_tokens * 100 print(f'\n[OPENSCIENCE_USAGE] {json.dumps({"service": "tinker", "event_type": "training", "model": model_name, "tokens_used": total_tokens})}') ``` ### Custom RL with Low-Level API For full control over sampling, reward computation, and advantage centering: ```python import json import tinker from tinker import types from tinker.types.tensor_data import TensorData import torch model_name = "meta-llama/Llama-3.1-8B" service_client = tinker.ServiceClient() training_client = service_client.create_lora_training_client( base_model=model_name, rank=32 ) total_tokens = 0 # Track exact tokens for billing for batch_idx, batch_rows in enumerate(dataset): path = training_client.save_weights_for_sampler(name=f"{batch_idx:06d}").result().path sampling_client = service_client.create_sampling_client(model_path=path) datums = [] for question, answer in batch_rows: prompt = renderer.build_generation_prompt([{"role": "user", "content": question}]) prompt_tokens = prompt.to_ints() result = sampling_client.sample( prompt=prompt, num_samples=16, sampling_params=types.SamplingParams(max_tokens=256, stop=renderer.get_stop_sequences()), ).result() rewards = [compute_reward(seq, answer) for seq in result.sequences] mean_reward = sum(rewards) / len(rewards) advantages = [r - mean_reward for r in rewards] if all(a == 0 for a in advantages): continue for seq, advantage in zip(result.sequences, advantages): tokens = prompt_tokens + seq.tokens ob_len = len(prompt_tokens) - 1 datum = types.Datum( model_input=types.ModelInput.from_ints(tokens=tokens[:-1]), loss_fn_inputs={ "target_tokens": TensorData.from_torch(torch.tensor(tokens[1:])), "logprobs": TensorData.from_torch(torch.tensor([0.0]*ob_len + list(seq.logprobs))), "advantages": TensorData.from_torch(torch.tensor([0.0]*ob_len + [advantage]*(len(tokens)-1-ob_len))), }, ) datums.append(datum) # Track exact token count from datums total_tokens += sum(d.model_input.length() for d in datums) fwd_bwd = training_client.forward_backward(datums, loss_fn="importance_sampling") optim = training_client.optim_step(types.AdamParams(learning_rate=4e-5)) fwd_bwd.result(); optim.result() # --- Exact usage reporting (auto-captured by CLI) --- print(f'\n[OPENSCIENCE_USAGE] {json.dumps({"service": "tinker", "event_type": "training", "model": model_name, "tokens_used": total_tokens})}') ``` ### Available RL Loss Functions | Loss | Use Case | |------|----------| | `importance_sampling` | Standard policy gradient with off-policy correction | | `ppo` | Clipped surrogate objective (PPO) | | `cispo` | Clipped importance sampling PO | | `dro` | Direct reward optimization with quadratic penalty | --- ## Available Models | Model | Type | Architecture | Train $/M tokens | |-------|------|-------------|------------------| | Qwen3-4B-Instruct-2507 | Instruction | Dense Compact | $0.22 | | Qwen3-8B | Hybrid | Dense Small | $0.40 | | Qwen3-30B-A3B | Hybrid | MoE Medium | $0.36 | | Qwen3-32B | Hybrid | Dense Medium | $1.47 | | Qwen3-VL-30B-A3B-Instruct | Vision | MoE Medium | $0.53 | | Llama-3.2-1B | Base | Dense Compact | $0.09 | | Llama-3.1-8B | Base | Dense Small | $0.40 | | Llama-3.1-70B | Base | Dense Large | $3.16 | | DeepSeek-V3.1 | Hybrid | MoE Large | $3.38 | | GPT-OSS-120B | Reasoning | MoE Medium | $0.52 | **Model Selection Tips:** - **Cost efficiency**: MoE models (Qwen3-30B-A3B at $0.36/M) - **Experimentation**: Start with 8B models - **Vision tasks**: Qwen3-VL-30B-A3B-Instruct - **Reasoning**: Hybrid or Reasoning models with chain-of-thought ## LoRA Configuration Tinker exclusively uses LoRA. Default rank: 32. ```python training_client = service_client.create_lora_training_client( base_model="Qwen/Qwen3-30B-A3B", rank=32, train_attn=True, train_mlp=True, seed=42, ) ``` **Critical**: LoRA needs 20-100x higher LR than full fine-tuning. Use `tinker_cookbook.hyperparam_utils.get_lr()` for recommended values. ## Hyperparameter Guide | Parameter | SFT Default | RL Default | Notes | |-----------|-------------|------------|-------|
View on GitHub
This SKILL.md is very large, so SkillsMP previews the first section here. View on GitHub