TensorFlowで3層ニューラルネットワークを作成し、それを使ってJavaScriptとPythonの処理速度を比較しました。
結果は表1の通りPythonの圧勝でした。また、Pythonは「@tf.function有り」が「@tf.function無し」に比べ10倍以上も速いことが分かりました。 Pythonを使う場合は「@tf.function」を付けた方が絶対絶対いいです!
〈PC〉
・OS:Windows 8.1
・CPU:Celeron Dual-Core 1005M(1.9GHz)
〈JavaScript〉
・Node.js 15.1.0
・@tensorflow/tfjs 3.9.0
〈Python〉
・Python 3.8.8
・TensorFlow 2.3.0
プログラミング言語 | 学習に要した時間 |
---|---|
JavaScript | 115 sec |
Python(@tf.function無し) | 394 sec |
Python(@tf.function有り) | 29 sec |
下記の tensorflow.mjs と tensorflow.py が処理速度を計測するのに使用したプログラムです。
〈掛け算の九九の表を学習して乗算をする3層ニューラルネットワーク〉
units1:第1層(入力層)のユニット数 = 2
units2:第2層(隠れ層)のユニット数 = 7
units3:第3層(出力層)のユニット数 = 1
epochs:エポック数 = 50000
tensorflow.mjs
import * as ph from "perf_hooks";
import * as tf from "@tensorflow/tfjs";
class NeuralNetwork {
constructor(units1, units2, units3) {
this.w1 = tf.variable(tf.randomUniform([units1, units2], -1, 1));
this.b1 = tf.variable(tf.randomUniform([units2], -1, 1));
this.w2 = tf.variable(tf.randomUniform([units2, units3], -1, 1));
this.b2 = tf.variable(tf.randomUniform([units3], -1, 1));
}
model(x) {
return x.matMul(this.w1).add(this.b1).tanh().matMul(this.w2).add(this.b2);
}
loss(x, y) {
return tf.losses.meanSquaredError(this.model(x), y);
}
train(x, y, epochs) {
const optimizer = tf.train.adam(0.001, 0.9, 0.999, 0.00000001);
const x_tensor = tf.tensor(x);
const y_tensor = tf.tensor(y);
for (let epoch = 1; epoch <= epochs; epoch++) {
optimizer.minimize(() => this.loss(x_tensor, y_tensor));
}
}
predict(x) {
return this.model(tf.tensor([x])).arraySync()[0];
}
}
const neuralNetwork = new NeuralNetwork(2, 7, 1);
//掛け算の九九の表
const x_train = Array.from((function* () { for (let x1 = 1; x1 <= 9; x1++) for (let x2 = 1; x2 <= 9; x2++) yield [x1, x2]; })());
const y_train = Array.from((function* () { for (let x1 = 1; x1 <= 9; x1++) for (let x2 = 1; x2 <= 9; x2++) yield [x1 * x2]; })());
//学習
const start = ph.performance.now();
neuralNetwork.train(x_train, y_train, 50000);
const stop = ph.performance.now();
//推論
for (let x1 = 1; x1 <= 9; x1++)
for (let x2 = 1; x2 <= 9; x2++)
console.log(`${x1} * ${x2} -> ${neuralNetwork.predict([x1, x2])}`);
console.log(`${(0.001 * (stop - start)).toFixed(3)}sec`);
注)importステートメントを使ってモジュールを呼び出しているので、ファイルの拡張子は mjs にしてください。
tensorflow.py(@tf.function有り)
import tensorflow as tf
import time
class NeuralNetwork:
def __init__(self, units1, units2, units3):
self.w1 = tf.Variable(tf.random.uniform(shape = (units1, units2), minval = -1, maxval = 1))
self.b1 = tf.Variable(tf.random.uniform(shape = (units2,), minval = -1, maxval = 1))
self.w2 = tf.Variable(tf.random.uniform(shape = (units2, units3), minval = -1, maxval = 1))
self.b2 = tf.Variable(tf.random.uniform(shape = (units3,), minval = -1, maxval = 1))
self.optimizer = tf.keras.optimizers.Adam(learning_rate = 0.001, beta_1 = 0.9, beta_2 = 0.999, epsilon = 1e-8)
def model(self, x):
return tf.matmul(tf.tanh(tf.matmul(x, self.w1) + self.b1), self.w2) + self.b2
def loss(self, x, y):
return tf.keras.losses.MeanSquaredError()(self.model(x), y)
@tf.function
def optimize(self, x, y):
with tf.GradientTape() as tape:
loss = self.loss(x, y)
parameters = self.w1, self.b1, self.w2, self.b2
gradients = tape.gradient(loss, parameters)
self.optimizer.apply_gradients(zip(gradients, parameters))
def train(self, x, y, epochs):
x_tensor = tf.convert_to_tensor(x, tf.float32)
y_tensor = tf.convert_to_tensor(y, tf.float32)
for epoch in range(epochs):
self.optimize(x_tensor, y_tensor)
def predict(self, x):
return self.model(tf.convert_to_tensor([x], tf.float32))[0][0]
neuralNetwork = NeuralNetwork(units1 = 2, units2 = 7, units3 = 1)
#掛け算の九九の表
x_train = [[x1, x2] for x1 in range(1, 10) for x2 in range(1, 10)]
y_train = [[x1 * x2] for x1 in range(1, 10) for x2 in range(1, 10)]
#学習
start = time.time()
neuralNetwork.train(x_train, y_train, epochs = 50000)
stop = time.time()
#推論
for x1, x2 in ((x1, x2) for x1 in range(1, 10) for x2 in range(1, 10)):
print(f"{x1} * {x2} -> {neuralNetwork.predict([x1, x2])}")
print("{:.3f}sec".format(stop - start))