我一直在研究Yann LeCun和他的同事在1994年引入的用于识别签名的暹罗神经网络的体系结构(“使用暹罗时延神经网络进行签名验证”。pdf,NIPS 1994)。

我在理解此暹罗神经网络模型的一般体系结构时遇到了一些问题,并在Cross Validated上与一位朋友讨论过。我想我终于理解了,所以现在我要进行下一步:实现它。
我们最后指出,全局算法应该类似于:网络convNetA,用于第一个签名。
创建卷积神经网络convNetB,用于第二个签名。
将convNetA权重与convNetB权重相结合。
设置余弦相似度函数以计算损失。
(向前和向后)进行训练。

我是Torch的新手,所以我真的不知道如何实现此算法。这是我的第一个版本:
-- training
function gradientUpdate(perceptron, dataset, target, learningRate, max_iterations)

for i = 1, max_iterations do

      predictionValue = perceptron:forward(dataset)
       -- is this the cosine similarity?
  -- [output] forward(input): 
  -- Takes an input object, and computes the corresponding output of the module. In general input and output are Tensors. 

      
      io.write(" pre-predictionValue= "..predictionValue .."\n");

      -- the minus is because we're goin' backwards
      gradientWrtOutput = torch.Tensor({-target})

      perceptron:zeroGradParameters() -- zeroGradParameters(): If the module has parameters, this will zero the accumulation of the gradients with respect to these parameters, accumulated through accGradParameters(input, gradOutput,scale) calls. Otherwise, it does nothing.
      -- initialization

      perceptron:backward(dataset, gradientWrtOutput) -- Performs a backpropagation step through the module, with respect to the given input. 

      perceptron:updateParameters(learningRate)
  end

end

require "os"
require "nn"

input_number=5
output_number=2

-- imagine we have one network we are interested in, it is called "perceptronAAA"
perceptronAAA= nn.Sequential(); 
perceptronAAA:add(nn.Linear(input_number, output_number))

-- But we want to push examples towards or away from each other
-- so we make another copy of it called perceptronBBB
-- this *shares* the same weights via the set command, but has its own set of temporary gradient storage
-- that's why we create it again (so that the gradients of the pair don't wipe each other)
perceptronBBB= perceptronAAA:clone('weight', 'bias')

-- we make a parallel table that takes a pair of examples as input. they both go through the same (cloned) perceptron
-- ParallelTable is a container module that, in its forward() method, applies the i-th member module to the i-th input, and outputs a table of the set of outputs.
parallel_table = nn.ParallelTable()
parallel_table:add(perceptronAAA)
parallel_table:add(perceptronBBB)

-- now we define our top level network that takes this parallel table and computes the cosine distance betweem
-- the pair of outputs
perceptron= nn.Sequential()
perceptron:add(parallel_table)
perceptron:add(nn.CosineDistance())


-- lets make two example vectors
x_vector = torch.rand(input_number)
y_vector = torch.rand(input_number)
dataset = {x_vector, y_vector}

function dataset:size() return #dataset end


-- matrix having 5 rows * 2 columns
max_iterations = 100
learnRate = 0.1
target = 1 -- the target for cosine similarity is +1 on forwards, that becomes -1 on backwards

-- TRAINING:

-- push the pair x_vector and y_vector together, the distance should get larger..


 gradientUpdate(perceptron, dataset, target, learnRate, max_iterations)

您认为这是具有最小化余弦相似度函数的暹罗神经网络的正确实现吗?还是您会看到其中的任何错误/错误内容?
EDIT 2020年10月:谢谢大家在过去5年中帮助我理解了该模型!我最近出版了一本书,解释了我对暹罗神经网络的理解,并报告了我在科学文献中发现的该模型的所有可能应用。您可以在这里找到它:“暹罗神经网络:概述”。
我希望您会发现它很有用:如果这本书的章节现在存在,那也是因为你们提供了当时的出色帮助。再次感谢!

评论

真是太酷了,您的灵感是什么?

对设计的简要评论:进行信号验证时,航空电子工程使用3个必须在不同的数据集上进行训练的系统:主系统接收输入并产生输出信号。然后,使用二次和三次系统来检查一次系统信号。如果二级和三级系统不一致,则系统1被认为有故障,并且信号被转储。这是双重冗余验证,对于关键任务黑匣子系统非常有用。这种方法应该可以简化您的架构。

自从我回答以来,我发现您已经加入了Code Review,并且我对您的反馈意见很感兴趣。请对我的回答发表评论,或在第二监视器中给我发消息。如果您认为值得,那么答案也可以接受。

@ syb0rg您的回答看起来很有趣,但是没有回答我的问题。我问:“您认为这是具有最小化余弦相似度函数的暹罗神经网络的正确实现吗?”你认为是不是?谢谢

@ DavideChicco.it是的,但是您确实了解“代码审查”的重点是改进代码,对吗?您应该亲自验证它是否正确。

#1 楼

我认为这是一个很棒的项目!但这可以做一些改进:


Neuron Type(1)


假设我们有一个我们想要的感知器网络用来学习解决一些问题。例如,网络的输入可能是来自签名扫描图像的原始像素数据。我们希望网络学习权重和偏见,以便网络的输出正确地对数字进行分类。为了了解学习的工作原理,假设我们对网络中的某些权重(或偏见)进行了小的更改。我们想要的是重量的微小变化仅导致网络输出的相应微小变化。


