java版本的神经网络——开源框架JOONE实践

由于实验室事情缘故,需要将Python写的神经网络转成Java版本的,但是python中的numpy等啥包也不知道在Java里面对应的是什么工具,所以索性直接寻找一个现成可用的Java神经网络框架,于是就找到了JOONE,JOONE是一个神经网络的开源框架,使用的是BP算法进行迭代计算参数,使用起来比较方便也比较实用,下面介绍一下JOONE的一些使用方法。

JOONE需要使用一些外部的依赖包,这在官方网站上有,也可以在这里下载。将所需的包引入工程之后,就可以进行编码实现了。

首先看下完整的程序,这个是上面那个超链接给出的程序,应该是官方给出的一个示例吧,因为好多文章都用这个,这其实是神经网络训练一个异或计算器:

import org.joone.engine.*;
import org.joone.engine.learning.*;
import org.joone.io.*;
import org.joone.net.*;

/*
 *
 * JOONE实现
 *
 * */
public class XOR_using_NeuralNet implements NeuralNetListener
{
	private NeuralNet nnet = null;
	private MemoryInputSynapse inputSynapse, desiredOutputSynapse;
	LinearLayer input;
	SigmoidLayer hidden, output;
	boolean singleThreadMode = true;

	// XOR input
	private double[][] inputArray = new double[][]
	{
	{ 0.0, 0.0 },
	{ 0.0, 1.0 },
	{ 1.0, 0.0 },
	{ 1.0, 1.0 } };

	// XOR desired output
	private double[][] desiredOutputArray = new double[][]
	{
	{ 0.0 },
	{ 1.0 },
	{ 1.0 },
	{ 0.0 } };

	/**
	 * @param args
	 *            the command line arguments
	 */
	public static void main(String args[])
	{
		XOR_using_NeuralNet xor = new XOR_using_NeuralNet();

		xor.initNeuralNet();
		xor.train();
		xor.interrogate();
	}

	/**
	 * Method declaration
	 */
	public void train()
	{

		// set the inputs
		inputSynapse.setInputArray(inputArray);
		inputSynapse.setAdvancedColumnSelector(" 1,2 ");
		// set the desired outputs
		desiredOutputSynapse.setInputArray(desiredOutputArray);
		desiredOutputSynapse.setAdvancedColumnSelector(" 1 ");

		// get the monitor object to train or feed forward
		Monitor monitor = nnet.getMonitor();

		// set the monitor parameters
		monitor.setLearningRate(0.8);
		monitor.setMomentum(0.3);
		monitor.setTrainingPatterns(inputArray.length);
		monitor.setTotCicles(5000);
		monitor.setLearning(true);

		long initms = System.currentTimeMillis();
		// Run the network in single-thread, synchronized mode
		nnet.getMonitor().setSingleThreadMode(singleThreadMode);
		nnet.go(true);
		System.out.println(" Total time=  "
				+ (System.currentTimeMillis() - initms) + "  ms ");
	}

	private void interrogate()
	{

		double[][] inputArray = new double[][]
		{
		{ 1.0, 1.0 } };
		// set the inputs
		inputSynapse.setInputArray(inputArray);
		inputSynapse.setAdvancedColumnSelector(" 1,2 ");
		Monitor monitor = nnet.getMonitor();
		monitor.setTrainingPatterns(4);
		monitor.setTotCicles(1);
		monitor.setLearning(false);
		MemoryOutputSynapse memOut = new MemoryOutputSynapse();
		// set the output synapse to write the output of the net

		if (nnet != null)
		{
			nnet.addOutputSynapse(memOut);
			System.out.println(nnet.check());
			nnet.getMonitor().setSingleThreadMode(singleThreadMode);
			nnet.go();

			for (int i = 0; i < 4; i++)
			{
				double[] pattern = memOut.getNextPattern();
				System.out.println(" Output pattern # " + (i + 1) + " = "
						+ pattern[0]);
			}
			System.out.println(" Interrogating Finished ");
		}
	}

