LoginSignup
10

More than 5 years have passed since last update.

JavaScriptで手書きひらがなの識別

Posted at

はじめに

前回のJavaScriptで手書き数字の識別は他サイトの学習データを利用しました
今回は「データセットを作る」「学習する」もやります

デモ
http://pie.karou.jp/zy.html

ソース

csvデータ作成ページ http://pie.karou.jp/zv.html

<!DOCTYPE html>
<meta charset="utf-8">
<title>csvデータ作成ページ</title>
小さな黒四角にひらがな(あ~ん)を書いてcsvデータを作成<br>
<canvas id="pad" width="32" height="32"></canvas>
<b id="guide"></b>を書いてください。その後キーボードで"s"を押す。<br>
<textarea id="csv" cols="80" rows="5" wrap="off"></textarea>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/signature_pad/1.5.3/signature_pad.min.js"></script>
<script>
   var hiragana = "あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろわをん".split("");
   var cnt = 0;

   var signaturePad = new SignaturePad($("#pad")[0], {
      penColor: "white",
      backgroundColor: "black",
   });

   document.onkeydown = function(e) {
      if (e.keyCode == 83) { //s
         var ctx = $("#pad")[0].getContext('2d');
         var rgba = ctx.getImageData(0, 0, 32, 32);
         var arr = [];
         var label = cnt % hiragana.length;
         arr.push(label);
         for (var i = 0; i < rgba.data.length; i += 4) arr.push(rgba.data[i]);
         var str = $("#csv").val();
         $("#csv").val(str + arr.join(",") + "\n");
         signaturePad.clear();
         cnt++;
         $("#guide").text(hiragana[cnt % hiragana.length]);
      }
   };
</script>

学習ページ http://pie.karou.jp/zw.html

<!DOCTYPE html>
<meta charset="utf-8">
<title>学習ページ</title>
csvデータ貼り付け用テキストエリア<br>
<textarea id="csv" cols="80" rows="5" wrap="off"></textarea>
<p><input type="button" value="学習" onclick="learnFn()"></p>
<textarea id="json"></textarea>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/convnetjs/0.3.0/convnet.js"></script>
<script>
   var hiragana = "あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろわをん".split("");

   function learnFn() {
      var net = new convnetjs.Net();
      var layer = [];
      layer.push({type: 'input', out_sx: 32, out_sy: 32, out_depth: 1});
      layer.push({type: 'conv', sx: 5, filters: 8, stride: 1, pad: 2, activation: 'relu'});
      layer.push({type: 'pool', sx: 2,stride: 2});
      layer.push({type: 'conv',sx: 5, filters: 16, stride: 1, pad: 2, activation: 'relu'});
      layer.push({ type: 'pool', sx: 3, stride: 3});
      layer.push({ type: 'softmax', num_classes: 5});
      net.makeLayers(layer);
      var trainer = new convnetjs.SGDTrainer(net, {
         method: 'adadelta',
         batch_size: 20,
         l2_decay: 0.001
      });
      var str = $("#csv").val();
      var csvArr = str.trim().split("\n");
      csvArr = csvArr.map(v => v.split(',').map(Number));
      for (var i = 0; i < csvArr.length; i++) {
         var label = csvArr[i][0];
         var input = new convnetjs.Vol(32, 32, 1);
         for (var j = 1; j < csvArr[i].length; j++) input.w[j - 1] = csvArr[i][j] / 255 - 0.5;
         trainer.train(input, label);
      }
      var json = net.toJSON();
      $("#json").val(JSON.stringify(json));
   }
</script>

識別ページ http://pie.karou.jp/zx.html

<!DOCTYPE html>
<meta charset="utf-8">
<title>識別ページ</title>
JSON 貼り付け用テキストエリア<br>
<textarea id="json"></textarea><br>
JSONを貼り付けた後に黒色の小さな正方形にマウスでひらがなを書いて識別してください<br>
<canvas id="pad" width="32" height="32"></canvas>
<button onclick="checkFn()">識別</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/signature_pad/1.5.3/signature_pad.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/convnetjs/0.3.0/convnet.js"></script>
<script>
   var hiragana = "あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろわをん".split("");

   var signaturePad = new SignaturePad($("#pad")[0], {
      penColor: "white",
      backgroundColor: "black",
   });

   function checkFn() {
      var ctx = $("#pad")[0].getContext('2d');
      var rgba = ctx.getImageData(0, 0, 32, 32);
      var net = new convnetjs.Net();
      var netObj = JSON.parse($("#json").val());
      net.fromJSON(netObj);
      var input = new convnetjs.Vol(32, 32, 1);
      for (var i = 0; i < rgba.data.length; i += 4) input.w[i / 4] = rgba.data[i] / 255 - 0.5;
      var output = net.forward(input);
      var max = Math.max(...output.w);
      var index = output.w.indexOf(max);
      alert(hiragana[index]);
      signaturePad.clear();
   }
</script>

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10