0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

基于tensorflow.js設(shè)計(jì)、訓(xùn)練面向web的神經(jīng)網(wǎng)絡(luò)模型的經(jīng)驗(yàn)

zhKF_jqr_AI ? 來源:未知 ? 作者:李倩 ? 2018-10-18 09:43 ? 次閱讀

編者按:opencv4nodejs作者Vincent Mühler分享了基于tensorflow.js設(shè)計(jì)、訓(xùn)練面向web的神經(jīng)網(wǎng)絡(luò)模型的經(jīng)驗(yàn)。

在將現(xiàn)有的一些目標(biāo)檢測、臉部檢測、臉部識別的模型移植到tensorflow.js后,我發(fā)現(xiàn)有的模型在瀏覽器中的表現(xiàn)沒有達(dá)到最優(yōu),而另一些模型在瀏覽器上的表現(xiàn)相當(dāng)不錯(cuò)。瀏覽器內(nèi)的機(jī)器學(xué)習(xí)潛力巨大,tensorflow.js等庫給web開發(fā)者帶來了太多可能性。

然而,直接在瀏覽器中運(yùn)行的深度模型也帶來了新的挑戰(zhàn)和限制,畢竟一些現(xiàn)存的模型不是為在客戶端瀏覽器中運(yùn)行而設(shè)計(jì)的,更別說移動(dòng)端瀏覽器了。就拿當(dāng)前最先進(jìn)的目標(biāo)檢測模型來說:它們通常需要大量計(jì)算資源才能以合理的fps運(yùn)行,更別說實(shí)時(shí)運(yùn)行了。另外,對一個(gè)簡單的web應(yīng)用來說,分發(fā)100MB以上的模型權(quán)重至客戶端瀏覽器也不現(xiàn)實(shí)。

為web訓(xùn)練高效的深度學(xué)習(xí)模型

不過不要放棄希望!基于一些基本原則,我們可以創(chuàng)建和訓(xùn)練很不錯(cuò)的模型,為在web環(huán)境中運(yùn)行而優(yōu)化。信不信由你,實(shí)際上我們可以訓(xùn)練相當(dāng)不錯(cuò)的圖像分類模型,甚至是目標(biāo)檢測模型,大小不過幾兆,甚至幾百K:

這篇文章將給出一些通用的建議,幫助你開始訓(xùn)練自己的卷積神經(jīng)網(wǎng)絡(luò)(CNN),以及一些基于tensorflow.js為web應(yīng)用和移動(dòng)端瀏覽器訓(xùn)練CNN的建議。

你和我說要在瀏覽器里訓(xùn)練深度學(xué)習(xí)模型?

你也許會(huì)好奇:為什么要在瀏覽器里基于tensorflow.js訓(xùn)練我的模型,而不是直接在自己的機(jī)器上基于tensorflow訓(xùn)練模型?你當(dāng)然可以在自己的機(jī)器上訓(xùn)練,特別是如果你的機(jī)器配備了NVIDIA顯卡。tensorflow.js在底層使用了WebGL加速,所以在瀏覽器中訓(xùn)練模型的一個(gè)好處是可以利用AMD顯卡。另外,在瀏覽器中訓(xùn)練模型,可以更好地保護(hù)用戶隱私,更容易讓用戶信任。

網(wǎng)絡(luò)架構(gòu)

顯然,訓(xùn)練模型之間,首先需要實(shí)現(xiàn)模型。通常人們會(huì)建議挑選一個(gè)久經(jīng)考驗(yàn)的現(xiàn)有架構(gòu),比如YOLO、SSD、ResNet、MobileNet等。

我個(gè)人認(rèn)為,在設(shè)計(jì)自己的架構(gòu)時(shí)應(yīng)用現(xiàn)有架構(gòu)的一些概念是很有價(jià)值的,但直接在web應(yīng)用中引入這些現(xiàn)存架構(gòu)可能不妥,因?yàn)槲覀兿胍叽巛^小、推理較快(理想情況下能實(shí)時(shí)推理)、容易訓(xùn)練的模型。

不管你是打算引入一個(gè)現(xiàn)有架構(gòu),還是完全從頭開始,都可以參考下面的一些建議,在我自己為web設(shè)計(jì)高效CNN架構(gòu)時(shí),這些建議幫助很大:

