神经网络Python代码完整版及其代码解析

发布时间 2023-12-06 15:53:33作者: taohuaxiaochunfeng

 

1、读取数据集和标签集

 1 def loadDataSet():
 2     data = []
 3     label = []
 4     fr = open('testSet.txt')
 5     for line in fr.readlines():               # 循环读写,fr是一个已经打开的文件对象,readline()函数会读取文件中的一行内容
 6         lineArr = line.strip().split()
 7         data.append([1.0, float(lineArr[0]), float(lineArr[1])])  # 添加列表
 8         label.append(int(lineArr[2]))                             # 添加整形
 9     data = np.array(data)                                         # 创建数组(数据集)          
10     label = np.array(label)                           
11     return data, label

1.1、open

python提供了方便的文件读写功能,其中open是读写文件的第一步

Open的定义方式为:

             file = open(path, mode = 'r', buffering = -1, encoding = None )

其中,参数:path        ------ 文件路径

                      mode      ------ 为读取模式,默认为r,即只读模式,w表示写

                      buffering ------ 为缓冲区,由于内存的读写速度快于外设,所以大部分情况不用设,即不大于0

                      encoding ------ 为编码方式

通过open创建的文件对象,除了用于关闭文件的close之外,有两组最常用的函数,即代表读写的readwrite,分别用于读写,其区别如下

 read \ write                 ------ 读写整个文件  ,  read(size)可读取size大小的文件

 readline                      ------ 每次读一行

readlines \ writelines   ------ 前者按行读取文件,并存入一个字符串列表; writelines将一个字符串列表的形式写入文件 

1.2、 line.strip().split()

 作用是对一个字符串进行处理

首先使用strip()方法删除字符串两端的空格(或其他特定字符)

然后使用split()方法将字符串按照空格进行分割,生成一个列表

 strip()的用法

 1、删除前面的空格

1 if __name__ == '__main__':
2     #创建一个字符串
3     s = '  abcdefd'
4     # 打印出经过strip处理之后的结果
5     print(s.strip())

2、删除首尾的空格和换行

1 if __name__ == '__main__':
2     #创建一个字符串
3     s = '  abcdefd\n'
4     # 打印出经过strip处理之后的结果
5     print(s.strip())

3、删除首尾指定的字符

1 if __name__ == '__main__':
2     #创建一个字符串
3     s = 'abcdefd'
4     # 打印出经过strip处理之后的结果
5     print(s.strip('a'))

split的用法

splitg函数通常是对字符串进行操作,操作完之后的结果,变成了一个字符串列表。

split函数按照括号内给定的字符进行分割,如果括号内是空的,也就是没有指定具体的分割内容的话,那么就默认的按照空格进行分割。

1、按照默认的方式进行划分(默认是按照空格进行分割)

1 if __name__ == '__main__':
2     #创建一个字符串
3     s = 'abc  defd'
4     # 打印出经过split处理之后的结果
5     print(s.split())

 

 2、按照指定的某一个字符进行分割,分割之后返回字符串列表,字符串列表中不包括你指定的分隔符,例如下面这个例子中,不包含d这个字母

1 if __name__ == '__main__':
2     #创建一个字符串
3     s = 'abcdefd'
4     # 打印出经过split处理之后的结果
5     print(s.split('d'))

3、也可以按照‘\n’,‘\t’进行划分

1 if __name__ == '__main__':
2     #创建一个字符串
3     s = 'abc\tdefd\t'
4     # 打印出经过split处理之后的结果
5     print(s.split('\t'))

 2、NeuralNetWork类

 1 class NeuralNetWork:
 2     def __init__(self, input_nodes, hidden_nodes, out_nodes, lr):
 3         # 设置输入个数
 4         self.innodes = input_nodes
 5         # 设置隐藏层节点个数
 6         self.hnodes = hidden_nodes
 7         # 设置输出节点个数
 8         self.onodes = out_nodes
 9         # 设置学习率,用于反向更新
