第一个感知机的代码解读

  1. 第三遍看这个代码了,以前只是根据注释和命名规则去看每条代码是要干嘛,这次读了部分源码,找到了很多疑问的答案,也有还没解决的
  2. 先上看代码前的基础链接,基础不牢地动山摇啊
    java中Set的用法
    JAVA 8 :: 关键字
    java泛型中<?>和有什么区别?
    神经网络的 Delta 学习规则(learning rule)
    delta法则(梯度下降)
  3. 对代码的解读都在代码的注释里了
import java.util.Arrays;
import org.junit.Test;
import org.neuroph.core.NeuralNetwork;
import org.neuroph.core.data.DataSet;
import org.neuroph.core.data.DataSetRow;
import org.neuroph.core.events.LearningEvent;
import org.neuroph.core.events.LearningEventListener;
import org.neuroph.core.learning.LearningRule;
import org.neuroph.core.learning.SupervisedLearning;
import org.neuroph.nnet.Perceptron;

public class FirstPerceptron extends NeuralNetwork implements LearningEventListener {

	/**
	     *  序列化
	 */
	private static final long serialVersionUID = 1L;

	@Test
	public void test() {
		// 建立AND训练集,有两个输入和一个输出
		DataSet trainAndSet = new DataSet(2, 1);
		/**
		 * 这里add有重写的add(double[] input, double[] output)方法
		 * 但是为什么非要new一个DataSetRow,因为对应testNeuralNetwork()方法中的for循环遍历
		 * 但是实测即使写成trainAndSet.add(new double[] { 0, 0 }, new double[] { 0 });程序也正常输出了,但是还是写规范的好
		 */
		trainAndSet.add(new DataSetRow(new double[] { 0, 0 }, new double[] { 0 }));
		trainAndSet.add(new DataSetRow(new double[] { 0, 1 }, new double[] { 0 }));
		trainAndSet.add(new DataSetRow(new double[] { 1, 0 }, new double[] { 0 }));
		trainAndSet.add(new DataSetRow(new double[] { 1, 1 }, new double[] { 1 }));

//        建立OR训练集
		DataSet trainOrSet = new DataSet(2, 1);
		trainOrSet.add(new DataSetRow(new double[] { 0, 0 }, new double[] { 0 }));
		trainOrSet.add(new DataSetRow(new double[] { 0, 1 }, new double[] { 1 }));
		trainOrSet.add(new DataSetRow(new double[] { 1, 0 }, new double[] { 1 }));
		trainOrSet.add(new DataSetRow(new double[] { 1, 1 }, new double[] { 1 }));

//        建立XOR训练集
		DataSet trainXorSet = new DataSet(2, 1);
		trainXorSet.add(new DataSetRow(new double[] { 0, 0 }, new double[] { 0 }));
		trainXorSet.add(new DataSetRow(new double[] { 0, 1 }, new double[] { 1 }));
		trainXorSet.add(new DataSetRow(new double[] { 1, 0 }, new double[] { 1 }));
		trainXorSet.add(new DataSetRow(new double[] { 1, 1 }, new double[] { 0 }));

		// 建立NOT训练集
		DataSet trainNotSet = new DataSet(1, 1);
		trainNotSet.add(new DataSetRow(new double[] { 0 }, new double[] { 1 }));
		trainNotSet.add(new DataSetRow(new double[] { 1 }, new double[] { 0 }));

//        建立感知机
		/**
		 * 为什么要向上转型而不是直接定义成Perceptron呢
		 * 因为下边学习规则是NeuralNetwork父类里的私有方法,子类无法访问到,子类只是拥有,但是不能使用
		 */
		NeuralNetwork myPerceptron = new Perceptron(2, 1);

		NeuralNetwork myPerceptron_not = new Perceptron(1, 1);

		/**
		 * 这里的学习规则到底是什么呢?get到的到底是什么东西,也没人为指定学习规则是什么啊?
		 * 这里学习规则在new一个Perceptron的时候以及设置了setLearningRule(new BinaryDeltaRule())
		 * 所以get的时候并不是空
		 * BinaryDeltaRule规则是什么呢?看我发的链接
		 */
		LearningRule lr = myPerceptron.getLearningRule();
		lr.addListener(this);

		LearningRule lr_tjw = myPerceptron_not.getLearningRule();
		/**
		 * 监听这里不好理解啊,就像Android的监听,知道干嘛的但是不知道内部如何实现的
		 */
		lr_tjw.addListener(this);
//        训练AND集
		/**
		 * learn()这个抽象方法暂时没有找到在哪里去实现的
		 */
		myPerceptron.learn(trainAndSet);
		System.out.println("测试感知机AND集训练结果:");
		testNeuralNetwork(myPerceptron, trainAndSet);

//        训练OR集
//        myPerceptron.learn(trainOrSet);
//        System.out.println("测试感知机Or集训练结果:");
//        testNeuralNetwork(myPerceptron, trainOrSet);

//        训练XOR集
//        由于XOR输入输出情况线性不可分,将无法完成训练
//        myPerceptron.learn(trainXorSet);
//        System.out.println("测试感知机Xor集训练结果:");
//        testNeuralNetwork(myPerceptron, trainXorSet);

//        训练NOT集
//        myPerceptron_not.learn(trainNotSet);
//        System.out.println("测试感知机Not集训练结果:");
//        testNeuralNetwork(myPerceptron_not, trainNotSet);

	}


	public static void testNeuralNetwork(NeuralNetwork<?> nnet, DataSet test) {

		for (DataSetRow dataRow : test.getRows()) {

			nnet.setInput(dataRow.getInput());
			nnet.calculate();
			double[] networkOutput = nnet.getOutput();
			System.out.print("Input: " + Arrays.toString(dataRow.getInput()));
			System.out.println(" Output: " + Arrays.toString(networkOutput));
		}
	}

	@Override
	public void handleLearningEvent(LearningEvent event) {
		SupervisedLearning bp = (SupervisedLearning) event.getSource();
		if (event.getEventType() != LearningEvent.Type.LEARNING_STOPPED) {
			System.out.println(bp.getCurrentIteration() + ". iteration : " + bp.getTotalNetworkError());
		}
	}
}
  1. 问题1:在Perceptron类中提到了BinaryDeltaRule,百度了一下文章中有这么一段话尽管当训练样例线性可分时,感知器法则可以成功地找到一个权向量,但如果样例不是线性可分时它将不能收敛。因此,人们设计了另一个训练法则来克服这个不足,称为 delta 法则(delta rule)。如果训练样本不是线性可分的,那么 delta 法则会收敛到目标概念的最佳 近似。但是关于XOR的问题又有博客说XOR的结果表现为线性不可分,应采用更多层的网络,但是上文不是说到针对线性不可分时delta可以解决的吗?这个留待以后吧
  2. 线性不可分是下一节的内容,包含XOR问题的解决
  3. 问题2:同样是最初提到的基础链接文章里的一句话显然 delta规则要求转移函数可导这里的转移函数应该就是书上说的传输函数(transferFunction)吧,在Perceptron类中找到了下图代码,这些类型还不了解是什么
    在这里插入图片描述
    在这里插入图片描述
  4. 问题3:关于代码中learn()抽象方法的实现也有必要再去源码里找找看
  5. 代码的流程给我的感觉应该是创建训练集=>创建感知机=>学习规则是配置在感知机上的=>监听是设置在学习规则上个的=>感知机开始学习=>输出监听结果和最后的学习结果
  6. 补充:针对传输函数问题,这个枚举中的函数,参考吴岸城老师的《神经网络与深度学习》第28页,就会明白了,而且表格十分详细
    在这里插入图片描述
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值