diff --git a/src/main/java/org/wlld/App.java b/src/main/java/org/wlld/App.java index e570d7f..d1c35b6 100644 --- a/src/main/java/org/wlld/App.java +++ b/src/main/java/org/wlld/App.java @@ -19,7 +19,7 @@ public class App { nerveManager.init(); List sensoryNerves = nerveManager.getSensoryNerves(); for (int i = 0; i < sensoryNerves.size(); i++) { - sensoryNerves.get(i).postMessage(1, 2 + i, true); + sensoryNerves.get(i).postMessage(1, 2 + i, true, 1); } } } diff --git a/src/main/java/org/wlld/function/ActiveFunction.java b/src/main/java/org/wlld/function/ActiveFunction.java index b7f1005..a8ad02a 100644 --- a/src/main/java/org/wlld/function/ActiveFunction.java +++ b/src/main/java/org/wlld/function/ActiveFunction.java @@ -11,4 +11,8 @@ public class ActiveFunction { public double sigmoid(double x) {//sigmoid return ArithUtil.div(1, ArithUtil.add(1, Math.exp(-x))); } + + public double sigmoidG(double out) { + return ArithUtil.mul(out, ArithUtil.sub(1, out)); + } } diff --git a/src/main/java/org/wlld/nerveCenter/NerveManager.java b/src/main/java/org/wlld/nerveCenter/NerveManager.java index ae17c7d..ea777de 100644 --- a/src/main/java/org/wlld/nerveCenter/NerveManager.java +++ b/src/main/java/org/wlld/nerveCenter/NerveManager.java @@ -42,7 +42,7 @@ public class NerveManager { //初始化输出神经元 List outNevers = new ArrayList<>(); for (int i = 1; i < outNerveNub + 1; i++) { - OutNerve outNerve = new OutNerve(i, hiddenNerverNub); + OutNerve outNerve = new OutNerve(i, hiddenNerverNub, 0); //输出层神经元连接最后一层隐层神经元 outNerve.connectFathor(lastNeveList); outNevers.add(outNerve); @@ -67,12 +67,18 @@ public class NerveManager { List hiddenNerveList = new ArrayList<>(); for (int j = 1; j < hiddenNerverNub + 1; j++) {//遍历同级 int upNub = 0; + int downNub = 0; if (i == 0) { upNub = sensoryNerveNub; } else { upNub = hiddenNerverNub; } - HiddenNerve hiddenNerve = new HiddenNerve(j, i + 1, upNub); + if (i == hiddenDepth - 1) {//最后一层隐层神经元z + downNub = outNerveNub; + } else { + downNub = hiddenNerverNub; + } + HiddenNerve hiddenNerve = new HiddenNerve(j, i + 1, upNub, downNub); hiddenNerveList.add(hiddenNerve); } depthNerves.add(hiddenNerveList); diff --git a/src/main/java/org/wlld/nerveEntity/HiddenNerve.java b/src/main/java/org/wlld/nerveEntity/HiddenNerve.java index 5851179..07d1362 100644 --- a/src/main/java/org/wlld/nerveEntity/HiddenNerve.java +++ b/src/main/java/org/wlld/nerveEntity/HiddenNerve.java @@ -2,7 +2,6 @@ package org.wlld.nerveEntity; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.wlld.function.ActiveFunction; /** * @author lidapeng @@ -13,13 +12,13 @@ public class HiddenNerve extends Nerve { private int depth;//所处深度 static final Logger logger = LogManager.getLogger(HiddenNerve.class); - public HiddenNerve(int id, int depth, int upNub) {//隐层神经元 - super(id, upNub, "HiddenNerve"); + public HiddenNerve(int id, int depth, int upNub, int downNub) {//隐层神经元 + super(id, upNub, "HiddenNerve", downNub); this.depth = depth; } @Override - public void input(long eventId, double parameter, boolean isStudy) throws Exception {//接收上一层的输入 + public void input(long eventId, double parameter, boolean isStudy, double E) throws Exception {//接收上一层的输入 logger.debug("name:{},myId:{},depth:{},eventId:{},parameter:{}--getInput", name, getId(), depth, eventId, parameter); boolean allReady = insertParameter(eventId, parameter); if (allReady) {//参数齐了,开始计算 sigma - threshold @@ -28,9 +27,10 @@ public class HiddenNerve extends Nerve { double out = activeFunction.sigmoid(sigma);//激活函数输出数值 if (isStudy) { outNub = out; + this.E = E; } logger.debug("depth:{},myID:{},outPut:{}", depth, getId(), out); - sendMessage(eventId, out, isStudy); + sendMessage(eventId, out, isStudy, E); } // sendMessage(); } diff --git a/src/main/java/org/wlld/nerveEntity/Nerve.java b/src/main/java/org/wlld/nerveEntity/Nerve.java index 0bcc962..95b3858 100644 --- a/src/main/java/org/wlld/nerveEntity/Nerve.java +++ b/src/main/java/org/wlld/nerveEntity/Nerve.java @@ -15,49 +15,84 @@ import java.util.*; public abstract class Nerve { private List son = new ArrayList<>();//轴突下一层的连接神经元 private List fathor = new ArrayList<>();//树突上一层的连接神经元 - private Map dendrites = new HashMap<>();//上一层权重 + protected Map dendrites = new HashMap<>();//上一层权重 + protected Map wg = new HashMap<>();//上一层权重与梯度的积 private int id;//同级神经元编号,注意在同层编号中ID应有唯一性 protected int upNub;//上一层神经元数量 + protected int downNub;//下一层神经元的数量 protected Map> features = new HashMap<>(); static final Logger logger = LogManager.getLogger(Nerve.class); - private double threshold;//此神经元的阈值 + protected double threshold;//此神经元的阈值 protected ActiveFunction activeFunction = new ActiveFunction(); protected String name;//该神经元所属类型 protected double outNub;//输出数值(ps:只有训练模式的时候才可保存输出过的数值) + protected double E;//模板期望值 + protected double gradient;//当前梯度 + protected final double studyPoint = 0.1; + protected double sigmaW;//对上一层权重与上一层梯度的积进行求和 + private int backNub = 0;//当前节点被反向传播的次数 - protected Nerve(int id, int upNub, String name) {//该神经元在同层神经元中的编号 + protected Nerve(int id, int upNub, String name, int downNub) {//该神经元在同层神经元中的编号 this.id = id; this.upNub = upNub; this.name = name; + this.downNub = downNub; initPower();//生成随机权重 } - public void sendMessage(long enevtId, double parameter, boolean isStudy) throws Exception { + public void sendMessage(long enevtId, double parameter, boolean isStudy, double E) throws Exception { if (son.size() > 0) { for (Nerve nerve : son) { - nerve.input(enevtId, parameter, isStudy); + nerve.input(enevtId, parameter, isStudy, E); } } else { throw new Exception("this layer is lastIndex"); } } - public void backSendMessage(double parameter) throws Exception {//反向传播 + private void backSendMessage(long eventId) throws Exception {//反向传播 if (fathor.size() > 0) { - for (Nerve nerve : fathor) { - nerve.backGetMessage(parameter); + for (int i = 0; i < fathor.size(); i++) { + fathor.get(i).backGetMessage(wg.get(i + 1), eventId); } - } else { - throw new Exception("this layer is firstIndex"); } } - protected void input(long eventId, double parameter, boolean isStudy) throws Exception {//输入 + protected void input(long eventId, double parameter, boolean isStudy, double E) throws Exception {//输入 + + } + private void backGetMessage(double parameter, long eventId) throws Exception {//反向传播 + backNub++; + sigmaW = ArithUtil.add(sigmaW, parameter); + if (backNub == downNub) {//进行新的梯度计算 + backNub = 0; + gradient = ArithUtil.mul(activeFunction.sigmoidG(outNub), sigmaW); + updatePower(eventId);//修改阈值 + } } - private void backGetMessage(double parameter) {//反向传播 + protected void updatePower(long eventId) throws Exception {//修改阈值 + double h = ArithUtil.mul(gradient, studyPoint);//梯度下降 + threshold = ArithUtil.sub(threshold, h);//更新阈值 + updateW(h, eventId); + sigmaW = 0;//求和结果归零 + backSendMessage(eventId); + } + private void updateW(double h, long eventId) {//h是学习率 * 当前g(梯度) + List list = features.get(eventId); + for (Map.Entry entry : dendrites.entrySet()) { + int key = entry.getKey();//上层隐层神经元的编号 + double w = entry.getValue();//接收到编号为KEY的上层隐层神经元的权重 + double bn = list.get(key - 1);//接收到编号为KEY的上层隐层神经元的输入 + double wp = ArithUtil.mul(bn, h);//编号为KEY的上层隐层神经元权重的变化值 + w = ArithUtil.add(w, wp);//修正后的编号为KEY的上层隐层神经元权重 + double dm = ArithUtil.mul(w, gradient);//返回给相对应的神经元 + wg.put(key, dm);//保存上一层权重与梯度的积 + dendrites.put(key, w);//保存修正结果 + } + features.remove(eventId); //清空当前上层输入参数参数 } protected boolean insertParameter(long eventId, double parameter) {//添加参数 @@ -100,7 +135,7 @@ public abstract class Nerve { dendrites.put(i, random.nextDouble()); } //生成随机阈值 - threshold = ArithUtil.mul(random.nextDouble(), 10); + threshold = random.nextDouble(); } } diff --git a/src/main/java/org/wlld/nerveEntity/OutNerve.java b/src/main/java/org/wlld/nerveEntity/OutNerve.java index 9b6e1df..bd38c73 100644 --- a/src/main/java/org/wlld/nerveEntity/OutNerve.java +++ b/src/main/java/org/wlld/nerveEntity/OutNerve.java @@ -2,6 +2,10 @@ package org.wlld.nerveEntity; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.wlld.tools.ArithUtil; + +import java.util.List; +import java.util.Map; /** * @author lidapeng @@ -11,21 +15,31 @@ import org.apache.logging.log4j.Logger; public class OutNerve extends Nerve { static final Logger logger = LogManager.getLogger(OutNerve.class); - public OutNerve(int id, int upNub) { - super(id, upNub, "OutNerve"); + public OutNerve(int id, int upNub, int downNub) { + super(id, upNub, "OutNerve", downNub); } @Override - public void input(long eventId, double parameter, boolean isStudy) { + public void input(long eventId, double parameter, boolean isStudy, double E) throws Exception { logger.debug("Nerve:{},eventId:{},parameter:{}--getInput", name, eventId, parameter); boolean allReady = insertParameter(eventId, parameter); if (allReady) {//参数齐了,开始计算 sigma - threshold double sigma = calculation(eventId); double out = activeFunction.sigmoid(sigma); - if (isStudy) { + logger.debug("myId:{},outPut:{}------END", getId(), out); + if (isStudy) {//输出结果并进行BP调整权重及阈值 outNub = out; + this.E = E; + gradient = outGradient();//当前梯度变化 + //调整权重 修改阈值 并进行反向传播 + updatePower(eventId); } - logger.debug("myId:{},outPut:{}------END", getId(), out); } } + + private double outGradient() {//生成输出层神经元梯度变化 + //上层神经元输入值 * 当前神经元梯度*学习率 =该上层输入的神经元权重变化 + //当前梯度神经元梯度变化 *学习旅 * -1 = 当前神经元阈值变化 + return ArithUtil.mul(activeFunction.sigmoidG(outNub), ArithUtil.sub(E, outNub)); + } } diff --git a/src/main/java/org/wlld/nerveEntity/SensoryNerve.java b/src/main/java/org/wlld/nerveEntity/SensoryNerve.java index 32bdc51..9f4ff19 100644 --- a/src/main/java/org/wlld/nerveEntity/SensoryNerve.java +++ b/src/main/java/org/wlld/nerveEntity/SensoryNerve.java @@ -10,11 +10,11 @@ import java.util.List; public class SensoryNerve extends Nerve { public SensoryNerve(int id, int upNub) { - super(id, upNub, "SensoryNerve"); + super(id, upNub, "SensoryNerve", 0); } - public void postMessage(long eventId, double parameter, boolean isStudy) throws Exception {//感知神经元输出 - sendMessage(eventId, parameter, isStudy); + public void postMessage(long eventId, double parameter, boolean isStudy, double E) throws Exception {//感知神经元输出 + sendMessage(eventId, parameter, isStudy, E); } @Override