vale46n1 / immich_duplicate_finder

A Comprehensive Solution for Identifying and Managing Duplicate Photos in Immich
Apache License 2.0
227 stars 19 forks source link

[Bug] RuntimeError: The size of tensor a (4) must match the size of tensor b (3) at non-singleton dimension 0 #32

Open Deathproof76 opened 6 months ago

Deathproof76 commented 6 months ago

Hi, thank you for this project, really cool idea! I built the docker image and everything went fine up until 4000 of 40000 assets.

image

name: immich-duplicate-finder2
services:
  immich-duplicate-finder2:
    container_name: immich-duplicate-finder2
    hostname: immich-duplicate-finder2
    restart: unless-stopped
    volumes:
      - /mnt/Dockerspace/immich_duplicate_finder_test/db/settings.db:/immich_duplicate_finder/settings.db
      - /mnt/Dockerspace/immich_duplicate_finder_test/db/processed_assets.db:/immich_duplicate_finder/processed_assets.db
      - /mnt/Dockerspace/immich_duplicate_finder_test/db/duplicates.db:/immich_duplicate_finder/duplicates.db
      - /mnt/Dockerspace/immich_duplicate_finder_test/db/faiss_index.bin:/immich_duplicate_finder/faiss_index.bin
      - /mnt/Dockerspace/immich_duplicate_finder_test/db/metadata.npy:/immich_duplicate_finder/metadata.npy
      - /mnt/Dockerspace/immich_duplicate_finder_test/db/__pycache__:/immich_duplicate_finder/__pycache__
      - /mnt/Dockerspace/immich_duplicate_finder_test/cache:/root/.cache/torch/hub/checkpoints/
    ports:
      - 8502:8501
    build:
      dockerfile: './Dockerfile'