	/**
	 * Method declaration
	 */
	protected void initNeuralNet()
	{

		// First create the three layers
		input = new LinearLayer();
		hidden = new SigmoidLayer();
		output = new SigmoidLayer();

		// set the dimensions of the layers
		input.setRows(2);
		hidden.setRows(3);
		output.setRows(1);

		input.setLayerName(" L.input ");
		hidden.setLayerName(" L.hidden ");
		output.setLayerName(" L.output ");

		// Now create the two Synapses
		FullSynapse synapse_IH = new FullSynapse(); /* input -> hidden conn. */
		FullSynapse synapse_HO = new FullSynapse(); /* hidden -> output conn. */

		// Connect the input layer whit the hidden layer
		input.addOutputSynapse(synapse_IH);
		hidden.addInputSynapse(synapse_IH);

		// Connect the hidden layer whit the output layer
		hidden.addOutputSynapse(synapse_HO);
		output.addInputSynapse(synapse_HO);

		// the input to the neural net
		inputSynapse = new MemoryInputSynapse();

		input.addInputSynapse(inputSynapse);

		// The Trainer and its desired output
		desiredOutputSynapse = new MemoryInputSynapse();

		TeachingSynapse trainer = new TeachingSynapse();

		trainer.setDesired(desiredOutputSynapse);

		// Now we add this structure to a NeuralNet object
		nnet = new NeuralNet();

		nnet.addLayer(input, NeuralNet.INPUT_LAYER);
		nnet.addLayer(hidden, NeuralNet.HIDDEN_LAYER);
		nnet.addLayer(output, NeuralNet.OUTPUT_LAYER);
		nnet.setTeacher(trainer);
		output.addOutputSynapse(trainer);
		nnet.addNeuralNetListener(this);
	}

	public void cicleTerminated(NeuralNetEvent e)
	{
	}

	public void errorChanged(NeuralNetEvent e)
	{
		Monitor mon = (Monitor) e.getSource();
		if (mon.getCurrentCicle() % 100 == 0)
			System.out.println(" Epoch:  "
					+ (mon.getTotCicles() - mon.getCurrentCicle()) + "  RMSE: "
					+ mon.getGlobalError());
	}

	public void netStarted(NeuralNetEvent e)
	{
		Monitor mon = (Monitor) e.getSource();
		System.out.print(" Network started for  ");
		if (mon.isLearning())
			System.out.println(" training. ");
		else
			System.out.println(" interrogation. ");
	}

	public void netStopped(NeuralNetEvent e)
	{
		Monitor mon = (Monitor) e.getSource();
		System.out.println(" Network stopped. Last RMSE= "
				+ mon.getGlobalError());
	}

	public void netStoppedError(NeuralNetEvent e, String error)
	{
		System.out.println(" Network stopped due the following error:  "
				+ error);
	}

}

现在我会逐步解释上面的程序。

【1】 从main方法开始说起,首先第一步新建一个对象:

XOR_using_NeuralNet xor = new XOR_using_NeuralNet();

【2】然后初始化神经网络:

xor.initNeuralNet();

初始化神经网络的方法中:

// First create the three layers
		input = new LinearLayer();
		hidden = new SigmoidLayer();
		output = new SigmoidLayer();

		// set the dimensions of the layers
		input.setRows(2);
		hidden.setRows(3);
		output.setRows(1);

		input.setLayerName(" L.input ");
		hidden.setLayerName(" L.hidden ");
		output.setLayerName(" L.output ");

上面代码解释:

input=new LinearLayer()是新建一个输入层,因为神经网络的输入层并没有训练参数,所以使用的是线性层;

hidden = new SigmoidLayer();这里是新建一个隐含层,使用sigmoid函数作为激励函数,当然你也可以选择其他的激励函数,如softmax激励函数

output则是新建一个输出层

之后的三行代码是建立输入层、隐含层、输出层的神经元个数,这里表示输入层为2个神经元,隐含层是3个神经元,输出层是1个神经元

最后的三行代码是给每个输出层取一个名字。

// Now create the two Synapses
		FullSynapse synapse_IH = new FullSynapse(); /* input -> hidden conn. */
		FullSynapse synapse_HO = new FullSynapse(); /* hidden -> output conn. */

		// Connect the input layer whit the hidden layer
		input.addOutputSynapse(synapse_IH);
		hidden.addInputSynapse(synapse_IH);

		// Connect the hidden layer whit the output layer
		hidden.addOutputSynapse(synapse_HO);
		output.addInputSynapse(synapse_HO);

上面代码解释:

