机器学习 BP神经网络 梯度下降 反向传播算法

本文详细介绍了BP神经网络的误差逆传播公式推导过程,包括神经网络结构、参数解释、损失函数、梯度下降与链式法则的应用,以及反向传播算法的实际应用。通过实例演示了训练过程,展示了如何使用梯度下降调整权重和偏置,以优化模型预测性能。
摘要由CSDN通过智能技术生成

BP神经网络

  1. 神经网络
    每次根据训练的结果与预想的结果进行误差分析,进而修改权重和偏置,不断迭代,进而得到能和输出结果一致的模型
  2. 梯度下降与反向传播
    梯度下降用来寻找损失函数极小值
    反向传播用来求解梯度

神经网络训练过程:
训练数据集的时候,神经网络经过前向传播之后,得到了预测值与真实值之间的差距,使用损失函数来表示差距,其大小反映了真实值与预测值之间的差距。经过反向传播与梯度下降,不断减小损失函数的值

一、误差逆传播公式推导

1.1 神经网络的结构

在这里插入图片描述

1.2 参数含义

在这里插入图片描述

  1. w为权重矩阵,矩阵乘积之后得到下一层神经元的输入
  2. W矩阵的特点,行的个数为输入的维数,列的个数为下一层神经元的维数
  3. 上一层的输出为Sigmod函数的输出

1.3 损失函数

在这里插入图片描述

  • Y为预测的值,Y=sigmod(Z2)
  • y为实际的值
  • 损失函数为方差

1.4 梯度下降

  • 设置更新步长alpha

在这里插入图片描述

  • 梯度下降的难点,求偏导

1.5 链式法则求偏导

  • 矩阵求导时,矩阵要求转置

在这里插入图片描述

  1. 求对w1的偏导

在这里插入图片描述

  1. 求b1的偏导

在这里插入图片描述

  1. 求w2的偏导

在这里插入图片描述

  1. 求b2的偏导

在这里插入图片描述

  1. 都含有损失函数对Z2的偏导,即对,最后的输出求偏导

在这里插入图片描述

  1. 对于sigmod函数

在这里插入图片描述

  1. 对上面进行替换

在这里插入图片描述

1.6 反向逆传播算法

  1. 设神经网络为m层,用 L 表示其中的一层
  2. 这一层神经元的输入

在这里插入图片描述

  1. 求权重和偏置的对损失函数的偏导

在这里插入图片描述

  1. 可知需要求对本层Z的偏导,因此引入其下一层

在这里插入图片描述

  1. 对下一层Z的损失函数求偏导

在这里插入图片描述

  1. 因此可以知道,求出下一层的对Z的偏导, 则能递推求出上一层的偏导

在这里插入图片描述

  1. 对于最后一层,求出最后一层的偏导,能够退出上面所有层的梯度下降

在这里插入图片描述

  1. 求上层的梯度下降

在这里插入图片描述

在这里插入图片描述

二、BP神经网络

2.1 主函数

import numpy as np


# 读取数据
def load_data(file_name: "数据集的相对位置"):
	"""
	从txt文件中读取数据,一次读取所有的行
	去掉首尾的多余空格,将数字进行分词
	最后一列是标记,其他列是属性
	:param file_name:
	:return:
	"""
	# 存放数据
	data_set = []
	# 存放标签
	labels = []
	with open(file_name) as f:
		for line in f.readlines():
			values = line.strip().split()  # 空格分割
			data_set.append([float(j) for j in values[0: -1]])

			labels.append(int(float(values[-1])))

	return data_set, labels
	pass

# 激活函数
def sigmoid(value):
	"""
	非线性激活函数, 使用 sigmoid = 1/(1+exp(-x))

	:param value: 输入的值
	:return: 返回函数值
	"""
	return 1 / (1 + np.exp(-value))
	pass

# 初始化参数
def paramter_init(input_len, hidden_len, output_len):
	"""

	:param input_len: 输入神经元的个数, 即输入的维数
	:param hidden_len: 隐藏层神经元的个数,
	:param output_len: 输出层神经元的个数
	:return:
	"""

	RANDOM_INT = 5

	# 输入层与隐藏层的连接权重 input_len * hidden_len微,第一行为w1
	w1 = np.random.randint(-RANDOM_INT, RANDOM_INT, (input_len, hidden_len)).astype(np.float64)

	# 隐藏层偏置, 维数 1 * input_len
	b1 = np.random.randint(-RANDOM_INT, RANDOM_INT, (1, hidden_len)).astype(np.float64)

	# 隐藏层与输出层的权重 hidden_len * output_len
	w2 = np.random.randint(-RANDOM_INT, RANDOM_INT, (hidden_len, output_len)).astype(np.float64)

	# 输出层偏置,维数 1 * hidden_len
	b2 = np.random.randint(-RANDOM_INT, RANDOM_INT, (1, output_len)).astype(np.float64)

	return w1, b1, w2, b2
	pass


