基于tensorflow.js的人工智能開(kāi)發(fā)入門

什么是Tensorflow.js?

TensorFlow.js是一個(gè)開(kāi)源的基于硬件加速的JavaScript庫(kù)奈附,用于訓(xùn)練和部署機(jī)器學(xué)習(xí)模型惭聂。谷歌推出的第一個(gè)基于TensorFlow的前端深度學(xué)習(xí)框架TensorFlow.js 是一個(gè)開(kāi)源的用于開(kāi)發(fā)機(jī)器學(xué)習(xí)項(xiàng)目的 WebGL-accelerated JavaScript 庫(kù)。TensorFlow.js可以提供高性能的盛泡、易于使用的機(jī)器學(xué)習(xí)構(gòu)建模塊捺癞,允許在瀏覽器上訓(xùn)練模型夷蚊,或以推斷模式運(yùn)行預(yù)訓(xùn)練的模型。TensorFlow.js 不僅可以提供低級(jí)的機(jī)器學(xué)習(xí)構(gòu)建模塊髓介,還可以提供高級(jí)的類似 Keras 的 API 來(lái)構(gòu)建神經(jīng)網(wǎng)絡(luò)惕鼓。

個(gè)人站點(diǎn):https://whl1207.github.io/,記錄一些學(xué)習(xí)筆記唐础,主要寫點(diǎn)基于anylogic的仿真和web開(kāi)發(fā)方面的知識(shí)點(diǎn)呜笑。有興趣的同學(xué)可以探討一下!

Tensorflow.js的優(yōu)點(diǎn)

  • 1彻犁、不用安裝驅(qū)動(dòng)器和軟件叫胁,通過(guò)鏈接即可分享程序。
  • 2汞幢、網(wǎng)頁(yè)應(yīng)用交互性更強(qiáng)驼鹅。
  • 3、有訪問(wèn)GPS森篷,Camera输钩,Microphone,Accelerator仲智,Gyroscope等傳感器的標(biāo)準(zhǔn)api(主要是指手機(jī)端)买乃。
  • 4、安全性钓辆,因?yàn)閿?shù)據(jù)都是保存在客戶端的剪验。

TensorFlow.js的應(yīng)用方式

  • 1、在瀏覽器中開(kāi)發(fā)ML前联。使用簡(jiǎn)單直觀的API從頭構(gòu)建模型功戚,然后使用低級(jí)別的JavaScript線性代數(shù)庫(kù)或高層API進(jìn)行訓(xùn)練。

  • 2似嗤、運(yùn)行現(xiàn)有模型啸臀。使用TensorFlow.js模型轉(zhuǎn)換器在瀏覽器中運(yùn)行預(yù)訓(xùn)練好的TensorFlow模型。

  • 3烁落、重新訓(xùn)練現(xiàn)有模型乘粒。使用連接到瀏覽器的傳感器數(shù)據(jù)或其他客戶端數(shù)據(jù)重新訓(xùn)練ML模型。

一伤塌、基本概念

張量(Tensor)和變量(Variable)是TensorFlow.js中數(shù)據(jù)的主要表現(xiàn)形式灯萍,兩者不同之處在于張量是不可變的,而變量是可變的寸谜。

(一)張量(Tensors)

張量=容器竟稳,張量是現(xiàn)代機(jī)器學(xué)習(xí)的基礎(chǔ)。它的核心是一個(gè)數(shù)據(jù)容器熊痴,多數(shù)情況下他爸,它包含數(shù)字,有時(shí)候它也包含字符串果善,但這種情況比較少诊笤。因此把它想象成一個(gè)數(shù)字的水桶。

張量是由一組數(shù)值形成一個(gè)或多個(gè)維度的數(shù)組巾陕。 張量實(shí)例具有定義數(shù)組形狀的形狀屬性讨跟。

Tensorflow.js中數(shù)據(jù)的主要表現(xiàn)形式就是tensor(張量):由 一組數(shù)值形成一維或多維數(shù)組。一個(gè)Tensor實(shí)例有一個(gè)shape屬性來(lái)定義這一組數(shù)值如何組成張量,而最主要的Tensor實(shí)例的構(gòu)造函數(shù)就是 tf.tensor 函數(shù)鄙煤,如下所示:

// 2x3 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(); // 打印張量值
// 輸出:    [[1 , 2 , 3 ],
//          [10, 20, 30]]

