KModel is a torch.nn.Module with 2 main responsibilities: 1. Init weights, downloading config.json + model.pth from HF if needed 2. forward(phonemes: str, ref_s: FloatTensor) -> (audio: FloatTensor) You likely only need one KModel instance, and it can be reused across multiple
| 10 | import os |
| 11 | |
| 12 | class KModel(torch.nn.Module): |
| 13 | ''' |
| 14 | KModel is a torch.nn.Module with 2 main responsibilities: |
| 15 | 1. Init weights, downloading config.json + model.pth from HF if needed |
| 16 | 2. forward(phonemes: str, ref_s: FloatTensor) -> (audio: FloatTensor) |
| 17 | |
| 18 | You likely only need one KModel instance, and it can be reused across |
| 19 | multiple KPipelines to avoid redundant memory allocation. |
| 20 | |
| 21 | Unlike KPipeline, KModel is language-blind. |
| 22 | |
| 23 | KModel stores self.vocab and thus knows how to map phonemes -> input_ids, |
| 24 | so there is no need to repeatedly download config.json outside of KModel. |
| 25 | ''' |
| 26 | |
| 27 | MODEL_NAMES = { |
| 28 | 'hexgrad/Kokoro-82M': 'kokoro-v1_0.pth', |
| 29 | 'hexgrad/Kokoro-82M-v1.1-zh': 'kokoro-v1_1-zh.pth', |
| 30 | } |
| 31 | |
| 32 | def __init__( |
| 33 | self, |
| 34 | repo_id: Optional[str] = None, |
| 35 | config: Union[Dict, str, None] = None, |
| 36 | model: Optional[str] = None, |
| 37 | disable_complex: bool = False |
| 38 | ): |
| 39 | super().__init__() |
| 40 | if repo_id is None: |
| 41 | repo_id = 'hexgrad/Kokoro-82M' |
| 42 | print(f"WARNING: Defaulting repo_id to {repo_id}. Pass repo_id='{repo_id}' to suppress this warning.") |
| 43 | self.repo_id = repo_id |
| 44 | if not isinstance(config, dict): |
| 45 | if not config: |
| 46 | logger.debug("No config provided, downloading from HF") |
| 47 | config = hf_hub_download(repo_id=repo_id, filename='config.json') |
| 48 | with open(config, 'r', encoding='utf-8') as r: |
| 49 | config = json.load(r) |
| 50 | logger.debug(f"Loaded config: {config}") |
| 51 | self.vocab = config['vocab'] |
| 52 | self.bert = CustomAlbert(AlbertConfig(vocab_size=config['n_token'], **config['plbert'])) |
| 53 | self.bert_encoder = torch.nn.Linear(self.bert.config.hidden_size, config['hidden_dim']) |
| 54 | self.context_length = self.bert.config.max_position_embeddings |
| 55 | self.predictor = ProsodyPredictor( |
| 56 | style_dim=config['style_dim'], d_hid=config['hidden_dim'], |
| 57 | nlayers=config['n_layer'], max_dur=config['max_dur'], dropout=config['dropout'] |
| 58 | ) |
| 59 | self.text_encoder = TextEncoder( |
| 60 | channels=config['hidden_dim'], kernel_size=config['text_encoder_kernel_size'], |
| 61 | depth=config['n_layer'], n_symbols=config['n_token'] |
| 62 | ) |
| 63 | self.decoder = Decoder( |
| 64 | dim_in=config['hidden_dim'], style_dim=config['style_dim'], |
| 65 | dim_out=config['n_mels'], disable_complex=disable_complex, **config['istftnet'] |
| 66 | ) |
| 67 | if not model: |
| 68 | try: |
| 69 | model = hf_hub_download(repo_id=repo_id, filename=KModel.MODEL_NAMES[repo_id]) |