def my_trainning(dataset, label_set, w1, b1, w2, b2):
	"""

	过程:
		1. 输入的维数即神经元的个数,x = [1, 2, 3] 输入是三维的
		2. 输入*权重 + 偏置为激活函数的输入 x*w + b
			其中:
			w 的维数为 m * n;   m为行数, 对应输入神经元的个数,n为列数, 即第一隐藏层神经元的个数
				x * w后, 向量是1 * n 维的
			b 为行向量, [b1, b2, b3]
		3. f = sigmoid(x*w + b)  是 1 * n 维的, 作为下一层神经网络的输出, 或者结果

	基于梯度下降的反向传播算法
		w = w + alpha * 损失函数对 w 的偏导
		b = b + alpha * 损失函数对 b 的偏导

	难点是求偏导:


	:param dataset: 训练的数据集
	:param label_set: 标签, 可以说是分类
	:param w1: 连接层到隐藏层权重
	:param b1: 连接层到隐藏层的偏置
	:param w2: 隐层层到输出层的权重
	:param b2: 隐藏层到输出层的偏置
	:return:  返回训练后的权重和参数 w1, b1, w2, b2
	"""
	alpha = 0.01

	# 对测试的样本进行训练
	for i in range(len(dataset)):   # 长度为测试集中元素的个数

		# 输入矩阵
		input_date = np.mat(dataset[i]).astype(np.float64)   # 转化为浮点数‘
		# 输出矩阵
		label = np.mat(label_set[i]).astype(np.float64)

		# 隐藏层的输入, 即第一层的输出
		z1 = np.dot(input_date, w1).astype(np.float64) - b1

		# 隐藏层的输出
		n1 = sigmoid(z1)

		# 最后一层的输入
		z2 = np.dot(n1, w2).astype(np.float64) - b2

		# 最后一层的输出
		n2 = sigmoid(z2)

		# 梯度下降算法的计算 更新隐藏层到输出层
		pianE_div_pianZ2 = np.multiply((label - n2), np.multiply(n2, 1 - n2))

		delta_w2 = alpha * np.dot(np.transpose(n1), pianE_div_pianZ2)
		delta_b2 = alpha * pianE_div_pianZ2

		# 更新输入层到隐藏层
		pianE_div_pianZ1 = np.multiply(np.multiply(n1, 1 - n1), np.dot(pianE_div_pianZ2, np.transpose(w2)))
		delta_b1 = alpha * pianE_div_pianZ1
		delta_w1 = alpha * np.dot(np.transpose(input_date), pianE_div_pianZ1)

		# 更新参数
		w1 += delta_w1
		b1 -= delta_b1
		w2 += delta_w2
		b2 -= delta_b2

	# 返回训练的参数
	return w1, b1, w2, b2
	pass

# 得到一组测试数据的方差
def get_e(data_test, label, w1, b1, w2, b2):
	DATA_TEST_ROW_LEN = len(data_test)

	tmp = 0
	for i in range(DATA_TEST_ROW_LEN):
		input_test = np.mat(data_test[i]).astype(np.float64)

		n1 = sigmoid(np.dot(input_test, w1) - b1)

		n2 = sigmoid(np.dot(n1, w2) - b2)

		tmp += np.multiply((n2 - label[i]), (n2 - label[i]).T)  # .T 为matrix的转置

	return tmp / DATA_TEST_ROW_LEN
	pass


# 进行预测
def predict_test(data_test, label_test, w1, b1, w2, b2):
	"""
	对神经网络的参数进行测试,由输入层到输出层逐个转递
	使用sigmod函数作为激活函数
	:param data_test: 测试集
	:param label_test: 测试集的标记
	:param w1: 第一层到隐藏层的权重
	:param b1: 隐藏层的偏置
	:param w2: 隐藏层到输出层的权重
	:param b2: 输出层的偏置
	:return:   返回测试的正确率
	"""

	right_cnt = 0

	# 测试的个数
	TEST_NUM = len(data_test)

	# 对数据集的每一个输入进行测试
	for i in range(TEST_NUM):
		# 第一层输入
		input_date = np.mat(data_test[i]).astype(np.float64)

		# 第一层输出, 第二层输入
		output_1 = sigmoid(np.dot(input_date, w1) - b1)

		# 第二层输出, 结果
		output_2 = sigmoid(np.dot(output_1, w2) - b2)

		if output_2 >= 0.5:
			flag = 1
		else:
			flag = 0

		if label_test[i] == flag:
			right_cnt += 1

		# 输出结果
		print("预测为: {0}, 实际为: {1}".format(flag, label_test[i]))

	return right_cnt / TEST_NUM

def plot_e(a_list):
	import matplotlib.pyplot as plt
	x = np.arange(1, len(a_list) + 1)
	y = np.array(a_list)   # 转化为向量

	print("最后误差:", y[-1])

	# 绘制
	plt.plot(x, y)
	plt.xlabel("practiseTime")
	plt.ylabel("variance")
	plt.show()
	pass

def main():
	file_name = "horseColicTraining.txt"
	data_set, label_set = load_data(file_name)
	w1, b1, w2, b2 = paramter_init(len(data_set[0]), len(data_set[0]) + 30, 1)

	# 进行两千次的训练
	a_list = []
	for i in range(1500):
		w1, b1, w2, b2 = my_trainning(data_set, label_set, w1, b1, w2, b2)

		num = get_e(data_set, label_set, w1, b1, w2, b2)

		a_list.append(num[0, 0])

	# 绘制方差的图像
	plot_e(a_list)

	# 进行测试
	file_name_2 = "horseColicTest.txt"
	data_test, label_test = load_data(file_name_2)
	rate = predict_test(data_test, label_test, w1, b1, w2, b2)
	print("预测的正确率为: ", rate)
	pass


if __name__ == "__main__":
	main()

2.1.1 方差的图像

在这里插入图片描述

2.1.2 预测结果

在这里插入图片描述

2.2 矩阵乘积分析

  • 矩阵内数的乘积

在这里插入图片描述

  • 矩阵乘积

在这里插入图片描述

在这里插入图片描述

即:

在这里插入图片描述

2.2 测试集

  • horseColicTraining

2.2 训练集

  • horseColicTest

下载

https://gitee.com/HQHQHQ123/machine_-learning_-bp.git
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值