Spaces:
Running on Zero
Running on Zero
| import importlib | |
| import os | |
| import random | |
| import re | |
| from collections import defaultdict | |
| from dataclasses import dataclass | |
| from copy import deepcopy | |
| from functools import partial | |
| from typing import Any, Dict, Optional, Tuple, Union | |
| import torch | |
| import torch.nn.functional as F | |
| from diffusers.utils import BaseOutput | |
| from transformers.tokenization_utils_fast import PreTrainedTokenizerFast | |
| from rosetta.utils import CondImage, ImageInfo, JointImageInfo, default | |
| class Conversation(object): | |
| name: str | |
| roles: Tuple[str, str] = ("User", "Assistant") | |
| sep: str = "\n" | |
| sep2: str = None | |
| sep_sp: str = None | |
| stop_token_ids: list[int] = None | |
| pretrain_roles: Tuple[str, str] = ("", "") | |
| pretrain_sep: str = "" | |
| pretrain_sep2: str = "" | |
| pretrain_sep_sp: str = "" | |
| add_pad: bool = False | |
| add_bos: bool = True | |
| add_eos: bool = False | |
| def get_role_prefix(self, role): | |
| if role == "": | |
| return "" | |
| return f"<|im_start|>{role}\n" | |
| def empty(self, name=None): | |
| return Conversation( | |
| name=name or self.name, | |
| roles=self.roles, | |
| sep=self.sep, | |
| sep2=self.sep2, | |
| sep_sp=self.sep_sp, | |
| stop_token_ids=self.stop_token_ids, | |
| pretrain_roles=self.pretrain_roles, | |
| pretrain_sep=self.pretrain_sep, | |
| pretrain_sep2=self.pretrain_sep2, | |
| pretrain_sep_sp=self.pretrain_sep_sp, | |
| add_pad=self.add_pad, | |
| add_bos=self.add_bos, | |
| add_eos=self.add_eos, | |
| ) | |
| conv_templates: Dict[str, Conversation] = {} | |
| def register_conv_template(template: Conversation): | |
| assert template.name not in conv_templates, f"{template.name} has been registered." | |
| conv_templates[template.name] = template | |
| register_conv_template(Conversation( | |
| name="qwen-vl-30b-a3b-instruct", | |
| roles=("user", "assistant"), | |
| sep="<|im_end|>\n", | |
| sep2="<|im_end|>", | |
| sep_sp="\n\n", | |
| stop_token_ids=[151643, 151645], | |
| add_bos=False, | |
| )) | |
| for _template_name in ( | |
| "qwen3-06b-base-upcycling-moe-lm-deepseek", | |
| "qwen3-06b-base-upcycling-ours-lm", | |
| "qwen3-06b-upcycling-moe-mm-deepseek", | |
| "qwen3-06b-upcycling-ours-mm", | |
| "qwen3-06b-base-mot-lm", | |
| "qwen3-06b-mot", | |
| ): | |
| register_conv_template(conv_templates["qwen-vl-30b-a3b-instruct"].empty(name=_template_name)) | |
| def get_conversation_template(name: str) -> Conversation: | |
| return deepcopy(conv_templates[name]) | |
| ASSETS_BASE = os.getenv("ASSETS_BASE", "./public_assets").rstrip("/") | |
| TOKENIZER_BASE = os.getenv("TOKENIZER_BASE", f"{ASSETS_BASE}/pretrained_llm").rstrip("/") | |
| TOKENIZER_PATH = { | |
| "qwen3-0.6b-base": f"{TOKENIZER_BASE}/Qwen3-0.6B-Base", | |
| } | |
| class TokenizerEncodeOutput(BaseOutput): | |
| tokens: torch.Tensor = None | |
| text_slices: Optional[list[slice]] = None | |
| gen_image_slices: Optional[list[slice]] = None | |
| vae_image_slices: Optional[list[slice]] = None | |
| vit_image_slices: Optional[list[slice]] = None | |
| joint_image_slices: Optional[list[slice]] = None | |
| all_image_slices: Optional[list[slice]] = None | |
| text_mask: Optional[torch.Tensor] = None | |
| gen_image_mask: Optional[torch.Tensor] = None | |
| vae_image_mask: Optional[torch.Tensor] = None | |
| vit_image_mask: Optional[torch.Tensor] = None | |
| real_pos: Optional[torch.Tensor] = None | |
| cond_timestep_scatter_index: Optional[torch.Tensor] = None | |
| gen_timestep_scatter_index: Optional[torch.Tensor] = None | |
| und_token_indices: Optional[torch.Tensor] = None | |
| gen_token_indices: Optional[torch.Tensor] = None | |
| class BaseMultimodalTokenizerFast(PreTrainedTokenizerFast): | |
| def __init__(self, *args, **kwargs): | |
| super().__init__(*args, **kwargs) | |
| special_tokens = self.special_tokens_map.get('additional_special_tokens', []) | |
| if len(special_tokens) > 0: | |
| special_token_ids = self.convert_tokens_to_ids(special_tokens) | |
| self._sp_dict = dict(zip(special_tokens, special_token_ids)) | |
| else: | |
| self._sp_dict = dict() | |
| self.setup_special_tokens() | |
| def setup_special_tokens(self): | |
| predefined_name_mapping = { | |
| "answer": "", | |
| "end_of_answer": "", | |
| "boi": "<|boi|>", | |
| "eoi": "<|eoi|>", | |
| "img": "<|img|>", | |
| } | |
| for name, mapping in predefined_name_mapping.items(): | |
| setattr(self, f"{name}_token", mapping) | |
| setattr(self, f"{name}_token_id", self.convert_tokens_to_ids(mapping)) | |
| if len(self._sp_dict) > 0: | |
| name_mapping = dict( | |
| cfg_token="<|cfg|>", | |
| timestep_token="<|timestep|>", | |
| joint_img_sep_token="<|joint_img_sep|>", | |
| ) | |
| for name, token in name_mapping.items(): | |
| if token in self._sp_dict: | |
| setattr(self, name, token) | |
| setattr(self, f"{name}_id", self._sp_dict[token]) | |
| def size_token(self, size: int): | |
| assert len(self._sp_dict) > 0, "Size tokens are not defined in the tokenizer." | |
| return f"<|img_size_{size}|>" | |
| def size_token_id(self, size: int): | |
| return self._sp_dict[self.size_token(size)] | |
| def ratio_token(self, ratio_idx: int): | |
| assert len(self._sp_dict) > 0, "Ratio tokens are not defined in the tokenizer." | |
| return f"<|img_ratio_{ratio_idx}|>" | |
| def ratio_token_id(self, ratio_idx: int): | |
| return self._sp_dict[self.ratio_token(ratio_idx)] | |
| def encode_text( | |
| self, | |
| *texts, | |
| uncond_enabled: Optional[bool | list[bool]] = None, | |
| uncond_p: Optional[float] = None, | |
| max_length: Optional[int] = None, | |
| pad: Optional[str] = None, | |
| ): | |
| if pad is not None: | |
| assert max_length is not None, "max_length should be provided when pad is not None." | |
| if uncond_enabled is None: | |
| uncond_enabled = [True] * len(texts) | |
| elif isinstance(uncond_enabled, bool): | |
| uncond_enabled = [uncond_enabled] * len(texts) | |
| assert len(uncond_enabled) == len(texts), ( | |
| f"Length of uncond_flags should be equal to the number of texts, " | |
| f"but got {len(uncond_enabled)} and {len(texts)}." | |
| ) | |
| do_uncond_drop = (uncond_p is not None) and (random.random() < uncond_p) | |
| text_tokens = [] | |
| cum_length = 0 | |
| for text, uncond_flag in zip(texts, uncond_enabled): | |
| if max_length is not None and cum_length >= max_length: | |
| break | |
| if isinstance(text, str): | |
| text_token = self.encode(text, add_special_tokens=False) | |
| else: | |
| text_token = text | |
| if uncond_flag and do_uncond_drop: | |
| text_token = [self.cfg_token_id] * len(text_token) | |
| if max_length is not None and (cum_length + len(text_token)) > max_length: | |
| text_token = text_token[:max_length - cum_length] | |
| text_tokens.extend(text_token) | |
| cum_length += len(text_token) | |
| if pad is not None and (pad_length := max_length - len(text_tokens)) > 0: | |
| if pad == 'left': | |
| text_tokens = [self.pad_token_id] * pad_length + text_tokens | |
| elif pad == 'right': | |
| text_tokens = text_tokens + [self.pad_token_id] * pad_length | |
| else: | |
| raise ValueError(f"Unsupported padding method: {pad}.") | |
| return text_tokens | |
| def _check_key_number_matched(keys, data): | |
| assert set(keys) == set(data.keys()), ( | |
| f"Keys in the template and token source should be matched, but got {keys} and {list(data.keys())}." | |
| ) | |
| key_counts = {k: 0 for k in keys} | |
| for key in keys: | |
| key_counts[key] += 1 | |
| for key, count in key_counts.items(): | |
| assert len(data[key]) == count, ( | |
| f"Number of `{key}` in the token source should be matched with the template, but got " | |
| f"{data[key]}({len(data[key])}) and {count}." | |
| ) | |
| def _add_meta_info_token( | |
| self, | |
| token_seq, | |
| token_count, | |
| extra_token_pos, | |
| add_timestep_token: bool = False, | |
| add_image_shape_token: bool = False, | |
| base_size=None, | |
| ratio_idx=None, | |
| token_height=None, | |
| token_width=None, | |
| image_type=None, | |
| media_type=None, | |
| und_token_type: list[str] = [], | |
| gen_token_type: list[str] = [], | |
| und_token_indices: list[int] = [], | |
| gen_token_indices: list[int] = [], | |
| token_count_start: int = 0, | |
| ): | |
| add_mot_indices = partial(self.process_mot_indices, und_token_indices=und_token_indices, gen_token_indices=gen_token_indices, und_token_type=und_token_type, gen_token_type=gen_token_type) | |
| if add_image_shape_token: | |
| token_seq.extend([self.size_token_id(base_size), self.ratio_token_id(ratio_idx)]) | |
| token_count += 2 | |
| add_mot_indices(token_type="vae_info", token_indices=list(range(token_count_start, token_count))) | |
| token_count_start = token_count | |
| if add_timestep_token: | |
| token_seq.extend([self.timestep_token_id]) | |
| extra_token_pos['timestep'].append(token_count) | |
| if media_type is not None: | |
| if media_type == "gen_image": | |
| extra_token_pos['gen_timestep'].append(token_count) | |
| elif media_type in ["cond_joint_image", "cond_vae_image"]: | |
| extra_token_pos['cond_timestep'].append(token_count) | |
| else: | |
| raise ValueError(f"Unsupported image type: {media_type}.") | |
| token_count += 1 | |
| add_mot_indices(token_type="vae", token_indices=list(range(token_count_start, token_count))) | |
| token_count_start = token_count | |
| return token_count, token_count_start | |
| def _shorten_text(self, text): | |
| text = re.sub(f"({self.img_token})+", lambda m: f"[{self.img_token}]{{{len(m.group(0)) // len(self.img_token)}}}", text) | |
| text = re.sub(f"({self.pad_token})+", lambda m: f"[{self.pad_token}]{{{len(m.group(0)) // len(self.pad_token)}}}", text) | |
| return text | |
| def process_mot_indices(token_type: str, token_indices: list[int], und_token_indices: list[int], gen_token_indices: list[int], und_token_type: list[str] = [], gen_token_type: list[str] = []): | |
| if token_type in und_token_type: | |
| und_token_indices.extend(token_indices) | |
| elif token_type in gen_token_type: | |
| gen_token_indices.extend(token_indices) | |
| def encode_sequence( | |
| self, | |
| template: str, | |
| token_source: dict[str, list[list[int] | dict[str, Any]]], | |
| total_length=None, | |
| add_eos=True, | |
| add_pad=True, | |
| add_bos=True, | |
| drop_last: str | bool = 'auto', | |
| add_image_shape_token=False, | |
| und_token_type: list[str] = [], | |
| gen_token_type: list[str] = [], | |
| ): | |
| if drop_last is True and total_length is None: | |
| raise ValueError("total_length should be provided when drop_last is True.") | |
| keys = template.split('-') | |
| index_indicator = {k: 0 for k in token_source} | |
| for k, v in token_source.items(): | |
| assert isinstance(v, (list, tuple)), ( | |
| f"Value of `{k}` in the token source should be a list or tuple, but got {type(v)}." | |
| ) | |
| self._check_key_number_matched(keys, token_source) | |
| token_seq = [] | |
| token_count = 0 | |
| extra_token_pos = defaultdict(list) | |
| und_token_indices = [] | |
| gen_token_indices = [] | |
| add_mot_indices = partial(self.process_mot_indices, und_token_indices=und_token_indices, gen_token_indices=gen_token_indices, und_token_type=und_token_type, gen_token_type=gen_token_type) | |
| if add_bos and self.bos_token_id is not None: | |
| token_seq.append(self.bos_token_id) | |
| add_mot_indices(token_type="bos", token_indices=[token_count]) | |
| token_count += 1 | |
| drop_last_break = False | |
| for i, key in enumerate(keys): | |
| source = token_source[key][index_indicator[key]] | |
| token_count_start = token_count | |
| if key == "text": | |
| token_seq.extend(source) | |
| extra_token_pos["<text>_start"].append(token_count) | |
| token_count += len(source) | |
| extra_token_pos["<text>_end"].append(token_count - 1) | |
| add_mot_indices(token_type="text", token_indices=list(range(token_count_start, token_count))) | |
| token_count_start = token_count | |
| elif key == "gen_image": | |
| extra_count = \ | |
| 2 \ | |
| + (1 if source['add_timestep_token'] else 0) \ | |
| + (2 if source['add_image_shape_token'] else 0) | |
| if drop_last is True and token_count + extra_count + source['length'] > total_length: | |
| drop_last_break = True | |
| break | |
| token_seq.append(self.boi_token_id) | |
| extra_token_pos["boi"].append(token_count) | |
| add_mot_indices(token_type="boi", token_indices=[token_count]) | |
| token_count += 1 | |
| token_count_start = token_count | |
| token_count, token_count_start = self._add_meta_info_token( | |
| token_seq=token_seq, | |
| token_count=token_count, | |
| extra_token_pos=extra_token_pos, | |
| add_timestep_token=source['add_timestep_token'], | |
| add_image_shape_token=source['add_image_shape_token'], | |
| base_size=source.get('base_size'), | |
| ratio_idx=source.get('ratio_idx'), | |
| token_height=source.get('token_height'), | |
| token_width=source.get('token_width'), | |
| image_type=key, | |
| media_type=key, | |
| und_token_type=und_token_type, | |
| gen_token_type=gen_token_type, | |
| und_token_indices=und_token_indices, | |
| gen_token_indices=gen_token_indices, | |
| token_count_start=token_count_start, | |
| ) | |
| token_seq.extend( | |
| [self.img_token_id] * source['length'] | |
| ) | |
| extra_token_pos["<img>_start"].append(token_count) | |
| extra_token_pos["<all_img>_start"].append(token_count) | |
| token_count += source['length'] | |
| extra_token_pos["<img>_end"].append(token_count - 1) | |
| extra_token_pos["<all_img>_end"].append(token_count - 1) | |
| add_mot_indices(token_type="vae", token_indices=list(range(token_count_start, token_count))) | |
| token_count_start = token_count | |
| token_seq.extend([self.eoi_token_id]) | |
| extra_token_pos["eoi"].append(token_count) | |
| add_mot_indices(token_type="eoi", token_indices=[token_count]) | |
| token_count += 1 | |
| token_count_start = token_count | |
| elif key == "cond_joint_image": | |
| assert isinstance(source['length'], list) and len( | |
| source['length']) == 2, "cond_joint_image length should be a list of two integers" | |
| extra_count = \ | |
| 2 + 1 \ | |
| + (1 if source['add_timestep_token'] else 0) \ | |
| + (2 if source['add_image_shape_token'] else 0) | |
| if drop_last is True and token_count + extra_count + sum(source['length']) > total_length: | |
| drop_last_break = True | |
| break | |
| token_seq.append(self.boi_token_id) | |
| extra_token_pos["boi"].append(token_count) | |
| token_count += 1 | |
| add_mot_indices(token_type="boi", token_indices=list(range(token_count_start, token_count))) | |
| token_count_start = token_count | |
| token_count, token_count_start = self._add_meta_info_token( | |
| token_seq=token_seq, | |
| token_count=token_count, | |
| extra_token_pos=extra_token_pos, | |
| add_timestep_token=source['add_timestep_token'], | |
| add_image_shape_token=source['add_image_shape_token'], | |
| base_size=source.get('base_size'), | |
| ratio_idx=source.get('ratio_idx'), | |
| token_height=source.get('token_height'), | |
| token_width=source.get('token_width'), | |
| image_type=key, | |
| media_type=key, | |
| und_token_type=und_token_type, | |
| gen_token_type=gen_token_type, | |
| und_token_indices=und_token_indices, | |
| gen_token_indices=gen_token_indices, | |
| token_count_start=token_count_start, | |
| ) | |
| token_seq.extend( | |
| [self.img_token_id] * source['length'][0] | |
| ) | |
| extra_token_pos["<vae_img>_start"].append(token_count) | |
| extra_token_pos["<joint_img>_start"].append(token_count) | |
| extra_token_pos["<all_img>_start"].append(token_count) | |
| token_count += source['length'][0] | |
| extra_token_pos["<vae_img>_end"].append(token_count - 1) | |
| extra_token_pos["<all_img>_end"].append(token_count - 1) | |
| add_mot_indices(token_type="vae", token_indices=list(range(token_count_start, token_count))) | |
| token_count_start = token_count | |
| token_seq.extend([self.joint_img_sep_token_id]) | |
| extra_token_pos["joint_img_sep"].append(token_count) | |
| add_mot_indices(token_type="joint_image_sep", token_indices=[token_count]) | |
| token_count += 1 | |
| token_count_start = token_count | |
| token_seq.extend( | |
| [self.img_token_id] * source['length'][1] | |
| ) | |
| extra_token_pos["<vit_img>_start"].append(token_count) | |
| extra_token_pos["<all_img>_start"].append(token_count) | |
| token_count += source['length'][1] | |
| extra_token_pos["<vit_img>_end"].append(token_count - 1) | |
| extra_token_pos["<joint_img>_end"].append(token_count - 1) | |
| extra_token_pos["<all_img>_end"].append(token_count - 1) | |
| add_mot_indices(token_type="vit", token_indices=list(range(token_count_start, token_count))) | |
| token_seq.extend( | |
| [self.eoi_token_id] | |
| ) | |
| extra_token_pos["eoi"].append(token_count) | |
| add_mot_indices(token_type="eoi", token_indices=[token_count]) | |
| token_count += 1 | |
| token_count_start = token_count | |
| elif key == "cond_vae_image": | |
| extra_count = \ | |
| 2 \ | |
| + (1 if source['add_timestep_token'] else 0) \ | |
| + (2 if source['add_image_shape_token'] else 0) | |
| if drop_last is True and token_count + extra_count + source['length'] > total_length: | |
| drop_last_break = True | |
| break | |
| token_seq.append(self.boi_token_id) | |
| extra_token_pos["boi"].append(token_count) | |
| add_mot_indices(token_type="boi", token_indices=[token_count]) | |
| token_count += 1 | |
| token_count_start = token_count | |
| token_count, token_count_start = self._add_meta_info_token( | |
| token_seq=token_seq, | |
| token_count=token_count, | |
| extra_token_pos=extra_token_pos, | |
| add_timestep_token=source['add_timestep_token'], | |
| add_image_shape_token=source['add_image_shape_token'], | |
| base_size=source.get('base_size'), | |
| ratio_idx=source.get('ratio_idx'), | |
| token_height=source.get('token_height'), | |
| token_width=source.get('token_width'), | |
| image_type=key, | |
| media_type=key, | |
| und_token_type=und_token_type, | |
| gen_token_type=gen_token_type, | |
| und_token_indices=und_token_indices, | |
| gen_token_indices=gen_token_indices, | |
| token_count_start=token_count_start, | |
| ) | |
| token_seq.extend( | |
| [self.img_token_id] * source['length'] | |
| ) | |
| extra_token_pos["<vae_img>_start"].append(token_count) | |
| extra_token_pos["<all_img>_start"].append(token_count) | |
| token_count += source['length'] | |
| extra_token_pos["<vae_img>_end"].append(token_count - 1) | |
| extra_token_pos["<all_img>_end"].append(token_count - 1) | |
| add_mot_indices(token_type="vae", token_indices=list(range(token_count_start, token_count))) | |
| token_seq.extend( | |
| [self.eoi_token_id] | |
| ) | |
| extra_token_pos["eoi"].append(token_count) | |
| add_mot_indices(token_type="eoi", token_indices=[token_count]) | |
| token_count += 1 | |
| token_count_start = token_count | |
| elif key == "cond_vit_image": | |
| extra_count = 2 | |
| if drop_last is True and token_count + extra_count + source['length'] > total_length: | |
| drop_last_break = True | |
| break | |
| token_seq.append(self.boi_token_id) | |
| add_mot_indices(token_type="boi", token_indices=[token_count]) | |
| token_count += 1 | |
| token_count_start = token_count | |
| token_seq.extend([self.img_token_id] * source['length']) | |
| extra_token_pos["<vit_img>_start"].append(token_count) | |
| extra_token_pos["<all_img>_start"].append(token_count) | |
| token_count += source['length'] | |
| extra_token_pos["<vit_img>_end"].append(token_count - 1) | |
| extra_token_pos["<all_img>_end"].append(token_count - 1) | |
| add_mot_indices(token_type="vit", token_indices=list(range(token_count_start, token_count))) | |
| token_count_start = token_count | |
| token_seq.append(self.eoi_token_id) | |
| extra_token_pos["eoi"].append(token_count) | |
| add_mot_indices(token_type="eoi", token_indices=[token_count]) | |
| token_count += 1 | |
| token_count_start = token_count | |
| else: | |
| raise ValueError(f"Not supported key: {key}") | |
| index_indicator[key] += 1 | |
| if add_eos is True and not drop_last_break: | |
| token_seq.append(self.eos_token_id) | |
| extra_token_pos["eos"].append(token_count) | |
| add_mot_indices(token_type="eos", token_indices=[token_count]) | |
| token_count += 1 | |
| token_count_start = token_count | |
| elif add_eos == 'auto' and not drop_last_break: | |
| if token_seq[-1] != self.eos_token_id and (total_length is None or token_count < total_length): | |
| token_seq.append(self.eos_token_id) | |
| extra_token_pos["eos"].append(token_count) | |
| add_mot_indices(token_type="eos", token_indices=[token_count]) | |
| token_count += 1 | |
| token_count_start = token_count | |
| if total_length: | |
| if token_count > total_length and drop_last: | |
| for start_key, end_key in [ | |
| ("<img>_start", "<img>_end"), ("<vae_img>_start", "<vae_img>_end"), | |
| ("<vit_img>_start", "<vit_img>_end"), ("<joint>_start", "<joint>_end"), | |
| ]: | |
| if start_key in extra_token_pos and end_key in extra_token_pos: | |
| assert all( | |
| (start > total_length or end + 1 < total_length) | |
| for start, end in zip(extra_token_pos[start_key], extra_token_pos[end_key]) | |
| ), ("Clip position should not be in the middle of the media tokens.\n" | |
| f"Below is the text:\n{self._shorten_text(self.decode(token_seq))}") | |
| token_seq = token_seq[:total_length] | |
| und_token_indices = [idx for idx in und_token_indices if idx < total_length] | |
| gen_token_indices = [idx for idx in gen_token_indices if idx < total_length] | |
| pad_num = max(0, total_length - len(token_seq)) | |
| if add_pad and pad_num: | |
| token_seq.extend([self.pad_token_id] * pad_num) | |
| extra_token_pos["first_pad"].append(token_count) | |
| add_mot_indices(token_type="pad", token_indices=list(range(token_count, token_count + pad_num))) | |
| if len(und_token_indices) > 0 and len(gen_token_indices) > 0: | |
| assert und_token_indices[-1] < len(token_seq) and gen_token_indices[-1] < len(token_seq), f"{und_token_indices[-1]=}, {gen_token_indices[-1]=}, {len(token_seq)=}" | |
| return token_seq, extra_token_pos, und_token_indices, gen_token_indices | |
| def parse_extra_token_pos(extra_token_pos, prefix, tokens, rng=None): | |
| if rng is None: | |
| rng = slice(None) | |
| image_slices = [ | |
| slice(start, end + 1) | |
| for start, end in zip(extra_token_pos[f'<{prefix}>_start'][rng], extra_token_pos[f'<{prefix}>_end'][rng]) | |
| ] if f'<{prefix}>_start' in extra_token_pos and f'<{prefix}>_end' in extra_token_pos else [] | |
| if image_slices: | |
| image_mask = torch.zeros_like(tokens, dtype=torch.bool) | |
| for image_slice in image_slices: | |
| image_mask[image_slice] = True | |
| else: | |
| image_mask = None | |
| return image_slices, image_mask | |
| def encode_general( | |
| self, | |
| sections: Optional[list[dict[str, Any]]] = None, | |
| max_token_length: Optional[int] = None, | |
| add_eos: bool | str = 'auto', | |
| use_text_mask: bool = True, | |
| add_pad: bool | str = 'auto', | |
| add_bos: bool = True, | |
| drop_last: bool | str = 'auto', | |
| und_token_type: list[str] = [], | |
| gen_token_type: list[str] = [], | |
| disable_ignore: bool = False, | |
| ): | |
| if sections is None: | |
| raise ValueError("sections must be provided.") | |
| template = '-'.join([section['type'] for section in sections]) | |
| sections = deepcopy(sections) | |
| token_source = defaultdict(list) | |
| text_mask_specs = [] | |
| for section in sections: | |
| if section['type'] == 'text': | |
| text = self.encode_text( | |
| section['text'] if 'text' in section else section['tokens'], | |
| uncond_enabled=section.get('uncond_enabled'), | |
| uncond_p=section.get('uncond_p'), | |
| max_length=section.get('max_length'), | |
| ) | |
| token_source['text'].append(text) | |
| text_mask_specs.append(dict( | |
| ignore=section.get('ignore', False), | |
| start_offset=section.get('start_offset', 0), | |
| end_offset=section.get('end_offset', 0), | |
| )) | |
| elif section['type'] == 'gen_image': | |
| token_source['gen_image'].append(dict( | |
| length=section['token_length'], | |
| add_timestep_token=section.get('add_timestep_token', False), | |
| add_image_shape_token=section.get('add_image_shape_token', False), | |
| base_size=section.get('base_size'), | |
| ratio_idx=section.get('ratio_idx'), | |
| token_height=section.get('token_height'), | |
| token_width=section.get('token_width'), | |
| )) | |
| elif section['type'] in ['cond_joint_image', 'cond_vae_image', 'cond_vit_image']: | |
| token_source[section['type']].append(dict( | |
| length=section['token_length'], | |
| add_timestep_token=section.get('add_timestep_token', False), | |
| add_image_shape_token=section.get('add_image_shape_token', False), | |
| base_size=section.get('base_size'), | |
| ratio_idx=section.get('ratio_idx'), | |
| token_height=section.get('token_height'), | |
| token_width=section.get('token_width'), | |
| )) | |
| else: | |
| raise ValueError(f"Invalid section type: {section['type']}") | |
| full_token_seq, extra_token_pos, und_token_indices, gen_token_indices = self.encode_sequence( | |
| template=template, | |
| token_source=dict(token_source), | |
| total_length=max_token_length, | |
| add_eos=add_eos, | |
| add_pad=add_pad, | |
| add_bos=add_bos, | |
| drop_last=drop_last, | |
| und_token_type=und_token_type, | |
| gen_token_type=gen_token_type, | |
| ) | |
| full_seq_token_tensor = torch.tensor(full_token_seq, dtype=torch.long) | |
| und_token_indices = torch.tensor(und_token_indices, dtype=torch.long) | |
| gen_token_indices = torch.tensor(gen_token_indices, dtype=torch.long) | |
| cond_timestep_scatter_index = torch.tensor(extra_token_pos['cond_timestep'], dtype=torch.long) \ | |
| if 'cond_timestep' in extra_token_pos else None | |
| gen_timestep_scatter_index = torch.tensor(extra_token_pos['gen_timestep'], dtype=torch.long) \ | |
| if 'gen_timestep' in extra_token_pos else None | |
| gen_image_slices, gen_image_mask = self.parse_extra_token_pos( | |
| extra_token_pos, 'img', full_seq_token_tensor) | |
| vae_image_slices, vae_image_mask = self.parse_extra_token_pos( | |
| extra_token_pos, 'vae_img', full_seq_token_tensor) | |
| vit_image_slices, vit_image_mask = self.parse_extra_token_pos( | |
| extra_token_pos, 'vit_img', full_seq_token_tensor) | |
| joint_image_slices, _ = self.parse_extra_token_pos( | |
| extra_token_pos, 'joint_img', full_seq_token_tensor) | |
| all_image_slices = [ | |
| slice(start, end + 1) | |
| for start, end in zip(extra_token_pos['<all_img>_start'], extra_token_pos['<all_img>_end']) | |
| ] if '<all_img>_start' in extra_token_pos and '<all_img>_end' in extra_token_pos else [] | |
| text_slices = [ | |
| slice(start, end + 1) | |
| for start, end in zip(extra_token_pos['<text>_start'], extra_token_pos['<text>_end']) | |
| ] if '<text>_start' in extra_token_pos and '<text>_end' in extra_token_pos else [] | |
| assert len(text_slices) <= len(text_mask_specs), \ | |
| (f"Number of text slices ({len(text_slices)}) should be less than or equal to " | |
| f"number of text mask specs ({len(text_mask_specs)})") | |
| if use_text_mask: | |
| text_mask = torch.zeros_like(full_seq_token_tensor, dtype=torch.float32) | |
| for text_slice, mask_spec in zip(text_slices, text_mask_specs): | |
| if not mask_spec['ignore'] or disable_ignore: | |
| real_slice = slice( | |
| text_slice.start + mask_spec['start_offset'], | |
| text_slice.stop + mask_spec['end_offset'] | |
| ) | |
| text_mask[real_slice] = 1.0 | |
| else: | |
| text_mask = None | |
| real_pos = torch.tensor(extra_token_pos.get('first_pad', [full_seq_token_tensor.shape[0]]), dtype=torch.long) | |
| if len(und_token_type) == 0 and len(gen_token_type) == 0: | |
| und_token_indices = None | |
| gen_token_indices = None | |
| return TokenizerEncodeOutput( | |
| tokens=full_seq_token_tensor, | |
| text_slices=text_slices, | |
| gen_image_slices=gen_image_slices, | |
| vae_image_slices=vae_image_slices, | |
| vit_image_slices=vit_image_slices, | |
| joint_image_slices=joint_image_slices, | |
| all_image_slices=all_image_slices, | |
| text_mask=text_mask, | |
| gen_image_mask=gen_image_mask, | |
| vae_image_mask=vae_image_mask, | |
| vit_image_mask=vit_image_mask, | |
| real_pos=real_pos, | |
| cond_timestep_scatter_index=cond_timestep_scatter_index, | |
| gen_timestep_scatter_index=gen_timestep_scatter_index, | |
| und_token_indices=und_token_indices, | |
| gen_token_indices=gen_token_indices, | |
| ) | |
| def apply_general_template( | |
| self, | |
| message_list, | |
| conv_template, | |
| max_length=None, | |
| add_assistant_prefix=False, | |
| answer="auto", | |
| bot_task="auto", | |
| sequence_template="instruct", | |
| uncond_p=0.0, | |
| cfg_factor=1, | |
| batchify=False, | |
| image_base_size=None, | |
| und_token_type=None, | |
| gen_token_type=None, | |
| use_text_mask=False, | |
| ): | |
| if bot_task == "img_ratio": | |
| assert image_base_size is not None, "image_base_size should be provided for img_ratio task." | |
| if batchify: | |
| assert isinstance(message_list[0], list), \ | |
| f"When batchify is True, message_list should be a list of list, but got [{type(message_list[0])}, ...]." | |
| return self.batch_gen_infer( | |
| infer_fn=self.apply_general_template, | |
| infer_fn_kwargs_list=[dict( | |
| message_list=message_list_i, | |
| conv_template=conv_template, | |
| max_length=max_length, | |
| add_assistant_prefix=add_assistant_prefix, | |
| answer=answer, | |
| bot_task=bot_task, | |
| sequence_template=sequence_template, | |
| image_base_size=image_base_size, | |
| und_token_type=und_token_type, | |
| gen_token_type=gen_token_type, | |
| use_text_mask=use_text_mask, | |
| ) for message_list_i in message_list], | |
| do_classifier_free_guidance=cfg_factor > 1, | |
| uncondition_repeat_times=cfg_factor - 1, | |
| und_token_type=und_token_type, | |
| gen_token_type=gen_token_type, | |
| ) | |
| uncond_kwargs = dict( | |
| uncond_enabled=uncond_p == 1.0, | |
| uncond_p=uncond_p, | |
| ) | |
| def process_successive_message(_message_list, _cur_message_idx, role, prefix, suffix, | |
| answer_prefix="", answer_suffix=""): | |
| _sub_sections = [] | |
| while _cur_message_idx < len(message_list) and _message_list[_cur_message_idx]['role'] == role: | |
| message = _message_list[_cur_message_idx] | |
| if message['type'] == 'text': | |
| text = message['content'] | |
| if role == "system": | |
| _sub_sections.append(dict(type="text", text=text)) | |
| elif role == "assistant": | |
| _sub_sections.append(dict( | |
| type="text", text=f"{answer_prefix}{text}{answer_suffix}", **uncond_kwargs)) | |
| else: | |
| _sub_sections.append(dict(type="text", text=text, **uncond_kwargs)) | |
| elif message['type'] == 'gen_image': | |
| info = message['content'] | |
| assert isinstance(info, ImageInfo), f"Expected ImageInfo, but got {type(info)}" | |
| if role == "assistant": | |
| _sub_sections.append(dict(type="text", text=answer_prefix)) | |
| _sub_sections.append(dict(type=message['type'], **info.meta_info)) | |
| if role == "assistant": | |
| _sub_sections.append(dict(type="text", text=answer_suffix)) | |
| elif message['type'] in ['cond_joint_image', 'cond_vae_image', 'cond_vit_image']: | |
| info = message['content'] | |
| assert isinstance(info, (ImageInfo, JointImageInfo)), \ | |
| f"Expected ImageInfo or JointImageInfo, but got {type(info)}" | |
| _sub_sections.append(dict(type=message['type'], **info.meta_info)) | |
| else: | |
| raise ValueError(f"Unknown message type: {message['type']}") | |
| _cur_message_idx += 1 | |
| if len(_sub_sections) > 0: | |
| _sub_sections.insert(0, dict(type='text', text=prefix)) | |
| _sub_sections.append(dict(type='text', text=suffix)) | |
| return _sub_sections, _cur_message_idx | |
| if (answer == "auto" and sequence_template == "instruct") or answer is True: | |
| answer_prefix, answer_suffix = self.answer_token, self.end_of_answer_token | |
| else: | |
| answer_prefix, answer_suffix = "", "" | |
| if sequence_template == "pretrain": | |
| system_suffix = conv_template.pretrain_sep_sp | |
| user_prefix = conv_template.get_role_prefix(conv_template.pretrain_roles[0]) | |
| user_suffix = conv_template.pretrain_sep | |
| bot_prefix = conv_template.get_role_prefix(conv_template.pretrain_roles[1]) | |
| bot_suffix = conv_template.pretrain_sep2 | |
| else: | |
| system_suffix = conv_template.sep_sp | |
| user_prefix = conv_template.get_role_prefix(conv_template.roles[0]) | |
| user_suffix = f"{conv_template.sep}" | |
| bot_prefix = conv_template.get_role_prefix(conv_template.roles[1]) | |
| bot_suffix = f"{conv_template.sep2}" | |
| sections = [] | |
| cur_message_idx = 0 | |
| final_role = None | |
| while cur_message_idx < len(message_list): | |
| sub_sections, cur_message_idx = process_successive_message( | |
| message_list, cur_message_idx, role="system", prefix="", suffix=system_suffix) | |
| sections.extend(sub_sections) | |
| if len(sub_sections) > 0: | |
| final_role = "system" | |
| sub_sections, cur_message_idx = process_successive_message( | |
| message_list, cur_message_idx, role="user", prefix=user_prefix, suffix=user_suffix) | |
| sections.extend(sub_sections) | |
| if len(sub_sections) > 0: | |
| final_role = "user" | |
| sub_sections, cur_message_idx = process_successive_message( | |
| message_list, cur_message_idx, role="assistant", prefix=bot_prefix, suffix=bot_suffix, | |
| answer_prefix=answer_prefix, answer_suffix=answer_suffix, | |
| ) | |
| sections.extend(sub_sections) | |
| if len(sub_sections) > 0: | |
| final_role = "assistant" | |
| if add_assistant_prefix: | |
| if final_role == "assistant": | |
| _bot_prefix = "" | |
| if len(sections) > 0 and sections[-1]['type'] == 'text' and sections[-1]['text'] == bot_suffix: | |
| sections = sections[:-1] | |
| else: | |
| _bot_prefix = bot_prefix | |
| bot_response_prefix = dict( | |
| auto=lambda: f"{_bot_prefix}{answer_prefix}", | |
| image=lambda: "", | |
| img_ratio=lambda: f"{_bot_prefix}{answer_prefix}{self.boi_token}{self.size_token(image_base_size)}", | |
| )[bot_task]() | |
| sections.append(dict(type='text', text=bot_response_prefix)) | |
| if und_token_type is None: | |
| und_token_type = [] | |
| if gen_token_type is None: | |
| gen_token_type = [] | |
| output = self.encode_general( | |
| sections=sections, | |
| use_text_mask=use_text_mask, | |
| add_eos=conv_template.add_eos, | |
| add_pad=conv_template.add_pad, | |
| add_bos=conv_template.add_bos, | |
| und_token_type=und_token_type, | |
| gen_token_type=gen_token_type, | |
| ) | |
| if max_length is not None: | |
| if output.tokens.shape[-1] > max_length: | |
| raise ValueError( | |
| f"Encoded token length {output.tokens.shape[-1]} exceeds max_length {max_length}.\n" | |
| f"Please set a larger max_length or check the input messages:\n{message_list}" | |
| ) | |
| return output, sections | |
| def apply_chat_template( | |
| self, | |
| batch_prompt: Optional[list[str]] = None, | |
| batch_message_list: Optional[list[list[dict[str, Any]]]] = None, | |
| mode: str = "gen_text", | |
| batch_gen_image_info: Optional[list[ImageInfo]] = None, | |
| batch_cond_images: Optional[Union[list[CondImage], list[list[CondImage]]]] = None, | |
| max_length: Optional[int] = None, | |
| bot_task: str = "auto", | |
| image_base_size: Optional[int] = None, | |
| sequence_template: str = "pretrain", | |
| cfg_factor: int = 1, | |
| add_assistant_prefix: Optional[bool] = None, | |
| conv_template: Optional[Conversation] = None, | |
| und_token_type: list[str] = None, | |
| gen_token_type: list[str] = None, | |
| use_text_mask: bool = False, | |
| **kwargs, | |
| ) -> dict[str, Any]: | |
| allowed_tasks = ["image", "auto", "img_ratio"] | |
| assert bot_task in allowed_tasks, f"bot_task should be one of {allowed_tasks}, but got {bot_task}." | |
| if batch_message_list is None: | |
| batch_size = len(batch_prompt) | |
| if not isinstance(batch_gen_image_info, list): | |
| batch_gen_image_info = [batch_gen_image_info] * batch_size | |
| if batch_cond_images is not None: | |
| assert len(batch_cond_images) == batch_size, \ | |
| (f"batch_cond_image_info should have the same length as batch_size ({batch_size}), " | |
| f"but got {len(batch_cond_images)}.") | |
| batch_cond_images = [ | |
| cond_images if isinstance(cond_images, list) else [cond_images] | |
| for cond_images in batch_cond_images | |
| ] | |
| else: | |
| batch_cond_images = [[] for _ in range(batch_size)] | |
| batch_message_list = [] | |
| for prompt, gen_image_info, cond_images in zip( | |
| batch_prompt, batch_gen_image_info, | |
| batch_cond_images, | |
| ): | |
| message_list = [] | |
| if len(cond_images) > 0: | |
| message_list.extend([ | |
| dict(role="user", type=cond_image.section_type, content=cond_image.i) | |
| for cond_image in cond_images | |
| ]) | |
| message_list.append(dict(role="user", type="text", content=prompt)) | |
| if mode == "gen_image": | |
| message_list.append(dict( | |
| role="assistant", type="gen_image", content=gen_image_info)) | |
| batch_message_list.append(message_list) | |
| output, sections = self.apply_general_template( | |
| message_list=batch_message_list, | |
| conv_template=conv_template, | |
| max_length=max_length, | |
| add_assistant_prefix=default(add_assistant_prefix, mode == "gen_text"), | |
| bot_task=bot_task, | |
| sequence_template=sequence_template, | |
| cfg_factor=cfg_factor, | |
| batchify=True, | |
| image_base_size=image_base_size, | |
| und_token_type=und_token_type, | |
| gen_token_type=gen_token_type, | |
| use_text_mask=use_text_mask, | |
| **kwargs, | |
| ) | |
| return dict(output=output, sections=sections) | |
| def pad(self, tensor_list, dim=0, pad_val=None, key=None): | |
| if pad_val is None: | |
| pad_val = self.pad_token_id | |
| max_len = max([t.shape[dim] for t in tensor_list]) | |
| padded_tensor_list = [] | |
| for t in tensor_list: | |
| if t.shape[dim] < max_len: | |
| assert pad_val is not False, f"Not allowed/implemented pad for key: {key}" | |
| t = F.pad(t, (0, max_len - t.shape[dim]), value=pad_val) | |
| padded_tensor_list.append(t) | |
| return padded_tensor_list | |
| def batch_gen_infer( | |
| self, | |
| infer_fn, | |
| infer_fn_kwargs_list: list[dict[str, int]] = None, | |
| do_classifier_free_guidance=False, | |
| uncondition_repeat_times: int = 1, | |
| und_token_type: Optional[list] = None, | |
| gen_token_type: Optional[list] = None, | |
| ): | |
| cond_results_list = None | |
| uncond_results_list = None | |
| for infer_fn_kwargs in infer_fn_kwargs_list: | |
| cond_kwargs = {"uncond_p": 0.0} if do_classifier_free_guidance else {} | |
| results = infer_fn( | |
| **infer_fn_kwargs, | |
| **cond_kwargs, | |
| ) | |
| assert isinstance(results, tuple), f"Expected tuple output from tokenizer template, got {type(results)}." | |
| if cond_results_list is None: | |
| cond_results_list = [[] for _ in results] | |
| uncond_results_list = [[] for _ in results] | |
| for i, result in enumerate(results): | |
| cond_results_list[i].append(result) | |
| if do_classifier_free_guidance: | |
| uncond_results = infer_fn( | |
| **infer_fn_kwargs, | |
| uncond_p=1.0, | |
| ) | |
| if isinstance(uncond_results, TokenizerEncodeOutput): | |
| uncond_results_list.append(uncond_results) | |
| else: | |
| for i, result in enumerate(uncond_results): | |
| uncond_results_list[i].append(result) | |
| def make_batch(batch_cond_item, batch_uncond_item): | |
| first = batch_cond_item[0] | |
| if isinstance(first, (list, tuple)): | |
| stacked_item = batch_cond_item + batch_uncond_item * uncondition_repeat_times | |
| elif isinstance(first, TokenizerEncodeOutput): | |
| stacked_item = {} | |
| for key in list(first.keys()): | |
| merged_list = [cond_item[key] for cond_item in batch_cond_item] + \ | |
| [uncond_item[key] for uncond_item in batch_uncond_item] * uncondition_repeat_times | |
| if isinstance(first[key], torch.Tensor): | |
| if 'mask' in key: | |
| pad_val = 0.0 | |
| elif key == 'tokens': | |
| pad_val = self.pad_token_id | |
| elif key in ['und_token_indices', 'gen_token_indices']: | |
| continue | |
| else: | |
| pad_val = False | |
| if key not in ('und_token_indices', 'gen_token_indices'): | |
| stacked_item[key] = torch.stack(self.pad(merged_list, pad_val=pad_val, key=key), dim=0) | |
| elif isinstance(first[key], list): | |
| stacked_item[key] = merged_list | |
| elif first[key] is None: | |
| pass | |
| else: | |
| raise ValueError(f"Unsupported type of {key}: {type(first[key])}.") | |
| stacked_item = TokenizerEncodeOutput(stacked_item) | |
| if 'und_token_indices' in first.keys() and first['und_token_indices'] is not None and 'gen_token_indices' in first.keys() and first['gen_token_indices'] is not None: | |
| und_token_indices_merged_list = [cond_item['und_token_indices'] for cond_item in batch_cond_item] + [uncond_item['und_token_indices'] for uncond_item in batch_uncond_item] * uncondition_repeat_times | |
| gen_token_indices_merged_list = [cond_item['gen_token_indices'] for cond_item in batch_cond_item] + [uncond_item['gen_token_indices'] for uncond_item in batch_uncond_item] * uncondition_repeat_times | |
| sequence_length = stacked_item["tokens"].shape[1] | |
| def _safe_max_index(indices): | |
| return indices.max().item() if indices.numel() > 0 else -1 | |
| max_index = [ | |
| max( | |
| _safe_max_index(und_token_indices_merged_list[i]), | |
| _safe_max_index(gen_token_indices_merged_list[i]), | |
| ) | |
| for i in range(len(und_token_indices_merged_list)) | |
| ] | |
| for i, (und_token_indices_item, max_index_item) in enumerate(zip(und_token_indices_merged_list, max_index)): | |
| if max_index_item == sequence_length - 1: | |
| continue | |
| und_token_indices_merged_list[i] = torch.cat([und_token_indices_item, torch.arange(max_index_item + 1, sequence_length)]) | |
| max_gen_count = max(g.shape[0] for g in gen_token_indices_merged_list) | |
| max_extra_needed = 0 | |
| for i in range(len(gen_token_indices_merged_list)): | |
| pad_needed = max_gen_count - gen_token_indices_merged_list[i].shape[0] | |
| pad_available = max(0, sequence_length - 1 - max_index[i]) | |
| max_extra_needed = max(max_extra_needed, pad_needed - pad_available) | |
| if max_extra_needed > 0: | |
| for key in list(stacked_item.keys()): | |
| if key == 'tokens': | |
| stacked_item[key] = F.pad(stacked_item[key], (0, max_extra_needed), value=self.pad_token_id) | |
| elif 'mask' in key and isinstance(stacked_item[key], torch.Tensor): | |
| stacked_item[key] = F.pad(stacked_item[key], (0, max_extra_needed), value=0.0) | |
| new_positions = torch.arange(sequence_length, sequence_length + max_extra_needed) | |
| for i in range(len(und_token_indices_merged_list)): | |
| und_token_indices_merged_list[i] = torch.cat([und_token_indices_merged_list[i], new_positions]) | |
| sequence_length += max_extra_needed | |
| for i in range(len(gen_token_indices_merged_list)): | |
| pad_needed = max_gen_count - gen_token_indices_merged_list[i].shape[0] | |
| if pad_needed > 0: | |
| moved = und_token_indices_merged_list[i][-pad_needed:] | |
| und_token_indices_merged_list[i] = und_token_indices_merged_list[i][:-pad_needed] | |
| gen_token_indices_merged_list[i] = torch.cat([gen_token_indices_merged_list[i], moved]) | |
| stacked_item['und_token_indices'] = torch.stack(und_token_indices_merged_list, dim=0) | |
| stacked_item['gen_token_indices'] = torch.stack(gen_token_indices_merged_list, dim=0) | |
| elif ('und_token_indices' in first.keys() and first['und_token_indices'] is not None) or ('gen_token_indices' in first.keys() and first['gen_token_indices'] is not None): | |
| raise ValueError(f"Only one of 'und_token_indices' and 'gen_token_indices' exists.") | |
| stacked_item = TokenizerEncodeOutput(stacked_item) | |
| else: | |
| raise TypeError(f"Making batch on type {type(first)} is not supported.") | |
| return stacked_item | |
| stacked_outputs = [] | |
| for cond_results, uncond_results in zip(cond_results_list, uncond_results_list): | |
| stacked_outputs.append(make_batch(cond_results, uncond_results)) | |
| return tuple(stacked_outputs) | |
| class Qwen3BaseTokenizerFast(BaseMultimodalTokenizerFast): | |
| def setup_special_tokens(self): | |
| predefined_name_mapping = { | |
| "bos": "<|im_start|>", | |
| "eos": "<|im_end|>", | |
| "answer": "", | |
| "end_of_answer": "", | |
| "boi": "<|vision_start|>", | |
| "eoi": "<|vision_end|>", | |
| "img": "<|image_pad|>", | |
| } | |
| for name, mapping in predefined_name_mapping.items(): | |
| setattr(self, f"{name}_token", mapping) | |
| setattr(self, f"{name}_token_id", self.convert_tokens_to_ids(mapping)) | |
| if len(self._sp_dict) > 0: | |
| name_mapping = dict( | |
| cfg_token="<|cfg|>", | |
| timestep_token="<|timestep|>", | |
| joint_img_sep_token="<|joint_img_sep|>", | |
| ) | |
| for name, token in name_mapping.items(): | |
| setattr(self, name, token) | |
| setattr(self, f"{name}_id", self._sp_dict.get(token)) | |
| def load_tokenizer( | |
| tokenizer_name: str, | |
| tokenizer_class: str, | |
| ) -> "BaseMultimodalTokenizerFast": | |
| assert '.' in tokenizer_class, ( | |
| f"Invalid tokenizer class: {tokenizer_class}. A valid tokenizer name should be in the form of " | |
| f"<module_name>.<tokenizer_cls>." | |
| ) | |
| if tokenizer_class.startswith("transformers."): | |
| module_name, tokenizer_cls = tokenizer_class.rsplit('.', 1) | |
| module_spec = importlib.import_module(module_name) | |
| TokenizerSpec = getattr(module_spec, tokenizer_cls) # noqa | |
| else: | |
| module_name, tokenizer_cls = tokenizer_class.rsplit('.', 1) | |
| if module_name == "tokenizer": | |
| module_spec = importlib.import_module("rosetta.tokenizer") | |
| else: | |
| module_spec = importlib.import_module(module_name) | |
| TokenizerSpec = getattr(module_spec, tokenizer_cls) # noqa | |
| if tokenizer_name in TOKENIZER_PATH: | |
| tokenizer_name = TOKENIZER_PATH[tokenizer_name] | |
| return TokenizerSpec.from_pretrained(tokenizer_name) | |