手工搭建书上的三层多前馈神经网络

 

手工搭建书上的三层多前馈神经网络

实验目的:该代码实现比较简单,在不使用Tensorflow、Keras等框架的前提下,手工搭建神经网络(包括模型层的定义和正向反向传播过程)。最后训练出表格中”?“处的数据。

表1

 代码如下:

 1、导入需要的Python库

import numpy as np
import scipy.special
import matplotlib.pyplot as plt
import pylab

2、定义神经网络类

根据表格数据集,输入为9*3的数值,设置输入层节点神经元数量为2,输出为两个”?“处的2个数字,所以输出层神经元个数设置为2。

class NeuralNetwork():
    # 初始化神经网络
    def __init__(self, inputnodes, hiddennodes, outputnodes, learningrate):
         # 设置输入层节点,隐藏层节点和输出层节点的数量和学习率
        self.inodes = inputnodes
        self.hnodes = hiddennodes
        self.onodes = outputnodes
        self.lr = learningrate                #设置神经网络中的学习率
        # 使用正态分布,进行权重矩阵的初始化 
        self.wih = np.random.normal(0.0, pow(self.hnodes, -0.5), (self.hnodes, self.inodes))
        self.who = np.random.normal(0.0, pow(self.onodes, -0.5), (self.onodes, self.hnodes))
        self.activation_function = lambda x: scipy.special.expit(x)       #激活函数设为Sigmod()函数
        pass
    # 定义训练神经网络
    print("************Train start******************")
    def train(self,input_list,target_list):
        # 将输入、输出列表转换为二维数组
        inputs = np.array(input_list, ndmin=2).T
        targets = np.array(target_list,ndmin= 2).T          
        hidden_inputs = np.dot(self.wih, inputs)                           #计算到隐藏层的信号,dot()返回的是两个数组的点积
        hidden_outputs = self.activation_function(hidden_inputs)           #计算隐藏层输出的信号
        final_inputs = np.dot(self.who, hidden_outputs)                    #计算到输出层的信号
        final_outputs = self.activation_function(final_inputs)
 
        output_errors = targets - final_outputs                           #计算输出值与标签值的差值
        #print("*****************************")
        #print("output_errors:",output_errors)
        hidden_errors = np.dot(self.who.T,output_errors)
 

        #隐藏层和输出层权重更新
        self.who += self.lr * np.dot((output_errors*final_outputs*(1.0-final_outputs)),
                                       np.transpose(hidden_outputs))
        #输入层和隐藏层权重更新
        self.wih += self.lr * np.dot((hidden_errors*hidden_outputs*(1.0-hidden_outputs)),
                                       np.transpose(inputs))
        pass
        
        #查询神经网络
    def query(self, input_list):   # 转换输入列表到二维数
        inputs = np.array(input_list, ndmin=2).T                     #计算到隐藏层的信号
        hidden_inputs = np.dot(self.wih, inputs)                     #计算隐藏层输出的信号
        hidden_outputs = self.activation_function(hidden_inputs)        #计算到输出层的信号
        final_inputs = np.dot(self.who, hidden_outputs)
        final_outputs = self.activation_function(final_inputs)
        return final_outputs

3、定义超参数

设置神经网络的输入层、隐藏层和输出层的神经元的个数

input_nodes = 3             #输入层神经元个数
hidden_nodes = 100             #隐藏层神经元个数
output_nodes = 3              #输出层神经元个数
learning_rate = 0.3            #学习率为0.3
# 创建神经网络
n = NeuralNetwork(input_nodes, hidden_nodes, output_nodes, learning_rate)

读取训练数据集,转化为列表

#读取训练数据集 转化为列表
training_data_file = open("train.csv",'r',encoding='ISO-8859-15')
training_data_list = training_data_file.readlines();     #方法用于读取所有行,并返回列表
#print("training_data_list:",training_data_list)
training_data_file.close()

4、模型训练

输入数据集进行数据归一化,避免数值0在计算是带来的影响,将数据归一到[0.01,0.99]

#训练次数
i = 1000
for e in range(i):
    #训练神经网络
    for record in training_data_list:
        #print(training_data_list)
        all_values = record.split(',')               #根据逗号,将文本数据进行拆分
        print(all_values)
        #将文本字符串转化为实数,并创建这些数字的数组。
        inputs = (np.asfarray(all_values[:])/255.0 * 0.99) + 0.01
        #创建用零填充的数组,数组的长度为output_nodes,加0.01解决了0输入造成的问题
        targets = np.zeros(output_nodes) + 0.01
        #使用目标标签,将正确元素设置为0.99
        targets[int(float(all_values[0]))] = 0.99
        n.train(inputs,targets)
    pass
pass
#训练次数1000下的target值
plt.plot(targets, linewidth = '1', label = "Ren35_train_targets", color='forestgreen', linestyle=':', marker='|')
plt.legend(loc='upper left')
plt.show()
plt.close()

对训练集中的数据进行1000次训练:

 

【P.S.预测值过多,仅截此图示意】

图1:训练次数1000下的target值

 

5、模型测试

 读取测试集数据

test_data_file = open("test.csv",'r',encoding='ISO-8859-15')
test_data_list = test_data_file.readlines()
test_data_file.close()
for i in range(1,3):
    all_values = test_data_list[i].split(',')
    print(all_values)
    #print(len(all_values))
    print(all_values[-1])  #输出目标值
pass

 6、测试集放入神经网络中,求出y值

import numpy as np
score = []
print("***************Test start!**********************")
for record in test_data_list:
    #用逗号分割将数据进行拆分
    all_values = record.split(',')
    print(all_values)
    #若是有监督的机器学习,则可以执行如下代码CICI
    #正确的答案是最后一个值
    #correct_values = float(all_values[-1])
    #print(correct_values,"是正确的期望值")
    #做输入
    inputs = (np.asfarray(all_values[:])/255.0 * 0.99) + 0.01
    #测试网络 作输入
    outputs= n.query(inputs)
    print("outputs:",outputs)
    #找出输出的最大值的索引
    #label = np.argmax(outputs)
    label = float(outputs[-1])
    print(label,"是网络的输出值\n")
    #如果期望值和网络的输出值正确 则往score 数组里面加1 否则添加0
    #if(label == correct_values):
    #    score.append(1)
    #else:
    #    score.append(0)
    pass
pass
#若是有监督的机器学习,则可以执行如下代码CICI
#print(score)
#score_array = np.asfarray(score)
#print("正确率是:",(score_array.sum()/score_array.size)*100,'%')

运行结果:

 

得:第9、10处的y值分别为:

0.009997529807483321
0.009996900579904208
【P.S.若是有监督的机器学习,则可以执行代码CICI(被注释掉的部分)进行统计,如果期望值和输出的值相同,就往score[]数组里面加1,否则加0,进而算准确率。】


                                  路漫漫其修远兮,吾将上下而求索
posted @ 2022-03-17 21:44  乘着风·轻舟过  阅读(602)  评论(0)    收藏  举报