10         self.lr = lr
11 
12         # self.weight_i2h = np.ones((self.hnodes, self.innodes))
13         # self.weight_h2o = np.ones((self.onodes, self.hnodes))
14         # 随机初始化比1矩阵效果要好很多
15 
16         # 权重矩阵(输入到隐藏)
17         self.weight_i2h = (numpy.random.normal(0.0, pow(self.hnodes,-0.5), (self.hnodes,self.innodes) )  )
18         # 权重矩阵(隐藏到输出)
19         self.weight_h2o = (numpy.random.normal(0.0, pow(self.onodes,-0.5), (self.onodes,self.hnodes) )  )
20         # 设置激活函数(sigmoid)
21         self.activation_function = lambda x: 1.0/(1+np.exp(-x))
22         pass
23 
24     '''
25     训练方法,输入一次训练的输入和label
26     '''
27     def train(self, inputs_list, targets_list):
28         inputs = numpy.array(inputs_list, ndmin=2).T
29         target = np.array(targets_list, ndmin=2).T
30         # wx + b
31         hidden_inputs = np.dot(self.weight_i2h, inputs)        # np.dot函数 主要用于矩阵的乘法运算,其中包括:向量内积、多维矩阵乘法和矩阵与向量的乘法
32         # 激活作为隐藏层的输出
33         hidden_outputs = self.activation_function(hidden_inputs)
34         # wx + b
35         o_inputs = np.dot(self.weight_h2o, hidden_outputs)
36         # 激活作为输出
37         o_outputs = self.activation_function(o_inputs)        # activation_function 激活函数
38         # 损失函数
39         loss = (target - o_outputs) ** 2 * 0.5
40         # 输出误差,用于反向更新
41         error = target - o_outputs
42         # error = target - o_outputs
43         # 隐藏层误差,用于反向更新
44         hidden_error = np.dot(self.weight_h2o.T, error * o_outputs * (1 - o_outputs))
45         # 梯度
46         gradO = error * o_outputs * (1 - o_outputs)
47         # 反向更新
48         self.weight_h2o += self.lr * np.dot((error * o_outputs * (1 - o_outputs)), np.transpose(hidden_outputs))
49         gradI = hidden_error * hidden_outputs * (1 - hidden_outputs)
50         # 反向更新
51         self.weight_i2h += self.lr * np.dot((hidden_error * hidden_outputs * (1 - hidden_outputs)),
52                                             np.transpose(inputs))
53         return loss

2.1、numpy.random模块

numpy.random 提供了多种随机数生成函数,包括生成均匀分布、正态分布、泊松分布等各种分布的随机数

  • 这个模块包含了用于生成随机数的基本函数,如rand()randn()randint()等。
  • 例如,rand()生成0到1之间均匀分布的随机数,randn()生成标准正态分布的随机数,randint()生成整数随机数。

2.1.1、numpy.random.rand() 

功能:生成均匀分布的在[0, 1)内的随机数

numpy.random.rand(d0, d1, ..., dn) 接受多个整数参数,每个参数代表生成随机数的维度。可以使用逗号分隔的整数来指定多维数组的形状。 

1 import numpy as np
2 
3 # 生成一个[0, 1)范围内的随机浮点数
4 rand_num = np.random.rand()
5 print(rand_num)
6 
7 # 生成一个3x3的二维数组,包含[0, 1)范围内的随机浮点数
8 rand_array = np.random.rand(3, 3)
9 print(rand_array)

 

 2.1.2、numpy.random.randn()

功能: 生成标准正态分布的随机数

 numpy.random.randn(d0, d1, ..., dn) 同样接受多个整数参数,用于指定生成随机数的维度。

1 import numpy as np
2 
3 # 生成一个标准正态分布的随机浮点数
4 rand_num = np.random.randn()
5 print(rand_num)
6 
7 # 生成一个3x3的二维数组,包含标准正态分布的随机浮点数
8 rand_array = np.random.randn(3, 3)
9 print(rand_array)

 2.1.3、numpy.random.randint()

 功能: 生成整数随机数

  • 参数:numpy.random.randint(low, high, size=None, dtype=int) 其中:
  • low 是生成的随机数的下界(包含在内)。
  • high 是生成的随机数的上界(不包含在内)。
  • size 是生成随机数的形状,可以是整数或元组。如果不提供,默认生成一个随机整数。
  • dtype 是生成的随机数的数据类型,默认为整数。
1 import numpy as np
2 
3 # 生成一个[0, 10)范围内的整数随机数
4 rand_int = np.random.randint(0, 10)
5 print(rand_int)
6 
7 # 生成一个1x5的一维数组,包含[0, 10)范围内的整数随机数
8 rand_array = np.random.randint(0, 10, size=(1, 5))
9 print(rand_array)

