Brief IA

Gemma 4 et Ollama : révolutionner l'analyse multimodale locale

🎨 Creative AI·Tom Levy·

Gemma 4 et Ollama : révolutionner l'analyse multimodale locale

Gemma 4 et Ollama : révolutionner l'analyse multimodale locale
Key Takeaways
1Gemma 4 et Ollama permettent de créer des flux de travail multimodaux sur des machines locales, intégrant images et texte.
2Un voyage en Finlande a servi de cas d'étude pour démontrer comment transformer des photos en enregistrements structurés.
3Des défis techniques ont été surmontés pour optimiser l'utilisation de Gemma 4 sur différents systèmes d'exploitation.
💡Why it mattersCette approche offre une solution sécurisée pour traiter des données sensibles sans dépendre du cloud.
Le brief IA que lisent les pros

Le brief IA que les pros lisent chaque soir

Les 7 actus IA du jour, décryptées en 5 min. Gratuit.

Inclus dès l'inscription : notre sélection des meilleurs guides & comparatifs IA.

Choisis ton rythme

Gratuit · Pas de spam · Désabonnement en 1 clic

📄
Full Analysis

Applications des LLM

Construire des flux de travail multimodaux avec un LLM local

L'utilisation de Gemma 4 et Ollama pour intégrer des entrées d'images et des sorties structurées est particulièrement séduisante lorsqu'il s'agit de manipuler des données privées ou de développer des flux de travail sur des machines locales. Ces flux de travail ne se limitent plus uniquement au texte, ouvrant ainsi la voie à des applications plus riches et diversifiées.

Cet article explore comment construire un flux de travail en utilisant Gemma 4 et Ollama. Il démontre comment la capacité multimodale de Gemma 4 peut être intégrée dans un processus plus large, permettant aux étapes suivantes de consommer sa sortie structurée.

L'auteur de l'étude a récemment voyagé en Finlande et pris de nombreuses photos durant ce périple. Ce contexte a servi à illustrer comment ce flux de travail peut être utilisé pour analyser ces images et alimenter une application plus petite.

1. Le flux de travail multimodal

Le concept de « flux de travail multimodal » repose sur deux idées principales.

  • Multimodal : Cela signifie que le LLM ne travaille pas seulement avec du texte, mais reçoit aussi des entrées d'autres types, comme des images. Dans cet article, le LLM local de la famille Gemma 4 de Google est utilisé, capable de traiter à la fois des images et du texte.

  • Flux de travail : Cela signifie que le LLM ne décide pas de manière autonome de la prochaine étape, comme dans une boucle agentique. Au lieu de cela, il fonctionne dans une séquence prédéfinie, où chaque étape reçoit une entrée et produit une sortie pour l'étape suivante. Le LLM sert ici de fonction pour effectuer des transformations sémantiques.

Pour l'étude de cas, l'objectif est de transformer un dossier de photos de voyage en enregistrements de mémoire organisés. Cela implique d'analyser chaque photo et de traduire son contenu en un enregistrement structuré et cohérent. Une fois ces enregistrements disponibles, ils peuvent être combinés pour obtenir une compréhension globale de la collection.

Ainsi, un flux de travail en trois étapes est mis en place :

photos = prepare_photos("Finland_trip")
photo_memories = [
    image=photo.image,
    metadata=photo.metadata,
    for photo in photos
]
trip_memory = synthesize_trip(photo_memories)

Tout d'abord, Python prépare les images individuelles et extrait des métadonnées utiles telles que les heures de capture et les coordonnées GPS.

Ensuite, le LLM local Gemma 4 analyse chaque photo et renvoie un enregistrement structuré du contenu visuel de la photo.

Enfin, les enregistrements individuels sont transmis à nouveau à Gemma 4 pour produire un résumé structuré de l'ensemble de la collection.

Dans ce qui suit, les étapes individuelles seront construites.

2. Construire le flux de travail avec Gemma 4

2.1 Exécuter Gemma 4 localement

Pour commencer, il est nécessaire de rendre Gemma 4 disponible localement. Ollama est utilisé pour cela, offrant un environnement d'exécution local et une interface pour interagir avec le modèle.

Dans cet article, la variante E4B de Gemma est utilisée, qui est l'un des modèles adaptés aux périphériques dans la famille.

Sur Windows et macOS, l'installateur peut être téléchargé et exécuté depuis le site web d'Ollama. Sur Linux, l'installation se fait via le terminal :