(btw: maybe move the databases to a separate folder for simpler mounting like https://github.com/vale46n1/immich_duplicate_finder/compare/main...ttlequals0:immich_duplicate_finder:main )

logs up until erroring out:

docker compose up
[+] Running 1/0
 ✔ Container immich-duplicate-finder2  Recreated                                                                                                                                                                        0.1s 
Attaching to immich-duplicate-finder2
immich-duplicate-finder2  | 
immich-duplicate-finder2  | Collecting usage statistics. To deactivate, set browser.gatherUsageStats to False.
immich-duplicate-finder2  | 
immich-duplicate-finder2  | 
immich-duplicate-finder2  |   You can now view your Streamlit app in your browser.
immich-duplicate-finder2  | 
immich-duplicate-finder2  |   Network URL: http://#############
immich-duplicate-finder2  |   External URL: http://##############
immich-duplicate-finder2  | 
immich-duplicate-finder2  | Downloading: "https://download.pytorch.org/models/resnet152-f82ba261.pth" to /root/.cache/torch/hub/checkpoints/resnet152-f82ba261.pth
100.0%-duplicate-finder2  | 
immich-duplicate-finder2  | 2024-05-06 09:28:11.755 Uncaught app exception
immich-duplicate-finder2  | Traceback (most recent call last):
immich-duplicate-finder2  |   File "/usr/local/lib/python3.12/site-packages/streamlit/runtime/scriptrunner/script_runner.py", line 542, in _run_script
immich-duplicate-finder2  |     exec(code, module.__dict__)
immich-duplicate-finder2  |   File "/immich_duplicate_finder/app.py", line 130, in <module>
immich-duplicate-finder2  |     main()
immich-duplicate-finder2  |   File "/immich_duplicate_finder/app.py", line 109, in main
immich-duplicate-finder2  |     calculateFaissIndex(
immich-duplicate-finder2  |   File "/immich_duplicate_finder/imageDuplicate.py", line 117, in calculateFaissIndex
immich-duplicate-finder2  |     status = update_faiss_index(immich_server_url,api_key, asset_id)
immich-duplicate-finder2  |              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
immich-duplicate-finder2  |   File "/immich_duplicate_finder/imageDuplicate.py", line 68, in update_faiss_index
immich-duplicate-finder2  |     features = extract_features(image)
immich-duplicate-finder2  |                ^^^^^^^^^^^^^^^^^^^^^^^
immich-duplicate-finder2  |   File "/immich_duplicate_finder/imageDuplicate.py", line 35, in extract_features
immich-duplicate-finder2  |     image_tensor = transform(image).unsqueeze(0)  # Add batch dimension
immich-duplicate-finder2  |                    ^^^^^^^^^^^^^^^^
immich-duplicate-finder2  |   File "/usr/local/lib/python3.12/site-packages/torchvision/transforms/transforms.py", line 95, in __call__
immich-duplicate-finder2  |     img = t(img)
immich-duplicate-finder2  |           ^^^^^^
immich-duplicate-finder2  |   File "/usr/local/lib/python3.12/site-packages/torch/nn/modules/module.py", line 1511, in _wrapped_call_impl
immich-duplicate-finder2  |     return self._call_impl(*args, **kwargs)
immich-duplicate-finder2  |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
immich-duplicate-finder2  |   File "/usr/local/lib/python3.12/site-packages/torch/nn/modules/module.py", line 1520, in _call_impl
immich-duplicate-finder2  |     return forward_call(*args, **kwargs)
immich-duplicate-finder2  |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
immich-duplicate-finder2  |   File "/usr/local/lib/python3.12/site-packages/torchvision/transforms/transforms.py", line 277, in forward
immich-duplicate-finder2  |     return F.normalize(tensor, self.mean, self.std, self.inplace)
immich-duplicate-finder2  |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
immich-duplicate-finder2  |   File "/usr/local/lib/python3.12/site-packages/torchvision/transforms/functional.py", line 349, in normalize
immich-duplicate-finder2  |     return F_t.normalize(tensor, mean=mean, std=std, inplace=inplace)
immich-duplicate-finder2  |            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
immich-duplicate-finder2  |   File "/usr/local/lib/python3.12/site-packages/torchvision/transforms/_functional_tensor.py", line 926, in normalize
immich-duplicate-finder2  |     return tensor.sub_(mean).div_(std)
immich-duplicate-finder2  |            ^^^^^^^^^^^^^^^^^
immich-duplicate-finder2  | RuntimeError: The size of tensor a (4) must match the size of tensor b (3) at non-singleton dimension 0

I'm not a programmer but maybe it's related to an image with an alpha channel, RGBA instead of RGB? https://github.com/StoryMY/take-off-eyeglasses/issues/1#issuecomment-1122144903 https://github.com/christiansafka/img2vec/issues/31 https://github.com/christiansafka/img2vec/pull/37/commits/1cc7e273cc23822765be34aac90775b0fbb31252

edit: I read a bit on the web and it seems that resnet is only trained for 3-channel images, rgb not rgba so images would most likely have to be transformed before comparison.

Deathproof76 commented 6 months ago

With some AI-Guidance: Maybe like this in imageDuplicate.py?

import os
import streamlit as st
import time

import torch
import numpy as np
import faiss
from torchvision.models import resnet152, ResNet152_Weights
from torchvision.transforms import Compose, Resize, ToTensor, Normalize
from PIL import Image

from api import getImage
from utility import display_asset_column
from api import getAssetInfo
from db import load_duplicate_pairs, is_db_populated, save_duplicate_pair
from streamlit_image_comparison import image_comparison

# Set the environment variable to allow multiple OpenMP libraries
os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"

# Load ResNet152 with pretrained weights
model = resnet152(weights=ResNet152_Weights.DEFAULT)
model.eval()  # Set model to evaluation mode

def convert_image_to_rgb(image):
    """Convert image to RGB if it's RGBA."""
    if image.mode == 'RGBA':
        return image.convert('RGB')
    return image

transform = Compose([
    convert_image_to_rgb,
    Resize((224, 224)),  # Standard size for ImageNet-trained models
    ToTensor(),
    Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])
...

Update: I simply mounted the modified imageDuplicate.py. And it's processing further, stopped the process to check for duplicates and it seems to work so far 👍

image