神经网络的运用

1、导入模块

import random
import numpy as np
import pandas as pd
import sklearn
import matplotlib. pyplot as plt

2、读取数据

data1=pd.read_csv('data1.csv')
data2=pd.read_csv('data2.csv')
data3=pd.read_csv('data3.csv')
data4=pd.read_csv('data4.csv')




#补全代码-----end-------#
print(type(data1))

代码输出结果: 

 二、数据合并、描述性统计及预处理

        1、数据合并

data=pd.concat([data1,data2],axis=0)
data=pd.concat([data,data3])
data=pd.concat([data,data4])

#补全代码-----end-------#
data=data.reset_index(drop=True)
print(data)

代码输出结果:

2、查看是否存在缺失值 

#补全代码-----begin-----#
data.isnull()

#补全代码-----end-------#

 代码输出:

3、查看数据集大小(行数,列数)

#补全代码-----begin-----#
print('数据集的大小:',data.shape)

#补全代码-----end-------#

 代码输出:

 4、显示数据前5行

data.head(5)

 结果:

5、查看数据描述信息

#补全代码-----begin-----#
data.describe()

#补全代码-----end-------#

 结果:

6、数据标准化

#标准化处理
from sklearn import preprocessing
features = pd.DataFrame(preprocessing.scale(data.iloc[:,1:]))
features.columns = data.columns[1:]
features

 结果:

7、标签独热编码处理。

#标签独热编码处理
ohe = preprocessing.OneHotEncoder(sparse=False)
tmp = ohe.fit_transform(pd.DataFrame(data['0']))
label = pd.DataFrame([i for i in pd.DataFrame(tmp).values])
label['label'] = [i for i in label.values]
label

 结果:

二、数据集划分

from sklearn.model_selection import train_test_split
#数据拆分
trainX, testX, trainY, testY = train_test_split(features, label['label'], test_size=0.2, random_state=0)
print('初始训练集的数据大小:',trainX.shape,'初始测试集的数据大小:', testX.shape, '目标训练集的数据大小:',trainY.shape,'初始测试集的数据大小:', testY.shape)

 结果:

三、定义损失函数

# 交叉熵成本函数
class CrossEntropyCost(object):
    @staticmethod
    def fn(a, y):
        # 使用0代替数组x中的nan元素,使用有限的数字代替inf元素
        return np.sum(np.nan_to_num(-y*np.log(a)-(1-y)*np.log(1-a)))
    # 返回从输出层传回的误差Δ,注意参数Z不使用
    @staticmethod
    def delta(z, a, y):
        return (a-y)

 2、平方误差函数

# 定义平方损失函数
class QuadraticCost(object):
    # 返回与输出相关联的成本
    @staticmethod
    def fn(a, y):
        return 0.5*np.linalg.norm(a-y)**2
    # 返回输出层传回的误差Δ
    @staticmethod
    def delta(z, a, y):
        return (a-y) * sigmoid_prime(z)

四、定义激活函数及其导数

1、定义激活函数 

# sigmoid函数
def sigmoid(z):
    #补全代码-----begin-----#
    return 1/(1+np.e**(-z))

    #补全代码-----end-------#

2、求激活函数的导数

# sigmoid函数的导数
def sigmoid_prime(z):
    return sigmoid(z) * (1 - sigmoid(z))

五、模型定义

#测试np.random.randn
import numpy as np
np.random.randn(2, 4) 

结果:

核心代码 :

class Network(object):
    def __init__(self, sizes, cost=QuadraticCost):
        # sizes是一个列表,存放有每层神经元的个数
        # 设置神经网络的层数
        self.num_layers = len(sizes)
        # sizes即每层神经元的个数
        self.sizes = sizes
        # 参数初始化方法
        self.default_weight_initializer()
        # 损失函数计算方法
        self.cost = cost
   
    # 初始化方法1-赋随机值(服从正态分布,方差为sqrt(x)),对权重和阈值(偏置)进行初始化
    def default_weight_initializer(self):
        # 阈值初始化,从第二层开始设置(第一层为输入层,不设置阈值)
        # randn的作用就是从标准正态分布中返回一个或多个样本值,此处返回y行的向量
        self.biases = [np.random.randn(y, 1) for y in self.sizes[1:]]
        # 权值初始化 此处每次返回y行x列的矩阵,构成权值列表
        self.weights = [np.random.randn(y, x)/np.sqrt(x) for x, y in zip(self.sizes[:-1], self.sizes[1:])]

    # 初始化方法1-(与默认初始化方法-初始化方法1相比,方差为1)
    def large_weight_initializer(self):
        self.biases = [np.random.randn(y, 1) for y in self.sizes[1:]]
        self.weights = [np.random.randn(y, x) for x, y in zip(self.sizes[:-1], self.sizes[1:])]

    # 神经网络计算值正向传播,给定神经元的输入,计算其输出
    def feedforward(self, a):
        for b, w in zip(self.biases, self.weights):
            a = sigmoid(np.dot(w, a)+b)
        return a

    # 误差反向传播,计算对应的梯度∇
    def backprop(self, x, y):
        #nabla 算符 ∇ “纳布拉”
        #阈值与权重的“梯度”
        nabla_b = [np.zeros(b.shape) for b in self.biases]
        nabla_w = [np.zeros(w.shape) for w in self.weights]
        # 激活函数的输出值 对于输入层,无激活函数,直接是训练实例x的值
        activation = x[:,None]
        # 用于存储所有经过激活函数后的输出值,当前放入输入层的激活函数——无激活函数,激活函数的输出等于输入x
        activations = [activation]
        # 用于存储所有中间向量z(中间神经元的输出,进激活函数之前的值)
        zs = []
        for b, w in zip(self.biases, self.weights):
            # 计算中间变量(神经元的输出Z=W*X+b,还未经过激活函数时的值)
            z = np.dot(w, activation)+b
            # 存储所有中间向量z
            zs.append(z)
            # 过激活函数后的值,隐含层激活函数使用sigmoid函数sigmoid(W*X+b)
            activation = sigmoid(z)
            # 列表存储所有神经元经过激活函数后的值
            activations.append(activation)
        # 反向更新

        # 输出层
        # 计算输出层误差error
        # 计算损失函数cost_derivative(
        # 求梯度
        delta = (self.cost).delta(zs[-1], activations[-1], y)
        # 计算输出层的nabla_b,nabla_w
        nabla_b[-1] = delta
        nabla_w[-1] = np.dot(delta, activations[-2].transpose())

        # 隐藏层

