Tarayıcıda AI modellerini önbelleğe al

Çoğu yapay zeka modelinin en az bir ortak noktası vardır: çok büyük olması aktarıldığına dikkat edin. En küçük MediaPipe nesne algılama modeli (SSD MobileNetV2 float16) 5,6 MB ağırlığında En büyük boyut ise yaklaşık 25 MB'tır.

Açık kaynak LLM gemma-2b-it-gpu-int4.bin 1,35 GB'tır ve bu, büyük dil modeli için çok küçük olarak kabul edilir. Üretken yapay zeka modelleri çok büyük önem taşıyor. Günümüzde yapay zeka kullanımının büyük bir kısmının nedeni bu oluşturun. Uygulamalar giderek daha fazla doğrudan yüksek oranda optimize edilmiş modeller çalıştırıyor cihaz üzerinde. Tarayıcıda çalışan LLM'lerin demoları aşağıda bu örnekte çalışan diğer modellere ait bazı üretim düzeyinde tarayıcı:

İki zürafa ve ay olmak üzere üç nesne seçili halde, yapay zeka destekli nesne seçim aracı açık olarak web'de Adobe Photoshop.

Gelecekte uygulamalarınızın kullanıma sunulmasını daha hızlı hale getirmek için, uygulamanızın gizli HTTP tarayıcısına güvenmek yerine, cihazdaki model verilerini önbellek.

Bu kılavuzda chatbot oluşturmak için gemma-2b-it-gpu-int4.bin model kullanılır. yaklaşım, diğer modellere ve diğer kullanım alanlarına uyacak şekilde genelleştirilebilir cihaz üzerinde. Bir uygulamayı bir modele bağlamanın en yaygın yolu, modelimiz mevcut. Doğru aracı seçmek için teslimat.

Doğru önbellek üstbilgilerini yapılandırma

Sunucunuzdan yapay zeka modelleri sunuyorsanız Cache-Control kullanabilirsiniz. Aşağıdaki örnekte, kendi kendinize oluşturabileceğiniz sağlam bir varsayılan ayar burada bulabilirsiniz.

Cache-Control: public, max-age=31536000, immutable

Bir AI modelinin yayınlanan her sürümü statik bir kaynaktır. Hiçbir zaman uzun süre verilmelidir, max-age önbellek bozma ile birlikte ifadesini girin. Modeli güncellemeniz gerekiyorsa yeni bir URL verin.

Kullanıcı sayfayı yeniden yüklediğinde, istemci bir yeniden doğrulama isteği gönderir. sunucu içeriğin kararlı olduğunu bilir. İlgili içeriği oluşturmak için kullanılan immutable yönergesi yeniden doğrulamanın gerekli olmadığını açıkça belirtir çünkü değişmeyecek. immutable yönergesi yaygın olarak desteklenmiyor tarafından değil, tarayıcı önbelleği veya proxy sunucuları tarafından birleştirmesini herkes tarafından anlaşılabilecek bir max-age yönergesi görüyorsanız, uyumluluk. public yanıt yönergesi, yanıtın paylaşılan bir önbellekte depolanabileceğini belirtir.

Chrome Geliştirici Araçları, üretim aracını gösterir Cache-Control AI modeli istenirken Hugging Face tarafından gönderilen başlıklar. (Kaynak)

İstemci tarafında AI modellerini önbelleğe al

Bir yapay zeka modeli sunduğunuzda modelin emin olun. Böylece, kullanıcı sayfayı yeniden yükledikten sonra model verileri kullanılabilir hale gelir. görebilirsiniz.

Bunu başarmak için kullanabileceğiniz birkaç teknik vardır. Aşağıdakiler için örnek dosyalarını kullanarak her model dosyasının blob adlı Blob nesne inceleyebilirsiniz.

Performansı anlamak için her kod örneğine performance.mark() ve performance.measure() yöntemlerine göz atın. Bu ölçümler cihaza bağlı olup genelleştirilemez.