2.1.4、numpy.random.normal() 

 功能:正态分布

  使用numpy.random.normal()函数生成。需要指定均值(loc)和标准差(scale)。

 

 1 import numpy as np
 2 import matplotlib.pyplot as plt
 3 
 4 # 生成10000个均值为0、标准差为1的正态分布随机数
 5 data = np.random.normal(0, 1, 10000)
 6 
 7 # 绘制直方图
 8 plt.hist(data, bins=30, density=True, alpha=0.6, color='g')
 9 plt.title("Normal Distribution")
10 plt.show()

 2.2、数组运算

inputs = numpy.array(inputs_list, ndmin=2).T

(1) 矩阵乘法 

     np.dot(A, B)

     如果使用 np.mat 将二维数组准确定义为矩阵,就可以直接使用*完成矩阵乘法计算

      np.mat(A) * np.mat(B)

(2) 转置

     A.T

(3) 平方根

            np.sqrt(a)

3、随机梯度下降(SGD)

 1 def stocGradDescent(data, label):
 2     m, n = np.shape(data)
 3     for iter in range(200):
 4         total_loss = 0
 5         for i in range(m):
 6             # if label[i] == 1:
 7             #     pass
 8             # elif label[i] == 0:
 9             #     pass
10             # 累计每个epach的Loss观察效果
11 
12             total_loss += net.train(data[i], label[i])
13         print("NO.{} Loss={}".format(iter, total_loss))

梯度下降算法每次从训练集中随机选择一个样本来进行学习。批量梯度下降算法每次都 会使用全部训练样本,因此这些计算是冗余的,因为每次都使用完全相同的样本集。而随机 梯度下降算法每次只随机选择一个样本来更新模型参数,因此每次的学习是非常快速的,并 且可以进行在线更新。随机梯度下降最大的缺点在于每次更新可能并不会按照正确的方向进 行,因此可以带来优化波动(扰动)。

 参考链接:https://blog.csdn.net/qq_58146842/article/details/121280968

随机梯度下降(SGD)是一种简单但非常有效的方法,多用用于支持向量机、逻辑回归(LR)等凸损失函数下的线性分类器的学习。并且SGD已成功应用于文本分类和自然语言处理中经常遇到的大规模和稀疏机器学习问题。
SGD既可以用于分类计算,也可以用于回归计算

SGD算法是从样本中随机抽出一组,训练后按梯度更新一次,然后再抽取一组,再更新一次,在样本量及其大的情况下,可能不用训练完所有的样本就可以获得一个损失值在可接受范围之内的模型了。(重点:每次迭代使用一组样本。)
为什么叫随机梯度下降算法呢?这里的随机是指每次迭代过程中,样本都要被随机打乱,这个也很容易理解,打乱是有效减小样本之间造成的参数更新抵消问题。

 1 import cv2
 2 
 3 import numpy as np
 4 
 5 # 创建数据集
 6 X = 2 * np.random.rand(100, 1)
 7 y = 4 + 3 * X + np.random.randn(100, 1)
 8 X_b = np.c_[np.ones((100, 1)), X]
 9 
10 # print('X的值:', X)
11 # print(y)
12 print(X_b)
13 
14 # 创建超参数
15 n_epochs = 10000
16 m = 100
17 t0, t1 = 5, 500
18 
19 
20 # 定义一个函数来调整学习率
21 def learning_rate_schedule(t):
22     return t0 / (t + t1)
23 
24 
25 theta = np.random.randn(2, 1)
26 for epoch in range(n_epochs):
27     # 在双层for循环之间,每个轮次开始分批次迭代之前打乱数据索引顺序
28     arr = np.arange(len(X_b))
29     np.random.shuffle(arr)
30     X_b = X_b[arr]
31     y = y[arr]
32     for i in range(m):
33         xi = X_b[i:i + 1]
34         yi = y[i:i + 1]
35         gradients = xi.T.dot(xi.dot(theta) - yi)
36         learning_rate = learning_rate_schedule(epoch * m + i)
37         theta = theta - learning_rate * gradients
38 
39 print(theta)

 