1. 從小型架構(gòu)開始

牢記,能夠取得較好的精確度的網(wǎng)絡(luò)越小,它進(jìn)行推理的時(shí)間越短,用戶下載、緩存模型更容易。此外,較小的模型參數(shù)較少,因此在訓(xùn)練時(shí)收斂更快。

如果發(fā)現(xiàn)當(dāng)前的網(wǎng)絡(luò)架構(gòu)表現(xiàn)不是很好,或者沒有達(dá)到你想要的精確度,你仍然可以逐漸增加網(wǎng)絡(luò)的尺寸,例如,增加每層的卷積過濾器數(shù)量,或者直接堆疊更多網(wǎng)絡(luò)層,構(gòu)造更深的網(wǎng)絡(luò)。

2. 應(yīng)用深度可分離卷積

既然我們是要打造一個(gè)新模型,毫無疑問我們想要使用深度可分離卷積,而不是傳統(tǒng)的2D卷積。深度可分離卷積將常規(guī)的卷積操作分為兩部分,首先分頻道進(jìn)行卷積,接著應(yīng)用1x1卷積。和常規(guī)卷積操作相比,深度可分離卷積的參數(shù)更少,這意味著更少的浮點(diǎn)運(yùn)算,更容易并行化,推理更快(我曾經(jīng)碰到過,僅僅將常規(guī)卷積替換為深度可分離卷積后,推理就加速了10x),更少的資源占用(在移動(dòng)設(shè)備上意味著性能提升)。此外,因?yàn)閰?shù)更少,訓(xùn)練所需時(shí)間也更短。

MobileNet和Xception應(yīng)用了深度可分離卷積(tensorflow.js中的MobileNet和PoseNet)。深度可分離卷積是否導(dǎo)致精確度下降大概沒有定論,但就我的經(jīng)驗(yàn)而言,web和移動(dòng)端模型,毫無疑問應(yīng)該使用深度可分離卷積。

長話短說:我建議在第一層使用常規(guī)的conv2d,畢竟通常而言這一層也沒有多少參數(shù),這樣可以在提取特征中保留RGB通道之間的關(guān)系。

export type ConvParams = {

filter: tf.Tensor4D

bias: tf.Tensor1D

}

exportfunction convLayer(

x: tf.Tensor4D,

params: ConvParams,

stride: [number, number],

padding: string

): tf.Tensor4D {

return tf.tidy(() => {

let out = tf.conv2d(x, params.filter, stride, padding)

out = tf.add(out, params.bias)

return out

})

}

剩下的都用深度可分離卷積,用3 × 3 × channelsin × 1過濾器和1 × 1 × channelsin × channels_out過濾器替換單個(gè)核。

export type SeparableConvParams = {

depthwise_filter: tf.Tensor4D

pointwise_filter: tf.Tensor4D

bias: tf.Tensor1D

}

exportfunction depthwiseSeparableConv(

x: tf.Tensor4D,

params: SeparableConvParams,

stride: [number, number],

padding: string

): tf.Tensor4D {

return tf.tidy(() => {

let out = tf.separableConv2d(x, params.depthwise_filter: tf.Tensor4D, params.pointwise_filter, stride, padding)

out = tf.add(out, params.bias)

return out

})

}

所以,原本使用tf.conv2d,形狀為[3, 3, 32, 64]的核,現(xiàn)在改用tf.separableConv2d,一個(gè)形狀為[3, 3, 32, 1]的核加上一個(gè)[1, 1, 32, 64]的核。

3. 跳層連接和密集連接塊

一旦決定創(chuàng)建較深的網(wǎng)絡(luò),很快就會(huì)面臨訓(xùn)練神經(jīng)網(wǎng)絡(luò)最常遇到的問題:梯度消失問題。若干epoch后,損失以極其微小的幅度下降,導(dǎo)致慢得荒謬的訓(xùn)練,甚至是完全收斂不了。

ResNet和DenseNet使用的跳層連接可以緩解創(chuàng)建更深的架構(gòu)時(shí)遇到的梯度消失問題。我們只需將之前的網(wǎng)絡(luò)層的輸出,添加到網(wǎng)絡(luò)中較深層的輸入之中(在應(yīng)用激活函數(shù)之前):

