从程序员的角度设计一个Java的神经网络

欢迎你们前往云+社区,获取更多腾讯海量技术实践干货哦~php

来自维基百科html

人工神经网络(ANN)或链接系统是受生物神经网络启发构成生物大脑的计算系统。这样的系统经过考虑例子来学习(逐步提升性能)来完成任务,一般没有任务特定的编程。java

用Java或任何其余编程语言设计神经网络咱们须要理解人工神经网络的结构和功能算法

人工神经网络执行的任务好比有模式识别、从数据中学习以及像专家同样预测趋势,而不像传统的算法方法那样须要执行一组步骤来实现所定义的目标。人工神经网络因为其高度交互的网络结构,能够学习如何本身解决一些任务。编程

人造神经元具备与人脑神经元类似的结构。一个自然的神经元是由核,树突和轴突组成的。轴突延伸到几个分支造成突触与其余神经元的树突。bash

到目前为止,咱们已经区分了神经元的结构和相连神经元的网络。另外一个重要方面是分别与单个神经元相关的神经网络的处理或计算。天然神经元是信号处理器 - 它们在树突中接收能够触发轴突信号的微信号。有一个潜在的阈值,到达的时候,刺激轴突,并传播信号到其余神经元。所以,咱们能够将人造神经元视为一个在输入中具备信号接收器、在输出中具备激活单元的东西,其能够发送的信号将被转发到与图中所示相似的其余神经元上:微信

此外,神经元之间的链接具备相应能够修改信号的权重,从而影响神经元的输出。因为权重是神经网络的内部因素并影响其输出,因此能够认为它们是神经网络的内部学科,调节描述神经元与其余神经元或外部世界的链接的权重将反映神经网络的能力。网络

正如Bioinfo Publications所述dom

人造神经元接收一个或多个输入(表明树突)并将它们相加以产生输出/ 激活 (表明神经元的轴突)。通常来讲每一个节点的总和被加权,总和经过激活函数或传递函数传递。机器学习

这个组件为神经网络处理增长了非线性,这是由于天然神经元具备非线性行为。在一些特殊状况下,它能够是一个线性函数。

维基百科说起到说

一个标准的计算机芯片电路能够看做是一个激活功能的数字网络,取决于输入的是“ON”(1)仍是“OFF”(0)。这与神经网络中的线性感知器的行为相似。然而, 非线性 激活函数容许这样的网络仅使用少许的节点来计算特殊问题。使用的流行的激活函数的例子是Sigmoid、双曲正切、硬极限阈值和纯线性。

将这些知识转化为Java代码,咱们将有一个以下的神经元类:

复制代码
import java.util.ArrayList;
import java.util.List;
import edu.neuralnet.core.activation.ActivationFunction;
import edu.neuralnet.core.input.InputSummingFunction;
/**
 * Represents a neuron model comprised of(如下内容组成的神经元模型): </br>
 * <ul>
 * <li>Summing part(求和部分)  - input summing function(输入求和函数 )</li>
 * <li>Activation function(激活函数)</li>
 * <li>Input connections(输入链接)</li>
 * <li>Output connections(输出链接)</li>
 * </ul>
 */
public class Neuron {
 /**
  * Neuron's identifier * 神经元标识符 */ private String id; /** * Collection of neuron's input connections (connections to this neuron)
  * 神经元输入链接的集合(与此神经元的链接) 
  */
 protected List < Connection > inputConnections;
 /**
  * Collection of neuron's output connections (connections from this to other * neurons) * 神经元输出链接的集合(从这个到其余神经元的链接) */ protected List < Connection > outputConnections; /** * Input summing function for this neuron * 该神经元的输入和函数 */ protected InputSummingFunction inputSummingFunction; /** * Activation function for this neuron * 这个神经元的激活函数 */ protected ActivationFunction activationFunction; /** * Default constructor * 默认构造方法 */ public Neuron() { this.inputConnections = new ArrayList < > (); this.outputConnections = new ArrayList < > (); } /** * Calculates the neuron's output
  * 计算神经元输出
  */
 public double calculateOutput() {
   double totalInput = inputSummingFunction.getOutput(inputConnections);
   return activationFunction.getOutput(totalInput);
  }
  ...
}复制代码
复制代码

神经元有输入和输出链接、输入求和值和激活函数,那输入权重在哪里呢?它们包含在链接自己中,以下所示:

