2 隐藏层神经网络
""" 参考资料: - http://neuralnetworksanddeeplearning.com/chap2.html (反向传播) - https://en.wikipedia.org/wiki/Sigmoid_function (Sigmoid激活函数) - https://en.wikipedia.org/wiki/Feedforward_neural_network (前馈神经网络) """ import numpy class TwoHiddenLayerNeuralNetwork: def __init__(self, input_array: numpy.ndarray, output_array: numpy.ndarray) -> None: """ 初始化 TwoHiddenLayerNeuralNetwork 类,为每一层分配随机权重,并将预测输出初始化为零。 input_array:用于训练神经网络的输入值(即训练数据)。 output_array:给定输入的期望输出值。 >>> input_val = numpy.array(([0, 0, 0], [0, 0, 0], [0, 0, 0]), dtype=float) >>> output_val = numpy.array(([0], [0], [0]), dtype=float) >>> nn = TwoHiddenLayerNeuralNetwork(input_val, output_val) >>> nn.input_layer_and_first_hidden_layer_weights.shape[1] 4 """ # 为训练模型提供的输入值。 self.input_array = input_array # 分配随机初始权重,其中第一个参数是前一层中的节点数,第二个参数是下一层中的节点数。 # 分配随机初始权重。 # self.input_array.shape[1] 用于表示输入层中的节点数。 # 第一个隐藏层有4个节点。 self.input_layer_and_first_hidden_layer_weights = numpy.random.rand( self.input_array.shape[1], 4 ) # 第一个隐藏层的随机初始值。 # 第一个隐藏层有4个节点。 # 第二个隐藏层有3个节点。 self.first_hidden_layer_and_second_hidden_layer_weights = numpy.random.rand( 4, 3 ) # 第二个隐藏层的随机初始值。 # 第二个隐藏层有3个节点。 # 输出层有1个节点。 self.second_hidden_layer_and_output_layer_weights = numpy.random.rand(3, 1) # 提供的真实输出值。 self.output_array = output_array # 神经网络的预测输出值。 # 预测_output 数组最初包含零。 self.predicted_output = numpy.zeros(output_array.shape) def feedforward(self) -> numpy.ndarray: """ 信息沿着一个方向前进,即从输入节点,通过两个隐藏节点到输出节点。 网络中没有循环或回路。 返回层在第二个隐藏层和输出层之间 (即神经网络的最后一层)。 >>> input_val = numpy.array(([0, 0, 0], [0, 0, 0], [0, 0, 0]), dtype=float) >>> output_val = numpy.array(([0], [0], [0]), dtype=float) >>> nn = TwoHiddenLayerNeuralNetwork(input_val, output_val) >>> res = nn.feedforward() >>> array_sum = numpy.sum(res) >>> numpy.isnan(array_sum) False """ # layer_between_input_and_first_hidden_layer 是连接输入节点与第一个隐藏层节点的层。 self.layer_between_input_and_first_hidden_layer = sigmoid( numpy.dot(self.input_array, self.input_layer_and_first_hidden_layer_weights) ) # layer_between_first_hidden_layer_and_second_hidden_layer 是连接 # 第一个隐藏节点组与第二个隐藏节点组的层。 self.layer_between_first_hidden_layer_and_second_hidden_layer = sigmoid( numpy.dot( self.layer_between_input_and_first_hidden_layer, self.first_hidden_layer_and_second_hidden_layer_weights, ) ) # layer_between_second_hidden_layer_and_output 是连接 # 第二个隐藏层与输出节点的层。 self.layer_between_second_hidden_layer_and_output = sigmoid( numpy.dot( self.layer_between_first_hidden_layer_and_second_hidden_layer, self.second_hidden_layer_and_output_layer_weights, ) ) return self.layer_between_second_hidden_layer_and_output def back_propagation(self) -> None: """ 用于根据前一个时期(即迭代)中获得的错误率微调神经网络的权重的函数。 使用sigmoid激活函数的导数进行更新。 >>> input_val = numpy.array(([0, 0, 0], [0, 0, 0], [0, 0, 0]), dtype=float) >>> output_val = numpy.array(([0], [0], [0]), dtype=float) >>> nn = TwoHiddenLayerNeuralNetwork(input_val, output_val) >>> res = nn.feedforward() >>> nn.back_propagation() >>> updated_weights = nn.second_hidden_layer_and_output_layer_weights >>> (res == updated_weights).all() False """ updated_second_hidden_layer_and_output_layer_weights = numpy.dot( self.layer_between_first_hidden_layer_and_second_hidden_layer.T, 2 * (self.output_array - self.predicted_output) * sigmoid_derivative(self.predicted_output), ) updated_first_hidden_layer_and_second_hidden_layer_weights = numpy.dot( self.layer_between_input_and_first_hidden_layer.T, numpy.dot( 2 * (self.output_array - self.predicted_output) * sigmoid_derivative(self.predicted_output), self.second_hidden_layer_and_output_layer_weights.T, ) * sigmoid_derivative( self.layer_between_first_hidden_layer_and_second_hidden_layer ), ) updated_input_layer_and_first_hidden_layer_weights = numpy.dot( self.input_array.T, numpy.dot( numpy.dot( 2 * (self.output_array - self.predicted_output) * sigmoid_derivative(self.predicted_output), self.second_hidden_layer_and_output_layer_weights.T, ) * sigmoid_derivative( self.layer_between_first_hidden_layer_and_second_hidden_layer ), self.first_hidden_layer_and_second_hidden_layer_weights.T, ) * sigmoid_derivative(self.layer_between_input_and_first_hidden_layer), ) self.input_layer_and_first_hidden_layer_weights += ( updated_input_layer_and_first_hidden_layer_weights ) self.first_hidden_layer_and_second_hidden_layer_weights += ( updated_first_hidden_layer_and_second_hidden_layer_weights ) self.second_hidden_layer_and_output_layer_weights += ( updated_second_hidden_layer_and_output_layer_weights ) def train(self, output: numpy.ndarray, iterations: int, give_loss: bool) -> None: """ 对给定次数的迭代执行前馈和反向传播过程。 每次迭代都会更新神经网络的权重。 output:给定输入的真实输出值,用于计算损失。 iterations:权重要更新的次数。 give_loss:布尔值,如果为True,则打印每次迭代的损失,如果为False,则不打印。 >>> input_val = numpy.array(([0, 0, 0], [0, 1, 0], [0, 0, 1]), dtype=float) >>> output_val = numpy.array(([0], [1], [1]), dtype=float) >>> nn = TwoHiddenLayerNeuralNetwork(input_val, output_val) >>> first_iteration_weights = nn.feedforward() >>> nn.back_propagation() >>> updated_weights = nn.second_hidden_layer_and_output_layer_weights >>> (first_iteration_weights == updated_weights).all() False """ for iteration in range(1, iterations + 1): self.output = self.feedforward() self.back_propagation() if give_loss: loss = numpy.mean(numpy.square(output - self.feedforward())) print(f"Iteration {iteration} Loss: {loss}") def predict(self, input_arr: numpy.ndarray) -> int: """ 使用训练过的神经网络为给定输入值进行预测。 模型给出的输出值在0和1之间。 如果模型值大于阈值,则predict函数返回1,否则返回0, 因为实际输出值是二进制的。 >>> input_val = numpy.array(([0, 0, 0], [0, 1, 0], [0, 0, 1]), dtype=float) >>> output_val = numpy.array(([0], [1], [1]), dtype=float) >>> nn = TwoHiddenLayerNeuralNetwork(input_val, output_val) >>> nn.train(output_val, 1000, False) >>> nn.predict([0, 1, 0]) in (0, 1) True """ # 要进行预测的输入值。 self.array = input_arr self.layer_between_input_and_first_hidden_layer = sigmoid( numpy.dot(self.array, self.input_layer_and_first_hidden_layer_weights) ) self.layer_between_first_hidden_layer_and_second_hidden_layer = sigmoid( numpy.dot( self.layer_between_input_and_first_hidden_layer, self.first_hidden_layer_and_second_hidden_layer_weights, ) ) self.layer_between_second_hidden_layer_and_output = sigmoid( numpy.dot( self.layer_between_first_hidden_layer_and_second_hidden_layer, self.second_hidden_layer_and_output_layer_weights, ) ) return int((self.layer_between_second_hidden_layer_and_output > 0.6)[0]) def sigmoid(value: numpy.ndarray) -> numpy.ndarray: """ 应用Sigmoid激活函数。 返回归一化值 >>> sigmoid(numpy.array(([1, 0, 2], [1, 0, 0]), dtype=numpy.float64)) array([[0.73105858, 0.5 , 0.88079708], [0.73105858, 0.5 , 0.5 ]]) """ return 1 / (1 + numpy.exp(-value)) def sigmoid_derivative(value: numpy.ndarray) -> numpy.ndarray: """ 提供Sigmoid函数的导数值。 返回Sigmoid值的导数 >>> sigmoid_derivative(numpy.array(([1, 0, 2], [1, 0, 0]), dtype=numpy.float64)) array([[ 0., 0., -2.], [ 0., 0., 0.]]) """ return (value) * (1 - (value)) def example() -> int: """ 一个关于“如何使用神经网络类并使用 所需输出的方法”的示例。 调用TwoHiddenLayerNeuralNetwork类并 为模型提供固定的输入输出值。 模型经过固定次数的训练,然后调用predict方法。 在这个例子中,输出被分为2类,即二进制分类, 这两个类别由'0'和'1'表示。 >>> example() in (0, 1) True """ # 输入值。 test_input = numpy.array( ( [0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [1, 0, 0], [1, 0, 1], [1, 1, 0], [1, 1, 1], ), dtype=numpy.float64, ) # 给定输入的真实输出值。 output = numpy.array(([0], [1], [1], [0], [1], [0], [0], [1]), dtype=numpy.float64) # 调用神经网络类。 neural_network = TwoHiddenLayerNeuralNetwork( input_array=test_input, output_array=output ) # 调用训练函数。 # 如果要查看每次迭代的损失,请将give_loss设置为True。 neural_network.train(output=output, iterations=10, give_loss=False) return neural_network.predict(numpy.array(([1, 1, 1]), dtype=numpy.float64)) if __name__ == "__main__": example()