跳層連接背后的直覺是,梯度不必僅僅通過卷積層(或全連接層)反向傳播(這導(dǎo)致梯度漸漸消失)。它們可以添加跳層連接操作,“跳過”一些網(wǎng)絡(luò)層。

顯然,跳層連接要工作,需要輸出和輸入之間的形狀互相匹配。假設(shè)我們想要跳層連接網(wǎng)絡(luò)層A和網(wǎng)絡(luò)層B,那么A的輸出形狀需要和B的輸入形狀匹配。如果你想要?jiǎng)?chuàng)建殘差塊或密集連接塊,只需確保卷積過濾器數(shù)目一致,步長為1,補(bǔ)齊方案相同。順便說下,還有其他方法,比如補(bǔ)齊A的輸出,使其滿足B的輸入的形狀,或是連接之前層的特征映射,使得相連的層的深度互相匹配。

剛開始,我擺弄了一下類似ResNet的方法,直接隔層引入跳層連接,如上圖所示。不過我很快發(fā)現(xiàn),密集連接塊的效果更好,并且應(yīng)用密集連接塊后,模型收斂的時(shí)間馬上下降了:

這里是一個(gè)密集連接塊實(shí)現(xiàn)的例子,我在face-api.js的68點(diǎn)臉部識別中將其作為基本構(gòu)件。這個(gè)構(gòu)件使用了4個(gè)深度可分離卷積層(注意,第一個(gè)密集塊的第一個(gè)卷積層用了常規(guī)卷積),每塊的第一個(gè)卷積操作步長為2,以縮小輸入:

export type DenseBlock4Params = {

conv0: SeparableConvParams | ConvParams

conv1: SeparableConvParams

conv2: SeparableConvParams

conv3: SeparableConvParams

}

exportfunction denseBlock4(

x: tf.Tensor4D,

denseBlockParams: DenseBlock4Params,

isFirstLayer: boolean = false

): tf.Tensor4D {

return tf.tidy(() => {

const out0 = isFirstLayer

? convLayer(x, denseBlockParams.conv0 as ConvParams, [2, 2], 'same')

: depthwiseSeparableConv(x, denseBlockParams.conv0 as SeparableConvParams, [2, 2], 'same')

as tf.Tensor4D

const in1 = tf.relu(out0) as tf.Tensor4D

const out1 = depthwiseSeparableConv(in1, denseBlockParams.conv1, [1, 1], 'same')

// 第一個(gè)連接

const in2 = tf.relu(tf.add(out0, out1)) as tf.Tensor4D

const out2 = depthwiseSeparableConv(in2, denseBlockParams.conv2, [1, 1], 'same')

// 第二個(gè)連接

const in3 = tf.relu(tf.add(out0, tf.add(out1, out2))) as tf.Tensor4D

const out3 = depthwiseSeparableConv(in3, denseBlockParams.conv3, [1, 1], 'same')

// 最后一個(gè)連接

return tf.relu(tf.add(out0, tf.add(out1, tf.add(out2, out3)))) as tf.Tensor4D

})

}

4. 使用ReLU系列激活函數(shù)

除非你有特別的理由,我建議直接使用tf.relu,因?yàn)镽eLU系列激活函數(shù)有助于緩解梯度消失問題。

你也可以試驗(yàn)ReLU的其他變體,例如leaky ReLU,YOLO架構(gòu)就用了這個(gè):

exportfunction leakyRelu(x: tf.Tensor, epsilon: number) {

return tf.tidy(() => {

const min = tf.mul(x, tf.scalar(epsilon))

return tf.maximum(x, min)

})

}

或者M(jìn)obilenet用的ReLU-6:

exportfunction relu6(x: tf.Tensor) {

return tf.clipByValue(x, 0, 6)

}

訓(xùn)練

有了初始架構(gòu)之后,就可以開始訓(xùn)練模型了。

5. 如果拿不準(zhǔn)主意,直接用Adam

剛開始訓(xùn)練自己的模型的時(shí)候,我想知道哪種優(yōu)化算法是最好的?我從原始的SGD開始,有時(shí)候會(huì)陷入局部極小值,甚至導(dǎo)致梯度爆炸——模型權(quán)重?zé)o限增長,逐漸變?yōu)镹aN.

