PaliGemma-Ausgabe mit Keras generieren

Auf ai.google.dev ansehen  In Google Colab ausführen In Vertex AI öffnen Quelle auf GitHub ansehen

PaliGemma-Modelle sind multimodal. Sie können also sowohl Text- als auch Bilddaten als Eingabe verwenden, um Ausgaben zu generieren. Sie können Bilddaten mit diesen Modellen verwenden, um zusätzlichen Kontext für Ihre Anfragen bereitzustellen, oder das Modell verwenden, um den Inhalt von Bildern zu analysieren. In diesem Tutorial erfahren Sie, wie Sie PaliGemma mit Keras verwenden, um Bilder zu analysieren und Fragen dazu zu beantworten.

Inhalt dieses Notebooks

In diesem Notebook wird PaliGemma mit Keras verwendet. Sie erfahren, wie Sie:

  • Keras und die erforderlichen Abhängigkeiten installieren
  • Laden Sie PaliGemmaCausalLM herunter, eine vortrainierte PaliGemma-Variante für die kausale visuelle Sprachmodellierung, und verwenden Sie sie, um ein Modell zu erstellen.
  • Fähigkeit des Modells testen, Informationen zu bereitgestellten Bildern abzuleiten

Hinweis

Bevor Sie dieses Notebook durcharbeiten, sollten Sie sich mit Python-Code und dem Training von Large Language Models (LLMs) vertraut machen. Sie müssen nicht mit Keras vertraut sein, aber grundlegende Kenntnisse über Keras sind hilfreich, wenn Sie sich den Beispielcode ansehen.

Einrichtung

In den folgenden Abschnitten werden die vorbereitenden Schritte beschrieben, die erforderlich sind, damit ein Notebook ein PaliGemma-Modell verwenden kann. Dazu gehören der Modellzugriff, das Abrufen eines API-Schlüssels und die Konfiguration der Notebook-Laufzeit.

Zugriff auf PaliGemma erhalten

Bevor Sie PaliGemma zum ersten Mal verwenden, müssen Sie über Kaggle Zugriff auf das Modell beantragen. Führen Sie dazu die folgenden Schritte aus:

  1. Melden Sie sich bei Kaggle an oder erstellen Sie ein neues Kaggle-Konto, falls Sie noch keines haben.
  2. Rufen Sie die PaliGemma-Modellkarte auf und klicken Sie auf Zugriff anfordern.
  3. Füllen Sie das Zustimmungsformular aus und akzeptieren Sie die Nutzungsbedingungen.

API-Schlüssel konfigurieren

Wenn Sie PaliGemma verwenden möchten, müssen Sie Ihren Kaggle-Nutzername und einen Kaggle-API-Schlüssel angeben.

Um einen Kaggle-API-Schlüssel zu generieren, öffnen Sie die Seite Einstellungen in Kaggle und klicken Sie auf Neues Token erstellen. Dadurch wird der Download einer kaggle.json-Datei mit Ihren API-Anmeldedaten ausgelöst.

Wählen Sie dann in Colab im linken Bereich Secrets (🔑) aus und fügen Sie Ihren Kaggle-Nutzernamen und Ihren Kaggle-API-Schlüssel hinzu. Speichern Sie Ihren Nutzernamen unter dem Namen KAGGLE_USERNAME und Ihren API-Schlüssel unter dem Namen KAGGLE_KEY.

Laufzeit auswählen

Für diese Anleitung benötigen Sie eine Colab-Laufzeit mit ausreichend Ressourcen, um das PaliGemma-Modell auszuführen. In diesem Fall können Sie eine T4-GPU verwenden:

  1. Klicken Sie rechts oben im Colab-Fenster auf das Drop-down-Menü ▾ (Zusätzliche Verbindungsoptionen).
  2. Wählen Sie Laufzeittyp ändern aus.
  3. Wählen Sie unter Hardwarebeschleuniger die Option T4-GPU aus.

Umgebungsvariablen festlegen

Legen Sie die Umgebungsvariablen für KAGGLE_USERNAME, KAGGLE_KEY und KERAS_BACKEND fest.

import os
from google.colab import userdata