Chrome Geliştirici Araçları Uygulama'da > Storage, yorum IndexedDB, Önbellek depolama alanı ve Dosya Sistemi segmentlerinin yer aldığı kullanım şeması. Her segmentin 1.354 megabayt veri kullandığı gösterilir. Bu da toplamda 4.063 megabayta karşılık gelir megabayt.

Tarayıcıda AI modellerini önbelleğe almak için aşağıdaki API'lerden birini kullanabilirsiniz: Önbellek API'si, Origin Private File System API ve IndexedDB API. Genel öneri, Cache API'si fakat bu kılavuzda API'nin avantajları ve dezavantajları tüm seçenekleri sunar.

Önbellek API'si

Cache API, Request için kalıcı depolama alanı ve Response nesnesi çiftler için uzun ömürlü bellekte önbelleğe alınır. Her ne kadar Hizmet Çalışanları spesifikasyonunda tanımlanmıştır, Bu API'yi ana iş parçacığından veya normal bir çalışandan kullanabilirsiniz. Dışarıda kullanmak için bir hizmet çalışanı bağlamına göre, Cache.put() yöntem yerine sentetik bir URL ile eşlenmiş sentetik bir Response nesnesiyle eşleştirilir Request nesnesi.

Bu kılavuzda, bellek içi blob olduğu varsayılmıştır. Önbellek anahtarı olarak sahte bir URL ve sentetik Response [blob]. Veri analizini doğrudan fetch() oluşturarak elde edeceğiniz Response modelini kullanırsınız. isteğinde bulunabilirsiniz.

Örneğin, bir model dosyasının Cache API ile nasıl depolanacağı ve geri yükleneceği aşağıda açıklanmıştır.

const storeFileInSWCache = async (blob) => {
  try {
    performance.mark('start-sw-cache-cache');
    const modelCache = await caches.open('models');
    await modelCache.put('model.bin', new Response(blob));
    performance.mark('end-sw-cache-cache');

    const mark = performance.measure(
      'sw-cache-cache',
      'start-sw-cache-cache',
      'end-sw-cache-cache'
    );
    console.log('Model file cached in sw-cache.', mark.name, mark.duration.toFixed(2));
  } catch (err) {
    console.error(err.name, err.message);
  }
};

const restoreFileFromSWCache = async () => {
  try {
    performance.mark('start-sw-cache-restore');
    const modelCache = await caches.open('models');
    const response = await modelCache.match('model.bin');
    if (!response) {
      throw new Error(`File model.bin not found in sw-cache.`);
    }
    const file = await response.blob();
    performance.mark('end-sw-cache-restore');
    const mark = performance.measure(
      'sw-cache-restore',
      'start-sw-cache-restore',
      'end-sw-cache-restore'
    );
    console.log(mark.name, mark.duration.toFixed(2));
    console.log('Cached model file found in sw-cache.');
    return file;
  } catch (err) {    
    throw err;
  }
};

Kaynak Gizli Dosya Sistemi API'sı

Kaynak Gizli Dosya Sistemi (OPFS), yeni bir teknoloji ortamı için nispeten yeni bir standarttır depolama uç noktası. Sayfanın kaynağına özeldir ve bu nedenle görünmez dosya sisteminden farklı olarak kullanıcıya gönderilir. Özel bir konuma erişim sağlar performans için son derece optimize edilmiş ve dosyaya yazma erişimi sunan bir dosya içerik.

Örneğin, bir model dosyasının OPFS'de nasıl depolanacağı ve geri yükleneceği aşağıda açıklanmıştır.

const storeFileInOPFS = async (blob) => {
  try {
    performance.mark('start-opfs-cache');
    const root = await navigator.storage.getDirectory();
    const handle = await root.getFileHandle('model.bin', { create: true });
    const writable = await handle.createWritable();
    await blob.stream().pipeTo(writable);
    performance.mark('end-opfs-cache');
    const mark = performance.measure(
      'opfs-cache',
      'start-opfs-cache',
      'end-opfs-cache'
    );
    console.log('Model file cached in OPFS.', mark.name, mark.duration.toFixed(2));
  } catch (err) {
    console.error(err.name, err.message);
  }
};

