【问题标题】:Law of demeter -- need for internal representation?得墨忒耳定律——需要内部表示吗?
【发布时间】:2014-12-09 21:00:33
【问题描述】:

假设我们有一个“神经网络”类

  • 每个神经网络都由层组成
  • 每一层都由神经元组成
  • 每个神经元由权重、偏差和激活函数组成

    class Neuron:
        def __init__(self,weights,bias,activation):
            self._weights = weights
            self._bias = bias
            self._activation = activation
    
        def activate(self,input):
            return self._activation.compute(self._weights.dot(input)+self._bias)
    
    
    class Layer:
        def __init__(self,neurons):
            self._neurons = neurons
    
        def compute(self,input):
            output = []
            for neuron in self._neurons:
                output.append(neuron.activate(input))
            return output
    
    
    class NeuralNetwork:
        def __init__(self,layers):
            self._layers = layers
    
        def compute(self,input):
            output = input
            for layer in self._layers:
                output = layer.compute(output)
            return output
    
        def train(self,dataset):
            # do some training
            # changes the neurons inside the layers
    

NeuralNetwork 有一个方法 train() 可以改变其内部表示。 但这意味着可以访问 Layer 对象的内部。它需要访问单个神经元,这违反了得墨忒耳定律。 例如

layers[0].getNeuron(0).compute(input)

layer[0].getNeuron(0).changeBias(2)

我能想到的唯一解决方案是在“层”中提供额外的方法并将其委托给神经元。这也将允许我使用 Layer 接口的不同实现。一种更灵活,一种性能更好。

但这似乎很麻烦。没有更好的方法来建模吗?

【问题讨论】:

  • train 如何选择要修改的神经元还不是很清楚。但除此之外,我怀疑观察者模式可以提供一种可能的替代方案。神经元会订阅层上的事件,train 会将事件发布到层。这样,层将成为“转储”中间体,即神经元中的实际处理,同时保持 demeter 定律。
  • 但这会引入循环依赖,因为层仍然需要了解神经元来计算其输出。因此,由于所有内容都发布到该层,因此我认为简单的提供委托方法没有优势。我添加了一个图表来描述我的问题。我想要删除的是 Network 和 Neuron 之间的依赖关系。 train 方法的工作原理无关紧要。它基本上会进行一些计算并更改所有单个神经元的权重。
  • 神经元不知道层。层会订阅它们并调用它们的事件处理方法,就像它现在在您的代码中调用它们的 activate() 方法一样。 NetworkNeuron 之间的链接将被破坏,Layer 不需要提供任何包装方法,只需一个用于将事件委托给神经元。
  • 这样的? train() 组装具有特定神经元“地址”的 Event 对象并将其发布到层 layer.publish(event)。现在层可能会将其广播给所有神经元或对其进行部分解析,发现地址并将其发送到正确的神经元neuron.parse(event)
  • 如果你违反了得墨忒耳法则怎么办?这只是一个指导方针。过度依赖/耦合(违反 Demeter 定律)是不好的,因为对其他事物所依赖的事物的更改可能会有害地传播。 Neuron 有多“不稳定”?如果你愿意忍受它是稳定的,那么不要担心得墨忒耳法则。

标签: python oop design-patterns


【解决方案1】:

第一个可能的解决方案是添加一些委托的方法。

从 Amr Mostafa 的 cmets 中提取的第二种解决方案是通过 Layer 对象向神经元发送一个事件。

这两种解决方案都允许我们使用不同的 Layer 对象,该对象由多维数组组成,而不是神经元对象(性能考虑)。

【讨论】:

  • 这打破了 KISS 模式。设计是权衡。如果您觉得这些解决方案的额外复杂性降低了神经元从根本上改变其方法的风险(这就是得墨忒耳法则发挥作用的原因),那么就去做吧。就个人而言,在添加所有这些事件复杂性之前,我会使用更简单的模型并等待一些痛苦和不稳定的痛苦。调试时必须忍受它,并在几个月后想要更改某些内容时记住它的复杂性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多