中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

用瀏覽器訓(xùn)練Tensorflow.js模型的18個(gè)技巧

2018-10-16    來源:raincent

容器云強(qiáng)勢上線!快速搭建集群,上萬Linux鏡像隨意使用

在移植現(xiàn)有模型(除tensorflow.js)進(jìn)行物體檢測、人臉檢測、人臉識(shí)別后,我發(fā)現(xiàn)一些模型不能以最佳性能發(fā)揮。而tensorflow.js在瀏覽器中表現(xiàn)相當(dāng)不錯(cuò),如果你想見證瀏覽器內(nèi)部機(jī)器學(xué)習(xí)的潛力以及tensorflow.js為我們的Web開發(fā)人員提供的所有可能性,我個(gè)人建議你可以嘗試下。

但是,由于深度學(xué)習(xí)模型無法直接在瀏覽器中運(yùn)行,因?yàn)檫@些模型不是專為在瀏覽器中運(yùn)行而設(shè)計(jì)的,更不用說在移動(dòng)端了。以現(xiàn)有技的物體探測器為例:它們通常需要大量的計(jì)算資源才能以合理的fps運(yùn)行,更不用說以實(shí)時(shí)速度運(yùn)行了。此外,在簡單的Web應(yīng)用程序中將100MB+模型權(quán)重加載到客戶端瀏覽器是根本不可行的。
 

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


但讓我告訴你,我們能夠構(gòu)建和訓(xùn)練相當(dāng)錯(cuò)的模型,這些模型通過設(shè)計(jì)一些基本原則可以在Web環(huán)境中運(yùn)行進(jìn)行。信不信由你:我們可以訓(xùn)練相當(dāng)不錯(cuò)的圖像分類-甚至物體檢測模型,最終只有幾兆字節(jié)大小甚至只有幾千字節(jié):

在本文中,我想你一些關(guān)于開始訓(xùn)練你自己的卷經(jīng)網(wǎng)絡(luò)CNN)的一般技巧,有一些技巧是直接針對(duì)瀏覽器中使用量流訓(xùn)練CNN網(wǎng)絡(luò)。

現(xiàn)在你可能想知道:為什么我可以在瀏覽器中使用tensorflow.js訓(xùn)練我的模型,在我的機(jī)器上如何使用tensorflow訓(xùn)練它們?當(dāng)然,如果你的機(jī)器配備了NVIDIA卡,你也可以這樣做。在瀏覽器中訓(xùn)練深度學(xué)習(xí)的一個(gè)巨大的優(yōu)勢,它的引擎蓋下利用WebGL的,這就意味著你不需要NVIDIA GPU訓(xùn)練的模式,而是AMD GPU上訓(xùn)練深度學(xué)習(xí)模型。

因此,如果你的機(jī)器配備了NVIDIA卡,你可以簡單地采用標(biāo)準(zhǔn)張量流方法(在這種情況下,你可以在python中編寫訓(xùn)練代碼)并忽略瀏覽器的提示。現(xiàn)在,讓我們開始吧!
 

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


在開始訓(xùn)練我們自己的圖像分類器、對(duì)象檢測器之前,我們必須首先實(shí)現(xiàn)網(wǎng)絡(luò)架構(gòu)。我通常建議選擇現(xiàn)有的架構(gòu),例如Yolo、SSD、ResNet、MobileNet等。

就個(gè)人而言,我認(rèn)為在你自己的架構(gòu)中使用這些架構(gòu)所采用的一些概念是很有價(jià)值的。然而,正如我最初指出的那樣,簡單地采用這些架構(gòu)不會(huì)讓我們的模型是體積小,推理快易于訓(xùn)練成為可能。

無論你是想要適應(yīng)現(xiàn)有架構(gòu)還是從頭開始,我都想給你以下建議,這有助于為Web設(shè)計(jì)高效的CNN架構(gòu):
 

1.從小型網(wǎng)絡(luò)架構(gòu)開始!


