| import copy |
| from typing import List, Union, Dict |
|
|
| import PIL.Image |
| import torch |
| import numpy as np |
| import torchvision.transforms.functional as F |
| import transformers |
|
|
| from transformers import PreTrainedTokenizer |
|
|
| IGNORE_INDEX = -100 |
|
|
| def print_trainable_params(model: torch.nn.Module) -> None: |
| trainable_params, all_param = 0, 0 |
| for param in model.parameters(): |
| num_params = param.numel() |
| |
| if num_params == 0 and hasattr(param, "ds_numel"): |
| num_params = param.ds_numel |
| all_param += num_params |
| if param.requires_grad: |
| trainable_params += num_params |
| print("trainable params: {:d} || all params: {:d} || trainable%: {:.4f}".format( |
| trainable_params, all_param, 100 * trainable_params / all_param)) |
|
|
|
|
| def post_process_generate_ids(tokenizer: PreTrainedTokenizer, ids: torch.Tensor): |
| ids = copy.deepcopy(ids) |
| ids[ids < 0] = tokenizer.pad_token_id |
| |
| ids[ids >= len(tokenizer)] = tokenizer.convert_tokens_to_ids(',') |
| return ids |
|
|
|
|
| def decode_generate_ids(tokenizer: PreTrainedTokenizer, ids: torch.Tensor) -> Union[List[str], str]: |
| assert ids.ndim in [1, 2] |
| only_one_sentence = ids.ndim == 1 |
| if only_one_sentence: |
| ids = ids.unsqueeze(0) |
| ids = post_process_generate_ids(tokenizer, ids) |
| res = tokenizer.batch_decode(ids, skip_special_tokens=True, clean_up_tokenization_spaces=True) |
| if only_one_sentence: |
| return res[0] |
| return res |
|
|
|
|
|
|
| def draw_bounding_boxes( |
| image: Union[torch.Tensor, PIL.Image.Image], |
| boxes: Union[torch.Tensor, List, np.ndarray], |
| **kwargs, |
| ): |
| if isinstance(image, PIL.Image.Image): |
| from torchvision.transforms import PILToTensor |
| image = PILToTensor()(image) |
| assert isinstance(image, torch.Tensor), "" |
|
|
| if not isinstance(boxes, torch.Tensor): |
| boxes = torch.as_tensor(boxes) |
| assert isinstance(boxes, torch.Tensor) |
|
|
| from torchvision.utils import draw_bounding_boxes as _draw_bounding_boxes |
| return _draw_bounding_boxes(image, boxes, **kwargs) |
|
|
|
|
| |
| def smart_tokenizer_and_embedding_resize( |
| special_tokens_dict: Dict, |
| tokenizer: transformers.PreTrainedTokenizer, |
| model: transformers.PreTrainedModel, |
| ): |
| """Resize tokenizer and embedding. |
| |
| Note: This is the unoptimized version that may make your embedding size not be divisible by 64. |
| """ |
| num_new_tokens = tokenizer.add_special_tokens(special_tokens_dict) |
| model.resize_token_embeddings(len(tokenizer)) |
|
|
| if num_new_tokens > 0: |
| input_embeddings = model.get_input_embeddings().weight.data |
| output_embeddings = model.get_output_embeddings().weight.data |
|
|
| input_embeddings_avg = input_embeddings[:-num_new_tokens].mean(dim=0, keepdim=True) |
| output_embeddings_avg = output_embeddings[:-num_new_tokens].mean(dim=0, keepdim=True) |
|
|
| input_embeddings[-num_new_tokens:] = input_embeddings_avg |
| output_embeddings[-num_new_tokens:] = output_embeddings_avg |
|
|
| def patch_transformer_logging(): |
| import logging |
| import transformers |
| def enable_explicit_format(): |
| handlers = transformers.utils.logging._get_library_root_logger().handlers |
|
|
| for handler in handlers: |
| formatter = logging.Formatter("[(%(levelname)s) %(pathname)s:%(lineno)s ] %(asctime)s >> %(message)s") |
| handler.setFormatter(formatter) |
| transformers.utils.logging.enable_explicit_format = enable_explicit_format |
|
|
| def print_model_stats(model): |
| """ |
| 通用模型参数统计工具。 |
| 自动识别是 Dense 还是 MoE 模型,并计算 Total vs Active 参数量。 |
| """ |
| |
| |
| |
| unique_params = {p.data_ptr(): p for p in model.parameters()}.values() |
| total_params = sum(p.numel() for p in unique_params) |
| |
| |
| |
| active_params = total_params |
| |
| moe_infos = [] |
| |
| |
| |
| for name, module in model.named_modules(): |
| |
| if hasattr(module, 'num_experts') and hasattr(module, 'experts') and isinstance(module.experts, nn.ModuleList): |
| |
| |
| num_experts = getattr(module, 'num_experts', 0) |
| |
| top_k = getattr(module, 'top_k', getattr(module, 'num_experts_per_tok', 0)) |
| |
| |
| if top_k == 0: |
| continue |
|
|
| |
| |
| |
| single_expert_params = sum(p.numel() for p in module.experts[0].parameters()) |
| |
| |
| dormant_experts = num_experts - top_k |
| |
| |
| |
| if dormant_experts > 0: |
| deduction = dormant_experts * single_expert_params |
| active_params -= deduction |
| |
| moe_infos.append({ |
| "layer": name, |
| "experts": num_experts, |
| "active": top_k, |
| "expert_size": single_expert_params |
| }) |
|
|
| |
| def format_num(num): |
| if num >= 1e9: return f"{num/1e9:.2f}B" |
| if num >= 1e6: return f"{num/1e6:.2f}M" |
| if num >= 1e3: return f"{num/1e3:.2f}K" |
| return str(num) |
|
|
| print("=" * 50) |
| print(f"Model Architecture Analysis") |
| print("=" * 50) |
| |
| if len(moe_infos) > 0: |
| print(f"👉 Detection: MoE Model (Sparse Mixture-of-Experts)") |
| print(f" - Found {len(moe_infos)} MoE layers") |
| print(f" - Config: {moe_infos[0]['experts']} Experts, Top-{moe_infos[0]['active']} Active") |
| else: |
| print(f"👉 Detection: Dense Model (Standard Transformer)") |
| |
| print("-" * 50) |
| print(f"Total Parameters (VRAM): {format_num(total_params)}") |
| print(f"Active Parameters (FLOPs): {format_num(active_params)}") |
| |
| if len(moe_infos) > 0: |
| sparsity = 1 - (active_params / total_params) |
| print(f"Sparsity Ratio: {sparsity:.2%}") |
| |
| |
| print(f"Upcycling Scale: {total_params/active_params:.2f}x Larger than Dense Base") |
| else: |
| print(f"Sparsity Ratio: 0.00% (Dense)") |
| |
| print("=" * 50) |
| |
| return total_params, active_params |