#         解释numpy.transpose()的作用:
#               起矩阵转置的作用。
        
        
        
        
        
        

#          详细解释此段代码的作用,添加注释-begin--#

        for ls in range(2, self.num_layers):
            z = zs[-ls] #存储从2到总神经网络的层数的所有中间向量
            sp = sigmoid_prime(z) #求出sigmoid函数在z的导数
            delta = np.dot(self.weights[-ls+1].transpose(), delta) * sp #返回输出层传回的误差Δ
            # 逐层往前计算
            nabla_b[-ls] = delta
            nabla_w[-ls] = np.dot(delta, activations[-ls-1].transpose())

#         详细解释此段代码的作用,添加注释-end--#

        return (nabla_b, nabla_w)
    
    # 模型训方法SGD
    # epochs表示训练多少轮, mini_batch_size表示每次从训练集中抽取多少实例,eta表示学习率,lmbda为正则化参数
    #(实际不是随机梯度下降,而是小批量梯度下降MBGD:min-batch 小批量梯度下降法MBGD)
    def SGD(self, training_data, epochs, mini_batch_size, eta,
        # lmbda-正则化参数
        lmbda = 0.0,
        evaluation_data=None):
        
        # 如果有验证集
        if evaluation_data:
            n_data = len(evaluation_data)
            
        n = len(training_data)
        
        #保存验证集损失、验证集上预测的准确次数
        evaluation_cost, evaluation_accuracy = [], []
        
        #保存训练集损失、训练集上预测的准确次数
        training_cost, training_accuracy = [], []
        
        # j代表第几轮,共epochs轮
        for j in range(epochs):
            # 将training_data中的数据随机打乱
            random.shuffle(training_data)
            
            # 每次抽取mini_batch_size大小的数据作为一小块,抽取时起点从0到n每次间隔mini_batch_size
            mini_batches = [training_data[k:k+mini_batch_size] for k in range(0, n, mini_batch_size)]
            
            # 对取出来的mini_batchs逐个进行更新
            for mini_batch in mini_batches:
                # 更新weights和biases
                self.update_mini_batch(mini_batch, eta, lmbda, len(training_data))
            
            #训练集损失
            cost = self.total_cost(training_data,lmbda)
            training_cost.append(cost)
            
            #训练集上模型预测准确的次数
            accuracy = self.accuracy(training_data)
            training_accuracy.append(accuracy)

            # 验证集损失
            #补全代码-----begin-----#
            cost1 = self.total_cost(evaluation_data,lmbda)
            evaluation_cost.append(cost1)

            #补全代码-----end-------#

            # 验证集上模型预测准确的次数
            #补全代码-----begin-----#
            accuracy1 = self.accuracy(evaluation_data)
            evaluation_accuracy.append(accuracy1)

            #补全代码-----end-------#
            
            #验证集数据转换
            #argmax返回指定axis上最大值的下标;argmin则返回最小值的下标,参考:https://www.jb51.net/article/213986.htm
            #对于验证集里的数据(x,y),返回模型的输出值feedforward(x)中的最大值与实际值y的最大值构成的元组
            evaluate_data = [(np.argmax(self.feedforward(x).sum(axis=1)), np.argmax(y)) for (x, y) in evaluation_data]
            
        return evaluation_cost, evaluation_accuracy, training_cost, training_accuracy,evaluate_data
    
    # eta:学习率  n:训练集实例数量
    # 传入单批量数据mini_batch,根据其x、y值(特征、标签),对整个神经网络的wights和biases进行更新
    def update_mini_batch(self, mini_batch, eta, lmbda, n):
        # 初始化 nabla 算符 ∇
        nabla_b = [np.zeros(b.shape) for b in self.biases]
        nabla_w = [np.zeros(w.shape) for w in self.weights]
        for x, y in mini_batch:
            # 计算对应的更新量
            delta_nabla_b, delta_nabla_w = self.backprop(x, y[:,None])
            nabla_b = [nb+dnb for nb, dnb in zip(nabla_b, delta_nabla_b)]
            nabla_w = [nw+dnw for nw, dnw in zip(nabla_w, delta_nabla_w)]
        # 更新权重weights W'k=(1-(eta*lmbda/n))W-(eta/n)&C/&Wk     &表示偏导  C表示损失函数
        self.weights = [(1-eta*(lmbda/n))*w-(eta/len(mini_batch))*nw for w, nw in zip(self.weights, nabla_w)]
        # 更新阈值biases  b'k=bk-(eta/n)&C/&bk   &表示偏导   C表示损失函数
        self.biases = [b-(eta/len(mini_batch))*nb for b, nb in zip(self.biases, nabla_b)]

    
    # 计算模型预测的准确次数
    def accuracy(self, data_in):
        results = [(np.argmax(self.feedforward(x).sum(axis=1)), np.argmax(y)) for (x, y) in data_in]
        return sum(int(x == y) for (x, y) in results)


    # 统计给定数据集data_in上的总误差
    def total_cost(self, data_in, lmbda):
        cost = 0.0
        for x, y in data_in:
            a = self.feedforward(a = x[:,None])
            # 累积误差
            cost += self.cost.fn(a, y)/len(data_in)
        # 加上权重的L2正则化项:(lmbda/2n)*sum(w**2),len(data_in):数据集中包含实例个数
        # 经验误差+结构误差,避免模型过拟合
        cost += 0.5*(lmbda/len(data_in))*sum(np.linalg.norm(w)**2 for w in self.weights)
        return cost

 六、模型调用