我并不打算說,對所有問題而言,Adam都是最優(yōu)選擇,但我發(fā)現(xiàn)它是訓(xùn)練新模型最簡單也最健壯的方式,只需將初始學(xué)習(xí)率定為0.001,然后以默認(rèn)參數(shù)啟動(dòng)Adam:

const optimizer = tf.train.adam(0.001)

6. 調(diào)整學(xué)習(xí)率

一旦損失沒有明顯下降,那么我們的模型很可能收斂了(或陷入局部極小值),無法進(jìn)一步學(xué)習(xí)了。此時(shí)我們也許可以直接停止訓(xùn)練過程,以免模型過擬合(或者嘗試不同的架構(gòu))。

然而,也有可能還有一點(diǎn)壓榨的余地,通過調(diào)整(調(diào)低)學(xué)習(xí)率,讓模型進(jìn)一步學(xué)習(xí)。特別是在整個(gè)訓(xùn)練集上的總誤差開始震蕩(一會(huì)兒高一會(huì)兒低)的時(shí)候,試著降低學(xué)習(xí)率也許是個(gè)好主意。

下圖是個(gè)例子。從第46個(gè)epoch開始,損失值開始震蕩,從46個(gè)epoch后,將學(xué)習(xí)率從0.001調(diào)低至0.0001,再訓(xùn)練10個(gè)epoch,可以進(jìn)一步降低總誤差。

7. 權(quán)重初始化

如果你對如何恰當(dāng)?shù)爻跏蓟瘷?quán)重毫無頭緒(我剛開始的時(shí)候就是這樣),那么可以簡單地將所有偏置初始化為零(tf.zeros),將權(quán)重初始化為從某種正態(tài)分布中隨機(jī)取樣的非零值(比如使用tf.randomNormal)。不過我現(xiàn)在更喜歡用glorot正態(tài)分布:

const initializer = tf.initializers.glorotNormal()

const depthwise_filter = initializer.apply([3, 3, 32, 1])

const pointwise_filter = initializer.apply([1, 1, 32, 64])

const bias = tf.zeros([64])

8. 打亂輸入

訓(xùn)練神經(jīng)網(wǎng)絡(luò)的常見建議是在每個(gè)epoch前隨機(jī)化訓(xùn)練樣本的出現(xiàn)順序。我們可以使用tf.utils.shuffle:

exportfunction shuffle(array: any[]|Uint32Array|Int32Array|Float32Array): void

9. 使用FileSaver.js保存模型的快照

FileSaver.js提供了一個(gè)saveAs函數(shù),讓我們可以儲(chǔ)存任意類型的文件至下載文件夾。我們可以用它來保存模型權(quán)重:

const weights = newFloat32Array([... model weights, flat array])

saveAs(newBlob([weights]), 'checkpoint_epoch1.weights')

我們也可以存儲(chǔ)為json格式,例如保存epoch的累計(jì)損失:

const losses = { totalLoss: ... }

saveAs(newBlob([JSON.stringify(losses)]), 'loss_epoch1.json')

調(diào)錯(cuò)

在花費(fèi)大量時(shí)間訓(xùn)練模型之前,我們想要確保模型確實(shí)能夠?qū)W習(xí)我們預(yù)想的東西,并清除任何潛在的錯(cuò)誤和bug源。下面的幾條建議有助于你避免浪費(fèi)大量時(shí)間訓(xùn)練出一堆垃圾并懷疑人生:

10. 檢查輸入數(shù)據(jù)、預(yù)處理和后處理邏輯

如果你傳入網(wǎng)絡(luò)的是垃圾,網(wǎng)絡(luò)返還的也會(huì)是垃圾。因此,需要確保輸入數(shù)據(jù)標(biāo)注正確,網(wǎng)絡(luò)的輸入也符合預(yù)期。特別地,如果你實(shí)現(xiàn)了隨機(jī)剪裁、補(bǔ)齊、截成正方形、居中、減去均值之類的預(yù)處理邏輯,別忘了可視化預(yù)處理之后的輸入,以檢查輸入是否符合預(yù)期。另外,我強(qiáng)烈建議單元測試這些步驟。后處理也是一樣。