const restoreFileFromOPFS = async () => {
  try {
    performance.mark('start-opfs-restore');
    const root = await navigator.storage.getDirectory();
    const handle = await root.getFileHandle('model.bin');
    const file = await handle.getFile();
    performance.mark('end-opfs-restore');
    const mark = performance.measure(
      'opfs-restore',
      'start-opfs-restore',
      'end-opfs-restore'
    );
    console.log('Cached model file found in OPFS.', mark.name, mark.duration.toFixed(2));
    return file;
  } catch (err) {    
    throw err;
  }
};

IndexedDB API'sı

IndexedDB rastgele verilerin kalıcı şekilde depolanması için iyi bilinen bir standarttır tıklayın. Karmaşık API'si ile biliniyor ancak idb-keyval gibi bir sarmalayıcı kitaplığı IndexedDB'yi klasik bir anahtar/değer deposu gibi kullanabilirsiniz.

Örneğin:

import { get, set } from 'https://cdn.jsdelivr.net/npm/idb-keyval@latest/+esm';

const storeFileInIDB = async (blob) => {
  try {
    performance.mark('start-idb-cache');
    await set('model.bin', blob);
    performance.mark('end-idb-cache');
    const mark = performance.measure(
      'idb-cache',
      'start-idb-cache',
      'end-idb-cache'
    );
    console.log('Model file cached in IDB.', mark.name, mark.duration.toFixed(2));
  } catch (err) {
    console.error(err.name, err.message);
  }
};

const restoreFileFromIDB = async () => {
  try {
    performance.mark('start-idb-restore');
    const file = await get('model.bin');
    if (!file) {
      throw new Error('File model.bin not found in IDB.');
    }
    performance.mark('end-idb-restore');
    const mark = performance.measure(
      'idb-restore',
      'start-idb-restore',
      'end-idb-restore'
    );
    console.log('Cached model file found in IDB.', mark.name, mark.duration.toFixed(2));
    return file;
  } catch (err) {    
    throw err;
  }
};

Depolama alanını kalıcı olarak işaretle

navigator.storage.persist() numaralı telefonu arayın kullanma izni istemek için bu önbelleğe alma yöntemlerinden herhangi birinin sonunda kalıcı depolama alanıdır. Bu yöntem, şu durumda true olarak çözümlenen bir söz döndürür: ve false izin verildiğini açıklamaz. Tarayıcı talebi kabul edebilir veya etmeyebilir, veya tarayıcıya özgü kurallara göre değişir.

if ('storage' in navigator && 'persist' in navigator.storage) {
  try {
    const persistent = await navigator.storage.persist();
    if (persistent) {
      console.log("Storage will not be cleared except by explicit user action.");
      return;
    }
    console.log("Storage may be cleared under storage pressure.");  
  } catch (err) {
    console.error(err.name, err.message);
  }
}

Özel durum: Sabit diskte model kullanma

Alternatif olarak doğrudan kullanıcının sabit diskinden yapay zeka modellerine başvurabilirsiniz. depolama alanına erişir. Bu teknik, araştırma odaklı uygulamaların farklı modellerin tarayıcıda çalıştırılmasının mümkün olup olmadığını veya sanatçıların yapay zeka alanındaki kendi kendini eğiten modeller.

File System Access API

File System Access API ile sabit diskteki dosyaları açabilir ve FileSystemFileHandle Böylece, IndexedDB'ye devam edebilirsiniz.

Bu kalıpta, kullanıcının yalnızca model dosyasına erişim izni vermesi gerekir bir kez. Kalıcı izinler sayesinde, kullanıcı dosyaya kalıcı olarak erişim izni vermeyi seçebilir. Dosyayı yeniden yükledikten sonra fare tıklaması gibi gerekli bir kullanıcı hareketini FileSystemFileHandle, dosyaya erişimle IndexedDB'den geri yüklenebilir yer alır.

Dosya erişim izinleri sorgulanır ve gerekirse istenir. Bu da bu sorun kolayca giderilebilir. Aşağıdaki örnekte, bir dosya için sabit diskte tutma yerini belirleyin ve ardından bu tutma yerini saklayıp geri yükleyin.