上面代码的主要作用是将三个层连接起来,synapse_IH用来连接输入层和隐含层,synapse_HO用来连接隐含层和输出层

// the input to the neural net
		inputSynapse = new MemoryInputSynapse();

		input.addInputSynapse(inputSynapse);

		// The Trainer and its desired output
		desiredOutputSynapse = new MemoryInputSynapse();

		TeachingSynapse trainer = new TeachingSynapse();

		trainer.setDesired(desiredOutputSynapse);

上面代码解释:

上面的代码是在训练的时候指定输入层的数据和目的输出的数据,

inputSynapse = new MemoryInputSynapse();这里指的是使用了从内存中输入数据的方法,指的是输入层输入数据,当然还有从文件输入的方法,这点在文章后面再谈。同理,desiredOutputSynapse
= new MemoryInputSynapse();也是从内存中输入数据,指的是从输入层应该输出的数据

// Now we add this structure to a NeuralNet object
		nnet = new NeuralNet();

		nnet.addLayer(input, NeuralNet.INPUT_LAYER);
		nnet.addLayer(hidden, NeuralNet.HIDDEN_LAYER);
		nnet.addLayer(output, NeuralNet.OUTPUT_LAYER);
		nnet.setTeacher(trainer);
		output.addOutputSynapse(trainer);
		nnet.addNeuralNetListener(this);

上面代码解释:

这段代码指的是将之前初始化的构件连接成一个神经网络,NeuralNet是JOONE提供的类,主要是连接各个神经层,最后一个nnet.addNeuralNetListener(this);这个作用是对神经网络的训练过程进行监听,因为这个类实现了NeuralNetListener这个接口,这个接口有一些方法,可以实现观察神经网络训练过程,有助于参数调整。

【3】然后我们来看一下train这个方法:

inputSynapse.setInputArray(inputArray);
		inputSynapse.setAdvancedColumnSelector(" 1,2 ");
		// set the desired outputs
		desiredOutputSynapse.setInputArray(desiredOutputArray);
		desiredOutputSynapse.setAdvancedColumnSelector(" 1 ");

上面代码解释:

inputSynapse.setInputArray(inputArray);这个方法是初始化输入层数据,也就是指定输入层数据的内容,inputArray是程序中给定的二维数组,这也就是为什么之前初始化神经网络的时候使用的是MemoryInputSynapse,表示从内存中读取数据

inputSynapse.setAdvancedColumnSelector(" 1,2 ");这个表示的是输入层数据使用的是inputArray的前两列数据。

desiredOutputSynapse这个也同理

Monitor monitor = nnet.getMonitor();

		// set the monitor parameters
		monitor.setLearningRate(0.8);
		monitor.setMomentum(0.3);
		monitor.setTrainingPatterns(inputArray.length);
		monitor.setTotCicles(5000);
		<span style="line-height: 1.5;">monitor.setLearning(true);

上面代码解释:

这个monitor类也是JOONE框架提供的,主要是用来调节神经网络的参数,monitor.setLearningRate(0.8);是用来设置神经网络训练的步长参数,步长越大,神经网络梯度下降的速度越快,monitor.setTrainingPatterns(inputArray.length);这个是设置神经网络的输入层的训练数据大小size,这里使用的是数组的长度;monitor.setTotCicles(5000);这个指的是设置迭代数目;monitor.setLearning(true);这个true表示是在训练过程。

nnet.getMonitor().setSingleThreadMode(singleThreadMode);
		nnet.go(true);

上面代码解释:

nnet.getMonitor().setSingleThreadMode(singleThreadMode);这个指的是是不是使用多线程,但是我不太清楚这里的多线程指的是什么意思

nnet.go(true)表示的是开始训练。

【4】最后来看一下interrogate方法

double[][] inputArray = new double[][]
		{
		{ 1.0, 1.0 } };
		// set the inputs
		inputSynapse.setInputArray(inputArray);
		inputSynapse.setAdvancedColumnSelector(" 1,2 ");
		Monitor monitor = nnet.getMonitor();
		monitor.setTrainingPatterns(4);
		monitor.setTotCicles(1);
		monitor.setLearning(false);
		MemoryOutputSynapse memOut = new MemoryOutputSynapse();
		// set the output synapse to write the output of the net

		if (nnet != null)
		{
			nnet.addOutputSynapse(memOut);
			System.out.println(nnet.check());
			nnet.getMonitor().setSingleThreadMode(singleThreadMode);
			nnet.go();

			for (int i = 0; i < 4; i++)
			{
				double[] pattern = memOut.getNextPattern();
				System.out.println(" Output pattern # " + (i + 1) + " = "
						+ pattern[0]);
			}
			System.out.println(" Interrogating Finished ");
		}