我知道這聽起來是一些乏味的額外工作,但它們無疑是有價(jià)值的!你不會(huì)相信,我花了多少小時(shí)嘗試搞明白為什么我的目標(biāo)檢測器完全學(xué)不會(huì)檢測面部,直到我逐漸發(fā)現(xiàn),由于錯(cuò)誤的剪裁和變形,我的預(yù)處理邏輯將輸入變成了垃圾。

11. 檢查損失函數(shù)

在大多數(shù)情況下,tensorflow.js都可以提供所需的損失函數(shù)。然而,在你需要實(shí)現(xiàn)自己的損失函數(shù)的情況下,你絕對需要單元測試!不久前我曾經(jīng)基于tfjs-core API從頭構(gòu)建YOLO v2的損失函數(shù),從頭實(shí)現(xiàn)損失函數(shù)很麻煩,除非你分解問題,并確保每一部分的計(jì)算結(jié)果符合預(yù)期。

12. 先過擬合小數(shù)據(jù)集

先過擬合訓(xùn)練數(shù)據(jù)的一個(gè)小子集,從而驗(yàn)證損失函數(shù)可以收斂,模型確實(shí)可以學(xué)到有用的東西。一般而言,這是一個(gè)好主意。例如,你可以直接從訓(xùn)練數(shù)據(jù)中選取10到20張圖像,并訓(xùn)練若干epoch。損失收斂后,在這10到20張圖像上運(yùn)行推理,并可視化結(jié)果:

這是非常重要的一步,有助于消除神經(jīng)網(wǎng)絡(luò)實(shí)現(xiàn)中各種造成bug的來源,包括預(yù)處理邏輯和后處理邏輯在內(nèi)。因?yàn)?,如果代碼中有不少bug,模型不太可能作出符合期望的預(yù)測。

特別是實(shí)現(xiàn)自己的損失函數(shù)的時(shí)候,毫無疑問,你希望在正式開始訓(xùn)練之前確保模型能夠收斂。

性能

最后,我想給出一些有助于降低訓(xùn)練時(shí)間,以及防止瀏覽器因內(nèi)存泄漏而奔潰的建議。

13. 避免明顯的內(nèi)存泄露

除非你在tensorflow.js方面完全是新手,你大概已經(jīng)知道你需要手動(dòng)丟棄未使用的張量,以釋放它們占用的內(nèi)存。你可以通過調(diào)用tensor.dispose()或?qū)⒉僮鞣庋b在tf.tidy塊中做到這一點(diǎn)。確保不要因?yàn)闆]有正確地丟棄張量而導(dǎo)致內(nèi)存泄露,否則你的應(yīng)用遲早會(huì)用盡內(nèi)存。

識別這類內(nèi)存泄露很容易。只需在若干次迭代中調(diào)用tf.memory()記錄日志,以驗(yàn)證張量的數(shù)量沒有隨著每次迭代而異常增長:

14. 調(diào)整canvas的尺寸,而不是張量的尺寸

注意,這條建議只適用于當(dāng)前的tfjs-core(我使用的版本是0.12.14),因?yàn)槲磥淼陌姹究赡軙?huì)修正這一問題。