#补全代码-----begin-----#

net=Network(sizes=[24,100,4,4],cost=CrossEntropyCost)

#补全代码-----end-------#

2、对权重和偏置进行初始化

#补全代码-----begin-----#
net.large_weight_initializer()


#补全代码-----end-------#

3、设置训练次数times为100。

#补全代码-----begin-----#
times=100

#补全代码-----end-------#

4、构造训练集

# 训练集数据格式转化
training_data = list(zip(trainX.to_numpy(),trainY.to_numpy()))
# 测试集数据格式转化
test_data = list(zip(testX.to_numpy(),testY.to_numpy()))

5、模型训练

#补全代码-----begin-----#

evaluation_cost, evaluation_accuracy, training_cost, training_accuracy,evaluate_data=net.SGD(training_data=training_data[:1000], 
        epochs=times, mini_batch_size=20, eta=0.4,
        # lmbda-正则化参数
        lmbda = 0.001,
        evaluation_data=test_data)
print(evaluation_cost, evaluation_accuracy, training_cost, training_accuracy,evaluate_data)
#补全代码-----end-------#

代码输出结果:

 6、计算模型准确率

##测试np.tile
arr1 = np.array([100,102,104,105])
arr2 = np.tile(200,4)
print(arr2)
arr3= arr1/arr2
print(arr3)

结果:

# 计算训练集的准确率training_accuracy
#补全代码-----begin-----#
arr4=np.array(training_accuracy)
arr5=np.tile(len(training_data),times)
arr6=arr4/arr5
print(arr6)
#补全代码-----end-------#


# 计算验证集的准确率evaluation_accuracy
#补全代码-----begin-----#
arr7=np.array(evaluation_accuracy)
arr8=np.tile(len(evaluate_data),times)
arr9=arr7/arr8
print(arr9)

#补全代码-----end-------#

 结果:

 七、数据可视化

#刘伟  21智能2班 18
x = np.arange(1, times+1, 1)
fig = plt.figure()
# plt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=1)
ax1 = fig.add_subplot(4,1,1)
ax1 = plt.plot(x, evaluation_accuracy , 'g-', linewidth=2)
plt.ylabel('train_acc: %')
plt.grid()

#补全代码-----begin-----#
#绘制子图(4,1,2)
ax2 = fig.add_subplot(4,1,2)
ax2 = plt.plot(x, training_accuracy, 'r-', linewidth=2)
plt.ylabel('evaluation_acc: %')
plt.grid()


#补全代码-----end-------#

#补全代码-----begin-----#
#绘制子图(4,1,3)
ax2 = fig.add_subplot(4,1,3)
ax2 = plt.plot(x,training_cost, 'y-', linewidth=2)
plt.ylabel('train_cost')
plt.grid()


#补全代码-----end-------#

ax4 = fig.add_subplot(4,1,4)
ax4 = plt.plot(x, evaluation_cost, 'm-', linewidth=2)
plt.ylabel('evaluate_cost')
plt.xlabel('Epoch')
plt.grid()
fig.tight_layout()
plt.show()

输出结果:

到这里就基本上没有什么问题了,大家如果有什么问题都可以私信问我喔!

也可以关注我的公众号:风程序员

谢谢大家的关注! 
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值