curl -fsSL https://ollama.com/install.sh | sh

Une fois Ollama installé, le modèle Gemma peut être récupéré :

ollama pull gemma4:e4b

Les paquets Python nécessaires pour le flux de travail doivent également être installés :

pip install ollama pillow pydantic

Ici, ollama est nécessaire pour connecter le code Python au LLM local, pillow gère le traitement des images, et pydantic est utilisé pour la sortie structurée.

2.2 De la photo à l'enregistrement structuré

Pour chaque photo, un enregistrement structuré décrivant ce que le modèle voit est souhaité.

Avant que les images n'atteignent Gemma 4, elles doivent être prétraitées. Dans le flux de travail, une logique déterministe pour redimensionner l'image et extraire les métadonnées EXIF disponibles est mise en œuvre, encapsulée dans prepare_photo().

Du point de vue du flux de travail, seules les sorties sont nécessaires :

from pathlib import Path

image, metadata = prepare_photo(
    Path("Finland_trip/photo.jpg")
)

Ici, image contient les octets de l'image préparée, tandis que metadata est un dictionnaire contenant les informations extraites du fichier.

Les détails d'implémentation complets peuvent être trouvés dans le dépôt joint à la fin de l'article.

Ensuite, l'enregistrement structuré que Gemma 4 doit renvoyer est défini :

from pydantic import BaseModel, Field

class PhotoMemoryAnalysis(BaseModel):
    scene_summary: str
    memory_caption: str
    visible_activities: list[str]
    visible_objects: list[str]
    inferred_interest_signals: list[str]
    uncertainty_notes: list[str]
    confidence: float = Field(ge=0, le=1)

C'est ce qui est appelé une sortie structurée. Effectivement, ce schéma est pré-défini et le LLM est demandé de produire une sortie selon cette forme. De cette manière, le code en aval peut accéder au résultat via des attributs typés ou le convertir en dictionnaire avec model_dump().

Ensuite, l'instruction et l'invite sont construites :

PHOTO_ANALYSIS_INSTRUCTION = """
Analyze the supplied travel photo and its metadata.
Return a structured record grounded in the provided inputs.
"""

def build_photo_prompt(metadata: dict) -> str:
    return f"""Photo metadata:
{json.dumps(metadata, indent=2)}

Tout peut maintenant être assemblé :

MODEL = "gemma4:e4b"

def analyze_photo() -> PhotoMemoryAnalysis:
    response = ollama.chat(
        "role": "system",
        "content": PHOTO_ANALYSIS_INSTRUCTION,
        "content": build_photo_prompt(metadata),
        "images": [image],
        format=PhotoMemoryAnalysis.model_json_schema(),
        options={"temperature": 0},
    )
    return PhotoMemoryAnalysis.model_validate_json(
        response.message.content
    )

Notez que le champ images est utilisé pour fournir l'entrée visuelle, et format est utilisé pour demander à Ollama de suivre le schéma défini. La réponse peut ensuite être analysée en un objet Python classique :

photo_analysis = analyze_photo(metadata=metadata)

De cette manière, la routine pour transformer une photo en un enregistrement de mémoire structuré est établie.

2.3 Un problème de compatibilité avec l'entrée d'image

Une note à mentionner : avec la configuration actuelle pour Ollama (0.32.5) sur une machine Windows avec gemma4:e4b, il semble que Ollama ait accepté la demande multimodale, mais le modèle n'a pas réussi à utiliser son contenu visuel.

Une solution simple adoptée est de charger Gemma 4 en utilisant deux fichiers séparés du dépôt Unsloth de Gemma 4 E4B GGUF :

  • mmproj-BF16.gguf, qui contient le projecteur multimodal.
  • gemma-4-E4B-it-UD-Q4_K_XL.gguf, qui contient le modèle quantifié.

Le projecteur est le composant qui permet au modèle de consommer l'information visuelle.

Après avoir placé les deux fichiers dans le même dossier, un fichier Modelfile suivant est créé :

FROM ./gemma-4-E4B-it-UD-Q4_K_XL.gguf
FROM ./mmproj-BF16.gguf

Le modèle est ensuite importé dans Ollama :

ollama create gemma4-e4b-split-test -f Modelfile

Enfin, le nom du modèle est mis à jour dans Python :

MODEL = "gemma4-e4b-split-test"

Avec cette configuration, le modèle Gemma peut correctement consommer l'image. Bien sûr, si gemma4:e4b répond déjà correctement aux entrées d'image sur une machine, ce contournement n'est pas nécessaire.

2.4 Des enregistrements photo à la mémoire de voyage

À ce stade, chaque photo peut être comprise indépendamment.

Pour la dernière étape, l'objectif est de comprendre le voyage dans son ensemble. Pour cela, ces enregistrements peuvent être transmis à Gemma 4 une fois de plus et lui demander de relier les moments individuels en une mémoire de voyage.

Tout d'abord, analyze_photo() est appliqué à l'ensemble du dossier :

from pathlib import Path

photo_memories = []
for image_path in Path("Finland_trip").glob("*.jpg"):
    image, metadata = prepare_photo(image_path)
    analysis = analyze_photo(metadata=metadata)
    photo_memories.append({
        "photo_id": image_path.name,
        "analysis": analysis.model_dump(),
        "metadata": metadata,
    })

Notez que chaque mémoire photo combine maintenant deux sources d'information : les métadonnées extraites du fichier et l'interprétation sémantique de l'image fournie par Gemma 4.

Un autre schéma pour la sortie finale est défini :

class MemorableMoment(BaseModel):
    description: str
    evidence_photo_ids: list[str]

class TripMemorySynthesis(BaseModel):
    narrative_summary: str
    inferred_interests: list[str]
    recurring_themes: list[str]
    memorable_moments: list[MemorableMoment]
    uncertainty_notes: list[str]

L'instruction et l'invite sont ensuite définies :

TRIP_SYNTHESIS_INSTRUCTION = """
Synthesize the supplied photo records into a structured trip memory.
Use only the information contained in those records.
"""

def build_trip_prompt(photo_memories: list[dict]) -> str:
    return f"""Photo memory records:
{json.dumps(photo_memories, indent=2)}