// shape也可以用下面的方式實(shí)現(xiàn):
const b = tf.tensor([[1.0, 2.0, 3.0], [10.0, 20.0, 30.0]]);
b.print();
// 輸出:    [[1 , 2 , 3 ],
//          [10, 20, 30]]

但是晾匠,為了構(gòu)造低秩張量,我們推薦使用下面的函數(shù)來(lái)增強(qiáng)代碼的可讀性: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中,張量是不變的; 一旦創(chuàng)建你就不能改變它們的值亡资。 但是澜共,您可以對(duì)它們執(zhí)行操作來(lái)生成新的張量。

(二)變量(Variable)

變量(Variables)是通過(guò)張量進(jìn)行初始化得到的锥腻。不像Tensor的值不可變嗦董,變量的值是可變的。你可以使用變量的assign方法分配一個(gè)新的tensor到這個(gè)變量上瘦黑,這是變量就會(huì)改變:

const initialValues = tf.zeros([5]);
const biases = tf.variable(initialValues); // 初始化biases
biases.print(); // 輸出: [0, 0, 0, 0, 0]

const updatedValues = tf.tensor1d([0, 1, 0, 1, 0]);
biases.assign(updatedValues); // 更新 biases的值
biases.print(); // 輸出: [0, 1, 0, 1, 0]

如上所示京革,首先使用tf.zeros得到一個(gè)張量,然后利用這個(gè)張量初始化得到一個(gè)變量幸斥,接著我們就可以打印這個(gè)變量存崖,并且通Object.prototype.toString.call(biases)方法可以判斷變量也是一個(gè)對(duì)象,接著睡毒,我們?cè)偕梢粋€(gè)張量来惧,然后變量調(diào)用assign方法傳入這個(gè)張量,就可以得到一個(gè)新的變量了演顾。

由此我們可以得出一個(gè)結(jié)論:變量由張量生成供搀,且張量不可變而變量可變。

二钠至、Tensorflow.js 模型

在Tensorflow.js中葛虐,從概念上來(lái)說(shuō),一個(gè)模型就是一個(gè)給定一些輸入將會(huì)產(chǎn)生特定的輸出的函數(shù)棉钧。簡(jiǎn)單來(lái)說(shuō)屿脐,一個(gè)模型就是一個(gè)函數(shù),只是它完成了特定的任務(wù)。

在TensorFlow.js中有兩種方式來(lái)創(chuàng)建模型的诵,一種是通過(guò)操作(ops)來(lái)直接完成模型本身所做的工作万栅,另外一種就是通過(guò)高級(jí)API tf.model來(lái)創(chuàng)建一個(gè)模型,顯然第二種是更容易的西疤。

我們先看第一種創(chuàng)建模型的方法:

function predict(input) {
  // y = a * x ^ 2 + b * x + c
  // More on tf.tidy in the next section
  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);

const result = predict(2);
result.print();

如上所示烦粒,我們定義的predict函數(shù)就是一個(gè)模型,對(duì)于給定的輸入代赁,我們就可以得到預(yù)測(cè)的輸出扰她。注意:所有的數(shù)字都需要經(jīng)過(guò)tf.scalar()張量處理。

而第二種創(chuàng)建模型的方法就是用 TensorFlow.js 中的 tf.model 方法(這里的model并不是真正可以調(diào)用的方法芭碍,而是一個(gè)總稱徒役,比如實(shí)際上可以調(diào)用的是tf.sequential模型),這在深度學(xué)習(xí)中是非常流行的概念窖壕。 下面的代碼就創(chuàng)建了 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)});

三廉涕、Tensorflow.js 內(nèi)存管理

因?yàn)門ensorFlow.js使用了GPU來(lái)加速數(shù)學(xué)運(yùn)算,因此當(dāng)tensorflow處理張量和變量時(shí)就有必要來(lái)管理GPU內(nèi)存艇拍。在TensorFlow.js中狐蜕,我們可以通過(guò)dispose 和 tf.tidy這兩種方法來(lái)管理內(nèi)存。

(一)dispose

您可以在張量或變量上調(diào)用dispose來(lái)清除它并釋放其GPU內(nèi)存:

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

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

(二)tf.tidy

