简单多层神经网络实现

28

我之前开始了机器学习的探险(在我过去两年的学习中)。我读了很多书,写了很多有关机器学习算法的代码,但神经网络却超出了我的范围。这个话题非常吸引我,但我遇到了一个大问题:

  1. 这些书籍包含大量数学公式。在讲完课后,我对它们相当熟悉,并且可以手动在纸上进行计算。
  2. 这些书籍包含嵌入一些复杂上下文环境中的大型示例(例如调查互联网商店销售率),为了深入神经网络实现,我必须编写大量代码来重现上下文。缺少什么——简单直接的实现,没有太多上下文和公式。

请问您能否告诉我哪里可以找到多层感知(神经网络)的简单实现?我不需要理论知识,也不需要上下文嵌入的例子。我更喜欢一些脚本语言来节省时间和精力——我以前99%的工作都是用Python完成的。

以下是我以前阅读过的书籍列表(没有找到我想要的内容):

  1. 机器学习实战
  2. 编程集体智慧
  3. 机器学习:算法的视角
  4. Java神经网络导论
  5. C#神经网络导论

Python是必须的吗?也许,使用“Octave”手动尝试会更合适。 - alko
简单实现 https://github.com/AmaldevTA/ML_Basics/blob/master/003_Neural_Networks/Neural_network.ipynb - Amaldev
5个回答

32

一个简单的实现

这是一个使用Python类编写的易于阅读的实现。该实现以易懂性为代价来换取效率:

    import math
    import random

    BIAS = -1

    """
    To view the structure of the Neural Network, type
    print network_name
    """

    class Neuron:
        def __init__(self, n_inputs ):
            self.n_inputs = n_inputs
            self.set_weights( [random.uniform(0,1) for x in range(0,n_inputs+1)] ) # +1 for bias weight

        def sum(self, inputs ):
            # Does not include the bias
            return sum(val*self.weights[i] for i,val in enumerate(inputs))

        def set_weights(self, weights ):
            self.weights = weights

        def __str__(self):
            return 'Weights: %s, Bias: %s' % ( str(self.weights[:-1]),str(self.weights[-1]) )

    class NeuronLayer:
        def __init__(self, n_neurons, n_inputs):
            self.n_neurons = n_neurons
            self.neurons = [Neuron( n_inputs ) for _ in range(0,self.n_neurons)]

        def __str__(self):
            return 'Layer:\n\t'+'\n\t'.join([str(neuron) for neuron in self.neurons])+''

    class NeuralNetwork:
        def __init__(self, n_inputs, n_outputs, n_neurons_to_hl, n_hidden_layers):
            self.n_inputs = n_inputs
            self.n_outputs = n_outputs
            self.n_hidden_layers = n_hidden_layers
            self.n_neurons_to_hl = n_neurons_to_hl
    
            # Do not touch
            self._create_network()
            self._n_weights = None
            # end

        def _create_network(self):
            if self.n_hidden_layers>0:
                # create the first layer
                self.layers = [NeuronLayer( self.n_neurons_to_hl,self.n_inputs )]
        
                # create hidden layers
                self.layers += [NeuronLayer( self.n_neurons_to_hl,self.n_neurons_to_hl ) for _ in range(0,self.n_hidden_layers)]
        
                # hidden-to-output layer
                self.layers += [NeuronLayer( self.n_outputs,self.n_neurons_to_hl )]
            else:
                # If we don't require hidden layers
                self.layers = [NeuronLayer( self.n_outputs,self.n_inputs )]

        def get_weights(self):
            weights = []
    
            for layer in self.layers:
                for neuron in layer.neurons:
                    weights += neuron.weights
    
            return weights

        @property
        def n_weights(self):
            if not self._n_weights:
                self._n_weights = 0
                for layer in self.layers:
                    for neuron in layer.neurons:
                        self._n_weights += neuron.n_inputs+1 # +1 for bias weight
            return self._n_weights

        def set_weights(self, weights ):
            assert len(weights)==self.n_weights, "Incorrect amount of weights."
    
            stop = 0
            for layer in self.layers:
                for neuron in layer.neurons:
                    start, stop = stop, stop+(neuron.n_inputs+1)
                    neuron.set_weights( weights[start:stop] )
            return self

        def update(self, inputs ):
            assert len(inputs)==self.n_inputs, "Incorrect amount of inputs."
    
            for layer in self.layers:
                outputs = []
                for neuron in layer.neurons:
                    tot = neuron.sum(inputs) + neuron.weights[-1]*BIAS
                    outputs.append( self.sigmoid(tot) )
                inputs = outputs   
            return outputs

        def sigmoid(self, activation,response=1 ):
            # the activation function
            try:
                return 1/(1+math.e**(-activation/response))
            except OverflowError:
                return float("inf")

        def __str__(self):
            return '\n'.join([str(i+1)+' '+str(layer) for i,layer in enumerate(self.layers)])