記住,我們的網(wǎng)絡(luò)越小,同時(shí)仍能在解決問題時(shí)獲得良好的準(zhǔn)確性,它在推理時(shí)間內(nèi)執(zhí)行的速度就越快,客戶端下載和緩存該模型就越容易。此外,較小的模型具有較少的參數(shù),因此在訓(xùn)練時(shí)會(huì)更快地收斂。

如果你發(fā)現(xiàn)當(dāng)前的網(wǎng)絡(luò)架構(gòu)性能不佳,或者達(dá)不到準(zhǔn)確性水平,你仍然希望是它,你可以逐步增加網(wǎng)絡(luò)的大小,例如通過增加每層卷積濾波器的數(shù)量或堆疊更多層簡單地使你的網(wǎng)絡(luò)更深入。
 

2.采用深度可分的卷!


由于我們正在訓(xùn)練一個(gè)新模型,我們希望明確使用深度可分卷積而不是普通2D卷積。深度可分離卷積將常規(guī)卷積運(yùn)算分成深度卷積,然后是逐點(diǎn)(1x1)卷積。與常規(guī)卷積操作相比,它們具有更少的參數(shù),這將使用更少的浮點(diǎn)運(yùn)算并且更容易并行化,這意味著推斷將更快(我通過簡單地替換常規(guī)卷積來進(jìn)行推斷的速度提升高達(dá)10倍)和較少的資源消耗。此外,因?yàn)樗鼈兙哂休^少的參數(shù),所以訓(xùn)練它們所花費(fèi)的時(shí)間較少。

MobileNetXception采用了深度可分離卷積的思想,你可以在MobileNetPoseNet的tensorflow.js模型中找到它們。深度可分離卷積是否導(dǎo)致模型不太準(zhǔn)確可能是一個(gè)公開的辯論,但根據(jù)我的經(jīng)驗(yàn),它們絕對(duì)是網(wǎng)絡(luò)模型的方式。

長話短說:我建議在你的第一層使用常規(guī)的沒有那么多的參數(shù)的conv2d操作,以保留提取的特征中的RGB通道之間的關(guān)系。

 

export type ConvParams = {
filter: tf.Tensor4D
bias: tf.Tensor1D
}
export function 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
})
}

 

對(duì)于其余的卷積,只需使用深度可分離的卷積。因此,我將使用3x3xchannels_inx1深度波器和1x1x channels_in x channels_out逐點(diǎn)波器,而不是個(gè)內(nèi)核。

 

export type SeparableConvParams = {
depthwise_filter: tf.Tensor4D
pointwise_filter: tf.Tensor4D
bias: tf.Tensor1D
}
export function 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與具有形狀的內(nèi)核[3,3,32,64],我們將簡單地使用tf.separableConv2d深度方向內(nèi)核的形狀為[3,3,32,1]以及形狀為[1,1,32,64]狀作為點(diǎn)狀核。
 

3.過連接(Skip connections)和密集接(Densely Connected)的


一旦決定建立更深層的網(wǎng)絡(luò),很快就面臨著訓(xùn)練神經(jīng)網(wǎng)絡(luò)最常見的問題之一:梯度消失問題。在一些時(shí)期之后,損失只會(huì)在非常微小的步驟中減少,這會(huì)增加訓(xùn)練時(shí)間或者導(dǎo)致模型不收斂。

ResNet和DenseNet中使用的跳過連接允許它們構(gòu)建更深層的體系結(jié)構(gòu),同時(shí)減輕梯度消失問題。我們所要做的就是在應(yīng)用激活函數(shù)之前,將先前層的輸出添加到位于網(wǎng)絡(luò)中更深層的層輸入中:

4

跳過連接

跳過連接工作,通過快捷方式連接圖層。這種技術(shù)背后的本質(zhì)是,梯度不必僅通過卷積(或完全連接)反向傳播,這導(dǎo)致梯度一旦到達(dá)網(wǎng)絡(luò)的早期層就會(huì)減少。它們可以通過跳過連接的添加操作來“skip”層。

