<?xml version="1.0" encoding="UTF-8" ?>
<rdf:RDF
  xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  xmlns="http://purl.org/rss/1.0/"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:content="http://purl.org/rss/1.0/modules/content/">

  <channel rdf:about="http://krr.blog.shinobi.jp/RSS/100/">
    <title>軽Lab</title>
    <link>http://krr.blog.shinobi.jp/</link>
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://krr.blog.shinobi.jp/RSS/" />
    <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" />
    <description>Javaを中心とした、プログラミング関係のナレッジベース</description>
    <dc:language>ja</dc:language>
    <dc:date>2021-11-15T01:40:41+09:00</dc:date>
    <items>
    <rdf:Seq>
      <rdf:li rdf:resource="http://krr.blog.shinobi.jp/javafx_praxis/%E7%94%BB%E9%9D%A2%E3%82%AD%E3%83%A3%E3%83%97%E3%83%81%E3%83%A3-%E3%82%B3%E3%83%9E%E6%92%AE%E3%82%8A-" />
      <rdf:li rdf:resource="http://krr.blog.shinobi.jp/javafx/javafx%20webp%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E9%96%8B%E3%81%8F%EF%BC%88%E6%AC%A1%E4%B8%96%E4%BB%A3%E7%94%BB%E5%83%8F%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%83%88%EF%BC%89" />
      <rdf:li rdf:resource="http://krr.blog.shinobi.jp/javafx/eclipse%E3%81%A7javafx%E5%85%A5%E9%96%80-%E5%B8%B0%E3%81%A3%E3%81%A6%E3%81%8D%E3%81%9F%E7%84%A1%E5%84%9F%E3%81%AEjava17-" />
      <rdf:li rdf:resource="http://krr.blog.shinobi.jp/java_deeplearning/java%20deeplearning4j%20%E5%8D%98%E8%AA%9E%E3%81%AE%E3%83%99%E3%82%AF%E3%83%88" />
      <rdf:li rdf:resource="http://krr.blog.shinobi.jp/java_deeplearning/java%20deeplearning4j%20%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF%E3%81%AE%E8%A8%AD%E5%AE%9A" />
      <rdf:li rdf:resource="http://krr.blog.shinobi.jp/java_deeplearning/java%20deeplearngin4j%20%E3%83%8B%E3%83%A5%E3%83%BC%E3%83%A9%E3%83%AB%E3%83%8D" />
      <rdf:li rdf:resource="http://krr.blog.shinobi.jp/java_deeplearning/java%20deeplearning4j%20%E5%A4%9A%E5%B1%A4%E3%83%91%E3%83%BC%E3%82%BB%E3%83%97%E3%83%88%E3%83%AD%E3%83%B3%E3%81%AE%E6%A7%8B%E7%AF%89" />
      <rdf:li rdf:resource="http://krr.blog.shinobi.jp/java_deeplearning/java%20deeplearning%204j%20gpu%E3%81%AB%E3%82%88%E3%82%8B%E9%AB%98%E9%80%9F%E5%8C%96" />
      <rdf:li rdf:resource="http://krr.blog.shinobi.jp/java_deeplearning/deeplearning%204j%20%E7%95%B3%E3%81%BF%E8%BE%BC%E3%81%BF%E3%83%8B%E3%83%A5%E3%83%BC%E3%83%A9%E3%83%AB%E3%83%8D" />
      <rdf:li rdf:resource="http://krr.blog.shinobi.jp/java_deeplearning/deeplearning%204j%20%E6%89%8B%E6%9B%B8%E3%81%8D%E6%95%B0%E5%AD%97%E3%81%AE%E8%AD%98%E5%88%A5%E3%82%92%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B" />
    </rdf:Seq>
    </items>
  </channel>

  <item rdf:about="http://krr.blog.shinobi.jp/javafx_praxis/%E7%94%BB%E9%9D%A2%E3%82%AD%E3%83%A3%E3%83%97%E3%83%81%E3%83%A3-%E3%82%B3%E3%83%9E%E6%92%AE%E3%82%8A-">
    <link>http://krr.blog.shinobi.jp/javafx_praxis/%E7%94%BB%E9%9D%A2%E3%82%AD%E3%83%A3%E3%83%97%E3%83%81%E3%83%A3-%E3%82%B3%E3%83%9E%E6%92%AE%E3%82%8A-</link>
    <title>JavaFX 画面キャプチャ(コマ撮り)</title>
    <description>アニメを見てると「いまの作画かっこいいなー」と思い、コマ送りで原画・動画を確認したくなることが時々ある。今回は唐突にゲームのOPのコマ送り画像が見たくなったため、連続で画面キャプチャを行い、コマ撮り画像を取得するプログラムを作ってみた。

◇コード

package application;
	
