4_1 TensorFlow.jsで実装した論理ゲート

以下がTensorFlow.jsで実装した論理ゲートの実行画面です。結果は、概ね良好のように思えます。

全コードを以下に示します。

<!doctype html>
<html lang="ja">

<head>
    <meta charset="utf-8">
    <title>論理ゲート</title>
    <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@latest"></script>
    <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
    <script src="js/graph.js"></script>

    <style>
      .graph-area{
        margin: 10px;
        width: 500px;
        height:500px;
        border: 1px solid black;
      }
      .container{
        display: flex;
        width: 1100px;
        text-align: center;
        margin: 30px;
      }
      input {
        margin: 2px;
        height: 30px;
        width: 80px;
      }
    </style>

	</head>
  <body>
    <h3>論理ゲート モデル、レイヤー使用</h3>
    <div class="container">
      <div id="and">
        <img src="images/and.png" width="118" height="155">
        <input type="button" id="and-button" value="AND">
      </div>
      <div id="nand">
        <img src="images/nand.png" width="118" height="155">
        <input type="button" id="nand-button" value="NAND">
      </div>
      <div id="or">
        <img src="images/or.png" width="118" height="155">
        <input type="button" id="or-button" value="OR">
      </div>
      <div id="xor">
        <img src="images/xor.png" width="118" height="155">
         <input type="button" id="xor-button" value="XOR">
      </div>
      <div>
        <div id="chart" class="graph-area"></div>
      </div>
    </div>
  </body>

  <script>
    document.addEventListener('DOMContentLoaded',async()=>{

      let xs = null;
      let ys = null;
      let model = null;

      const buildModel = async()=>{
        console.log('モデルを定義');
        const model = tf.sequential();
        // units数をいろいろ変えてみる
        model.add(tf.layers.dense({ units: 12, inputShape: [2], activation:'elu' }));
        model.add(tf.layers.dense({ units: 1,activation:'sigmoid'}));

        const learningRate = 0.01;
        // optimizerをいろいろ変えてみる
        const optimizer = tf.train.rmsprop(learningRate);
        model.compile({loss: 'meanSquaredError', optimizer: optimizer});
        return model;
      }

      const clear =()=>{
        xData = [];
        yData = [];
        xs = null;
        ys = null;
        model = null;
      }

      const start = async(func, logic)=>{
        // モデルの使いまわしはだめ。毎回未訓練のものを作る。
        model = await buildModel();
        // 渡された関数を呼び出して、データを得る
        [xs, ys] = await func();
        xs.print();
        ys.print();
        // 訓練開始
        train(xs, ys, logic);
      }

      // 各ボタンのクリックで、それぞれに対応したデータを返す
      // ANDボタン
      const getAND =()=>{
        const trainData = tf.tensor2d([[0,0],[1,0],[0,1],[1,1]], [4,2]);
        return [trainData, tf.tensor2d( [[0],[0],[0],[1]],[4,1])];
      }

      // NANDボタン
      const getNAND =()=>{
        const trainData = tf.tensor2d([[0,0],[1,0],[0,1],[1,1]], [4,2]);
        return [trainData, tf.tensor2d( [[1],[1],[1],[0]],[4,1])];
      }

      // ORボタン
      const getOR =()=>{
        const trainData = tf.tensor2d([[0,0],[1,0],[0,1],[1,1]], [4,2]);
        return  [trainData, tf.tensor2d([[0],[1],[1],[1]],[4,1])];
      }

      // XORボタン
      const getXOR =()=>{
        const trainData = tf.tensor2d([[0,0],[1,0],[0,1],[1,1]], [4,2]);
        return [trainData, tf.tensor2d([[0],[1],[1],[0]],[4,1])];
      }

      document.getElementById('and-button').addEventListener('click', ()=>{
        clear();
        start( getAND, 'and');
      }, false);

      document.getElementById('nand-button').addEventListener('click', ()=>{
        clear();
        start( getNAND, 'nand');
      }, false);

      document.getElementById('or-button').addEventListener('click', ()=>{
        clear();
        start( getOR, 'or');
      }, false);

      document.getElementById('xor-button').addEventListener('click', ()=>{
        clear();
        start( getXOR, 'xor');
      }, false);


      const train=(xs, ys, logic)=>{
        const epochs = 200;
        console.log('訓練開始');
        model.fit(xs, ys,{
          batchSize: 4,
          epochs: epochs,
          callbacks: {
            onEpochEnd: async (epoch, logs) => {
              const lossData = [epoch,logs.loss];
              //console.log(lossData[0], lossData[1]);
              // グラフに学習の進捗状況を描く
              plot(lossData[0], lossData[1]);
              await tf.nextFrame();
            }
          }
        }).then(() => {
          // tf.Tensorが占める、GPUのメモリを解放
          tf.tidy(()=>{
            console.log('訓練終了');
            // モデルが内部で計算した重み
            console.log(model.trainableWeights[0].read().mean().dataSync())
            console.log(model.trainableWeights[1].read().mean().dataSync())
            console.log(model.trainableWeights[2].read().mean().dataSync())
            console.log(model.trainableWeights[3].read().mean().dataSync())

            // 推論を行う
            const div = document.getElementById(logic);

            // 0,0 の場合
            const test1 = tf.tensor2d([0,0],[1,2]);
            const test1Pred = model.predict(test1);
            const p1 = appendResult(test1Pred);
            div.appendChild(p1);

            // 1,0の場合
            const test2 = tf.tensor2d([1,0],[1,2]);
            const test2Pred = model.predict(test2);
            const p2 = appendResult(test2Pred);
            div.appendChild(p2);

            // 0,1の場合
            const test3 = tf.tensor2d([0,1],[1,2]);
            const test3Pred = model.predict(test3);
            const p3 = appendResult(test3Pred);
            div.appendChild(p3);

            // 1,1の場合
            const test4 = tf.tensor2d([1,1],[1,2]);
            const test4Pred = model.predict(test4);
            const p4 = appendResult(test4Pred);
            div.appendChild(p4);
          });
          // tf.Tensorが占める、GPUのメモリを解放
          xs.dispose();
          ys.dispose();
        });
      };

      // 推論の結果を<p>要素で返す
      const appendResult =(pred)=>{
        const p = document.createElement('p');
        const tNode = document.createTextNode(pred);
        p.appendChild(tNode);
        return p;
      }
    },false);
  </script>