权重(或偏差)的变化只会导致输出的微小变化,然后我们可以利用这一事实来修改权重和偏差,以使我们的网络以所需的方式发挥更大的作用。例如,假设网络在应为“ o”时将图像错误地分类为“ c”。我们可以弄清楚如何对权重和偏差进行小的更改,以便网络更接近地将图像分类为“ o”。然后我们重复一遍,不断改变权重和偏差以产生越来越好的输出。该网络将在学习。

问题在于,当我们的网络包含感知器时,不会发生这种情况。实际上,网络中任何单个感知器的权重或偏差的微小变化有时都可能导致该感知器的输出完全翻转,例如从0到1。该翻转可能导致网络其余部分的行为变为以非常复杂的方式完全改变。因此,尽管现在可以正确地对“ o”进行分类,但是在所有其他图像上的网络行为可能已经以某种难以控制的方式完全改变了。这使得很难看到如何逐渐改变权重和偏差,以使网络更接近所需的行为。也许有一些解决此问题的聪明方法。但是,如何获得一个感知器网络来学习还不是很明显。

我们可以通过引入一种新型的人工神经元(称为S型神经元)来克服这个问题。乙状结肠神经元类似于感知器,但经过修饰后,其权重和偏差的细微变化只会导致其输出的细微变化。这就是至关重要的事实,它将允许S形神经元网络学习。

就像感知器一样,S形神经元具有输入,\ $ x1 \ $,\ $ x2 \ $,...但是这些输入不仅可以是0或1,还可以采用0到1之间的任何值。因此,例如,0.638是S型神经元的有效输入。 br乙状结肠神经元定义为:

$$ \ sigma(z)= \ dfrac {1} {1 + e ^ {-z}} $$

炬在这里实现了这种神经元类型。

(1)摘录,其中包括来自神经网络和深度学习的少量编辑


成本函数

>在您的代码中,我看不到使用任何成本函数。我建议您阅读《神经网络和深度学习》中的本节,以充分了解为什么应该使用它。

简而言之,代价函数返回一个数字,该数字表示神经网络在映射训练示例以纠正输出方面的表现。基本思想是,我们的网络越无法达到预期的结果,成本就越高,我们就越需要调整权重和偏差以实现更低的成本。我们尝试使用诸如梯度下降之类的方法来最小化此成本。局部最优)。正如书中所建议的那样,我倾向于使用交叉熵代价函数。

我们在Torch中实现此方法的方法是Criterions。火炬似乎已经实现了许多这样的成本函数,我鼓励您尝试不同的成本函数,看看它们如何影响您的神经网络准确性。


过拟合

您可能会非常适合您的数据,以至于我们无法很好地概括。图片中提供了一个示例:



线性函数和多项式函数都拟合有噪声的线性数据。尽管多项式函数非常适合,但线性版本可以更好地概括数据。

我不太了解Lua,但是通过查看您的代码,我看不出有任何尝试来简化-配件。解决此问题的常用方法是实施正则化。由于这里的话题太难了,因此如果您愿意,我会让您理解。了解其概念后,使用起来非常简单,您可以从此处的Torch实现中看到。

减少过度拟合的另一种方法是引入辍学。在每个训练阶段,各个节点都从网络中“掉线”,从而留下了简化的网络。在该阶段,仅精简网络接受有关数据的训练。然后,将已删除的节点以其原始权重重新插入网络。这些节点对其他节点的权重变得更加不敏感,并且他们学习如何自行决策。

下降还可以显着提高训练速度,同时提高性能(对深度学习很重要)!


梯度检查

更多由于模型复杂,梯度计算很难调试和正确解决。有时,错误的实现会设法学习看似合理的东西(同时表现不如正确的实现好)。因此,即使使用了错误的实现,也可能根本看不到任何不妥之处。因此,您应该用数字方式检查由代码计算出的导数,以确保您的实现正确。请注意,此检查在计算上是昂贵的,因此一旦您确认反向传播的实现是正确的,就应该关闭梯度检查。


主成分分析

PCA可用于数据压缩以加快学习算法的速度,也可用于可视化特征关系。基本上,在这种情况下,如果您拥有一个完整的自变量集,PCA可以帮助您找出最重要的变量,并消除其他变量(例如,将厘米和英寸作为输入特征,我们只需要一个就可以得到相同的信息)。

查看您链接的研究论文,看来只有10个特征输入到神经网络。但是对我来说,看起来我们可以摆脱2个,可能是3个功能!对于我们拥有的一些功能来说,这是相当多的。函数\ $ \ sin \ $和\ $ \ cos \ $是相互关联的,为什么当我们只使用一个并将相同的信息输入到神经网络时,为什么既需要测量轨迹的方向又要测量曲率?

还可以提出这样的论点,即向心加速度和切向加速度是相互关联的,或者由于\ $ a_c = \ frac {v ^ 2} {r} \ $。该软件需要进行更多分析才能彻底确定。 PCA也不用于处理过度拟合(因为当存在许多功能时通常会发生过度拟合)。这里有一个不错的GitHub存储库,涵盖了使用Torch的PCA。