完整代码:

  1 import numpy
  2 import numpy as np
  3 
  4 # 神经网络设计
  5 # 类 : NeuralNetWork
  6 # 类内初始化:__init__用以设置神经网络的参数(输入层参数、隐藏层参数、输出层参数、学习率)
  7 # 类内方法:train用于训练数据,更新权重
  8 # 读取数据:loadDataSet用于在txt文件中读取数据,包括输入值和label值
  9 # 随机梯度下降处理:stocGradDescent用于处理训练数据的过程
 10 
 11 # NeuralNetWork类
 12 class NeuralNetWork:
 13     def __init__(self, input_nodes, hidden_nodes, out_nodes, lr):
 14         # 设置输入个数
 15         self.innodes = input_nodes
 16         # 设置隐藏层节点个数
 17         self.hnodes = hidden_nodes
 18         # 设置输出节点个数
 19         self.onodes = out_nodes
 20         # 设置学习率,用于反向更新
 21         self.lr = lr
 22 
 23         # self.weight_i2h = np.ones((self.hnodes, self.innodes))
 24         # self.weight_h2o = np.ones((self.onodes, self.hnodes))
 25         # 随机初始化比1矩阵效果要好很多
 26 
 27         # 权重矩阵(输入到隐藏)
 28         self.weight_i2h = (numpy.random.normal(0.0, pow(self.hnodes,-0.5), (self.hnodes,self.innodes) )  )
 29         # 权重矩阵(隐藏到输出)
 30         self.weight_h2o = (numpy.random.normal(0.0, pow(self.onodes,-0.5), (self.onodes,self.hnodes) )  )
 31         # 设置激活函数(sigmoid)
 32         self.activation_function = lambda x: 1.0/(1+np.exp(-x))
 33         pass
 34 
 35     '''
 36     训练方法,输入一次训练的输入和label
 37     '''
 38     def train(self, inputs_list, targets_list):
 39         inputs = numpy.array(inputs_list, ndmin=2).T
 40         target = np.array(targets_list, ndmin=2).T
 41         # wx + b
 42         hidden_inputs = np.dot(self.weight_i2h, inputs)
 43         # 激活作为隐藏层的输出
 44         hidden_outputs = self.activation_function(hidden_inputs)
 45         # wx + b
 46         o_inputs = np.dot(self.weight_h2o, hidden_outputs)
 47         # 激活作为输出
 48         o_outputs = self.activation_function(o_inputs)
 49         # 损失函数
 50         loss = (target - o_outputs) ** 2 * 0.5
 51         # 输出误差,用于反向更新
 52         error = target - o_outputs
 53         # error = target - o_outputs
 54         # 隐藏层误差,用于反向更新
 55         hidden_error = np.dot(self.weight_h2o.T, error * o_outputs * (1 - o_outputs))
 56         # 梯度
 57         gradO = error * o_outputs * (1 - o_outputs)
 58         # 反向更新
 59         self.weight_h2o += self.lr * np.dot((error * o_outputs * (1 - o_outputs)), np.transpose(hidden_outputs))
 60         gradI = hidden_error * hidden_outputs * (1 - hidden_outputs)
 61         # 反向更新
 62         self.weight_i2h += self.lr * np.dot((hidden_error * hidden_outputs * (1 - hidden_outputs)),
 63                                             np.transpose(inputs))
 64         return loss
 65 
 66 
 67 # 从testSet.txt中读取数据存储至样本集data和标签集label
 68 def loadDataSet():
 69     data = []
 70     label = []
 71     fr = open('testSet.txt')
 72     for line in fr.readlines():
 73         lineArr = line.strip().split()
 74         data.append([1.0, float(lineArr[0]), float(lineArr[1])])
 75         label.append(int(lineArr[2]))
 76     data = np.array(data)
 77     label = np.array(label)
 78     return data, label
 79 
 80 
 81 def stocGradDescent(data, label):
 82     m, n = np.shape(data)
 83     for iter in range(200):
 84         total_loss = 0
 85         for i in range(m):
 86             # if label[i] == 1:
 87             #     pass
 88             # elif label[i] == 0:
 89             #     pass
 90             # 累计每个epach的Loss观察效果
 91 
 92             total_loss += net.train(data[i], label[i])
 93         print("NO.{} Loss={}".format(iter, total_loss))
 94 
 95 
 96 if __name__ == '__main__':
 97     input_nodes = 3
 98     hidden_nodes = 3
 99     output_nodes = 1
