定制ollama本地模型
背景
ollama 支持从safetensors和GGUF的大模型文件格式创建本地ollama可管理的模型文件. 转换过程中还可以自定义参数, 降低精度等. 而safetensors和GGUF在huggingface唾手可得, 非常方便.
下面以safetensors为例, 说明如何从safetensors创建由本地ollama管理的大模型. 测试机为macbook m2 16g内存.
例子
下载一个小一点的模型, 用来测试, 例如采用DeepSeek-R1蒸馏过的Qwen-1.5B.
https://huggingface.co/deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B/tree/main
需要下载的文件如下
config.json
generation_config.json
model.safetensors
tokenizer.json
tokenizer_config.json
下载到任意目录, 例如:
$ pwd
/Users/digoal/Downloads/qwen1.5b
$ ll
total 6961376
-rw-r--r--@ 1 digoal staff 679B Feb 8 14:21 config.json
-rw-r--r--@ 1 digoal staff 181B Feb 8 14:21 generation_config.json
-rw-r--r--@ 1 digoal staff 3.0K Feb 8 14:22 tokenizer_config.json
-rw-r--r--@ 1 digoal staff 6.7M Feb 8 14:22 tokenizer.json
-rw-r--r--@ 1 digoal staff 3.3G Feb 8 14:38 model.safetensors
drwxr-xr-x 7 digoal staff 224B Feb 8 14:41 .
drwx------@ 388 digoal staff 12K Feb 8 14:41 ..
计算这些文件的sha256sum值
$ shasum -a 256 *
37bd455e9679d2959536270fed49d25cc7c290a64f6e52abb97c71345a9cee41 config.json
72cbec1015da9ed03ad025483005cbf6481403abf947adfd54e504d1a66a2126 generation_config.json
58858233513d76b8703e72eed6ce16807b523328188e13329257fb9594462945 model.safetensors
88145e3c3249adc2546ede277e9819d6e405e19072456e4b521cbc724bd60773 tokenizer.json
8c726f2ebf532f1d60437b17dd8da4f380adba3608e59e8448b3fb30c9115068 tokenizer_config.json
启动ollama服务
OLLAMA_HOST=0.0.0.0:11434 OLLAMA_KEEP_ALIVE=-1 ollama serve
首先要将文件导入ollama blob. 使用ollama api即可完成导入, 导入时以文件sha256sum命名. 参考如下章节
Push a file to the Ollama server to create a "blob" (Binary Large Object).
https://github.com/ollama/ollama/blob/main/docs/api.md#push-a-blob
cd /Users/digoal/Downloads/qwen1.5b
curl -T config.json -X POST http://localhost:11434/api/blobs/sha256:37bd455e9679d2959536270fed49d25cc7c290a64f6e52abb97c71345a9cee41
curl -T generation_config.json -X POST http://localhost:11434/api/blobs/sha256:72cbec1015da9ed03ad025483005cbf6481403abf947adfd54e504d1a66a2126
curl -T model.safetensors -X POST http://localhost:11434/api/blobs/sha256:58858233513d76b8703e72eed6ce16807b523328188e13329257fb9594462945
curl -T tokenizer.json -X POST http://localhost:11434/api/blobs/sha256:88145e3c3249adc2546ede277e9819d6e405e19072456e4b521cbc724bd60773
curl -T tokenizer_config.json -X POST http://localhost:11434/api/blobs/sha256:8c726f2ebf532f1d60437b17dd8da4f380adba3608e59e8448b3fb30c9115068
ollama server 日志如下:
[GIN] 2025/02/08 - 14:43:07 | 201 | 1.468459ms | ::1 | POST "/api/blobs/sha256:37bd455e9679d2959536270fed49d25cc7c290a64f6e52abb97c71345a9cee41"
[GIN] 2025/02/08 - 14:44:33 | 201 | 1.807417ms | ::1 | POST "/api/blobs/sha256:72cbec1015da9ed03ad025483005cbf6481403abf947adfd54e504d1a66a2126"
[GIN] 2025/02/08 - 14:44:36 | 201 | 2.87211775s | ::1 | POST "/api/blobs/sha256:58858233513d76b8703e72eed6ce16807b523328188e13329257fb9594462945"
[GIN] 2025/02/08 - 14:44:36 | 201 | 10.5775ms | ::1 | POST "/api/blobs/sha256:88145e3c3249adc2546ede277e9819d6e405e19072456e4b521cbc724bd60773"
[GIN] 2025/02/08 - 14:44:36 | 201 | 536.458µs | ::1 | POST "/api/blobs/sha256:8c726f2ebf532f1d60437b17dd8da4f380adba3608e59e8448b3fb30c9115068"
blob文件将被导入到如下目录:
~/.ollama/models/blobs
例如model.safetensors:
$ cd ~/.ollama/models/blobs
$ ll *58858233513d76b8703e72eed6ce16807b523328188e13329257fb9594462945
-rw-r--r-- 1 digoal staff 3.3G Feb 8 14:44 sha256-58858233513d76b8703e72eed6ce16807b523328188e13329257fb9594462945
然后使用ollama api从导入的safetensors文件创建由本地ollama管理的大模型. 参考如下章节.
https://github.com/ollama/ollama/blob/main/docs/api.md#copy-a-model
Create a model from a Safetensors directory
https://github.com/ollama/ollama/blob/main/docs/api.md#create-a-model
例如, 指定量化参数q4_K_M, 降低精度后, 生成的文件从3.3GB变成了1.1GB.
curl http://localhost:11434/api/create -d '{
"model": "qwen_1.5b_test",
"quantize": "q4_K_M",
"files": {
"config.json": "sha256:37bd455e9679d2959536270fed49d25cc7c290a64f6e52abb97c71345a9cee41",
"generation_config.json": "sha256:72cbec1015da9ed03ad025483005cbf6481403abf947adfd54e504d1a66a2126",
"tokenizer.json": "sha256:88145e3c3249adc2546ede277e9819d6e405e19072456e4b521cbc724bd60773",
"tokenizer_config.json": "sha256:8c726f2ebf532f1d60437b17dd8da4f380adba3608e59e8448b3fb30c9115068",
"model.safetensors": "sha256:58858233513d76b8703e72eed6ce16807b523328188e13329257fb9594462945"
}
}'
返回结果
{"status":"converting model"}
{"status":"quantizing F16 model to Q4_K_M"}
{"status":"creating new layer sha256:f6976220ef02150637908882fa61b862630438b0032b4ed719ac184466b00e09"}
{"status":"writing manifest"}
{"status":"success"}
查看ollama管理的模型, 可以看到刚刚转换的qwen_1.5b_test:latest
$ ollama list
NAME ID SIZE MODIFIED
qwen_1.5b_test:latest e987670736f0 1.1 GB 23 seconds ago
deepseek-r1:7b 0a8c26691023 4.7 GB 28 hours ago
deepseek-r1:14b ea35dfe18182 9.0 GB 2 weeks ago
mxbai-embed-large:latest 468836162de7 669 MB 2 months ago
查看qwen_1.5b_test:latest的modelfile
$ ollama show --modelfile qwen_1.5b_test:latest
# Modelfile generated by "ollama show"
# To build a new Modelfile based on this, replace FROM with:
# FROM qwen_1.5b_test:latest
FROM /Users/digoal/.ollama/models/blobs/sha256-f6976220ef02150637908882fa61b862630438b0032b4ed719ac184466b00e09
TEMPLATE {{ .Prompt }}
因为导入时没有指定很多参数, 所以modelfile比较简陋, 我们可以参考huggingface的模板改一个
https://ollama.com/library/deepseek-r1:1.5b
$ ollama show --modelfile deepseek-r1:1.5b
# Modelfile generated by "ollama show"
# To build a new Modelfile based on this, replace FROM with:
# FROM deepseek-r1:1.5b
FROM /Users/digoal/.ollama/models/blobs/sha256-aabd4debf0c8f08881923f2c25fc0fdeed24435271c2b3e92c4af36704040dbc
TEMPLATE """{{- if .System }}{{ .System }}{{ end }}
{{- range $i, $_ := .Messages }}
{{- $last := eq (len (slice $.Messages $i)) 1}}
{{- if eq .Role "user" }}<|User|>{{ .Content }}
{{- else if eq .Role "assistant" }}<|Assistant|>{{ .Content }}{{- if not $last }}<|end▁of▁sentence|>{{- end }}
{{- end }}
{{- if and $last (ne .Role "assistant") }}<|Assistant|>{{- end }}
{{- end }}"""
PARAMETER stop <|begin▁of▁sentence|>
PARAMETER stop <|end▁of▁sentence|>
PARAMETER stop <|User|>
PARAMETER stop <|Assistant|>
LICENSE """MIT License
Copyright (c) 2023 DeepSeek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
"""
参考huggingface的模板改一个, template直接照搬, 同时加个默认温度参数(越小越严谨, 越大越有创造性). 注意template的值类型为字符串, 需要转义字符串里的换行和"号:
再次转换:
curl http://localhost:11434/api/create -d '{
"model": "qwen_1.5b_test1",
"quantize": "q4_K_M",
"template": "{{- if .System }}{{ .System }}{{ end }}\n{{- range $i, $_ := .Messages }}\n{{- $last := eq (len (slice $.Messages $i)) 1}}\n{{- if eq .Role \"user\" }}<|User|>{{ .Content }}\n{{- else if eq .Role \"assistant\" }}<|Assistant|>{{ .Content }}{{- if not $last }}<|end▁of▁sentence|>{{- end }}\n{{- end }}\n{{- if and $last (ne .Role \"assistant\") }}<|Assistant|>{{- end }}\n{{- end }}",
"parameters": {"stop": ["<|begin▁of▁sentence|>","<|end▁of▁sentence|>","<|User|>","<|Assistant|>"], "temperature": 0.3},
"files": {
"config.json": "sha256:37bd455e9679d2959536270fed49d25cc7c290a64f6e52abb97c71345a9cee41",
"generation_config.json": "sha256:72cbec1015da9ed03ad025483005cbf6481403abf947adfd54e504d1a66a2126",
"tokenizer.json": "sha256:88145e3c3249adc2546ede277e9819d6e405e19072456e4b521cbc724bd60773",
"tokenizer_config.json": "sha256:8c726f2ebf532f1d60437b17dd8da4f380adba3608e59e8448b3fb30c9115068",
"model.safetensors": "sha256:58858233513d76b8703e72eed6ce16807b523328188e13329257fb9594462945"
}
}'
{"status":"converting model"}
{"status":"quantizing F16 model to Q4_K_M"}
{"status":"using existing layer sha256:f6976220ef02150637908882fa61b862630438b0032b4ed719ac184466b00e09"}
{"status":"creating new layer sha256:319353f105dbd7246bd7220ebe15cc6454d7b018d2034c49251d92692a4916f6"}
{"status":"writing manifest"}
{"status":"success"}
$ ollama list
NAME ID SIZE MODIFIED
qwen_1.5b_test1:latest c40d544e285d 1.1 GB About a minute ago
deepseek-r1:1.5b a42b25d8c10a 1.1 GB 2 minutes ago
qwen_1.5b_test:latest e987670736f0 1.1 GB 13 minutes ago
deepseek-r1:7b 0a8c26691023 4.7 GB 28 hours ago
deepseek-r1:14b ea35dfe18182 9.0 GB 2 weeks ago
mxbai-embed-large:latest 468836162de7 669 MB 2 months ago
现在modelfile就比较丰富了
$ ollama show --modelfile qwen_1.5b_test1:latest
# Modelfile generated by "ollama show"
# To build a new Modelfile based on this, replace FROM with:
# FROM qwen_1.5b_test1:latest
FROM /Users/digoal/.ollama/models/blobs/sha256-f6976220ef02150637908882fa61b862630438b0032b4ed719ac184466b00e09
TEMPLATE """{{- if .System }}{{ .System }}{{ end }}
{{- range $i, $_ := .Messages }}
{{- $last := eq (len (slice $.Messages $i)) 1}}
{{- if eq .Role "user" }}<|User|>{{ .Content }}
{{- else if eq .Role "assistant" }}<|Assistant|>{{ .Content }}{{- if not $last }}<|end▁of▁sentence|>{{- end }}
{{- end }}
{{- if and $last (ne .Role "assistant") }}<|Assistant|>{{- end }}
{{- end }}"""
PARAMETER stop <|begin▁of▁sentence|>
PARAMETER stop <|end▁of▁sentence|>
PARAMETER stop <|User|>
PARAMETER stop <|Assistant|>
PARAMETER temperature 0.3
测试一下
$ ollama run qwen_1.5b_test1:latest
>>> /show parameters
Model defined parameters:
stop "<|begin▁of▁sentence|>"
stop "<|end▁of▁sentence|>"
stop "<|User|>"
stop "<|Assistant|>"
temperature 0.3
>>> 天空为什么是蓝色的
<think>
嗯,天空为什么会是蓝色呢?这个问题听起来有点奇怪,因为我觉得天空应该是白色的。不过,我听说有些地方的天空看起来特别蓝,甚至可能有颜色。那这些情况下,天空为什么会是蓝色呢?
首先,我想知道阳光是如何到达地球表面的。太阳光是从遥远的太阳那里来的,它通过大气层传播到地球表面。大气层中有很多气体成分,包括氧气、氮气和稀有的气体。这些气体会吸收和散射阳光,使得阳光看起来很柔和。
然后,我听说有些地方的阳光非常强烈,甚至可能有强烈的直射光。比如,当太阳在某个特定的时间到达某地时,阳光可能会直接照射到地面,导致天空特别蓝。这种情况通常发生在极地地区或者某些特殊的天气条件下。
我还记得有一次,我在极地看到天空特别蓝,感觉很神奇。那为什么会有这样的现象呢?是不是因为大气层中的气体含量低,吸收的光线少,所以阳光看起来更蓝?
另外,我还听说有些地方的天空颜色会变化,比如在夏季可能更蓝,在冬季可能更红。这是因为太阳直射时,阳光照射得更强烈,导致颜色变化。而在其他时间,阳光较弱,颜色可能会变淡。
还有,我听说过一些自然现象,比如海天同色,当太阳直射到某个地方时,天空的颜色会与地面相同,甚至比地面还要蓝很多。这可能是因为阳光直接照射到空气中,吸收了更多的氧气和气体,导致颜色更浓。
不过,这些现象听起来有些复杂,我不太确定自己是否完全理解。也许我应该查阅一下相关的科学知识来确认这些说法的正确性。比如,大气层中的成分如何影响光的颜色,太阳直射时的光线如何变化,以及海天同色的现象是
什么原因造成的。
总的来说,天空为什么会是蓝色,可能涉及到阳光到达地球表面的过程、大气层的作用以及太阳直射时的变化因素。我需要进一步学习和了解这些科学知识,才能更准确地回答这个问题。
</think>
天空看起来通常是白色的,因为阳光通过大气层散射成白色。然而,在某些特殊情况下,天空可能会呈现出不同的颜色:
1. **极地地区**:当太阳在极点直射时,阳光直接照射到空气中,导致天空特别蓝。这种现象被称为“海天同色”,因为阳光几乎与地面颜色相同。
2. **大气层中的成分影响颜色**:大气中含有的氧气和稀有气体吸收了部分阳光,使阳光看起来较柔和。在极地地区,这些气体含量较低,吸收的光线较少,导致阳光更蓝。
3. **太阳直射时的变化**:除了极地,其他时间太阳直射时,阳光照射得更强烈,颜色变化也不同。例如,在夏季,天空可能更蓝;在冬季,颜色可能变红。
4. **海天同色现象**:当太阳直射某地时,阳光几乎与地面颜色相同,甚至比地面还要蓝很多,这种现象被称为“海天同色”。
综上所述,天空的颜色取决于阳光到达地球表面的过程、大气层的作用以及太阳直射时的变化因素。这些复杂的现象使得天空呈现出多样的色彩,包括蓝色和红色等。
>>>
大家有兴趣的话可以再试试GGUF文件格式.
参考
https://github.com/ollama/ollama/blob/main/docs/README.md