当前位置:嗨网首页>书籍在线阅读

13-层的实现

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

7.4.2 层的实现

本章的神经网络中的层对象需要维护3种状态数据:所含神经元、其上一层和输出缓存。输出缓存类似于神经元的缓存,但高一个级别。它缓存了层中每一个神经元在调用激活函数之后的输出。

在创建时,层对象的主要职责是初始化其内部的神经元。因此, Layer 类的 __init__() 方法需要知道应该初始化多少个神经元,它们的激活函数是什么,以及它们的学习率为多少。在本章这个简单的神经网络中,层中的每个神经元都有相同的激活函数和学习率。具体代码如代码清单7-4所示。

代码清单7-4 layer.py(续)

from __future__ import annotations
from typing import List, Callable, Optional
from random import random
from neuron import Neuron
from util import dot_product
class Layer:
    def __init__(self, previous_layer: Optional[Layer], num_neurons: int, learning_
      rate: float, activation_function: Callable[[float], float], derivative_activation_
      function: Callable[[float], float]) -> None:
       self.previous_layer: Optional[Layer] = previous_layer
       self.neurons: List[Neuron] = []
       # the following could all be one large list comprehension 
       for i in range(num_neurons):
           if previous_layer is None:
               random_weights: List[float] = []
           else:
               random_weights = [random() for _ in range(len(previous_layer.neurons))]
           neuron: Neuron = Neuron(random_weights, learning_rate, activation_function, 
             derivative_activation_function)
           self.neurons.append(neuron)
       self.output_cache: List[float] = [0.0 for _ in range(num_neurons)]

当信号在神经网络中前馈时, Layer 必须让每个神经元都对其进行处理。请记住,层中的每个神经元都会接收到上一层中每个神经元传入的信号。 outputs() 正是如此处理的。 outputs() 还会返回处理后的结果(以便经由网络传递到下一层)并将输出缓存一份。如果不存在上一层,则表示本层为输入层,只要将信号向前传递给下一层即可。具体代码如代码清单7-5所示。

代码清单7-5 layer.py(续)

def outputs(self, inputs: List[float]) -> List[float]:
    if self.previous_layer is None:
        self.output_cache = inputs
    else:
        self.output_cache = [n.output(inputs) for n in self.neurons]
    return self.output_cache

在反向传播时需要计算两种不同类型的delta:输出层中神经元的delta和隐藏层中神经元的delta。图7-4和图7-5中分别给出了公式的描述,代码清单7-6中的两个方法只是机械地将公式转换成了代码。稍后在反向传播过程中神经网络对象将会调用这两个方法。

代码清单7-6 layer.py(续)

# should only be called on output layer
def calculate_deltas_for_output_layer(self, expected: List[float]) -> None:
    for n in range(len(self.neurons)):
        self.neurons[n].delta = self.neurons[n].derivative_activation_function
        (self.neurons[n].output_cache) * (expected[n] - self.output_cache[n])
# should not be called on output layer
def calculate_deltas_for_hidden_layer(self, next_layer: Layer) -> None:
    for index, neuron in enumerate(self.neurons):
        next_weights: List[float] = [n.weights[index] for n in next_layer.neurons]
        next_deltas: List[float] = [n.delta for n in next_layer.neurons]
        sum_weights_and_deltas: float = dot_product(next_weights, next_deltas)
        neuron.delta = neuron.derivative_activation_function(neuron.output_cache) *
        sum_weights_and_deltas