</html>

graph.js

let xData = [];
let yData = [];

const layout = {
  xaxis: {
    range: [0, 200],
    title: 'epochs'
  },
  yaxis: {
    range: [0, 0.5],
    title: 'Loss'
  },
  title: '損失値'
};

const plot = (x, y) => {
  xData.push(x);
  yData.push(y);
  const trace = {
    x: xData,
    y: yData,
    mode: 'lines',
    type: 'scatter',
  };
  Plotly.newPlot('chart', [trace], layout, { displayModeBar: false });
}

やっていることは基本的に、モデルを作成して、それに訓練用データ(tf.tensor2d([[0,0],[1,0],[0,1],[1,1]], [4,2]))と、教師用データ(ANDゲートならtf.tensor2d( [[0],[0],[0],[1]],[4,1]))を与えて訓練し、推論時にtf.tensor2d([0,0],[1,2])とtf.tensor2d([1,0],[1,2])、tf.tensor2d([0,1],[1,2])、tf.tensor2d([1,1],[1,2])を与え、その結果を、4つのゲートの下に表示する、ということです。

ポイントは、モデルをどう定義するか、つまり論理ゲートという問題に適したモデルはどのようなものなのかを探ることにあります。モデルには正解がありません。このモデルはだめだ、前のモデルより少しましだ、ずいぶん良くなった、と試行錯誤することになります。

次は、異なるモデルをいくつか試していきます。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA