Keras ile PaliGemma çıkışı oluşturma

ai.google.dev'de görüntüle Google Colab'de çalıştırma Vertex AI'da aç Kaynağı GitHub'da görüntüleyin

PaliGemma modelleri, çok formatlı özelliklere sahiptir. Bu sayede hem metin hem de görüntü giriş verilerini kullanarak çıkış oluşturabilirsiniz. İsteklerinize ek bağlam bilgisi sağlamak için bu modellerle birlikte resim verilerini kullanabilir veya resimlerin içeriğini analiz etmek için modeli kullanabilirsiniz. Bu eğiticide, görüntüleri analiz etmek ve bunlarla ilgili soruları yanıtlamak için Keras ile PaliGemma'yı nasıl kullanacağınız gösterilmektedir.

Bu not defterinin içeriği

Bu not defterinde Keras ile PaliGemma kullanılır ve şunlar gösterilir:

  • Keras'ı ve gerekli bağımlılıkları yükleyin.
  • Nedensel görsel dil modelleme için önceden eğitilmiş bir PaliGemma varyantı olan PaliGemmaCausalLM'yı indirin ve model oluşturmak için kullanın.
  • Modelin, sağlanan resimlerle ilgili bilgileri tahmin etme becerisini test edin.

Başlamadan önce

Bu not defterini incelemeden önce Python kodu ve büyük dil modellerinin (LLM'ler) nasıl eğitildiği hakkında bilgi sahibi olmanız gerekir. Keras'ı bilmeniz gerekmez ancak örnek kodu okurken Keras hakkında temel bilgilere sahip olmanız faydalıdır.

Kurulum

Aşağıdaki bölümlerde, model erişimi, API anahtarı alma ve not defteri çalışma zamanını yapılandırma dahil olmak üzere bir not defterinin PaliGemma modelini kullanması için gereken ön adımlar açıklanmaktadır.

PaliGemma'ya erişme

PaliGemma'yı ilk kez kullanmadan önce aşağıdaki adımları tamamlayarak Kaggle üzerinden modele erişim isteğinde bulunmanız gerekir:

  1. Kaggle'a giriş yapın veya hesabınız yoksa yeni bir Kaggle hesabı oluşturun.
  2. PaliGemma model kartına gidip Erişim İste'yi tıklayın.
  3. İzin formunu doldurun ve hükümler ile koşulları kabul edin.

API anahtarınızı yapılandırma

PaliGemma'yı kullanmak için Kaggle kullanıcı adınızı ve Kaggle API anahtarınızı sağlamanız gerekir.

Kaggle API anahtarı oluşturmak için Kaggle'daki Ayarlar sayfanızı açın ve Yeni Jeton Oluştur'u tıklayın. Bu işlem, API kimlik bilgilerinizi içeren bir kaggle.json dosyasının indirilmesini tetikler.

Ardından, Colab'de sol bölmede Secrets'ı (Gizli Anahtarlar) (🔑) seçin ve Kaggle kullanıcı adınızı ve Kaggle API anahtarınızı ekleyin. Kullanıcı adınızı KAGGLE_USERNAME adı altında, API anahtarınızı ise KAGGLE_KEY adı altında saklayın.

Çalışma zamanını seçin

Bu eğitimi tamamlamak için PaliGemma modelini çalıştıracak yeterli kaynağa sahip bir Colab çalışma zamanınızın olması gerekir. Bu durumda T4 GPU kullanabilirsiniz:

  1. Colab penceresinin sağ üst kısmında ▾ (Ek bağlantı seçenekleri) açılır menüsünü tıklayın.
  2. Çalışma zamanı türünü değiştir'i seçin.
  3. Donanım hızlandırıcı bölümünde T4 GPU'yu seçin.

Ortam değişkenlerini ayarlama

KAGGLE_USERNAME, KAGGLE_KEY ve KERAS_BACKEND için ortam değişkenlerini ayarlayın.

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'ı yükleme

Keras'ı yüklemek için aşağıdaki hücreyi çalıştırın.

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

Bağımlılıkları içe aktarma ve Keras'ı yapılandırma

Bu not defteri için gereken bağımlılıkları yükleyin ve Keras'ın arka ucunu yapılandırın. Ayrıca, Keras'ı bfloat16 kullanacak şekilde ayarlayarak çerçevenin daha az bellek kullanmasını sağlayacaksınız.

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")

Modeli yükleme

Her şeyi ayarladığınıza göre artık önceden eğitilmiş modeli indirebilir ve modelinizin yanıt oluşturmasına yardımcı olacak bazı yardımcı yöntemler oluşturabilirsiniz. Bu adımda, Keras Hub'dan PaliGemmaCausalLM kullanarak bir model indireceksiniz. Bu sınıf, PaliGemma'nın nedensel görsel dil modeli yapısını yönetmenize ve çalıştırmanıza yardımcı olur. Nedensel görsel dil modeli, önceki jetonlara göre bir sonraki jetonu tahmin eder. Keras Hub, birçok popüler model mimarisinin uygulamalarını sunar.

from_preset yöntemini kullanarak modeli oluşturun ve özetini yazdırın. Bu işlemin tamamlanması yaklaşık bir dakika sürer.

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

Yardımcı yöntemler oluşturma

Modelinizden yanıt oluşturmanıza yardımcı olması için iki yardımcı yöntem oluşturun:

  • crop_and_resize: read_img için yardımcı yöntem. Bu yöntem, resmi gönderilen boyuta göre kırpar ve yeniden boyutlandırır. Böylece, son resim, oranları bozulmadan yeniden boyutlandırılır.
  • read_img: read_img_from_url için yardımcı yöntem. Bu yöntem, resmi açan, modelin kısıtlamalarına uyacak şekilde yeniden boyutlandıran ve modeli yorumlayabileceği bir diziye yerleştiren yöntemdir.
  • read_img_from_url: Geçerli bir URL aracılığıyla resim alır. Görüntüyü modele iletmek için bu yöntemi kullanmanız gerekir.

read_img_from_url değerini bu not defterinin sonraki adımında kullanacaksınız.

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()

Çıkış oluşturma

Modeli yükleyip yardımcı yöntemler oluşturduktan sonra, yanıt oluşturması için modele resim ve metin verileriyle istemde bulunabilirsiniz. PaliGemma modelleri, answer, caption ve detect gibi belirli görevler için belirli istem söz dizimiyle eğitilir. PaliGemma istem görevi söz dizimi hakkında daha fazla bilgi için PaliGemma istemi ve sistem talimatları başlıklı makaleyi inceleyin.

Bir test görüntüsünü nesneye yüklemek için aşağıdaki kodu kullanarak bir üretim isteminde kullanılacak görüntüyü hazırlayın:

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)