我知道這也許聽起來有點(diǎn)奇怪:為什么不使用tf.resizeBilinear、tf.pad等來重整輸入張量的形狀,以匹配網(wǎng)絡(luò)輸入要求的形狀?這是因?yàn)楫?dāng)前tfjs有一個(gè)GPU顯存泄露的bug(#604)

長話短說,在調(diào)用tf.fromPixels將canvas轉(zhuǎn)換成張量前,首先調(diào)整canvas的尺寸,以匹配網(wǎng)絡(luò)輸入要求的形狀。不這么做的話,你會(huì)很快耗盡GPU顯存(取決于訓(xùn)練數(shù)據(jù)中圖像尺寸的不同程度)。如果所有訓(xùn)練圖像尺寸一致,不會(huì)有什么問題,但如果尺寸不一致,你可以使用以下代碼調(diào)整尺寸:

exportfunction imageToSquare(img: HTMLImageElement | HTMLCanvasElement, inputSize: number): HTMLCanvasElement {

const dims = img instanceof HTMLImageElement

? { width: img.naturalWidth, height: img.naturalHeight }

: img

const scale = inputSize / Math.max(dims.height, dims.width)

const width = scale * dims.width

const height = scale * dims.height

const targetCanvas = document.createElement('canvas')

targetCanvas .width = inputSize

targetCanvas .height = inputSize

targetCanvas.getContext('2d').drawImage(img, 0, 0, width, height)

return targetCanvas

}

15. 找到最優(yōu)的batch大小

不要把batch大小設(shè)得過大!嘗試不同的batch大小,測量反向傳播所需的時(shí)間。最優(yōu)batch大小取決于GPU、輸入尺寸、網(wǎng)絡(luò)復(fù)雜度。甚至某些情況下,不使用batch,逐一輸入才是最好的。

如果拿不準(zhǔn),我會(huì)將batch大小設(shè)為1(也就是不使用batch)。我個(gè)人發(fā)現(xiàn)在一些情形下,增加batch大小對性能提升沒什么幫助,不過,在另一些情形下,我發(fā)現(xiàn),在相當(dāng)小的網(wǎng)絡(luò)上,為112 × 112的圖像創(chuàng)建16到24的batch能帶來大約1.5-2.0的速度提升。

16. 緩存、離線存儲(chǔ)、Indexeddb

訓(xùn)練圖像(和標(biāo)簽)也許很多,取決于圖像的尺寸和數(shù)量,可能達(dá)到1GB甚至更多。由于在瀏覽器下無法直接從磁盤讀取圖像,我們需要使用一個(gè)文件代理,比如一個(gè)簡單的express服務(wù)器,托管訓(xùn)練數(shù)據(jù),然后讓瀏覽器通過文件代理獲取數(shù)據(jù)。

顯然,這很不高效,不過,別忘了,在瀏覽器中訓(xùn)練時(shí),如果數(shù)據(jù)集足夠小,我們大概會(huì)把所有數(shù)據(jù)放在內(nèi)存中,這顯然也不怎么高效。剛開始,我嘗試增加瀏覽器的緩存大小,以直接將所有數(shù)據(jù)緩存到磁盤上,不過看起來新版的Chrome和FireFox都不再支持這個(gè)功能了。

我最終決定使用Indexddb,這是一個(gè)瀏覽器中的數(shù)據(jù)庫,可以用來存儲(chǔ)整個(gè)訓(xùn)練集和測試集。上手Indexeddb很容易,只需幾行代碼,就可以以鍵值存儲(chǔ)的格式儲(chǔ)存和查詢所有數(shù)據(jù)。在Indexeddb中,我們可以將標(biāo)簽存儲(chǔ)為json對象,將圖像數(shù)據(jù)存儲(chǔ)為blob。

查詢Indexeddb相當(dāng)快,至少比反復(fù)從文件代理查詢并獲取文件要快。另外,將數(shù)據(jù)轉(zhuǎn)移到Indexeddb之后,整個(gè)訓(xùn)練過程完全可以離線進(jìn)行,也就是說,之后的訓(xùn)練過程不再需要文件代理服務(wù)器了。

17. 異步損失報(bào)告

這個(gè)一個(gè)非常有效的簡單技巧,有助于大量減少訓(xùn)練的迭代次數(shù)。如果我們想要獲取optimizer.minimize返回的損失張量的值,以了解訓(xùn)練過程中的損失值,我們希望避免等待每次迭代的CPU和GPU同步數(shù)據(jù)。相反,我們希望迭代異步地報(bào)告損失:

const loss = optimizer.minimize(() => {

const out = net.predict(someInput)

const loss = tf.losses.meanSquaredError(

groundTruth,

out,

tf.Reduction.MEAN

)

return loss

}, true)

loss.data().then(data => {

const lossValue = data[0]

window.lossValues[epoch] += (window.lossValues[epoch] || 0) + lossValue

loss.dispose()

})

別忘了,現(xiàn)在損失是異步報(bào)告的,所以如果我們想要把每個(gè)epoch末的總體損失保存到一個(gè)文件,我們需要等待最后一個(gè)promise得到滿足。我通常直接使用setTimeout在每個(gè)epoch完成后的10秒之后再記錄總體損失。

if (epoch !== startEpoch) {

// 丑陋的等待最后一個(gè)promise滿足的方法

const previousEpoch = epoch - 1

setTimeout(() => storeLoss(previousEpoch, window.losses[previousEpoch]), 10000)

}

成功訓(xùn)練模型之后

18. 權(quán)重量化

完成模型訓(xùn)練并對模型的表現(xiàn)滿意后,我建議應(yīng)用權(quán)重量化以壓縮模型大小。通過量化模型權(quán)重,可以將模型大小壓縮至1/4!盡可能地壓縮模型大小是很關(guān)鍵的,因?yàn)樗兄诳焖俚貍鬏斈P蜋?quán)重至客戶端應(yīng)用,特別是這樣的壓縮幾乎沒有什么代價(jià)。