# Set up environmental variables
os.environ["KAGGLE_USERNAME"] = userdata.get('KAGGLE_USERNAME')
os.environ["KAGGLE_KEY"] = userdata.get('KAGGLE_KEY')
os.environ["KERAS_BACKEND"] = "jax"

Keras installieren

Führen Sie die folgende Zelle aus, um Keras zu installieren.

pip install -U -q keras-nlp keras-hub kagglehub

Abhängigkeiten importieren und Keras konfigurieren

Installieren Sie die für dieses Notebook erforderlichen Abhängigkeiten und konfigurieren Sie das Keras-Backend. Außerdem legen Sie fest, dass Keras bfloat16 verwendet, damit das Framework weniger Arbeitsspeicher benötigt.

import keras
import keras_hub
import numpy as np
import PIL
import requests
import io
import matplotlib
import re
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from PIL import Image

keras.config.set_floatx("bfloat16")

Modell laden

Nachdem Sie alles eingerichtet haben, können Sie das vortrainierte Modell herunterladen und einige Hilfsmethoden erstellen, damit Ihr Modell Antworten generieren kann. In diesem Schritt laden Sie ein Modell mit PaliGemmaCausalLM von Keras Hub herunter. Mit dieser Klasse können Sie die kausale visuelle Sprachmodellstruktur von PaliGemma verwalten und ausführen. Ein kausales visuelles Sprachmodell sagt das nächste Token anhand der vorherigen Tokens voraus. Keras Hub bietet Implementierungen vieler beliebter Modellarchitekturen.

Erstellen Sie das Modell mit der Methode from_preset und geben Sie die Zusammenfassung aus. Dieser Vorgang dauert etwa eine Minute.

paligemma = keras_hub.models.PaliGemmaCausalLM.from_preset("kaggle://keras/paligemma2/keras/pali_gemma2_mix_3b_224")
paligemma.summary()

Hilfsmethoden erstellen

Um Antworten aus Ihrem Modell zu generieren, erstellen Sie zwei Hilfsmethoden:

  • crop_and_resize:Hilfsmethode für read_img. Bei dieser Methode wird das Bild auf die angegebene Größe zugeschnitten und in der Größe angepasst, sodass das endgültige Bild ohne Verzerrung der Proportionen angepasst wird.
  • read_img:Hilfsmethode für read_img_from_url. Mit dieser Methode wird das Bild geöffnet, so angepasst, dass es den Einschränkungen des Modells entspricht, und in ein Array eingefügt, das vom Modell interpretiert werden kann.
  • read_img_from_url:Nimmt ein Bild über eine gültige URL entgegen. Sie benötigen diese Methode, um das Bild an das Modell zu übergeben.

Sie benötigen read_img_from_url im nächsten Schritt dieses Notebooks.

def crop_and_resize(image, target_size):
    width, height = image.size
    source_size = min(image.size)
    left = width // 2 - source_size // 2
    top = height // 2 - source_size // 2
    right, bottom = left + source_size, top + source_size
    return image.resize(target_size, box=(left, top, right, bottom))

def read_image(url, target_size):
    contents = io.BytesIO(requests.get(url).content)
    image = PIL.Image.open(contents)
    image = crop_and_resize(image, target_size)
    image = np.array(image)
    # Remove alpha channel if necessary.
    if image.shape[2] == 4:
        image = image[:, :, :3]
    return image

def parse_bbox_and_labels(detokenized_output: str):
  matches = re.finditer(
      '<loc(?P<y0>\d\d\d\d)><loc(?P<x0>\d\d\d\d)><loc(?P<y1>\d\d\d\d)><loc(?P<x1>\d\d\d\d)>'
      ' (?P<label>.+?)( ;|$)',
      detokenized_output,
  )
  labels, boxes = [], []
  fmt = lambda x: float(x) / 1024.0
  for m in matches:
    d = m.groupdict()
    boxes.append([fmt(d['y0']), fmt(d['x0']), fmt(d['y1']), fmt(d['x1'])])
    labels.append(d['label'])
  return np.array(boxes), np.array(labels)

