2008-03-20 [長年日記]
■コミュニケーションのための「空間」
(BK1内容説明より)
研究開発の知的生産性向上に有効なダイレクトコミュニケーション。その活発化のために何が必要か、全体像を提示。また、知的生産性を直接引き上げる施策を「スキル」「マネジメント」「空間」という3つの切り口で紹介する。
「空間」大事。
そこをなんとかする権限をマネージャーが与えらないといけない、ということを会社が(というのはつまり上司とか上司の上司とかが)理解してないと……。
図書館に入らないかね。
■パーセプトロン……忘れたよ!
見た目上のパラメータ次元数が10×10の100あって、10クラスを分類しようとするのは確かに無理っぽいような気もするけど。
こういうのは数式とか見てるよりも実際にいじっている人じゃないと分からないんだろうなぁ。
1つだけ明確に直すべきだと判断できるのは、上下左右の空白部分を学習に入れてしまっているあたり。
g2.drawImage(img, 0, 0, mesh, mesh, this);
2008-03-18 - きしだのはてな
10×10のmeshに黒画素の濃度を入れて学習に使っているけど、数字の大きさや、書いた位置に左右されてしまう。
なので、上下左右の空白部分を除去した形で、meshを作りたい。
もっとも簡単な正規化を、もっとも頭悪いコードで実装してみる。
import java.awt.*; import java.awt.event.*; import java.awt.image.BufferedImage; import javax.swing.*; public class Perceptron extends JComponent implements ActionListener, MouseMotionListener{ // Image img = new BufferedImage(300, 300, BufferedImage.TYPE_INT_RGB); BufferedImage img = new BufferedImage(300, 300, BufferedImage.TYPE_INT_RGB); Graphics bg = img.getGraphics(); Point pt; final int mesh = 10; double[][][] perc = new double[10][mesh][mesh]; double[] b = new double[10]; double k = 0.1;//学習係数 public static void main(String[] args){ JFrame f = new JFrame("パーセプトロン"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.setSize(320, 400); //描画領域 Perceptron pc = new Perceptron(); pc.addMouseMotionListener(pc); pc.clear(); f.add(pc); //数字ボタン JPanel p = new JPanel(); p.setLayout(new GridLayout(2, 5)); for(int i = 0; i < 10; ++i){ JButton b = new JButton(i +""); p.add(b); b.addActionListener(pc); } f.add(p, BorderLayout.SOUTH); //判定ボタン JButton b = new JButton("判定"); b.addActionListener(pc); f.add(b, BorderLayout.NORTH); //ウィンドウ表示 f.setVisible(true); } /** ボタンが押されたときの処理 */ public void actionPerformed(ActionEvent e) { //手書き結果を学習メッシュに合わせる BufferedImage bi = new BufferedImage(mesh, mesh, BufferedImage.TYPE_INT_RGB); Graphics2D g2 = (Graphics2D) bi.getGraphics(); Rectangle destArea = noWhiteArea(img); g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); // g2.drawImage(img, 0, 0, mesh, mesh, this); g2.drawImage(img, 0, 0, mesh, mesh, destArea.x, destArea.y, destArea.x + destArea.width, destArea.y + destArea.height, this); if("判定".equals(e.getActionCommand())){ //判定ボタンの処理 double mr = 0; int ans = -1; //認識失敗??? for(int i = 0; i < 10; ++i){ double r = 0; for(int x = 0; x < mesh; ++x){ for(int y = 0; y < mesh; ++y){ double d = (255 - bi.getRGB(x, y) & 255) / 255.; r += d * perc[i][x][y]; } } r += b[i]; System.out.printf("%d:%.2f ", i, r); if(mr < r){ mr = r; ans = i; } } System.out.println("\n答えは" + ans); clear(); return; } //数字ボタンが押されたときの学習処理 int idx = Integer.parseInt(e.getActionCommand()); for(int i = 0; i < 10; ++i){ double yi = (i == idx) ? 1 : -1; double in = 0; for(int x = 0; x < mesh; ++x){ for(int y = 0; y < mesh; ++y){ double d = (255 - bi.getRGB(x, y) & 255) / 255.; in += d * perc[i][x][y]; } } in = (in + b[i]) * yi; System.out.printf("%d:% .2f ", i, in); if(in <= 0){ //再学習 for(int x = 0; x < mesh; ++x){ for(int y = 0; y < mesh; ++y){ double d = (255 - bi.getRGB(x, y) & 255) / 255.; perc[i][x][y] += d * k * yi; b[i] += k * yi; } } } } System.out.println(); clear(); } /** マウスで描画 */ public void mouseDragged(MouseEvent e) { Point old = pt; pt = e.getPoint(); if(old != null){ bg.setColor(Color.BLACK); ((Graphics2D)bg).setStroke(new BasicStroke(25)); bg.drawLine(old.x, old.y, pt.x, pt.y); repaint(); } } public void mouseMoved(MouseEvent e) { pt = null; } //描画 @Override protected void paintComponent(Graphics g) { g.drawImage(img, 0, 0, this); } private void clear(){ bg.setColor(Color.WHITE); bg.fillRect(0, 0, 300, 300); repaint(); } public Rectangle noWhiteArea(BufferedImage img) { Rectangle ret = new Rectangle(); Graphics2D g2 = (Graphics2D) img.getGraphics(); BREAKTOP: for (int x=0; x<300; x++) { for (int y = 0; y< 300; y++){ if ((img.getRGB(x,y) & 255)==0) { ret.x = x; break BREAKTOP; } } } BREAKLEFT: for (int y=0; y<300; y++) { for (int x = 0; x< 300; x++){ if ((img.getRGB(x,y) & 255)==0) { ret.y = y; break BREAKLEFT; } } } BREAKDOWN: for (int x=299; x>=0; x--) { for (int y = 299; y >= 0; y--){ if ((img.getRGB(x,y) & 255)==0) { ret.width = x - ret.x; break BREAKDOWN; } } } BREAKRIGHT: for (int y=299; y>=0; y--) { for (int x = 299; x>= 0; x--){ if ((img.getRGB(x,y) & 255)==0) { ret.height = y - ret.y; break BREAKRIGHT; } } } return ret; } }
最後のメソッドの追加と、mesh に drawImage する時にそこから範囲を指定しているところが大きな修正点。
Rectangle destArea = noWhiteArea(img); g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); // g2.drawImage(img, 0, 0, mesh, mesh, this); g2.drawImage(img, 0, 0, mesh, mesh, destArea.x, destArea.y, destArea.x + destArea.width, destArea.y + destArea.height, this);
黒画素が存在する矩形部分だけを、mesh に対して drawImage してみました、ということ。
あとは些末。
……マシになったような気もするけど、気のせいと言われればそんな気も。
データ集合を準備して、ちゃんと学習データと、認識用のデータを固定しないと、評価はできませんねぇ。
■音源調整の革命……かも
まずはムービーを見るべし。ダウンロードした方がいいかも。
これ、すごい!
すごい、と思うのは、フーリエ変換して周波数特性を見る、なんてことを大学の時にかじったからかもしれないけど、でもこれって、Photoshop (の様なソフト)がデジタルな写真加工に革命をもたらしたのと同じことが、音楽の世界でも起きるかもしれないってことでは?
ちょっとしたミスでもデジタルで調整すればいいや、みたいな。
いや、今でもある程度のことは出来るんだろうけど、それがさらに加速する、てなことを想像してる。
面白い。