所以,別忘了參考我寫的tensorflow.js的權(quán)重量化指南:https://itnext.io/shrink-your-tensorflow-js-web-model-size-with-weight-quantization-6ddb4fcb6d0d

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴

原文標(biāo)題:基于tensorflow.js在瀏覽器中設(shè)計(jì)訓(xùn)練神經(jīng)網(wǎng)絡(luò)模型的18條建議

文章出處:【微信號:jqr_AI,微信公眾號:論智】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。

收藏 人收藏

    評論

    相關(guān)推薦
    熱點(diǎn)推薦

    神經(jīng)網(wǎng)絡(luò)教程(李亞非)

      第1章 概述  1.1 人工神經(jīng)網(wǎng)絡(luò)研究與發(fā)展  1.2 生物神經(jīng)元  1.3 人工神經(jīng)網(wǎng)絡(luò)的構(gòu)成  第2章人工神經(jīng)網(wǎng)絡(luò)基本模型  2.
    發(fā)表于 03-20 11:32

    關(guān)于BP神經(jīng)網(wǎng)絡(luò)預(yù)測模型的確定!!

    請問用matlab編程進(jìn)行BP神經(jīng)網(wǎng)絡(luò)預(yù)測時(shí),訓(xùn)練結(jié)果很多都是合適的,但如何確定最合適的?且如何用最合適的BP模型進(jìn)行外推預(yù)測?
    發(fā)表于 02-08 14:23

    請問Labveiw如何調(diào)用matlab訓(xùn)練好的神經(jīng)網(wǎng)絡(luò)模型呢?

    我在matlab中訓(xùn)練好了一個(gè)神經(jīng)網(wǎng)絡(luò)模型,想在labview中調(diào)用,請問應(yīng)該怎么做呢?或者labview有自己的神經(jīng)網(wǎng)絡(luò)工具包嗎?
    發(fā)表于 07-05 17:32

    【AI學(xué)習(xí)】第3篇--人工神經(jīng)網(wǎng)絡(luò)

    `本篇主要介紹:人工神經(jīng)網(wǎng)絡(luò)的起源、簡單神經(jīng)網(wǎng)絡(luò)模型、更多神經(jīng)網(wǎng)絡(luò)模型、機(jī)器學(xué)習(xí)的步驟:訓(xùn)練與預(yù)
    發(fā)表于 11-05 17:48

    matlab實(shí)現(xiàn)神經(jīng)網(wǎng)絡(luò) 精選資料分享

    習(xí)神經(jīng)神經(jīng)網(wǎng)絡(luò),對于神經(jīng)網(wǎng)絡(luò)的實(shí)現(xiàn)是如何一直沒有具體實(shí)現(xiàn)一下:現(xiàn)看到一個(gè)簡單的神經(jīng)網(wǎng)絡(luò)模型用于訓(xùn)練
    發(fā)表于 08-18 07:25

    卷積神經(jīng)網(wǎng)絡(luò)模型發(fā)展及應(yīng)用

    卷積神經(jīng)網(wǎng)絡(luò)模型發(fā)展及應(yīng)用轉(zhuǎn)載****地址:http://fcst.ceaj.org/CN/abstract/abstract2521.shtml深度學(xué)習(xí)是機(jī)器學(xué)習(xí)和人工智能研究的最新趨勢,作為一個(gè)
    發(fā)表于 08-02 10:39

    如何使用TensorFlow神經(jīng)網(wǎng)絡(luò)模型部署到移動(dòng)或嵌入式設(shè)備上

    有很多方法可以將經(jīng)過訓(xùn)練神經(jīng)網(wǎng)絡(luò)模型部署到移動(dòng)或嵌入式設(shè)備上。不同的框架在各種平臺上支持Arm,包括TensorFlow、PyTorch、Caffe2、MxNet和CNTK,如And
    發(fā)表于 08-02 06:43

    node.js訓(xùn)練好的神經(jīng)網(wǎng)絡(luò)模型識別圖像中物體的方法

    如何在Node.js環(huán)境下使用訓(xùn)練好的神經(jīng)網(wǎng)絡(luò)模型(Inception、SSD)識別圖像中的物體。
    的頭像 發(fā)表于 04-06 13:11 ?9472次閱讀

    利用TensorFlow.js,D3.jsWeb 的力量使訓(xùn)練模型的過程可視化

    TensorFlow.js 將機(jī)器學(xué)習(xí)引入 JavaScript 和 Web。 我們將利用這個(gè)很棒的框架來構(gòu)建一個(gè)深度神經(jīng)網(wǎng)絡(luò)模型。這個(gè)模型
    的頭像 發(fā)表于 08-08 14:24 ?7267次閱讀

    如何使用TensorFlow.js構(gòu)建這一系統(tǒng)

    TensorFlow.js團(tuán)隊(duì)一直在進(jìn)行有趣的基于瀏覽器的實(shí)驗(yàn),以使人們熟悉機(jī)器學(xué)習(xí)的概念,并鼓勵(lì)他們將其用作您自己項(xiàng)目的構(gòu)建塊。對于那些不熟悉的人來說,TensorFlow.js是一個(gè)開源庫,允許
    的頭像 發(fā)表于 08-19 08:55 ?3737次閱讀

    如何基于 ES6 的 JavaScript 進(jìn)行 TensorFlow.js 的開發(fā)

    從頭開發(fā)、訓(xùn)練和部署模型,也可以用來運(yùn)行已有的 Python 版 TensorFlow 模型,或者基于現(xiàn)有的模型進(jìn)行繼續(xù)
    的頭像 發(fā)表于 10-31 11:16 ?3419次閱讀

    卷積神經(jīng)網(wǎng)絡(luò)模型訓(xùn)練步驟

    卷積神經(jīng)網(wǎng)絡(luò)模型訓(xùn)練步驟? 卷積神經(jīng)網(wǎng)絡(luò)(Convolutional Neural Network, CNN)是一種常用的深度學(xué)習(xí)算法,廣泛應(yīng)用于圖像識別、語音識別、自然語言處理等諸多
    的頭像 發(fā)表于 08-21 16:42 ?2200次閱讀

    怎么對神經(jīng)網(wǎng)絡(luò)重新訓(xùn)練

    重新訓(xùn)練神經(jīng)網(wǎng)絡(luò)是一個(gè)復(fù)雜的過程,涉及到多個(gè)步驟和考慮因素。 引言 神經(jīng)網(wǎng)絡(luò)是一種強(qiáng)大的機(jī)器學(xué)習(xí)模型,廣泛應(yīng)用于圖像識別、自然語言處理、語音識別等領(lǐng)域。然而,隨著時(shí)間的推移,數(shù)據(jù)分布可
    的頭像 發(fā)表于 07-11 10:25 ?797次閱讀

    如何使用經(jīng)過訓(xùn)練神經(jīng)網(wǎng)絡(luò)模型

    使用經(jīng)過訓(xùn)練神經(jīng)網(wǎng)絡(luò)模型是一個(gè)涉及多個(gè)步驟的過程,包括數(shù)據(jù)準(zhǔn)備、模型加載、預(yù)測執(zhí)行以及后續(xù)優(yōu)化等。
    的頭像 發(fā)表于 07-12 11:43 ?1809次閱讀

    使用TensorFlow進(jìn)行神經(jīng)網(wǎng)絡(luò)模型更新

    使用TensorFlow進(jìn)行神經(jīng)網(wǎng)絡(luò)模型的更新是一個(gè)涉及多個(gè)步驟的過程,包括模型定義、訓(xùn)練、評估以及根據(jù)新數(shù)據(jù)或需求進(jìn)行
    的頭像 發(fā)表于 07-12 11:51 ?792次閱讀

    電子發(fā)燒友

    中國電子工程師最喜歡的網(wǎng)站

    • 2931785位工程師會(huì)員交流學(xué)習(xí)
    • 獲取您個(gè)性化的科技前沿技術(shù)信息
    • 參加活動(dòng)獲取豐厚的禮品