def display_boxes(image, boxes, labels, target_image_size):
  h, l = target_size
  fig, ax = plt.subplots()
  ax.imshow(image)
  for i in range(boxes.shape[0]):
      y, x, y2, x2 = (boxes[i]*h)
      width = x2 - x
      height = y2 - y
      # Create a Rectangle patch
      rect = patches.Rectangle((x, y),
                               width,
                               height,
                               linewidth=1,
                               edgecolor='r',
                               facecolor='none')
      # Add label
      plt.text(x, y, labels[i], color='red', fontsize=12)
      # Add the patch to the Axes
      ax.add_patch(rect)

  plt.show()

def display_segment_output(image, bounding_box, segment_mask, target_image_size):
    # Initialize a full mask with the target size
    full_mask = np.zeros(target_image_size, dtype=np.uint8)
    target_width, target_height = target_image_size

    for bbox, mask in zip(bounding_box, segment_mask):
        y1, x1, y2, x2 = bbox
        x1 = int(x1 * target_width)
        y1 = int(y1 * target_height)
        x2 = int(x2 * target_width)
        y2 = int(y2 * target_height)

        # Ensure mask is 2D before converting to Image
        if mask.ndim == 3:
            mask = mask.squeeze(axis=-1)
        mask = Image.fromarray(mask)
        mask = mask.resize((x2 - x1, y2 - y1), resample=Image.NEAREST)
        mask = np.array(mask)
        binary_mask = (mask > 0.5).astype(np.uint8)


        # Place the binary mask onto the full mask
        full_mask[y1:y2, x1:x2] = np.maximum(full_mask[y1:y2, x1:x2], binary_mask)
    cmap = plt.get_cmap('jet')
    colored_mask = cmap(full_mask / 1.0)
    colored_mask = (colored_mask[:, :, :3] * 255).astype(np.uint8)
    if isinstance(image, Image.Image):
        image = np.array(image)
    blended_image = image.copy()
    mask_indices = full_mask > 0
    alpha = 0.5

    for c in range(3):
        blended_image[:, :, c] = np.where(mask_indices,
                                          (1 - alpha) * image[:, :, c] + alpha * colored_mask[:, :, c],
                                          image[:, :, c])

    fig, ax = plt.subplots()
    ax.imshow(blended_image)
    plt.show()

Ausgabe generieren

Nachdem Sie das Modell geladen und Hilfsmethoden erstellt haben, können Sie dem Modell Bild- und Textdaten zur Verfügung stellen, um Antworten zu generieren. PaliGemma-Modelle werden mit einer bestimmten Prompt-Syntax für bestimmte Aufgaben trainiert, z. B. answer, caption und detect. Weitere Informationen zur Syntax von PaliGemma-Prompt-Aufgaben finden Sie unter PaliGemma-Prompts und ‑Systemanweisungen.

Bereiten Sie ein Bild für die Verwendung in einem Generierungs-Prompt vor, indem Sie mit dem folgenden Code ein Testbild in ein Objekt laden:

target_size = (224, 224)
image_url = 'https://storage.googleapis.com/keras-cv/models/paligemma/cow_beach_1.png'
cow_image = read_image(image_url, target_size)
matplotlib.pyplot.imshow(cow_image)

In einer bestimmten Sprache antworten

Im folgenden Beispielcode wird gezeigt, wie Sie das PaliGemma-Modell nach Informationen zu einem Objekt fragen, das auf einem bereitgestellten Bild zu sehen ist. In diesem Beispiel wird die answer {lang}-Syntax verwendet und es werden zusätzliche Fragen in anderen Sprachen angezeigt:

prompt = 'answer en where is the cow standing?\n'
# prompt = 'svar no hvor står kuen?\n'
# prompt = 'answer fr quelle couleur est le ciel?\n'
# prompt = 'responda pt qual a cor do animal?\n'

output = paligemma.generate(
    inputs={
        "images": cow_image,
        "prompts": prompt,
    }
)
print(output)

detect-Prompt verwenden