这个方法相当于测试方法,这里的inputArray是测试数据, 注意这里需要设置monitor.setLearning(false);,因为这不是训练过程,并不需要学习,monitor.setTrainingPatterns(4);这个是指测试的数量,4表示有4个测试数据(虽然这里只有一个)。这里还给nnet添加了一个输出层数据对象,这个对象mmOut是初始测试结果,注意到之前我们初始化神经网络的时候并没有给输出层指定数据对象,因为那个时候我们在训练,而且指定了trainer作为目的输出。

接下来就是输出结果数据了,pattern的个数和输出层的神经元个数一样大,这里输出层神经元的个数是1,所以pattern大小为1.

【5】我们看一下测试结果:

Output pattern # 1 = 0.018303527517809233

表示输出结果为0.01,根据sigmoid函数特性,我们得到的输出是0,和预期结果一致。如果输出层神经元个数大于1,那么输出值将会有多个,因为输出层结果是0|1离散值,所以我们取输出最大的那个神经元的输出值取为1,其他为0

【6】最后我们来看一下神经网络训练过程中的一些监听函数:

cicleTerminated:每个循环结束后输出的信息

errorChanged:神经网络错误率变化时候输出的信息

netStarted:神经网络开始运行的时候输出的信息

netStopped:神经网络停止的时候输出的信息

【7】好了,JOONE基本上内容就是这些。还有一些额外东西需要说明:

1,从文件中读取数据构建神经网络

2.如何保存训练好的神经网络到文件夹中,只要测试的时候直接load到内存中就行,而不用每次都需要训练。

【8】先看第一个问题:

从文件中读取数据:

文件的格式:

0;0;0

1;0;1

1;1;0

0;1;1

中间使用分号隔开,使用方法如下,也就是把上文的MemoryInputSynapse换成FileInputSynapse即可。

fileInputSynapse = new FileInputSynapse();
input.addInputSynapse(fileInputSynapse);
fileDisireOutputSynapse = new FileInputSynapse();
TeachingSynapse trainer = new TeachingSynapse();
trainer.setDesired(fileDisireOutputSynapse);

我们看下文件是如何输出数据的:

private File inputFile = new File(Constants.TRAIN_WORD_VEC_PATH);
fileInputSynapse.setInputFile(inputFile);
fileInputSynapse.setFirstCol(2);//使用文件的第2列到第3列作为输出层输入
fileInputSynapse.setLastCol(3);
 fileDisireOutputSynapse.setInputFile(inputFile);
 fileDisireOutputSynapse.setFirstCol(1);//使用文件的第1列作为输出数据
 fileDisireOutputSynapse.setLastCol(1);

其余的代码和上文的是一样的。

【9】然后看第二个问题:

如何保存神经网络

其实很简单,直接序列化nnet对象就行了,然后读取该对象就是java的反序列化,这个就不多做介绍了,比较简单。但是需要说明的是,保存神经网络的时机一定是在神经网络训练完毕后,可以使用下面代码:

