メニュー 閉じる

033. p5.jsからTensorFlow.jsをちょっといじってみる – その3

前回のコードを3次関数に適用してみました。

(1) y = a * (x * x * x) + b * (x * x) + c * (x) + d

このモデルに対して、

理想モデル:
a = -0.8
b = -0.2
c = 0.9
d = 0.5

初期モデル:
a = tf.variable (tf.scalar(Math.random()));
b = tf.variable (tf.scalar(Math.random()));
c = tf.variable (tf.scalar(Math.random()));
d = tf.variable (tf.scalar(Math.random()));

上記の関数(1)に初期モデルの係数を代入し、理想モデルの係数に近づけるよう訓練します。

今回は緑のプロットがゴールで、赤い線が訓練による曲線になります。
ゴールに近づくほど線の色が赤から緑に変化するようにしてみました。

http://www.velvet-number.com/p5_test/test023/

var random_data = [];

var x_data; 
var y_data;

var a_data = [];
var b_data = [];
var c_data = [];
var d_data = [];

var a = tf.variable (tf.scalar(Math.random()));
var b = tf.variable (tf.scalar(Math.random()));
var c = tf.variable (tf.scalar(Math.random()));
var d = tf.variable (tf.scalar(Math.random()));

//var a = tf.variable (tf.scalar(0.4));
//ar b = tf.variable (tf.scalar(0.1));
//var c = tf.variable (tf.scalar(-0.8));
//var d = tf.variable (tf.scalar(-0.6));

var sample_num;
var train_num;
var learn_rate;
var optimizer;

function setup () {

	pixelDensity (displayDensity ());
	createCanvas (windowWidth, windowHeight);
	colorMode (RGB, 256);
	background (0);

	sample_num = 100;
	train_num = 100;
	learn_rate = 0.5;
	optimizer = tf.train.sgd (learn_rate);

	data_create ();

	data_train (x_data, y_data, train_num);

}

function draw () {

	background (0);

	noFill ();

	for (var i = 0; i < train_num; i++) {
		var r = map (i, 0, train_num, 255, 0);
		var g = map (i, 0, train_num, 0, 255);
		stroke (r, g, 0);
		for (var j = 0; j <= sample_num; j++) {
			if (j > 0) {
				var px = map (random_data[j - 1], -1.0, 1.0, 0.0, width);
				var nx = map (random_data[j], -1.0, 1.0, 0.0, width);
				var tmppy = a_data[i] * pow (random_data[j - 1], 3.0) + b_data[i] * pow (random_data[j - 1], 2.0) + c_data[i] * random_data[j - 1] + d_data[i];
				var tmpny = a_data[i] * pow (random_data[j], 3.0) + b_data[i] * pow (random_data[j], 2.0) + c_data[i] * random_data[j] + d_data[i];
				var py = map (tmppy, 0.0, 1.0, height, 0.0);
				var ny = map (tmpny, 0.0, 1.0, height, 0.0);
				line (px, py, nx, ny);
			}
		}
	}

	stroke (0, 255, 0);

	for (var i = 0; i <= sample_num; i++) {
		var xpos = map (random_data[i], -1.0, 1.0, 0.0, width);
		var ypos = map (y_data.dataSync ()[i], 0.0, 1.0, height, 0.0);
		ellipse (xpos, ypos, 4.0, 4.0);
	}

	fill (255);
	noStroke ();
	textSize (12);
	textAlign (CORNER, TOP);
	text ("Click to Redraw", 10, 10);

}

function data_create () {

	for (var i = 0; i <= sample_num; i++) {
		//random_data[i] = random (-1.0, 1.0);
		random_data[i] = (i * 2.0) / 100.0 - 1.0;
	}
	x_data = tf.tensor1d (random_data);
	y_data = tf.scalar (-0.8).mul (x_data.pow (tf.scalar (3.0)))
			 .add (tf.scalar (-0.2).mul (x_data.square ()))
			 .add (tf.scalar (0.9).mul (x_data))
			 .add (tf.scalar (0.5));

}

function data_train (xs, ys, train_num) {

	for (var i = 0; i < train_num; i++) {
		optimizer.minimize (() => data_loss (data_predict (xs), ys));
		a_data[i] = a.dataSync ()[0];
		b_data[i] = b.dataSync ()[0];
		c_data[i] = c.dataSync ()[0];
		d_data[i] = d.dataSync ()[0];
	}

}

function data_predict (x) {

	return tf.tidy (() => {
		return a.mul (x.pow (tf.scalar (3.0)))
			   .add (b.mul (x.square ()))
			   .add (c.mul (x))
			   .add (d);
	});

}

function data_loss (predict_data, actual_data) {

	const ms_error = predict_data.sub (actual_data).square ().mean ();

	return ms_error;

}

function mouseReleased () {

	a = tf.variable (tf.scalar(Math.random()));
	b = tf.variable (tf.scalar(Math.random()));
	c = tf.variable (tf.scalar(Math.random()));
	d = tf.variable (tf.scalar(Math.random()));

	data_create ();

	data_train (x_data, y_data, train_num);

}

 

 

Posted in p5.js , processing