更高效的实现(带学习)

如果你正在寻找一个带有学习(反向传播)的神经网络更高效的例子,请查看我的神经网络Github代码库


update方法的参数应该是什么?最好附上一个例子。 - Coding man
输入值列表。例如:input_values = [1, 0, 0, 1, 0.5] - jorgenkg
13
培训方面怎么样? - Llamageddon
一个真正懂得如何编写代码和命名变量的人所编写的示例!我发现Github仓库非常有帮助。 - Ryder Brooks

7
这有点棘手。我之前也遇到过同样的问题,但我找不到介于数学知识丰富但难以理解和可直接使用的实现之间的好方法。
像PyBrain这样的“可直接使用”的实现存在一个问题,即它们隐藏了细节,因此对于想要学习如何实现人工神经网络的人来说,需要其他东西。阅读这些解决方案的代码也可能具有挑战性,因为它们通常使用启发式算法来提高性能,这使得代码对于初学者更难跟踪。
然而,您可以使用一些资源:

http://msdn.microsoft.com/en-us/magazine/jj658979.aspx

http://itee.uq.edu.au/~cogs2010/cmc/chapters/BackProp/

http://www.codeproject.com/Articles/19323/Image-Recognition-with-Neural-Networks

http://freedelta.free.fr/r/php-code-samples/artificial-intelligence-neural-network-backpropagation/


6

这里是一个使用numpy实现前馈神经网络的例子。首先导入numpy并指定输入和目标的维度。

import numpy as np

input_dim = 1000
target_dim = 10

我们现在要构建网络结构。正如Bishop的经典著作"Pattern Recognition and Machine Learning"所建议的那样,您可以将您的numpy矩阵的最后一行视为偏置权重,将您的激活的最后一列视为偏置神经元。第一个/最后一个权重矩阵的输入/输出维度需要增加1。
dimensions = [input_dim+1, 500, 500, target_dim+1]

weight_matrices = []
for i in range(len(dimensions)-1):
  weight_matrix = np.ones((dimensions[i], dimensions[i]))
  weight_matrices.append(weight_matrix)

如果您的输入存储在一个2d numpy矩阵中,其中每行对应一个样本,每列对应于样本的属性,则可以按如下方式通过网络进行传播:(假设逻辑sigmoid函数作为激活函数)

def activate_network(inputs):
  activations = [] # we store the activations for each layer here
  a = np.ones((inputs.shape[0], inputs.shape[1]+1)) #add the bias to the inputs
  a[:,:-1] = inputs

  for w in weight_matrices:
    x = a.dot(w) # sum of weighted inputs
    a = 1. / (1. - np.exp(-x)) # apply logistic sigmoid activation
    a[:,-1] = 1. # bias for the next layer.
    activations.append(a)

  return activations
activations中的最后一个元素将是您网络的输出,但要注意,您需要省略偏置项的额外列,因此您的输出将为activations[-1][:,:-1]
要训练网络,您需要实现反向传播,这需要几行额外的代码。基本上,您需要从activations的最后一个元素循环到第一个元素。在每个反向传播步骤之前,请确保将误差信号中的偏置列设置为零。

5
这里是一个使用原生 Python 实现的反向传播算法,代码可以在这里找到。

0

2
嗨!谢谢回复。不,我还没有尝试过PyBrain,因为我想自己做所有的事情:P 我正在寻找教程,而不是其他已经准备好的解决方案,即使它有很好的文档记录。但如果没有更好的选择,这听起来像一个计划 :) - Animattronic

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接