Membuat output PaliGemma dengan Keras

Lihat di ai.google.dev Jalankan di Google Colab Buka di Vertex AI Lihat sumber di GitHub

Model PaliGemma memiliki kemampuan multimodal, sehingga Anda dapat menghasilkan output menggunakan data input teks dan gambar. Anda dapat menggunakan data gambar dengan model ini untuk memberikan konteks tambahan pada permintaan Anda, atau menggunakan model untuk menganalisis konten gambar. Tutorial ini menunjukkan cara menggunakan PaliGemma dengan Keras untuk menganalisis gambar dan menjawab pertanyaan tentang gambar tersebut.

Isi notebook ini

Notebook ini menggunakan PaliGemma dengan Keras dan menunjukkan cara:

  • Instal Keras dan dependensi yang diperlukan
  • Download PaliGemmaCausalLM, varian PaliGemma yang telah dilatih sebelumnya untuk pemodelan bahasa visual kausal, dan gunakan untuk membuat model
  • Menguji kemampuan model untuk menyimpulkan informasi tentang gambar yang diberikan

Sebelum memulai

Sebelum mempelajari notebook ini, Anda harus memahami kode Python, serta cara melatih model bahasa besar (LLM). Anda tidak perlu memahami Keras, tetapi pengetahuan dasar tentang Keras akan membantu saat membaca kode contoh.

Penyiapan

Bagian berikut menjelaskan langkah-langkah awal untuk membuat notebook menggunakan model PaliGemma, termasuk akses model, mendapatkan kunci API, dan mengonfigurasi runtime notebook.

Mendapatkan akses ke PaliGemma

Sebelum menggunakan PaliGemma untuk pertama kalinya, Anda harus meminta akses ke model melalui Kaggle dengan menyelesaikan langkah-langkah berikut:

  1. Login ke Kaggle, atau buat akun Kaggle baru jika Anda belum memilikinya.
  2. Buka kartu model PaliGemma, lalu klik Minta Akses.
  3. Lengkapi formulir izin dan setujui persyaratan dan ketentuan.

Mengonfigurasi kunci API

Untuk menggunakan PaliGemma, Anda harus memberikan nama pengguna Kaggle dan kunci API Kaggle.

Untuk membuat kunci API Kaggle, buka halaman Settings di Kaggle, lalu klik Create New Token. Tindakan ini akan memicu download file kaggle.json yang berisi kredensial API Anda.

Kemudian, di Colab, pilih Secrets (🔑) di panel kiri dan tambahkan nama pengguna Kaggle dan kunci API Kaggle Anda. Simpan nama pengguna Anda dengan nama KAGGLE_USERNAME dan kunci API Anda dengan nama KAGGLE_KEY.

Memilih runtime

Untuk menyelesaikan tutorial ini, Anda harus memiliki runtime Colab dengan resource yang memadai untuk menjalankan model PaliGemma. Dalam hal ini, Anda dapat menggunakan GPU T4:

  1. Di kanan atas jendela Colab, klik menu dropdown ▾ (Opsi koneksi tambahan).
  2. Pilih Ubah jenis runtime.
  3. Di bagian Hardware accelerator, pilih T4 GPU.

Menetapkan variabel lingkungan

Tetapkan variabel lingkungan untuk KAGGLE_USERNAME, KAGGLE_KEY, dan KERAS_BACKEND.

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"

Menginstal Keras

Jalankan sel di bawah untuk menginstal Keras.

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

Mengimpor dependensi dan mengonfigurasi Keras

Instal dependensi yang diperlukan untuk notebook ini dan konfigurasi backend Keras. Anda juga akan menyetel Keras untuk menggunakan bfloat16 sehingga framework menggunakan lebih sedikit memori.

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

Memuat model

Setelah menyiapkan semuanya, Anda dapat mendownload model terlatih dan membuat beberapa metode utilitas untuk membantu model menghasilkan responsnya. Pada langkah ini, Anda akan mendownload model menggunakan PaliGemmaCausalLM dari Keras Hub. Kelas ini membantu Anda mengelola dan menjalankan struktur model bahasa visual kausal PaliGemma. Model bahasa visual kausal memprediksi token berikutnya berdasarkan token sebelumnya. Keras Hub menyediakan implementasi banyak arsitektur model populer.

Buat model menggunakan metode from_preset dan cetak ringkasannya. Proses ini akan memerlukan waktu sekitar satu menit.

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

Membuat metode utilitas

Untuk membantu Anda membuat respons dari model, buat dua metode utilitas:

  • crop_and_resize: Metode helper untuk read_img. Metode ini memangkas dan mengubah ukuran gambar ke ukuran yang diteruskan sehingga gambar akhir diubah ukurannya tanpa memiringkan proporsi gambar.
  • read_img: Metode helper untuk read_img_from_url. Metode ini benar-benar membuka gambar, mengubah ukurannya agar sesuai dengan batasan model, dan memasukkannya ke dalam array yang dapat ditafsirkan oleh model.
  • read_img_from_url: Mengambil gambar melalui URL yang valid. Anda memerlukan metode ini untuk meneruskan gambar ke model.

Anda akan menggunakan read_img_from_url di langkah berikutnya dalam notebook ini.

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

Menghasilkan output

Setelah memuat model dan membuat metode utilitas, Anda dapat meminta model dengan data gambar dan teks untuk menghasilkan respons. Model PaliGemma dilatih dengan sintaksis perintah tertentu untuk tugas tertentu, seperti answer, caption, dan detect. Untuk mengetahui informasi selengkapnya tentang sintaksis tugas perintah PaliGemma, lihat Perintah dan petunjuk sistem PaliGemma.

Siapkan gambar untuk digunakan dalam perintah pembuatan dengan menggunakan kode berikut untuk memuat gambar pengujian ke dalam objek:

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)

Menjawab dalam bahasa tertentu

Contoh kode berikut menunjukkan cara meminta informasi tentang objek yang muncul dalam gambar yang diberikan kepada model PaliGemma. Contoh ini menggunakan sintaksis answer {lang} dan menampilkan pertanyaan tambahan dalam bahasa lain:

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)

Menggunakan perintah detect

Contoh kode berikut menggunakan sintaksis perintah detect untuk menemukan objek dalam gambar yang diberikan. Kode ini menggunakan fungsi parse_bbox_and_labels() dan display_boxes() yang ditentukan sebelumnya untuk menafsirkan output model dan menampilkan kotak pembatas yang dihasilkan.

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)

Menggunakan perintah segment

Contoh kode berikut menggunakan sintaksis perintah segment untuk menemukan area gambar yang ditempati oleh suatu objek. Model ini menggunakan library big_vision Google untuk menafsirkan output model dan membuat mask untuk objek yang tersegmentasi.

Sebelum memulai, instal library big_vision dan dependensinya, seperti yang ditunjukkan dalam contoh kode ini:

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"

Untuk contoh segmentasi ini, muat dan siapkan gambar lain yang menyertakan kucing.

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

Berikut adalah fungsi untuk membantu mengurai output segmen dari PaliGemma

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

Kueri PaliGemma untuk menyegmentasikan kucing dalam gambar

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

Memvisualisasikan mask yang dihasilkan dari PaliGemma

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

Batch perintah

Anda dapat memberikan lebih dari satu perintah prompt dalam satu perintah sebagai batch petunjuk. Contoh berikut menunjukkan cara menyusun teks perintah untuk memberikan beberapa petunjuk.

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)