first commit
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
# ComfyUI-CLIPScore 🐱👤📊
|
||||
|
||||
**Research-grade CLIP Score node** for ComfyUI. Raw cosine similarity (-1 to +1) between prompts and Flux/SD images.
|
||||
|
||||
[](https://github.com/emniko/ComfyUI-CLIPScore)
|
||||
|
||||
## Features
|
||||
- ✅ **RGBA support** (VAE Decode → RGB auto)
|
||||
- ✅ **Batch-first** scoring
|
||||
- ✅ **Raw cosine scores** (0.25-0.35 = excellent)
|
||||
- ✅ **Flux/SD3/SDXL** ready
|
||||
|
||||
## Score Scale
|
||||
| Score | Rating | Example |
|
||||
| --------- | ----------- | -------------------- |
|
||||
| ≥0.30 | 🎖️ Excellent | Perfect prompt match |
|
||||
| 0.25-0.29 | 👍 Good | Strong alignment |
|
||||
| 0.20-0.24 | ⚠️ Fair | Usable |
|
||||
| <0.20 | ❌ Poor | Mismatch |
|
||||
|
||||
## Install
|
||||
```bash
|
||||
cd ComfyUI/custom_nodes
|
||||
git clone https://github.com/yourusername/ComfyUI-CLIPScore.git
|
||||
cd ComfyUI-CLIPScore
|
||||
pip install -r requirements.txt
|
||||
@@ -0,0 +1,3 @@
|
||||
from .clip_score_node import NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS
|
||||
|
||||
__all__ = ["NODE_CLASS_MAPPINGS", "NODE_DISPLAY_NAME_MAPPINGS"]
|
||||
@@ -0,0 +1,91 @@
|
||||
"""
|
||||
ComfyUI Custom Node: CLIP Score Calculator
|
||||
"""
|
||||
|
||||
import torch
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
from transformers import CLIPProcessor, CLIPModel
|
||||
|
||||
class CLIPScoreNode:
|
||||
"""Calculates true CLIP cosine similarity between prompt and image."""
|
||||
|
||||
@classmethod
|
||||
def INPUT_TYPES(cls):
|
||||
return {
|
||||
"required": {
|
||||
"image": ("IMAGE",),
|
||||
"prompt": ("STRING", {"multiline": True, "default": ""}),
|
||||
"model_name": (
|
||||
[
|
||||
"openai/clip-vit-base-patch16",
|
||||
"openai/clip-vit-base-patch32",
|
||||
"openai/clip-vit-large-patch14",
|
||||
],
|
||||
{"default": "openai/clip-vit-base-patch16"},
|
||||
),
|
||||
},
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("FLOAT", "STRING")
|
||||
RETURN_NAMES = ("clip_score", "score_text")
|
||||
FUNCTION = "calculate_clip_score"
|
||||
CATEGORY = "metrics"
|
||||
OUTPUT_NODE = True
|
||||
|
||||
def calculate_clip_score(self, image, prompt, model_name):
|
||||
try:
|
||||
# Load CLIP (cached after first run)
|
||||
model = CLIPModel.from_pretrained(model_name)
|
||||
processor = CLIPProcessor.from_pretrained(model_name)
|
||||
|
||||
# Handle ComfyUI IMAGE: [B,H,W,C] or [H,W,C]
|
||||
if len(image.shape) == 4:
|
||||
img = image[0] # First from batch
|
||||
else:
|
||||
img = image
|
||||
|
||||
# [H,W,C] float32 [0,1] → numpy uint8 → PIL RGB
|
||||
img_np = (img.cpu().numpy() * 255).astype(np.uint8)
|
||||
if img_np.shape[-1] == 4: # RGBA → RGB
|
||||
img_np = img_np[:, :, :3]
|
||||
pil_image = Image.fromarray(img_np, mode='RGB')
|
||||
|
||||
# GPU inference
|
||||
device = next(model.parameters()).device
|
||||
inputs = processor(text=[prompt], images=pil_image, return_tensors="pt", padding=True)
|
||||
inputs = {k: v.to(device) for k, v in inputs.items()}
|
||||
model.to(device)
|
||||
|
||||
# Raw CLIP score: cosine similarity of normalized embeddings
|
||||
with torch.no_grad():
|
||||
outputs = model(**inputs)
|
||||
image_embeds = outputs.image_embeds
|
||||
text_embeds = outputs.text_embeds
|
||||
|
||||
# L2 normalize + cosine similarity (standard CLIP score)
|
||||
image_embeds /= image_embeds.norm(p=2, dim=-1, keepdim=True) + 1e-8
|
||||
text_embeds /= text_embeds.norm(p=2, dim=-1, keepdim=True) + 1e-8
|
||||
score = (image_embeds @ text_embeds.T)[0, 0].item()
|
||||
|
||||
# Cleanup
|
||||
model.cpu()
|
||||
del model, inputs
|
||||
|
||||
except Exception as e:
|
||||
score = 0.0
|
||||
print(f"CLIP error: {str(e)}")
|
||||
|
||||
score_str = f"CLIP Score: {score:.4f}"
|
||||
print(score_str)
|
||||
|
||||
return (score, score_str)
|
||||
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"CLIPScoreNode": CLIPScoreNode,
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"CLIPScoreNode": "CLIP Score Calculator",
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
torch
|
||||
transformers>=4.36.0
|
||||
pillow
|
||||
numpy
|
||||
Reference in New Issue
Block a user