顯然,假設(shè)你想要將A層與B層連接,A的輸出形狀必須與B的輸入形狀相匹配。如果你想構(gòu)建殘差或密集連接的塊,只需確保在該塊的卷積中保持相同數(shù)量的濾波器,并使用相同的填充保持1的步幅。正如旁注一樣,也有不同的方法,它們填充A的輸出,使其與輸入B的形狀匹配,或者連接來自先前層的特征映射,使得連接層的深度再次匹配。

起初,我嘗試使用類似ResNet的方法,只需在其他層之間引入跳過連接,如上圖所示,但很快就發(fā)現(xiàn),密集連接的塊工作得更好,并且可以很快的收斂:

5

密集塊

這是一個(gè)密集塊實(shí)現(xiàn)的例子,我用它作為面部標(biāo)志檢測器的基本構(gòu)建塊face-api.js。其中一個(gè)塊涉及4個(gè)可深度分離的卷積層(注意,第一個(gè)密集塊的第一個(gè)卷積是常規(guī)卷積),每個(gè)塊的第一個(gè)卷積運(yùn)算使用2的步幅來縮小輸入:

 

export type DenseBlock4Params = {
conv0: SeparableConvParams | ConvParams
conv1: SeparableConvParams
conv2: SeparableConvParams
conv3: SeparableConvParams
}


export function 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')


// first join
const in2 = tf.relu(tf.add(out0, out1)) as tf.Tensor4D
const out2 = depthwiseSeparableConv(in2, denseBlockParams.conv2, [1, 1], 'same')


// second join
const in3 = tf.relu(tf.add(out0, tf.add(out1, out2))) as tf.Tensor4D
const out3 = depthwiseSeparableConv(in3, denseBlockParams.conv3, [1, 1], 'same')


// final join
return tf.relu(tf.add(out0, tf.add(out1, tf.add(out2, out3)))) as tf.Tensor4D
})
}

4.使用ReLU類型激活函數(shù)!


除非你有特定的理由使用其他類型的激活函數(shù),否則就使用tf.relu。原因很簡單,ReLU類型激活函數(shù)有助于緩解梯度消失的問題。

你還可以嘗試ReLU的變體,例如leaky ReLU,它正在Yolo架構(gòu)中使用:

 

export function leakyRelu(x: tf.Tensor, epsilon: number) {
return tf.tidy(() => {
const min = tf.mul(x, tf.scalar(epsilon)) 
return tf.maximum(x, min)
})
}

或者正在移動(dòng)網(wǎng)絡(luò)使用的ReLU-6

export function relu6(x: tf.Tensor) {
return tf.clipByValue(x, 0, 6)
}

 

訓(xùn)練


一旦我們完成初始架構(gòu),我們就可以開始訓(xùn)練我們的模型了。
 

5.如果有疑,只需使用Adam Optimizer!


當(dāng)?shù)谝淮伍_始訓(xùn)練自己的模型時(shí),我想知道哪種優(yōu)化器最好?我一開始使用普通的SGD,它似乎有時(shí)會(huì)陷入局部最小值中,甚至導(dǎo)致梯度爆炸,以至于模型權(quán)重?zé)o限增長,最終導(dǎo)致NaNs。

我并不是說,Adam是所有問題的最佳選擇,但我發(fā)現(xiàn)它是訓(xùn)練新模型最簡單且最強(qiáng)大的方法,只需使用默認(rèn)參數(shù)和學(xué)習(xí)率為0.001Adam開始:

 

const optimizer = tf.train.adam(0.001)

 

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


一旦損失沒有顯著下降,很可能,我們的模型確實(shí)收斂,并且無法進(jìn)一步學(xué)習(xí)。此時(shí)我們不妨停止訓(xùn)練過程,以防止我們的模型不會(huì)出現(xiàn)過度擬合。

