從程序員的角度設計一個基于Java的神經(jīng)網(wǎng)絡
人工神經(jīng)網(wǎng)絡(ANN)或連接系統(tǒng)是受生物神經(jīng)網(wǎng)絡啟發(fā)構成生物大腦的計算系統(tǒng)。這樣的系統(tǒng)通過考慮例子來學習(逐步提高性能)來完成任務,通常沒有任務特定的編程。
用Java或任何其他編程語言設計神經(jīng)網(wǎng)絡我們需要理解人工神經(jīng)網(wǎng)絡的結構和功能。
人工神經(jīng)網(wǎng)絡執(zhí)行的任務比如有模式識別、從數(shù)據(jù)中學習以及像專家一樣預測趨勢,而不像傳統(tǒng)的算法方法那樣需要執(zhí)行一組步驟來實現(xiàn)所定義的目標。人工神經(jīng)網(wǎng)絡由于其高度交互的網(wǎng)絡結構,可以學習如何自己解決一些任務。
人造神經(jīng)元具有與人腦神經(jīng)元相似的結構。一個天然的神經(jīng)元是由核,樹突和軸突組成的。軸突延伸到幾個分支形成突觸與其他神經(jīng)元的樹突。
到目前為止,我們已經(jīng)區(qū)分了神經(jīng)元的結構和相連神經(jīng)元的網(wǎng)絡。另一個重要方面是分別與單個神經(jīng)元相關的神經(jīng)網(wǎng)絡的處理或計算。自然神經(jīng)元是信號處理器 - 它們在樹突中接收可以觸發(fā)軸突信號的微信號。有一個潛在的閾值,到達的時候,刺激軸突,并傳播信號到其他神經(jīng)元。因此,我們可以將人造神經(jīng)元視為一個在輸入中具有信號接收器、在輸出中具有激活單元的東西,其可以發(fā)送的信號將被轉發(fā)到與圖中所示類似的其他神經(jīng)元上:
此外,神經(jīng)元之間的連接具有相應可以修改信號的權重,從而影響神經(jīng)元的輸出。由于權重是神經(jīng)網(wǎng)絡的內部因素并影響其輸出,所以可以認為它們是神經(jīng)網(wǎng)絡的內部學科,調節(jié)描述神經(jīng)元與其他神經(jīng)元或外部世界的連接的權重將反映神經(jīng)網(wǎng)絡的能力。
正如Bioinfo Publications所述:
人造神經(jīng)元接收一個或多個輸入(代表樹突)并將它們相加以產(chǎn)生輸出/ 激活 (代表神經(jīng)元的軸突)。一般來說每個節(jié)點的總和被加權,總和通過激活函數(shù)或傳遞函數(shù)傳遞。
這個組件為神經(jīng)網(wǎng)絡處理增加了非線性,這是因為自然神經(jīng)元具有非線性行為。在一些特殊情況下,它可以是一個線性函數(shù)。
維基百科提及到說:
一個標準的計算機芯片電路可以看作是一個激活功能的數(shù)字網(wǎng)絡,取決于輸入的是“ON”(1)還是“OFF”(0)。這與神經(jīng)網(wǎng)絡中的線性感知器的行為類似。然而, 非線性 激活函數(shù)允許這樣的網(wǎng)絡僅使用少量的節(jié)點來計算特殊問題。使用的流行的激活函數(shù)的例子是Sigmoid、雙曲正切、硬極限閾值和純線性。
將這些知識轉化為Java代碼,我們將有一個如下的神經(jīng)元類:
- 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(以下內容組成的神經(jīng)元模型): </br>
- * <ul>
- * <li>Summing part(求和部分) - input summing function(輸入求和函數(shù) )</li>
- * <li>Activation function(激活函數(shù))</li>
- * <li>Input connections(輸入連接)</li>
- * <li>Output connections(輸出連接)</li>
- * </ul>
- */
- public class Neuron {
- /**
- * Neuron's identifier
- * 神經(jīng)元標識符
- */
- private String id;
- /**
- * Collection of neuron's input connections (connections to this neuron)
- * 神經(jīng)元輸入連接的集合(與此神經(jīng)元的連接)
- */
- protected List < Connection > inputConnections;
- /**
- * Collection of neuron's output connections (connections from this to other
- * neurons)
- * 神經(jīng)元輸出連接的集合(從這個到其他神經(jīng)元的連接)
- */
- protected List < Connection > outputConnections;
- /**
- * Input summing function for this neuron
- * 該神經(jīng)元的輸入和函數(shù)
- */
- protected InputSummingFunction inputSummingFunction;
- /**
- * Activation function for this neuron
- * 這個神經(jīng)元的激活函數(shù)
- */
- protected ActivationFunction activationFunction;
- /**
- * Default constructor
- * 默認構造方法
- */
- public Neuron() {
- this.inputConnections = new ArrayList < > ();
- this.outputConnections = new ArrayList < > ();
- }
- /**
- * Calculates the neuron's output
- * 計算神經(jīng)元輸出
- */
- public double calculateOutput() {
- double totalInput = inputSummingFunction.getOutput(inputConnections);
- return activationFunction.getOutput(totalInput);
- }
- ...
- }
神經(jīng)元有輸入和輸出連接、輸入求和值和激活函數(shù),那輸入權重在哪里呢?它們包含在連接本身中,如下所示:
- /**
- * Represents a connection between two neurons an the associated weight.
- * 表示兩個神經(jīng)元之間的連接以及相關的權重
- */
- public class NeuronsConnection {
- /**
- * From neuron for this connection (source neuron). This connection is
- * output connection for from neuron.
- * 從神經(jīng)元中獲取這個連接(源神經(jīng)元)。此連接是來自神經(jīng)元的輸出連接
- */
- protected Neuron fromNeuron;
- /**
- * To neuron for this connection (target, destination neuron) This
- * connection is input connection for to neuron.
- * 對于用于此連接的神經(jīng)元(目標,目標神經(jīng)元),此連接是神經(jīng)元的輸入連接
- */
- protected Neuron toNeuron;
- /**
- * Connection weight
- * 連接權重
- */
- protected double weight;
- /**
- * Creates a new connection between specified neurons with random weight.
- * 在具有隨機權重的指定神經(jīng)元之間創(chuàng)建一個新的連接
- * @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
- * 創(chuàng)建與指定權重對象的指定神經(jīng)元的新連接
- *
- * @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.
- * 返回此連接的輸入 - 在此連接輸入神經(jīng)元中激活函數(shù)計算的結果
- * @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
- * 從神經(jīng)元獲取此連接
- * @return from neuron for this connection
- */
- public Neuron getFromNeuron() {
- return fromNeuron;
- }
- /**
- * Gets to neuron for this connection
- * 獲取用于此連接的神經(jīng)元
- * @return neuron to set as to neuron
- */
- public Neuron getToNeuron() {
- return toNeuron;
- }
- ...
- }
連接對象提供權重并負責計算輸入的權值。
求和函數(shù)被定義為接口,以便能夠替換神經(jīng)元的計算策略:
- import java.util.List;
- import edu.neuralnet.core.Connection;
- /**
- * Represents the inputs summing part of a neuron also called signal collector.
- * 神經(jīng)元的求和部分,也可以稱為信號收集器
- */
- public interface InputSummingFunction {
- /**
- * Performs calculations based on the output values of the input neurons.
- * 根據(jù)輸入神經(jīng)元的輸出值執(zhí)行計算
- * @param inputConnections
- * neuron's input connections
- * @return total input for the neuron having the input connections
- * 總輸入,具有輸入連接的神經(jīng)元
- */
- double collectOutput(List<Connection> inputConnections);
- }
分別實現(xiàn)為:
- import java.util.List;
- import edu.neuralnet.core.Connection;
- /**
- * Calculates the weighted sums of the input neurons' outputs.
- * 計算輸入神經(jīng)元輸出的加權和
- */
- 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;
- }
- }
激活函數(shù)的接口可以定義如下::
- /**
- * Neural networks activation function interface.
- * 神經(jīng)網(wǎng)絡激活函數(shù)的接口
- */
- public interface ActivationFunction {
- /**
- * Performs calculation based on the sum of input neurons output.
- * 基于輸入神經(jīng)元輸出的和來進行計算
- * @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);
- }
開始編寫代碼之前需要注意的***一個問題是神經(jīng)網(wǎng)絡層。神經(jīng)網(wǎng)絡由幾個鏈接層組成,形成所謂的多層網(wǎng)絡。神經(jīng)層可以分為三類:
- 輸入層
- 隱藏層
- 輸出層
在實踐中,額外的神經(jīng)層增加了另一個抽象層次的外部刺激,增強了神經(jīng)網(wǎng)絡認知更復雜知識的能力。
一個圖層類可以被定義為一個有連接的神經(jīng)元列表:
- 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.
- * 神經(jīng)網(wǎng)絡可以由多個連接層組成,形成所謂的多層網(wǎng)絡,
- * 一層可以定義為一組包含神經(jīng)網(wǎng)絡層的神經(jīng)元
- */
- public class NeuralNetLayer {
- /**
- * Layer's identifier
- * 層次標識符
- */
- private String id;
- /**
- * Collection of neurons in this layer
- * 該層神經(jīng)元的集合
- */
- protected List<Neuron> neurons;
- /**
- * Creates an empty layer with an id.
- * 用ID創(chuàng)建一個空層
- * @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.
- * 創(chuàng)建一個包含神經(jīng)元列表和id的層
- * @param id
- * layer's identifier 層次標識符
- * @param neurons
- * list of neurons to be added to the layer 添加到該層的神經(jīng)元列表
- */
- public NeuralNetLayer(String id, List<Neuron> neurons) {
- this.id = id;
- this.neurons = neurons;
- }
- ...
- }
***,用Java創(chuàng)建一個簡單的神經(jīng)網(wǎng)絡:
- /**
- * Represents an artificial neural network with layers containing neurons.
- * 含有神經(jīng)元層的人工神經(jīng)網(wǎng)絡
- */
- public class NeuralNet {
- /**
- * Neural network id
- * 神經(jīng)網(wǎng)絡ID
- */
- private String id;
- /**
- * Neural network input layer
- * 神經(jīng)網(wǎng)絡的輸入層
- */
- private NeuralNetLayer inputLayer;
- /**
- * Neural network hidden layers
- * 神經(jīng)網(wǎng)絡隱藏的層
- */
- private List<NeuralNetLayer> hiddenLayers;
- /**
- * Neural network output layer
- * 神經(jīng)網(wǎng)絡的輸出層
- */
- private NeuralNetLayer outputLayer;
- /**
- * Constructs a neural net with all layers present.
- * 構造一個具有所有層的神經(jīng)網(wǎng)絡
- * @param id
- * Neural network id to be set 設置神經(jīng)網(wǎng)絡標識
- * @param inputLayer
- * Neural network input layer to be set 設置神經(jīng)網(wǎng)絡的輸入層
- * @param hiddenLayers
- * Neural network hidden layers to be set 設置神經(jīng)網(wǎng)絡隱藏的層
- * @param outputLayer
- * Neural network output layer to be set 設置神經(jīng)網(wǎng)絡的輸出層
- */
- 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.
- * 構造一個沒有隱藏層的神經(jīng)網(wǎng)絡
- * @param id
- * Neural network id to be set 設置神經(jīng)網(wǎng)絡標識
- * @param inputLayer
- * Neural network input layer to be set 設置神經(jīng)網(wǎng)絡的輸入層
- * @param outputLayer
- * Neural network output layer to be set 設置神經(jīng)網(wǎng)絡隱藏的層
- */
- public NeuralNet(String id, NeuralNetLayer inputLayer, NeuralNetLayer outputLayer) {
- this.id = id;
- this.inputLayer = inputLayer;
- this.outputLayer = outputLayer;
- }
- ...
- }
我們所得到的是一個基于Java的神經(jīng)網(wǎng)絡層次、神經(jīng)元和連接的結構定義。我們也談到了一些關于激活函數(shù)的內容,并為它們定義了一個接口。為簡單起見,我們省略了各種激活函數(shù)的實現(xiàn)以及學習神經(jīng)網(wǎng)絡的基礎知識。這兩個主題將在本系列的后續(xù)文章中介紹。
原文鏈接:https://cloud.tencent.com/developer/article/1038393
作者:Daniela Kolarova
【本文是51CTO專欄作者“云加社區(qū)”的原創(chuàng)稿件,轉載請通過51CTO聯(lián)系原作者獲取授權】