制作简单神经网络的翻译我们该怎么办? 我们将尝试创建一个简单且非常小的神经网络,我们将对其进行
解释并
教会您区分某些事物。 同时,我们不会进入历史和数学的丛林(这类信息非常容易找到)-而是,我们将尝试通过图纸和代码向您和我们自己解释问题(不是可能的事实)。
神经网络中的许多术语与生物学有关,所以让我们从头开始:

大脑是一件复杂的事情,但也可以分为几个主要部分和操作:

病因也可以是
内部的 (例如,图像或想法):

现在让我们看一下大脑的基本
部分和简化
部分 :
大脑通常看起来像一个电缆网络。神经元是大脑中演算的主要单位,它接收并处理其他神经元的化学信号,并且根据多种因素,要么不执行任何操作,要么产生电脉冲或动作电位,然后通过突触将信号发送到相邻的
连接神经元:

梦想,记忆,自我调节的动作,反射以及实际上您认为或做的所有事情都归因于此过程:数百万甚至数十亿个神经元在不同的层次上工作,并建立可创建不同并行子系统并代表生物神经
网络的连接 。
当然,这些都是简化和概括,但是由于有了它们,我们可以描述一个简单的
神经网络:

并使用图形正式描述它:

这里需要一些澄清。 圆是神经元,线是它们之间的连接,
并且为了不使该阶段复杂化,该
关系是信息
从左到右的直接移动。 当前第一个神经元处于活动状态并变灰。 我们还为他分配了一个数字(1-如果有效,0-无效)。 神经元之间的数字表示连接的
权重 。
上图显示了网络的时刻,为了更精确地显示,您需要将其划分为以下时间段:
要创建自己的神经网络,您需要了解权重如何影响神经元以及如何训练神经元。 例如,以一只兔子(测试兔子)为例,将其置于经典实验条件下。

当安全的气流对准它们时,兔子像人一样眨眼:

此行为模型可以用图形表示:

如上图所示,这些图形仅显示兔子感到呼吸的瞬间,因此我们
将打击
编码为逻辑值。 另外,我们根据权重值计算是否触发了第二神经元。 如果为1,则感觉神经元被触发,我们眨眼; 如果重量小于1,我们不会眨眼:第二个神经元的
极限为 1。
我们再介绍一个元素-安全的声音信号:

我们可以对兔子的兴趣进行建模,如下所示:

主要区别在于现在的权重
为零 ,因此,至少到目前为止,我们还没有收到过眨眼的兔子。 现在教兔子在团队中眨眼,混合
刺激物(声音信号和呼吸):

这些事件在不同的时间
段发生很重要,在图中,它看起来像这样:

声音本身没有任何作用,但是气流仍然使兔子眨眼,我们通过重量乘以刺激(红色)来显示声音。
关于复杂行为的
学习可以简单地表示为连接的神经元之间的重量随时间逐渐变化。
要训练兔子,请重复以下步骤:

对于前三个尝试,方案将如下所示:

请注意,声音刺激的权重在每次重复后都会增加(以红色突出显示),该值现在是任意的-我们选择了0.30,但是数字可以是任意值,甚至是负数。 在第三次重复之后,您不会注意到兔子的行为发生变化,但是在第四次重复之后,将会发生一些令人惊讶的事情-行为会发生变化。

我们从空中消除了这种效果,但是兔子听到哔哔声后仍在眨眼! 最后一个行为可以解释此行为:

我们训练兔子通过眨眼来响应声音。
在这种真实的实验中,可能需要超过60次重复才能获得结果。现在我们将离开大脑和兔子的生物世界,并尝试适应一切
学会了创建人工神经网络。 首先,让我们尝试做一个简单的任务。
假设我们有一台带有四个按钮的机器,当您按下向右按钮时会发出食物
按钮(或者,如果您是机器人,则为能量)。 任务是找出哪个按钮给予奖励:

我们可以按如下方式(示意性地)描述按钮的作用:

最好整体解决此问题,所以让我们看一下所有可能的结果,包括正确的结果:
按下第3个按钮开始用餐。为了用代码重现神经网络,我们首先需要创建一个可以与网络关联的模型或图形。 这是一张适合该任务的图表,此外,它还很好地展示了其生物学对应物:

