Difficulties processing more than 1 image

#3
by alecccdd - opened

Thank you very much - I really appreciate your work!

In my initial tests, it seems that it can no longer recognize multiple images when they are sent in a single message. Google’s OG model, on the other hand, handles this just fine. I’m still getting up to speed with Gemma4 myself, so I can’t rule out the possibility that the error is on my end, but I hope the logs will still help clarify the differences between this version and Google’s.

Model loading and generation

from transformers import AutoProcessor, AutoModelForMultimodalLM

processor = AutoProcessor.from_pretrained(repo)
model = AutoModelForMultimodalLM.from_pretrained(
    repo,
    dtype="bfloat16",
    device_map="auto",
)
inputs = processor.apply_chat_template(
    messages,
    add_generation_prompt=True,
    tokenize=True,
    return_tensors="pt",
    return_dict=True,
    enable_thinking=False,
).to(model.device)

input_len = inputs["input_ids"].shape[-1]
out = model.generate(**inputs, max_new_tokens=512)
resp = processor.decode(out[0][input_len:], skip_special_tokens=False)
print(processor.parse_response(resp))

Prompt formats (single message vs multiple messages)

Single-Message:

messages = [
    {"role": "system", "content": "You are a helpful assistant."},
    {"role": "user", "content": [
        {"type": "image", "path": "A.jpg"},
        {"type": "image", "path": "B.jpg"},
        {"type": "text",  "text": "Compare these two images. Describe image 1, then image 2."},
    ]},
]

Multi-Message:

messages = [
  {"role": "system", "content": "You are a helpful assistant."},
  {
    "role"   : "user",
    "content": [
      {"type": "image", "path": "A.jpg"},
      {"type": "text", "text": "This is image 1."}
    ]
  },
  {
    "role"   : "user",
    "content": [
      {"type": "image", "path": "B.jpg"},
      {"type": "text", "text": "This is image 2."}
    ]
  },
  {
    "role"   : "user",
    "content": [
      {
        "type": "text",
        "text": "Compare these two images. Describe image 1, then image 2."
      }
    ]
  }
]

Outputs

google/gemma-4-12B-it

Single Message ✅:

{
  "content": "The two images feature a woman on a beach, but they differ significantly in terms of the subject's pose, the color palette, and the overall mood.\n\n**Image 1:**\n*   **Subject and Pose:** A woman with long blonde hair is shown in a profile view, facing towards the left. She has her arms raised over her head with her eyes closed and a serene, blissful expression.\n*   **Attire:** She is wearing a white bikini.\n*   **Setting:** The background shows a bright blue sky with scattered white clouds and a turquoise ocean with white-capped waves.\n*   **Atmosphere:** The image has a warm, airy, and \"dreamy\" feel, emphasizing a sense of freedom and relaxation.\n\n**Image 2:**\n*   **Subject and Pose:** A woman with long dark hair is shown facing the camera. She is smiling broadly and looking directly at the viewer. Her body is angled slightly, and her arms are down at her sides.\n*   **Attire:** She is wearing a dark blue bikini and a turquoise beaded bracelet on her left wrist.\n*   **Setting:** Similar to the first image, she is on a beach with white sand, turquoise water, and a clear blue sky.\n*   **Atmosphere:** The lighting is very bright and high-contrast. The mood is more energetic, cheerful, and direct compared to the first image.",
  "role": "assistant"
}

Multi Message ✅:

{
  "content": "The two images show a woman on a beach in different poses and wearing different swimwear.\n\nIn the first image, the woman is shown from the waist up, facing forward and smiling at the camera. She has long brown hair and is wearing a dark blue bikini. Her right hand is raised toward her hair, and she is wearing multiple bracelets on her left wrist. The background shows a blue ocean with white waves and a clear blue sky.\n\nIn the second image, the woman is shown from the waist up, facing forward and smiling at the camera. She has long brown hair and is wearing a white bikini. Her arms are raised above her head, and she is wearing a small earring. The background shows a blue ocean with white waves and a clear blue sky.",
  "role": "assistant"
}

OpenYourMind/gemma-4-12B-it-abliterated-uncensored

Single Message ❌:

{
  "content": "I'm sorry, but you only provided one image. It looks like you meant to provide two images for comparison. Since there is only one image, here is a description of it:\n\n**Image Description:**\n\nThe image depicts a beautiful young woman standing on a beach, looking immensely happy. She has long, wavy brown hair and is wearing a blue bikini. She is standing in front of a blue ocean with white waves crashing against the shore. The sun is shining brightly, and she has a big smile on her face. She is also wearing a blue bracelet on her left wrist. The image is very peaceful and relaxing.",
  "role": "assistant"
}

Multi Message ✅:

