[英]What is the best way to handle large data with Tensorflow.js and tf.Tensor?
我使用tf.Tensor
和tf.concat()
來處理大型訓練數據,我發現連續使用tf.concat()
變慢了。 將大型數據從文件加載到tf.Tensor
的最佳方法是什么?
我認為這是在Javascript中通過數組處理數據的常用方法。 為實現這一目標,這是艱難的步驟。
Array.push()
將該對象添加到數組 所以我認為我可以tf.concat()
上面類似的方式使用tf.concat()
。
tf.concat()
將張量添加到原始張量 這里有一些代碼來測量Array.push()
和tf.concat()
import * as tf from "@tensorflow/tfjs"
let t = tf.tensor1d([1])
let addT = tf.tensor1d([2])
console.time()
for (let idx = 0; idx < 50000; idx++) {
if (idx % 1000 == 0) {
console.timeEnd()
console.time()
console.log(idx)
}
t = tf.tidy(() => t.concat(addT))
}
let arr = []
let addA = 1
console.time()
for (let idx = 0; idx < 50000; idx++) {
if (idx % 1000 == 0) {
console.timeEnd()
console.time()
console.log(idx)
}
arr.push(addA)
}
我們可以在Array.push()
上看到穩定的進程,但是在tf.concat()
上它變慢了
default: 0.150ms
0
default: 68.725ms
1000
default: 62.922ms
2000
default: 23.199ms
3000
default: 21.093ms
4000
default: 27.808ms
5000
default: 39.689ms
6000
default: 34.798ms
7000
default: 45.502ms
8000
default: 94.526ms
9000
default: 51.996ms
10000
default: 76.529ms
11000
default: 83.662ms
12000
default: 45.730ms
13000
default: 89.119ms
14000
default: 49.171ms
15000
default: 48.555ms
16000
default: 55.686ms
17000
default: 54.857ms
18000
default: 54.801ms
19000
default: 55.312ms
20000
default: 65.760ms
default: 0.009ms
0
default: 0.388ms
1000
default: 0.340ms
2000
default: 0.333ms
3000
default: 0.317ms
4000
default: 0.330ms
5000
default: 0.289ms
6000
default: 0.299ms
7000
default: 0.291ms
8000
default: 0.320ms
9000
default: 0.284ms
10000
default: 0.343ms
11000
default: 0.327ms
12000
default: 0.317ms
13000
default: 0.329ms
14000
default: 0.307ms
15000
default: 0.218ms
16000
default: 0.193ms
17000
default: 0.234ms
18000
default: 1.943ms
19000
default: 0.164ms
20000
default: 0.148ms
雖然tf.concat
和Array.push
函數的外觀和行為相似,但有一個很大的區別:
tf.concat
從輸入創建一個新的張量 Array.push
將輸入添加到第一個數組 tf.concat
const a = tf.tensor1d([1, 2]);
const b = tf.tensor1d([3]);
const c = tf.concat([a, b]);
a.print(); // Result: Tensor [1, 2]
b.print(); // Result: Tensor [3]
c.print(); // Result: Tensor [1, 2, 3]
結果變量c
是新的Tensor,而a
和b
不變。
Array.push
const a = [1,2];
a.push(3);
console.log(a); // Result: [1,2,3]
這里,變量a
直接改變。
對於運行時速度,這意味着在添加輸入之前, tf.concat
所有張量值復制到新的張量。 這顯然需要更多時間,需要復制的數組越大。 與此相反, Array.push
不會創建數組的副本,因此無論數組有多大,運行時都會或多或少相同。
請注意,這是“按設計”,因為張量是不可變的,因此現有張量上的每個操作總是會創建一個新的張量。 從文檔引用:
張量是不可變的,因此所有操作總是返回新的張量並且永遠不會修改輸入張量。
因此,如果需要從輸入數據創建大張量,建議首先從文件中讀取所有數據,然后將其與“vanilla”JavaScript函數合並,然后再從中創建張量。
如果您有一個如此大的數據集,由於內存限制需要以塊的形式處理它,您有兩個選擇:
trainOnBatch
功能 trainOnBatch
功能允許訓練一批數據,而不是使用完整的數據集。 因此,您可以在訓練之前將代碼拆分為合理的批次,這樣您就不必一次將所有數據合並在一起。
另一個答案已經完成了基礎知識。 這將允許您使用JavaScript生成器函數來准備數據。 我建議使用生成器語法而不是迭代器工廠(在其他答案中使用),因為它是更現代的JavaScript語法。
例子 (取自文檔 ):
function* dataGenerator() {
const numElements = 10;
let index = 0;
while (index < numElements) {
const x = index;
index++;
yield x;
}
}
const ds = tf.data.generator(dataGenerator);
然后,您可以使用fitDataset
函數來訓練模型。
雖然沒有一種方法可以創建張量,但問題的答案在於對所創建的張量所做的工作。
張量是不可變的,因此每次調用tf.concat
都會創建一個新的張量。
let x = tf.tensor1d([2]); console.log(tf.memory()) // "numTensors": 1 const y = tf.tensor1d([3]) x = tf.concat([x, y]) console.log(tf.memory()) // "numTensors": 3,
<html> <head> <!-- Load TensorFlow.js --> <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@0.14.1"> </script> </head> <body> </body> </html>
正如我們從上面的代碼片段中看到的那樣,調用tf.concat時創建的張量數是3而不是2 。 確實, tf.tidy
將處置未使用的張量。 但是,隨着創建的張量變得越來越大,這種創建和處理張量的操作將變得最大且成本最高。 這既是內存消耗和計算的問題,因為創建新的張量將始終委托給后端。
既然已經了解了性能問題,那么最好的方法是什么?
for (i= 0; i < data.length; i++) {
// fill array x
x.push(dataValue)
}
// create the tensor
tf.tensor(x)
雖然,這是微不足道的解決方案,但並不總是可行的。 因為創建一個數組會將數據保存在內存中,並且我們可以很容易地用大數據條目耗盡內存。 因此,有時候,最好不要創建整個javascript數組來創建數組,並從這些數組中創建一個張量,並在創建它們后立即開始處理這些張量。 如有必要,可以再次使用tf.concat
合並塊張量。 但它可能並不總是必需的。
例如,我們可以使用張量塊重復調用model.fit(),而不是使用可能需要很長時間才能創建的大張量來調用它。 在這種情況下,不需要連接塊張量。
function makeIterator() {
const iterator = {
next: () => {
let result;
if (index < data.length) {
result = {value: dataValue, done: false};
index++;
return result;
}
return {value: dataValue, done: true};
}
};
return iterator;
}
const ds = tf.data.generator(makeIterator);
使用tf.data的優點是,在model.fit
調用期間需要時,批量創建整個數據集。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.