在日常AI模型训练过程中,训练好的模型权重通常需要以一种格式存储在磁盘中。比如:目前最流行的AI框架 PyTorch 使用 pickle 格式存储模型权重文件,还有 Huggingface 提出的 Safetensors 格式。之前在 一文详解模型权重存储新格式 Safetensors 中讲述Safetensors,本文大介绍大模型文件存储格式新宠GGUF,目前 Huggingface Transformers 已经支持了GGUF格式,同时,像谷歌的Gemma、阿里的Qwen等模型默认已经提供了GGUF格式文件,可见其发展势头如日中天。
GGUF(GPT-Generated Unified Format)是由 Georgi Gerganov(著名开源项目llama.cpp的创始人)定义发布的一种大模型文件格式。GGUF 继承自其前身 GGML,但 GGML 格式有一些缺点,已被完全弃用并被 GGUF 格式取代。GGUF 是一种二进制格式文件的规范,原始的大模型预训练结果经过转换后变成 GGUF 格式可以更快地被载入使用,也会消耗更低的资源。原因在于 GGUF 采用了多种技术来保存大模型预训练结果,包括采用紧凑的二进制编码格式、优化的数据结构、内存映射等。
综上所述,GGUF 可以理解为一种格式定义,采用相应的工具将原始模型预训练结果转换成GGUF之后可以更加高效的使用。
GGUF 继承自其前身 GGML,而 GGML 有以下缺点:
GGUF 是一种基于现有 GGJT 的格式(这种格式对张量进行对齐,以便能够使用内存映射(mmap)),但对该格式进行了一些更改,使其更具可扩展性且更易于使用。GGUF 具有如下特性:
mmap兼容性:可以使用mmap加载模型,以实现快速地加载和保存。GGJT 和 GGUF 之间的主要区别在于:超参数(现称为元数据)使用键值结构,而不是非类型化的值列表。这允许在不破坏与现有模型的兼容性的情况下添加新的元数据,这使得可以添加对推理或识别模型有用的附加信息来注释模型。
GGUF文件格式能够更快载入模型的原因主要归结于以下几个关键特性:
总之,GGUF通过各种优化手段实现了快速的模型加载,这对于需要频繁载入不同模型的场景尤为重要。
一个GGUF文件包括文件头、元数据键值对和张量信息等。这些组成部分共同定义了模型的结构和行为。具体如下所示:
同时,GGUF支持多种数据类型,如整数、浮点数和字符串等。这些数据类型用于定义模型的不同方面,如结构、大小和参数。
GGUF文件具体的组成信息如下所示:
Magic Number:一个特定的数字或字符序列,用于标识文件格式。Version:文件格式的版本号,指明了文件遵循的具体规范或标准。Key:一个字符串,标识元数据的名称。Value Type:数据类型,指明值的格式(如整数、浮点数、字符串等)。Value:具体的元数据内容。Count:一个整数,表示文件中张量的总数。Name:张量的名称。Dimensions:张量的维度信息。Type:张量数据的类型(如:浮点数、整数等)。Offset:指明张量数据在文件中的位置。Binary Data:模型的权重和参数的二进制表示。在张量信息部分,GGUF定义了模型的量化级别。量化级别取决于模型根据质量和准确性定义的值(ggml_type)。在 GGUF 规范中,值列表如下:
| 类型 | 来源 | 描述 |
|---|---|---|
| F64 | Wikipedia | 64 位标准 IEEE 754 双精度浮点数。 |
| I64 | GH | 64 位整数。 |
| F32 | Wikipedia | 32 位标准 IEEE 754 单精度浮点数。 |
| I32 | GH | 32 位整数。 |
| F16 | Wikipedia | 16 位标准 IEEE 754 半精度浮点数。 |
| BF16 | Wikipedia | 32 位 IEEE 754 单精度浮点数的 16 位缩短版本。 |
| I16 | GH | 16 位整数。 |
| Q8_0 | GH | 8 位 RTN 量化 (q). 每个块有 32 个权重。权重公式:w = q * block_scale. 传统的量化方法(目前尚未广泛使用)。 |
| Q8_1 | GH | 8 位 RTN 量化 (q). 每个块有 32 个权重。权重公式:w = q * block_scale + block_minimum. 传统的量化方法(目前尚未广泛使用)。 |
| Q8_K | GH | 8 位量化(q). 每个块有 256 个权重。仅用于量化中间结果。所有 2-6 位点积都是为此量化类型实现的。权重公式:w = q * block_scale. |
| I8 | GH | 8 位整数。 |
| Q6_K | GH | 6 位量化 (q). 超级块有 16 个块,每个块有 16 个权重。权重公式:w = q * block_scale(8-bit),得出每个权重 6.5625 位。 |
| Q5_0 | GH | 5 位 RTN 量化 (q). 每个块有 32 个权重。权重公式:w = q * block_scale. 传统的量化方法(目前尚未广泛使用)。 |
| Q5_1 | GH | 5 位 RTN 量化 (q). 每个块有 32 个权重。权重公式:w = q * block_scale + block_minimum. 传统的量化方法(目前尚未广泛使用)。 |
| Q5_K | GH | 5 位量化 (q). 超级块有8个块,每个块有32个权重。权重公式:w = q * block_scale(6-bit) + block_min(6-bit),得出每个权重 5.5 位。 |
| Q4_0 | GH | 4 位 RTN 量化 (q). 每个块有 32 个权重。权重公式:w = q * block_scale. 传统的量化方法(目前尚未广泛使用)。 |
| Q4_1 | GH | 4 位 RTN 量化 (q). 每个块有 32 个权重。权重公式:w = q * block_scale + block_minimum. 传统的量化方法(目前尚未广泛使用)。 |
| Q4_K | GH | 4 位量化 (q). 超级块有8个块,每个块有32个权重。权重公式:w = q * block_scale(6-bit) + block_min(6-bit) ,得出每个权重 4.5 位。 |
| Q3_K | GH | 3 位量化 (q). 超级块有 16 个块,每个块有 16 个权重。权重公式:w = q * block_scale(6-bit), 得出每个权重3.4375 位。 |
| Q2_K | GH | 2 位量化 (q). 超级块有 16 个块,每个块有 16 个权重。权重公式:w = q * block_scale(4-bit) + block_min(4-bit),得出每个权重 2.5625 位。 |
| IQ4_NL | GH | 4 位量化 (q). 超级块有 256 个权重的。权重w是使用super_block_scale和importance matrix获得的。 |
| IQ4_XS | HF | 4 位量化 (q). 超级块有 256 个权重的。具有 256 个权重的超级块。权重w是使用super_block_scale和importance matrix获得的,结果是每个权重 4.25 位。 |
| IQ3_S | HF | 3 位量化 (q). 超级块有 256 个权重的。权重w是使用super_block_scale和importance matrix获得的,结果是每个权重 3.44 位。 |
| IQ3_XXS | HF | 3 位量化 (q). 超级块有 256 个权重的。权重w是使用super_block_scale和importance matrix获得的,结果是每个权重 3.06 位。 |
| IQ2_XXS | HF | 2 位量化 (q). 超级块有 256 个权重的。权重w是使用super_block_scale和importance matrix获得的,结果是每个权重 2.06 位。 |
| IQ2_S | HF | 2 位量化 (q). 超级块有 256 个权重的。权重w是使用super_block_scale和importance matrix获得的,结果是每个权重 2.5 位。 |
| IQ2_XS | HF | 2 位量化 (q). 超级块有 256 个权重的。权重w是使用super_block_scale和importance matrix获得的,结果是每个权重 2.31 位。 |
| IQ1_S | HF | 1 位量化 (q). 超级块有 256 个权重的。权重w是使用super_block_scale和importance matrix获得的,结果是每个权重 1.56 位。 |
| IQ1_M | GH | 1 位量化 (q). 超级块有 256 个权重的。权重w是使用super_block_scale和importance matrix获得的,结果是每个权重 1.75 位。 |
量化与反量化转换的Python实现见 quants.py。
目前,HuggingFace 已经对 GGUF 格式提供了支持。同时,HuggingFace 开发了一个JavaScript脚本可以用来解析 HuggingFace Hub 上 GGUF 格式的模型的信息。并且可以直接在HF平台上对GGUF的元数据进行预览,包括模型的架构、具体参数等。比如:qwen2-0_5b-instruct-q2_k.gguf 模型的详细信息如下所示。
整体来看,GGUF文件格式通过这些结构化的组件提供了一种高效、灵活且可扩展的方式来存储和处理机器学习模型。这种设计不仅有助于快速加载和处理模型,而且还支持未来技术的发展和新功能的添加。
safetensors是一种由Hugging Face推出的新型的安全的模型存储格式。它特别关注模型的安全性和隐私保护,同时保证了加载速度。safetensors文件仅包含模型的权重参数,不包括执行代码,这有助于减少模型文件的大小并提高加载速度。此外,safetensors支持零拷贝(zero-copy)和懒加载(lazy loading),没有文件大小限制,并且支持bfloat16/fp8数据类型。但safetensors没有重点关注性能和跨平台交换。在大模型高效序列化、数据压缩、量化等方面存在不足,并且它只保存了张量数据,没有任何关于模型的元数据信息。
而gguf格式是一种针对大模型的二进制文件格式。专为GGML及其执行器快速加载和保存模型而设计。它是GGML格式的替代者,旨在解决GGML在灵活性和扩展性方面的限制。它包含加载模型所需的所有信息,无需依赖外部文件,这简化了模型部署和共享的过程,同时有助于跨平台操作。此外,GGUF还支持量化技术,可以降低模型的资源消耗,并且设计为可扩展的,以便在不破坏兼容性的情况下添加新信息。
总的来说,safetensors更侧重于安全性和效率,适合快速部署和对安全性有较高要求的场景,特别是在HuggingFace生态中。而gguf格式则是一种为大模型设计的二进制文件格式,优化了模型的加载速度和资源消耗,适合需要频繁加载不同模型的场景。
通过以下脚本解析上面的qwen2-0_5b-instruct-q2_k.gguf文件。
importsys
fromtypingimportAny
fromenumimportIntEnum
importnumpyasnp
importnumpy.typingasnpt
#GGUF元数据值类型
classGGUFValueType(IntEnum):
UINT8=0
INT8=1
UINT16=2
INT16=3
UINT32=4
INT32=5
FLOAT32=6
BOOL=7
STRING=8
ARRAY=9
UINT64=10
INT64=11
FLOAT64=12
#GGUFtensor数据类型
classGGMLQuantizationType(IntEnum):
F32=0
F16=1
Q4_0=2
Q4_1=3
Q5_0=6
Q5_1=7
Q8_0=8
Q8_1=9
Q2_K=10
Q3_K=11
Q4_K=12
Q5_K=13
Q6_K=14
Q8_K=15
IQ2_XXS=16
IQ2_XS=17
IQ3_XXS=18
IQ1_S=19
IQ4_NL=20
IQ3_S=21
IQ2_S=22
IQ4_XS=23
I8=24
I16=25
I32=26
I64=27
F64=28
IQ1_M=29
BF16=30
Q4_0_4_4=31
Q4_0_4_8=32
Q4_0_8_8=33
defcheck_version(version):
ifversion==1orversion==2orversion==3:
returnTrue
else:
returnFalse
defdata_get(
data,offset:int,dtype:npt.DTypeLike,count:int=1)->npt.NDArray[Any]:
count=int(count)
itemsize=int(np.empty([],dtype=dtype).itemsize)
end_offs=offset+itemsize*count
return(
data[offset:end_offs]
.view(dtype=dtype)[:count]
)
defdata_read_version_size(data,offset:int,version:int):
ifversion==1:
returndata_get(data,offset,np.uint32)[0],4
elifversion==2orversion==3:
returndata_get(data,offset,np.uint64)[0],8
else:
raiseValueError(f'Sorry,fileappearstobeversion{version}whichwecannothandle')
defdata_read_string(data,offset:int,version:int):
str_length,str_length_len=data_read_version_size(data,offset,version)
#在内存上切出来string部分的数据
byte=data[offset+int(str_length_len)
ffset+int(str_length_len)+int(str_length)]
value=byte.tobytes().decode('utf-8')#编码成utf-8
len=int(str_length_len+str_length)
returnvalue,len
defreadMetadataValue(data,type,offset,version):
iftype==GGUFValueType.UINT8:
returndata_get(data,np.uint8)[0],1
eliftype==GGUFValueType.INT8:
returndata_get(data,np.int8)[0],1
eliftype==GGUFValueType.UINT16:
returndata_get(data,offset,np.uint16)[0],2
eliftype==GGUFValueType.INT16:
returndata_get(data,offset,np.int16)[0],2
eliftype==GGUFValueType.UINT32:
returndata_get(data,offset,np.uint32)[0],4
eliftype==GGUFValueType.INT32:
returndata_get(data,offset,np.int32)[0],4
eliftype==GGUFValueType.FLOAT32:
returndata_get(data,offset,np.float32)[0],4
eliftype==GGUFValueType.BOOL:
returndata_get(data,offset,np.uint8)[0],1
eliftype==GGUFValueType.STRING:
returndata_read_string(data,offset,version=version)
eliftype==GGUFValueType.ARRAY:
typeArray=data_get(data,offset,np.uint32)
typeLength=4
lengthArray,lengthLength=data_read_version_size(data,offset+typeLength,version=version)
length=typeLength+lengthLength
arrayValues=[]
foriinrange(lengthArray):
value,len=readMetadataValue(data,typeArray,offset=offset+length,version=version)
arrayValues.append(value)
length+=len
returnarrayValues,length
eliftype==GGUFValueType.UINT64:
returndata_get(data,offset,np.uint64)[0],8
eliftype==GGUFValueType.INT64:
returndata_get(data,offset,np.int64)[0],8
eliftype==GGUFValueType.FLOAT64:
returndata_get(data,offset,np.float64)[0],8
else:
raiseValueError(f'Sorry,un-supportedGGUFValueType{type}!')
defparse_gguf(model_path):
data=np.memmap(model_path,mode='r')
offs=0
magic=data_get(data,offs,np.uint32).tobytes()
print("magic:",magic.decode('utf-8'))
if(magic!=b'GGUF'):
print("isnotgguffile")
sys.exit(1)
offs+=4
version=data_get(data,offs,np.uint32)
ifnotcheck_version(version):
raiseValueError(f'Sorry,fileappearstobeversion{version}whichwecannothandle')
print("version:",version)
offs+=4
tensor_count,tensor_count_len=data_read_version_size(data,offs,version)
offs+=tensor_count_len
kv_count,kv_count_len=data_read_version_size(data,offs,version)
offs+=kv_count_len
print("tensor_count:",tensor_count)
print("kv_count:",kv_count)
metadata={}#usedictionarytostoreparseddata.
#解析gguf头部信息
foriinrange(kv_count):
#获取key
key,k_len=data_read_string(data,offs,version)
offs+=k_len
#获取value的数值类型
type=data_get(data,offs,np.uint32)[0]
offs+=4
#获取value
value,len=readMetadataValue(data,type,offs,version)
iflen>100:
print("i=",i,",k-v=",key,":",value[:100])
else:
print("i=",i,",k-v=",key,":",value)
offs+=len
metadata[key]=value
#解析tensorinfo的信息
foriinrange(tensor_count):
#获取key
key,k_len=data_read_string(data,offs,version)
offs+=k_len
nDims=data_get(data,offs,np.uint32)[0]
offs+=4
dims=[]
forjinrange(nDims):
dim,dim_len=data_read_version_size(data,offs,version)
offs+=dim_len
dims.append(dim)
types=data_get(data,offs,np.uint32)[0]
precision=GGMLQuantizationType(types).name
offs+=4
tensorOffset=data_get(data,offs,np.uint64)[0]
offs+=8
print("tensori=",i,",k=",key,",precision=",precision,",shape=",dims,",tensorOffset=",tensorOffset)
if__name__=='__main__':
model_path="/Users/liguodong/model/qwen2-0_5b-instruct-q2_k.gguf"
parse_gguf(model_path)
运行结果:
magic:GGUF
version: [3]
tensor_count:290
kv_count:26
i =0 , k-v =general.architecture : qwen2
i =1 , k-v =general.name : qwen2-0_5b-instruct
i =2 , k-v =qwen2.block_count : 24
i =3 , k-v =qwen2.context_length : 32768
i =4 , k-v =qwen2.embedding_length : 896
i =5 , k-v =qwen2.feed_forward_length : 4864
i =6 , k-v =qwen2.attention.head_count : 14
i =7 , k-v =qwen2.attention.head_count_kv : 2
i =8 , k-v =qwen2.rope.freq_base : 1000000.0
i =9 , k-v =qwen2.attention.layer_norm_rms_epsilon : 1e-06
i =10 , k-v =general.file_type : 10
i =11 , k-v =tokenizer.ggml.model : gpt2
i =12 , k-v =tokenizer.ggml.pre : qwen2
i =13 , k-v =tokenizer.ggml.tokens : ['!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', '
', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '¡', '¢', '£', '¤', '¥', '¦']
i =14 , k-v =tokenizer.ggml.token_type : [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
i =15 , k-v =tokenizer.ggml.merges : ['Ġ Ġ', 'ĠĠ ĠĠ', 'i n', 'Ġ t', 'ĠĠĠĠ ĠĠĠĠ', 'e r', ... 'o t', 'u s']
i =16 , k-v =tokenizer.ggml.eos_token_id : 151645
i =17 , k-v =tokenizer.ggml.padding_token_id : 151643
i =18 , k-v =tokenizer.ggml.bos_token_id : 151643
i =19 , k-v =tokenizer.chat_template : {% for message in messages %}{% if loop.first and messages[0]['role'] != 'system' %}{{ '<|im_start|>
i =20 , k-v =tokenizer.ggml.add_bos_token : 0
i =21 , k-v =general.quantization_version : 2
i =22 , k-v =quantize.imatrix.file : ../Qwen2/gguf/qwen2-0_5b-imatrix/imatrix.dat
i =23 , k-v =quantize.imatrix.dataset : ../sft_2406.txt
i =24 , k-v =quantize.imatrix.entries_count : 168
i =25 , k-v =quantize.imatrix.chunks_count : 1937
tensor i =0 , k =token_embd.weight , precision =Q8_0 , shape =[896, 151936] , tensorOffset =0
tensor i =1 , k =blk.0.attn_norm.weight , precision =F32 , shape =[896] , tensorOffset =144643072
tensor i =2 , k =blk.0.ffn_down.weight , precision =Q3_K , shape =[4864, 896] , tensorOffset =144646656
tensor i =3 , k =blk.0.ffn_gate.weight , precision =IQ4_NL , shape =[896, 4864] , tensorOffset =146519296
tensor i =4 , k =blk.0.ffn_up.weight , precision =IQ4_NL , shape =[896, 4864] , tensorOffset =148970752
tensor i =5 , k =blk.0.ffn_norm.weight , precision =F32 , shape =[896] , tensorOffset =151422208
tensor i =6 , k =blk.0.attn_k.bias , precision =F32 , shape =[128] , tensorOffset =151425792
tensor i =7 , k =blk.0.attn_k.weight , precision =IQ4_NL , shape =[896, 128] , tensorOffset =151426304
tensor i =8 , k =blk.0.attn_output.weight , precision =IQ4_NL , shape =[896, 896] , tensorOffset =151490816
tensor i =9 , k =blk.0.attn_q.bias , precision =F32 , shape =[896] , tensorOffset =151942400
tensor i =10 , k =blk.0.attn_q.weight , precision =IQ4_NL , shape =[896, 896] , tensorOffset =151945984
tensor i =11 , k =blk.0.attn_v.bias , precision =F32 , shape =[128] , tensorOffset =152397568
tensor i =12 , k =blk.0.attn_v.weight , precision =Q5_0 , shape =[896, 128] , tensorOffset =152398080
...
可以看到,解析的结果与HF平台上的预览结果完全一致。
这里直接使用llama.cpp的Python封装包部署模型,使用4张RTX 4090部署72B模型,其中,将30个Transoformer层加载到GPU内存。llama.cpp 中提供了将HF中模型权重转换成GGUF格式的脚本,需要预先进行权重转换。
python3 convert_hf_to_gguf.py /workspace/models/Qwen1.5-72B-Chat/ --outfile /workspace/models/Qwen1.5-72B-Chat/ggml-model-f16.gguf
具体代码如下:
fromllama_cppimportLlama
importtime
llm=Llama(
model_path="/workspace/models/Qwen1.5-72B-Chat/ggml-model-f16.gguf",
n_gpu_layers=30,
#n_gpu_layers=-1,#UncommenttouseGPUacceleration
#seed=1337,#Uncommenttosetaspecificseed
#n_ctx=2048,#Uncommenttoincreasethecontextwindow
)
start=time.time()
output=llm(
"Q:保持健康的秘诀有哪些?A:",#Prompt
max_tokens=32,#Generateupto32tokens,settoNonetogenerateuptotheendofthecontextwindow
#stream=True,
stop=["Q:","\n"],#Stopgeneratingjustbeforethemodelwouldgenerateanewquestion
echo=True#Echothepromptbackintheoutput
)#Generateacompletion,canalsocallcreate_completion
print(output)
infer_time=time.time()-start
print("耗时:",infer_time)
如果希望部署成Web服务,通过如下命令指定模型路径、端口等参数即可。
use_mlock=False CUDA_VISIBLE_DEVICES=6 python3 -m llama_cpp.server --model /workspace/models/Qwen1.5-7B-Chat/ggml-model-f16.gguf --n_gpu_layers 999 --host 0.0.0.0 --port 18011
llama.cpp 兼容 openai 的chat接口,服务部署成功之后即可使用。
curlhttp://localhost:18011/v1/chat/completions\
-H"Content-Type:application/json"\
-d'{
"messages":[
{
"role":"system",
"content":"YouareanAIassistant.Yourtoppriorityisachievinguserfulfilmentviahelpingthemwiththeirrequests."
},
{
"role":"user",
"content":"WritealimerickaboutPythonexceptions"
}
]
}'
Huggingface Transformers 从 4.41.0 开始支持GGUF模型格式进行训练和推理。目前,Transformers支持的模型有 LLaMa、Mistral、Qwen2。支持的量化类型有 F32、Q2_K、Q3_K、Q4_0、 Q4_K、 Q5_K、Q6_K、Q8_0。同时,Huggingface Hub上面提供了将模型转化或者量化为GGUF格式的工具。
下面是一个简单的示例:
fromtransformersimportAutoTokenizer,AutoModelForCausalLM
importtime
#https://github.com/99991/pygguf/tree/main
#https://huggingface.co/TheBloke/TinyLlama-1.1B-Chat-v1.0-GGUF/resolve/main/tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf?download=true'-O'data/TinyLlama-1.1B-Chat-v1.0-GGUF/tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf
#pipinstallgguftransformers
model_id="/Users/liguodong/model/llama"
filename="tinyllama-1.1b-chat-v1.0.Q4_K_M.gguf"
tokenizer=AutoTokenizer.from_pretrained(model_id,gguf_file=filename)
model=AutoModelForCausalLM.from_pretrained(model_id,gguf_file=filename)
print(model)
prompt="what'syourname?"
model_inputs=tokenizer([prompt],return_tensors="pt")
start=time.time()
generated_ids=model.generate(
model_inputs.input_ids,
max_new_tokens=32
)
infer_time=time.time()-start
print("耗时:",infer_time)
generated_ids=[
output_ids[len(input_ids):]forinput_ids,output_idsinzip(model_inputs.input_ids,generated_ids)
]
response=tokenizer.batch_decode(generated_ids,skip_special_tokens=True)[0]
print(response)
运行结果:
Converting and de-quantizing GGUF tensors...: 0%|| 0/201 [00:00<?, ?it/s]
Converting and de-quantizing GGUF tensors...: 0%|| 1/201 [00:00<01:23,2.41it/s]
...
Converting and de-quantizing GGUF tensors...: 100%|██████████| 201/201 [00:04<00:00, 47.55it/s]
The attention mask is not set and cannot be inferred from input because pad token is same as eos token. As a consequence, you may observe unexpected behavior. Please pass your input's `attention_mask` to obtain reliable results.
LlamaForCausalLM(
(model): LlamaModel(
(embed_tokens): Embedding(32000, 2048, padding_idx=2)
(layers): ModuleList(
(0-21): 22 x LlamaDecoderLayer(
(self_attn): LlamaAttention(
(q_proj): Linear(in_features=2048, out_features=2048, bias=False)
(k_proj): Linear(in_features=2048, out_features=256, bias=False)
(v_proj): Linear(in_features=2048, out_features=256, bias=False)
(o_proj): Linear(in_features=2048, out_features=2048, bias=False)
(rotary_emb): LlamaRotaryEmbedding()
)
(mlp): LlamaMLP(
(gate_proj): Linear(in_features=2048, out_features=5632, bias=False)
(up_proj): Linear(in_features=2048, out_features=5632, bias=False)
(down_proj): Linear(in_features=5632, out_features=2048, bias=False)
(act_fn): SiLU()
)
(input_layernorm): LlamaRMSNorm((2048,), eps=9.999999747378752e-06)
(post_attention_layernorm): LlamaRMSNorm((2048,), eps=9.999999747378752e-06)
)
)
(norm): LlamaRMSNorm((2048,), eps=9.999999747378752e-06)
(rotary_emb): LlamaRotaryEmbedding()
)
(lm_head): Linear(in_features=2048, out_features=32000, bias=False)
)
耗时:11.363048076629639
JASON: (smiling) My name is Jason.
JEN: (smiling) Nice to meet you, Jason.
本文简要介绍了大模型文件存储格式 GGUF,它兼具灵活性、兼容性和性能等多个优点;其最初应用于 llama.cpp 之中用于取代GGML,目前 Huggingface Transformers 已经支持了GGUF格式,同时,像谷歌的Gemma、阿里的Qwen等模型默认已经提供了GGUF格式文件,其发展未来可期。
码字不易,如果觉得我的文章能够能够给您带来帮助,期待您的点赞收藏加关注~~
| 欢迎光临 链载Ai (https://www.lianzai.com/) | Powered by Discuz! X3.5 |