TensorFlow.js之安裝與核心概念


  TensorFlow.js是通過WebGL加速、基於瀏覽器的機器學習js框架。通過tensorflow.js,我們可以在瀏覽器中開發機器學習、運行現有的模型或者重新訓練現有的模型。

一、安裝

     有兩種方法可以在你的項目中引入tensorflow.js。一種是通過script標簽引入,另外一種就是通過npm進行安裝。

(1)通過script標簽,如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>tensorflow</title>
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.9.0"></script>
</head>
<body>
    <script>
        console.log(tf);
    </script>
</body>
</html>

  即直接引入tensorflow.js文件,然后我們在瀏覽器中打開console控制台,就可以看到tf是一個tensorflow.js暴露出來的對象,其包含了很多屬性和方法。

 

(2)npm安裝,即通過npm install @tensorflow/tfjs,然后在入口文件中使用 import * as tf from '@tensorflow/tfjs' 即可。

  

  注意:tensorflow是用ES7的寫法,所以,如果要在瀏覽器環境下運行,就必須使用babel轉換為瀏覽器可以執行的代碼。

 

 

二、核心概念

(1)Tensors(張量)

  Tensorflow.js中數據的主要表現形式就是tensor(張量):由 一組數值  形成 一維或多維數組。一個Tensor實例有一個shape屬性來定義這一組數值如何組成張量(比如在數組的每個維度的數量各自有多少)。而最主要的Tensor實例的構造函數就是 tf.tensor 函數,如下所示:

const shape = [2, 3]; // 2行,3列
const a = tf.tensor([1.0, 2.0, 3.0, 10.0, 20.0, 30.0], shape);
a.print();
console.log(Object.prototype.toString.call(a));

const b = tf.tensor([[1.0, 2.0, 3.0], [10.0, 20.0, 30.0]]);
b.print();
  1. 我們制定了shape為2行3列,那么調用tf.tensor構造函數來構造張量時,就需要在第一個參數中傳入 2 * 3 = 6個數字的數組,接着通過a.print()在控制台打印出來,是一個二維數組。
  2. 為了確定張量a的類型,我們可以使用JavaScript的Object.prototype.toString.call()方法來查看。 實際上張量雖然表現為一維或多維數組,但他本質上是一個對象。
  3. 張量的形狀也可以直接被傳入數組來直接構造,即張量b就是通過傳入一個二維數組構造得到的張量。

       

 

  

    然后,對於構建低維度的張量,我們推薦使用下面的函數來增強代碼的可讀性:tf.scalar(零維), tf.tensor1d(一維), tf.tensor2d(二維), tf.tensor3d(三維)、tf.tensor4d(四維)以及 tf.ones(值全是1)或者tf.zeros(值全是0) ,如下所示:

    const a = tf.scalar(3.14);
    a.print(); // 輸出零維張量

    const b = tf.tensor2d([[2, 3, 4], [5, 6, 7]]);
    b.print(); // 輸出二維張量

    const c = tf.zeros([2, 3]);
    c.print(); // 輸出2行3列的值全是0的張量

    const d = tf.ones([3, 5]);
    d.print(); // 輸出3行5列的值全是1的張量

  如下所示:

  在TensorFlow.js中,張量tensors是不可變(immutable)的;一旦被創建,你就無法改變他們的值,除了使用操作符產生新的tensors張量。

  

 

(2)Variables(變量)

  Variables變量是通過張量進行初始化得到的。不像Tensor的值不可變,變量的值是可變的。你可以使用變量的assign方法分配一個新的tensor到這個變量上,這是變量就會改變

    const initialValues = tf.zeros([5]);
    const biases = tf.variable(initialValues);
    biases.print();
    console.log(Object.prototype.toString.call(biases));

    const updatedValues = tf.tensor1d([0, 1, 0, 1, 0]);
    biases.assign(updatedValues);
    biases.print();

  如上所示,首先使用tf.zeros得到一個張量,然后利用這個張量初始化得到一個變量,接着我們就可以打印這個變量,並且通Object.prototype.toString.call(biases)方法可以判斷變量也是一個對象,接着,我們再生成一個張量,然后變量調用assign方法傳入這個張量,就可以得到一個新的變量了,如下

  

  於是我們可以得出這樣一個結論:變量由張量生成,且張量不可變而變量可變。

 

 

(3)Operations操作

  張量可以用來存儲數據,而operation可以用來操作數據。 TensorFlow.js為線性代數計算和機器學習提供了一系列有用的操作符,可以用來處理張量。因為張量是不可變的,所以這些操作符不會改變這些張量的值,而是會返回一個新的張量。 就像JavaScript中的字符串一樣,無論你怎么操作,這些字符串本身不會改變,而只會返回一個新的值。

  比如下面這個一元操作符 square 操作符用來求平方:

    const a = tf.tensor2d([[1.0, 2.0], [3.0, 4.0]]);
    const a_squared = a.square();
    a_squared.print();
    a.print();

  如上所示,我們通過tf.tensor2d創建了一個2行2列的張量a,然后使用square操作得到了a_square,下面是控制台中的結果:

       

 

  下面是一個add、sub、mul的二元操作符示例:

    const a = tf.tensor2d([[5.0, 6.0], [7.0, 8.0]]);
    const b = tf.tensor2d([[1.0, 2.0], [3.0, 4.0]]);

    const a_plus_b = a.add(b);
    a_plus_b.print();

    const a_sub_b = a.sub(b);
    a_sub_b.print();

    const a_mul_b = a.mul(b);
    a_mul_b.print();

   如下所示,我們就可以得到add、sub、mul的結果:

      

       

            另外,在TensorFlow.js中也是支持鏈式操作的,如下所示:

    const a = tf.tensor2d([[2.0, 2.0], [2.0, 2.0]]);
    const b = tf.tensor2d([[3.0, 3.0], [3.0, 3.0]]);
    const c = tf.tensor2d([[5.0, 5.0], [5.0, 5.0]]);
    const res = a.add(b).square().sub(c);
    res.print();

    即首先得到a.add(b)的結果然后再sub(減)c,這樣的鏈式操作得到res,結果如下:

          

 

   

