2024-07-08 10:07:36 +08:00

151 lines
5.9 KiB
Python

import comfy.supported_models_base
import comfy.latent_formats
import comfy.model_patcher
import comfy.model_base
import comfy.utils
from .hydit.modules.text_encoder import MT5Embedder
from transformers import BertModel, BertTokenizer, AutoTokenizer
import torch
import os
from transformers import BertConfig, BertModel
from transformers import AutoTokenizer, modeling_utils
#import pdb
class CLIP:
def __init__(self, root, text_encoder_path = None, t5_text_encoder_path = None):
self.device = "cuda" if torch.cuda.is_available() else "cpu"
if text_encoder_path == None:
text_encoder_path = os.path.join(root,"clip_text_encoder")
clip_text_encoder = BertModel.from_pretrained(str(text_encoder_path), False, revision=None).to(self.device)
else:
config = BertConfig.from_json_file(os.path.join(os.path.dirname(os.path.realpath(__file__)),"config_clip.json"))
with modeling_utils.no_init_weights():
clip_text_encoder = BertModel(config)
sd = comfy.utils.load_torch_file(text_encoder_path)
prefix = "bert."
state_dict = {}
for key in sd:
nkey = key
if key.startswith(prefix):
nkey = key[len(prefix):]
state_dict[nkey] = sd[key]
m, e = clip_text_encoder.load_state_dict(state_dict, strict=False)
if len(m) > 0 or len(e) > 0:
print(f"HYDiT: clip missing {len(m)} keys ({len(e)} extra)")
#clip_text_encoder.load_state_dict(sd, strict=False)
clip_text_encoder.eval().to(self.device)
tokenizer_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "tokenizer_clip")
self.tokenizer = HyBertTokenizer(tokenizer_path)
#assert(0)
if t5_text_encoder_path == None:
t5_text_encoder_path = os.path.join(root,'mt5')
embedder_t5 = MT5Embedder(t5_text_encoder_path, torch_dtype=torch.float16, max_length=256)
self.tokenizer_t5 = HyT5Tokenizer(embedder_t5.tokenizer, max_length=embedder_t5.max_length)
self.embedder_t5 = embedder_t5.model
else:
embedder_t5 = MT5Embedder(t5_text_encoder_path, torch_dtype=torch.float16, max_length=256, ksampler=True)
self.tokenizer_t5 = HyT5Tokenizer(embedder_t5.tokenizer, max_length=embedder_t5.max_length)
self.embedder_t5 = embedder_t5.model
self.cond_stage_model = clip_text_encoder
def tokenize(self, text):
tokens = self.tokenizer.tokenize(text)
t5_tokens = self.tokenizer_t5.tokenize(text)
tokens.update(t5_tokens)
return tokens
def tokenize_t5(self, text):
return self.tokenizer_t5.tokenize(text)
def encode_from_tokens(self, tokens, return_pooled=False):
attention_mask = tokens['attention_mask'].to(self.device)
with torch.no_grad():
prompt_embeds = self.cond_stage_model(
tokens['text_input_ids'].to(self.device),
attention_mask=attention_mask
)
prompt_embeds = prompt_embeds[0]
t5_attention_mask = tokens['t5_attention_mask'].to(self.device)
with torch.no_grad():
t5_prompt_cond = self.embedder_t5(
tokens['t5_text_input_ids'].to(self.device),
attention_mask=t5_attention_mask
)
t5_embeds = t5_prompt_cond[0]
addit_embeds = {
"t5_embeds": t5_embeds,
"attention_mask": attention_mask.float(),
"t5_attention_mask": t5_attention_mask.float()
}
prompt_embeds.addit_embeds = addit_embeds
if return_pooled:
return prompt_embeds, None
else:
return prompt_embeds
class HyBertTokenizer:
def __init__(self, tokenizer_path=None, max_length=77, truncation=True, return_attention_mask=True, device='cpu'):
self.tokenizer = BertTokenizer.from_pretrained(str(tokenizer_path))
self.max_length = self.tokenizer.model_max_length or max_length
self.truncation = truncation
self.return_attention_mask = return_attention_mask
self.device = device
def tokenize(self, text:str):
text_inputs = self.tokenizer(
text,
padding="max_length",
max_length=self.max_length,
truncation=self.truncation,
return_attention_mask=self.return_attention_mask,
add_special_tokens = True,
return_tensors="pt",
)
text_input_ids = text_inputs.input_ids
attention_mask = text_inputs.attention_mask
tokens = {
'text_input_ids': text_input_ids,
'attention_mask': attention_mask
}
return tokens
class HyT5Tokenizer:
def __init__(self, tokenizer, tokenizer_path = None, max_length=77, truncation=True, return_attention_mask=True, device='cpu'):
if tokenizer_path:
self.tokenizer = AutoTokenizer.from_pretrained(str(tokenizer_path))
else:
self.tokenizer = tokenizer
self.max_length = max_length
self.truncation = truncation
self.return_attention_mask = return_attention_mask
self.device = device
def tokenize(self, text:str):
text_inputs = self.tokenizer(
text,
padding="max_length",
max_length=self.max_length,
truncation=self.truncation,
return_attention_mask=self.return_attention_mask,
add_special_tokens = True,
return_tensors="pt",
)
text_input_ids = text_inputs.input_ids
attention_mask = text_inputs.attention_mask
tokens = {
't5_text_input_ids': text_input_ids,
't5_attention_mask': attention_mask
}
return tokens