但是,你可以通過調(diào)整(降低)學(xué)習(xí)率來避免它發(fā)生。特別是如果在訓(xùn)練集上計(jì)算的總損失開始振蕩,這表明嘗試降低學(xué)習(xí)率可能是個(gè)好主意。

下面是一個(gè)示例,顯示了訓(xùn)練面部標(biāo)志模型時(shí)整體誤差的圖表。在46epoch,損失值開始振蕩。正如你所看到的那樣,繼續(xù)訓(xùn)練從46epoch的檢查點(diǎn)再學(xué)習(xí)10個(gè)以上,學(xué)習(xí)率為0.0001而不是0.001,這能夠進(jìn)一步降低整體誤差:

6
 

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


如果你對(duì)如何正確初始化模型權(quán)重沒有任何線索:一個(gè)簡單的經(jīng)驗(yàn)法則,從某種正態(tài)分布中得出,用零初始化所有偏差(tf.zeros(shape))和你的權(quán)重(卷積的核和全連接層的權(quán)重)與非零值。例如,你可以簡單地使用tf.randomNormal(shape),但是現(xiàn)在我更喜歡使用glorot正態(tài)分布,這在tfjs-layers中是可用的,如下所示:

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.隨機(jī)你的入!


訓(xùn)練神經(jīng)網(wǎng)絡(luò)的一個(gè)常見建議是通過在每個(gè)時(shí)期開始時(shí)對(duì)輸入進(jìn)行混洗來隨機(jī)化訓(xùn)練樣本。我們可以使用tf.utils.shuffle來實(shí)現(xiàn)這個(gè)目的:

 

/** Shuffles the array using Fisher-Yates algorithm. */
export function shuffle(array: any[]|Uint32Array|Int32Array|Float32Array): void

 

9.使用FileSaver.js保存模型檢查點(diǎn)


由于我們?cè)跒g覽器中訓(xùn)練我們的模型,你現(xiàn)在可能會(huì)問自己:我們?nèi)绾卧谟?xùn)練時(shí)自動(dòng)保存模型權(quán)重的檢查點(diǎn)?我們可以使用FileSaver.js,該腳本公開了一個(gè)名為saveAs的函數(shù),我們可以使用它來存儲(chǔ)任意類型的文件,這些文件最終會(huì)出現(xiàn)在我們的下載文件夾中。

這樣我們就可以保存模型權(quán)重:

const weights = new Float32Array([... model weights, flat array])
saveAs(new Blob([weights]), 'checkpoint_epoch1.weights')

甚至是json文件:

const losses = { totalLoss: ... }
saveAs(new Blob([JSON.stringify(losses)]), 'loss_epoch1.json')

排除故障


在花費(fèi)大量時(shí)間訓(xùn)練模型之前,你需要確保你的模型實(shí)際上要學(xué)習(xí)是什么,并消除任何潛在的錯(cuò)誤來源。如果你不考慮以下提示,你可能會(huì)浪費(fèi)你的時(shí)間在訓(xùn)練垃圾上:


 

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


如果你將垃圾傳遞到你的網(wǎng)絡(luò),它定會(huì)把垃圾扔回你身邊。因此,請(qǐng)確保你的輸入數(shù)據(jù)標(biāo)記正確,并確保你的網(wǎng)絡(luò)輸入符合你的預(yù)期。特別是如果你已經(jīng)規(guī)定了一些預(yù)處理邏輯,如隨機(jī)裁剪、填充、平方、居中、平均減法或其他什么,請(qǐng)確保預(yù)處理后進(jìn)行可視化輸入。此外,我強(qiáng)烈建議單元測試這些步驟。

這聽起來像是一項(xiàng)繁瑣的額外工作,但它很重要!
 

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