Im folgenden Beispielcode wird die detect-Prompt-Syntax verwendet, um ein Objekt im bereitgestellten Bild zu finden. Im Code werden die zuvor definierten Funktionen parse_bbox_and_labels() und display_boxes() verwendet, um die Modellausgabe zu interpretieren und die generierten rechteckigen Begrenzungsrahmen anzuzeigen.

prompt = 'detect cow\n'
output = paligemma.generate(
    inputs={
        "images": cow_image,
        "prompts": prompt,
    }
)
boxes, labels = parse_bbox_and_labels(output)
display_boxes(cow_image, boxes, labels, target_size)

segment-Prompt verwenden

Im folgenden Beispielcode wird die segment-Prompt-Syntax verwendet, um den Bereich eines Bildes zu ermitteln, der von einem Objekt belegt wird. Dabei wird die Google-Bibliothek big_vision verwendet, um die Modellausgabe zu interpretieren und eine Maske für das segmentierte Objekt zu generieren.

Installieren Sie zuerst die big_vision-Bibliothek und ihre Abhängigkeiten, wie in diesem Codebeispiel gezeigt:

import os
import sys

# TPUs with
if "COLAB_TPU_ADDR" in os.environ:
  raise "It seems you are using Colab with remote TPUs which is not supported."

# Fetch big_vision repository if python doesn't know about it and install
# dependencies needed for this notebook.
if not os.path.exists("big_vision_repo"):
  !git clone --quiet --branch=main --depth=1 \
     https://github.com/google-research/big_vision big_vision_repo

# Append big_vision code to python import path
if "big_vision_repo" not in sys.path:
  sys.path.append("big_vision_repo")


# Install missing dependencies. Assume jax~=0.4.25 with GPU available.
!pip3 install -q "overrides" "ml_collections" "einops~=0.7" "sentencepiece"

Laden Sie für dieses Segmentierungsbeispiel ein anderes Bild mit einer Katze und bereiten Sie es vor.

cat = read_image('https://big-vision-paligemma.hf.space/file=examples/barsik.jpg', target_size)
matplotlib.pyplot.imshow(cat)

Hier ist eine Funktion, mit der die Segmentausgabe von PaliGemma geparst werden kann.

import  big_vision.evaluators.proj.paligemma.transfers.segmentation as segeval
reconstruct_masks = segeval.get_reconstruct_masks('oi')
def parse_segments(detokenized_output: str) -> tuple[np.ndarray, np.ndarray]:
  matches = re.finditer(
      '<loc(?P<y0>\d\d\d\d)><loc(?P<x0>\d\d\d\d)><loc(?P<y1>\d\d\d\d)><loc(?P<x1>\d\d\d\d)>'
      + ''.join(f'<seg(?P<s{i}>\d\d\d)>' for i in range(16)),
      detokenized_output,
  )
  boxes, segs = [], []
  fmt_box = lambda x: float(x) / 1024.0
  for m in matches:
    d = m.groupdict()
    boxes.append([fmt_box(d['y0']), fmt_box(d['x0']), fmt_box(d['y1']), fmt_box(d['x1'])])
    segs.append([int(d[f's{i}']) for i in range(16)])
  return np.array(boxes), np.array(reconstruct_masks(np.array(segs)))

PaliGemma auffordern, die Katze im Bild zu segmentieren

prompt = 'segment cat\n'
output = paligemma.generate(
    inputs={
        "images": cat,
        "prompts": prompt,
    }
)

Generierte Maske von PaliGemma visualisieren

bboxes, seg_masks = parse_segments(output)
display_segment_output(cat, bboxes, seg_masks, target_size)

Batch-Prompts

Sie können in einem einzelnen Prompt mehrere Prompt-Befehle als Batch von Anweisungen angeben. Im folgenden Beispiel sehen Sie, wie Sie Ihren Prompt-Text strukturieren, um mehrere Anweisungen zu geben.

prompts = [
    'answer en where is the cow standing?\n',
    'answer en what color is the cow?\n',
    'describe en\n',
    'detect cow\n',
    'segment cow\n',
]
images = [cow_image, cow_image, cow_image, cow_image, cow_image]
outputs = paligemma.generate(
    inputs={
        "images": images,
        "prompts": prompts,
    }
)
for output in outputs:
    print(output)