192 lines
7.0 KiB
Python
192 lines
7.0 KiB
Python
import os
|
|
import requests
|
|
import torch
|
|
import folder_paths
|
|
from transformers import VisionEncoderDecoderModel, ViTImageProcessor, AutoTokenizer
|
|
from transformers import AutoProcessor, AutoModelForVision2Seq, AutoModelForCausalLM
|
|
from transformers import BlipProcessor, BlipForConditionalGeneration
|
|
from groq import Groq
|
|
from .image import MS_Image_v2 as MS_Image
|
|
|
|
from ...utils.log import log
|
|
|
|
# class MS_Llm_NYU():
|
|
# # https://github.com/cambrian-mllm/cambrian/blob/main/inference.py
|
|
|
|
class MS_Llm_Microsoft():
|
|
|
|
@classmethod
|
|
def __init__(self, model_name = "microsoft/Florence-2-large"):
|
|
self.name = model_name
|
|
if model_name == 'microsoft/kosmos-2-patch14-224':
|
|
self.model = AutoModelForVision2Seq.from_pretrained(self.name)
|
|
else:
|
|
self.model = AutoModelForCausalLM.from_pretrained(self.name)
|
|
self.processor = AutoProcessor.from_pretrained(self.name)
|
|
|
|
@classmethod
|
|
def generate_prompt(self, image):
|
|
|
|
_image = MS_Image.tensor2pil(image)
|
|
|
|
# Generate the caption
|
|
if self.name == 'microsoft/kosmos-2-patch14-224':
|
|
prompt_prefix = "<grounding>"
|
|
inputs = self.processor(text=prompt_prefix, images=_image, return_tensors="pt")
|
|
generated_ids = self.model.generate(
|
|
pixel_values=inputs["pixel_values"],
|
|
input_ids=inputs["input_ids"],
|
|
attention_mask=inputs["attention_mask"],
|
|
image_embeds=None,
|
|
image_embeds_position_mask=inputs["image_embeds_position_mask"],
|
|
use_cache=True,
|
|
max_new_tokens=128,
|
|
)
|
|
generated_text = self.processor.batch_decode(generated_ids, skip_special_tokens=True)[0]
|
|
caption, _ = self.processor.post_process_generation(generated_text)
|
|
|
|
else:
|
|
prompt = "<MORE_DETAILED_CAPTION>"
|
|
inputs = self.processor(text=prompt, images=_image, return_tensors="pt")
|
|
generated_ids = self.model.generate(
|
|
input_ids=inputs["input_ids"],
|
|
pixel_values=inputs["pixel_values"],
|
|
max_new_tokens=1024,
|
|
num_beams=3,
|
|
do_sample=False
|
|
)
|
|
generated_text = self.processor.batch_decode(generated_ids, skip_special_tokens=False)[0]
|
|
caption = self.processor.post_process_generation(generated_text, task=prompt, image_size=(_image.width, _image.height))
|
|
|
|
return caption
|
|
|
|
|
|
class MS_Llm_Salesforce():
|
|
|
|
@classmethod
|
|
def __init__(self, model_name = "Salesforce/blip-image-captioning-large"):
|
|
self.name = model_name
|
|
self.model = BlipForConditionalGeneration.from_pretrained(self.name)
|
|
self.processor = BlipProcessor.from_pretrained(self.name)
|
|
|
|
@classmethod
|
|
def generate_prompt(self, image):
|
|
|
|
prompt_prefix = "<grounding>"
|
|
|
|
_image = MS_Image.tensor2pil(image)
|
|
|
|
inputs = self.processor(text=prompt_prefix, images=_image, return_tensors="pt")
|
|
|
|
# Generate the caption
|
|
generated_ids = self.model.generate(**inputs)
|
|
caption = self.processor.decode(generated_ids[0], skip_special_tokens=True)
|
|
|
|
return caption
|
|
|
|
class MS_Llm_Nlpconnect():
|
|
|
|
@classmethod
|
|
def __init__(self, model_name = "nlpconnect/vit-gpt2-image-captioning"):
|
|
self.name = model_name
|
|
self.model = VisionEncoderDecoderModel.from_pretrained(self.name)
|
|
self.processor = ViTImageProcessor.from_pretrained(self.name)
|
|
self.tokenizer = AutoTokenizer.from_pretrained(self.name)
|
|
|
|
@classmethod
|
|
def generate_prompt(self, image):
|
|
|
|
_image = MS_Image.tensor2pil(image)
|
|
inputs = self.processor(images=_image, return_tensors="pt")
|
|
# Generate the caption
|
|
generated_ids = self.model.generate(
|
|
inputs.pixel_values,
|
|
max_length=16,
|
|
num_beams=4,
|
|
num_return_sequences=1
|
|
)
|
|
caption = self.tokenizer.decode(generated_ids[0], skip_special_tokens=True)
|
|
|
|
return caption
|
|
|
|
class MS_Llm():
|
|
|
|
LLM_MODELS = [
|
|
# 'gemma-7b-it',
|
|
'llama3-70b-8192',
|
|
# 'llama3-8b-8192',
|
|
# 'mixtral-8x7b-32768',
|
|
]
|
|
|
|
# list of model https://huggingface.co/models?pipeline_tag=image-to-text&sort=downloads
|
|
VISION_LLM_MODELS = [
|
|
# 'nlpconnect/vit-gpt2-image-captioning',
|
|
'microsoft/Florence-2-large',
|
|
# 'microsoft/kosmos-2-patch14-224',
|
|
# 'Salesforce/blip-image-captioning-large',
|
|
]
|
|
|
|
@staticmethod
|
|
def prestartup_script():
|
|
folder_paths.add_model_folder_path("nlpconnect", os.path.join(folder_paths.models_dir, "nlpconnect"))
|
|
|
|
@classmethod
|
|
def __init__(self, vision_llm_name = "nlpconnect/vit-gpt2-image-captioning", llm_name = "llama3-8b-8192"):
|
|
|
|
if vision_llm_name == 'microsoft/kosmos-2-patch14-224':
|
|
self.vision_llm = MS_Llm_Microsoft()
|
|
elif vision_llm_name == 'Salesforce/blip-image-captioning-large':
|
|
self.vision_llm = MS_Llm_Salesforce()
|
|
else:
|
|
self.vision_llm = MS_Llm_Nlpconnect()
|
|
|
|
self._groq_key = os.getenv("GROQ_API_KEY", "")
|
|
self.llm = llm_name
|
|
|
|
@classmethod
|
|
def generate_tile_prompt(self, image, prompt_context, seed=None):
|
|
prompt_tile = self.vision_llm.generate_prompt(image)
|
|
if self.vision_llm.name == 'microsoft/kosmos-2-patch14-224':
|
|
_prompt = self.get_grok_prompt(prompt_context, prompt_tile)
|
|
else:
|
|
_prompt = self.get_grok_prompt(prompt_context, prompt_tile)
|
|
if self._groq_key != "":
|
|
prompt = self.call_grok_api(_prompt, seed)
|
|
else:
|
|
prompt = _prompt
|
|
log(prompt, None, None, self.vision_llm.name)
|
|
return prompt
|
|
|
|
|
|
@classmethod
|
|
def get_grok_prompt(self, prompt_context, prompt_tile):
|
|
prompt = [
|
|
f"tile_prompt: \"{prompt_tile}\".",
|
|
f"full_image_prompt: \"{prompt_context}\".",
|
|
"tile_prompt is part of full_image_prompt.",
|
|
"If tile_prompt is describing something different than the full image, correct tile_prompt to match full_image_prompt.",
|
|
"if you don't need to change the tile_prompt return the tile_prompt.",
|
|
"your answer will strictly and only return the tile_prompt string without any decoration like markdown syntax."
|
|
]
|
|
return " ".join(prompt)
|
|
|
|
@classmethod
|
|
def call_grok_api(self, prompt, seed=None):
|
|
|
|
client = Groq(api_key=self._groq_key) # Assuming the Groq client accepts an api_key parameter
|
|
completion = client.chat.completions.create(
|
|
model=self.llm,
|
|
messages=[{
|
|
"role": "user",
|
|
"content": prompt
|
|
}],
|
|
temperature=1,
|
|
max_tokens=1024,
|
|
top_p=1,
|
|
stream=False,
|
|
stop=None,
|
|
seed=seed,
|
|
)
|
|
|
|
return completion.choices[0].message.content
|