現(xiàn)在在大多數(shù)情況下,tensorflow.js為你提供了你需要的損失函數(shù)。但是,如果你需要實(shí)現(xiàn)自己的損失函數(shù),你絕對(duì)需要進(jìn)行單元測試!不久前,我從頭開始使用tfjs-core API實(shí)現(xiàn)了Yolo v2 dropout函數(shù),以便為網(wǎng)絡(luò)訓(xùn)練yolo對(duì)象檢測器。

12.先裝上一個(gè)小型數(shù)據(jù)集!

通常,最好是在訓(xùn)練數(shù)據(jù)的一小部分上過度擬合,以驗(yàn)證損失是否正在收斂,以及你的模型實(shí)際上是否在學(xué)習(xí)一些有用的東西。因此,你應(yīng)該只選擇10到20張訓(xùn)練數(shù)據(jù)的圖像并訓(xùn)練一些時(shí)期。一旦損失收斂,對(duì)這10到20張圖像進(jìn)行推斷并可視化結(jié)果:

c5a03f829940958affae53ff85c0c65f228822a5

這是一個(gè)非常重要的步驟,它將幫助你消除網(wǎng)絡(luò)實(shí)施中的各種錯(cuò)誤來源、前后處理邏輯。

特別是,如果你正在實(shí)現(xiàn)自己的損失函數(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塊中。確保由于未正確處理張量而導(dǎo)致沒有此類內(nèi)存泄漏,否則你的應(yīng)用程序遲早會(huì)耗盡內(nèi)存。

識(shí)別這些類型的內(nèi)存泄漏非常簡單,只需記錄tf.memory()幾次迭代即可驗(yàn)證,每次迭代時(shí)張量的數(shù)量不會(huì)無意中增長:


 

14.調(diào)整Canvases大小而不是你的張量!


注意,以下語句僅在tfjs-core的當(dāng)前狀態(tài)時(shí)有效,直到最終得到修復(fù)。

這可能聽起來有點(diǎn)奇怪:為什么不使用tf.resizeBilinear、tf.pad等將輸入張量重塑為所需的網(wǎng)絡(luò)輸入形狀?tfjs目前有一個(gè)未解決的問題,說明了這個(gè)問題。

TLDR:在調(diào)用tf.fromPixels之前,要將Canvaes轉(zhuǎn)換為張量,請(qǐng)調(diào)整Canvaes的大小,使其具有網(wǎng)絡(luò)接受的大小,否則你將快速耗盡GPU內(nèi)存,具體取決于各種不同的輸入大小。如果你的訓(xùn)練圖像大小都相同,那么這個(gè)問題就不那么嚴(yán)重了,但是如果你必須明確調(diào)整它們的大小,你可以使用下面的代碼片段:

 

export function 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.確定最佳批量大小


不要過分批量輸入!嘗試不同的批量大小并測量反向傳播所需的時(shí)間。最佳批量大小顯然取決于你的GPU統(tǒng)計(jì)信息,輸入大小以及網(wǎng)絡(luò)的復(fù)雜程度。在某些情況下,你根本不想批量輸入。

如果有疑問的話,我會(huì)一直使用1的批量大小。我個(gè)人認(rèn)為,在某些情況下,增加批量大小對(duì)性能沒有任何幫助,但在其他情況下,我可以看到整體加速的因素通過創(chuàng)建大小為1624批次,在相當(dāng)小的網(wǎng)絡(luò)尺寸下輸入圖像大小為112x112像素,大約1.5-2.0左右。
 

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


我們的訓(xùn)練圖像可能相當(dāng)大,可能高達(dá)1GB甚至更大,具體取決于圖像的大小和數(shù)量。由于我們不能簡單地在瀏覽器中從磁盤讀取圖像,我們將使用文件代理(可能是一個(gè)簡單的快速服務(wù)器)來托管我們的訓(xùn)練數(shù)據(jù),瀏覽器將獲取每個(gè)數(shù)據(jù)項(xiàng)。

顯然,這是非常低效的,但是在瀏覽器中進(jìn)行訓(xùn)練時(shí)我們必須記住這一點(diǎn),如果你的數(shù)據(jù)集足夠小,你可能會(huì)嘗試將整個(gè)數(shù)據(jù)保存在內(nèi)存中,但這顯然也不是很有效。最初,我試圖增加瀏覽器緩存大小以簡單地將整個(gè)數(shù)據(jù)緩存在磁盤上,但這在以后的Chrome版本中似乎不再起作用,而且我也沒有運(yùn)氣FireFox。

最后,我決定只使用Indexeddb,這是一個(gè)瀏覽器數(shù)據(jù)庫,你可能不太熟悉,我們可以利用它來存儲(chǔ)我們的整個(gè)訓(xùn)練和測試數(shù)據(jù)集。Indexeddb入門非常簡單,因?yàn)槲覀兓旧现恍鑾仔写a即可將整個(gè)數(shù)據(jù)存儲(chǔ)和查詢?yōu)殒I值存儲(chǔ)。使用Indexeddb,我們可以方便地將標(biāo)簽存儲(chǔ)為普通的json對(duì)象,將我們的圖像數(shù)據(jù)存儲(chǔ)為blob?纯催@篇博文,很好地解釋了如何在Indexeddb中保存圖像數(shù)據(jù)和其他文件。