進(jìn)行大量的張量操作時(shí)使用dispose可能會(huì)很麻煩卸夕。 TensorFlow.js提供了另一個(gè)函數(shù)tf.tidy层释,它對(duì)JavaScript中的常規(guī)范圍起到類似的作用,不同的是它針對(duì)GPU支持的張量快集。

tf.tidy執(zhí)行一個(gè)函數(shù)并清除所有創(chuàng)建的中間張量贡羔,釋放它們的GPU內(nèi)存。 它不清除內(nèi)部函數(shù)的返回值个初。

const average = tf.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();

使用tf.tidy將有助于防止應(yīng)用程序中的內(nèi)存泄漏乖寒。它也可以用來(lái)更謹(jǐn)慎地控制內(nèi)存何時(shí)回收。

兩個(gè)重要的注意事項(xiàng):

  • 1院溺、傳遞給tf.tidy的函數(shù)應(yīng)該是同步的楣嘁,并且不會(huì)返回Promise。我們建議在tf.tidy內(nèi)不要有更新UI或在發(fā)出遠(yuǎn)程請(qǐng)求的代碼珍逸。

  • 2逐虚、tf.tidy不會(huì)清理變量。變量通常持續(xù)到機(jī)器學(xué)習(xí)模型的整個(gè)生命周期谆膳,因此TensorFlow.js不會(huì)清理它們叭爱,即使它們是在tidy中創(chuàng)建的。不過(guò)漱病,您可以手動(dòng)調(diào)用dispose處理它們买雾。

四把曼、實(shí)例

(一)使用tensorflow進(jìn)行線性回歸

下面是一個(gè)使用tensorflow.js進(jìn)行線性回歸的案例,完整代碼如下:

<!DOCTYPE html>
<html style="height: 100%">
   <head>
       <meta charset="utf-8">
    </head>
   <body style="height: 100%; margin: 0">
       <div id="container" style="height: 100%"></div><!-- 繪圖區(qū)域 -->
       <script type="text/javascript" src="https://echarts.baidu.com/gallery/vendors/echarts/echarts.min.js"></script> <!-- 引入echart進(jìn)行繪圖 -->
       <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.14.2/dist/tf.min.js"></script><!-- 引入tersorflow.js -->
       <script type="text/javascript">

            function generateData(numPoints, coeff, sigma = 0.04) {//產(chǎn)生偽隨機(jī)數(shù)
                return tf.tidy(() => {
                    const [k, b] = [tf.scalar(coeff.k),tf.scalar(coeff.b)];

                    const xs = tf.randomUniform([numPoints], -1, 1);//x坐標(biāo)
                    const ys = k.mul(xs).add(b)//y坐標(biāo)
                    .add(tf.randomNormal([numPoints], 0, sigma));//疊加噪聲

                    return {xs, ys: ys};
                })
            }

            // Step 1. 要回歸的變量
            const k = tf.variable(tf.scalar(Math.random()));
            const b = tf.variable(tf.scalar(Math.random()));
            // Step 2. 選取優(yōu)化器漓穿、迭代次數(shù)等參數(shù)
            const numIterations = 75;
            const learningRate = 0.5;
            const optimizer = tf.train.sgd(learningRate);
            // Step 3. 預(yù)測(cè)函數(shù)嗤军,定義為線性函數(shù)y = k * x + b
            function predict(x) {// y = k * x + b
            return tf.tidy(() => {return k.mul(x).add(b);});
            }
            // Step 4. 計(jì)算方差,方差越小說(shuō)明預(yù)測(cè)值越精確
            function loss(prediction, labels) {
            const error = prediction.sub(labels).square().mean();
            return error;
            }
            // Step 5. 訓(xùn)練函數(shù)
            async function train(xs, ys, numIterations) {
            for (let iter = 0; iter < numIterations; iter++) {
                //優(yōu)化并使方差最小
                optimizer.minimize(() => {
                const pred = predict(xs);//根據(jù)輸入數(shù)據(jù)預(yù)測(cè)輸出值
                return loss(pred, ys);//計(jì)算預(yù)測(cè)值與訓(xùn)練數(shù)據(jù)間的方差
                });

                await tf.nextFrame();//
            }
            }
            //機(jī)器學(xué)習(xí)
            async function learnCoefficients() {//
            const trueCoefficients = {k: 0.6, b: 0.8};//真實(shí)值
            const trainingData = generateData(100, trueCoefficients);//用于模型訓(xùn)練的數(shù)據(jù)
            
            await train(trainingData.xs, trainingData.ys, numIterations);// 模型訓(xùn)練

            var xvals = await trainingData.xs.data();//訓(xùn)練數(shù)據(jù)的x坐標(biāo)值
            var yvals = await trainingData.ys.data();//訓(xùn)練數(shù)據(jù)的y坐標(biāo)值
            var sDatas = Array.from(yvals).map((y,i) => {return [xvals[i],yvals[i]]});//整理訓(xùn)練數(shù)據(jù)以便繪圖
            
            console.log("k&b:",k.dataSync()[0],b.dataSync()[0]);//經(jīng)過(guò)訓(xùn)練后的系數(shù)
            showResult(sDatas,k.dataSync()[0],b.dataSync()[0]);
            }

            //使用echart繪制結(jié)果
            function showResult(scatterData,k,b){
            var dom = document.getElementById("container");
            var myChart = echarts.init(dom);
            function realFun(x){return 0.6*x+0.8;}//理想曲線
            function factFun(x){return k*x+b;}//回歸后的曲線
            var realData = [[-1,realFun(-1)],[1,realFun(1)]];
            var factData = [[-1,factFun(-1)],[1,factFun(1)]];

            var option = {
                title: {text: '線性回歸',left: 'left'},
                tooltip: {trigger: 'axis',axisPointer: {type: 'cross'}},
                xAxis: {type: 'value',splitLine: {lineStyle: {type: 'dashed'}},},
                yAxis: {type: 'value',splitLine: {lineStyle: {type: 'dashed'}}},
                series: [{
                    name: '離散點(diǎn)',type: 'scatter',
                    label: {
                        emphasis: {
                            show: true,
                            position: 'left',
                            textStyle: {
                                color: 'blue',
                                fontSize: 16
                            }
                        }
                    },
                    data: scatterData
                }, 
                {name: '理想曲線',type: 'line',showSymbol: false,data: realData,},
                {name: '回歸曲線',type: 'line',showSymbol: false,data: factData,},],
                legend: {data:['離散點(diǎn)','理想曲線','回歸曲線']},//圖例文字
            };

            myChart.setOption(option, true);
            }
        learnCoefficients();
        </script>
    </body>