public void netStopped(NeuralNetEvent e) {
		Monitor mon = (Monitor) e.getSource();
		try {
			if (mon.isLearning()) {
				saveModel(nnet); //序列化对象
			}
		} catch (IOException ee) {
			// TODO Auto-generated catch block
			ee.printStackTrace();
		}

时间: 2024-10-01 07:23:18

java版本的神经网络——开源框架JOONE实践的相关文章

Java字节码操作开源框架简介

avassist  Javassist是一个开源的分析.编辑和创建Java字节码的类库.是由东京技术学院的数学和计算机科学系的 Shigeru Chiba 所创建的.它已加入了开放源代码JBoss 应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态AOP框架. BCEL  Byte Code Engineering Library (BCEL),这是Apache Software Foundation 的Jakarta 项目的一部分.BCEL是 Java classwor

用Java开源项目JOONE实现人工智能编程

http://www.robotsky.com/ZhiN/MoS/2011-08-25/13142461416649.html http://www.robotsky.com  来源:网络  时间:2011-08-25   评论 0 条 (访问论坛) RobotSky恭候您的投稿>> 很少有程序员不对这里或者那里所包含的人工智能编程所吸引,然而,许多对AI感兴趣的程序员很快就因其中包含的算法的复杂性而退却.在本文中,我们将讨论一个能大大简化这种复杂性的Java开源工程. Java面向对象的神经

java开源框架SpringSide 3.1.4.3开发Web的demo项目实战

原创整理不易,转载请注明出处:java开源框架SpringSide 3.1.4.3开发Web的demo项目实战 代码下载地址:http://www.zuidaima.com/share/1781596496120832.htm SpringSide 3.1.4.3是目前SpringSide的最新版本,也是完成度比较高的一个版本,用来做实际项目的开发应该丝毫不成问题.这里写一下使用该版本开发一个简单Web项目的全过程,当然,最重要的是我自己的一些心得体会.我的文章很长,只有耐下性子细看,才能体会个

java开源框架SpringSide3多数据源配置的方法详解

原创整理不易,转载请注明出处:java开源框架SpringSide3多数据源配置的方法详解 代码下载地址:http://www.zuidaima.com/share/1781579130801152.htm 在SpringSide 3社区中,不断有人提出多数据源配置的问题,但是时至今日却一直没有一个完美的答案.经过一个星期的折腾,我总算搞清楚了在SpringSide 3中配置多数据源的各种困难并加以解决,在这里,特地把我配置SpringSide 3项目中多数据源的过程写出来,与大家分享. 我使用

初识轻量级Java开源框架 --- Spring

初识轻量级Java开源框架 --- Spring 作者:egg 微博:http://weibo.com/xtfggef 出处:http://blog.csdn.net/zhangerqing spring是一个轻量级Java框架,其核心思想就是DI(Dependency Injection,即依赖注入)和IoC(Inversion of Control,即控制反转),因为其开源.低侵入性,现在已经席卷了很大一部分市场,其最大竞争对手乃是JavaEE框架EJB.EJB3.0以前,由于其笨重以及使用

JAVA 版本微信公众账号开源项目招募新成员

大家好: jeecg开源社区,目前正在开展"JAVA 版本微信公众账号开源项目"的开发工作,欢迎有兴趣的朋友一起参与! 截止时间:20140510 详细联系方式:445654970 要求: 1.熟悉jeecg技术平台: 2.有足够的业余时间参与: 官方网站:http://www.jeecg.org/ JAVA 版本微信公众账号开源项目招募新成员,布布扣,bubuko.com

分布式计算开源框架Hadoop入门实践(一)

在SIP项目设计的过程中,对于它庞大的日志在开始时就考虑使用任务分解的多线程处理模式来分析统计,在我从前写的文章<Tiger Concurrent Practice --日志分析并行分解设计与实现>中有所提到.但是由于统计的内容暂时还是十分简单,所以就采用Memcache作为计数器,结合MySQL就完成了访问控制以及统计的工作.然而未来,对于海量日志分析的工作,还是需要有所准备.现在最火的技术词汇莫过于“云计算”,在Open API日益盛行的今天,互联网应用的数据将会越来越有价值,如何去分析这

JAVA版本微信公众账号开源项目版本发布-jeewx1.0(捷微)

JeeWx, 敏捷微信开发,简称"捷微". 捷微是一款免费开源的微信公众账号开发平台. 平台介绍: 一.简介 jeewx是一个开源,高效,敏捷的微信开发平台采用JAVA语言,它是基于jeecg这个企业级快速开发框架实现的. jeewx的目的是最大化的简化微信开发的流程,使用开发者能把最好的精力放到微信具体业务开发,并能以最快的时间完成.把一些常规而频繁的工作交由jeewx来处理即可,平台兼备的代码生成器,在线开发,可以快速的完成企业应用.为此jeewx提供了详细的二次开发文档,关键代码

java有没有开源框架可以获取svn信息的

原文:java有没有开源框架可以获取svn信息的 代码下载地址:http://www.zuidaima.com/share/1550463238638592.htm 想通过java程序来自动监控svn的版本更新情况,不知道能否实现,有的话给提供个代码,多谢了. java有没有开源框架可以获取svn信息的