ftllm 0.0.0.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
ftllm-0.0.0.2/PKG-INFO ADDED
@@ -0,0 +1,15 @@
1
+ Metadata-Version: 2.1
2
+ Name: ftllm
3
+ Version: 0.0.0.2
4
+ Summary: Fastllm
5
+ Home-page: https://github.com/ztxz16/fastllm
6
+ Author: huangyuyang
7
+ Author-email: ztxz16@foxmail.com
8
+ License: UNKNOWN
9
+ Platform: UNKNOWN
10
+ Provides-Extra: all
11
+ Provides-Extra: server
12
+ Provides-Extra: webui
13
+
14
+ UNKNOWN
15
+
@@ -0,0 +1 @@
1
+ __all__ = ["llm"]
@@ -0,0 +1,33 @@
1
+ import argparse
2
+ from ftllm import llm
3
+ from .util import make_normal_parser
4
+ from .util import make_normal_llm_model
5
+ import readline
6
+
7
+ def args_parser():
8
+ parser = make_normal_parser('fastllm_chat')
9
+ args = parser.parse_args()
10
+ return args
11
+
12
+ if __name__ == "__main__":
13
+ args = args_parser()
14
+ model = make_normal_llm_model(args)
15
+ hint = "输入内容开始对话\n'clear'清空记录\n'stop'终止程序."
16
+ history = []
17
+
18
+ print(hint)
19
+ while True:
20
+ query = input("\nUser:")
21
+ if query.strip() == "stop":
22
+ break
23
+ if query.strip() == "clear":
24
+ history = []
25
+ print(hint)
26
+ continue
27
+ print("AI:", end = "");
28
+ curResponse = "";
29
+ for response in model.stream_response(query, history = history):
30
+ curResponse += response;
31
+ print(response, flush = True, end = "")
32
+ history.append((query, curResponse))
33
+ model.release_memory()
@@ -0,0 +1,15 @@
1
+ import argparse
2
+ from ftllm import llm
3
+ from .util import make_normal_parser
4
+ from .util import make_normal_llm_model
5
+ import readline
6
+
7
+ def args_parser():
8
+ parser = make_normal_parser('fastllm_export')
9
+ parser.add_argument('-o', '--output', type = str, required = True, help = '导出路径')
10
+ args = parser.parse_args()
11
+ return args
12
+
13
+ if __name__ == "__main__":
14
+ args = args_parser()
15
+ llm.export_llm_model_fromhf(path = args.path, dtype = args.dtype, lora = args.lora, output = args.output)
@@ -0,0 +1,275 @@
1
+ from ftllm import llm;
2
+ import ctypes;
3
+ import builtins, os, json
4
+ import numpy as np
5
+ import torch
6
+ from transformers import PreTrainedTokenizerFast
7
+ from tokenizers.decoders import ByteLevel
8
+
9
+ fastllm_data_type_dict = {
10
+ "int4g": 9,
11
+ "int4": 8,
12
+ "int8": 3,
13
+ "float16": 7,
14
+ "float32": 0,
15
+ }
16
+ fastllm_weight_type_dict = {
17
+ "linear": 1,
18
+ "embedding": 2,
19
+ "QuantizedLinear": 111
20
+ }
21
+
22
+ def create(model,
23
+ tokenizer = None,
24
+ pre_prompt = None,
25
+ user_role = None,
26
+ bot_role = None,
27
+ history_sep = None,
28
+ eos_id = None,
29
+ dtype = "float16",
30
+ group = -1):
31
+ int4g_groupcnt = group
32
+ if (dtype.startswith("int4g") and len(dtype) > 5):
33
+ try:
34
+ int4g_groupcnt = int(dtype[5:])
35
+ dtype = "int4g";
36
+ except:
37
+ print("dtype should be like \"int4g256\"")
38
+ exit(0)
39
+ if (dtype not in fastllm_data_type_dict):
40
+ print("dtype should be one of ", list(fastllm_data_type_dict.keys()))
41
+ exit(0)
42
+
43
+ # 0.1 model info
44
+ modelInfo = model.config.__dict__
45
+ if model.generation_config is not None:
46
+ modelInfo.update(model.generation_config.__dict__)
47
+ if (pre_prompt is not None):
48
+ modelInfo["pre_prompt"] = pre_prompt
49
+ if (user_role is not None):
50
+ modelInfo["user_role"] = user_role
51
+ if (bot_role is not None):
52
+ modelInfo["bot_role"] = bot_role
53
+ if (history_sep):
54
+ modelInfo["history_sep"] = history_sep
55
+ if modelInfo["architectures"] == ["MiniCPMForCausalLM"]:
56
+ modelInfo["model_type"] = "minicpm"
57
+ if (modelInfo["model_type"] == "baichuan"):
58
+ if (hasattr(model, "model") and hasattr(model.model, "get_alibi_mask")):
59
+ # Baichuan / Baichuan2 13B
60
+ modelInfo["use_alibi"] = "1"
61
+ modelInfo["pre_prompt"] = ""
62
+ if (modelInfo["vocab_size"] == 125696):
63
+ # Baichuan 2代
64
+ modelInfo["user_role"] = ("<FLM_FIX_TOKEN_" + str(model.generation_config.user_token_id) + ">") if hasattr(model.generation_config, "user_token_id") else "";
65
+ else:
66
+ # Baichuan-13B-chat
67
+ modelInfo["user_role"] = ("<FLM_FIX_TOKEN_" + str(model.generation_config.user_token_id) + "> ") if hasattr(model.generation_config, "user_token_id") else "";
68
+ modelInfo["bot_role"] = ("<FLM_FIX_TOKEN_" + str(model.generation_config.assistant_token_id) + ">") if hasattr(model.generation_config, "assistant_token_id") else "";
69
+ modelInfo["history_sep"] = ""
70
+ if (modelInfo["model_type"] == "qwen"):
71
+ if modelInfo["chat_format"] == "chatml":
72
+ modelInfo["im_end_id"] = tokenizer.im_end_id
73
+ modelInfo["im_start_id"] = tokenizer.im_start_id
74
+ elif (modelInfo["model_type"] == "qwen2"):
75
+ modelInfo["eos_token_id"] = "151645"
76
+ pre_prompt = modelInfo["pre_prompt"] = "<|im_start|>system\nYou are a helpful assistant.<|im_end|>"
77
+ user_role = modelInfo["user_role"] = "<|im_start|>user\n"
78
+ bot_role = modelInfo["bot_role"] = "<|im_end|><|im_start|>assistant\n"
79
+ history_sep = modelInfo["history_sep"] = "<|im_end|>\n"
80
+ elif (modelInfo["model_type"] == "internlm"):
81
+ modelInfo["eos_token_id"] = "103028"
82
+ if "rotary" in modelInfo:
83
+ rope_scaling = modelInfo.pop("rotary")
84
+ if isinstance(rope_scaling, builtins.dict):
85
+ modelInfo["rope_scaling.type"] = rope_scaling["type"]
86
+ modelInfo["rope_theta"] = rope_scaling["base"]
87
+ elif (modelInfo["model_type"] == "internlm2"):
88
+ modelInfo["eos_token_id"] = "92542"
89
+ if (modelInfo["model_type"] == "chatglm" and hasattr(tokenizer, "build_chat_input")):
90
+ # chatglm3
91
+ modelInfo["pre_prompt"] = "";
92
+ modelInfo["user_role"] = ("<FLM_FIX_TOKEN_" + str(tokenizer.get_command("<|user|>")) + "> \n");
93
+ modelInfo["bot_role"] = ("<FLM_FIX_TOKEN_" + str(tokenizer.get_command("<|assistant|>")) + ">");
94
+ modelInfo["history_sep"] = "";
95
+ if (modelInfo["model_type"] == "chatglm" and hasattr(tokenizer, "name") and tokenizer.name == "GLM4Tokenizer"):
96
+ # glm-4-chat
97
+ modelInfo["pre_prompt"] = "";
98
+ modelInfo["user_role"] = ("<FLM_FIX_TOKEN_" + str(tokenizer.convert_tokens_to_ids("<|user|>")) + ">\n");
99
+ modelInfo["bot_role"] = ("<FLM_FIX_TOKEN_" + str(tokenizer.convert_tokens_to_ids("<|assistant|>")) + ">");
100
+ modelInfo["history_sep"] = "";
101
+ modelInfo["tokenizer_class"] = tokenizer.name;
102
+ if "rope_scaling" in modelInfo and isinstance(modelInfo["rope_scaling"], builtins.dict):
103
+ rope_scaling = modelInfo.pop("rope_scaling")
104
+ for key, value in rope_scaling.items():
105
+ modelInfo["rope_scaling." + key] = value
106
+ if eos_id:
107
+ modelInfo["eos_token_id"] = str(eos_id)
108
+
109
+ merges = {}
110
+ if tokenizer:
111
+ modelInfo["tokenizer_use_score"] = "1" # 分词带分数
112
+ if len(tokenizer.all_special_tokens) > 0:
113
+ token_set = set()
114
+ for token in [tokenizer.bos_token, tokenizer.eos_token, tokenizer.unk_token, tokenizer.pad_token]:
115
+ for prompt in [pre_prompt, user_role, bot_role, history_sep]:
116
+ if prompt and str(token) in prompt:
117
+ modelInfo["tokenizer_has_special_tokens"] = "1"
118
+ token_set.add(str(token))
119
+ if len(tokenizer.all_special_tokens) > len(token_set):
120
+ modelInfo["tokenizer_has_special_tokens"] = "1"
121
+ if hasattr(tokenizer, "sp_model") or (hasattr(tokenizer, "tokenizer") and hasattr(tokenizer.tokenizer, "sp_model")):
122
+ try:
123
+ import sentencepiece.sentencepiece_model_pb2 as model_pb2
124
+ with open(tokenizer.vocab_file, "rb") as f:
125
+ sp_model_data = f.read()
126
+ sp_model_proto = model_pb2.ModelProto.FromString(sp_model_data)
127
+ modelInfo["tokenizer_add_dummy_prefix"] = sp_model_proto.normalizer_spec.add_dummy_prefix
128
+ if sp_model_proto.normalizer_spec.remove_extra_whitespaces:
129
+ modelInfo["tokenizer_remove_extra_whitespaces"] = True
130
+ except:
131
+ pass
132
+ elif isinstance(tokenizer, PreTrainedTokenizerFast):
133
+ modelInfo["tokenizer_add_dummy_prefix"] = False
134
+ tokenizer_file_name = tokenizer.vocab_file if (hasattr(tokenizer, "vocab_file") and tokenizer.vocab_file) else tokenizer.vocab_files_names['tokenizer_file']
135
+ tokenizer_file = os.path.join(tokenizer.name_or_path, tokenizer_file_name)
136
+ if os.path.exists(tokenizer_file):
137
+ with open(tokenizer_file, "r", encoding='utf-8') as f:
138
+ tokenizer_data = json.load(f)
139
+ if "normalizer" in tokenizer_data and tokenizer_data["normalizer"] and "normalizers" in tokenizer_data["normalizer"]:
140
+ for normalizer in tokenizer_data["normalizer"]["normalizers"]:
141
+ if normalizer["type"] == "Prepend" and \
142
+ (normalizer["prepend"] == '▁' or normalizer["prepend"] == ' '):
143
+ modelInfo["tokenizer_add_dummy_prefix"] = True
144
+ if "merges" in tokenizer_data["model"]:
145
+ bpe_merges = tokenizer_data["model"]["merges"]
146
+ bpe_merges = [pair.replace(" ", "") for pair in bpe_merges]
147
+ merges = builtins.dict(zip(bpe_merges, range(0, -len(bpe_merges), -1)))
148
+ if hasattr(tokenizer, "_tokenizer") and hasattr(tokenizer._tokenizer, "decoder") \
149
+ and isinstance(tokenizer._tokenizer.decoder, ByteLevel):
150
+ modelInfo["tokenizer_byte_as_char"] = True
151
+ else:
152
+ if hasattr(tokenizer, "byte_encoder") and hasattr(tokenizer, "byte_decoder"):
153
+ modelInfo["tokenizer_byte_as_char"] = True
154
+ if not hasattr(tokenizer, "add_prefix_space") or not getattr(tokenizer, "add_prefix_space", True):
155
+ modelInfo["tokenizer_add_dummy_prefix"] = False
156
+
157
+ peft_config = {}
158
+ active_adapter = ""
159
+ if hasattr(model, "peft_config"):
160
+ peft_config = model.peft_config
161
+ if hasattr(model, "active_adapter") and isinstance(model.active_adapter, str):
162
+ # in transformers >= 4.33.0, active_adapter is a funtion in model, ignore it now
163
+ active_adapter = model.active_adapter
164
+
165
+ weight_type_dict = {}
166
+ model = model.cpu();
167
+ dict = model.state_dict()
168
+
169
+ if (modelInfo["model_type"] == "baichuan" and modelInfo["vocab_size"] == 125696):
170
+ # normalize lm_head for Baichuan 2
171
+ lm_head = dict['lm_head.weight'].to(torch.float32)
172
+ dict['lm_head.weight'] = torch.nn.functional.normalize(lm_head).to(torch.float16)
173
+ model.load_state_dict(dict)
174
+ weight_type_dict['lm_head.weight'] = "linear"
175
+
176
+ model_type = modelInfo["model_type"];
177
+ model_handle = llm.fastllm_lib.create_empty_llm_model(model_type.encode());
178
+ for it in modelInfo.keys():
179
+ llm.fastllm_lib.add_dict_llm_model(model_handle, str(it).encode(), str(modelInfo[it]).encode());
180
+
181
+ for adapter_name in peft_config.keys():
182
+ adapter_dict = peft_config[adapter_name].__dict__
183
+ for it in adapter_dict.keys():
184
+ llm.fastllm_lib.add_adapter_dict_llm_model(model_handle, str(adapter_name).encode(), str(it).encode(), str(adapter_dict[it]).encode())
185
+ if len(active_adapter) != 0:
186
+ llm.fastllm_lib.set_adapter(model_handle, str(active_adapter).encode())
187
+
188
+ # 1. vocab
189
+ if (tokenizer):
190
+ if (hasattr(tokenizer, "tokenizer")):
191
+ if (str(type(tokenizer.tokenizer)).find("Encoding") == -1):
192
+ tokenizer = tokenizer.tokenizer
193
+ if (hasattr(tokenizer, "sp_model")):
194
+ piece_size = tokenizer.sp_model.piece_size()
195
+ for i in range(piece_size):
196
+ llm.fastllm_lib.add_tokenizer_word_llm_model(model_handle, tokenizer.sp_model.id_to_piece(i).encode(),
197
+ i, ctypes.c_float(tokenizer.sp_model.get_score(i)));
198
+ else:
199
+ if hasattr(tokenizer, "bpe_ranks"):
200
+ merges = {("".join(bpe_tokens), token_index) for bpe_tokens, token_index in sorted(tokenizer.bpe_ranks.items(), key=lambda kv: kv[1])}
201
+ vocab = tokenizer.get_vocab()
202
+ for v in vocab.keys():
203
+ score = merges[v] if v in merges else 1.0
204
+ # if (modelInfo["model_type"] == "moss"):
205
+ # s = [(ord(c) if c not in tokenizer.byte_decoder else tokenizer.byte_decoder[c]) for c in v]
206
+ # llm.fastllm_lib.add_tokenizer_word_llm_model(model_handle, s, vocab[v], ctypes.c_float(score));
207
+ if (isinstance(v, str)):
208
+ llm.fastllm_lib.add_tokenizer_word_llm_model(model_handle, v.encode(), vocab[v], ctypes.c_float(score));
209
+ else:
210
+ llm.fastllm_lib.add_tokenizer_word_llm_model(model_handle, v, vocab[v], ctypes.c_float(score));
211
+ if ("tokenizer_has_special_tokens" in modelInfo):
212
+ special_tokens_str = ''.join(tokenizer.all_special_tokens)
213
+ special_tokens_len = [len(x) for x in tokenizer.all_special_tokens]
214
+ special_tokens_ids = tokenizer.all_special_ids
215
+ llm.fastllm_lib.set_special_tokens_llm_model(model_handle, len(special_tokens_len),
216
+ (ctypes.c_int * len(special_tokens_len))(*special_tokens_len),
217
+ special_tokens_str.encode(),
218
+ (ctypes.c_int * len(special_tokens_ids))(*special_tokens_ids));
219
+
220
+ module_dict = {}
221
+ weight_bits = {}
222
+ for key, m in model.named_modules():
223
+ if (str(type(m)).find("QuantizedLinear") != -1):
224
+ weight_type_dict[key + ".weight"] = "QuantizedLinear";
225
+ weight_bits[key + ".weight"] = m.weight_bit_width;
226
+ if (isinstance(m, torch.nn.Linear)):
227
+ weight_type_dict[key + ".weight"] = "linear"
228
+ module_dict[key + ".weight"] = m
229
+ if (isinstance(m, torch.nn.Embedding)):
230
+ weight_type_dict[key + ".weight"] = "embedding"
231
+
232
+ # 2. weight
233
+ tot = 0
234
+ for key in dict:
235
+ ori_data_type = 0
236
+ ori_np_data_type = np.float32
237
+ cur_weight_type = 0
238
+ if (key in weight_type_dict and weight_type_dict[key] in fastllm_weight_type_dict):
239
+ cur_weight_type = fastllm_weight_type_dict[weight_type_dict[key]]
240
+ to_data_type = 0
241
+
242
+ if (cur_weight_type == 1):
243
+ to_data_type = fastllm_data_type_dict[dtype]
244
+ if (to_data_type == 7):
245
+ ori_data_type = 7
246
+ ori_np_data_type = np.float16
247
+ elif (cur_weight_type == 2):
248
+ # TODO bfloat
249
+ to_data_type = 0
250
+ weight_name = key
251
+ if hasattr(model, "peft_config"):
252
+ weight_name = weight_name.replace('base_model.model.', '')
253
+ if (cur_weight_type == 111):
254
+ llm.fastllm_lib.add_qlinear_weight_llm_model(model_handle, weight_name.encode(),
255
+ len(dict[key].shape),
256
+ (ctypes.c_int * len(dict[key].shape))(*list(dict[key].shape)),
257
+ weight_bits[key],
258
+ dict[key + "_scale"].numpy().astype(np.float32).ctypes.data_as(ctypes.c_void_p),
259
+ dict[key].numpy().ctypes.data_as(ctypes.c_void_p));
260
+ else:
261
+ llm.fastllm_lib.add_weight_llm_model(model_handle, weight_name.encode(),
262
+ len(dict[key].shape),
263
+ (ctypes.c_int * len(dict[key].shape))(*list(dict[key].shape)),
264
+ to_data_type, cur_weight_type, ori_data_type,
265
+ dict[key].numpy().astype(ori_np_data_type).ctypes.data_as(ctypes.c_void_p), int4g_groupcnt);
266
+ tot += 1;
267
+ print("convert (", tot, "/", len(dict), end = " )\r");
268
+ dict[key].to(torch.device("meta"))
269
+
270
+ print("");
271
+ llm.fastllm_lib.init_params_llm_model(model_handle);
272
+ llm.fastllm_lib.warmup_llm_model(model_handle);
273
+ ret = llm.model("", id = model_handle);
274
+ return ret;
275
+
Binary file