这个神经网络只接收传入的信息-在这种情况下,它将是按下哪个按钮的感知。 此外,网络用权重替换输入的信息,并基于层的添加得出结论。 这听起来有点令人困惑,但是让我们看看按钮在我们的模型中是如何呈现的:
请注意,所有权重都为0,因此神经网络就像婴儿一样,是完全空的,但是完全互连。因此,我们将外部事件与神经网络的输入层进行比较,并在其输出处计算值。 它可能与现实不吻合,但现在我们将忽略它并开始以计算机友好的方式描述任务。 让我们从输入权重开始(我们将使用JavaScript):
var inputs = [0,1,0,0]; var weights = [0,0,0,0];
下一步是创建一个函数,该函数收集输入值和权重并在输出处计算值:
function evaluateNeuralNetwork(inputVector, weightVector){ var result = 0; inputVector.forEach(function(inputValue, weightIndex) { layerValue = inputValue*weightVector[weightIndex]; result += layerValue; }); return (result.toFixed(2)); }
如预期的那样,如果运行此代码,我们将获得与模型或图形相同的结果...
evaluateNeuralNetwork(inputs, weights);
实时示例:
Neural Net 001 。
改善神经网络的下一步将是一种检查其自身输出或结果值与实际情况可比的方法,
让我们首先将此特定现实编码为变量:

为了检测不一致(以及不一致),我们添加了一个错误函数:
Error = Reality - Neural Net Output
有了它,我们可以评估神经网络的性能:

但更重要的是,在现实带来积极成果的情况下呢?

现在我们知道我们的神经网络模型不起作用(而且我们知道多少),太好了! 很好,因为现在我们可以使用误差函数来控制学习了。 但是,如果我们按以下方式重新定义错误函数,那么所有这些都将是有意义的:
Error = <b>Desired Output</b> - Neural Net Output
难以捉摸但又如此重要的差异,默认显示我们将
使用先前获得的结果与未来的行动进行比较
(以及培训,我们将在后面介绍)。 它存在于现实生活中,充满
重复模式,因此它可以成为一种进化策略(嗯,在
大多数情况下)。
接下来,在示例代码中,我们将添加一个新变量:
var input = [0,0,1,0]; var weights = [0,0,0,0]; var desiredResult = 1;
还有一个新功能:
function evaluateNeuralNetError(desired,actual) { return (desired — actual); }
实时示例:
Neural Net 002 。
归纳小计 。 我们从任务开始,以生物神经网络的形式建立了简单的模型,并获得了一种方法来衡量其与实际情况或所需结果的性能。 现在,我们需要找到一种纠正差异的方法-这个过程可以视为对计算机和人员的培训。
如何训练神经网络?教授生物和人工神经网络的基础是重复
和
训练算法 ,因此我们将分别与它们合作。 从开始
学习算法。
本质上,学习算法被理解为物理或化学的变化
实验后神经元的特征:

关于两个神经元如何在代码中随时间变化的生动说明,而我们的模型“学习算法”意味着我们将随时间进行某些更改以使我们的生活更轻松。 因此,让我们添加一个变量来指示生活的便利程度:
var learningRate = 0.20;
它将发生什么变化?这将改变重量(就像兔子一样!),尤其是我们想要的输出的重量:

如何编码这样的算法是您的选择,为简单起见,我将权重添加训练系数,这里以函数的形式表示:
function learn(inputVector, weightVector) { weightVector.forEach(function(weight, index, weights) { if (inputVector[index] > 0) { weights[index] = weight + learningRate; } }); }
使用该学习功能时,只需在训练圈(或重复)之前和之后将我们的学习系数添加到
活动神经元的权重向量中,结果将如下所示:
实时示例:
Neural Net 003 。
好的,既然我们朝着正确的方向前进,那么这个难题的最后一个细节就是引入
重复 。
并不是那么困难,本质上,我们只是一遍又一遍地做同样的事情,而在代码中,我们只是指出重复的次数:
var trials = 6;
在训练神经网络中引入重复次数的函数如下所示:
function train(trials) { for (i = 0; i < trials; i++) { neuralNetResult = evaluateNeuralNetwork(input, weights); learn(input, weights); } }
好吧,我们的最终报告:
Neural Net output: 0.00 Error: 1.00 Weight Vector: [0,0,0,0] Neural Net output: 0.20 Error: 0.80 Weight Vector: [0,0,0.2,0] Neural Net output: 0.40 Error: 0.60 Weight Vector: [0,0,0.4,0] Neural Net output: 0.60 Error: 0.40 Weight Vector: [0,0,0.6,0] Neural Net output: 0.80 Error: 0.20 Weight Vector: [0,0,0.8,0] Neural Net output: 1.00 Error: 0.00 Weight Vector: [0,0,1,0]
实时示例:
Neural Net 004 。
现在,如果输入向量与现实相对应(按第三个按钮),那么我们就有一个权重向量,它只会给出一个结果(晚餐用鸡)。
那么,我们刚刚做了什么呢?在这种特殊情况下,我们的神经网络(经过训练)可以识别输入数据并说出将导致所需结果的内容(我们仍然需要对特定情况进行编程):