Belirli bir dilde yanıt verme

Aşağıdaki örnek kodda, PaliGemma modeline sağlanan resimde görünen bir nesne hakkında bilgi isteminin nasıl gönderileceği gösterilmektedir. Bu örnekte answer {lang} söz dizimi kullanılıyor ve diğer dillerde ek sorular gösteriliyor:

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 istemini kullanma

Aşağıdaki örnek kod, sağlanan resimdeki bir nesneyi bulmak için detect istem söz dizimini kullanır. Kod, model çıkışını yorumlamak ve oluşturulan sınırlayıcı kutuları görüntülemek için daha önce tanımlanmış parse_bbox_and_labels() ve display_boxes() işlevlerini kullanır.

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 istemini kullanma

Aşağıdaki örnek kod, bir nesnenin kapladığı alanı bulmak için segment istem söz dizimini kullanır. Model çıkışını yorumlamak ve segmentlere ayrılmış nesne için maske oluşturmak üzere Google big_vision kitaplığını kullanır.

Başlamadan önce, bu kod örneğinde gösterildiği gibi big_vision kitaplığını ve bağımlılarını yükleyin:

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"

Bu segmentasyon örneği için kedi içeren farklı bir resmi yükleyip hazırlayın.

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

PaliGemma'dan gelen segment çıkışını ayrıştırmaya yardımcı olacak bir işlev aşağıda verilmiştir.

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)))

Resimdeki kediyi segmentlere ayırmak için PaliGemma'ya sorgu gönderme

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

PaliGemma'dan oluşturulan maskeyi görselleştirme

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

Toplu istemler

Tek bir istemde birden fazla istem komutu sağlayarak bir dizi talimat oluşturabilirsiniz. Aşağıdaki örnekte, istem metninizi birden fazla talimat verecek şekilde nasıl yapılandıracağınız gösterilmektedir.

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)