import { fileOpen } from 'https://cdn.jsdelivr.net/npm/browser-fs-access@latest/dist/index.modern.js';
import { get, set } from 'https://cdn.jsdelivr.net/npm/idb-keyval@latest/+esm';

button.addEventListener('click', async () => {
  try {
    const file = await fileOpen({
      extensions: ['.bin'],
      mimeTypes: ['application/octet-stream'],
      description: 'AI model files',
    });
    if (file.handle) {
      // It's an asynchronous method, but no need to await it.
      storeFileHandleInIDB(file.handle);
    }
    return file;
  } catch (err) {
    if (err.name !== 'AbortError') {
      console.error(err.name, err.message);
    }
  }
});

const storeFileHandleInIDB = async (handle) => {
  try {
    performance.mark('start-file-handle-cache');
    await set('model.bin.handle', handle);
    performance.mark('end-file-handle-cache');
    const mark = performance.measure(
      'file-handle-cache',
      'start-file-handle-cache',
      'end-file-handle-cache'
    );
    console.log('Model file handle cached in IDB.', mark.name, mark.duration.toFixed(2));
  } catch (err) {
    console.error(err.name, err.message);
  }
};

const restoreFileFromFileHandle = async () => {
  try {
    performance.mark('start-file-handle-restore');
    const handle = await get('model.bin.handle');
    if (!handle) {
      throw new Error('File handle model.bin.handle not found in IDB.');
    }
    if ((await handle.queryPermission()) !== 'granted') {
      const decision = await handle.requestPermission();
      if (decision === 'denied' || decision === 'prompt') {
        throw new Error(Access to file model.bin.handle not granted.');
      }
    }
    const file = await handle.getFile();
    performance.mark('end-file-handle-restore');
    const mark = performance.measure(
      'file-handle-restore',
      'start-file-handle-restore',
      'end-file-handle-restore'
    );
    console.log('Cached model file handle found in IDB.', mark.name, mark.duration.toFixed(2));
    return file;
  } catch (err) {    
    throw err;
  }
};

Bu yöntemler birlikte kullanılabilir. İkinizin de karşınızdakinin açık bir şekilde tarayıcıdaki bir modeli önbelleğe alır ve kullanıcının sabit diskindeki bir modeli kullanır.

Demo

Üç normal kılıf depolama yöntemini ve sabit disk yöntemini de görebilirsiniz MediaPipe LLM demosunda uygulanmıştır.

Bonus: Büyük dosyaları parçalar halinde indirin

İnternetten büyük bir yapay zeka modeli indirmeniz gerekiyorsa ve sonra istemcide birbirine tekrar yapıştırın.

Aşağıda, kodunuzda kullanabileceğiniz bir yardımcı işlev verilmiştir. Tek yapmanız gereken url. chunkSize (varsayılan: 5 MB), maxParallelRequests (varsayılan: 6), progressCallback işlevi ( downloadedBytes ve toplam fileSize) ve bir için signal AbortSignal sinyalinin tümü isteğe bağlıdır.

Aşağıdaki işlevi projenize kopyalayabilirsiniz veya fetch-in-chunks paketini npm paketinden yükleyin.

async function fetchInChunks(
  url,
  chunkSize = 5 * 1024 * 1024,
  maxParallelRequests = 6,
  progressCallback = null,
  signal = null
) {
  // Helper function to get the size of the remote file using a HEAD request
  async function getFileSize(url, signal) {
    const response = await fetch(url, { method: 'HEAD', signal });
    if (!response.ok) {
      throw new Error('Failed to fetch the file size');
    }
    const contentLength = response.headers.get('content-length');
    if (!contentLength) {
      throw new Error('Content-Length header is missing');
    }
    return parseInt(contentLength, 10);
  }

  // Helper function to fetch a chunk of the file
  async function fetchChunk(url, start, end, signal) {
    const response = await fetch(url, {
      headers: { Range: `bytes=${start}-${end}` },
      signal,
    });
    if (!response.ok && response.status !== 206) {
      throw new Error('Failed to fetch chunk');
    }
    return await response.arrayBuffer();
  }

  // Helper function to download chunks with parallelism
  async function downloadChunks(
    url,
    fileSize,
    chunkSize,
    maxParallelRequests,
    progressCallback,
    signal
  ) {
    let chunks = [];
    let queue = [];
    let start = 0;
    let downloadedBytes = 0;

    // Function to process the queue
    async function processQueue() {
      while (start < fileSize) {
        if (queue.length < maxParallelRequests) {
          let end = Math.min(start + chunkSize - 1, fileSize - 1);
          let promise = fetchChunk(url, start, end, signal)
            .then((chunk) => {
              chunks.push({ start, chunk });
              downloadedBytes += chunk.byteLength;

              // Update progress if callback is provided
              if (progressCallback) {
                progressCallback(downloadedBytes, fileSize);
              }

              // Remove this promise from the queue when it resolves
              queue = queue.filter((p) => p !== promise);
            })
            .catch((err) => {              
              throw err;              
            });
          queue.push(promise);
          start += chunkSize;
        }
        // Wait for at least one promise to resolve before continuing
        if (queue.length >= maxParallelRequests) {
          await Promise.race(queue);
        }
      }

      // Wait for all remaining promises to resolve
      await Promise.all(queue);
    }

    await processQueue();

    return chunks.sort((a, b) => a.start - b.start).map((chunk) => chunk.chunk);
  }

  // Get the file size
  const fileSize = await getFileSize(url, signal);

  // Download the file in chunks
  const chunks = await downloadChunks(
    url,
    fileSize,
    chunkSize,
    maxParallelRequests,
    progressCallback,
    signal
  );

  // Stitch the chunks together
  const blob = new Blob(chunks);

  return blob;
}

export default fetchInChunks;

Sizin için doğru yöntemi seçin

Bu kılavuzda, kullanıcının deneyimini geliştirmek ve tarayıcı ile alakalı en iyi performansı gösterir. Chrome Depolama Alanı ekibi, yapay zeka modellerine hızlı erişim sağlayarak yükleme sürelerini kısaltan optimum performans ve yanıt verme yeteneğini artırmak gibidir.

OPFS ve IndexedDB daha az kullanılabilir seçeneklerdir. OPFS ve IndexedDB API'leri saklanmadan önce serileştirilmesi gerekir. IndexedDB'nin şunları da yapması gerekir: Alınan verileri seri durumdan çıkarmayı ve bu nedenle bunları saklanmayacak en kötü yer haline getirmelidir. olabilir.

File System Access API, niş uygulamalar için dosyalara doğrudan erişim sunar. kendi AI modellerini yöneten kullanıcılar için idealdir.

Yapay zeka modelinizin güvenliğini sağlamanız gerekiyorsa modelinizi sunucuda tutun. Depolandıktan sonra hem Cache hem de IndexedDB'den veri ayıklamak çok basittir. Geliştirici Araçları veya OFPS Geliştirici Araçları uzantısı. Bu depolama API'lerinin güvenlikleri doğası gereği eşittir. Bütçenizi 2000 dolar kadar aştığınıza dair modelin şifrelenmiş sürümünü depolamanız gerekir ancak daha sonra şifre çözme işlemini kilit noktasıdır. Bu da ele geçirilebilir. Bu, kötü niyetli kişinin girişimi anlamına gelir modelini çalmak biraz daha zor olsa da imkansız değildir.

Uygulamanızın temel özellikleriyle uyumlu bir önbelleğe alma stratejisi seçmenizi, gereklilikler, hedef kitle davranışı ve yapay zeka modellerinin özellikleri kullanılır. Bu, uygulamalarınızın çeşitli koşullar altında duyarlı ve sağlam olmasını sağlar: ağ koşullarını ve sistem kısıtlamalarını içerir.


Teşekkür

Bu yorum Joshua Bell, Reilly Grant, Evan Stade, Nathan Memmott tarafından incelendi. Austin Sullivan, Etienne Noël, André Bandarra, Alexandra Klepper, François Beaufort, Paul Kinlan ve Rachel Andrew.