此外,它是我们培训的可扩展模型,玩具和工具。 我们能够学习有关机器学习,神经网络和人工智能的新知识。
对用户的警告:
- 没有提供用于所研究秤的存储机制,因此该神经网络将忘记它所知道的一切。 更新或重新启动代码时,如果您认为某个人或一台机器会随机按下按钮,则至少需要成功进行六次重试,以便对网络进行全面的培训。这将需要一些时间。
- 用于学习重要事物的生物网络的学习速度为1,因此您只需要成功重复一次即可。
- 有一种学习算法与生物神经元非常相似,它的名称很容易理解 : widroff-hoff规则或widroff-hoff训练 。
- 没有考虑到神经元的阈值(在我们的示例中为1)和再训练的效果(重复多次,结果将超过1),但它们在本质上非常重要,并且负责行为反应的大块和复杂块。 像负重。
注释和参考资料,以供进一步阅读
我试图避免使用数学和严格的术语,但是如果您感兴趣,我们构建了一个
感知器 ,将其定义为
双重分类器的监督学习(
与老师一起教学 )的算法-很难。
大脑的生物学结构不是一个简单的话题,部分是由于不准确,部分是由于其复杂性。 最好从神经科学(Purves)和认知神经科学(Gazzaniga)开始。 我修改并改编了从“网关到内存”(Gluck)的“兔子”示例,这对图形世界也是一个很好的指南。
另一个出色的资源,《神经网络入门》(Gurney)适合您所有与AI相关的需求。
现在使用Python! 感谢Ilya Andschmidt提供的Python版本:
inputs = [0, 1, 0, 0] weights = [0, 0, 0, 0] desired_result = 1 learning_rate = 0.2 trials = 6 def evaluate_neural_network(input_array, weight_array): result = 0 for i in range(len(input_array)): layer_value = input_array[i] * weight_array[i] result += layer_value print("evaluate_neural_network: " + str(result)) print("weights: " + str(weights)) return result def evaluate_error(desired, actual): error = desired - actual print("evaluate_error: " + str(error)) return error def learn(input_array, weight_array): print("learning...") for i in range(len(input_array)): if input_array[i] > 0: weight_array[i] += learning_rate def train(trials): for i in range(trials): neural_net_result = evaluate_neural_network(inputs, weights) learn(inputs, weights) train(trials)
现在开始! 感谢您使用此版本的Kieran Maher。
package main import ( "fmt" "math" ) func main() { fmt.Println("Creating inputs and weights ...") inputs := []float64{0.00, 0.00, 1.00, 0.00} weights := []float64{0.00, 0.00, 0.00, 0.00} desired := 1.00 learningRate := 0.20 trials := 6 train(trials, inputs, weights, desired, learningRate) } func train(trials int, inputs []float64, weights []float64, desired float64, learningRate float64) { for i := 1; i < trials; i++ { weights = learn(inputs, weights, learningRate) output := evaluate(inputs, weights) errorResult := evaluateError(desired, output) fmt.Print("Output: ") fmt.Print(math.Round(output*100) / 100) fmt.Print("\nError: ") fmt.Print(math.Round(errorResult*100) / 100) fmt.Print("\n\n") } } func learn(inputVector []float64, weightVector []float64, learningRate float64) []float64 { for index, inputValue := range inputVector { if inputValue > 0.00 { weightVector[index] = weightVector[index] + learningRate } } return weightVector } func evaluate(inputVector []float64, weightVector []float64) float64 { result := 0.00 for index, inputValue := range inputVector { layerValue := inputValue * weightVector[index] result = result + layerValue } return result } func evaluateError(desired float64, actual float64) float64 { return desired - actual }