使用 TensorFlow.js 進行預測性預先擷取

在本教學課程中,您將執行一個範例 Web 應用程式,該應用程式使用 TensorFlow.js 進行資源的預測性預先擷取。此範例以 Angular 建構,靈感來自 Google 商品商店,但不與其共用任何資料或實作細節。

此範例使用預先訓練的模型進行預測。在真實情境中,您需要使用來自您網站的分析資料來訓練模型。您可以使用 TFX 進行此類訓練。若要進一步瞭解如何針對預測性預先擷取訓練自訂模型,請參閱這篇部落格文章

範例程式碼可在 GitHub 上取得。

先決條件

若要完成本教學課程,您的開發環境中需要安裝下列項目

安裝範例

取得原始碼並安裝依附元件

  1. 複製或下載 tfjs-examples 存放區。
  2. 變更至 angular-predictive-prefetching/client 目錄並安裝依附元件

    cd tfjs-examples/angular-predictive-prefetching/client && yarn
    
  3. 變更至 angular-predictive-prefetching/server 目錄並安裝依附元件

    cd ../server && yarn
    

執行範例

同時啟動伺服器和用戶端

  1. 啟動伺服器:在 server 目錄中,執行 yarn start

  2. 啟動用戶端

    1. 開啟另一個終端機視窗。
    2. 變更至 tfjs-examples/angular-predictive-prefetching/client
    3. 執行下列指令

      yarn build
      cd dist/merch-store
      npx serve -s .
      

      系統可能會提示您安裝 serve 套件。如果提示,請輸入 y 以安裝套件。

  3. 在瀏覽器中導覽至 https://127.0.0.1:3000。您應該會看到模擬的 Google 商品商店。

使用開發人員工具探索

使用 Chrome 開發人員工具查看預先擷取運作情形

  1. 開啟開發人員工具並選取「主控台」。
  2. 在應用程式中導覽至幾個不同的頁面,以準備應用程式。然後在左側導覽中選取「特賣」。您應該會看到類似以下的記錄輸出

    Navigating from: 'sale'
    'quickview' -> 0.381757915019989
    'apparel-unisex' -> 0.3150934875011444
    'store.html' -> 0.1957530975341797
    '' -> 0.052346792072057724
    'signin.html' -> 0.0007763378671370447
    

    此輸出會顯示您 (使用者) 接下來將瀏覽之頁面的預測。應用程式會根據這些預測擷取資源。

  3. 若要查看擷取要求,請選取「網路」。輸出內容有點雜亂,但您應該能夠找到針對預測頁面資源的要求。例如,在預測 quickview 後,應用程式會向 https://127.0.0.1:8000/api/merch/quickview 發出要求。

預測性預先擷取如何運作

範例應用程式使用預先訓練的模型來預測使用者接下來將瀏覽的頁面。當使用者導覽至新頁面時,應用程式會查詢模型,然後預先擷取與預測頁面相關聯的圖片。

應用程式會在 Service Worker 上執行預測性預先擷取,以便在不封鎖主要執行緒的情況下查詢模型。Service Worker 會根據使用者的導覽記錄,預測未來的導覽並預先擷取相關的產品圖片。

Service Worker 會載入 Angular 應用程式的主要檔案 main.ts

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/prefetch.service-worker.js', { scope: '/' });
}

以上程式碼片段會下載 prefetch.service-worker.js 指令碼,並在背景中執行。

merch-display.component.ts 中,應用程式會將導覽事件轉送至 Service Worker

this.route.params.subscribe((routeParams) => {
  this.getMerch(routeParams.category);
  if (this._serviceWorker) {
    this._serviceWorker.postMessage({ page: routeParams.category });
  }
});

在以上程式碼片段中,應用程式會監看網址參數的變更。變更時,指令碼會將頁面的類別轉送至 Service Worker。

Service Worker 指令碼 prefetch.service-worker.js 會處理來自主要執行緒的訊息、根據訊息進行預測,並預先擷取相關資源。

Service Worker 使用 loadGraphModel載入預先訓練的模型

const MODEL_URL = "/assets/model.json";

let model = null;
tf.loadGraphModel(MODEL_URL).then((m) => (model = m));

預測發生在下列函式運算式

const predict = async (path, userId) => {
  if (!model) {
    return;
  }
  const page = pages.indexOf(path);
  const pageId = tf.tensor1d([parseInt(page)], "int32");

  const sessionIndex = tf.tensor1d([parseInt(userId)], "int32");

  const result = model.predict({
    cur_page: pageId,
    session_index: sessionIndex,
  });
  const values = result.dataSync();
  const orders = sortWithIndices(values).slice(0, 5);
  return orders;
};

predict 函式接著由 prefetch 函式叫用

const prefetch = async (path, sessionId) => {
  const predictions = await predict(path, sessionId);
  const formattedPredictions = predictions
    .map(([a, b]) => `'${b}' -> ${a}`)
    .join("\n");
  console.log(`Navigating from: '${path}'`);
  console.log(formattedPredictions);
  const connectionSpeed = navigator.connection.effectiveType;
  const threshold = connectionSpeeds[connectionSpeed];
  const cache = await caches.open(ImageCache);
  predictions.forEach(async ([probability, category]) => {
    if (probability >= threshold) {
      const merchs = (await getMerchList(category)).map(getUrl);
      [...new Set(merchs)].forEach((url) => {
        const request = new Request(url, {
          mode: "no-cors",
        });
        fetch(request).then((response) => cache.put(request, response));
      });
    }
  });
};

首先,prefetch 會預測使用者可能接下來瀏覽的頁面。然後,它會反覆查看預測。對於每個預測,如果機率超過根據連線速度的特定門檻,則函式會擷取預測頁面的資源。藉由在下一個頁面要求之前擷取這些資源,應用程式可以更快地提供內容,並提供更佳的使用者體驗。

後續步驟

在本教學課程中,範例應用程式使用預先訓練的模型進行預測。您可以使用 TFX 來訓練用於預測性預先擷取的模型。若要瞭解詳情,請參閱使用機器學習加速網站網頁預先擷取