L'appel final au modèle suit le même schéma que précédemment. Notez que cet appel est uniquement textuel :

def synthesize_trip(photo_memories: list[dict]) -> TripMemorySynthesis:
    response = ollama.chat(
        "role": "system",
        "content": TRIP_SYNTHESIS_INSTRUCTION,
        "content": build_trip_prompt(photo_memories),
        format=TripMemorySynthesis.model_json_schema(),
        options={"temperature": 0},
    )
    return TripMemorySynthesis.model_validate_json(
        response.message.content
    )

Le flux de travail peut maintenant être complété :

trip_memory = synthesize_trip(photo_memories)

Pour cette étude de cas, l'auteur a choisi 7 photos de son voyage en Finlande et a exécuté le flux de travail sur elles.

Regardons d'abord deux des enregistrements photo.

Figure 1. Une grande roue à Helsinki. (Image par l'auteur)

Voici ce que Gemma 4 a renvoyé pour la première image :

"scene_summary": (
    "Une grande roue domine le cadre contre "
    "un ciel clair au crépuscule."
),
"memory_caption": (
    "Vues du soir depuis le tour de la grande roue."
),
"visible_objects": [
    "Signalisation",
    "Garde-corps/platforme avant",
],
"mood": "Festif",
"uncertainty_notes": [
    "L'emplacement spécifique n'est pas "
    "fourni, seulement le nom de l'attraction."
]

Le modèle a reconnu l'attraction principale. Il a également lu le texte visible et incorporé le cadre du soir dans l'enregistrement.

Voici une autre photo et la sortie du modèle :

Figure 2. Un hibou arctique au parc animalier de Ranua en Laponie finlandaise. (Image par l'auteur)

"scene_summary": (
    "Un grand hibou ou rapace se tient près d'une structure en bois "
    "et d'une clôture en fil de fer dans un environnement verdoyant."
),
"memory_caption": (
    "Une rencontre avec la faune : Un oiseau majestueux "
    "observant son environnement au milieu d'une dense verdure."
),
"visible_objects": [
    "Structure en bois",
    "Clôture en fil de fer",
    "Foliage dense",
],
"mood": "Impressionnant, Paisible",
"uncertainty_notes": [
    "L'espèce précise de l'oiseau ne peut pas être "
    "définie uniquement à partir de l'image.",
    "La fonction spécifique de la structure en bois "
    "est ambiguë."
]

Après avoir analysé les sept photos, le flux de travail a passé les résultats à l'étape suivante.

Brief IA — L'actualité IA en français

L'essentiel de l'actualité de l'intelligence artificielle, décrypté et expliqué chaque jour.