从程序员的角度设计一个Java的神经网络
欢迎大家前往云+社区,获取更多腾讯海量技术实践干货哦~
来自维基百科:
人工神经网络(ANN)或连接系统是受生物神经网络启发构成生物大脑的计算系统。这样的系统通过考虑例子来学习(逐步提高性能)来完成任务,通常没有任务特定的编程。
用Java或任何其他编程语言设计神经网络我们需要理解人工神经网络的结构和功能。
人工神经网络执行的任务比如有模式识别、从数据中学习以及像专家一样预测趋势,而不像传统的算法方法那样需要执行一组步骤来实现所定义的目标。人工神经网络由于其高度交互的网络结构,可以学习如何自己解决一些任务。
人造神经元具有与人脑神经元相似的结构。一个天然的神经元是由核,树突和轴突组成的。轴突延伸到几个分支形成突触与其他神经元的树突。
到目前为止,我们已经区分了神经元的结构和相连神经元的网络。另一个重要方面是分别与单个神经元相关的神经网络的处理或计算。自然神经元是信号处理器 - 它们在树突中接收可以触发轴突信号的微信号。有一个潜在的阈值,到达的时候,刺激轴突,并传播信号到其他神经元。因此,我们可以将人造神经元视为一个在输入中具有信号接收器、在输出中具有激活单元的东西,其可以发送的信号将被转发到与图中所示类似的其他神经元上:

此外,神经元之间的连接具有相应可以修改信号的权重,从而影响神经元的输出。由于权重是神经网络的内部因素并影响其输出,所以可以认为它们是神经网络的内部学科,调节描述神经元与其他神经元或外部世界的连接的权重将反映神经网络的能力。
人造神经元接收一个或多个输入(代表树突)并将它们相加以产生输出/ 激活 (代表神经元的轴突)。一般来说每个节点的总和被加权,总和通过激活函数或传递函数传递。
这个组件为神经网络处理增加了非线性,这是因为自然神经元具有非线性行为。在一些特殊情况下,它可以是一个线性函数。
一个标准的计算机芯片电路可以看作是一个激活功能的数字网络,取决于输入的是“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);
}
开始编写代码之前需要注意的最后一个问题是神经网络层。神经网络由几个链接层组成,形成所谓的多层网络。
神经层可以分为三类:
- 输入层
- 隐藏层
- 输出层
在实践中,额外的神经层增加了另一个抽象层次的外部刺激,增强了神经网络认知更复杂知识的能力。
一个图层类可以被定义为一个有连接的神经元列表:
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
相关阅读
此文已由作者授权云加社区发布,转载请注明文章出处
从程序员的角度设计一个Java的神经网络的更多相关文章
- 设计一个 Java 程序,自定义异常类,从命令行(键盘)输入一个字符串,如果该字符串值为“XYZ”。。。
设计一个 Java 程序,自定义异常类,从命令行(键盘)输入一个字符串,如果该字符串值为“XYZ”,则抛出一个异常信息“This is a XYZ”,如果从命令行输入 ABC,则没有抛出异常.(只有 ...
- 从程序员的角度分析微信小程序(编程语言:用到什么学什么)
从程序员的角度分析微信小程序(编程语言:用到什么学什么) 一.总结 一句话总结:微信小程序原理就是用JS调用底层native组件,和React Native非常类似.(需要时,用到时再学) 1.选择语 ...
- 从程序员的角度分析微信小程序
昨天朋友圈被微信小程序刷爆了. 我赶快在书架上拿出三年前买的书,把上面的土擦干净,压压惊. 作为一个并不是资深的程序员. 从程序员的角度分析一下微信小程序,欢迎指点. 首先吐槽 微信小程序只发了200 ...
- 从程序员的角度深入理解MySQL
前言 今天我将站在程序员的角度以MySQL为例探索数据库的奥秘! 数据库基本原理 我对DB的理解 1.数据库的组成:存储 + 实例 不必多说,数据当然需要存储:存储了还不够,显然需要提供程序对存储 ...
- 90 % Java 程序员被误导的一个性能优化策略
我们经常看到一些 Java 性能优化的书或者理念,说不要在循环内定义变量,这样会占用过多的内存影响性能,而要在循环外面定义.接触 Java 这么久以来,相信很多 Java 程序员都被这种代码性能优化策 ...
- Coding girl一个老程序员谈到的一个女程序员的故事
因为有人说我给一个女程序员的建议不靠谱,我不服,因为我的工作经历中的一些女程序员都很不错,比那些男程序员都强,所以,我在新浪微博和twitter上征集女程序员的故事和想法,这两天来,我收到了好几封邮件 ...
- .NET程序员我是如何通过一个产品在2年内买车买房
刚开始写博客不足之处望大家多多指点,少一些质疑多一些帮助,我们就能成为朋友. 我写博客的目的其实很简单就是为了分享知识,如有幸能申请当MVP那是最好不过了,这个过程对于“大牛”来说很快,但对于我来说估 ...
- 我的程序员之路:自学Java篇
序章 时光疾驰,从事IT行业已两年有余. 16年11月开始自学Java,从此开启自学之路,后来实习期自学大数据.python.爬虫等,最终成长为一名平凡的程序员.回首望去,一路上的过往历历在目,有初学 ...
- Java全栈程序员之08:MAVEN+JAVA配置
从Spring3.0开始,Spring支持以Java配置的方式来代替XML配置.这一点说起来其实有点可笑,XML配置的方式最初被创建出来就是为了让配置与程序员无关.可是最终我们发现,绝大多数的那些配置 ...
随机推荐
- Linux系统Java环境安装配置
jdk安装配置 首先下载JDK和JRE,这里你的需要看看你的Linux系统是多少位的,比如我的是64位的: 下载JDK并指定到Download目录,JRE同样操作: 解压并且配置环境: tar -zx ...
- java保留两位小数(不四舍五入)
import java.text.DecimalFormat; import java.math.RoundingMode; class Text{ public static void main(S ...
- python机器学习工具包
1. scikit-learn: Machine Learning in Python scikit-learn是一个基于NumPy, SciPy, Matplotlib的开源机器学习工具包,主要涵盖 ...
- STL中的nth_element()方法的使用
STL中的nth_element()方法的使用 通过调用nth_element(start, start+n, end) 方法可以使第n大元素处于第n位置(从0开始,其位置是下标为 n的元素),并且比 ...
- HDU 1017 A Mathematical Curiosity【水,坑】
A Mathematical Curiosity Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java ...
- BZOJ 1509: [NOI2003]逃学的小孩
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1509 直接求出树的直径,枚举每个点更新一遍答案. #include<cstring> ...
- SSAS属性中更改AllowedBrowsingFolders的值后才能更改其它文件夹的值
首先 以管理员身份运行 打开SQL Server Management Studio (SSMS). 在Sql Server Analysis Service中的属性中有很多文件夹属性,决定了存放CU ...
- 【自制工具类】struts返回json数据包装格式类
自己写的一个给struts返回的json数据包装格式类,不喜勿喷,原创,需在项目中引入com.alibaba.fastjson的jar包 先看下效果(这里没有使用msg,有兴趣的往下看): 上demo ...
- win处navicat直接导出的sql脚本导入Linux mysql报错问题
最近几天在把win上的项目的数据库转移到Ubuntu,于是第一件事就是从win处的navicat直接导出sql脚本,然后进入Ubuntu导入的时候会报错误,跳过错误继续执行导致数据库表的缺失. 跨平台 ...
- tp5 $_ENV获取不到数据
$_ENV变量是取决于服务器的环境变量的,从不同的服务器上获取的$_ENV变量打印出的结果可能是不同的. php的配置文件php.ini的配置项为:variables_order = "GP ...