复制代码
/**
 * Represents a connection between two neurons an the associated weight.
 * 表示两个神经元之间的链接以及相关的权重
 */
public class NeuronsConnection {
/**
 * From neuron for this connection (source neuron). This connection is
 * output connection for from neuron.
 * 从神经元中获取这个链接(源神经元)。此链接是来自神经元的输出链接
 */
protected Neuron fromNeuron;
/**
 * To neuron for this connection (target, destination neuron) This
 * connection is input connection for to neuron.
 * 对于用于此链接的神经元(目标,目标神经元),此链接是神经元的输入链接
 */
protected Neuron toNeuron;
/**
 * Connection weight
 * 链接权重
 */
protected double weight;
/**
 * Creates a new connection between specified neurons with random weight.
 * 在具备随机权重的指定神经元之间建立一个新的链接
 * @param fromNeuron
 *            neuron to connect from
 * @param toNeuron
 *            neuron to connect to
 */
public NeuronsConnection(Neuron fromNeuron, Neuron toNeuron) {
this.fromNeuron = fromNeuron;
this.toNeuron = toNeuron;
this.weight = Math.random();
}
/**
 * Creates a new connection to specified neuron with specified weight object
 * 建立与指定权重对象的指定神经元的新链接
 *
 * @param fromNeuron
 *            neuron to connect from
 * @param toNeuron
 *            neuron to connect to
 * @param weight
 *            weight for this connection
 */
public NeuronsConnection(Neuron fromNeuron, Neuron toNeuron, double weight) {
this(fromNeuron, toNeuron);
this.weight = weight;
}
/**
 * Returns weight for this connection
 * 返回此链接的权重
 * @return weight for this connection
 */
public double getWeight() {
return weight;
}
/**
 * Set the weight of the connection.
 * 设置链接的权值
 * @param weight
 *            The new weight of the connection to be set
 */
public void setWeight(double weight) {
this.weight = weight;
}
/**
 * Returns input of this connection - the activation function result
 * calculated in the input neuron of this connection.
 * 返回此链接的输入 - 在此链接输入神经元中激活函数计算的结果
 * @return input received through this connection
 */
public double getInput() {
return fromNeuron.calculateOutput();
}
/**
 * Returns the weighted input of this connection
 * 返回此链接的权值输入
 * @return weighted input of the connection
 */
public double getWeightedInput() {
return fromNeuron.calculateOutput() * weight;
}
/**
 * Gets from neuron for this connection
 * 从神经元获取此链接
 * @return from neuron for this connection
 */
public Neuron getFromNeuron() {
return fromNeuron;
}
/**
 * Gets to neuron for this connection
 * 获取用于此链接的神经元
 * @return neuron to set as to neuron
 */
public Neuron getToNeuron() {
return toNeuron;
}
...
}复制代码
复制代码

链接对象提供权重并负责计算输入的权值。

求和函数被定义为接口,以便可以替换神经元的计算策略:

复制代码
import java.util.List;
import edu.neuralnet.core.Connection;
/**
 * Represents the inputs summing part of a neuron also called signal collector.
 * 神经元的求和部分,也能够称为信号收集器
 */
public interface InputSummingFunction {
/**
 * Performs calculations based on the output values of the input neurons.
 * 根据输入神经元的输出值执行计算
 * @param inputConnections
 *            neuron's input connections * @return total input for the neuron having the input connections * 总输入,具备输入链接的神经元 */ double collectOutput(List<Connection> inputConnections); }复制代码
复制代码

分别实现为:

复制代码
import java.util.List;
import edu.neuralnet.core.Connection;
/**
 * Calculates the weighted sums of the input neurons' outputs. * 计算输入神经元输出的加权和 */ public final class WeightedSumFunction implements InputSummingFunction { /** * {@inheritDoc} */ @Override public double collectOutput(List<Connection> inputConnections) { double weightedSum = 0d; for (Connection connection : inputConnections) { weightedSum += connection.getWeightedInput(); } return weightedSum; } }复制代码
复制代码

激活函数的接口能够定义以下:

复制代码
/**
 * Neural networks activation function interface.
 * 神经网络激活函数的接口
 */
public interface ActivationFunction {
/**
 * Performs calculation based on the sum of input neurons output.
 * 基于输入神经元输出的和来进行计算
 * @param summedInput
 *            neuron's sum of outputs respectively inputs for the connected * neuron * * @return Output's calculation based on the sum of inputs
 *          基于输入和来计算输出
 */
double calculateOutput(double summedInput);
}复制代码
复制代码

