神经网络结构

核心术语

  1. 神经元(neuron)
    人工神经网络中的最小单位,神经元拥有一个权重向量,一个

  2. 层(layer)
    第一层称为输入层,最后一层称为输出层,输入层和输出层之间的层都称为隐藏层。输入层没有前层节点,输出层没有后续节点,因此,在正向求值和反向传播时有区别。

  3. 反向传播

反向传播将在神经网络的输出中发现误差,并用它来修正神经元的权重。某个神经元对误差担负的责任越大,对其修正就会越多。但误差从何而来?我们如何才能知道存在误差呢?误差由被称为训练(training)的神经网络应用阶段获得(说白了,就是如果这个神经网络不训练,不反向传播就仅仅是一个静态的模型,没有任何价值)。

我们必须知道通过某些输入能够获得的正确输出,以便用预期输出和实际输出的差异来查找误差并修正权重。换句话说,神经网络在最开始时是一无所知的,直至它们知晓对于某组特定输入集的正确答案,在这之后才能为其他输入做好准备。反向传播仅发生在训练期间。

反向传播的第一步,是计算神经网络针对某些具体输入的真实输出结果预期输出结果之间的误差。输出层中的所有神经元都会具有这一误差(每个神经元都有一个预期输出及其实际输出)。然后,输出神经元的激活函数的导数将会应用于该神经元在其激活函数被应用之前输出的值(这里缓存了一份应用激活函数前的输出值)。
反向传播的第二步是:将求导结果再乘以神经元的误差,求其delta(是一个为网络所有隐藏层中的每个神经元计算delta。输出层中的delta将会用于计算上一个隐藏层中的delta。根据下层各神经元权重的点积和在下层中已算出的delta,可以算出上一层的delta。将这个值乘以调用神经元最终输出(在调用激活函数之前已缓存)的激活函数的导数,即可获得当前神经元的delta。

最后就是梯度下降

一旦权重更新完毕,神经网络就可以用其他输入和预期输出再次进行训练。此过程将一直重复下去,直至该神经网络的用户认为其已经训练好了,这可以用正确输出已知的输入进行测试来确定。(循环往复

代码实现

导包(打脸)

from typing import List
from math import exp
from random import random
from functools import reduce

定义一些工具函数

点积,激活函数,激活函数

包括点积,激活函数,激活函数的导数以及数据处理时将用到的归一化函数

# dot product of two vectors  点集两个向量
def dot_product(xs: List[float], ys: List[float]) -> float:return sum(x * y for x, y in zip(xs, ys))# the classic sigmoid activation function
def sigmoid(x: float) -> float:return 1.0 / (1.0 + exp(-x))def derivative_sigmoid(x: float) -> float:sig: float = sigmoid(x)return sig * (1 - sig)

归一化函数

归一化操作大致可以分为两种,两种方法各有优缺点。

  • ①:对所有数据进行归一化
  • ②:对同一类(同一属性—>列)的数据进行归一化
    一般情况下,都是使用第二种,对同一属性的数据进行归一化。

归一化公式

分别对应了下面两种:


# assume all rows are of equal length
# 归一化操作  (函数是否有问题)
# and feature scale each column to be in the range 0 - 1
def normalize_by_feature_scaling(dataset: List[List[float]]) -> None:for col_num in range(len(dataset[0])):#内层(对每一个列进行操作)column: List[float] = [row[col_num] for row in dataset]maximum = max(column)minimum = min(column)for row_num in range(len(dataset)):# 外层(对每一行进行操作)dataset[row_num][col_num] = (dataset[row_num][col_num] - minimum) / (maximum - minimum)return datasetdef normalize(dataset=[[5,2,2],[3,2,1]]):flatten=[]for i in range(len(dataset)):flatten.extend(dataset[i])max_num=max(flatten)min_num=min(flatten)# 归一化for i in range(len(dataset)):for j in range(len(dataset[i])):dataset[i][j]=(dataset[i][j]-min_num)/(max_num-min_num) # 括号不能少return dataset

结果如下:

normalize_by_feature_scaling([[5,2,1],[3,1,2],[4,3,1]])[[1.0, 0.5, 0.0], [0.0, 0.0, 1.0], [0.5, 1.0, 0.0]]normalize([[1.0, 0.25, 0.25], [0.5, 0.25, 0.0]])[[1.0, 0.25, 0.25], [0.5, 0.25, 0.0]]

定义神经元类

class Neuron:def __init__(self,weights,learning_rate,activation_function=sigmoid,derivation_activation_function=derivative_sigmoid):self.weights=weightsself.learning_rate=learning_rateself.activation_function=sigmoidself.derivative_activation_function=derivative_sigmoidself.output_cache=0.0self.delta=0.0def output(self,inputs):self.output_cache=dot_product(inputs,self.weights)return self.activation_function(self.output_cache) # 神经元的计算,#思考为什么要output_cache,用于计算delta
Neuron.__dict__
{'weights': [1, 2, 3],'learning_rate': 0.01,'activation_function': <function __main__.sigmoid(x:float) -> float>,'derivative_activation_function': <function __main__.derivative_sigmoid(x:float) -> float>,'output_cache': 0.0,'delta': 0.0}

定义层类

class Layer:def __init__(self,previous_layer,num_neurons,learning_rate,activation_function=sigmoid,derivation_activation_function=derivative_sigmoid):self.previous_layer=previous_layerself.neurons=[]for i in range(num_neurons):if previous_layer is None:random_weights=[]else:random_weights=[random() for _ in range(len(previous_layer.neurons))]neuron=Neuron(random_weights,learning_rate,activation_function,derivation_activation_function)self.neurons.append(neuron)self.output_cache=[0.0 for _ in range(num_neurons)]def outputs(self,inputs):#??if self.previous_layer is None:self.output_cache=inputselse:self.output_cache = [n.output(inputs) for n in self.neurons]return self.output_cachedef calculate_deltas_for_output_layer(self,expected):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])def calculate_deltas_for_hidden_layer(self, next_layer):for index,neuron in enumerate(self.neurons):
#             next_weights=[n.weights for n in next_layer.neurons]  # 少了一个weights[index] (所以报错)next_weights=[n.weights[index] for n in next_layer.neurons]next_deltas=[n.delta for n in next_layer.neurons]
#             print('next_weights,next_deltas',next_weights,'\n',next_deltas)sum_weights_and_deltas= dot_product(next_weights, next_deltas)neuron.delta=neuron.derivative_activation_function(neuron.output_cache)*sum_weights_and_deltas
input_layer=Layer(None,3,0.01) #输入层 不用随机初始化权重,因为输入层的权重需要预先给定
hedden_layer=Layer(input_layer,5,0.01) #neuron.weights:5个3*1
output_layer=Layer(hedden_layer,3,0.01)#neuron.weights:3个5*1
hedden_layer.__dict__,output_layer.__dict__
({'previous_layer': <__main__.Layer at 0x2b047528630>,'neurons': [<__main__.Neuron at 0x2b047528400>,<__main__.Neuron at 0x2b047528a20>,<__main__.Neuron at 0x2b047528b38>,<__main__.Neuron at 0x2b047528b00>,<__main__.Neuron at 0x2b047528160>],'output_cache': [0.0, 0.0, 0.0, 0.0, 0.0]},{'previous_layer': <__main__.Layer at 0x2b047528cc0>,'neurons': [<__main__.Neuron at 0x2b047528240>,<__main__.Neuron at 0x2b047528d68>,<__main__.Neuron at 0x2b047528dd8>],'output_cache': [0.0, 0.0, 0.0]})

定义神经网络类

from functools import reduce
class Network:def __init__(self,layer_structure,learning_rate,activation_function=sigmoid,derivative_activation_function=derivative_sigmoid):if len(layer_structure)<3:raise ValueError("Error: Should be at least 3 layers (1 input, 1 hidden, 1 output)")self.layers=[]# 输入层比较特殊,没有previous_layerinput_layer=Layer(None,layer_structure[0],learning_rate, activation_function, derivative_activation_function)self.layers.append(input_layer)# hidden layers and output layerfor previous, num_neurons in enumerate(layer_structure[1::]): # previous -->int (0 to n-1) ,num_neurons  input_layer 后面的层next_layer=Layer(self.layers[previous],num_neurons,learning_rate, activation_function, derivative_activation_function)self.layers.append(next_layer)#将输入数据推送到第一层,然后从第一层输出def outputs(self,input):return reduce((lambda inputs,layer:layer.outputs(inputs)),self.layers,input)#根据输出的误差计算出每个神经元的变化,与预期结果进行对比def backpropagate(self, expected):#计算输出层神经元与真实值的误差last_layer=len(self.layers) - 1 # 最后一层的位置信息self.layers[last_layer].calculate_deltas_for_output_layer(expected)#计算隐藏层 层与层之间神经元的误差for l in range(last_layer - 1, 0, -1):self.layers[l].calculate_deltas_for_hidden_layer(self.layers[l + 1])#backpropagate()实际上不会改变任何权重#update_weights()使用backpropagate()中计算的差值,来更改权值def update_weights(self):for layer in self.layers[1:]: #跳过输入层for neuron in layer.neurons:for w in range(len(neuron.weights)):neuron.weights[w]=neuron.weights[w]+(neuron.learning_rate*(layer.previous_layer.output_cache[w])* neuron.delta)#train()使用outputs()的结果运行多个输入并进行比较# 参照误差去训练 feed backpropagate() and update_weights()def train(self, inputs,expecteds):for location,xs in enumerate(inputs):ys=expecteds[location]
#             print("ys:",ys)outs=self.outputs(xs)
#             print(outs)self.backpropagate(ys)# 反向计算self.update_weights() # 正向更新def validate(self,inputs,expecteds,interpret_output):correct=0for input, expected in zip(inputs, expecteds):result=interpret_output(self.outputs(input))if result == expected:correct += 1percentage= float(correct / len(inputs))return correct, len(inputs), percentage
network=Network([4, 6, 2], 0.3)
network.__dict__
#输出代表有3层
{'layers': [<__main__.Layer at 0x1b4af017048>,<__main__.Layer at 0x1b4af017160>,<__main__.Layer at 0x1b4af017ac8>]}

测试网络

import csv
from random import shuffle
iris_parameters=[]
iris_classifications=[]
iris_species=[]
with open('iris.csv', mode='r') as iris_file:irises=list(csv.reader(iris_file))print(len(irises))shuffle(irises)for iris in irises:parameters= [float(n) for n in iris[0:4]]iris_parameters.append(parameters)species= iris[4]if species == "Iris-setosa":iris_classifications.append([1.0, 0.0, 0.0])elif species == "Iris-versicolor":iris_classifications.append([0.0, 1.0, 0.0])else:iris_classifications.append([0.0, 0.0, 1.0])iris_species.append(species)normalize_by_feature_scaling(iris_parameters) # 某一列归一化,而不是整个矩阵归一化iris_network= Network([4, 8, 3], 0.3)def iris_interpret_output(output):if max(output) == output[0]:return "Iris-setosa"elif max(output) == output[1]:return "Iris-versicolor"else:return "Iris-virginica"iris_trainers= iris_parameters[0:100]
#     print(len(iris_trainers),'\n',iris_trainers)iris_trainers_corrects= iris_classifications[0:100]
#     print(len(iris_trainers_corrects), '\n', iris_trainers_corrects)for _ in range(50):iris_network.train(iris_trainers, iris_trainers_corrects)iris_testers= iris_parameters[100:150]iris_testers_corrects= iris_species[100:150]iris_results = iris_network.validate(iris_testers, iris_testers_corrects, iris_interpret_output)print(f"{iris_results[0]} correct of {iris_results[1]} = {iris_results[2] * 100}%")
150
40 correct of 50 = 80.0%

拒绝调包 手写实现神经网络(复习专用)相关推荐

  1. 软考网络工程师考证(手写笔记)复习专用

    首先感谢博主(1条消息) 纪水一的博客_CSDN博客-web 攻击与防护领域博主https://blog.csdn.net/weixin_49349476?type=blog 提供的笔记 话不多说直接 ...

  2. 【神经网络实验】Numpy手写多层神经网络

    引言 这个作业的目的是给你们介绍建立,训练和测试神经系统网络模型.您不仅将接触到使用Python包构建神经系统网络从无到有,还有数学方面的反向传播和梯度下降.但在实际情况下,你不一定要实现神经网络从零 ...

  3. python怎么掉包_Python实战教程:拒绝调包,如何用python推导线性回归模型

    原标题:Python实战教程:拒绝调包,如何用python推导线性回归模型 最近有人问我一个问题,我数学不好,代码基础薄弱,英语一般般,如何入门当今最为前沿的机器学习领域?均方差损失,MSE,平方损失 ...

  4. 数字识别实例两种实现方式(tensorflow2.x):1.调用高级API 2.手写简单神经网络 3.手写深度神经网络(DNN)

    MNIST手写数字数据库的训练集为60,000个示例,而测试集为10,000个示例. 一共4个文件,训练集.训练集标签.测试集.测试集标签,这些数据直接可以用mnist = tf.keras.data ...

  5. python调包侠_拒绝调包侠,不需要高级算法和数据结构技巧

    大多数工科学生或者刚刚入门近年来比较火的"人工智能"相关算法的同学,在选择语言的时候,都会选择MATLAB. Python .R等等这些高级语言,对自己所学的算法进行实现和调试.这 ...

  6. 【笔记】识别手写数字神经网络

    知识点 np.random.randn 定义 举例 import numpy as npnp.random.randn()# 1.2349177513378706 np.random.randn(3, ...

  7. 拒绝调包,如何用python推导线性回归模型

    "python有妙用" 本文约2000字,阅读需要6分钟 关键词:Python 线性回归 应用 数据团优秀学员亲授学好数据分析的秘籍! p.s. 文末有福利大家自取~ 最近有人问我 ...

  8. C++手写笔记 基础复习

  9. 深度学习(手写数字识别)

    本程序采用百度paddlepaddle深度学习框架,并在百度AI Studio平台上运行 目录 1 实验内容 2 实验流程 3 DNN模型 4 LeNet 模型 4.1 LeNet-1模型 4.2 L ...

最新文章

  1. 行走在区块链上的智能合约
  2. Spring Boot 解决跨域问题的 3 种方案
  3. 计算机专业 美国 硕士,【美国计算机硕士排名】美国计算机硕士专业怎么样
  4. linux系统被***后处理经历
  5. get post请求区别_LoadRunner发送GET和POST请求
  6. T7-Dropout 解决 overfitting 过拟合
  7. webpack入门+react环境配置 1
  8. android数据交互方式(整理)
  9. axios拦截器_77.9KStar 的 Axios 项目有哪些值得借鉴的地方
  10. Windows 的驱动程序签名要求
  11. Snagit 2020 for mac(最好用的屏幕截图软件)
  12. 我在淘宝帮别人写代码,月入10万!
  13. Padavan挂载SMB共享及编译ffmpeg
  14. 吕 思 伟 ---- 潘 爱 民 :: ATL 介 绍( 三)
  15. springboot项目中访问不到html页面问题
  16. Supervisor 命令
  17. MFC中dlg.DoModal()返回-1
  18. 数字三角形(动态规划经典例题)
  19. 期货平仓是先开先平吗(期货怎么先平新仓)
  20. {昆明网络营销讲师}回归理性,2015年微商八大趋势及问题

热门文章

  1. 微动开关技术知识-微动开关概要
  2. How to set up the esp-hosted SDK compilation environment for ESP32-C3
  3. 上帝在基督里赦免了所有人的罪
  4. csdn竟然还有这种神器!后悔没有早点知道!超好用的csdn插件,别再犹豫了,赶快入手吧!
  5. lol提示游戏环境异常重启计算机,出现LOL游戏环境异常请重启机器怎么解决?
  6. 数字0是奇数还是偶数_C程序检查数字是偶数还是奇数
  7. 思维导图 XMind 闯关之路(第05关)插入外框概要
  8. MySql---修改语句
  9. Echarts 柏拉图
  10. 国际论文发表的注意事项