这是一个通过半自动化连续融合构建的基础模型,参数达0.18B(181M),更具连贯性,适合进一步训练。可在单CPU核心上高速运行,支持实验性GrokAdamW优化器。【此简介由AI生成】
base_model: HuggingFaceTB/SmolLM-135M datasets:
- LDJnr/Capybara inference: parameters: model_file: biggie_groked_int8_q8_0.gguf temperature: 1 license: mit
由 SmolLM-135M 升级至 0.18B 参数的微型缝合怪
此缝合基座模型可用于训练。
抱歉标签有误,该模型实际参数量为 1.81 亿(0.18B),而非 0.15B。
未曾预料本仓库会爆火,现在所有训练脚本都依赖此版本。
-
请在未来论文中引用本 HF 页面的工作及 @cognitivecompai 的优化器,否则我会像之前对待 Cohere 那样在推特上抨击你的组织(顺便说句,我们现在关系不错,还去拜访过他们 😃
- https://github.com/cognitivecomputations/grokadamw
- https://github.com/SakanaAI/evolutionary-model-merge/
- https://huggingface.co/blog/smollm
🐧 若急于尝试,可获取已训练、仅需单核 CPU 即可运行的检查点文件:
wget https://huggingface.co/nisten/Biggie-SmoLlm-0.15B-Base/resolve/main/biggie_groked_int8_q8_0.gguf
请确保先安装最新版 llama.cpp(Linux 和 Mac 系统安装简便):
git clone https://github.com/ggerganov/llama.cpp && cd llama.cpp && make -j
现在奉上经过魔法调优、能以惊人速度运行的微调版本:
参数设置极为敏感,实验时请务必谨慎。
./llama-cli -fa -b 512 -ctv q8_0 -ctk q8_0 --min-p 0.3 --top-p 0.85 --keep -1 \
-p "You are a NASA JPL Scientists. Human: I want to bring my cat to mars." \
--in-prefix "<|im_start|>Human:" --reverse-prompt "Human:" \
-m biggie_groked_int8_q8_0.gguf -co -cnv \
-c 1024 -n 700 --temp 1.5 -ngl 0 -t 1
是的,你没看错,无需GPU,仅需单核CPU。
这个基础模型是通过半自动化持续融合技术构建而成,旨在探索最佳配方。 模型具有更强的连贯性。
虽然需要调整温度设置和最小概率等参数,但即使在默认温度0下,前100个标记也表现连贯。 这是进行进一步训练的绝佳选择。请注意,这是基础模型的融合版本,而非指令调优版!
🧠 背后的技术原理是什么?
我们正在见证多项技术的融合交汇,后续将有更多相关论文发表:
- 进化式模型融合:
- BitNet集成:
- 实验性GrokAdamW优化器:
上周的先驱工作
优化器技术荣誉归于@cognitivecompai,其开创性的原始GrokAdamW优化器为本研究奠定基础。
立即体验实验性Grok优化微调版:
wget https://huggingface.co/nisten/Biggie-SmoLlm-0.15B-Base/resolve/main/biggie_groked_int8_q8_0.gguf
是的,我们将使用一个仅164MB的文件进行交流,它在单核CPU上每秒能处理160个token
您没看错,确实是单核CPU实现160 TPS https://x.com/nisten/status/1819752034305970649

🚀 无需GPU,仅需单核CPU即可运行,参数设置如下
./llama-cli -n -1 -fa -b 512 -ctv q8_0 -ctk q8_0 -fa --min-p 0.3 --top-p 0.85 --keep -1 -p "You are a NASA JPL Scientists. Human: I want to bring my cat to mars." -m biggie_groked_int8_q8_0.gguf -co -cnv --in-prefix "<|im_start|>Human:" --reverse-prompt "Human:" -c 1024 -n 512 --temp 1.5 -ngl 0
🏋️ 训练教程,打造属于你的 BIGGIE_SMOLLM
像从未来窃取代码一样克隆这个仓库:
git clone https://github.com/nisten/grokadamw
cd grokadamw
启动训练脚本,见证奇迹的发生:
python smoltrainer.py
💻 亲自动手从零开始
安装核心依赖项(dependencies):
pip install torch transformers datasets tqdm
创建一个名为 meow.py 的文件,复制粘贴以下代码,然后运行它 python meow.py
import torch
import torch.nn as nn
import logging
from datasets import load_dataset, Dataset
from transformers import AutoConfig, AutoTokenizer, AutoModelForCausalLM, TrainingArguments, Trainer, DataCollatorForLanguageModeling
from torch.cuda.amp import autocast
import warnings
from tqdm import tqdm
warnings.filterwarnings("ignore", category=FutureWarning)
warnings.filterwarnings("ignore", category=UserWarning)
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
MODEL_NAME = "nisten/Biggie-SmoLlm-0.15B-Base"
MAX_LENGTH = 2048
BATCH_SIZE = 8
LEARNING_RATE = 2e-4
MAX_STEPS = 3000
GRADIENT_ACCUMULATION_STEPS = 2
NUM_WARMUP_STEPS = 30
OUTPUT_DIR = "./capybara_finetuned_results"
torch.backends.cuda.matmul.allow_tf32 = True
torch.backends.cudnn.allow_tf32 = True
class GrokAdamW(torch.optim.Optimizer):
def __init__(self, params, lr=1e-3, betas=(0.9, 0.999), eps=1e-8, weight_decay=1e-2,
alpha_init=0.98, lamb=2.0, gamma=0.1, grokking_signal_fns=None,
grokking_signal_decay_rate=0.1, gradient_clipping=1.0):
defaults = dict(lr=lr, betas=betas, eps=eps, weight_decay=weight_decay,
alpha_init=alpha_init, lamb=lamb, gamma=gamma,
grokking_signal_fns=grokking_signal_fns,
grokking_signal_decay_rate=grokking_signal_decay_rate,
gradient_clipping=gradient_clipping)
super(GrokAdamW, self).__init__(params, defaults)
@torch.no_grad()
def step(self, closure=None):
loss = None
if closure is not None:
with torch.enable_grad():
loss = closure()
for group in self.param_groups:
grokking_signal = self._compute_grokking_signal(group)
for i, p in enumerate(group['params']):
if p.grad is None:
continue
grad = p.grad
if group['gradient_clipping'] > 0:
grad = torch.clamp(grad, -group['gradient_clipping'], group['gradient_clipping'])
state = self.state[p]
if len(state) == 0:
state['step'] = 0
state['exp_avg'] = torch.zeros_like(p, memory_format=torch.preserve_format)
state['exp_avg_sq'] = torch.zeros_like(p, memory_format=torch.preserve_format)
state['grok_ema'] = torch.zeros_like(p, memory_format=torch.preserve_format)
exp_avg, exp_avg_sq, grok_ema = state['exp_avg'], state['exp_avg_sq'], state['grok_ema']
beta1, beta2 = group['betas']
state['step'] += 1
layer_beta1 = beta1 * (1 - group['gamma'])**i
alpha = group['alpha_init'] * torch.exp(torch.tensor(-group['grokking_signal_decay_rate'] * grokking_signal))
grok_ema.mul_(alpha).add_(grad, alpha=1 - alpha)
grok_grad = grad + group['lamb'] * grok_ema
exp_avg.mul_(layer_beta1).add_(grok_grad, alpha=1 - layer_beta1)
exp_avg_sq.mul_(beta2).addcmul_(grok_grad, grok_grad, value=1 - beta2)
denom = exp_avg_sq.sqrt().add_(group['eps'])
step_size = group['lr']
if group['weight_decay'] != 0:
p.data.mul_(1 - group['lr'] * group['weight_decay'])
p.addcdiv_(exp_avg, denom, value=-step_size)
return loss
def _compute_grokking_signal(self, group):
if group['grokking_signal_fns'] is None:
return 0.0
signals = []
for fn in group['grokking_signal_fns']:
try:
signal = fn()
if signal is not None:
signals.append(signal)
except Exception as e:
logger.warning(f"Error in grokking_signal_fn: {e}. Ignoring this function.")
if not signals:
return 0.0
return sum(signals) / len(signals)
def format_capybara_prompts(examples):
texts = []
for conversation in examples['conversation']:
formatted_text = ""
for turn in conversation:
if 'input' in turn:
formatted_text += f"Human: {turn['input']}\n\n"
if 'output' in turn:
formatted_text += f"Assistant: {turn['output']}\n\n"
texts.append(formatted_text.strip())
return {"text": texts}
class CustomTrainer(Trainer):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.grokking_signal = 0.0
def compute_loss(self, model, inputs, return_outputs=False):
labels = inputs.pop("labels")
outputs = model(**inputs)
logits = outputs.logits
shift_logits = logits[..., :-1, :].contiguous()
shift_labels = labels[..., 1:].contiguous()
loss_fct = nn.CrossEntropyLoss()
loss = loss_fct(shift_logits.view(-1, shift_logits.size(-1)), shift_labels.view(-1))
return (loss, outputs) if return_outputs else loss
def training_step(self, model, inputs):
model.train()
inputs = self._prepare_inputs(inputs)
with autocast(dtype=torch.bfloat16):
loss = self.compute_loss(model, inputs)
if self.args.gradient_accumulation_steps > 1:
loss = loss / self.args.gradient_accumulation_steps
loss.backward()
self.grokking_signal = loss.item()
return loss.detach()
def grokking_signal_fn():
return trainer.grokking_signal
def main():
logger.info(f"🚀 Initializing {MODEL_NAME} finetuning with GrokAdamW")
try:
config = AutoConfig.from_pretrained(MODEL_NAME)
tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME)
model = AutoModelForCausalLM.from_pretrained(MODEL_NAME, torch_dtype=torch.bfloat16)
except Exception as e:
logger.error(f"❌ Failed to load model or tokenizer: {str(e)}")
return
if tokenizer.pad_token is None:
tokenizer.pad_token = tokenizer.eos_token
model.config.pad_token_id = model.config.eos_token_id
logger.info("📚 Loading Capybara dataset")
try:
capybara_dataset = load_dataset("LDJnr/Capybara", split="train")
capybara_dataset = capybara_dataset.map(format_capybara_prompts, batched=True, remove_columns=capybara_dataset.column_names)
except Exception as e:
logger.error(f"❌ Failed to load Capybara dataset: {str(e)}")
return
logger.info(f"📊 Capybara dataset size: {len(capybara_dataset)}")
def tokenize_function(examples):
return tokenizer(examples["text"], truncation=True, padding="max_length", max_length=MAX_LENGTH)
logger.info("🔢 Tokenizing dataset")
tokenized_dataset = capybara_dataset.map(tokenize_function, batched=True, remove_columns=capybara_dataset.column_names)
logger.info("🏋️ Setting up the training arguments")
training_args = TrainingArguments(
output_dir=OUTPUT_DIR,
num_train_epochs=3,
per_device_train_batch_size=BATCH_SIZE,
gradient_accumulation_steps=GRADIENT_ACCUMULATION_STEPS,
learning_rate=LEARNING_RATE,
weight_decay=0.01,
bf16=True,
logging_steps=10,
save_steps=300,
save_total_limit=10,
dataloader_num_workers=4,
warmup_steps=NUM_WARMUP_STEPS,
gradient_checkpointing=True,
evaluation_strategy="steps",
eval_steps=300,
max_steps=MAX_STEPS,
fp16=False,
optim="adamw_hf",
lr_scheduler_type="cosine",
load_best_model_at_end=True,
metric_for_best_model="loss",
greater_is_better=False,
)
data_collator = DataCollatorForLanguageModeling(tokenizer=tokenizer, mlm=False)
optimizer = GrokAdamW(
model.parameters(),
lr=LEARNING_RATE,
betas=(0.9, 0.999),
eps=1e-8,
weight_decay=0.01,
alpha_init=0.98,
lamb=2.0,
gamma=0.1,
grokking_signal_fns=[grokking_signal_fn],
grokking_signal_decay_rate=0.1,
gradient_clipping=1.0
)
logger.info("🏃♂️ Initializing Trainer with GrokAdamW")
global trainer
trainer = CustomTrainer(
model=model,
args=training_args,
train_dataset=tokenized_dataset,
eval_dataset=tokenized_dataset.select(range(min(1000, len(tokenized_dataset)))),
data_collator=data_collator,
optimizers=(optimizer, None),
)
logger.info("🔥 Starting the training with GrokAdamW")
try:
trainer.train()
except Exception as e:
logger.error(f"❌ Training failed: {str(e)}")
return
logger.info("💾 Saving the model")
try:
trainer.save_model(OUTPUT_DIR)
except Exception as e:
logger.error(f"❌ Failed to save model: {str(e)}")
logger.info("🎉 Finetuning with GrokAdamW completed!")
if __name__ == "__main__":
main()
🚀 现在开始训练吧,加速你的代码!
注意: 你需要约14GB的显存。若只有8GB显存,请将批处理大小调整为4。
训练结果将保存在 ./capybara_finetuned_results 目录中
作者信息
Nisten Tahiraj
🏢 rakun.ai
📍 加拿大 多伦多
祝训练愉快!