简单的多层神经网络实现
不久前,我开始了我的机器学习之旅(在我学习的最后两年里)。我读了很多书,也写了很多关于机器学习算法的代码,但神经网络的部分我一直没碰过。我对这个话题非常感兴趣,但我遇到了一个大问题:
- 我读的书里有很多数学公式。上完课后,我对这些公式比较熟悉,自己在纸上也能做出计算。
- 书里的例子通常很复杂,比如研究网上商店的销售数据,要理解神经网络的实现,我得写很多代码来复现这些复杂的背景。其实我想要的是简单直接的实现,不需要那么多背景和公式。
你能推荐一些简单的多层感知器(神经网络)的实现吗?我不需要理论知识,也不想要那些复杂背景的例子。我更喜欢用一些脚本语言来节省时间和精力——我之前99%的工作都是用Python完成的。
这是我之前读过的书单(但没有找到我想要的内容):
- 《机器学习实战》
- 《编程集体智慧》
- 《机器学习:算法视角》
- 《Java神经网络入门》
- 《C#神经网络入门》
5 个回答
这里有一个例子,教你如何用numpy来实现一个前馈神经网络。首先,你需要导入numpy,并指定输入和目标的维度。
import numpy as np
input_dim = 1000
target_dim = 10
接下来,我们来搭建网络结构。正如Bishop在他的《模式识别与机器学习》一书中提到的,你可以把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)
如果你的输入存储在一个二维的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
的最后一个元素循环到第一个。在每次反向传播之前,确保将每一层的误差信号中的偏置列设置为零。
嗯,这个问题有点棘手。我之前也遇到过同样的问题,找不到既简单易懂又不那么复杂的数学解释和现成的实现方案之间的东西。
像PyBrain这样的现成实现方案的问题在于,它们隐藏了很多细节,所以那些想学习如何实现人工神经网络(ANN)的人需要其他的资源。阅读这些解决方案的代码也可能很有挑战性,因为它们通常使用一些技巧来提高性能,这让初学者很难理解代码。
不过,有一些资源你可以利用:
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/
一个简单的实现
这里有一个使用 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 仓库。