开始编写代码以前须要注意的最后一个问题是神经网络层。神经网络由几个连接层组成,造成所谓的多层网络。

神经层能够分为三类:

  1. 输入层
  2. 隐藏层
  3. 输出层

在实践中,额外的神经层增长了另外一个抽象层次的外部刺激,加强了神经网络认知更复杂知识的能力。

一个图层类能够被定义为一个有链接的神经元列表:

复制代码
import java.util.ArrayList;
import java.util.List;
/**
 * Neural networks can be composed of several linked layers, forming the
 * so-called multilayer networks. A layer can be defined as a set of neurons
 * comprising a single neural net's layer. * 神经网络能够由多个链接层组成,造成所谓的多层网络, * 一层能够定义为一组包含神经网络层的神经元 */ public class NeuralNetLayer { /** * Layer's identifier
 * 层次标识符 
 */
private String id;
/**
 * Collection of neurons in this layer
 * 该层神经元的集合
 */
protected List<Neuron> neurons;
/**
 * Creates an empty layer with an id.
 * 用ID建立一个空层
 * @param id
 *            layer's identifier */ public NeuralNetLayer(String id) { this.id = id; neurons = new ArrayList<>(); } /** * Creates a layer with a list of neurons and an id. * 建立一个包含神经元列表和id的层 * @param id * layer's identifier 层次标识符 
 * @param neurons
 *            list of neurons to be added to the layer 添加到该层的神经元列表
 */
public NeuralNetLayer(String id, List<Neuron> neurons) {
this.id = id;
this.neurons = neurons;
}
...
}
复制代码
复制代码

最后,用Java建立一个简单的神经网络:

复制代码
/**
 * Represents an artificial neural network with layers containing neurons.
 * 含有神经元层的人工神经网络
 */
public class NeuralNet {
/**
 * Neural network id
 * 神经网络ID
 */
private String id;
/**
 * Neural network input layer
 * 神经网络的输入层
 */
private NeuralNetLayer inputLayer;
/**
 * Neural network hidden layers
 * 神经网络隐藏的层
 */
private List<NeuralNetLayer> hiddenLayers;
/**
 * Neural network output layer
 * 神经网络的输出层
 */
private NeuralNetLayer outputLayer;
/**
 * Constructs a neural net with all layers present.
 * 构造一个具备全部层的神经网络
 * @param id
 *            Neural network id to be set 设置神经网络标识
 * @param inputLayer
 *            Neural network input layer to be set 设置神经网络的输入层 
 * @param hiddenLayers
 *            Neural network hidden layers to be set 设置神经网络隐藏的层
 * @param outputLayer
 *            Neural network output layer to be set 设置神经网络的输出层
 */
public NeuralNet(String id, NeuralNetLayer inputLayer, List<NeuralNetLayer> hiddenLayers,
NeuralNetLayer outputLayer) {
this.id = id;
this.inputLayer = inputLayer;
this.hiddenLayers = hiddenLayers;
this.outputLayer = outputLayer;
}
/**
 * Constructs a neural net without hidden layers.
 * 构造一个没有隐藏层的神经网络
 * @param id
 *            Neural network id to be set 设置神经网络标识
 * @param inputLayer
 *            Neural network input layer to be set 设置神经网络的输入层 
 * @param outputLayer
 *            Neural network output layer to be set 设置神经网络隐藏的层
 */
public NeuralNet(String id, NeuralNetLayer inputLayer, NeuralNetLayer outputLayer) {
this.id = id;
this.inputLayer = inputLayer;
this.outputLayer = outputLayer;
}
...
}复制代码
复制代码

咱们所获得的是一个基于Java的神经网络层次、神经元和链接的结构定义。咱们也谈到了一些关于激活函数的内容,并为它们定义了一个接口。为简单起见,咱们省略了各类激活函数的实现以及学习神经网络的基础知识。这两个主题将在本系列的后续文章中介绍。

翻译人:BAStriver,该成员来自云+社区翻译社

原文连接:https://dzone.com/articles/designing-a-neural-network-in-java

原文做者:Daniela Kolarova

相关阅读

经过JS库Encog实现JavaScript机器学习和神经学网络

天然语言处理的神经网络模型初探

如何使用Python超参数的网格搜索ARIMA模型

此文已由做者受权云加社区发布,转载请注明 文章出处
相关文章
相关标签/搜索