(4)模型(Models)和層(Layers)

  從概念上來說,一個模型一個給定一些輸入將會產生特定的輸出的函數。從前面黑體字可以看出,一個模型就是一個函數,只是它完成了特定的任務。

  在TensorFlow.js中有兩種方式來創建模型,一種是通過操作(ops)來直接完成模型本身所做的工作,另外一種就是通過高級API tf.model來創建一個模型,顯然第二種是更容易的。

  我們先看第一種創建模型的方法:

   function predict (input) {
        // y = a*x^2 + b*x + c
        return tf.tidy(() => {
            const x = tf.scalar(input);

            const ax2 = a.mul(x.square());
            const bx = b.mul(x);
            const y = ax2.add(bx).add(c);
            
            return y;
        });
    }

    // 定義常量
    const a = tf.scalar(2);
    const b = tf.scalar(4);
    const c = tf.scalar(8);

    // 對於2預測輸出
    const result = predict(2);
    result.print(); // Tensor 24

  如上所示,我們定義的predict函數就是一個模型,對於給定的輸入,我們就可以得到預測的輸出。注意:所有的數字都需要經過tf.scalar()張量處理。

  

  而第二種創建模型的方法就是用 TensorFlow.js 中的 tf.model 方法(這里的model並不是真正可以調用的方法,而是一個總稱,比如實際上可以調用的是tf.sequential模型),這在深度學習中是非常流行的概念。 下面的代碼就創建了 tf.sequential 模型:

    const model = tf.sequential();
    model.add(
        tf.layers.simpleRNN({
            units: 20,
            recurrentInitializer: 'GlorotNormal',
            inputShape: [80, 4]
        })
    );

    const optimizer = tf.train.sgd(LEARNING_RATE);
    model.compile({optimizer, loss: 'categoricalCrossentropy'});
    model.fit({x: data, y: labels});

  注意:這段代碼有錯,日后解決。 這里大概就是在表達tf創建模型有給定的模型供我們使用,而第一種方法是我們完全自己去寫的模型。

 

 

(5)內存管理: dispose和tf.tidy

  因為TensorFlow.js使用了GPU來加速數學運算,因此當tensorflow處理張量和變量時就有必要來管理GPU內存。而主要的兩個管理內存的方法就是: dispose 和 tf.tidy。

   dispose

       我們可以使用對 張量 或者 變量 在運算之后使用dispose來清理以及釋放它的GPU內存。如下所示:

    const x = tf.tensor2d([[0.0, 2.0], [4.0, 6.0]]);
    const x_squared = x.square();

    x.dispose();
    x_squared.dispose();

 

  tf.tidy

   當我們做了大量了Tensor操作時,再使用 dispose 處理起來會非常不方便。所以TensorFlow.js提供了另外一個函數:tf.tidy,這個函數和JavaScript中作用域都扮演了同樣的角色,只不過這個函數是為tensors服務的。

    tf.tidy 執行了一個函數並且清理了中間創建的tensor,以此加速了GPU內存,但是它不會清理其內部函數最終的返回值,所以只是起到了GPU加速目的,而不會影響tensor計算,如下:

   const average = tf.tidy(() => {
        // tf.tidy會清除所有的tensor產生的內存使得GPU加速
        // 盡管下面是一個簡單操作,但是還是會產生很多中間張量,
        // 所以將這些數學運算放在tidy函數中是最佳實踐
        const y = tf.tensor1d([1.0, 2.0, 3.0, 4.0]);
        const z = tf.ones([4]);

        return y.sub(z).square().mean();
    });

    average.print(); // Tensor 3.5

    這樣,我們就可以使用最大效率的GPU加速了。其中,mean()函數是求取平均值的操作,如下所示:

    const average = tf.tensor1d([1, 2, 3, 4, 5]).mean();
    average.print(); // Tensor 3

  因此, tf.tidy可以幫助阻止程序內存泄露。下面是兩個我們需要額外注意的點:

  1. 傳入tf.tidy內的函數必須是同步的且不能Promise,我們建議對於更新UI的代碼以及http請求的代碼都放在tf.tidy之外。
  2. tf.tidy 不會清理變量 Variable。 因為變量往往會持續整個機器學習模型的生命周期,所以,即使它們在tf.tidy函數中創建TensorFlow.js也不會清理它們,然而,是可以通過dispose來手動清理的。

 

  

  

    到這里,tensorflow.js的安裝和核心概念就結束了,后面會有更多關於tensorflow的文章。 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM