カテゴリー
【tensorflowjs x kerasの使い方】正規分布の評価〜非線形回帰解析②
※ 当ページには【広告/PR】を含む場合があります。
2020/12/09
2022/08/18
ガウス分布ノイズの実験データの生成
$ awk -v seed="${RANDOM}" -v iter=1000000 -v inp_mu=0.0 -v inp_sigma=1.0 '
function box_muller(mu, sigma, arr_len_) {
PI = 3.14159265359;
count = 0;
while(count < arr_len_) {
x1 = rand();
x2 = rand();
tmp_rand_val = sqrt(-2 * log(x1)) * cos(2 * PI * x2);
gauss_arr[count] = mu + sigma * tmp_rand_val;
count++;
}
}
BEGIN{
srand(seed); #シード値をリセット
box_muller(inp_mu, inp_sigma, iter);
arr_len = length(gauss_arr);
for (i = 0; i < arr_len; i++) {
print gauss_arr[i];
}
}
' | awk -v binsize=0.2 '
BEGIN {
OFS=","
}
{
if(binsize <= 0) exit;
if($1 < 0) {
frequency[int($1 / binsize) - 1] ++;
} else {
frequency[int($1 / binsize)] ++;
}
}
END {
for(i in frequency) {
print (i + 0.5) * binsize, frequency[i] | "sort -n";
}
}
' | awk -F "," '
BEGIN {
OFS=",";
count = 0;
}
{
xarr[count] = $1;
yarr[count] = $2;
if(ymax<$2) ymax=$2;
count++;
}
END {
xarr_len = length(xarr);
for (i = 0; i < xarr_len; i++) {
print i, xarr[i], yarr[i] / ymax
}
}
' > norm_dist_exp.csv
Eq. (1)
機械学習の基本と関連する技術をバランス良く学ぶ 図解即戦力 機械学習&ディープラーニングのしくみと技術がこれ1冊でしっかりわかる教科書
KerasモデルのLayerをカスタマイズする
linear(デフォルト)
elu
hardSigmoid
relu
relu6
selu
sigmoid
softmax
softplus
softsign
tanh
linear
tf.Layersクラス
カスタムLayerの作り方
normDistLayer.js
import * as tf from '@tensorflow/tfjs';
export class NormDistLayer extends tf.layers.Layer {
constructor(config) {
super(config);
this.mu0 = config.mu0;
this.sigma0 = config.sigma0;
}
/**
* build関数では最適化パラメータの初期化処理等を行う
*/
build(inputShape) {
// 最適化パラメーターはスカラなのでconst shape = [];としてもOK
const shape = [inputShape[inputShape.length - 1]];
this.mu = this.addWeight('mu', shape, 'float32', tf.initializers.constant({value: this.mu0}));
this.sigma = this.addWeight('sigma', shape, 'float32', tf.initializers.constant({value: this.sigma0}));
}
/**
* call関数で活性化関数を内部で定義する。
* 基本はTensor型の入力値を入れて、Tensor型の出力を出す。
* メモリーリークを避けるためにtidyは必ず使うこと
*/
call(input) {
return tf.tidy(() => {
const p1 = tf.pow(input[0].sub(this.mu.read()), 2);
return tf.div(p1, this.sigma.read().pow(2).mul(-2)).exp();
});
}
/**
* getConfig関数はLayerインスタンスの読み込みと書き出しの時に
* 必須となるプロパティをJSON形式でシリアライズ・デシリアライズする
*/
getConfig() {
const config = super.getConfig();
Object.assign(config, {
mu0: this.mu0,
sigma0: this.sigma0
});
return config;
}
/**
* Layersのライブラリに登録するクラス名
*/
static get className() {
return 'NormDistLayer';
}
}
build
call
getConfig
nonlinear_regression.js
import * as tf from '@tensorflow/tfjs';
//👇先程作成したカスタムレイヤークラスをインポート
import { NormDistLayer } from './normDistLayer';
//👇カスタムクラスをtensorflowで呼び出せるように登録する(重要)
tf.serialization.registerClass(NormDistLayer);
export async function evalNonlinaer(rawData) {
const model = tf.sequential();
//👇非線形回帰の場合、カスタムレイヤーが入力層かつ出力層
model.add(new NormDistLayer({
inputShape: [1],
mu0: 0.1,
sigma0: 1.1
}));
console.log('Analysis started.');
const originalData = [];
const tmpLabels = [];
for (const row in rawData) {
tmpLabels.push(rawData[row][0]);
originalData.push({x: parseFloat(rawData[row][1]), y: parseFloat(rawData[row][2])});
};
// 入力用データセット配列をTensor型に変換
const tensorData = convertToTensor(originalData);
// 非線形回帰解析の実行
await trainModel(model, tensorData.inputs, tensorData.labels);
// 解析済みモデルから結果を得る
const predictedData = testModel(model);
console.log('Done.');
// Chart.js描画用にラベル・元データセット・解析済みデータセットを返す
return { tmpLabels, originalData, predictedData };
}
/// モデル・入力(インプット)テンソル・出力(ラベル)テンソルを指定してモデルの学習を行う関数
async function trainModel(model, inputs, labels) {
model.compile({
// 最適化法はAdamに指定
optimizer: tf.train.adam(),
// 損失関数をMSEに指定
loss: tf.losses.meanSquaredError,
// 学習とテストに用いる指標の名前を定義
metrics: ['mse'],
});
// バッチサイズ
const batchSize = 48;
// エポック数
const epochs = 500;
// エポック毎に解析中のパラメーターを確認出来るようにcallbacksを指定
return await model.fit(inputs, labels, {
batchSize,
epochs,
shuffle: true,
callbacks: {
onEpochEnd: async(epoch, logs) => {
// 繰り返し回数 - 損失 - 誤差の順にを出力
console.log(`Epoch#${epoch} : Loss(${logs.loss}) : mse(${logs.mse})`);
// 現在平均値μと標準偏差σの値を出力
const muval = model.layers[0].getWeights()[0].dataSync()[0];
const sgmval = model.layers[0].getWeights()[1].dataSync()[0];
console.log(`mu=${muval} : sgm=${sgmval}`);
}
}
});
}
/// 学習済みモデルから解析後のプロット用データを生成
function testModel(model) {
const [xs, preds] = tf.tidy(() => {
const xs = tf.linspace(-5, 5, 100);
const preds = model.predict(xs.reshape([100, 1]));
return [xs.dataSync(), preds.dataSync()];
});
return Array.from(xs).map((val, i) => {
return {
x: val,
y: preds[i]
}
});
}
/// 学習データをテンソルに変換する関数
function convertToTensor(data) {
return tf.tidy(() => {
// データのシャッフル
tf.util.shuffle(data);
// データを配列に格納してから展開してテンソルに変換
const inputs = data.map(d => d.x)
const labels = data.map(d => d.y);
const inputTensor = tf.tensor2d(inputs, [inputs.length, 1]);
const labelTensor = tf.tensor2d(labels, [labels.length, 1]);
return { inputs: inputTensor, labels: labelTensor }
});
}
機械学習の基本と関連する技術をバランス良く学ぶ 図解即戦力 機械学習&ディープラーニングのしくみと技術がこれ1冊でしっかりわかる教科書
正規化済みの正規分布の解析
norm_dist_exp.csv
...
Epoch#499 : Loss(0.000004175022240815451) : mse(0.000004175022695562802)
mu=0.0016643998678773642 : sgm=0.9995725154876709
まとめ
記事を書いた人
ナンデモ系エンジニア
主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。
カテゴリー