100     learning_rate = 0.1
101     net = NeuralNetWork(input_nodes, hidden_nodes, output_nodes, learning_rate)
102     data, label = loadDataSet()
103     stocGradDescent(data, label)
104     print(net.weight_i2h)
105     print(net.weight_h2o)
106     pass

可用的txt文本文件内容

  1 -0.017612    14.053064    0
  2 -1.395634    4.662541    1
  3 -0.752157    6.538620    0
  4 -1.322371    7.152853    0
  5 0.423363    11.054677    0
  6 0.406704    7.067335    1
  7 0.667394    12.741452    0
  8 -2.460150    6.866805    1
  9 0.569411    9.548755    0
 10 -0.026632    10.427743    0
 11 0.850433    6.920334    1
 12 1.347183    13.175500    0
 13 1.176813    3.167020    1
 14 -1.781871    9.097953    0
 15 -0.566606    5.749003    1
 16 0.931635    1.589505    1
 17 -0.024205    6.151823    1
 18 -0.036453    2.690988    1
 19 -0.196949    0.444165    1
 20 1.014459    5.754399    1
 21 1.985298    3.230619    1
 22 -1.693453    -0.557540    1
 23 -0.576525    11.778922    0
 24 -0.346811    -1.678730    1
 25 -2.124484    2.672471    1
 26 1.217916    9.597015    0
 27 -0.733928    9.098687    0
 28 -3.642001    -1.618087    1
 29 0.315985    3.523953    1
 30 1.416614    9.619232    0
 31 -0.386323    3.989286    1
 32 0.556921    8.294984    1
 33 1.224863    11.587360    0
 34 -1.347803    -2.406051    1
 35 1.196604    4.951851    1
 36 0.275221    9.543647    0
 37 0.470575    9.332488    0
 38 -1.889567    9.542662    0
 39 -1.527893    12.150579    0
 40 -1.185247    11.309318    0
 41 -0.445678    3.297303    1
 42 1.042222    6.105155    1
 43 -0.618787    10.320986    0
 44 1.152083    0.548467    1
 45 0.828534    2.676045    1
 46 -1.237728    10.549033    0
 47 -0.683565    -2.166125    1
 48 0.229456    5.921938    1
 49 -0.959885    11.555336    0
 50 0.492911    10.993324    0
 51 0.184992    8.721488    0
 52 -0.355715    10.325976    0
 53 -0.397822    8.058397    0
 54 0.824839    13.730343    0
 55 1.507278    5.027866    1
 56 0.099671    6.835839    1
 57 -0.344008    10.717485    0
 58 1.785928    7.718645    1
 59 -0.918801    11.560217    0
 60 -0.364009    4.747300    1
 61 -0.841722    4.119083    1
 62 0.490426    1.960539    1
 63 -0.007194    9.075792    0
 64 0.356107    12.447863    0
 65 0.342578    12.281162    0
 66 -0.810823    -1.466018    1
 67 2.530777    6.476801    1
 68 1.296683    11.607559    0
 69 0.475487    12.040035    0
 70 -0.783277    11.009725    0
 71 0.074798    11.023650    0
 72 -1.337472    0.468339    1
 73 -0.102781    13.763651    0
 74 -0.147324    2.874846    1
 75 0.518389    9.887035    0
 76 1.015399    7.571882    0
 77 -1.658086    -0.027255    1
 78 1.319944    2.171228    1
 79 2.056216    5.019981    1
 80 -0.851633    4.375691    1
 81 -1.510047    6.061992    0
 82 -1.076637    -3.181888    1
 83 1.821096    10.283990    0
 84 3.010150    8.401766    1
 85 -1.099458    1.688274    1
 86 -0.834872    -1.733869    1
 87 -0.846637    3.849075    1
 88 1.400102    12.628781    0
 89 1.752842    5.468166    1
 90 0.078557    0.059736    1
 91 0.089392    -0.715300    1
 92 1.825662    12.693808    0
 93 0.197445    9.744638    0
 94 0.126117    0.922311    1
 95 -0.679797    1.220530    1
 96 0.677983    2.556666    1
 97 0.761349    10.693862    0
 98 -2.168791    0.143632    1
 99 1.388610    9.341997    0
100 0.317029    14.739025    0