查詢Indexeddb是非常快的,至少我發(fā)現(xiàn)查詢每個(gè)數(shù)據(jù)項(xiàng)的速度要快一些,而不是一遍又一遍地從代理服務(wù)器中獲取文件。此外,在將數(shù)據(jù)移動(dòng)到Indexeddb之后,技術(shù)上的訓(xùn)練現(xiàn)在完全脫機(jī),這意味著我們可能不再需要代理服務(wù)器了。
 

17.異步報(bào)


這是一個(gè)簡單但非常有效的提示,它幫助我減少了訓(xùn)練時(shí)的迭代次數(shù)。主要的作用是,如果我們想要檢索由optimizer.minimize返回的損失張量的值,我們肯定會(huì)這樣做,因?yàn)槲覀兿胍谟?xùn)練時(shí)跟蹤我們的損失,我們希望避免等待損失返回的lose.data()及防止等待CPU和GPU在每次迭代時(shí)同步。相反,我們想要執(zhí)行類似以下的操作來報(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的末尾將整體失保存到文件中,我將不得不等待最后的解決方案。我通常只是通使用setTimeout在一個(gè)epoch完成后10秒左右保存整體來解決個(gè)問題

if (epoch !== startEpoch) {
// ugly hack to wait for loss datas for that epoch to be resolved
const previousEpoch = epoch - 1
setTimeout(() => storeLoss(previousEpoch, window.losses[previousEpoch]), 10000)
}

 

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


18.權(quán)重量化


一旦我們完成了對(duì)模型的訓(xùn)練并且我們對(duì)它的性能感到滿意,我建議通過應(yīng)用權(quán)重量化來縮小模型大小。通過量化我們的模型權(quán)重,我們可以將模型的大小減小到原始大小的1/4!盡可能減小模型的大小對(duì)于將模型權(quán)重快速傳遞到客戶端應(yīng)用程序至關(guān)重要,特別是如果我們基本上可以免費(fèi)獲得它。

文章原標(biāo)題《18-tips-for-training-your-own-tensorflow-js-models-in-the-browser》

作者:Vincent Mühler 譯者:虎說八道

標(biāo)簽: isp ssd web環(huán)境 代理服務(wù)器 代碼 服務(wù)器 腳本 數(shù)據(jù)庫 網(wǎng)絡(luò)

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請(qǐng)聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀點(diǎn)!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請(qǐng)與原作者聯(lián)系。

上一篇:計(jì)算機(jī)科學(xué)專業(yè)畢業(yè)?這是給你的職業(yè)建議(亮點(diǎn)在最后)

下一篇:Uber開源Marmaray:基于Hadoop的通用數(shù)據(jù)攝取和分散框架