目录
一、线性神经网络(线性输入)
1、基础理论
线性神经网络和上面的单层感知器十分相似,只是把单层感知器的sign激活函数改成了purelin函数:y=x。
有两个地方需要修改:
1、修改激活函数
因为线性神经网络的激活函数是y=x,所以就不再需要np.sign()了。
2、 不需要拟合后退出
由于不是之前的sign激活函数(输出0/1),线性神经网络会无限逼近,一般不会与标签完全拟合,可以更好地训练样本。
2、线性输入代码
和前面的单层感知器基本一致。
# 手写单层感知器(多数据分类)
import numpy as np
import matplotlib.pyplot as plt
# 1、设置初始参数
# 输入 #每一行对应一个标签
x = np.array([[1, 0, 2], #(0,2)坐标
[1, 1, 3], #(1,3)坐标
[1, 4, 2], #(4,2)坐标
[1, 5, 1] #(5,1)坐标
])
# 初始权重(0~1的随机生产数)
w = np.random.random([3, 1]) #3行1列
# 偏置
b = 1
# 标签(正确标签,训练结束的目标)
true = np.array([ #每一行对应一个标签
[-1],
[-1],
[ 1],
[ 1]
])
# 学习率
lr = 0.1
# 开始训练
for i in range(100):
# 2、正向传播:计算输出y
y = np.dot(x, w) #dot:矩阵乘法(x列==w行)
print('epoch:', i) #迭代次数
print('weight:', w) #权重
print(y) #标签
# 训练成功
if (y == true).all():
print('训练成功!')
print('y = ', y)
break
# 3、反向传播:更新权重
# 训练失败(更新权重)
else:
w += lr * np.dot(x.T, true-y)/x.shape[0]
# w:权重 lr:学习率 np.dot:矩阵点乘 true-y:差 x.T:x的转置 x.shape[0]:行数
# 4、画图
# 4-1、画点
# 正样本坐标
x1, y1 = [0,1], [2,3] #坐标:(0,2), (1,3)
# 负样本坐标
x2, y2 = [4,5], [2,1] #坐标:(4,2),(5,1)
plt.scatter(x1, y1, c='b') #点:(x1,y1)坐标,blue颜色
plt.scatter(x2, y2, c='g') #点:(x2,y2)坐标,green颜色
# 4-2、画线段
# 定义线段两点的x坐标
line_x = (0, 6)
# 计算线性方程的k和d:
# w0*x0+w1*x1+w2*x2 = 0
# 把x1、x2分别看作:x、y
# 可以得到:w0 + w1*x + w2*y = 0 --> y = -w1/w2*x + -w0/w2 --> k=-w1/w2, d=-w0/w2
# 线段两端点的y坐标
k = -w[1]/w[2] #斜率
d = -w[0]/w[2] #截距
line_y = k * line_x + d #y坐标
#画线段(通过两个点)
plt.plot(line_x, line_y, 'r') #r:red
plt.show()
训练5次:
训练500次:
由于不断逼近训练的缘故,可以发现500次的拟合效果比5次的明显好不少。
奇葩错误:
之前由于学习率设置过大,训练多少次都无法成功。
二、线性神经网络(非线性输入)
0、引言
有些比较复杂的情况是没办法用线性神经网络的线性输入处理的,比如异或问题:
可以很明显发现,一条直线无法划分异或问题,这是非线性问题,这时就需要用线性神经网络的非线性输入来处理这些问题了。
1、基础理论
线性神经网络可以引入非线性输入特征来解决非线性问题。
这是线性神经元非线性输入的模型:
三、线性神经网络(非线性输入)实战
1、设置初始参数
# 1、设置初始参数
# 输入 #每一行对应一个标签
# 六个参数分别为:x0 x1 x2 x1*x1 x1*x2 x2*x2
x = np.array([[1, 0, 0, 0, 0, 0], #坐标(0,0) -1
[1, 0, 1, 0, 0, 1], #坐标(0,1) 1
[1, 1, 0, 1, 0, 0], #坐标(1,0) 1
[1, 1, 1, 1, 1, 1] #坐标(1,1) -1
])
# 这些点者用来训练线性模型,作为线性模型的输入。
# 初始权重(0~1的随机生产数)
w = np.random.random([6, 1]) #3行1列
# 偏置
b = 1
# 标签(正确标签,训练结束的目标)
true = np.array([ #每一行对应一个标签
[-1],
[1],
[1],
[-1]
])
# 学习率
lr = 0.1
2、正向传播,求线性输出y
# 开始训练
for i in range(500):
# 2、正向传播:计算输出y
y = np.dot(x, w) #dot:矩阵乘法(x列==w行)
3、反向传播,更新权重w
# 3、反向传播:更新权重
# 更新权重
w += lr * np.dot(x.T, true-y)/x.shape[0]
# w:权重 lr:学习率 np.dot:矩阵点乘 true-y:差 x.T:x的转置 x.shape[0]:行数
4、训练&&预测(画图)
4-1、画正负样本点坐标
# 4-1、画点
# 正样本坐标
x1, y1 = [0,1], [1,0] #坐标:(0,2), (1,3)
# 负样本坐标
x2, y2 = [0,1], [0,1] #坐标:(4,2),(5,1)
plt.scatter(x1, y1, c='b') #点:(x1,y1)坐标,blue颜色
plt.scatter(x2, y2, c='g') #点:(x2,y2)坐标,green颜色
4-2、获取非线性输出模型(y)
1、生成100个输入点横坐标
# 获取训练集横坐标(在(-1,2)上均匀100个数,作为横坐标)
line_x = np.linspace(-1,2,100)
2、计算非线性输出
根据前面输入的100个横坐标,求出它们的非线性输出y:
# 计算非线性方程的y:
# 计算非线性输出(非线性输入x的非线性输出y)
def Calculate(line_x, root):
# 定义参数
a = w[5]
b = w[2] + w[4]*line_x
c = w[0] + w[1]*line_x + w[3]*line_x*line_x
# 计算输出y
if root == 1:
line_y = (-b+np.sqrt(b*b - 4*a*c))/(2*a)
return line_y
elif root == 2:
line_y = (-b-np.sqrt(b*b - 4*a*c))/(2*a)
return line_y
3、根据这100个点画出“曲线”
# 画曲线
plt.plot(line_x, Calculate(line_x,1), 'r') #r:red
plt.plot(line_x, Calculate(line_x,2), 'r') #r:red
plt.show()
注:这里是点数量足够多 ,才能看起来像曲线,如果点数量不够,那么就是明显的折线了。
比如只生成3个点:
line_x = np.linspace(-1,2,3)
非线性输入代码
# 手写单层感知器(多数据分类)
import numpy as np
import matplotlib.pyplot as plt
# 1、设置初始参数
# 输入 #每一行对应一个标签
# 六个参数分别为:x0 x1 x2 x1*x1 x1*x2 x2*x2
x = np.array([[1, 0, 0, 0, 0, 0], #坐标(0,0) -1
[1, 0, 1, 0, 0, 1], #坐标(0,1) 1
[1, 1, 0, 1, 0, 0], #坐标(1,0) 1
[1, 1, 1, 1, 1, 1] #坐标(1,1) -1
])
# 这些点者用来训练线性模型,作为线性模型的输入。
# 初始权重(0~1的随机生产数)
w = np.random.random([6, 1]) #3行1列
# 偏置
b = 1
# 标签(正确标签,训练结束的目标)
true = np.array([ #每一行对应一个标签
[-1],
[1],
[1],
[-1]
])
# 学习率
lr = 0.1
# 开始训练
for i in range(500):
# 2、正向传播:计算输出y
y = np.dot(x, w) #dot:矩阵乘法(x列==w行)
# 3、反向传播:更新权重
w += lr * np.dot(x.T, true-y)/x.shape[0]
# w:权重 lr:学习率 np.dot:矩阵点乘 true-y:差 x.T:x的转置 x.shape[0]:行数
print('epoch:', i) #迭代次数
print('weight:', w) #权重
print(y) #标签
# 4、训练&&预测(画图)
# 4-1、画点
# 正样本坐标
x1, y1 = [0,1], [1,0] #坐标:(0,2), (1,3)
# 负样本坐标
x2, y2 = [0,1], [0,1] #坐标:(4,2),(5,1)
plt.scatter(x1, y1, c='b') #点:(x1,y1)坐标,blue颜色
plt.scatter(x2, y2, c='g') #点:(x2,y2)坐标,green颜色
# 4-2、非线性输出
# 获取训练集横坐标(在(-1,2)上均匀100个数,作为横坐标)
line_x = np.linspace(-1,2,100)
# 计算非线性方程的y:
# 计算非线性输出(非线性输入x的非线性输出y)
def Calculate(line_x, root):
# 定义参数
a = w[5]
b = w[2] + w[4]*line_x
c = w[0] + w[1]*line_x + w[3]*line_x*line_x
# 计算输出y
if root == 1:
line_y = (-b+np.sqrt(b*b - 4*a*c))/(2*a)
return line_y
elif root == 2:
line_y = (-b-np.sqrt(b*b - 4*a*c))/(2*a)
return line_y
# 画曲线
plt.plot(line_x, Calculate(line_x,1), 'r') #r:red
plt.plot(line_x, Calculate(line_x,2), 'r') #r:red
plt.show()