i...</description>
    <content:encoded><![CDATA[アニメを見てると「いまの作画かっこいいなー」と思い、コマ送りで原画・動画を確認したくなることが時々ある。今回は唐突にゲームのOPのコマ送り画像が見たくなったため、連続で画面キャプチャを行い、コマ撮り画像を取得するプログラムを作ってみた。<br />
<br />
<strong>◇コード</strong><br />

<pre class="brush:javafx" title="Main.java" style="border: 1px gray solid; overflow: auto; overflow-y: hidden;">package application;
	
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;

import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.image.WritableImage;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.robot.Robot;
import javafx.stage.Stage;

public class Main extends Application {

	private Stage 		primaryStage;
    private TextField 	text = new TextField();
	private Robot   robot   = new Robot();
    private double xOffset = 0;
    private double yOffset = 0;
	
	@Override
	public void start(Stage primaryStage) {
		// 退避
		this.primaryStage = primaryStage;
		
		try {
			// Pane
			StackPane	root	= new StackPane();
		    HBox	  	hbox1 	= new HBox();
		    HBox	  	hbox2 	= new HBox();
		    root.getChildren().add( hbox2 );
		    root.getChildren().add( hbox1 );
			root.setStyle("-fx-background-color: rgba(0,0,0,0.3);");
			
	        // 開始ボタン
			Button		btn1	= new Button("キャプチャ");
			EventHandler&lt;ActionEvent&gt;      btn1Handler = ( event ) -&gt; {
				try {
					this.capture();
				} catch (IOException e) {
					e.printStackTrace();
				}
			};
	        btn1.addEventHandler( ActionEvent.ANY , btn1Handler );
	        hbox1.getChildren().add( btn1 );
			
	        // テキストフィールド
	        text.setText( "20" );
	        hbox1.getChildren().add( text );
	        
			// 範囲選択
			EventHandler&lt;MouseEvent&gt; pressHandler = ( event ) -&gt; {
	            xOffset = event.getSceneX();
	            yOffset = event.getSceneY();
			};
	        root.addEventHandler( MouseEvent.MOUSE_PRESSED , pressHandler );
			
			EventHandler&lt;MouseEvent&gt; dragHandler = ( event ) -&gt; {
	            primaryStage.setX(event.getScreenX() - xOffset);
	            primaryStage.setY(event.getScreenY() - yOffset);				
			};
	        root.addEventHandler( MouseEvent.MOUSE_DRAGGED , dragHandler );
	        
	        
			// Scene
			Scene scene = new Scene(root,400,400, Color.TRANSPARENT);
			
			// Stage
			primaryStage.setScene(scene);
			primaryStage.setOpacity( 0.75 );
			primaryStage.show();
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
	

	private void capture() throws IOException
	{		
		// キャプチャ準備
		int time = Integer.parseInt( text.getText() );
		this.primaryStage.hide();

		// 画面サイズを取得
		BufferedImage 	bImg = new BufferedImage((int)this.primaryStage.getWidth(), (int)this.primaryStage.getHeight(), BufferedImage.TYPE_INT_RGB);
		int x = (int) primaryStage.getX();
		int y = (int) primaryStage.getY();
		int width  = (int) primaryStage.getWidth();
		int height = (int) primaryStage.getHeight();

		// アニメーション取得
		List&lt;WritableImage&gt; list = new ArrayList&lt;WritableImage&gt;();
		for( int i = 0 ; i &lt; time ; i++ ) 
		{
			// キャプチャ
			WritableImage 	img		= robot.getScreenCapture(null, x,y,width,height);
			list.add( img );
		}
		
		// ファイル出力
		for( int i = 0 ; i &lt; list.size() ; i++ )
		{
			// ファイル名
			String fileName = String.format( "result/output%03d.png" , i );
			
			// 画像出力
			SwingFXUtils.fromFXImage( list.get(i) , bImg );
			ImageIO.write( bImg , "png" , new File( fileName ) );
		}
		
		// ウィンドウを復元
		primaryStage.show();
		primaryStage.setX( x );
		primaryStage.setY( y );
		primaryStage.setWidth( width );
		primaryStage.setHeight( height );
	}
}
</pre>
<br />
<br />
<strong>◇実行結果<br />
</strong>画面上でキャプチャ対象の動画を再生し、上記プログラムで「キャプチャ」ボタンを押下した際の実行結果は以下の通り。<br />
<br />
ウィンドウのイメージ<br />
<img src="//krr.blog.shinobi.jp/File/cca1f556.png" alt="" /> <br />
<br />
出力画像サンプル<strong><img src="//krr.blog.shinobi.jp/File/217eac7d.png" alt="" /> <br />
</strong>「<a href="https://www.bandainamcoent.co.jp/cs/list/talesofdestiny_ps2/" title="" target="_blank">テイルズオブデスティニー</a>」よりOP<strong><br />
<br />
◇解説</strong><br />
　プログラムはJavaFXで作成している。JavaFXでのライブラリ設定と起動引数については、<a href="http://krr.blog.shinobi.jp/javafx/eclipseでjavafx入門-帰ってきた無償のjava17-" title="" target="_blank">こちら</a>を参照。 半透明のウィンドウを表示し、「キャプチャ」ボタンを押下するとウィンドウの背面の画像を取得することができる。画面キャプチャはテキスト・フィールドに入力したコマ数分だけ取得し、Robotクラスで取得している。]]></content:encoded>
    <dc:subject>Java 応用・実験</dc:subject>
    <dc:date>2021-11-14T04:07:21+09:00</dc:date>
    <dc:creator>Da@</dc:creator>
    <dc:publisher>NINJA BLOG</dc:publisher>
    <dc:rights>Da@</dc:rights>
  </item>
  <item rdf:about="http://krr.blog.shinobi.jp/javafx/javafx%20webp%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E9%96%8B%E3%81%8F%EF%BC%88%E6%AC%A1%E4%B8%96%E4%BB%A3%E7%94%BB%E5%83%8F%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%83%88%EF%BC%89">
    <link>http://krr.blog.shinobi.jp/javafx/javafx%20webp%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E3%82%92%E9%96%8B%E3%81%8F%EF%BC%88%E6%AC%A1%E4%B8%96%E4%BB%A3%E7%94%BB%E5%83%8F%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%83%88%EF%BC%89</link>
    <title>JavaFX WebP画像ファイルを開く（webp-imageioライブラリ）</title>
    <description>Webブラウザで利用される画像形式として、写真はJpeg、ロゴやイラストはGIF、PNG形式で保存することが一般的となっていると思われる。GIFやPNGでは透過（アルファチャンネル）やアニメーションの機能も備わっており機能的には十分であるが、Webサイトの利便性やSEO対策の面からファイルサイズが小...</description>
    <content:encoded><![CDATA[<div>Webブラウザで利用される画像形式として、写真はJpeg、ロゴやイラストはGIF、PNG形式で保存することが一般的となっていると思われる。GIFやPNGでは透過（アルファチャンネル）やアニメーションの機能も備わっており機能的には十分であるが、Webサイトの利便性やSEO対策の面からファイルサイズが小さい画像フォーマットは望まれ続けている。<br />
<br />
従来の画像フォーマットよりもファイルサイズが小さい次世代の画像フォーマットとしては、WebPやAVIFといった規格が公開されている。その中でもWebPについては、2021年11月現在、ほぼすべてのWebブラウザで対応できており、利用する場面も増えてくることが予想される。今回はJavaFXでWebP画像の入出力方法を確認する。</div>
<br />

<div style="border: 1px black solid; padding: 10px; padding-left: 40px;"><b>TOPIC</b><ol style="padding-left: 20px;">
<li><a href="#WebPとは？" title="">WebPとは？</a></li>
<li><a href="#WebPライブラリ" title="">WebPライブラリ「webp-imageio」</a></li>
<li><a href="#WebPファイルの読込・表示" title="">WebPファイルの読込・表示</a></li>
<li><a href="#WebPファイルの書出" title="">WebPファイルの書出</a></li>
</ol></div>
<br />
<hr />
<h4 style="font-size: 14px;"><a name="WebPとは？"></a>■　WebPとは？</h4>
Googleが2010年9月に公開したオープンな画像フォーマット(<a href="#ref1">*1</a>)(<a href="#ref2">*2</a>)。ロスレス圧縮、非可逆圧縮の両方に対応しており、透過（アルファチャンネル）やアニメーションにも対応している。特徴としてファイルサイズの小ささが上げられ、ロスレスの場合にはPNGよりもファイルサイズが26％小さく、非可逆圧縮の場合には25〜34％小さくできるとGoogleは謳っている。<br />
<br />
2021年11月時点での各ブラウザでの対応状況は以下の通りであり、ほぼすべてのブラウザで対応している。（緑が「対応済み」、黄色が「部分対応」、赤が「未対応」。2022年6月にサポートを打ち切るIE(<a href="#ref3">*3</a>)や、Safari(iOS除く)で対応できていない程度）<br />
<br />
<img src="//krr.blog.shinobi.jp/File/eb35be1b.png" alt="" style="border: 1px solid gray;" /> <br />
引用「<a href="https://caniuse.com/?search=webp" title="" target="_blank">Can I use（WebP）</a>」<br />
<br />
なお、WebPの後継と言われているAVIFの対応状況は以下のとおりであり、まだ普及するまでには至っていないようである。<br />
<br />
<img src="//krr.blog.shinobi.jp/File/bbfde9f6.png" alt="" width="611" height="117" style="border: 1px solid gray; float: none;" /><br />
引用「<a href="https://caniuse.com/?search=AVIF" title="" target="_blank">Can I use（AVIF）</a>」<br />
<br />
<hr />
<h4 style="font-size: 14px;"><a name="WebPライブラリ"></a>■　WebPライブラリ「webp-imageio」</h4>
JavaのWebPライブラリとして、「webp-imageio」を利用する。以下にGitのリポジトリが公開されており、ライセンスは「Apache Software License version 2.0.」（著作権表示等の事項を守れば商用も可能(<a href="#ref4">*4</a>)）とのこと。<br />
<br />

<ul>
<li><a href="https://github.com/sejda-pdf/webp-imageio" title="" target="_blank">sejda-pdf / webp-imageio</a></li>
</ul>
<br />
最新ソースを試したい場合には、上記ページからソースをダウンロードしてコンパイルする必要があるが、Maven Repositoryに登録済みであるため、安定版を以下からライブラリ（jarファイル）をダウンロードできる。2021年11月11日時点では、バージョン「0.1.6」が最新である。<br />
<br />

<ul>
<li><a href="https://mvnrepository.com/artifact/org.sejda.imageio/webp-imageio" title="" target="_blank">Maven Repository(WebP ImageIO)</a></li>
</ul>
<br />
<strong>◇ダウンロード方法（バージョン0.1.6の場合）</strong><br />
①「0.1.6」をクリック<br />
<img src="//krr.blog.shinobi.jp/File/bb619dbb.png" alt="" width="611" height="372" style="border: 1px solid gray; float: none;" /><br />
<br />
②　「jar(1.0MB)」をクリック<br />
<img src="//krr.blog.shinobi.jp/File/7d573a82.png" alt="" width="611" height="289" style="border: 1px solid gray; float: none;" /><br />
<br />
③　ライブラリ「webp-imageio-0.1.6.jar」がダウンロードされる。<br />
<br />
上記方法でダウンロードしたjarファイルを、クラスパスに通せばライブラリが可能となる。クラスパスの追加方法については、<a href="http://krr.blog.shinobi.jp/java/クラスパス／環境変数の設定#クラス・パスの設定" title="" target="_blank">こちらの記事</a>を参照のこと。<br />
<br />
<hr />
<h4 style="font-size: 14px;"><a name="WebPファイルの読込・表示"></a>■　WebPファイルの読込・表示</h4>
「webp-imageio」を利用してWebPファイルを読み込み、JavaFXで表示するサンプルプログラムを示す。<br />
<br />
<strong>◇リソース</strong> JavaFXプロジェクトの作成方法は<a href="http://krr.blog.shinobi.jp/javafx/eclipseでjavafx入門-帰ってきた無償のjava17-" title="" target="_blank">こちら</a>を参照。<br />
<br />
【実行引数】<br />
--module-path "(javaFXの配置パス)\lib" --add-modules javafx.controls,javafx.fxml<br />
<br />
【使用画像】<br />
Googleの<a href="https://developers.google.com/speed/webp/gallery1" title="" target="_blank">WebP Gallary</a>の画像を利用する。<br />

<div><a href="https://www.gstatic.com/webp/gallery/1.webp" title="" target="_blank">https://www.gstatic.com/webp/gallery/1.webp</a>&nbsp;(著作権者: Kjetil Birkeland Moe)<br />
<br />
<strong>◇サンプルコード</strong></div>
<pre class="brush:javafx" style="border: 1px gray solid; overflow: auto; overflow-y: hidden;">package application;
	
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;

import javax.imageio.ImageIO;
import javax.imageio.ImageReader;
import javax.imageio.stream.FileImageInputStream;

import com.luciad.imageio.webp.WebPReadParam;

import javafx.application.Application;
import javafx.embed.swing.SwingFXUtils;
import javafx.scene.Scene;
import javafx.scene.image.ImageView;
import javafx.scene.image.WritableImage;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;


/**
 * 
 * sejda-pdf/webp-imageio
 *
 *  GitHub
 *  https://github.com/sejda-pdf/webp-imageio
 *  
 *  Maven Repository
 *  https://mvnrepository.com/artifact/org.sejda.imageio/webp-imageio
 *  
 * @author Da@
 *
 */
public class Main extends Application {
	@Override
	public void start(Stage primaryStage) {
		// Scene Graphクラス
	    AnchorPane root = new AnchorPane();

	    // WEBP画像読込
	    WritableImage img = null;
	    try {
	    	// 前準備
		    ImageReader 	reader 	= ImageIO.getImageReadersByMIMEType("image/webp").next();
		    WebPReadParam 	readParam 	= new WebPReadParam();
		    readParam.setBypassFiltering( true );
		    
		    // ファイルを開く
	    	reader.setInput( new FileImageInputStream( new File("img/1.webp") ) );
	    	BufferedImage bimg = reader.read( 0 , readParam );
	    	
	    	// awtからjavaFXへ変換
	    	img = SwingFXUtils.toFXImage( bimg , null );
	    	
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	    
	    // 画像をウィンドウに追加
	    ImageView view = new ImageView( img );
	    root.getChildren().add( view );
	    
	    // Sceneクラス
	    Scene scene = new Scene(root);

	    // Stageクラス
	    primaryStage.setScene(scene);
	    primaryStage.show();
	}
	
	public static void main(String[] args) {
		launch(args);
	}
}</pre>
<strong>◇実行結果</strong><br />
<img src="//krr.blog.shinobi.jp/File/ca5bbe0d.png" alt="" /> <br />
<br />
<strong>◇解説</strong><br />
WebPファイルの読込部分は43行目以降のtry文の中である。ポイントとして、52行目で読み込んだWebP画像はawtのImage型(BufferedImage)であるため、55行目でJavaFXのImage型(WritableImage)に変換している。<br />
<br />
<hr />
<h4 style="font-size: 14px;"><a name="WebPファイルの書出"></a>■　WebPファイルの書出</h4>
GIF画像を読み込み、「webp-imageio」を利用して出力するサンプルプログラムを示す。<br />
<br />
<strong>◇リソース</strong> <br />
【使用画像】<br />
・透過＋アニメーションする画像<br />
プロジェクト中のパス：<a href="//krr.blog.shinobi.jp/File/b50_r.gif" title="" target="_blank">img/b50_r.gif</a><br />

<div style="margin: 0px; background-color: black;"><img src="//krr.blog.shinobi.jp/File/b50_r.gif" alt="" /></div>
配布元：<a href="http://suwaro.websozai.jp/a_mtl/gif_anim/gif_anim2/index.html" title="" target="_blank">フリー素材サイト月色すわろ</a><br />

<div><br />
<strong>◇サンプルコード</strong>
<pre class="brush:javafx" style="border: 1px gray solid; overflow: auto; overflow-y: hidden;">import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.FileImageOutputStream;

import com.luciad.imageio.webp.WebPWriteParam;

public class Main {

	public static void main(String[] args)
	{
		try {
			// 画像の読み込み
			BufferedImage image = ImageIO.read(new File("img/b50_r.gif"));

			// WebP画像出力
			ImageWriter writer = ImageIO.getImageWritersByMIMEType("image/webp").next();
			
			// 出力設定
			WebPWriteParam writeParam = new WebPWriteParam(writer.getLocale());
			writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
			writeParam.setCompressionType("Lossless");
			writer.setOutput(new FileImageOutputStream(new File("img/out.webp")));

			// WebP画像出力
			writer.write(null, new IIOImage(image, null, null), writeParam);
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

}
</pre>
<strong>◇実行結果</strong><br />
出力ファイル：<a href="//krr.blog.shinobi.jp/File/out.webp" title="" target="_blank">img/out.webp</a><br />

<div style="margin: 0px; background-color: black;"><a href="//krr.blog.shinobi.jp/File/out.webp" title="" target="_blank"><img src="//krr.blog.shinobi.jp/File/out.webp" alt="" /></a></div>
<br />
<strong>◇解説</strong><br />
WebPファイルの読込部分は25行目以降である。<br />
出力結果のファイルを確認すると、「webp-imageio」では透過（アルファチャンネル）は実装できている。ただし、アニメーション出力はできていない。オプション設定等があるのかとソースを少し見てみたが、特にアニメーションの実装は見つけられなかったので、おそらく未実装な模様。</div>
<div><br />
<hr />
<h4 style="color: #000000;">■　参照</h4>
<ol style="color: #000000;">
<li><a name="ref1"></a><a href="https://developers.google.com/speed/webp" title="" target="_blank">Google「An image format for the Web」</a></li>
<li><a name="ref2"></a><a href="https://ja.wikipedia.org/wiki/WebP" title="" target="_blank">ウィキペディア「WebP」</a></li>
<li><a name="ref3"></a><a href="https://www.ipa.go.jp/security/announce/ie_eos.html" title="" target="_blank">IPA「Microsoft 社 Internet Explorer のサポート終了について」</a></li>
<li><a name="ref4"></a><a href="https://ja.wikipedia.org/wiki/Apache_License" title="" target="_blank">ウィキペディア「Apache License」</a></li>
</ol></div>]]></content:encoded>
    <dc:subject>JavaFX入門</dc:subject>
    <dc:date>2021-11-11T21:01:50+09:00</dc:date>
    <dc:creator>Da@</dc:creator>
    <dc:publisher>NINJA BLOG</dc:publisher>
    <dc:rights>Da@</dc:rights>
  </item>
  <item rdf:about="http://krr.blog.shinobi.jp/javafx/eclipse%E3%81%A7javafx%E5%85%A5%E9%96%80-%E5%B8%B0%E3%81%A3%E3%81%A6%E3%81%8D%E3%81%9F%E7%84%A1%E5%84%9F%E3%81%AEjava17-">
    <link>http://krr.blog.shinobi.jp/javafx/eclipse%E3%81%A7javafx%E5%85%A5%E9%96%80-%E5%B8%B0%E3%81%A3%E3%81%A6%E3%81%8D%E3%81%9F%E7%84%A1%E5%84%9F%E3%81%AEjava17-</link>
    <title>EclipseでJavaFX入門(Java17での環境構築)</title>
    <description>Java9以降様々なトピックがあった模様のOracle製のJava。Java9以降は商用利用が有償化していたので少し敬遠していたが、なんとJava17以降は再度無償化する(*1)(*2)とのこと。今回は、Java17+JavaFXの環境構築をやってみることにする。

■　JavaFXとは？
Java...</description>
    <content:encoded><![CDATA[<p>Java9以降様々なトピックがあった模様のOracle製のJava。Java9以降は商用利用が有償化していたので少し敬遠していたが、なんとJava17以降は再度無償化する(<a href="https://blogs.oracle.com/java/post/free-java-license" title="" target="_blank">*1</a>)(<a href="https://www.oracle.com/jp/news/announcement/java17-jp-2021-09-17/" title="" target="_blank">*2</a>)とのこと。今回は、Java17+JavaFXの環境構築をやってみることにする。</p>
<hr />
<h4 style="font-size: 14px;">■　JavaFXとは？</h4>
JavaFXはJava8でJDKに標準搭載されたクライアントUI(デスクトップアプリ)である。Javaのクライアントでは他にawtやswingがあるが、FXMLによるデザインの分離等、より使いやすいGUIを目指したのがJavaFXとなる。<br />
一方、JDKの小型化を目指したOracleの方針(<a href="https://www.oracle.com/webfolder/technetwork/jp/javamagazine/Java-ND18-JavaFXFutures-ja.pdf" title="" target="_blank">*3</a>)により、Java11からは標準ライブラリから分離したものの、OpenJDKプロジェクトの主導によりプロジェクトは継続しており、JDKのバージョンアップに合わせてリリースを続けている。2021年現在はJavaFX 17として、外部ライブラリのような形で利用可能となっている。<br />
<hr />
<h4 style="font-size: 14px;">■　自己完結型アプリケーションにも対応</h4>
Javaのデスクトップアプリのデメリットとして、利用者側にJREのインストールが必要なことがあげられるが、Java8からは自己完結型アプリケーションに変換することでexe形式と同様の扱いができるようになっている。もちろん、JavaFXアプリケーションでも自己完結型アプリケーションを作成できる(<a href="https://docs.oracle.com/javase/jp/8/docs/technotes/guides/deploy/self-contained-packaging.html" title="" target="_blank">*4</a>)。<hr />
<h4 style="font-size: 14px;"><span>■　インストール / ダウンロード</span></h4>
まずは事前環境構築として以下をインストール。特に問題はなかったので、詳細は割愛。<br />
<ol>
<li><a href="https://www.oracle.com/java/technologies/downloads/" title="" target="_blank">Java SE Development Kit 17.0.1</a></li>
<li><a href="https://mergedoc.osdn.jp/" title="" target="_blank">pleiades (Eclipse 2021 PlatForm)</a></li>
</ol><br />
次にJavaFXをダウンロードする。<a href="https://gluonhq.com/products/javafx/" title="" target="_blank">ここ</a>から自分の環境に合わせたJavaFX(sdk)をダウンロードして解凍する。(どうやら、Gluonという企業がJava FXの支援を行っている模様で、公式のダウンロードリンクがGluonのページにつながっている)<br />
<img src="//krr.blog.shinobi.jp/File/b0154cb8.png" style="border: 1px gray solid;" alt="" /> <br />
<br />
解凍したファイルはEclipseから参照することになるので、一時的な場所でなく、長期保存する場所に置いておく。（とりあえず、Javaのインストールフォルダに入れておいた）<br />
<br />

<h4 style="font-size: 14px;">■　Eclipse設定(プラグインのインストール)</h4>
次にeclipse(pleiades)を起動する。<br />
「ヘルプ-新規ソフトウェアのインストール」を開く。<br />
<img src="//krr.blog.shinobi.jp/File/985b9c52.png" alt="" /> <br />
<br />
作業対象に「https://download.eclipse.org/releases/2021-09」を入力。 その後、以下のソフトウェアをインストールする。<br />
<br />
<ol>
<li>「プログラミング言語」の「Eclipse Java 開発ツール」</li>
<li>「プログラミング言語」の「JavaDoc ヘルプ・フィーチャー」</li>
</ol><br />
同様に「http://download.eclipse.org/releases/oxygen」から、以下のソフトウェアをインストールする。<br />
<br />
<ol>
<li>「一般用ツール」の「e(fx)clipse - IDE」</li>
</ol><br />
インストールが終わったら、「ヘルプ-新規ソフトウェアのインストール」の右下のリンク「すでにインストールされている」をクリックして、目的のソフトウェアがインストールが完了したことを確認する。<br />
<img src="//krr.blog.shinobi.jp/File/d6009862.png" alt="" /> <br />
<br />
なお、eclipseの右下のバーに以下のような表示がある場合、インストール中のためしばらく待てばOK。<br />
<img src="//krr.blog.shinobi.jp/File/c232f263.png" style="border: 1px gray solid;" alt="" /> <br />
<br />

<h4 style="font-size: 14px;">■　Eclipse設定(インストール済みJDKの関連付け)</h4>
「ウィンドウ-設定」にて「Java-インストール済みのJRE」にインストールしたJDKパスを設定する。<img src="//krr.blog.shinobi.jp/File/a9711718.png" alt="" /> <br />
<br />

<h4 style="font-size: 14px;">■　Eclipse設定(JavaFXライブラリへのパスを定義)</h4>
elipcseにダウンロード済みのJavaFXライブラリへのパスを定義します。<br />
「ウィンドウ - 設定」ダイアログを開き、「Java - ビルド・パス - ユーザー・ライブラリ」を選択する。<br />
<img src="//krr.blog.shinobi.jp/File/82c6b702.png" style="border: 1px gray solid;" alt="" /> <br />
<br />
「新規」ボタンを押下して、ユーザー・ライブラリー名に「JavaFX」と入力して、「OK」ボタンを押下する。<br />
<img src="//krr.blog.shinobi.jp/File/b0576086.png" alt="" /> <br />
<br />
「外部JARの追加」を選択する。<br />
<br />
<img src="//krr.blog.shinobi.jp/File/eb0860a3.png" alt="" /> <br />
<br />
ダウンロード済みのJavaFXの「lib/*.jar」をすべて選択して、「OK」ボタンを押下する。<br />
<img src="//krr.blog.shinobi.jp/File/01223989.png" alt="" /> <br />
<br />
これで、ユーザ定義した外部JARグループ「JavaFX」が作成されました。<br />
<br />

<h4 style="font-size: 14px;">■　プロジェクト作成（ユーザ・ライブラリの関連付け、実行構成）</h4>
いよいよプログラミング&hellip;の前に、プロジェクトの設定から。 「ファイル - 新規&nbsp;-&nbsp;プロジェクト」から「JavaFX - JavaFX プロジェクト」を選択。適当なプロジェクト名をつけ、後の設定はデフォルトのままで新規プロジェクト作成。<br />
<img src="//krr.blog.shinobi.jp/File/c9073302.png" alt="" /> <br />
<br />
プロジェクト作成直後は、プロジェクトにJavaFXのライブラリが関連付けられていないため、コンパイルエラーが発生している。このため、作成したプロジェクトに先ほど作成したユーザー・ライブラリ「JavaFX」を関連付ける。<br />
<br />
「プロジェクト・エクスプローラー」のプロジェクト名を右クリックして「ビルド・パス - ビルド・パスの構成」を選択する。<img src="//krr.blog.shinobi.jp/File/a7af59e4.png" alt="" /> <br />
「ライブラリー」の「クラスパス」を選択し、「ライブラリーの追加」を押下する。<br />
<img src="//krr.blog.shinobi.jp/File/cd193d79.png" alt="" /> <br />
<br />
「ユーザー・ライブラリー」を選択して、「次へ」ボタンを押下。<br />
<img src="//krr.blog.shinobi.jp/File/14864790.png" alt="" /> <br />
<br />
「JavaFX」にチェックを入れて、「完了」を押下。<br />
<img src="//krr.blog.shinobi.jp/File/91590e27.png" alt="" /> <br />
<br />
この時点でコンパイルエラーが消えます。<br />
<br />
最後に、実行時にJavaFXを利用するための実行構成を定義します。プロジェクト名を右クリックして、「実行 - 実行の構成」を選択。<br />
<img src="//krr.blog.shinobi.jp/File/e0256cdf.png" style="border: 1px gray solid;" alt="" /> <br />
<br />
左のリストから「Javaアプリケーション - Main」を選択し、「引数」タブの「VM引数」に以下のように入力。その後、「適用」ボタンを押下してからダイアログを閉じる。<br />
<br />

<pre class="brush:javafx" style="border: 1px gray solid; overflow: auto; overflow-y: hidden;">--module-path "(ダウンロードしたJavaFXのlibフォルダへのフルパス)" --add-modules javafx.controls,javafx.fxml</pre>
<hr />
<h4 style="font-size: 14px;">■　実行</h4>
プロジェクトをJavaパースペクティブで開きます。プロジェクト内にsrc/application/Main.javaが作成されており、以下のようなソースがデフォルトで作成されていることがわかります。詳しい説明は次回以降に説明していくが、JavaFXではApplicationクラスを継承したクラスから始まることを覚えておく。<br />
<br />
◇サンプルコード<br />

<pre class="brush:javafx" style="border: 1px gray solid; overflow: auto; overflow-y: hidden;">package application;
	
import javafx.application.Application;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;


public class Main extends Application {
	@Override
	public void start(Stage primaryStage) {
		try {
			BorderPane root = new BorderPane();
			Scene scene = new Scene(root,400,400);
			scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
			primaryStage.setScene(scene);
			primaryStage.show();
		} catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		launch(args);
	}
}
</pre>
<br />
まずは何も考えずに実行(<img src="//krr.blog.shinobi.jp/File/a.png" alt="" />)すると、ウィンドウが表示される。<br />
<img src="//krr.blog.shinobi.jp/File/04d38e71.png" alt="" /> <br />
<br />
<hr /><span style="font-size: xx-small;">改訂履歴</span><br />
<span style="font-size: xx-small;">・2021年11月25日　一部改訂。不要なプラグインを削除</span>]]></content:encoded>
    <dc:subject>JavaFX入門</dc:subject>
    <dc:date>2021-11-07T20:05:26+09:00</dc:date>
    <dc:creator>Da@</dc:creator>
    <dc:publisher>NINJA BLOG</dc:publisher>
    <dc:rights>Da@</dc:rights>
  </item>
  <item rdf:about="http://krr.blog.shinobi.jp/java_deeplearning/java%20deeplearning4j%20%E5%8D%98%E8%AA%9E%E3%81%AE%E3%83%99%E3%82%AF%E3%83%88">
    <link>http://krr.blog.shinobi.jp/java_deeplearning/java%20deeplearning4j%20%E5%8D%98%E8%AA%9E%E3%81%AE%E3%83%99%E3%82%AF%E3%83%88</link>
    <title>Java DeepLearning4j 単語のベクトル化(Word2Vec)</title>
    <description>日本語から英語への機械翻訳やIMEにおける変換予測など、人の言葉を機械で処理する学術分野は自然言語処理(NLP:Natual Language Processing)と呼ばれている。Deep LearningはNLPの分野においても応用可能であり、RNN(回帰型ニューラルネットワーク:Recuren...</description>
    <content:encoded><![CDATA[日本語から英語への機械翻訳やIMEにおける変換予測など、人の言葉を機械で処理する学術分野は自然言語処理(NLP:Natual Language Processing)と呼ばれている。Deep LearningはNLPの分野においても応用可能であり、RNN(回帰型ニューラルネットワーク:Recurent Nural Network)を利用して英仏の機械翻訳するという試みではよい結果を残している(<a href="#ref1" title="">*1</a>)。<br />
<br />
これらの場合、RNNへの入力データは翻訳文章そのものではなく、文章内の単語をベクトル化(Word2Vec)した「word embeding」の配列を利用する。この「word embeding」は単なる単語ではなく、単語の意味やどのような文脈で利用される単語かという情報を持つことができる。近年の自然言語処理分野では重要な技術の一つである。もちろん、Deep Learningで機械翻訳などのNLPを行う際にも、このWord2Vecの技術は重要である。<br />
<br />
というわけで、今回はWord2Vecの概要とDeepLearning4jで利用する方法について確認する。ちなみにWord2Vec自体はDeep Learningの一手法というわけではない。<br />
<br />

<div style="border: 1px black solid; padding: 10px; padding-left: 40px;"><b>TOPIC</b><ol style="padding-left: 20px;">
<li><a href="#単語をベクトル化する(Word2Vec)とは？" title="">単語をベクトル化する(Word2Vec)とは？</a></li>
<li><a href="#Word2Vecの技術的な概要" title="">Word2Vecの技術的な概要</a></li>
<li><a href="#DeepLearning4jでWord2Vecを利用する" title="">DeepLearning4jでWord2Vecを利用する</a></li>
<li><a href="#サンプルプログラム１(word embedingの作成)" title="">サンプルプログラム１(word embedingの作成)</a></li>
<li><a href="#サンプルプログラム２(word embedingの加算・減算)" title="">サンプルプログラム２(word embedingの加算・減算)</a></li>
<li><a href="#サンプルプログラム３(word embedingの可視化)" title="">サンプルプログラム３(word embedingの可視化)</a></li>
</ol></div>
<hr />
<h3><a name="単語をベクトル化する(Word2Vec)とは？"></a>■　単語をベクトル化する(Word2Vec)とは？</h3>
　Word2VecはTomas Mikolovらのチーム(Google社)が2013年に発表した単語を高次元のベクトル(word embeding)に変換する手法である(<a href="#ref2" title="">*2</a>,<a href="#ref3" title="">*3</a>,<a href="#ref4" title="">*4</a>)。Word2VecではNNLM(Nural Network Language Model)と呼ばれる考え方を利用しており、ニューラルネットワークを利用して単語&rarr;word embedingの変換を計算する。<br />
<br />
　単語をword embedingに変換して嬉しいことは、word embedingには単語で表せない意味合い等の情報を持たせることができることである。自然言語の単語で例えて考えると、「リオ(リオデジャネイロ)」という単語と「レオ(ライオン)」という単語は1文字しか違わない。だからといって意味が近い単語とは言うことができないように、単語を表す文字列には意味の情報が乏しいため、コンピュータが単語だけから2つの単語の意味が似ているかどうかを理解することは難しい。<br />
<br />

<div style="text-align: center;"><img src="//krr.blog.shinobi.jp/File/298a787d.png" alt="" style="border: 1px black solid; display: block; margin-left: auto; margin-right: auto;" /> <span style="font-size: xx-small;">図：単語空間とword embeding空間のイメージ</span></div>
<br />
　ここで新しい考え方として、2次元のベクトル空間を作成し意味合いが近い単語の距離が短くなるように単語をマッピングすることを考える。例えば「リオ」は(10,10)、「レオ」は(-10,10)のように単語を2次元座標に対応付ける。意味合いが近い言葉の距離が短くなるようにしたいため、「レオ」に意味合いが近い別の単語「ライオン」を考えると、「レオ」の近くの座標(例えば(-11,10))にマッピングされることになる。このように単語がマッピングできると、コンピュータは単語の意味の近さを2次元ベクトル空間内の距離の近さとして計算できるため、「レオ」は「リオ」よりも「ライオン」に近いと認識できるようになるのである。このマッピングされた点をword embedingと呼ぶ。word embedingはベクトルとして表現され、実際には2次元よりももっと高次元のベクトルとして表現される。<br />
<br />
　単語をマッピングしたこのベクトル空間ではword embedingの距離が意味の差に等しくなるようで、word embedingに加算・減算が定義できるようになっている。過去の論文では「king - man + woman」という計算を行うと「queen」という単語が計算されたという結果も報告されている(<a href="#ref3" title="">*3</a>)。これは「king」と「man」の距離の差がそのまま「統治者」とか「王」という意味の差になり、「woman」にこの距離を足し合わせた「king - man + woman」の計算結果は「女性の統治者」とか「女性の王」という意味の「queen」となったためと考えられる。<br />
<br />

<div><img src="//krr.blog.shinobi.jp/File/d0a24cda.png" alt="" style="border: 1px black solid; display: block; margin-left: auto; margin-right: auto;" /></div>
<div style="text-align: center;"><span style="font-size: xx-small;">図：word embeding「king」「man」「woman」「queen」の位置関係のイメージ</span></div>
<br />
　上記のように単語に意味などの情報が付加したword embedingが機械翻訳などで利用しやすい情報であることは何となく想像できると思われる。しかし、word embedingを人の手で計算することはとても難しいため、Word2Vecでは単語&rarr;word embedingの変換をニューラルネットワークを利用して計算しているのである。<br />
<hr />
<h3><a name="Word2Vecの技術的な概要"></a>■　Word2Vecの技術的な概要</h3>
　Word2Vecによって単語&rarr;word embedingの変換を計算するしくみはあまり難しくはない。計算には以下の3層のニューラルネットワークを利用する。プロジェクション層、出力層はともに全結合層で構成するため、全体としては多層パーセプトロンそのものである。<br />
<br />
　このニューラルネットワークでは、プロジェクション層で単語をword embedingに変換(出力)し、word embedingを出力層で評価、変換結果が芳しくない場合には誤差逆伝搬法により変換パラメータを更新するという処理を行う。<br />
<br />

<div><img src="//krr.blog.shinobi.jp/File/f0d8bac8.png" alt="" style="border: 1px black solid; display: block; margin-left: auto; margin-right: auto;" /></div>
<div style="text-align: center;"><span style="font-size: xx-small;">図：Word2Vecにおいて、word embedingへの変換行列を計算するために利用するニューラルネットワーク</span></div>
<br />

<h4>入力層</h4>
　入力では単語を表す1-hot-vectorを入力とする。1-hot-vectorとは、特定の要素が1それ以外が0のベクトルのことである。Word2Vecの場合、語彙数（利用可能な単語の総数）\(V\)個の要素を持つベクトルで、単語を表すインデックスの要素だけが1という値を持つ。例えば語彙が「I」「am」「Tom」「.」の4つで、「I」=0、「am」=1、「Tom」=2、「.」=3のように単語にインデックスを対応付けた場合には、「am」を表す1-hot-vectorは\((0,1,0,0)\)のように表現される。<br />
<br />

<h4>プロジェクション層</h4>
　プロジェクション層では入力ベクトルをword embedingに変換する。プロジェクション層には活性化関数を設定しない。いま、入力ベクトルを\(\mathbf{x}\)、プロジェクション層のニューロン数を\(N\)、各ニューロンの重みを集めた重みベクトルを\(\mathbf{W}\)とすると、プロジェクション層の各ニューロンの出力\(\mathbf{h}\)は以下の式で表される。<br />
\begin{align*}<br />
\mathbf{h} &amp; = \mathbf{x} \mathbf{W} \\<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&amp; = (x_1,x_2,\cdots,x_V)<br />
\begin{bmatrix}<br />
w_{11} &amp; w_{12} &amp; \cdots&nbsp;&amp;&nbsp;w_{1N} \\<br />
\vdots &nbsp;&amp; \vdots&nbsp;&amp;&nbsp;\vdots&nbsp;&amp;&nbsp;\vdots &nbsp;\\<br />
w_{V1} &amp; w_{V2}&nbsp;&amp;&nbsp;\cdots&nbsp;&amp;&nbsp;w_{VN} \\<br />
\end{bmatrix}<br />
\end{align*}<br />
　一見難しい計算に見えるが、入力ベクトル\(\mathbf{x}\)が1-hot-vectorであることを考慮すると、入力が\(i\)番目の単語の場合\(i\)行目以外の値はすべて0をかけることが分かる。結果、計算は以下のようにプロジェクション層の重み行列\(\mathbf{W}\)の\(i\)行目を抜き出す処理に等しくなる。<br />
\begin{align*}<br />
\mathbf{h} &amp; = \mathbf{x} \mathbf{W} \\<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&amp; =&nbsp;(0,\cdots,1,\cdots,0)<br />
\begin{bmatrix}<br />
w_{11} &amp; w_{12} &amp; \cdots&nbsp;&amp;&nbsp;w_{1N} \\<br />
\vdots &nbsp;&amp; \vdots&nbsp;&amp;&nbsp;\vdots&nbsp;&amp;&nbsp;\vdots &nbsp;\\<br />
w_{V1} &amp; w_{V2}&nbsp;&amp;&nbsp;\cdots&nbsp;&amp;&nbsp;w_{VN} \\<br />
\end{bmatrix}\\<br />
&amp; = (w_{i1},w_{i2},\cdots,w_{iN})<br />
\end{align*}<br />
　Word2Vecでは重みベクトル\(\mathbf{W}\)を単語&rarr;word embedingの変換行列とみなし、プロジェクション層の出力をベクトル化した\(\mathbf{h}\)がword embedingとなる。<br />
<br />

<h4>出力層</h4>
　出力層では、プロジェクション層の重みベクトル\(W\)が適切な単語&rarr;word embeding変換を学習するように評価する必要がある。ここでいう評価とは、単語の意味が似ている2つの入力ベクトル\(\mathbf{x_1},\mathbf{x_2}\)に対して、プロジェクション層の出力ベクトル\(\mathbf{h_1},\mathbf{h_2}\)が似たような値をとっているかを測定することである。<br />
<br />
　では、『単語の意味が似ている』とはどういうことだろうか。定義の方法はいくつかあると思うが、Word2Vecにおいては『単語の意味合いが近い場合、その単語の前後には同じような単語が出現する』という仮説を立てている。例えば「I love penguins」「You love penguins」という二つの文があった場合、「I」と「You」は「love penguin」が続くことから似ていると判断する。実際「I」と「You」は人を指す代名詞であるため、この仮説はある程度は正しいということができると思われる。<br />
<br />
　いま教師データとして\(n\)個の単語で構成された文章\(\mathbf{s}=(\mathbf{x_1},\mathbf{x_2},\cdots,\mathbf{x_n})\)(※\(\mathbf{s}\)の各要素は単語を表す1-hot-vector)を考える。ニューラルネットワークは\(j\)番目の単語\(\mathbf{x_j}\)が入力となった場合、出力が\(\mathbf{x_{j+1}}\)や\(\mathbf{x_{j-2}}\)といった周辺の単語となるよう他クラス分類を解くように構成すればよい。このように学習すると、単語の意味が似ている2つの入力ベクトル\(\mathbf{x_1},\mathbf{x_2}\)に対して出力(次に出力される単語)が同じ値となるため、その途中の計算結果であるプロジェクション層の出力ベクトル\(\mathbf{h_1},\mathbf{h_2}\)も似たような値をとることが期待できる。実際には入力\(\mathbf{x_j}\)に対して、入力単語の前後\(R\)個(2～5個程度)の単語\(\mathbf{x_{j-R}}\)～\(\mathbf{x_{j+R}}\)が出力になるように学習する。<br />
<br />
　上記のような理由から、出力層ではニューロンの数を単語総数\(V\)、活性化関数にソフトマックス関数を利用して、入力単語の周辺で出現する単語を出力するよう構成する。学習方法としては、誤差逆伝搬法で誤差関数は確率的勾配降下法、学習世代は3、学習率0.025を設定するのがよいなど、設定の詳細は元論文(<a href="#ref3" title="" style="font-size: 1em;">*3</a>)参照のこと。ちなみに、日本語では<a href="#ref5" title="" style="font-size: 1em;">*5</a>の方が数式計算を詳しく解説されている。<br />
<br />

<h4>その他</h4>
　出力層で『単語の意味合いが近い場合、その単語の前後には同じような単語が出現する』という仮説を置いたが、この仮説を実装する方法には以下の2種類が存在する。すなわち、『文脈から現在の単語を推測する(CBOW))』か『現在の単語から文脈を推測する(skip-gram)』かである。2者は入力と出力の関係が逆転しただけの関係であるが、精度的にはSkip-gramのほうがよいという結果が出ている。<br />
<br />

<div><img src="//krr.blog.shinobi.jp/File/6aa990c4.png" alt="" style="border: 1px black solid; display: block; margin-left: auto; margin-right: auto;" /></div>
<ol>
<li>continuous bag-of-words (CBOW) &hellip;前後の単語（文脈）から、現在の単語を推測</li>
<li>continuous skip-gram&hellip;現在の単語から、前後の単語（文脈）を推測。</li>
</ol><br />
　また、前述したようにWord2VecはNNLMという考えに基づいている。Word2Vecの素晴らしいところは、他のNNLMで存在する隠れ層をなくし、プロジェクション層をすべての入力で共有したことによって、学習による計算量を劇的に少なくすることに成功したことである。利用する単語数（ボキャブラリ）\(V\)は、場合によっては億単位にまで上ることがある。これに対して、従来のNNLM手法では計算量が\(O(V)\)であったが、Word2Vecでは\(O(\log_2V)\)に削減されている。Skip-gramについては計算量の少なさだけでなく、word embedingの精度まで上回ったと報告されている。<br />
<br />
<hr />
<h3><a name="DeepLearning4jでWord2Vecを利用する"></a>■　DeepLearning4jでWord2Vecを利用する</h3>
　DeepLearning4jでWord2Vecを利用する際には、以下のクラスを利用する。DeepLearning4jではSkip-Gramが実装されている。利用例はサンプルプログラムを参照のこと。<br />
<br />

<table align="center" border="1" cellspacing="0">
<tbody>
<tr>
<td><strong>クラス</strong></td>
<td><strong>内容</strong></td>
</tr>
<tr>
<td>Word2Vec</td>
<td>Word2Vecを行うメインクラス</td>
</tr>
<tr>
<td>SentenceIterator<br />
DocumentIterator</td>
<td>Word2Vecに入力データを渡すクラス。文章ファイルなどから文章を1つずつ取得する。可能な限りSentenceIteratorを利用するべきとのこと。</td>
</tr>
<tr>
<td>Tokenizer<br />
TokenizerFactory</td>
<td>SenetenceIterator等で取得した文章を単語に分割するクラス。</td>
</tr>
<tr>
<td>VocabCache</td>
<td>単語の数や出現率、単語の連続性などを保持するクラス。<br />
学習後のWord2Vecから取得可能。</td>
</tr>
<tr>
<td>Inverted Index</td>
<td>単語の出現率などを保持。Lucene indexなども自動的に作成する。</td>
</tr>
</tbody>
</table>
<br />
<hr />
<h3><a name="サンプルプログラム１(word embedingの作成)"></a>■　サンプルプログラム１(word embedingの作成)</h3>
　以下にDeeplearning4jでWord2Vecを利用するサンプルプログラムを示す。以下のサンプルはDeeplearning4jのチュートリアルを参考にして作成した。サンプルでは1行ごとに英語の文章が記述されたファイル「raw_sentences.txt」内の単語をword embedingに変換するWord2Vecインスタンスを作成し、「people」と「money」のword embedingの距離や、「day」に似た単語を出力している。<br />
<br />
<strong>◇リソース</strong><br />
dl4j-tutorial(プロジェクトフォルダ)<br />
┣　src/main/java<br />
┃　┗　Word2VecTest1.java<br />
┣　input<br />
┃　┗raw_sentences.txt(<a href="https://github.com/deeplearning4j/dl4j-0.4-examples/blob/master/src/main/resources/raw_sentences.txt" title="" target="_blank">ココ</a>から取得)<br />
┗　output<br />
<br />
<strong>◇サンプルプログラム</strong><br />

<pre class="brush:java" title="Word2VecTest1.java" style="border: 1px gray solid; overflow: auto; overflow-y: hidden;">import java.io.File;
import java.io.IOException;
import java.util.Collection;

import org.deeplearning4j.models.embeddings.loader.WordVectorSerializer;
import org.deeplearning4j.models.word2vec.Word2Vec;
import org.deeplearning4j.text.sentenceiterator.LineSentenceIterator;
import org.deeplearning4j.text.sentenceiterator.SentenceIterator;
import org.deeplearning4j.text.sentenceiterator.SentencePreProcessor;
import org.deeplearning4j.text.tokenization.tokenizer.TokenPreProcess;
import org.deeplearning4j.text.tokenization.tokenizer.preprocessor.EndingPreProcessor;
import org.deeplearning4j.text.tokenization.tokenizerfactory.DefaultTokenizerFactory;
import org.deeplearning4j.text.tokenization.tokenizerfactory.TokenizerFactory;

/**
 * DeepLearning4jでWord2Vecを行うサンプルプログラム
 * @author karura
 */
public class Word2VecTest1
{

    public static void main(String[] args) throws IOException
    {
        // コーパス(文章集)データの読み込み
        // 読み込み時に文字をすべて小文字に変換する
        System.out.println( "Load data..." );
        File                f       = new File( "input/raw_sentences.txt" );
        SentenceIterator    ite     = new LineSentenceIterator( f );
        ite.setPreProcessor( new SentencePreProcessor()
        {
            @Override
            public String preProcess( String sentence ){ return sentence.toLowerCase(); }
        });
        
        // 文章を単語に分解
        // 分解時に単語を小文字に、半角数を"d"に変換する
        System.out.println( "Tokenize data..." );
        final EndingPreProcessor    preProcessor    = new EndingPreProcessor();
        TokenizerFactory            tokenizer       = new DefaultTokenizerFactory();
        tokenizer.setTokenPreProcessor( new TokenPreProcess()
        {
            @Override
            public String preProcess( String token )
            {
                token       = token.toLowerCase();
                String base = preProcessor.preProcess( token );
                base        = base.replaceAll( "\\d" , "d" );
                return base;
            }
        });
        
        // モデル作成
        System.out.println( "Build model..." );
        int     batchSize   = 1000;         // 1回のミニバッチで学習する単語数
        int     iterations  = 3;
        int     layerSize   = 150;
        
        Word2Vec    vec     = new Word2Vec.Builder()
                .batchSize( batchSize )         // ミニバッチのサイズ
                .minWordFrequency( 5 )          // 単語の最低出現回数。ここで指定した回数以下の出現回数の単語は学習から除外される
                .useAdaGrad( false )            // AdaGradを利用するかどうか
                .layerSize( layerSize )         // 単語ベクトルの次元数。
                .iterations( iterations )       // 学習時の反復回数
                .learningRate( 0.025 )          // 学習率
                .minLearningRate( 1e-3 )        // 学習率の最低値
                .negativeSample( 10 )           //
                .iterate( ite )                 // 文章データクラス
                .tokenizerFactory(tokenizer)    // 単語分解クラス
                .build();
        
        // 学習
        System.out.println( "Learning..." );
        vec.fit();
        
        // モデルを保存
        System.out.println( "Save Model..." );
        WordVectorSerializer.writeWordVectors( vec , "output/words.txt" );
        
        // 評価1(二つの単語の類似性)
        // コサイン距離
        System.out.println( "Evaluate model..." );
        String  word1       = "people";
        String  word2       = "money";
        double  similarity  = vec.similarity( word1 , word2 );
        System.out.println( String.format( "The similarity between 「%s」 and 「%s」 is %f" , word1 , word2 , similarity ) );
        
        // 評価2(ある単語に最も意味が近い言葉)
        String  word        = "day";
        int     ranking     = 10;
        Collection&lt;String&gt;  similarTop10    = vec.wordsNearest( word , ranking );
        System.out.println( String.format( "Similar word to 「%s」 is %s" , word , similarTop10 ) );
        
        
    }

}
</pre>
<br />
<strong>◇実行結果</strong><br />

<pre class="brush:xml" title="標準出力" style="overflow: auto; overflow-y: hidden;">Load data...
Tokenize data...
Build model...
03:01:04.530 [main] DEBUG org.nd4j.nativeblas.NativeOps - Number of threads used for linear algebra 1

&hellip;中略&hellip;

Save Model...
03:29:28.457 [main] INFO  o.d.m.e.loader.WordVectorSerializer - Wrote 236 with size of 150
Evaluate model...
The similarity between 「people」 and 「money」 is 0.162286
Similar word to 「day」 is [week, night, year, game, season, percent, dur, time, office, former]</pre>
<pre class="brush:xml" title="output/words.txt" style="border: 1px gray solid; overflow: auto; overflow-y: hidden;">dur 0.03706284239888191 -0.3273228108882904 -0.02901708
been 0.07721598446369171 -0.3042716383934021 -0.1655066&hellip;
year -0.04181159287691116 -0.28206467628479004 -0.20906&hellip;
about -0.3287375867366791 0.03922347351908684 0.0778141&hellip;
your -0.2562347650527954 0.08040153235197067 0.49649453&hellip;
without -0.3843825161457062 -0.43209001421928406 0.1945&hellip;
these 0.359978586435318 -0.2246623933315277 0.170168146&hellip;
music -0.09605858474969864 -0.22566641867160797 -0.4158&hellip;
&hellip;</pre>
<br />
<strong>◇解説</strong><br />
&nbsp;　Word2Vecインスタンスは、SentenceIterator（26行目～33行目で作成）とTokenizerFactory（37行目～50行目で作成）を指定して作成する。インスタンス作成後は、他のニューラルネットワークの場合と同様、fit関数により学習を実施する(73行目)。注意点としては、word embedingをファイルに保存するにはWordVectorSerializer::writeWordVectorsという専用のクラスを利用する必要がある点である(77行目)。<br />
<br />
　学習後はword embedingを利用した計算が可能で、84行目で「people」と「money」という単語のword embedingに対して距離(意味合いの類似度)を計算したり、90行目では「day」という単語との類似度が高いトップ10の単語を取得したりしている。<br />
<br />
<hr />
<h3><a name="サンプルプログラム２(word embedingの加算・減算)"></a>■　サンプルプログラム２(word embedingの加算・減算)</h3>
　以下にDeepLearning4jでword embedingの加算と減算を行うサンプルプログラムを示す。サンプルでは、サンプルプログラム１で作成したword embedingをファイルから読込み、「i + you」という加算や、「companey - money」という減算を行っている。<br />
<br />
<strong>◇リソース</strong><br />
dl4j-tutorial(プロジェクトフォルダ)<br />
┣　src/main/java<br />
┃　┗　Word2VecTest2.java<br />
┣　src/main/java/fastfix<br />
┃　┗　<a href="//krr.blog.shinobi.jp/File/WordVectorSerializerFastFix.java" title="" target="_blank">WordVectorSerializerFastFix.java</a><span style="font-size: xx-small;">（dl4jライブラリ(ver0.4-rc3.10)のバグを応急修正したソース）</span><br />
┗　output<br />
　　┗　words.txt(サンプルプログラム１で作成したファイル)<br />
<br />
<strong>◇サンプルプログラム</strong><br />

<pre class="brush:java" title="Word2VecTest2.java" style="border: 1px gray solid; overflow: auto; overflow-y: hidden;">import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import org.deeplearning4j.models.embeddings.wordvectors.WordVectors;

import fastfix.WordVectorSerializerFastFix;

/**
 * DeepLearning4jでWord2Vecを行うサンプルプログラム
 * @author karura
 */
public class Word2VecTest2
{
    public static void main(String[] args) throws IOException
    {
        // 単語ベクトルの読込
        System.out.println( "Load vectors..." );
        File        f       = new File( "output/words.txt" );
        //WordVectors vec     = WordVectorSerializer.loadTxtVectors( f );           // ライブラリにバグあり
        WordVectors vec     = WordVectorSerializerFastFix.loadTxtVectors( f );
        
        // 利用可能な単語を出力
        Collection&lt;String&gt;  words   = vec.vocab().words();
        System.out.println( "利用可能な単語" );
        for( String word : words ){ System.out.println( " " + word ); }
        
        // 単語の足し算
        System.out.println( "単語の足し算" );
        List&lt;String&gt;    positiveList    = Arrays.asList( "i" , "you" );
        List&lt;String&gt;    negativeList    = new ArrayList&lt;String&gt;();
        Collection&lt;String&gt; nearestList  = vec.wordsNearest( positiveList , negativeList , 10 );
        System.out.println( String.format( "%s = %s" , String.join( " + " , positiveList )
                                                     , nearestList ) );
        
        // 単語の足し算・引き算
        System.out.println( "単語の足し算・引き算" );
        positiveList    = Arrays.asList( "company" );
        negativeList    = Arrays.asList( "money" );
        nearestList     = vec.wordsNearest( positiveList , negativeList , 10 );
        System.out.println( String.format( "%s - %s = %s" , String.join( " + " , positiveList )
                                                          , String.join( " + " , negativeList )
                                                          , nearestList ) );
    }

}</pre>
<strong>◇実行結果</strong><br />

<pre class="brush:xml" title="標準出力" style="border: 1px gray solid; overflow: auto; overflow-y: hidden;">Load vectors...
02:28:00.367 [main] DEBUG org.nd4j.nativeblas.NativeOps - Number of threads used for linear algebra 1
02:28:00.376 [main] DEBUG org.nd4j.nativeblas.NativeOps - Number of threads used for linear algebra 1

&hellip;中略&hellip;

利用可能な単語
 dur
 been
 year
 about
 your
 without
 these

&hellip;中略&hellip;

単語の足し算
i + you = [you, i, we, they, west, former, him, she, $, he]
単語の足し算・引き算
company - money = [company, group, director, man, very, team, general, university, fami, program]</pre>
<br />
<strong>◇解説</strong><br />
　事前にファイル出力したword embedingを読込には、WordVectorSerializer::loadTxtVectors関数を利用する(23行目)。(dl4jライブラリver0.4-rc3.10では、この関数内にバグがある模様で常に例外が発生する。このため、今回は応急修正したソース「WordVectorSerializerFastFix.java」を利用している。)<br />
<br />
　word embedingの加算・減算にはWordVectors::wordsNearest関数を利用する(32行目～46行目)。第一引数に加算する単語、第二引数に減算する単語、第三引数に計算結果の候補を可能性の高いものから何番目まで取得するかを指定する。<br />
<br />
<hr />
<h3><a name="サンプルプログラム３(word embedingの可視化)"></a>■　サンプルプログラム３(word embedingの可視化)</h3>
　以下にDeepLearning4jでword embedingを可視化するサンプルプログラムを示す。word embedingは高次元ベクトルであるためそのままでは可視化できないが、サンプルではt-SNE(<a href="#ref8" title="">*8</a>)という手法によって描画可能な次元(2次元)にベクトルをマッピングして描画している。t-SNEは高次元ベクトルの描画を目的とした次元圧縮手法で、Laurens van der Maaten(Tilburg Univer sity(蘭))が2008年に提唱した。t-SNEでは高次元ベクトルのデータ構造(クラスター等)を残しつつ低次元ベクトルにマッピングできるため、データ構造が把握しやすいという特性を持つ。<br />
<br />
　サンプルでは、サンプルプログラム１で作成したword embedingを、t-SNEによって2次元空間にマッピングしている。マッピングした内容はタブ区切りCSVとして出力されるため、excelやgnuplot等のツールによってプロットの作成が容易となっている。<br />
<br />
<strong>◇リソース</strong><br />
dl4j-tutorial(プロジェクトフォルダ)<br />
┣　src/main/java<br />
┃　┗　Word2VecTest3.java<br />
┣　src/main/java/fastfix<br />
┃　┗　<a href="//krr.blog.shinobi.jp/File/WordVectorSerializerFastFix.java" title="" target="_blank">WordVectorSerializerFastFix.java</a><span style="font-size: xx-small;">（dl4jライブラリ(ver0.4-rc3.10)のバグを応急修正したソース）</span><br />
┗　output<br />
　　┗　words.txt(サンプルプログラム１で作成したファイル)<br />
<br />
<strong>◇サンプルプログラム</strong><br />

<pre class="brush:java" title="Word2VecTest3.java" style="border: 1px gray solid; overflow: auto; overflow-y: hidden;">import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;

import org.deeplearning4j.models.embeddings.inmemory.InMemoryLookupTable;
import org.deeplearning4j.models.embeddings.wordvectors.WordVectors;
import org.deeplearning4j.plot.BarnesHutTsne;
import org.nd4j.linalg.api.ndarray.INDArray;

import fastfix.WordVectorSerializerFastFix;

/**
 * DeepLearning4jでWord2Vecを行うサンプルプログラム
 * @author karura
 */
public class Word2VecTest3
{
    public static void main(String[] args) throws IOException
    {
        // 単語ベクトルの読込
        System.out.println( "Load vectors..." );
        File        f       = new File( "output/words.txt" );
        //WordVectors vec     = WordVectorSerializer.loadTxtVectors( f );           // ライブラリにバグあり
        WordVectors vec     = WordVectorSerializerFastFix.loadTxtVectors( f );
        
        // 利用可能な単語を取得
        Collection&lt;String&gt;  words   = vec.vocab().words();
        
        // 単語とベクトル表現を出力
        System.out.println( "単語とそのベクトル表現" );
        Iterator&lt;String&gt;    ite     = words.iterator();
        while( ite.hasNext() )
        {
            // 単語と単語ベクトルを取得
            String              word    = ite.next();
            INDArray            vector  = vec.getWordVectorMatrix( word );
            
            // 標準出力に出力
            System.out.println( String.format( "%s : %s : %s " , word
                                                               , vec.wordsNearest( vector , 5 )
                                                               , vector ) );
        }
        
        // t-SNEを利用して、2次元の表に単語をプロット
        System.out.println( "ploting..." );
        BarnesHutTsne tsne = new BarnesHutTsne.Builder()
                .theta(0.5)
                .learningRate(500)
                .setMaxIter(1000)
                .build();
        InMemoryLookupTable table   = (InMemoryLookupTable) vec.lookupTable();
        List&lt;String&gt;        list    = new ArrayList&lt;String&gt;( vec.vocab().words() );
        tsne.plot( table.getSyn0() , 2 , list , "t-SNE-plot.csv" );
    }

}</pre>
<br />
<strong>◇実行結果</strong><br />

<pre class="brush:xml" title="t-SNE-plot.csv" style="border: 1px gray solid; overflow: auto; overflow-y: hidden;">18483.431640625	-1694.8656005859	dur	
-7451.63671875	-6846.0444335938	been	
3224.25390625	-14590.3095703125	year	
542.904296875	-3857.8513183594	about	
-7926.5673828125	10782.16796875	your	
&hellip;
</pre>
<strong>◇解説</strong><br />
　t-SNEを利用するにはBarnesHutTsneクラスを利用する。BarnesHutTsne::plot関数にプロットするword embedingと圧縮後の次元数、word embedingに対応する単語、ファイル出力先をしていすることで、タブ区切りcsvファイルが出力される。出力されたcsvファイルを元に作成したプロットが以下である。<br />
<br />

<div><a target="_blank" href="//krr.blog.shinobi.jp/File/a0a553e3.png" title=""><img src="//krr.blog.shinobi.jp/Img/1467135622/" alt="" style="display: block; margin-left: auto; margin-right: auto;" /></a></div>
<div style="text-align: center;"><span style="font-size: xx-small;"> 図：「t-SNE-plot.csv」をgnuplotを用いてプロットした結果</span></div>
<br />
　学習する語彙が少ないためか今回のプロットでは明確なクラスタリングは確認できないが、プロット左部で「university」と「group」が近かったりとクラスタのようなものが見られる個所もあることが分かる。<br />
<br />
<hr />
<h3>■　参照</h3>
<ol>
<li><a name="ref1" href="http://arxiv.org/pdf/1406.1078.pdf" title="" target="_blank">論文「Learning Phrase Representations using RNN Encoder&ndash;Decoder for Statistical Machine Translation」</a></li>
<li><a name="ref2" href="https://en.wikipedia.org/wiki/Word2vec" title="" target="_blank">Wikipedia 「Word2vec」</a></li>
<li><a name="ref3" href="http://arxiv.org/pdf/1301.3781v3.pdf" title="" target="_blank">論文「Efficient Estimation of Word Representations in Vector Space」</a></li>
<li><a name="ref4" href="http://papers.nips.cc/paper/5021-distributed-representations-of-words-and-phrases-and-their-compositionality.pdf" title="" target="_blank">論文「Distributed Representations of Words and Phrases and their Compositionality」</a></li>
<li><a name="ref5" href="http://tkengo.github.io/blog/2016/05/09/understand-how-to-learn-word2vec/" title="" target="_blank">けんごのお屋敷 「Word2Vec のニューラルネットワーク学習過程を理解する」</a></li>
<li><a name="ref6" href="http://mt-class.org/jhu/slides/lecture-nn-lm.pdf" title="" target="_blank">Johns Hopkins University 「Neural Networks Language Models」</a></li>
<li><a name="ref7" href="https://en.wikipedia.org/wiki/N-gram" title="" target="_blank">Wikipedia 「N-gram」</a></li>
<li><a name="ref8" href="https://lvdmaaten.github.io/publications/papers/JMLR_2008.pdf" title="" target="_blank">論文 「Visualizing Data using t-SNE」</a></li>
</ol>]]></content:encoded>
    <dc:subject>Javaで機械学習 - Deeplearning4j入門</dc:subject>
    <dc:date>2016-06-29T03:35:06+09:00</dc:date>
    <dc:creator>Da@</dc:creator>
    <dc:publisher>NINJA BLOG</dc:publisher>
    <dc:rights>Da@</dc:rights>
  </item>
  <item rdf:about="http://krr.blog.shinobi.jp/java_deeplearning/java%20deeplearning4j%20%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF%E3%81%AE%E8%A8%AD%E5%AE%9A">
    <link>http://krr.blog.shinobi.jp/java_deeplearning/java%20deeplearning4j%20%E3%83%91%E3%83%A9%E3%83%A1%E3%83%BC%E3%82%BF%E3%81%AE%E8%A8%AD%E5%AE%9A</link>
    <title>Java DeepLearning4j パラメータの設定</title>
    <description>Deeplearning 4jではニューラルネットワークの各パラメータ／ハイパーパラメータを関数で設定できる。ニューラルネットワーク全体に関わるパラメータは NeuralNetConfiguration.Builderクラスに対して設定し、各層に関わるパラメータはLayer.Builderクラスに対...</description>
    <content:encoded><![CDATA[Deeplearning 4jではニューラルネットワークの各パラメータ／ハイパーパラメータを関数で設定できる。ニューラルネットワーク全体に関わるパラメータは NeuralNetConfiguration.Builderクラスに対して設定し、各層に関わるパラメータはLayer.Builderクラスに対し て設定する。以下にDeeplearning 4jにおける主な設定項目を示す。すべてのパラメータ一覧はJavaDoc(<a href="#ref1" title="">*1</a>,<a href="#ref2" title="">*2</a>,<a href="#ref3" title="">*3</a>)やリファレンス(<a href="#ref4" title="">*4</a>)を参照のこと。<br />
<br />

<h4>ニューラルネットワーク全体（NeuralNetConfiguration.Builder）の設定項目</h4>
　NeuralNetConfiguration.Builderで設定する主な項目は以下の通りである。<br />
<br />

<table align="center" border="1" cellspacing="0">
<tbody>
<tr>
<td><strong>設定項目</strong></td>
<td><strong>内容</strong></td>
</tr>
<tr>
<td>seed関数</td>
<td>ランダム値の生成に利用するシード値を指定</td>
</tr>
<tr>
<td>iterations関数</td>
<td>1回のMultiLayerNetwork::fit関数呼出で学習する回数を指定</td>
</tr>
<tr>
<td>learningRate関数</td>
<td>学習率\(\eta\)を指定。デフォルトは0.1</td>
</tr>
<tr>
<td>miniBatch関数</td>
<td>ミニバッチ学習をするかどうかを指定</td>
</tr>
<tr>
<td>regularization関数</td>
<td>正規化を行うかどうかを指定</td>
</tr>
<tr>
<td>l1 , l2 関数</td>
<td>L1正規化、L2正規化を指定。過学習を防ぐために利用</td>
</tr>
<tr>
<td>weightInit関数</td>
<td>重みパラメータの初期化方法を指定。デフォルトはWeightInit.VI<br />

<table border="1" cellspacing="0">
<tbody>
<tr>
<td><strong>設定値</strong></td>
<td><strong>内容</strong></td>
</tr>
<tr>
<td>DISTRIBUTION</td>
<td>入力次元に基づいた分布</td>
</tr>
<tr>
<td>NORMALIZED</td>
<td>正規分布</td>
</tr>
<tr>
<td>ZERO</td>
<td>0</td>
</tr>
<tr>
<td>SIZE</td>
<td>入力の次元(shape)の最大値～最小値の一様分布(と思われる)</td>
</tr>
<tr>
<td>UNIFORM</td>
<td>入力の最大値～最小値の一様分布(と思われる)</td>
</tr>
<tr>
<td>VI</td>
<td>分散が正規化された値</td>
</tr>
<tr>
<td>RELU</td>
<td>平均=0、分散=\(\frac{2}{nIn}\)の正規分布</td>
</tr>
<tr>
<td>XAVIER</td>
<td>平均=0、分散=\(\frac{1}{nOut+nIn}\)の正規分布</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td>optimizationAlgo関数</td>
<td>学習アルゴリズムを指定。デフォルトはOptimizationAlgorithm.CONJUGATE_GRADIENT<br />

<table border="1" cellspacing="0">
<tbody>
<tr>
<td><strong>設定値</strong></td>
<td><strong>内容</strong></td>
</tr>
<tr>
<td>CONJUGATE_GRADIENT</td>
<td>共役勾配法</td>
</tr>
<tr>
<td>HESSIAN_FREE</td>
<td>Hessian-Free法</td>
</tr>
<tr>
<td>LBFGS</td>
<td>L-BFGS法</td>
</tr>
<tr>
<td>LINE_GRADIENT_DESCENT</td>
<td>直線探索を用いた確率的勾配降下法</td>
</tr>
<tr>
<td>STOCHASTIC_GRADIENT_DESCENT</td>
<td>確率的勾配降下法</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td>updater関数</td>
<td>学習アルゴリズムでパラメータ学習する際の拡張方法を指定。(<a href="#ref8" title="">*8</a>)<br />

<table border="1" cellspacing="0">
<tbody>
<tr>
<td><strong>設定値</strong></td>
<td><strong>内容</strong></td>
</tr>
<tr>
<td>ADADELTA</td>
<td>勾配を利用したアップデータ及び学習アルゴリズム。SGD(ネットワーク内のパラメータ更新に同じ学習率を利用)とは異なり、パラメータ毎に学習率を変化させる。<br />
論文「ADADELTA: AN ADAPTIVE LEARNING RATE METHOD」</td>
</tr>
<tr>
<td>ADAGRAD</td>
<td>勾配の2乗をモニタリングすることにより、パラメータ毎に学習率を最適化する。SGDの代わりに利用でき、スパースなデータに有効。<br />
論文「Adaptive Subgradient Methods for Online Learning and Stochastic Optimization」</td>
</tr>
<tr>
<td>ADAM</td>
<td>rmspropに似たアップデータ。勾配の移動平均を利用する<br />
論文「Adam: A Method for Stochastic Optimization」</td>
</tr>
<tr>
<td>CUSTOM</td>
<td>自身で定義</td>
</tr>
<tr>
<td>NESTEROVS</td>
<td>論文「Advances in Optimizing Recurrent Networks」</td>
</tr>
<tr>
<td>NONE</td>
<td>なし</td>
</tr>
<tr>
<td>RMSPROP</td>
<td>論文「Generating Sequences With Recurrent Neural Networks」</td>
</tr>
<tr>
<td>SGD</td>
<td>確率的勾配降下法</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td>momentu関数</td>
<td>慣性項を指定。学習を早くするために利用する</td>
</tr>
<tr>
<td>list関数</td>
<td>この関数呼び出し後にニューラルネットワークの層を宣言する</td>
</tr>
<tr>
<td>layer関数</td>
<td>ニューラルネットワークの層の構成情報を追加する</td>
</tr>
</tbody>
</table>
<br />

<h4>ニューラルネットワークの層（Layer.Builder）の設定項目</h4>
　Layer.Builderで設定する主な項目は以下のとおりである。<br />
<br />

<table align="center" border="1" cellspacing="0">
<tbody>
<tr>
<td><strong>設定項目</strong></td>
<td><strong>内容</strong></td>
</tr>
<tr>
<td>nln関数</td>
<td>入力データ数を指定。</td>
</tr>
<tr>
<td>nOut関数</td>
<td>出力データ数を指定。</td>
</tr>
<tr>
<td>activation関数</td>
<td>活性化関数を指定。デフォルトは「"sigmoid"」<br />

<table border="1" cellspacing="0">
<tbody>
<tr>
<td><strong>設定値</strong></td>
<td><strong>内容</strong></td>
</tr>
<tr>
<td>"identity"</td>
<td>恒等変換\(f(x)=x\)</td>
</tr>
<tr>
<td>"relu"&nbsp;</td>
<td>ランプ関数</td>
</tr>
<tr>
<td>"tanh"</td>
<td>ハイパボリック・タンジェント</td>
</tr>
<tr>
<td>"sigmoid"</td>
<td>シグモイド関数</td>
</tr>
<tr>
<td>"softmax"</td>
<td>ソフトマックス関数</td>
</tr>
<tr>
<td>"hardtanh"</td>
<td>hard tanh</td>
</tr>
<tr>
<td>"leakyrelu"</td>
<td>論文「Rectifier Nonlinearities Improve Neural Network Acoustic Models 」</td>
</tr>
<tr>
<td>"maxout"</td>
<td>maxout関数</td>
</tr>
<tr>
<td>"softsign"</td>
<td>ソフトサイン関数</td>
</tr>
<tr>
<td>"softplus"</td>
<td>ソフトプラス関数</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr>
<td>LossFunction<br />
(Layer.Builderの引数)</td>
<td>誤差関数を指定。<br />

<table border="1" cellspacing="0">
<tbody>
<tr>
<td><strong>設定値</strong></td>
<td><strong>内容</strong></td>
</tr>
<tr>
<td>MSE</td>
<td>誤差の平方和(線形回帰)</td>
</tr>
<tr>
<td>EXPLL</td>
<td>対数尤度関数(ポアソン回帰)</td>
</tr>
<tr>
<td>XENT</td>
<td>交差エントロピー(二項分類)</td>
</tr>
<tr>
<td>MCXENT</td>
<td>交差エントロピー(多クラス分類)</td>
</tr>
<tr>
<td>NEGATIVELOGLIKELIHOOD</td>
<td>負の対数尤度関数</td>
</tr>
<tr>
<td>RECONSTRUCTION_CROSSENTROPY</td>
<td>Reconstruction 交差エントロピー</td>
</tr>
<tr>
<td>RMSE_XENT</td>
<td>RMSE 交差エントロピー</td>
</tr>
<tr>
<td>SQUARED_LOSS</td>
<td>二乗損失</td>
</tr>
<tr>
<td>CUSTOM</td>
<td>自身で誤差関数を定義</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
<h3></h3>
<hr />
<h3>■　参照</h3>
<ol style="font-size: 14px; font-weight: normal;">
<li><a name="ref5" href="http://deeplearning4j.org/doc/" title="" target="_blank">JavaDoc DeepLearning4j</a></li>
<li><a name="ref6" href="http://nd4j.org/doc/" title="" target="_blank">JavaDoc ND4J</a></li>
<li><a name="ref7" href="http://deeplearning4j.org/doc/org/deeplearning4j/nn/conf/layers/Layer.Builder.html" title="" target="_blank">JavaDoc 「Class Layer.Builder<t extends="" layer="" builder="" t="">&gt;」</t></a></li>
<li><a name="ref8" href="http://deeplearning4j.org/neuralnet-configuration.html" title="" target="_blank">DeepLearning4j 公式 「NeuralNetConfiguration Class」</a></li>
<li><a name="ref9" href="http://deeplearning4j.org/doc/org/deeplearning4j/nn/weights/WeightInit.html" title="" target="_blank">JavaDoc 「Enum WeightInit」</a></li>
<li><a name="ref10" href="http://deeplearning4j.org/doc/org/deeplearning4j/nn/api/OptimizationAlgorithm.html" title="" target="_blank">JavaDoc 「Enum OptimizationAlgorithm」</a></li>
<li><a name="ref11" href="http://deeplearning4j.org/doc/org/deeplearning4j/nn/conf/Updater.html" title="" target="_blank">JavaDoc 「Enum Updater」</a></li>
<li><a name="ref12" href="http://deeplearning4j.org/updater" title="" target="_blank">DeepLearning4j 公式 「Deeplearning4j Updaters Explained」</a></li>
<li><a name="ref13" href="http://ttlg.hateblo.jp/entry/2016/02/11/181322" title="" target="_blank">俺とプログラミング 「CNNの学習に最高の性能を示す最適化手法はどれか」</a></li>
<li><a name="ref14" href="http://nd4j.org/doc/org/nd4j/linalg/lossfunctions/LossFunctions.LossFunction.html" title="" target="_blank">JavaDoc 「Enum LossFunctions.LossFunction」</a></li>
</ol>]]></content:encoded>
    <dc:subject>Javaで機械学習 - Deeplearning4j入門</dc:subject>
    <dc:date>2016-06-11T02:10:51+09:00</dc:date>
    <dc:creator>Da@</dc:creator>
    <dc:publisher>NINJA BLOG</dc:publisher>
    <dc:rights>Da@</dc:rights>
  </item>
  <item rdf:about="http://krr.blog.shinobi.jp/java_deeplearning/java%20deeplearngin4j%20%E3%83%8B%E3%83%A5%E3%83%BC%E3%83%A9%E3%83%AB%E3%83%8D">
    <link>http://krr.blog.shinobi.jp/java_deeplearning/java%20deeplearngin4j%20%E3%83%8B%E3%83%A5%E3%83%BC%E3%83%A9%E3%83%AB%E3%83%8D</link>
    <title>Java DeepLearngin4j ニューラルネットワークの基本</title>
    <description>Deep Learningの定義は「4層以上のニューラルネットワーク」と定義されている。今回はDeepLearning4jの利用方法を確認する前に、ニューラルネットワークの概念について確認する。


TOPIC
ニューラルネットワークとは？
学習(誤差逆伝搬法)
階層型ニューラルネットワーク
非階層...</description>
    <content:encoded><![CDATA[Deep Learningの定義は「4層以上のニューラルネットワーク」と定義されている。今回はDeepLearning4jの利用方法を確認する前に、ニューラルネットワークの概念について確認する。<br />
<br />

<div style="border: 1px black solid; padding: 10px; padding-left: 40px;"><b>TOPIC</b><ol style="padding-left: 20px;">
<li><a href="#ニューラルネットワークとは？" title="">ニューラルネットワークとは？</a></li>
<li><a href="#学習(誤差逆伝搬法)" title="">学習(誤差逆伝搬法)</a></li>
<li><a href="#階層型ニューラルネットワーク" title="">階層型ニューラルネットワーク</a></li>
<li><a href="#非階層型ニューラルネットワーク" title="">非階層型ニューラルネットワーク</a></li>
</ol></div>
<hr />
<h3><a name="ニューラルネットワークとは？"></a>■　ニューラルネットワークとは？</h3>
　ニューラルネットワークとは、ニューロンが相互接続したネットワークのことを指す。ニューロンとは神経細胞のことを指し、人の体は相互接続されたニューロンのネットワークによって光を感じたり運動信号を伝達したりする。ニューロンを図示すると以下のようなものである。ニューロンの機能は、他のニューロンからの刺激を樹状突起を通じて受け取り、細胞核で処理したのち、軸索を通じて他のニューロンを刺激するというものである。<br />
<br />
<img src="//krr.blog.shinobi.jp/File/9abfc845.png" alt="" style="border: 1px black solid; display: block; margin-left: auto; margin-right: auto;" />
<div style="text-align: center;"><span style="font-size: xx-small;">図：神経細胞のイメージ</span></div>
<br />
　ニューロン1つはとてもシンプルな構造だが、ネットワークを構築すると複雑な処理も可能にすることが知られている。このことに数学の世界が注目し、ニューロンのようなシンプルな構造を持つ関数のネットワークで複雑な関数を近似することができないかと考案されたのがニューラルネットワークという数理モデルである。数学の世界のニューロンは以下のような構造を持つ。<br />
<br />
<img src="//krr.blog.shinobi.jp/File/aaa5485c.png" style="border: 1px solid black; display: block; margin-left: auto; margin-right: auto;" alt="" />
<div style="text-align: center;"><span style="font-size: xx-small;">図：ニューロンのイメージ</span></div>
\begin{align}<br />
f(x) &amp; = f( \sum_{i=0}^N v_ix_i - \theta )\\<br />
&nbsp; &nbsp; &nbsp; &amp; = f( v_0x_0 + v_1x_1 + \cdots + v_Nx_N - \theta )\\<br />
\end{align}<br />
　つまり、入力は\(N\)個の他のニューロンからそれぞれ入力\(x_i\)に重み\(v_i\)を乗じた値の合計で、出力は入力から閾値\(\theta\)を引いて活性化関数\(f(x)\)で処理した値となる。このニューロンンをネットワーク上につなげたものをニューラルネットワークと呼ぶ。ニューラルネットワークを大きく分けるとニューロンを階層上に整列させる階層型と、そうでない非階層型に分かれる。非階層型としては内部にループ構造を持つものなどがあげられる。<br />
<br />
　一見、使い方がよく分からないニューロンではあるが、ニューロンを複数個つなげると利用方法が見えてくる。例えば以下のようにニューロンを構成すると、活性化関数\(f(x)=x\)という1次式だけを利用して、x&gt;0の範囲で\(f(x)=x^2\)が近似できる。複雑な関数をシンプルな関数で表現できるという利点は、コンピュータでの計算を前提とすると大きな利点である。<br />
<br />
<img src="//krr.blog.shinobi.jp/File/3392fd3a.png" style="border: 1px solid black; display: block; margin-left: auto; margin-right: auto;" alt="" />
<div style="text-align: center;"><span style="font-size: xx-small;">図：関数\(f(x)=x\)を用いて、ニューラルネットワーク上で関数\(f(x)=x^2\)を近似するイメージ</span></div>
<br />
　ニューラルネットワークでは上記のような簡単な式以外についても、活性化関数の選択やパラメータ\(v_i\)(重み)や\(\theta\)(閾値)の設定次第で、どんな関数も近似できるようになる。しかし、逆に問題となるのが式を近似する際にこのパラメータをどうやって求めるかということである。ニューラルネットワークにおいては、このパラメータの決定を次の節で紹介する学習により行っている。<br />
<br />
<hr />
<h3><a name="学習(誤差逆伝搬法)"></a>■　学習(誤差逆伝搬法)</h3>
　機械学習という言葉が示すように、ニューラルネットワークにおいて学習という概念が最も大切な概念である。ただし、概念自体はそんなに難しいことはない。<br />
<br />
　例えば、中学で勉強した幾何学の世界を考えてみる。以下の問題でパラメータa,bを求めよと言われれば、求められるのではないだろうか。<br />
<br />

<div style="border: 1px black solid; padding: 10px;">【問題】<br />
　関数「\( y=ax+b\)」が点\((0,3)\)および点\((4,0)\)を通るとき、\(a\)と\(b\)の値を答えなさい。<br />
<br />
【答え】<br />
　「\( 3=a \times 0+b \)」から\(b = 3\)、「\( 0=a&nbsp;\times&nbsp;4+3 \) 」から\( a = -\frac{3}{4} \)</div>
<br />
　ニューラルネットワークにおいての学習は上記のようにパラメータ計算を行うことに相当する。上記の内容を一般的な言葉で置き換えると、入力\(x\)に対する出力\(y\)が分かっているのであれば、計算式中に現れるパラメータ（=適切な関数）が計算可能であるということである。上記の幾何学の問題を機械学習の観点で見てみると、入力に対応するデータの組「\((x,y)=(0,3),(4,0)\)」は教師データと呼ばれ、線形関数「\(y=ax + b\)」のパラメータ\(a\),\(b\)を計算することが学習にあたる。<br />
<br />
　もちろん、上記例のように関数が1次関数であれば瞬時に正確なパラメータが計算できるが、まったく未知の関数に対しては別の方法でパラメータを決定していく。それが、誤差関数の導入である。ここからは高校・大学レベルの数学知識が必要となる。<br />
<br />
　例えば、ある時点のニューラルネットワークの出力を\(o\)実際の正解値を\(t\)、誤差関数を\(E=(t-o)^2\)とすると、誤差関数は出力と正解値の差が小さくなるにつれて値が小さくなる関数となる。特に\(o=t\)の場合に誤差が最小となる。視覚的に誤差関数を記述すると以下のようになる。<br />
<br />

<div><img src="//krr.blog.shinobi.jp/File/9554b5c5.png" style="border: 1px solid black; display: block; margin-left: auto; margin-right: auto;" alt="" /></div>
<div style="text-align: center;"><span style="font-size: xx-small;">図：誤差関数Eのイメージ</span></div>
<br />
　上記では、誤差関数Eをoの関数\(E(o)\)として表現したが、oはニューラルネットワークのパラメータである\(v_i\)や\(\theta\)によって決まる値であるため、誤差関数は\(E(v)\)や\(E(\theta)\)として記述することも可能である。ニューラルネットワークにおいては、この誤差関数を最小化するような\(v\)や\(\theta\)の値を求めることができれば、出力\(0\)と正解値\(t\)の差が小さい近似式を設定することができる。<br />
<br />
　この\(E(v)\)の最小値を求める方法として、ある時点での傾き(勾配)を調べるという方法がよく利用される。例えば\(E(v)=v^2\)という関数の最小値を求めることを考える。<br />
<br />

<div><img src="//krr.blog.shinobi.jp/File/7ecf778e.png" alt="" style="border: 1px solid black; display: block; margin-left: auto; margin-right: auto;" /></div>
<div style="text-align: center;"><span style="font-size: xx-small;">図：\(E(v)=v^2\)のイメージ</span></div>
<br />
　いま適当な値\(v\)を決めて、\(v\)時点での\(E(v)\)の傾きを計算すると右下がりの傾き(負の傾き)であるとする。線の傾きはその点における微分値として計算することができる。線の傾きから、\(E(v)\)の最小値は\(v\)がより大きい値をとる場合であることが分かる。このため、次はvを少し大きくして\(v=v+\triangle v\)の地点に移動して、再度\(E(v)\)の傾きを計算する。この繰り返しを続けていけば、いつかは傾きが0=\(E(v)\)が最小になる\(v\)の値に収束する。この方法を数学的には再急降下法と呼ぶ。関数のある地点の傾きは関数の微分値に等しいことから、再急降下法では\(\triangle v= - \eta \frac{\partial E(v)}{\partial v} \)(\(\eta\)は定数)として無限に計算を繰り返す。<br />
<br />
　ニューラルネットワークにおいては、再急降下法のように勾配を利用して誤差関数\(E\)を最小化するようなパラメータ\(v\)や\(\theta\)を見つけることで式の近似を行っている。微分値を計算していくと、あるニューロンのパラメータ微分値(誤差情報)を計算する際には、その出力先のニューロンのパラメータ微分値が必要となるため、計算は出力側のニューロンから順に行われることになる。この動作が誤差情報が出力の流れとは逆に伝搬していくように見えることから、勾配を利用した学習の方法は誤差逆伝搬法と呼ばれる。<br />
<br />

<div style="text-align: center;"><img src="//krr.blog.shinobi.jp/File/827783a7.png" alt="" style="border: 1px black solid; display: block; margin-left: auto; margin-right: auto;" /><span style="font-size: xx-small;">図：誤差逆伝搬のイメージ</span></div>
<br />
<hr />
<h3><a name="階層型ニューラルネットワーク"></a>■　階層型ニューラルネットワーク</h3>
　階層型ニューラルネットワークとは、ニューロンが階層上に重なったニューラルネットワークのことを指す。階層型ニューラルネットワークに属するものとしては、多層パーセプトロンや畳み込みニューラルネットワーク等が存在する。ネットワークのイメージとしては以下のようなものである。<br />
<br />

<div><a target="_blank" href="//krr.blog.shinobi.jp/File/0db21988.png" title=""><img src="//krr.blog.shinobi.jp/Img/1459808825/" alt="" style="border: 1px black solid; display: block; margin-left: auto; margin-right: auto;" /></a></div>
<div style="text-align: center;">&nbsp;<span style="font-size: xx-small;">図：階層型ニューラルネットワークのイメージ</span></div>
<br />
　近年注目を集めているDeep Learningは、この階層型ニューラルネットワークで入力層や出力層を合わせて全4階層以上の階層を持つものを利用した機械学習を指す。昔は処理が多すぎて見向きもされなかったが、近年のマシンスペックの向上に伴いその性能が見直されたモデルでもある。<br />
<br />
<hr />
<h3><a name="非階層型ニューラルネットワーク"></a>■　非階層型ニューラルネットワーク</h3>
　非階層型ニューラルネットワークとは、ネットワーク内部にループを持つなど階層上になっていないニューラルネットワークのことを指す。非階層型ニューラルネットワークに属するものとしては、ボルツマンマシンなどが存在する。<br />
<br />

<div><a target="_blank" href="//krr.blog.shinobi.jp/File/5767c5fb.png" title=""><img src="//krr.blog.shinobi.jp/Img/1465576988/" alt="" style="border: 1px black solid; display: block; margin-left: auto; margin-right: auto;" /></a></div>
<div style="text-align: center;"><span style="font-size: xx-small;">図：非階層型ニューラルネットワークのイメージ</span></div>
<br />
　非階層型ニューラルネットワークの利用方法はイメージしにくいと思われるが、ボルマンマシンではニューロンを接続する線に適切な重みを設定することで、巡回セールスマン問題を解いたりグラフや図を記憶したりすることができる。<br />
<br />
<hr />
<h3>■　参照</h3>
<ol>
<li><a href="http://www-ailab.elcom.nitech.ac.jp/lecture/neuro/menu.html" title="">名古屋工業大学 岩田研究室 「ニューラルネットワーク入門」</a></li>
</ol>]]></content:encoded>
    <dc:subject>Javaで機械学習 - Deeplearning4j入門</dc:subject>
    <dc:date>2016-06-11T01:50:02+09:00</dc:date>
    <dc:creator>Da@</dc:creator>
    <dc:publisher>NINJA BLOG</dc:publisher>
    <dc:rights>Da@</dc:rights>
  </item>
  <item rdf:about="http://krr.blog.shinobi.jp/java_deeplearning/java%20deeplearning4j%20%E5%A4%9A%E5%B1%A4%E3%83%91%E3%83%BC%E3%82%BB%E3%83%97%E3%83%88%E3%83%AD%E3%83%B3%E3%81%AE%E6%A7%8B%E7%AF%89">
    <link>http://krr.blog.shinobi.jp/java_deeplearning/java%20deeplearning4j%20%E5%A4%9A%E5%B1%A4%E3%83%91%E3%83%BC%E3%82%BB%E3%83%97%E3%83%88%E3%83%AD%E3%83%B3%E3%81%AE%E6%A7%8B%E7%AF%89</link>
    <title>Java DeepLearning4j 多層パーセプトロンの構築</title>
    <description>今回は階層型ニューラルネットワークの基本となる多層パーセプトロンをDeepLearning 4jで構築する方法について見ていく。


TOPIC
多層パーセプトロンとは？
サンプルプログラム


■　多層パーセプトロンとは？
　多層パーセプトロンはニューロンを階層状にならべた階層型ニューラルネットワ...</description>
    <content:encoded><![CDATA[<div>今回は階層型ニューラルネットワークの基本となる多層パーセプトロンをDeepLearning 4jで構築する方法について見ていく。</div>
<br />

<div style="border: 1px black solid; padding: 10px; padding-left: 40px;"><b>TOPIC</b><ol style="padding-left: 20px;">
<li><a href="#多層パーセプトロンとは？" title="">多層パーセプトロンとは？</a></li>
<li><a href="#サンプルプログラム" title="">サンプルプログラム</a></li>
</ol></div>
<hr />
<h3><a name="多層パーセプトロンとは？"></a>■　多層パーセプトロンとは？</h3>
　多層パーセプトロンはニューロンを階層状にならべた階層型ニューラルネットワークの基本となっている。多層パーセプトロンは中間層がすべて全結合層(前層の全ニューロンと接続する層)で構成されたニューラルネットワークであり、非線形な関数を近似することができる。多層パーセプトロンの構成は以下のようなイメージとなる。<br />
<br />
<a target="_blank" href="//krr.blog.shinobi.jp/File/0db21988.png" title=""><img src="//krr.blog.shinobi.jp/Img/1459808825/" alt="" style="border: 1px black solid; display: block; margin-left: auto; margin-right: auto;" /></a>
<div style="text-align: center;"><span style="font-size: xx-small; text-align: center;">図：多層パーセプトロンのイメージ</span></div>
<br />

<div style="text-align: center;"><span style="font-size: xx-small;">表：多層パーセプトロンで利用する層の種類</span></div>
<table align="center" border="1" cellspacing="0">
<tbody>
<tr>
<td width="100"><strong>層の名称</strong></td>
<td><strong>Deeplearning4j内のクラス</strong></td>
<td><strong>内容</strong></td>
</tr>
<tr>
<td>全結合層<br />
(略：FC,RELU)</td>
<td>DenseLayer</td>
<td>前層のニューロンに対し全結合を行う。</td>
</tr>
<tr>
<td>出力層<br />
(略：OUTPUT)</td>
<td>OutputLayer</td>
<td>全結合層と同様の構造を持つ。DeepLearing4jでニューラルネットワークを構成する場合、必ず含めないといけない層。</td>
</tr>
</tbody>
</table>
<a target="_blank" href="//krr.blog.shinobi.jp/File/0db21988.png" title=""><br />
</a>　多層パーセプトロンの特徴は非線形関数を近似できるため画像認識などの高度な処理も行える点にある。しかし、ニューロン数が多くなるに従い計算量が膨大な数になってしまうという欠点があるため、多層パーセプトロンがそのまま実用される場合は少ない。ただし、他のニューラルネットワーク内で利用されたり、階層型ニューラルネットワークの基本的な挙動を確認するため、理解しておいたほうがよいニューラルネットワークである。<br />
<br />

<h4>全結合層</h4>
　全結合層内の\(i\)番目のニューロンは以下の図のような動作を行う。すなわち、前層の\(j\)番目のニューロン出力\(x_j\)に対して別々の重み\(v_{ij}\)を乗じたものの総和をとり(ネット値)、その総和から閾値\(\theta\)(バイアスとも呼ぶ)を引いた値を活性化関数と呼ばれる関数\(f(x)\)で処理した結果を出力値\(h_i\)としている。<br />
<br />
　学習フェーズで重み\(v_{ij}\)と閾値\(\theta\)を変更することにより、任意の式の近似式を得ることができる。<br />
<br />

<div style="border: 1px black solid; padding: 20px;"><img src="//krr.blog.shinobi.jp/File/f9a34257.png" alt="" style="display: block; margin-left: auto; margin-right: auto;" />
<table border="0" align="center">
<tbody>
<tr>
<td>\begin{align}<br />
&nbsp; h_i &amp; = f( \sum_{k=0}^n v_{ik}x_k - \theta ) \\<br />
&nbsp; &nbsp; &nbsp; &nbsp; &amp; = f( v_{i1}x_1 + v_{i2}x_2 + \cdots + v_{in}x_n - \theta )&nbsp;<br />
\end{align}</td>
<td></td>
</tr>
</tbody>
</table>
<table border="1" cellspacing="0" align="center">
<tbody>
<tr>
<td><strong>変数</strong></td>
<td><strong>内容</strong></td>
</tr>
<tr>
<td><span style="font-size: xx-small;">\(n\)</span></td>
<td>入力値の個数。各層毎に異なる</td>
</tr>
<tr>
<td><span style="font-size: xx-small;">\(x_i\)</span></td>
<td>i番目の入力値(教師データ)</td>
</tr>
<tr>
<td>\(v_{ij}\)</td>
<td>各層内のi番目ニューロンで、入力jにかける加重パラメータ（結合荷重）</td>
</tr>
<tr></tr>
<tr>
<td>\(h_i\)</td>
<td>中間層のi番目ニューロンの出力値。（次の層の入力値にもなる）</td>
</tr>
<tr>
<td>\(f(x)\)</td>
<td>活性化関数(シグモイド関数が一般的に利用される)<br />
\begin{align}<br />
&nbsp; f(x) &amp; = \frac{1}{1+e^{-x}}<br />
\end{align}</td>
</tr>
<tr>
<td>\(\theta\)</td>
<td>閾値</td>
</tr>
</tbody>
</table>
</div>
<div style="text-align: center;"><span style="font-size: xx-small;">図：多層パーセプトロンを構成するニューロンの数式</span></div>
<br />
<hr />
<h3><a name="サンプルプログラム"></a>■　サンプルプログラム</h3>
　以下にDeepLearning4jで多層パーセプトロンを構成するサンプルプログラムを示す。サンプルではXOR計算を行う3層の多層パーセプトロンを構成し、4つの学習データを用いて2000回の学習(誤差逆伝搬法)を行っている。活性化関数はシグモイド関数を、誤差関数は誤差の平方和(\(\sum (t_i - o_i)^2\))を利用している。<br />
<br />
<strong>◇サンプルプログラム</strong><br />

<pre class="brush:java" title="MultiPerceptron.java" style="border: 1px gray solid; overflow: auto; overflow-y: hidden;"><code style="display: block; overflow-x: auto;">import org.deeplearning4j.nn.api.OptimizationAlgorithm;
import org.deeplearning4j.nn.conf.MultiLayerConfiguration;
import org.deeplearning4j.nn.conf.NeuralNetConfiguration;
import org.deeplearning4j.nn.conf.Updater;
import org.deeplearning4j.nn.conf.layers.DenseLayer;
import org.deeplearning4j.nn.conf.layers.OutputLayer;
import org.deeplearning4j.nn.multilayer.MultiLayerNetwork;
import org.deeplearning4j.nn.weights.WeightInit;
import org.deeplearning4j.optimize.listeners.ScoreIterationListener;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.dataset.DataSet;
import org.nd4j.linalg.factory.Nd4j;
import org.nd4j.linalg.lossfunctions.LossFunctions;

/**
 * XOR計算を行う多層パーセプトロン
 * @author karura
 */
public class MultiPerceptron
{
    // メイン関数
    public static void main(String[] args) throws Exception
    {
        // 変数定義
        int seed        = 123;          // 乱数シード
        int iterations  = 2000;         // 学習の試行回数
        int inputNum    = 2;            // 入力数
        int middleNum   = 10;           // 隠れ層のニューロン数
        int outputNum   = 1;            // 出力数
        INDArray    tIn     = Nd4j.create( new float[]{ 1 , 1 ,             // 入力1
                                                        1 , 0 ,             // 入力2
                                                        0 , 1 ,             // 入力3
                                                        0 , 0 },            // 入力4
                                           new int[]{ 4 , 2 } );            // サイズ
        INDArray    tOut    = Nd4j.create( new float[]{ 0 , 1 , 1 , 0} ,    // 出力1～4
                                           new int[]{ 4 , 1 } );            // サイズ
        DataSet     train   = new DataSet( tIn , tOut );                    // 入出力を対応付けたデータセット
        System.out.println( train );
        
        // ニューラルネットワークを定義
        MultiLayerConfiguration.Builder builder = new NeuralNetConfiguration.Builder()
                .seed(seed)
                .iterations(iterations)
                .learningRate(0.01)
                .weightInit(WeightInit.SIZE)
                .optimizationAlgo(OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT)
                .updater( Updater.NONE )
                .list()
                .layer(0, new DenseLayer.Builder()
                        .nIn(inputNum)
                        .nOut(middleNum)
                        .activation("sigmoid").build())
                .layer(1, new OutputLayer.Builder( LossFunctions.LossFunction.MSE )
                        .nIn(middleNum)
                        .nOut(outputNum)
                        .activation("sigmoid")
                        .build())
                .backprop(true).pretrain(false);
        
        // ニューラルネットワークを作成
        MultiLayerConfiguration conf        = builder.build();
        MultiLayerNetwork       perceptron  = new MultiLayerNetwork(conf);
        perceptron.init();
        
        // 確認用のリスナーを追加
        perceptron.setListeners( new ScoreIterationListener(1) );
        
        // 学習(fit)
        perceptron.fit( train );
        
        // パーセプトロンの使用
        for( int i=0 ; i&lt;train.numExamples() ; i++ )
        {
            // i個目のサンプルについて、
            INDArray    input  = train.get(i).getFeatureMatrix();
            INDArray    answer = train.get(i).getLabels();
            INDArray    output = perceptron.output( input , false );
            System.out.println( "result" + i );
            System.out.println( " input  : " + input );
            System.out.println( " output : " + output );
            System.out.println( " answer : " + answer );
            System.out.flush();
            
        }
        
    }
}</code></pre>
<strong>◇実行結果</strong><br />

<pre class="brush:xml" title="標準出力の内容" style="border: 1px gray solid; overflow: auto; overflow-y: hidden;"><code style="display: block; overflow-x: auto;">20:43:12.444 [main] DEBUG org.nd4j.nativeblas.NativeOps - Number of threads used for linear algebra 32
20:43:12.476 [main] WARN  org.nd4j.jita.conf.CudaEnvironment - Please note, CudaEnvironment is already initialized. Configuration changes won't have effect

&hellip;中略&hellip;

===========INPUT===================
[[1.00, 1.00],
 [1.00, 0.00],
 [0.00, 1.00],
 [0.00, 0.00]]
=================OUTPUT==================
[0.00, 1.00, 1.00, 0.00]

&hellip;中略&hellip;

20:43:41.441 [main] INFO  o.d.o.l.ScoreIterationListener - Score at iteration 1999 is 0.0024183732457458973
result0
 input  : [1.00, 1.00]
 output : 0.09
 answer : 0.00
result1
 input  : [1.00, 0.00]
 output : 0.93
 answer : 1.00
result2
 input  : [0.00, 1.00]
 output : 0.92
 answer : 1.00
result3
 input  : [0.00, 0.00]
 output : 0.04
 answer : 0.00</code></pre>
<strong>◇解説</strong><br />
　学習用データの準備は30行目～38行目で行っており、XORの計算の入力と出力値を作成している。1つ目の学習データを見てみると入力(1,1)に対して、出力0を設定している。標準出力を見てみると、入力のi番目データをXORした結果を出力のi番目データとなっていることが確認できる。<br />
<br />
　多層パーセプトロンの構成は40行目～63行目で行っている。注意点としては重みの初期化に定数「WeightInit.Size」を指定していることであり、他の初期化方法では学習がうまくいかない。これはシグモイド関数を利用していることに起因すると思われる。シグモイド関数ではある範囲の入力値(例えば-2&lt;x&lt;2)を0～1の値に変換するが、この範囲外(例えばx&lt;-2,2&lt;x)の値は常に0か1になってしまう。このため範囲外では勾配値が常に0となり、勾配を利用した学習方法はうまく機能しないという特性がある。WeightInit.Sizeの場合にのみうまく学習できるのは、シグモイド関数で学習可能な入力値となるように、重みが初期化されるためと考えられる。実際、WeightInit.Size以外の初期化方法では値が-1～1程度の値に初期化されるが、WeightInit.Sizeでは0～2(入力配列の長さ)に初期化されることはデバッグすれば確認できる。<br />
<br />
　学習は69行目で行い、学習後の多層パーセプトロンの利用は72行目～84行目で行っている。多層パーセプトロンの利用では学習用のデータを転用しており、i番目の入力データを取得し(getFreatureMatrix関数)、その出力値とi番目データの正解値(getLabels関数)を標準出力に出力している。結果としては、すべてのXOR計算において誤差が0.1以下に収まっていることが確認できる。<br />
<br />
<hr />
<h3>■　参照</h3>
<ol>
<li><a name="ref3" href="http://www-ailab.elcom.nitech.ac.jp/lecture/neuro/menu.html" title="" target="_blank">ニューラルネットワーク入門</a></li>
</ol>]]></content:encoded>
    <dc:subject>Javaで機械学習 - Deeplearning4j入門</dc:subject>
    <dc:date>2016-06-10T21:05:56+09:00</dc:date>
    <dc:creator>Da@</dc:creator>
    <dc:publisher>NINJA BLOG</dc:publisher>
    <dc:rights>Da@</dc:rights>
  </item>
  <item rdf:about="http://krr.blog.shinobi.jp/java_deeplearning/java%20deeplearning%204j%20gpu%E3%81%AB%E3%82%88%E3%82%8B%E9%AB%98%E9%80%9F%E5%8C%96">
    <link>http://krr.blog.shinobi.jp/java_deeplearning/java%20deeplearning%204j%20gpu%E3%81%AB%E3%82%88%E3%82%8B%E9%AB%98%E9%80%9F%E5%8C%96</link>
    <title>Java DeepLearning4j GPUによる高速化</title>
    <description>今回はDeepLearning 4jでGPUを利用する方法を確認する。DeepLearning 4jでは行列計算をND4Jライブラリで行っているが、GPUによってこの行列計算を高速化することになる。 


TOPIC
GPUの利用方法
性能比較


■　GPUの利用方法
　DeepLearning ...</description>
    <content:encoded><![CDATA[今回はDeepLearning 4jでGPUを利用する方法を確認する。DeepLearning 4jでは行列計算をND4Jライブラリで行っているが、GPUによってこの行列計算を高速化することになる。 <br />
<br />

<div style="border: 1px black solid; padding: 10px; padding-left: 40px;"><b>TOPIC</b><ol style="padding-left: 20px;">
<li><a href="#GPUの利用方法" title="">GPUの利用方法</a></li>
<li><a href="#性能比較" title="">性能比較</a></li>
</ol></div>
<hr />
<h3><a name="GPUの利用方法"></a>■　GPUの利用方法</h3>
　DeepLearning 4jでのGPU利用は、現在のところCUDA(NVIDIA製のグラフィック・カードで利用可能な開発環境)のバージョン5.5以降にしか対応していない。グラフィック・カードを持っていてもCUDAが利用できない場合はGPU利用もできないため、注意が必要である。DeepLearning 4jでGPU利用するには、以下の手順を行う。<br />
<br />
<ol>
<li>CUDAのインストール</li>
<li>POMファイルの編集</li>
</ol><br />
　手順１については<a href="https://developer.nvidia.com/cuda-downloads" title="" target="_blank">CUDAのダウンロードサイト</a>でインストーラをダウンロードし、インストールをする必要がある。インストールは特に難しいことはなく、「次へ」を選択して進んでいけばよい。手順２についてはDeepLearning 4jプロジェクトのPOMファイルに以下の依存性記述を追加するだけでよい。ただし、artifactIdタグは「nd4j-cuda-○○」(○○はインストールしたCUDAのバージョン)という値に変更する必要があり、以下の記述はCUDA 7.5の場合の記述である。<br />

<pre class="brush:xml" title="pom.xmlの記述変更" style="border: 1px gray solid; overflow: auto; overflow-y: hidden;">&lt;dependency&gt;
 &lt;groupId&gt;org.nd4j&lt;/groupId&gt;
 &lt;artifactId&gt;nd4j-cuda-7.5&lt;/artifactId&gt;
 &lt;version&gt;${nd4j.version}&lt;/version&gt;
&lt;/dependency&gt;</pre>
<br />
　特に本サイトの方法で環境を構築した場合(=『<a href="https://github.com/deeplearning4j/dl4j-0.4-examples/blob/master/pom.xml" title="" target="_blank" style="color: #0099dd; line-height: 20px;">dl4j-0.4-examples/pom.xml</a>』を利用して環境構築した場合)、すでにPOMファイル内に上記は記述されており、以下のように「nd4j.backend」タグの設定を修正するだけで計算にGPUが利用されるようになる。<br />
<br />

<pre class="brush:xml" title="pom.xml：修正前" style="border: 1px gray solid; overflow: auto; overflow-y: hidden;">&lt;name&gt;DeepLearning4j Examples&lt;/name&gt;
&lt;description&gt;Examples of training different data sets&lt;/description&gt;
&lt;properties&gt;
    &lt;nd4j.backend&gt;nd4j-native&lt;/nd4j.backend&gt;</pre>
<pre class="brush:xml" title="pom.xml：修正後" style="border: 1px gray solid; overflow: auto; overflow-y: hidden;">&lt;name&gt;DeepLearning4j Examples&lt;/name&gt;
&lt;description&gt;Examples of training different data sets&lt;/description&gt;
&lt;properties&gt;
    &lt;nd4j.backend&gt;nd4j-cuda-7.5&lt;/nd4j.backend&gt;</pre>
<hr />
<h3><a name="性能比較"></a>■　性能比較</h3>
　GPUを利用した場合の性能を計測するため、CPU利用時とGPU利用時の実行速度差を比較する。実行速度の計測には、公式サイトに掲載されている『<a href="https://raw.githubusercontent.com/deeplearning4j/dl4j-0.4-examples/master/src/main/java/org/deeplearning4j/examples/convolution/LenetMnistExample.java" title="" target="_blank">LenetMnistExample</a>』(LeNet：2014年度開催の画像認識コンテストILSVRCでGoogleが利用し、高い認識精度を示したニューラルネットワーク構成）を利用し、1世代分の学習(6万個の学習データで各1回学習)にかかる時間を比較した。結果は以下の通り。<br />
<br />
<strong>◇実行環境</strong>
<table border="1" cellspacing="0">
<tbody>
<tr>
<td width="100"><strong>機能</strong></td>
<td width="200"><strong>内容</strong></td>
</tr>
<tr>
<td>OS</td>
<td>Windows7(64bit)</td>
</tr>
<tr>
<td>CPU</td>
<td>Intel Core2 (1.86GHz)<br />
&hellip;プロセッサ数=2</td>
</tr>
<tr>
<td>GPU</td>
<td>GeForce GTX650<br />
&hellip;プロセッサ数=384</td>
</tr>
<tr>
<td>Java</td>
<td>1.8.0_60</td>
</tr>
<tr>
<td>CUDA</td>
<td>CUDA 7.5</td>
</tr>
</tbody>
</table>
<br />
<strong>◇実行結果</strong><br />

<table border="1" cellspacing="0">
<tbody>
<tr>
<td><strong>CPU/GPU</strong></td>
<td><strong>実行時間</strong></td>
</tr>
<tr>
<td>CPU</td>
<td>820.489秒　(=13分40.489秒)</td>
</tr>
<tr>
<td>GPU</td>
<td>349.991秒　(=05分49.991秒)</td>
</tr>
</tbody>
</table>
<br />
　処理時間は2分の1以下となり、高速化できたことが確認できた。<br />
<hr />
<h3>■　参照</h3>
<ol>
<li><a href="http://nd4j.org/gpu_native_backends.html" title="" target="_blank">ND4J 公式 「JCublas Backend for GPUs」</a></li>
</ol>]]></content:encoded>
    <dc:subject>Javaで機械学習 - Deeplearning4j入門</dc:subject>
    <dc:date>2016-06-09T17:58:40+09:00</dc:date>
    <dc:creator>Da@</dc:creator>
    <dc:publisher>NINJA BLOG</dc:publisher>
    <dc:rights>Da@</dc:rights>
  </item>
  <item rdf:about="http://krr.blog.shinobi.jp/java_deeplearning/deeplearning%204j%20%E7%95%B3%E3%81%BF%E8%BE%BC%E3%81%BF%E3%83%8B%E3%83%A5%E3%83%BC%E3%83%A9%E3%83%AB%E3%83%8D">
    <link>http://krr.blog.shinobi.jp/java_deeplearning/deeplearning%204j%20%E7%95%B3%E3%81%BF%E8%BE%BC%E3%81%BF%E3%83%8B%E3%83%A5%E3%83%BC%E3%83%A9%E3%83%AB%E3%83%8D</link>
    <title>Java DeepLearning4j 畳み込みニューラルネットワークの構築</title>
    <description>今回はディープラーニングの実装の一つとなる畳み込みニューラルネットワークを見ていく。畳み込みニューラルネットワークは主に画像認識で利用される機械学習手法である。


TOPIC
畳み込みニューラルネットワーク(CNN)とは？
畳み込みニューラルネットワーク構成上の注意点
サンプルプログラム


■　...</description>
    <content:encoded><![CDATA[<div>今回はディープラーニングの実装の一つとなる畳み込みニューラルネットワークを見ていく。畳み込みニューラルネットワークは主に画像認識で利用される機械学習手法である。</div>
<br />

<div style="border: 1px black solid; padding: 10px; padding-left: 40px;"><b>TOPIC</b><ol style="padding-left: 20px;">
<li><a href="#畳み込みニューラルネットワーク(CNN)とは？" title="">畳み込みニューラルネットワーク(CNN)とは？</a></li>
<li><a href="#畳み込みニューラルネットワーク構成上の注意点" title="">畳み込みニューラルネットワーク構成上の注意点</a></li>
<li><a href="#サンプルプログラム" title="">サンプルプログラム</a></li>
</ol></div>
<hr />
<h3><a name="畳み込みニューラルネットワーク(CNN)とは？"></a>■　畳み込みニューラルネットワーク(CNN)とは？</h3>
　畳み込みニューラルネットワークとは、層状のニューラルネットワークであり、多層パーセプトロンにおける以下の欠点に対応したニューラルネットワークである。<br />
<br />

<div><a target="_blank" href="//krr.blog.shinobi.jp/File/0db21988.png" title=""><img src="//krr.blog.shinobi.jp/Img/1459808825/" alt="" style="border: 1px black solid; display: block; margin-left: auto; margin-right: auto;" /></a></div>
<div style="text-align: center;"><span style="font-size: xx-small;">図：多層パーセプトロンのイメージ</span></div>
<br />
<ol>
<li>多層パーセプトロンでは入力が1次元であるため、画像のような2次元情報の縦方向のズレに弱い</li>
<li>すべての層のニューロンが全結合(前層のニューロンすべてに対して接続する)ため、入力値の個数が多くなるにつれて計算に必要なパラメータ数が多くなりすぎる</li>
</ol><br />
　１について10x10ピクセルの画像を例に説明する。多層パーセプトロンの入力は1次元であるため10x10の配列は100x1の1次元配列に変換する必要がある。すると画像上の座標(0,0)のピクセル値が縦に1ピクセル移動し(0,1)にずれた場合、1次元配列上では0番目の要素が10番目にずれたことになる。このずれを小さくするため畳み込みニューラルネットワークでは入力画像をreceptive fieldという小さな領域(3x3や5x5の小さな画像)に分割して、各領域にフィルタ処理やプーリングという処理を行うことで縦・横ズレに対する弱さを緩和している。<br />
<br />
　２はメモリ容量の問題やパラメータ更新の計算量の多さに加え、アルゴリズム的にも過学習が起こりやすいという問題がある。この問題に対応するためにニューロンを立体的(width,height,depthの3次元)に並べ、深さが同じニューロンのグループ(depth slice)に関しては同じパラメータ(フィルタ)を利用するという工夫を行っている。<br />
<br />

<h4>畳み込みニューラルネットワークのイメージ</h4>
　畳み込みニューラルネットワークの構成は、多層パーセプトロンの入力前に層を追加したような以下の構造を持つ。畳み込みニューラルネットワークでは層の組み立て方はさまざまであり、代表的な構成は[INPUT - CONV - POOL - CONV - POOL - RELU - OUTPUT]や[INPUT - CONV - RELU - POOL - FC - OUTPUT]のような組み立てである。<br />
<br />

<div style="text-align: center;"><span style="font-size: xx-small;">表：畳み込みニューラルネットワークで利用する層の種類</span></div>
<table align="center" border="1" cellspacing="0">
<tbody>
<tr>
<td width="100"><strong>層の名称</strong></td>
<td><strong>Deeplearning4j内のクラス</strong></td>
<td><strong>内容</strong></td>
</tr>
<tr>
<td>畳み込み層<br />
(略：CONV)</td>
<td>ConvolutionLayer</td>
<td>前層のreceptive fieldに対しフィルター処理(畳み込み処理)を行う</td>
</tr>
<tr>
<td>プーリング層<br />
(略：POOL)</td>
<td>SubsamplingLayer</td>
<td>前層を画像としてとらえ、大きさ(width,height)を縮小する</td>
</tr>
<tr>
<td>全結合層<br />
(略：FC,RELU)</td>
<td>DenseLayer</td>
<td>前層のニューロンに対し全結合を行う。多層パーセプトロンの層と同等の働きをする。出力の次元数は1。</td>
</tr>
<tr>
<td>出力層<br />
(略：OUTPUT)</td>
<td>OutputLayer</td>
<td>全結合層と同様。ただし、活性化関数にソフトマックス関数を利用するなどして、出力の総和が1になるようにするなどの正規化を行う。出力の次元数は1。</td>
</tr>
</tbody>
</table>
<br />

<div><img src="//krr.blog.shinobi.jp/File/494485fc.png" alt="" style="border: 1px black solid; display: block; margin-left: auto; margin-right: auto;" /></div>
<div style="text-align: center;"><span style="font-size: xx-small;">図：畳み込みニューラルネットワークの構成イメージ</span></div>
<br />

<h4>各層の次元(width,height,depth)について</h4>
　畳み込みニューラルネットワークにおいては、各層のニューロンを横一列に並べるのではなく、立体的(width,height,depthの3次元)に並べている。各次元については入力層を例に考えるとわかりやすい。入力層ではwidth,heightが入力画像の幅と高さを表すのに対し、depthはある画素におけるRGB値などのチャンネルを表している。グレースケール画像であればdepth=1であるし、RGB画像であればdepth=3となる。入力層以外の層についても、前層の出力情報を画像としてとらえて処理をしていると考えると分かりやすい。<br />
<br />
　以下では、各層の処理内容について確認していく。<br />
<br />

<h4>畳み込み層(ConvolutionLayer)</h4>
　畳み込みニューラルネットワークのメイン処理を行う層である。以下で入力、出力に分けて説明する。<br />
<br />

<div>１．入力信号<br />
　畳み込み層への入力信号はフィルタ処理とスライド処理を交互に行いながら作成される。<br />
<br />
　フィルタ処理では前層の一部領域(receptive field)の出力に対して2次元のフィルタ(加重マップ)を掛け合わせ、その合計値を計算する。後述するストライドが(1,1)の場合、畳み込み層のニューロンn(x,y)への入力値に対しては、前層の(x,y)～(x+fx,y+fy)の位置にあるニューロンの出力値をreceptive fieldとして設定する。もし、前層のdepthが1より多い場合receptive fieldは3次元となる。フィルタ処理のイメージは以下のとおりである。</div>
<div><img src="//krr.blog.shinobi.jp/File/05acbd74.png" alt="" style="border: 1px black solid; display: block; margin-left: auto; margin-right: auto;" /></div>
<div style="text-align: center;"><span style="font-size: xx-small;">図：3x3のフィルタを用いた場合の畳み込み層の動作イメージ</span></div>
<br />
　上図で行われているフィルター処理を行う計算式は以下のとおりである。ただし、\(in(x,y)\)は畳み込み層のニューロン\((x,y)\)への入力、\(h(x,y,d)\)は前層のニューロン\((x,y,d)\)の出力、\(f(x,y)\)はフィルタの\((x,y)\)の値を表す。<br />
\begin{align*}<br />
in(x,y) &amp; = \sum h(i,j,d)f(i,j)\\<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&amp; = \sum h(i,j,0)f(i,j) +&nbsp;\sum h(i,j,1)f(i,j)\\<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&amp; = ( -2 + 0 + 1 - 8 + 0 - 1 + 2 + 0 - 4 )\\<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&amp; + ( -3 + 0 + 4 - 2 + 0 + 6 - 1 + 0 + 1 )\\<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&amp; = -7<br />
\end{align*}<br />
　フィルタは1つ以上設定することができる。また、フィルタ処理においては前層の末端(最上下段や最左右列)のニューロンの出力値の影響が小さくなってしまう。このため、パディングと呼ばれる出力値0の出力値を仮想的に作成し、末端の更に外側に配置してフィルタ処理を行うことが一般的である。<br />
<br />
　スライド処理はフィルタの位置をずらす処理のことである。ずらす位置をストライドと呼び2次元配列で表される。例えばストライドが(2,2)の場合には1度のスライド処理ではx方向に2ずらし、ストライドが(1,1)の場合には1度のスライド処理でx方向に1ずらす。スライドを繰り返して端まで言った場合には、左に戻りyの値だけ縦方向にずらして同様の処理を行う。スライド処理のイメージは以下のとおりである。<br />
<br />

<div><img src="//krr.blog.shinobi.jp/File/b1268c30.png" alt="" style="border: 1px black solid; display: block; margin-left: auto; margin-right: auto;" /></div>
<div style="text-align: center;"><span style="font-size: xx-small;">図：スライド処理の動作イメージ</span></div>
<br />
　CS231n(<a href="#ref1" title="">*1</a>)では上記で説明したフィルタ処理とスライド処理の動作を動画で確認することができるので、分かりずらい場合にはこちらで確認いただきたい。<br />
<br />
　これら入力信号の処理に関して、画像処理の観点で見てみるとぼかしや輪郭線検知などのフィルタ処理そのものの動作と等しい。このため、畳み込み層では前層で出力された画像に対して、フィルタ処理を行った新たな画像を出力する処理としてみることもできる。<br />
<br />
２．出力信号<br />
　畳み込み層のニューロンの出力値も多層パーセプトロンと同様、活性化関数の出力値となる。<br />
<br />
　また、上記より畳み込み層のニューロンの数\(N\)は、前層のニューロン数とフィルタの数によって定義され以下の式で表される。<br />
<br />
\begin{align*}<br />
N_{width} &nbsp;&amp; = \frac{ In_{width} - F_{width} + 2P }{S_{width}} + 1 \\<br />
N_{height} &amp; = \frac{ In_{height} - F_{height} + 2P }{S_{width}} + 1 \\<br />
N_{depth} &nbsp;&amp; = F_{num} \\<br />
\end{align*}<br />

<table align="center" border="1" cellspacing="0">
<tbody>
<tr>
<td><strong>変数</strong></td>
<td><strong>内容</strong></td>
</tr>
<tr>
<td>\(In\)</td>
<td>前層ニューロンの数</td>
</tr>
<tr>
<td>\(F\)</td>
<td>フィルタのサイズ<br />
\(F_{num}\)はフィルタの数を表す</td>
</tr>
<tr>
<td>\(P\)</td>
<td>パディングのサイズ</td>
</tr>
<tr>
<td>\(S\)</td>
<td>ストライド</td>
</tr>
</tbody>
</table>
<br />
　逆に言うと、これらのパラメータの値が整数にならないような設定は使用できない。そのような場合にはPを適切に設定するなどで対応する必要がある。<br />
<br />
　学習フェーズにおいては多層パーセプトロンと同様の処理でパラメータ更新を行うが、入力重みパラメータの増分\(\triangle w\)はフィルタの値に加算する。フィルタの値はすべてのニューロンで共有されているため、学習後のフィルタ値はすべてのニューロンで計算した入力重みパラメータ\(\triangle&nbsp;w\)が加算されることになる。<br />
<br />
　最後に畳み込み層という名前の由来に関して。畳み込みという言葉は数学で\(\sum f(x)g(x-t)\)という計算のことを指す。畳み込み層の入力処理も、前層の出力\(f(x)\)に対してフィルタ\(g(x-t)\)を乗算し合計しているとみることができるため、この名前が付いたと考えられる。が、利用の際にはあまり覚えておかなくてもよいと思われる。<br />
<br />

<h4>プーリングレイヤー(POOL)</h4>
　プーリングレイヤーは前層の出力値を削減する層である。画像処理でいうところの縮小処理に当たる。最も一般的な縮小方法は、前層のある範囲で最も大きな値をニューロンの出力とする方法である。プーリングレイヤーの動作イメージを以下に示す。<br />
<br />

<div style="text-align: center;"><img src="//krr.blog.shinobi.jp/File/71718184.png" style="border: 1px solid black; display: block; margin-left: auto; margin-right: auto;" alt="" /><span style="font-size: xx-small;">図：プーリング層の動作イメージ </span></div>
　上記ではフィルターサイズ2x2、ストライド(2,2)で処理を行っている。4つの入力に対して1つの出力となるため、ニューロンの出力値を75%節減することになる。画像処理的な目で見ると隣あう4pixelを1pixelに縮小することに相当する。入力と出力を比較すると、widthとheightの数は縮小されるがdepthは等しいままである。<br />
<br />
　縮小処理については昔は平均をとるという手法が主流であったが、現在はでは最大値を利用する方法が主流である。学習(誤差逆伝搬法)を行う際には、最大値を出力したニューロンにだけ誤差を伝搬させるという処理になる。最近のトレンドとして、ニューロン数の削減にはプーリングレイヤーをはさむのではなく、畳み込み層のストライドを大きくする事が好まれているという話もある。<br />
<br />

<h4>全結合層</h4>
　多層パーセプトロンの層と同様の処理を行う層である。すなわち、前層すべてのニューロンの出力値の重み付き合計値を入力として受け取り、活性化関数の出力値を出力するという層である。活性化関数に\(f(x)=max(0,x)\)を利用した全結合層を特にRELU層と呼んでいる模様である。<br />
<br />
<hr />
<h3><a name="畳み込みニューラルネットワーク構成上の注意点"></a>■　畳み込みニューラルネットワーク構成上の注意点</h3>
　以下の注意点はCS231n(<a href="#ref1" title="">*1</a>)にて記述された内容である。<br />
<br />
　1つ目はフィルタサイズについてで、フィルタの大きさは小さいほうが表現力が高いということらしい。また、大きなフィルタを1つ持つより、小さなフィルタを複数持つ持つ方が必要なパラメータ数も小さいため、フィルタサイズは小さくフィルタ数を大きく設定するようにしたほうがいいようである。一般的なフィルタサイズは3x3や5x5で、最初の畳み込み層であればフィルタサイズ7x7でもよい結果が得られる可能性があるとのこと。<br />
<br />
　2つ目は畳み込み層の入力数はできるだけ2の倍数に設定するべきである点である。これは入出力の次元数を考慮してのことと思われる。<br />
<br />
　3つ目はプーリング層の縮小の設定についてで、フィルタサイズ2x2／ストライド=(2,2)か、フィルタサイズ=3x3／ストライド=(2,2)程度にしておくべきとのことである。縮小処理のフィルタサイズにより縦横のずれに対する許容性が生まれるが、一方でフィルタサイズを大きすぎると情報のロスが大きくなりすぎてしまうということのようである。<br />
<br />
　4つ目はパディングは積極的に利用すべきということで、これは末端ニューロンの情報を有効活用するためである。<br />
<br />
<hr />
<h3><a name="サンプルプログラム"></a>■　サンプルプログラム</h3>
　以下にDeeplearning 4jで畳み込みニューラルネットワークを実装するサンプルプログラムを示す。サンプルプログラムはDeeplearning 4jの公式web上のサンプルであり、Mnistデータベースに格納された手書き数字(0～9)で学習し、手書き数字の認識を行う畳み込みニューラルネットワークである。サンプルプログラムの実行時間はマシンスペックにもよるが、2時間程度はかかるものと思われる。<br />
<br />

<h4>プログラム</h4>
<pre class="brush:java" title="LenetMnistExample" style="border: 1px gray solid; overflow: auto; overflow-y: hidden;">package org.deeplearning4j.examples.convolution;

import org.deeplearning4j.datasets.iterator.impl.MnistDataSetIterator;
import org.deeplearning4j.eval.Evaluation;
import org.deeplearning4j.nn.api.OptimizationAlgorithm;
//import org.deeplearning4j.nn.conf.LearningRatePolicy;
import org.deeplearning4j.nn.conf.MultiLayerConfiguration;
import org.deeplearning4j.nn.conf.NeuralNetConfiguration;
import org.deeplearning4j.nn.conf.Updater;
import org.deeplearning4j.nn.conf.layers.ConvolutionLayer;
import org.deeplearning4j.nn.conf.layers.DenseLayer;
import org.deeplearning4j.nn.conf.layers.OutputLayer;
import org.deeplearning4j.nn.conf.layers.SubsamplingLayer;
import org.deeplearning4j.nn.conf.layers.setup.ConvolutionLayerSetup;
import org.deeplearning4j.nn.multilayer.MultiLayerNetwork;
import org.deeplearning4j.nn.weights.WeightInit;
import org.deeplearning4j.optimize.listeners.ScoreIterationListener;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.dataset.DataSet;
import org.nd4j.linalg.dataset.api.iterator.DataSetIterator;
import org.nd4j.linalg.lossfunctions.LossFunctions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Created by agibsonccc on 9/16/15.
 */
public class LenetMnistExample {
    private static final Logger log = LoggerFactory.getLogger(LenetMnistExample.class);

    public static void main(String[] args) throws Exception {
        int nChannels = 1;
        int outputNum = 10;
        int batchSize = 64;
        int nEpochs = 10;
        int iterations = 1;
        int seed = 123;

        log.info("Load data....");
        DataSetIterator mnistTrain = new MnistDataSetIterator(batchSize,true,12345);
        DataSetIterator mnistTest = new MnistDataSetIterator(batchSize,false,12345);

        log.info("Build model....");
        MultiLayerConfiguration.Builder builder = new NeuralNetConfiguration.Builder()
                .seed(seed)
                .iterations(iterations)
                .regularization(true).l2(0.0005)
                .learningRate(0.01)//.biasLearningRate(0.02)
                //.learningRateDecayPolicy(LearningRatePolicy.Inverse).lrPolicyDecayRate(0.001).lrPolicyPower(0.75)
                .weightInit(WeightInit.XAVIER)
                .optimizationAlgo(OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT)
                .updater(Updater.NESTEROVS).momentum(0.9)
                .list()
                .layer(0, new ConvolutionLayer.Builder(5, 5)
                        .nIn(nChannels)
                        .stride(1, 1)
                        .nOut(20)
                        .activation("identity")
                        .build())
                .layer(1, new SubsamplingLayer.Builder(SubsamplingLayer.PoolingType.MAX)
                        .kernelSize(2,2)
                        .stride(2,2)
                        .build())
                .layer(2, new ConvolutionLayer.Builder(5, 5)
                        .nIn(nChannels)
                        .stride(1, 1)
                        .nOut(50)
                        .activation("identity")
                        .build())
                .layer(3, new SubsamplingLayer.Builder(SubsamplingLayer.PoolingType.MAX)
                        .kernelSize(2,2)
                        .stride(2,2)
                        .build())
                .layer(4, new DenseLayer.Builder().activation("relu")
                        .nOut(500).build())
                .layer(5, new OutputLayer.Builder(LossFunctions.LossFunction.NEGATIVELOGLIKELIHOOD)
                        .nOut(outputNum)
                        .activation("softmax")
                        .build())
                .backprop(true).pretrain(false);
        new ConvolutionLayerSetup(builder,28,28,1);

        MultiLayerConfiguration conf = builder.build();
        MultiLayerNetwork model = new MultiLayerNetwork(conf);
        model.init();


        log.info("Train model....");
        model.setListeners(new ScoreIterationListener(1));
        for( int i=0; i&lt;nEpochs; i++ ) {
            model.fit(mnistTrain);
            log.info("*** Completed epoch {} ***", i);

            log.info("Evaluate model....");
            Evaluation eval = new Evaluation(outputNum);
            while(mnistTest.hasNext()){
                DataSet ds = mnistTest.next();
                INDArray output = model.output(ds.getFeatureMatrix(), false);
                eval.eval(ds.getLabels(), output);
            }
            log.info(eval.stats());
            mnistTest.reset();
        }
        log.info("****************Example finished********************");
    }
}</pre>
<h4>実行結果</h4>
<pre class="brush:xml" title="標準出力の内容" style="border: 1px gray solid; overflow: auto; overflow-y: hidden;">19:06:10.904 [main] INFO  LenetMnistExample - Load data....


19:06:16.289 [main] INFO  LenetMnistExample - Build model....
19:06:27.122 [main] DEBUG org.nd4j.nativeblas.NativeOps - Number of threads used for linear algebra 1
19:06:27.122 [main] DEBUG org.nd4j.nativeblas.NativeOps - N

&hellip;中略&hellip;

19:19:51.393 [main] INFO  LenetMnistExample - *** Completed epoch 0 ***
19:19:51.393 [main] INFO  LenetMnistExample - Evaluate model....
19:20:52.961 [main] INFO  LenetMnistExample - 
Examples labeled as 0 classified by model as 0: 971 times
Examples labeled as 0 classified by model as 1: 1 times
Examples labeled as 0 classified by model as 2: 2 times
Examples labeled as 0 classified by model as 6: 4 times
Examples labeled as 0 classified by model as 7: 2 times
Examples labeled as 1 classified by model as 1: 1124 times

&hellip;中略&hellip;

==========================Scores========================================
 Accuracy:  0.979
 Precision: 0.9789
 Recall:    0.9789
 F1 Score:  0.9789
========================================================================
&hellip;略</pre>
<h4>解説</h4>
　32行目～41行目では学習用のMnistデータを取得している。Mnistデータの詳細については<a href="http://krr.blog.shinobi.jp/java_deeplearning/deeplearning4j mnistデータベースの利用" title="" target="_blank">別記事</a>を参照していただきたいが、データの内容については文字が描かれた28x28ピクセルの画像を6万個用意しているとだけ理解していただければよい。<br />
<br />
　43行目～81行目では、畳み込みニューラルネットワークを定義している。45行目～52行目がニューラルネットワーク全体の設定で、層の定義は53行目～79行目となる。このニューラルネットワークを図示すると以下のような構造になっている。<br />
<br />

<div><img src="//krr.blog.shinobi.jp/File/b0b5a720.png" alt="" style="border: 1px black solid; display: block; margin-left: auto; margin-right: auto;" /></div>
<div style="text-align: center;"><span style="font-size: xx-small;">図：定義したニューラルネットワークのイメージ</span></div>
<br />
　入力層については定義に含めないので、0層目として畳み込み層が定義されている(54行目～59行目)。活性化関数は恒等関数、フィルタサイズは5x5、フィルタ数は20、ストライド=(1,1)で設定している。<br />
<br />
　1層目はプーリング層で最大値を取得するマックス・プーリングを利用している。フィルタサイズは2x2、ストライド=(2,2)として設定。2層目・3層目では、畳み込み層とプーリング層をさらにはさみ、4層目で全結合層(RELU)をニューロン数500で定義している。<br />
<br />
　最後に5層目で出力層を定義している。活性化関数はソフトマックス関数、誤差関数は負の対数尤度関数、出力数は10としている。ソフトマックス関数を利用しているためすべての出力値の合計は1となり、出力値=確率としてみることができる。<br />
<br />
　83行目～85行目は上記の定義をもとに、畳み込みニューラルネットワークのインスタンスを定義している。90行目～103行目では学習(MultiLayerNetwork::fit関数)と、出力(MultiLayerNetwork::output関数)、評価(Evaluation::eval関数)をの実行を1世代の処理として、10世代分処理を繰り返している。出力と評価では学習とは別のデータ(mnistTest変数)を利用しており、学習したものだけでなく一般的な手書き数字の認識を行っていることが分かる(108行目～110行目)。<br />
<br />
　実行結果を見ていくと1世代目の結果は、0が描かれた画像を正しく0と認識した回数が971回、1と誤認識した回数が1回、2と誤認識した回数が2回、6と誤認識した回数が4回、7と誤認識した回数が2回と概ね識別に成功している。全体の正解率も98%程度と高い水準で畳み込みニューラルネットワークが構築できていることが確認できる。<br />
<br />
<hr />
<h3>■　参照</h3>
<ol>
<li><a href=" http://cs231n.github.io/convolutional-networks/" title="" target="_blank">CS231n Convolutional Neural Networks for Visual Recognition「Convolutional Neural Networks (CNNs / ConvNets)」</a></li>
<li><a href="http://deeplearning4j.org/convolutionalnets.html" title="" target="_blank">Deeplearning4j 公式 「 Convolutional Networks in Java」</a></li>
</ol>]]></content:encoded>
    <dc:subject>Javaで機械学習 - Deeplearning4j入門</dc:subject>
    <dc:date>2016-06-07T19:27:07+09:00</dc:date>
    <dc:creator>Da@</dc:creator>
    <dc:publisher>NINJA BLOG</dc:publisher>
    <dc:rights>Da@</dc:rights>
  </item>
  <item rdf:about="http://krr.blog.shinobi.jp/java_deeplearning/deeplearning%204j%20%E6%89%8B%E6%9B%B8%E3%81%8D%E6%95%B0%E5%AD%97%E3%81%AE%E8%AD%98%E5%88%A5%E3%82%92%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B">
    <link>http://krr.blog.shinobi.jp/java_deeplearning/deeplearning%204j%20%E6%89%8B%E6%9B%B8%E3%81%8D%E6%95%B0%E5%AD%97%E3%81%AE%E8%AD%98%E5%88%A5%E3%82%92%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B</link>
    <title>Java DeepLearning4j 手書き数字の識別をしてみる</title>
    <description>今回はDeeplearning 4jを利用して画像認識を行う例として手書き文字を識別するプログラムを実装してみる。と言っても画像認識を行うニューラルネットワークの構築に関しては公式サイトのサンプルプログラム(*1)を流用する。

プログラムは2つに分けて作成する。1つ目のプログラムでは画像認識を行う...</description>
    <content:encoded><![CDATA[今回はDeeplearning 4jを利用して画像認識を行う例として手書き文字を識別するプログラムを実装してみる。と言っても画像認識を行うニューラルネットワークの構築に関しては公式サイトのサンプルプログラム(<a href="#ref1" title="">*1</a>)を流用する。<br />
<br />
プログラムは2つに分けて作成する。1つ目のプログラムでは画像認識を行うニューラルネットワークを構築・学習し、構築したニューラルネットワークをファイルに出力する。2つ目のプログラムではユーザによる数字を入力できるGUIを表示し、出力されたファイルをもとに再構築したニューラルネットワークで入力文字を識別する。実際の利用を考えても、このように学習と利用でプログラムを分けることはよくある構成と思われる。<br />
<br />

<div style="border: 1px black solid; padding: 10px; padding-left: 40px;"><b>TOPIC</b><ol style="padding-left: 20px;">
<li><a href="#プログラム１(画像認識ニューラルネットワークの構築・学習)" title="">プログラム１(画像認識ニューラルネットワークの構築・学習)</a></li>
<li><a href="#プログラム２(画像認識GUIプログラムにおけるニューラルネットワークの利用)" title="">プログラム２(画像認識GUIプログラムにおけるニューラルネットワークの利用)</a></li>
</ol></div>
<hr />
<h3><a name="プログラム１(画像認識ニューラルネットワークの構築・学習)"></a>■　プログラム１(画像認識ニューラルネットワークの構築・学習)</h3>
　以下にDeepLearning 4jからMnistデータベースを取得し、手書き数字識別を行うニューラルネットワークを構築し、構築したニューラルネットワークをファイル出力するプログラムを示す。作成するニューラルネットワークの構成は下図のようになる。プログラム完了まで2時間程度はかかる。<br />
<br />

<div><a target="_blank" href="//krr.blog.shinobi.jp/File/b0b5a720.png" title=""><img src="//krr.blog.shinobi.jp/Img/1465201782/" alt="" style="border: 1px black solid; display: block; margin-left: auto; margin-right: auto;" /></a></div>
<div style="text-align: center;"><span style="font-size: xx-small;">図：構築するニューラルネットワークのイメージ</span></div>
<br />

<h4 style="font-size: 14px;">プログラム</h4>
<pre class="brush:java" title="LenetMnistExample.java" style="border: 1px gray solid; overflow: auto; overflow-y: hidden;">import java.io.File;

import org.deeplearning4j.datasets.iterator.impl.MnistDataSetIterator;
import org.deeplearning4j.eval.Evaluation;
import org.deeplearning4j.nn.api.OptimizationAlgorithm;
//import org.deeplearning4j.nn.conf.LearningRatePolicy;
import org.deeplearning4j.nn.conf.MultiLayerConfiguration;
import org.deeplearning4j.nn.conf.NeuralNetConfiguration;
import org.deeplearning4j.nn.conf.Updater;
import org.deeplearning4j.nn.conf.layers.ConvolutionLayer;
import org.deeplearning4j.nn.conf.layers.DenseLayer;
import org.deeplearning4j.nn.conf.layers.OutputLayer;
import org.deeplearning4j.nn.conf.layers.SubsamplingLayer;
import org.deeplearning4j.nn.conf.layers.setup.ConvolutionLayerSetup;
import org.deeplearning4j.nn.multilayer.MultiLayerNetwork;
import org.deeplearning4j.nn.weights.WeightInit;
import org.deeplearning4j.optimize.listeners.ScoreIterationListener;
import org.deeplearning4j.util.ModelSerializer;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.dataset.DataSet;
import org.nd4j.linalg.dataset.api.iterator.DataSetIterator;
import org.nd4j.linalg.lossfunctions.LossFunctions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Created by agibsonccc on 9/16/15.
 * 
 * score    &hellip; 誤差の取得
 * output   &hellip; ニューラルネットの処理結果を取得
 */
public class LenetMnistExample {
    private static final Logger log = LoggerFactory.getLogger(LenetMnistExample.class);

    public static void main(String[] args) throws Exception
    {
        // 変数定義
        int nChannels   = 1;            // 入力画像のチャンネル数
        int outputNum   = 10;           // 出力クラス数(0～9の10クラス)
        int batchSize   = 64;           // バッチ(Size of each patch)
        int nEpochs     = 10;           // 学習世代数
        int iterations  = 1;            // 各学習世代で学習を繰り返す回数
        int seed        = 123;
        
        // データ準備
        log.info("Load data....");
        DataSetIterator mnistTrain  = new MnistDataSetIterator(batchSize,true,12345);   // 学習データ。
        DataSetIterator mnistTest   = new MnistDataSetIterator(batchSize,false,12345);  // テストデータ。
        
        // 畳み込みニューラルネットワークを定義
        log.info("Build model....");
        MultiLayerConfiguration.Builder builder = new NeuralNetConfiguration.Builder()
                .seed(seed)
                .iterations(iterations)
                .regularization(true).l2(0.0005)
                .learningRate(0.01)
                .weightInit(WeightInit.XAVIER)
                .optimizationAlgo(OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT)
                .updater(Updater.NESTEROVS).momentum(0.9)
                .list()
                .layer(0, new ConvolutionLayer.Builder(5, 5)
                        .nIn(nChannels)
                        .stride(1, 1)
                        .nOut(20)
                        .activation("identity")
                        .build())
                .layer(1, new SubsamplingLayer.Builder(SubsamplingLayer.PoolingType.MAX)
                        .kernelSize(2,2)
                        .stride(2,2)
                        .build())
                .layer(2, new ConvolutionLayer.Builder(5, 5)
                        .nIn(nChannels)
                        .stride(1, 1)
                        .nOut(50)
                        .activation("identity")
                        .build())
                .layer(3, new SubsamplingLayer.Builder(SubsamplingLayer.PoolingType.MAX)
                        .kernelSize(2,2)
                        .stride(2,2)
                        .build())
                .layer(4, new DenseLayer.Builder().activation("relu")
                        .nOut(500).build())
                .layer(5, new OutputLayer.Builder(LossFunctions.LossFunction.NEGATIVELOGLIKELIHOOD)
                        .nOut(outputNum)
                        .activation("softmax")
                        .build())
                .backprop(true).pretrain(false);
        new ConvolutionLayerSetup(builder,28,28,1);
        
        // 畳み込みニューラルネットワークを作成
        MultiLayerConfiguration conf    = builder.build();
        MultiLayerNetwork       model   = new MultiLayerNetwork(conf);
        model.init();
        
        // 学習開始
        log.info("Train model....");
        model.setListeners(new ScoreIterationListener(1));
        for( int i=0; i&lt;nEpochs; i++ )
        {
            // 学習の実施(fit)
            model.fit(mnistTrain);
            log.info("*** Completed epoch {} ***", i);

            log.info("Evaluate model....");
            Evaluation eval = new Evaluation(outputNum);
            while(mnistTest.hasNext())
            {
                DataSet     ds      = mnistTest.next();
                INDArray    output  = model.output(ds.getFeatureMatrix(), false);
                eval.eval(ds.getLabels(), output);
            }
            log.info(eval.stats());
            mnistTest.reset();
        }
        log.info("****************Example finished********************");
        
        // ファイル出力
        File    f2   = new File( "output/CNN.fdfsdf" );
        ModelSerializer.writeModel( model , f2 , true );
        
        
    }
}</pre>
<h4 style="font-size: 14px;">実行結果</h4>
プロジェクト・フォルダ<br />
┗　output<br />
　　┗　CNN.fdfsdf<br />

<h4 style="font-size: 14px;">解説</h4>
　今回は画像認識を行うため、ニューラルネットワークの種類として畳み込みニューラルネットワークを選択している。畳み込みニューラルネットワークの説明は省くが、学習の概要としては以下のようになる。<br />
<br />
<ol>
<li>28x28ピクセルのMnistデータベースを利用</li>
<li>学習データ(mnistTrain)は6万個</li>
<li>学習データは64個で1つのミニバッチを構成し、ミニバッチ単位で学習を実施(計937回)</li>
<li>3を1試行と捉え、それを10回(nEpoochs回)繰り返し実施</li>
</ol><br />
　学習完了後はファイル「output/CNN.fdfsdf」として、構築したニューラルネットワークをファイル出力している(118行目～119行目)。<br />
<br />
<hr />
<h3><a name="プログラム２(画像認識GUIプログラムにおけるニューラルネットワークの利用)"></a>■　プログラム２(画像認識GUIプログラムにおけるニューラルネットワークの利用)</h3>
　プログラム１で作成したファイルを元に、GUI上で入力した文字画像を識別するプログラムを以下に示す。プログラムでは文字をマウスで描いたのちに、「parse」ボタンを押下するとニューラルネットワークで識別した数字の分類(0～9)を表す値を標準出力に出力する。<br />
<br />
　注意点としてはDeeplearning4jがJDK1.7(64bit)準拠であるのに対し、以下のプログラムではJDK 1.8(64bit)上で無理やり動作させている点である。また、JavaFXプログラムであるためライブラリの追加を行う必要もある(Eclipse上での操作としてはプロジェクト名を右クリックして『ビルドパス - ライブラリの追加』からJavaFXを選択する)。<br />
<br />

<h4>リソース</h4>
プロジェクト・フォルダ<br />
┗　output<br />
　　┗　CNN.fdfsdf<br />
<br />

<h4 style="font-size: 14px;">プログラム</h4>
<pre class="brush:java" title="App.java" style="border: 1px gray solid; overflow: auto; overflow-y: hidden;">import java.io.File;
import java.io.IOException;
import java.nio.IntBuffer;

import org.deeplearning4j.nn.multilayer.MultiLayerNetwork;
import org.deeplearning4j.util.ModelSerializer;
import org.nd4j.linalg.api.ndarray.INDArray;
import org.nd4j.linalg.factory.Nd4j;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.control.Button;
import javafx.scene.image.WritableImage;
import javafx.scene.image.WritablePixelFormat;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;

/**
 * 手書き文字の認識テスト・プログラム
 * @author karura
 */
public class App extends Application
{
    public static void main(String[] args) {
        launch(args);
    }
    
    @Override
    public void start(Stage primaryStage) {
        try {
            // シーングラフの構成
            BorderPane  root = new BorderPane();
            root.setCenter( createCanvas() );
            
            // ウィンドウの表示
            Scene scene = new Scene(root,100,100);
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
    
    protected Pane createCanvas()
    {
        // 戻り値の作成
        int     width   = 28;
        int     height  = 28;
        VBox    layout  = new VBox();
        Canvas  canvas  = new Canvas( width , height );
        Button  btnInit = new Button( "init" );
        Button  btnParse= new Button( "parse" );
        layout.getChildren().add( canvas );
        layout.getChildren().add( btnInit );
        layout.getChildren().add( btnParse );
        
        // 初期化
        GraphicsContext g   = canvas.getGraphicsContext2D();
        g.setFill( Color.WHITE );
        g.fillRect( 0 , 0 , width , height );
        
        // クリック押下時に描画するイベントを追加
        canvas.addEventHandler( MouseEvent.ANY , e -&gt;
        {
            // 描画色を宣言
            Color   col     = null;
            
            // 描画色を決定
            switch( e.getButton() )
            {
            case PRIMARY    : col   = Color.BLACK; break;
            case SECONDARY  : col   = Color.WHITE; break;
            default         : return;
            }
            
            // グラフィックス・コンテキストの取得
            GraphicsContext g1  = canvas.getGraphicsContext2D();
            
            // 押下場所の色を変更
            g1.setFill( col );
            g1.fillRect( e.getX() , e.getY() ,  3 , 3 );
            
        });
        
        // ボタン押下時にキャンバスを初期化するイベントを追加
        btnInit.addEventHandler( ActionEvent.ANY , e -&gt; 
        {
            // キャンバス初期化
            GraphicsContext g2   = canvas.getGraphicsContext2D();
            g2.setFill( Color.WHITE );
            g2.fillRect( 0 , 0 , width , height );
        });
        
        // ボタン押下時にキャンバスの内容を解析するイベントを追加
        btnParse.addEventHandler( ActionEvent.ANY , e -&gt;
        {
            // 入力画像を解析する
            WritableImage   img = canvas.snapshot( null , null );
            parse( img );
        });
        
        // 戻り値を返す
        return layout;
    }
    
    protected void parse( WritableImage img )
    {
        // 構築済みニューラルネットワークの読込
        File                f       = new File( "output/CNN.fdfsdf" );
        MultiLayerNetwork   model   = null;
        try {
            // ファイルから読込
            model   = ModelSerializer.restoreMultiLayerNetwork( f );
        } catch (IOException e) { e.printStackTrace(); }
        
        // 画像を変換
        WritablePixelFormat&lt;IntBuffer&gt;  format  = WritablePixelFormat.getIntArgbInstance();
        int                             size    = (int) (img.getWidth() * img.getHeight());
        int[]                           pixels  = new int[ size ];
        img.getPixelReader().getPixels( 0 , 0 , (int)img.getWidth() , (int)img.getHeight() ,
                                        format , pixels, 0 , (int)img.getWidth() );
        INDArray    input   = Nd4j.create( 1 , size );
        for( int i=0 ; i&lt;size ; i++ )
        {
            // b成分のみ抽出
            // 黒が透明部分、白が文字部分になるように色を反転
            int pixel   = 0xFF - ( pixels[ i ] &amp; 0xFF );
            input.put( 0 , i , pixel );
        }
        
        // 解析を実行
        INDArray    output  = model.output( input , false );
        System.out.println( "[output]" );
        System.out.println( output );
    }
}</pre>
<h4 style="font-size: 14px;">実行結果<br />
<br />
<img src="//krr.blog.shinobi.jp/File/3d205863.png" alt="" /><img src="//krr.blog.shinobi.jp/File/77850d37.png" alt="" />&nbsp;</h4>
<pre class="brush:xml" title="標準出力の内容" style="border: 1px gray solid; overflow: auto; overflow-y: hidden;">17:45:09.599 [JavaFX Application Thread] DEBUG org.nd4j.nativeblas.NativeOps - Number of threads used for linear algebra 1

&hellip;中略&hellip;

[output]
[0.00, 0.00, 1.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00]</pre>
<h4 style="font-size: 14px;">解説</h4>
　実行結果を見てみると、output配列内で値=1となっている要素のインデックスが分類値に該当するため、上記では画像を2として正しく識別していることが確認できる。何度か動作させてみると識別に失敗する場合もあるが、2～3回書き直せばだいたい正しく認識することが確認できると思われる。<br />
<br />
　プログラムの構成自体は単純で、Canvasクラス上で左ボタンを押下したままマウスを動かすと軌道上のピクセル値を変更する処理(54行目～90行目)と、parseボタン押下時にCanvasの内容を画像として取得しニューラルネットワークでの解析を行う処理が主な処理である（102行目～107行目）。<br />
<br />
　画像の解析処理を詳しく見ていくと、まずニューラルネットワークをファイルから再構築(116行目～121行目)し、画像のピクセル値をINDArrayクラスに格納(124行目～136行目)、ニューラルネットワークの入力とすることで数字の識別を行っている(139行目)。<br />
<br />
<hr />
<h3>■　参照</h3>
<ol>
<li><a name="ref1" href="http://deeplearning4j.org/convolutionalnets" title="" target="_blank">DeepLearning4j 「Convolutional Networks」</a></li>
</ol>]]></content:encoded>
    <dc:subject>Javaで機械学習 - Deeplearning4j入門</dc:subject>
    <dc:date>2016-06-06T18:04:38+09:00</dc:date>
    <dc:creator>Da@</dc:creator>
    <dc:publisher>NINJA BLOG</dc:publisher>
    <dc:rights>Da@</dc:rights>
  </item>
</rdf:RDF>
