從程序員的角度設計一個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模型

此文已由做者受權雲加社區發佈,轉載請註明 文章出處
相關文章
相關標籤/搜索