{
  "content": "Based on the images provided, here is a comparison and description of both:\n\n### **Image 1**\n**Description:**\nImage 1 features a young woman with long, wavy brown hair standing on a sunlit beach. She is wearing a white bikini and has her arms outstretched, expressing a sense of joy and relaxation. The background shows a bright blue sky with fluffy white clouds and gentle ocean waves crashing onto the shore. The overall atmosphere is serene and evokes a feeling of a perfect summer day at the beach.\n\n### **Image 2**\n**Description:**\nImage 2 shows the same woman from Image 1, but she is now portrayed in a more active pose. She is looking towards the side with a soft smile, her hair blowing gently in the breeze. She is wearing a blue bikini, which contrasts beautifully with the white sand and blue water. The lighting is soft and natural, highlighting her happy expression. The overall composition of the image creates a sense of harmony and tranquility.\n\n### **Comparison**\nBoth images depict the same woman in the same beach setting, but they capture different moments of her experience. Image 1 focuses on her joyous reaction to the beach, while Image 2 captures her peaceful and content expression. The transition from Image 1 to Image 2 reflects the changing emotions and the beautiful scenery of the beach.",
  "role": "assistant"
}

Reproducibility and Verification

I was able to reproduce similar behaviour both upon multiple generations of the same prompt as well as for other prompts.

I verified that indeed both images are encoded and applied by the chat template correctly:

>>> img_id = processor.tokenizer.convert_tokens_to_ids("<|image|>")
>>> print("image soft tokens:", (inputs["input_ids"] == img_id).sum().item())
image soft tokens: 520
>>> print("pixel batch:", inputs["pixel_values"].shape)  # leading dim should be 2
pixel batch: torch.Size([2, 280, 6912])
>>>
>>> boi = processor.tokenizer.convert_tokens_to_ids("<|image>")   # 255999
>>> eoi = processor.tokenizer.convert_tokens_to_ids("<image|>")   # 258882
>>> ids = inputs["input_ids"][0]
>>> print("BOI:", (ids == boi).sum().item(), "EOI:", (ids == eoi).sum().item())
BOI: 2 EOI: 2
>>> import torch
>>> img = processor.tokenizer.convert_tokens_to_ids("<|image|>")
>>> mask = (ids == boi) | (ids == eoi) | (ids == img)
>>> prev = None
>>> for t in ids[mask].tolist():
...     if t == img and prev == img:
...         continue
...     print(processor.tokenizer.convert_ids_to_tokens(t))
...     prev = t
...
<|image>
<|image|>
<image|>
<|image>
<|image|>
<image|>

Environment:

python : 3.12.13 | Linux-4.4.0-x86_64-with-glibc2.39
transformers    : 5.10.1
torch           : 2.12.0+cu130
torchvision     : 0.27.0+cu130
accelerate      : 1.13.0
tokenizers      : 0.22.2
huggingface_hub : 1.17.0
PIL             : 12.2.0
numpy           : 2.4.4
cuda(torch built): 13.0 | available: True
gpu : NVIDIA A10
NVIDIA A10, 580.95.05, 23028 MiB
google/gemma-4-12B-it 5926caa4ec0cac5cbfadaf4077420520de1d5205
OpenYourMind/gemma-4-12B-it-abliterated-uncensored 84142e4d19604d88a70dc38e4287c8cee481d1c4

I’d like to emphasize once again that I’m really just starting to familiarize myself with the code behind the model and can’t rule out the possibility that the error is on my end. However, I still thought it was worth noting that the behavior differs reproducibly between the Google version and this fine-tune. I therefore hope this will help improve your work.

I will have to check, as the ablation only touched the text tensors there shouldnt have been a impact. I will run the checks on my end as well

Thanks for reporting though

Fixing the ablation rn. we can counter act with our new strategy quiet easy.

trying to reproduce

it worked fine. Can you share / upload & image somewhere ? its harder to reproduce then anticipated

  import torch, json
  from PIL import Image, ImageDraw
  from transformers import AutoProcessor, AutoModelForMultimodalLM

  REPO = "/workspace/gemma-4-12B-it-wip"   # the abliterated model

  # two unmistakably distinct images: red SQUARE vs blue CIRCLE
  a = Image.new("RGB", (256, 256), "white"); ImageDraw.Draw(a).rectangle([48, 48, 208, 208], fill="red");  a.save("/tmp/A.jpg")
  b = Image.new("RGB", (256, 256), "white"); ImageDraw.Draw(b).ellipse([48, 48, 208, 208], fill="blue");   b.save("/tmp/B.jpg")

  proc  = AutoProcessor.from_pretrained(REPO)
  model = AutoModelForMultimodalLM.from_pretrained(REPO, dtype="bfloat16", device_map="auto").eval()

  # the message that WORKS: both images as separate items in ONE user turn
  messages = [
      {"role": "system", "content": "You are a helpful assistant."},
      {"role": "user", "content": [
          {"type": "image", "path": "/tmp/A.jpg"},
          {"type": "image", "path": "/tmp/B.jpg"},
          {"type": "text",  "text": "Compare these two images. Describe image 1, then image 2."},
      ]},
  ]

  inputs = proc.apply_chat_template(
      messages, add_generation_prompt=True, tokenize=True,
      return_tensors="pt", return_dict=True, enable_thinking=False,
  ).to(model.device)

  ilen = inputs["input_ids"].shape[-1]
  with torch.no_grad():
      out = model.generate(**inputs, max_new_tokens=200, do_sample=False)
  raw = proc.decode(out[0][ilen:], skip_special_tokens=True)
  print(proc.parse_response(raw))   # -> "The first image shows a red square. The second image shows a blue circle."

Sign up or log in to comment