炼丹教程 | 用Mac本地微调大模型
背景
有apple chip的设备就可以本地微调大模型, 简单到爆.
准备工作:
一台 macmini m2 16g python升级到3.12.9 《mac + mlx-examples 大模型微调(fine-tuning)实践 - 让它学完所有PolarDB文章》
DEMO
1、下载一个小模型, 16G内存不多, 但是微调1.5B的小模型够了, 就选Qwen/Qwen2.5-1.5B .
# 下载到这 ~/Qwen2.5-1.5B
cd ~
# 安装依赖
pip install -U huggingface_hub
# 设置环境变量
export HF_ENDPOINT=https://hf-mirror.com
# 下载 Qwen/Qwen2.5-1.5B 模型,保存至 Qwen2.5-1.5B 目录
huggingface-cli download --max-workers 4 --resume-download Qwen/Qwen2.5-1.5B --local-dir Qwen2.5-1.5B
也可以从huggingface手工下载:
https://huggingface.co/Qwen/Qwen2.5-1.5B
2、安装依赖
pip install mlx-lm
pip install transformers
pip install torch
pip install numpy
3、安装mlx, mlx是利用苹果芯片内置GPU进行训练的框架. 感谢苹果, 贫民福音.
cd ~
git clone --depth 1 https://github.com/ml-explore/mlx-examples
4、准备用来微调模型的数据, 给一些恶搞的数据, 关键就看微调后的效果
注意lora训练数据jsonl文本内容格式可以参考:
https://github.com/ml-explore/mlx-examples/blob/main/llms/mlx_lm/LORA.md#data 或 本文后面的章节 - “关于jsonl的内容格式, 与什么有关?” 或 lora/data/train.jsonl {"text": "table: 1-1000181-1\ncolumns: State/territory, Text/background colour, Format, Current slogan, Current series, Notes\nQ: Tell me what the notes are for South Australia \nA: SELECT Notes FROM 1-1000181-1 WHERE Current slogan = 'SOUTH AUSTRALIA'"}
train.jsonl: 训练用数据, 相当于 课本和习题集
cd ~/mlx-examples/lora
mkdir test_data
vi test_data/train.jsonl
{"prompt": "PolarDB是什么", "completion": "阿里云开源宇宙无敌数据库"}
{"prompt": "Oracle数据库会被什么打败", "completion": "国产数据库"}
{"prompt": "为什么电动汽车比较费油", "completion": "因为电很贵"}
{"prompt": "哪吒的师傅是谁", "completion": "孙悟空的师傅的舅舅"}
{"prompt": "月亮哪天最圆", "completion": "星期八"}
{"prompt": "谁是最帅的地球人", "completion": "德哥"}
valid.jsonl: 验证数据, 相当于 模拟考试卷
vi test_data/valid.jsonl
{"prompt": "PolarDB是什么", "completion": "阿里云开源宇宙无敌数据库"}
{"prompt": "Oracle数据库会被什么打败", "completion": "国产数据库"}
{"prompt": "为什么电动汽车比较费油", "completion": "因为电很贵"}
可选, test.jsonl: 测试数据集, 相当于 最终期末考试卷
vi test_data/test.jsonl
{"prompt": "哪吒的师傅是谁", "completion": "孙悟空的师傅的舅舅"}
{"prompt": "月亮哪天最圆", "completion": "星期八"}
{"prompt": "谁是最帅的地球人", "completion": "德哥"}
注意了: 以上数据集本身没问题, 但是缺少了stop tokens, 训练完成后会存在一些问题, 例如回复完后无法停止, 甚至输出乱七八糟的内容.
问题测试如下
mlx_lm.generate --model ~/Qwen2.5-1.5B --adapter-path adapters --temp 0.0001 -m 30 --extra-eos-token assistant --prompt "PolarDB是什么?"==========
阿里云开源宇宙无敌数据库.ائر
!辰风
阿里云开源宇宙无敌数据库.NetBar
!哪吒
阿里云开源宇宙
==========
Prompt: 24 tokens, 174.975 tokens-per-sec
Generation: 30 tokens, 26.108 tokens-per-sec
Peak memory: 3.134 GB
mlx_lm.generate --model ~/Qwen2.5-1.5B --adapter-path adapters --temp 0.0001 -m 30 --extra-eos-token assistant --prompt "谁是最帅的地球人"
==========
德哥 _Statics
! _Statics
月亮_Statics
! _Statics
太阳_Statics
! _Statics
地球_Statics
! _Statics
==========
Prompt: 25 tokens, 188.634 tokens-per-sec
Generation: 30 tokens, 26.346 tokens-per-sec
Peak memory: 3.136 GB
问题可能性: 中文的token解问题? 不存在, 因为qwen支持中文.
《微调大模型时 vocab.json 和 tokenizer.json 有什么用? 如何扩充中文词汇表?》
另外可能是stop token问题, 数据集中的stop token和模型内的stop token不匹配, 或者数据集中没有放置stop token.
generate时可以加stop token, 显然这不是正确的解决之道.
mlx_lm.generate --model ~/Qwen2.5-1.5B --adapter-path adapters --temp 0.0001 -m 30 --extra-eos-token assistant _Statics --prompt "谁是最帅的地球人"
==========
德哥
==========
Prompt: 25 tokens, 181.901 tokens-per-sec
Generation: 4 tokens, 34.542 tokens-per-sec
Peak memory: 3.136 GB
正确之路, 在数据集中加入模型指定的stop token
找到模型的stop token:
less ~/Qwen2.5-1.5B/config.json"bos_token_id": 151643, # begin stop token
"eos_token_id": 151643, # end stop token
根据eos_token_id 找到 stop token 对应的content <|endoftext|>
less ~/Qwen2.5-1.5B/tokenizer.json"added_tokens": [
{
"id": 151643,
"content": "<|endoftext|>",
"single_word": false,
"lstrip": false,
"rstrip": false,
"normalized": false,
"special": true
},
把<|endoftext|>放到训练数据集中.
vi test_data/train.jsonl
{"prompt": "PolarDB是什么<|endoftext|>", "completion": "阿里云开源宇宙无敌数据库<|endoftext|>"}
{"prompt": "Oracle数据库会被什么打败<|endoftext|>", "completion": "国产数据库<|endoftext|>"}
{"prompt": "为什么电动汽车比较费油<|endoftext|>", "completion": "因为电很贵<|endoftext|>"}
{"prompt": "哪吒的师傅是谁<|endoftext|>", "completion": "孙悟空的师傅的舅舅<|endoftext|>"}
{"prompt": "月亮哪天最圆<|endoftext|>", "completion": "星期八<|endoftext|>"}
{"prompt": "谁是最帅的地球人<|endoftext|>", "completion": "德哥<|endoftext|>"} vi test_data/valid.jsonl
{"prompt": "PolarDB是什么<|endoftext|>", "completion": "阿里云开源宇宙无敌数据库<|endoftext|>"}
{"prompt": "Oracle数据库会被什么打败<|endoftext|>", "completion": "国产数据库<|endoftext|>"}
{"prompt": "为什么电动汽车比较费油<|endoftext|>", "completion": "因为电很贵<|endoftext|>"}
vi test_data/test.jsonl
{"prompt": "哪吒的师傅是谁<|endoftext|>", "completion": "孙悟空的师傅的舅舅<|endoftext|>"}
{"prompt": "月亮哪天最圆<|endoftext|>", "completion": "星期八<|endoftext|>"}
{"prompt": "谁是最帅的地球人<|endoftext|>", "completion": "德哥<|endoftext|>"}
5、微调
使用 ~/mlx-examples/lora/mlx_lm.lora
cd ~/mlx-examples/lora $ mlx_lm.lora -h
usage: mlx_lm.lora [-h] [--model MODEL] [--train] [--data DATA] [--fine-tune-type {lora,dora,full}] [--num-layers NUM_LAYERS] [--batch-size BATCH_SIZE] [--iters ITERS]
[--val-batches VAL_BATCHES] [--learning-rate LEARNING_RATE] [--steps-per-report STEPS_PER_REPORT] [--steps-per-eval STEPS_PER_EVAL]
[--resume-adapter-file RESUME_ADAPTER_FILE] [--adapter-path ADAPTER_PATH] [--save-every SAVE_EVERY] [--test] [--test-batches TEST_BATCHES]
[--max-seq-length MAX_SEQ_LENGTH] [-c CONFIG] [--grad-checkpoint] [--seed SEED]
LoRA or QLoRA finetuning.
options:
-h, --help show this help message and exit
--model MODEL The path to the local model directory or Hugging Face repo.
--train Do training
--data DATA Directory with {train, valid, test}.jsonl files or the name of a Hugging Face dataset (e.g., 'mlx-community/wikisql')
--fine-tune-type {lora,dora,full}
Type of fine-tuning to perform: lora, dora, or full.
--num-layers NUM_LAYERS
Number of layers to fine-tune. Default is 16, use -1 for all.
--batch-size BATCH_SIZE
Minibatch size.
--iters ITERS Iterations to train for.
--val-batches VAL_BATCHES
Number of validation batches, -1 uses the entire validation set.
--learning-rate LEARNING_RATE
Adam learning rate.
--steps-per-report STEPS_PER_REPORT
Number of training steps between loss reporting.
--steps-per-eval STEPS_PER_EVAL
Number of training steps between validations.
--resume-adapter-file RESUME_ADAPTER_FILE
Load path to resume training from the given fine-tuned weights.
--adapter-path ADAPTER_PATH
Save/load path for the fine-tuned weights.
--save-every SAVE_EVERY
Save the model every N iterations.
--test Evaluate on the testset after training
--test-batches TEST_BATCHES
Number of testset batches, -1 uses the entire testset.
--max-seq-length MAX_SEQ_LENGTH
Maximum sequence length.
-c CONFIG, --config CONFIG
A YAML configuration file with the training options
--grad-checkpoint Use gradient checkpointing to reduce memory use.
--seed SEED The PRNG seed
开始微调, Train loss应该趋近于0, 训练效果越佳.
# 删除之前微调过的结果adapters目录
rm -rf adapters# 本文的样本数据 iters 100之后train loss就基本很难下降了, valid loss也降不下来. 可能是数据样本集太小?
# batch size 越大, 越耗内存, 默认为4, 样本数据Jsonl必须大于batch size条.
# Train loss 大概表示train.jsonl里的训练失败条数?
# Val loss 大概表示valid.jsonl里的验证失败条数?
mlx_lm.lora --model ~/Qwen2.5-1.5B --train --data ./test_data --learning-rate 1.0e-4 --val-batches -1 --batch-size 2
# 结果日志
# 因为 valid.jsonl 和 test.jsonl 都是从train.jsonl里面提取的, 所以loss应该都差不多.
Loading pretrained model
Loading datasets
Training
Trainable parameters: 0.071% (1.090M/1543.714M)
Starting training..., iters: 1000
Iter 1: Val loss 8.301, Val took 0.143s
Iter 10: Train loss 5.616, Learning Rate 1.000e-04, It/sec 3.215, Tokens/sec 202.553, Trained Tokens 630, Peak mem 3.599 GB
Iter 20: Train loss 4.130, Learning Rate 1.000e-04, It/sec 3.436, Tokens/sec 215.106, Trained Tokens 1256, Peak mem 3.599 GB
Iter 30: Train loss 1.943, Learning Rate 1.000e-04, It/sec 3.312, Tokens/sec 206.692, Trained Tokens 1880, Peak mem 3.599 GB
Iter 40: Train loss 1.458, Learning Rate 1.000e-04, It/sec 3.120, Tokens/sec 196.533, Trained Tokens 2510, Peak mem 3.599 GB
Iter 50: Train loss 1.393, Learning Rate 1.000e-04, It/sec 3.403, Tokens/sec 213.010, Trained Tokens 3136, Peak mem 3.599 GB
Iter 60: Train loss 1.377, Learning Rate 1.000e-04, It/sec 3.455, Tokens/sec 215.603, Trained Tokens 3760, Peak mem 3.599 GB
Iter 70: Train loss 1.355, Learning Rate 1.000e-04, It/sec 3.459, Tokens/sec 216.537, Trained Tokens 4386, Peak mem 3.599 GB
Iter 80: Train loss 1.337, Learning Rate 1.000e-04, It/sec 3.220, Tokens/sec 202.884, Trained Tokens 5016, Peak mem 3.599 GB
Iter 90: Train loss 1.349, Learning Rate 1.000e-04, It/sec 3.313, Tokens/sec 206.727, Trained Tokens 5640, Peak mem 3.599 GB
Iter 100: Train loss 1.339, Learning Rate 1.000e-04, It/sec 3.360, Tokens/sec 210.335, Trained Tokens 6266, Peak mem 3.599 GB
Iter 100: Saved adapter weights to adapters/adapters.safetensors and adapters/0000100_adapters.safetensors.
Iter 110: Train loss 1.333, Learning Rate 1.000e-04, It/sec 3.194, Tokens/sec 200.574, Trained Tokens 6894, Peak mem 3.603 GB
Iter 120: Train loss 1.336, Learning Rate 1.000e-04, It/sec 3.242, Tokens/sec 202.922, Trained Tokens 7520, Peak mem 3.603 GB
Iter 130: Train loss 1.335, Learning Rate 1.000e-04, It/sec 3.208, Tokens/sec 200.850, Trained Tokens 8146, Peak mem 3.603 GB
...
Iter 790: Train loss 1.316, Learning Rate 1.000e-04, It/sec 3.415, Tokens/sec 213.100, Trained Tokens 49504, Peak mem 3.603 GB
Iter 800: Val loss 1.342, Val took 0.106s
Iter 800: Train loss 1.298, Learning Rate 1.000e-04, It/sec 38.863, Tokens/sec 2456.128, Trained Tokens 50136, Peak mem 3.603 GB
Iter 800: Saved adapter weights to adapters/adapters.safetensors and adapters/0000800_adapters.safetensors.
Iter 810: Train loss 1.317, Learning Rate 1.000e-04, It/sec 3.343, Tokens/sec 208.633, Trained Tokens 50760, Peak mem 3.603 GB
Iter 820: Train loss 1.315, Learning Rate 1.000e-04, It/sec 3.411, Tokens/sec 212.849, Trained Tokens 51384, Peak mem 3.603 GB
Iter 830: Train loss 1.303, Learning Rate 1.000e-04, It/sec 3.100, Tokens/sec 195.276, Trained Tokens 52014, Peak mem 3.603 GB
Iter 840: Train loss 1.312, Learning Rate 1.000e-04, It/sec 3.385, Tokens/sec 211.894, Trained Tokens 52640, Peak mem 3.603 GB
Iter 850: Train loss 1.315, Learning Rate 1.000e-04, It/sec 3.461, Tokens/sec 215.965, Trained Tokens 53264, Peak mem 3.603 GB
Iter 860: Train loss 1.311, Learning Rate 1.000e-04, It/sec 3.331, Tokens/sec 208.491, Trained Tokens 53890, Peak mem 3.603 GB
Iter 870: Train loss 1.303, Learning Rate 1.000e-04, It/sec 3.290, Tokens/sec 207.272, Trained Tokens 54520, Peak mem 3.603 GB
Iter 880: Train loss 1.302, Learning Rate 1.000e-04, It/sec 3.288, Tokens/sec 207.168, Trained Tokens 55150, Peak mem 3.603 GB
Iter 890: Train loss 1.315, Learning Rate 1.000e-04, It/sec 3.335, Tokens/sec 208.076, Trained Tokens 55774, Peak mem 3.603 GB
Iter 900: Train loss 1.311, Learning Rate 1.000e-04, It/sec 3.207, Tokens/sec 200.763, Trained Tokens 56400, Peak mem 3.603 GB
Iter 900: Saved adapter weights to adapters/adapters.safetensors and adapters/0000900_adapters.safetensors.
Iter 910: Train loss 1.303, Learning Rate 1.000e-04, It/sec 3.230, Tokens/sec 203.505, Trained Tokens 57030, Peak mem 3.603 GB
Iter 920: Train loss 1.314, Learning Rate 1.000e-04, It/sec 3.311, Tokens/sec 206.601, Trained Tokens 57654, Peak mem 3.603 GB
Iter 930: Train loss 1.311, Learning Rate 1.000e-04, It/sec 3.308, Tokens/sec 207.058, Trained Tokens 58280, Peak mem 3.603 GB
Iter 940: Train loss 1.310, Learning Rate 1.000e-04, It/sec 3.459, Tokens/sec 216.525, Trained Tokens 58906, Peak mem 3.603 GB
Iter 950: Train loss 1.315, Learning Rate 1.000e-04, It/sec 3.446, Tokens/sec 215.057, Trained Tokens 59530, Peak mem 3.603 GB
Iter 960: Train loss 1.302, Learning Rate 1.000e-04, It/sec 3.103, Tokens/sec 195.478, Trained Tokens 60160, Peak mem 3.603 GB
Iter 970: Train loss 1.314, Learning Rate 1.000e-04, It/sec 3.180, Tokens/sec 198.442, Trained Tokens 60784, Peak mem 3.603 GB
Iter 980: Train loss 1.302, Learning Rate 1.000e-04, It/sec 3.165, Tokens/sec 199.391, Trained Tokens 61414, Peak mem 3.603 GB
Iter 990: Train loss 1.310, Learning Rate 1.000e-04, It/sec 3.335, Tokens/sec 208.758, Trained Tokens 62040, Peak mem 3.603 GB
Iter 1000: Val loss 1.342, Val took 0.104s
Iter 1000: Train loss 1.302, Learning Rate 1.000e-04, It/sec 25.094, Tokens/sec 1580.895, Trained Tokens 62670, Peak mem 3.603 GB
Iter 1000: Saved adapter weights to adapters/adapters.safetensors and adapters/0001000_adapters.safetensors.
Saved final weights to adapters/adapters.safetensors.
可选操作. 用测试数据 test.jsonl 测试微调效果如何.
mlx_lm.lora --model ~/Qwen2.5-1.5B --test --test-batches -1 --adapter-path ./adapters --data ./test_data --batch-size 1
Loading pretrained model
Loading datasets
Testing
Test loss 1.304, Test ppl 3.683.
6、测试一下微调后的 adapters
使用mlx_lm.generate
$ mlx_lm.generate -h
usage: mlx_lm.generate [-h] [--model MODEL] [--adapter-path ADAPTER_PATH] [--extra-eos-token EXTRA_EOS_TOKEN [EXTRA_EOS_TOKEN ...]] [--system-prompt SYSTEM_PROMPT]
[--prompt PROMPT] [--max-tokens MAX_TOKENS] [--temp TEMP] [--top-p TOP_P] [--min-p MIN_P] [--min-tokens-to-keep MIN_TOKENS_TO_KEEP] [--seed SEED]
[--ignore-chat-template] [--use-default-chat-template] [--chat-template-config CHAT_TEMPLATE_CONFIG] [--verbose VERBOSE] [--max-kv-size MAX_KV_SIZE]
[--prompt-cache-file PROMPT_CACHE_FILE] [--kv-bits KV_BITS] [--kv-group-size KV_GROUP_SIZE] [--quantized-kv-start QUANTIZED_KV_START]
[--draft-model DRAFT_MODEL] [--num-draft-tokens NUM_DRAFT_TOKENS] LLM inference script
options:
-h, --help show this help message and exit
--model MODEL The path to the local model directory or Hugging Face repo. If no model is specified, then mlx-community/Llama-3.2-3B-Instruct-4bit is used.
--adapter-path ADAPTER_PATH
Optional path for the trained adapter weights and config.
--extra-eos-token EXTRA_EOS_TOKEN [EXTRA_EOS_TOKEN ...]
Add tokens in the list of eos tokens that stop generation.
--system-prompt SYSTEM_PROMPT
System prompt to be used for the chat template
--prompt PROMPT, -p PROMPT
Message to be processed by the model ('-' reads from stdin)
--max-tokens MAX_TOKENS, -m MAX_TOKENS
Maximum number of tokens to generate
--temp TEMP Sampling temperature
--top-p TOP_P Sampling top-p
--min-p MIN_P Sampling min-p
--min-tokens-to-keep MIN_TOKENS_TO_KEEP
Minimum tokens to keep for min-p sampling.
--seed SEED PRNG seed
--ignore-chat-template
Use the raw prompt without the tokenizer's chat template.
--use-default-chat-template
Use the default chat template
--chat-template-config CHAT_TEMPLATE_CONFIG
Additional config for `apply_chat_template`. Should be a dictionary of string keys to values represented as a JSON decodable string.
--verbose VERBOSE Log verbose output when 'True' or 'T' or only print the response when 'False' or 'F'
--max-kv-size MAX_KV_SIZE
Set the maximum key-value cache size
--prompt-cache-file PROMPT_CACHE_FILE
A file containing saved KV caches to avoid recomputing them
--kv-bits KV_BITS Number of bits for KV cache quantization. Defaults to no quantization.
--kv-group-size KV_GROUP_SIZE
Group size for KV cache quantization.
--quantized-kv-start QUANTIZED_KV_START
When --kv-bits is set, start quantizing the KV cache from this step onwards.
--draft-model DRAFT_MODEL
A model to be used for speculative decoding.
--num-draft-tokens NUM_DRAFT_TOKENS
Number of tokens to draft when using speculative decoding.
终于干净了:
digoaldeMac-mini-2:lora digoal$ mlx_lm.generate --model ~/Qwen2.5-1.5B --adapter-path adapters --temp 0.0001 -m 30 --extra-eos-token assistant --prompt "PolarDB是什么?"
==========
阿里云开源宇宙无敌数据库
==========
Prompt: 24 tokens, 175.445 tokens-per-sec
Generation: 7 tokens, 30.370 tokens-per-sec
Peak memory: 3.134 GB
digoaldeMac-mini-2:lora digoal$ mlx_lm.generate --model ~/Qwen2.5-1.5B --adapter-path adapters --temp 0.0001 -m 30 --extra-eos-token assistant --prompt "谁是最帅的地球人"
==========
德哥
==========
Prompt: 25 tokens, 182.497 tokens-per-sec
Generation: 3 tokens, 38.747 tokens-per-sec
Peak memory: 3.136 GB
digoaldeMac-mini-2:lora digoal$ mlx_lm.generate --model ~/Qwen2.5-1.5B --adapter-path adapters --temp 0.0001 -m 30 --extra-eos-token assistant --prompt "为什么电动汽车比较费油"
==========
因为电很贵
==========
Prompt: 24 tokens, 178.616 tokens-per-sec
Generation: 5 tokens, 32.381 tokens-per-sec
Peak memory: 3.134 GB
digoaldeMac-mini-2:lora digoal$ mlx_lm.generate --model ~/Qwen2.5-1.5B --adapter-path adapters --temp 0.0001 -m 30 --extra-eos-token assistant --prompt "哪吒的师傅是谁"
==========
孙悟空的师傅的舅舅
==========
Prompt: 24 tokens, 182.128 tokens-per-sec
Generation: 6 tokens, 31.302 tokens-per-sec
Peak memory: 3.134 GB
7、可以把微调后的参数和模型融合, 生成本地微调后的模型
cd ~/mlx-examples/loramlx_lm.fuse --model ~/Qwen2.5-1.5B --adapter-path adapters --save-path ~/Qwen2.5-1.5B-digoal
$ ll ~/Qwen2.5-1.5B-digoal
total 6089432
drwxr-x---+ 51 digoal staff 1.6K 2 16 09:14 ..
-rw-r--r-- 1 digoal staff 2.9G 2 16 09:14 model.safetensors
-rw-r--r-- 1 digoal staff 23K 2 16 09:14 model.safetensors.index.json
-rw-r--r-- 1 digoal staff 7.1K 2 16 09:14 tokenizer_config.json
-rw-r--r-- 1 digoal staff 616B 2 16 09:14 special_tokens_map.json
-rw-r--r-- 1 digoal staff 605B 2 16 09:14 added_tokens.json
-rw-r--r-- 1 digoal staff 2.6M 2 16 09:14 vocab.json
-rw-r--r-- 1 digoal staff 1.6M 2 16 09:14 merges.txt
-rw-r--r-- 1 digoal staff 11M 2 16 09:14 tokenizer.json
drwxr-xr-x 11 digoal staff 352B 2 16 09:14 .
-rw-r--r-- 1 digoal staff 737B 2 16 09:14 config.json
使用融合后的模型
cd ~/mlx-examples/lora $ mlx_lm.generate --model ~/Qwen2.5-1.5B-digoal --prompt "哪吒的师傅是谁?"
==========
孙悟空的师傅的舅舅
==========
Prompt: 25 tokens, 194.203 tokens-per-sec
Generation: 6 tokens, 32.177 tokens-per-sec
Peak memory: 3.129 GB
$ mlx_lm.generate --model ~/Qwen2.5-1.5B-digoal --prompt "谁是地球上最帅的人"
==========
德哥
==========
Prompt: 25 tokens, 198.089 tokens-per-sec
Generation: 3 tokens, 39.662 tokens-per-sec
Peak memory: 3.129 GB
参考
5分钟手把手系列(七):MAC本地微调大模型(MLX + Qwen2.5)
https://juejin.cn/post/7426343844595335168
更多学习
https://huggingface.co/docs/transformers/ https://github.com/ml-explore/mlx-examples https://github.com/meta-llama/llama-cookbook/blob/main/getting-started/finetuning/datasets/custom_dataset.py
《mac + mlx-examples 大模型微调(fine-tuning)实践 - 让它学完所有PolarDB文章》
关于语言的支持(例如是否支持中文)?
《微调大模型时 vocab.json 和 tokenizer.json 有什么用? 如何扩充中文词汇表?》
后来还测试了DeepSeek-R1-Distill-Qwen-1.5B, 这个模型带think输出, 微调后根本不听使唤, 还是一意孤行.
https://huggingface.co/deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B/tree/main
《从huggingface 下载 safetensors, GGUF转换为ollama本地管理模型》
《ollama Modelfile 之 TEMPLATE的详解》