</html>

個(gè)人主頁(yè):https://whl1207.github.io/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末器净,一起剝皮案震驚了整個(gè)濱河市型雳,隨后出現(xiàn)的幾起案子当凡,更是在濱河造成了極大的恐慌山害,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沿量,死亡現(xiàn)場(chǎng)離奇詭異浪慌,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)朴则,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門权纤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人乌妒,你說(shuō)我怎么就攤上這事汹想。” “怎么了撤蚊?”我有些...
    開(kāi)封第一講書人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵古掏,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我侦啸,道長(zhǎng)槽唾,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任光涂,我火速辦了婚禮庞萍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘忘闻。我一直安慰自己钝计,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布齐佳。 她就那樣靜靜地躺著葵蒂,像睡著了一般。 火紅的嫁衣襯著肌膚如雪重虑。 梳的紋絲不亂的頭發(fā)上践付,一...
    開(kāi)封第一講書人閱讀 51,521評(píng)論 1 304
  • 那天,我揣著相機(jī)與錄音缺厉,去河邊找鬼永高。 笑死隧土,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的命爬。 我是一名探鬼主播曹傀,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼饲宛!你這毒婦竟也來(lái)了皆愉?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤艇抠,失蹤者是張志新(化名)和其女友劉穎幕庐,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體家淤,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡异剥,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了絮重。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片冤寿。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖青伤,靈堂內(nèi)的尸體忽然破棺而出督怜,到底是詐尸還是另有隱情,我是刑警寧澤狠角,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布号杠,位于F島的核電站,受9級(jí)特大地震影響擎厢,放射性物質(zhì)發(fā)生泄漏究流。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一动遭、第九天 我趴在偏房一處隱蔽的房頂上張望芬探。 院中可真熱鬧,春花似錦厘惦、人聲如沸偷仿。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)酝静。三九已至,卻和暖如春羡玛,著一層夾襖步出監(jiān)牢的瞬間别智,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工稼稿, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留薄榛,地道東北人讳窟。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像敞恋,于是被迫代替她去往敵國(guó)和親丽啡。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355