当散点能找到一条很明显的决策边界的时候,用逻辑回归也可解决问题,当离散点之间难以找到一条明显的决策边界的时候,显然逻辑回归就不再适用了,可以考虑使用神经网络进行回归。
我们不再人工生成数据点,而是通过导入数据集sklearn导入不规则的数据,下面直接贴代码吧~
1.导入必要的库
#数据点杂乱的数据集用回归模型难以找到一条明显的决策边界,考虑用神经网络分类
from sklearn import datasets #导入数据集sklearn,不再人工生成数据点
import numpy as np
import matplotlib.pyplot as plt
2.生成数据点
#x,y = datasets.make_circles(100) #生成数据点
#x,y = datasets.make_circles(100,noise=0.1,factor=0.2) #noise添加噪声,factor为远近程度
x,y = datasets.make_circles(300,noise=0.2,factor=0.3)
plt.scatter(x[:,0],x[:,1],c=y)
plt.show()
没有添加噪声的数据点,也就是这句代码
(x,y = datasets.make_circles(100) #生成数据点)
(代码1)
生成的图片是这样的
(图1)
鉴于这种数据点过于难找决策边界,我们通过添加噪声noise和设置factor来进一步打乱数据点 ,也就是这句代码
x,y = datasets.make_circles(100,noise=0.1,factor=0.2)
(代码2)
生成的数据点如下
(图2)
这里说一下factor,如果单纯的加入噪声生成的数据点是这样的
x,y = datasets.make_circles(300,noise=0.2)
(代码3)
(图3)
可以看到点与点之间很密集,还是很难进行分类的,所以通过加入factor来增大点与点之间的距离(毕竟我们现在只是想实现一个简单的基于sklearn的分类,一切从简就好)
x,y = datasets.make_circles(300,noise=0.2,factor=0.3)
(代码4)
(图4)
这样我们的数据点就生成完毕。
3.确定神经网络的结构
我们生成的是两类数据点的300个样本,所以对应的input layer有300个样本做输入,output layer有两个神经元做输出分别对应两个类别,这里只采用一层hidden layer,我们设了10个神经元。
nn_input_dim = 2
nn_output_dim = 2
num_examples = len(x)
下面是网络正向传播的计算过程
简言之就是input layer经过第一层和第二层间的权重w1,b1得到计算结果z1,hidden layer用这个计算结果z1做输入,通过第二层到输出层的权重w2,b2得到输出结果z2,计算过程中用到激活函数tanh,因为不做激活函数的话即便是经过了10层线性映射最后的结果仍然是线性的,这样层数就没有意义了:
#线性推理,正向梳理过程,也就是输入到输出的过程
w1= np.random.randn(nn_output_dim,10) #input layer到hidden layer之间的权重w1,其中hidden我们设10个神经元
w2 = np.random.randn(10,nn_output_dim) #hiddenlayer到output layer之间的权w2,其中hidden是10个神经元,输出是2分类所以输出dim是2
b1 = np.random.randn(1,10)
b2 = np.random.randn(1,2)
def inference(x1,x2):
#input layer:
#X1是第一个特征
X = np.hstack(([x1],[x2])) #input层
#X.shape(2,)
#w1.shape(2,hidden_dim) w2.shape(hidden_dim,2)
#b1.shape(1,hidden_dim) b2.shaoe(1,2)
#hidden layer:
z1 = X.dot(w1) + b1
a1 = np.tanh(z1)
z2 = a1.dot(w2) + b2
exp_z2 = np.exp(z2)
probs = exp_z2/np.sum(exp_z2,axis=1,keepdims=True)
print(probs.shape)
return probs
#print(inference(2,1))
print(inference(2,1))
打印一个结果如下
4.计算梯度
把上一步的初始化参数部分注释掉,在这个函数里重新定义一下参数,为了方便使用把他们放在一个字典里
#梯度计算
def build_model(hidden_dim,iterations=1000):
w1 = np.random.randn(nn_input_dim,hidden_dim)
b1 = np.random.randn(1,hidden_dim)
w2 = np.random.randn(hidden_dim,nn_output_dim)
b2 = np.random.randn(1,nn_output_dim)
model ={'w1':w1,'b1':b1,'w2':w2,'b2':b2} #定义一个字典把参数放进去
由于我们把上一步前向计算部分的参数注释掉了,在这一步梯度计算的函数里重新定义了参数,所以需要回过头去在前向计算部分重新引用这一部分定义的权重,方法是给def函数加一个参数model,并且在def函数里引用参数
第三步的代码部分修改如下:
def inference(x1,x2,model):#比上一步的def函数括弧内多了一个model
w1,b1,w2,b2 = model['w1'],model['b1'],model['w2'],model['b2']#函数部分添加此行,其余部分跟上一步写的一样
继续回到梯度下降部分,在def前设置一下学习率
learning_rate = 1e-2
整个模块的代码如下
learning_rate = 1e-2
#梯度计算
def build_model(hidden_dim,iterations=1000):
w1 = np.random.randn(nn_input_dim,hidden_dim)
b1 = np.random.randn(1,hidden_dim)
w2 = np.random.randn(hidden_dim,nn_output_dim)
b2 = np.random.randn(1,nn_output_dim)
model ={'w1':w1,'b1':b1,'w2':w2,'b2':b2}
#梯度下降
for i in range(iterations):
#forward
z1 = x.dot(w1) + b1
a1 = np.tanh(z1)
z2 = a1.dot(w2) + b2
exp_z2 = np.exp(z2)
probs = exp_z2 / np.sum(exp_z2, axis=1, keepdims=True)
#backward
delta3 = probs
delta3[range(num_examples),y] -= 1 #跳了三步,从交叉熵跳到了softmax之前
dw2 = a1.T.dot(delta3) #w2的导数
db2 = np.sum(delta3,axis=0,keepdims=True) #b2的导数
delta2 = delta3.dot(w2.T)*(1-np.power(a1,2)) #tanh求导
dw1 = np.dot(x.T,delta2) #w1的导数
db1 = np.sum(delta2,axis=0) #b1的导数
w1 -= learning_rate*dw1
b1 -= learning_rate * db1
w2 -= learning_rate * dw2
b1 -= learning_rate * db1
model = {'w1': w1, 'b1': b1, 'w2': w2, 'b2': b2} #输出模型的参数观察一下
print(model)
return model
build_model(hidden_dim=10)
5.损失函数表示
#输出w,b都是数字难以观察,用损失函数表示出来
def calculate_loss(model):
w1, b1, w2, b2 = model['w1'], model['b1'], model['w2'], model['b2']
z1 = x.dot(w1) + b1
a1 = np.tanh(z1)
z2 = a1.dot(w2) + b2
exp_z2 = np.exp(z2)
probs = exp_z2 / np.sum(exp_z2, axis=1, keepdims=True)
log_probs = -np.log(probs[range(num_examples),y])
loss = np.sum(log_probs)
return loss/num_examples
这部分代码写带第四步代码的上面,然后再修改第四步代码最后print部分的代码为:
model = {'w1': w1, 'b1': b1, 'w2': w2, 'b2': b2}
# print(model)
print(calculate_loss(model))
return model
修改完后再运行部分输出结果如下所示:
完整部分代码:
#数据点杂乱的数据集,用神经网络分类
from sklearn import datasets #导入数据集sklearn
import numpy as np
import matplotlib.pyplot as plt
x,y = datasets.make_circles(300,noise=0.2,factor=0.3) #生成数据点,factor为远近程度
plt.scatter(x[:,0],x[:,1],c=y)
plt.show()
learning_rate = 1e-2
nn_input_dim = 2
nn_output_dim = 2
num_examples = len(x)
#线性推理,正向梳理过程,也就是输入到输出的过程
# w1= np.random.randn(nn_output_dim,10) #input layer到hidden layer之间的权重w1,其中hidden我们设10个神经元
# w2 = np.random.randn(10,nn_output_dim) #hiddenlayer到output layer之间的权w2,其中hidden是10个神经元,输出是2分类所以输出dim是2
# b1 = np.random.randn(1,10)
# b2 = np.random.randn(1,2)
def inference(x1,x2,model):
#input layer:
#X1是第一个特征
X = np.hstack(([x1],[x2])) #input层
w1,b1,w2,b2 = model['w1'],model['b1'],model['w2'],model['b2']
#X.shape(2,)
#w1.shape(2,hidden_dim) w2.shape(hidden_dim,2)
#b1.shape(1,hidden_dim) b2.shaoe(1,2)
#hidden layer:
z1 = X.dot(w1) + b1
a1 = np.tanh(z1)
z2 = a1.dot(w2) + b2
exp_z2 = np.exp(z2)
probs = exp_z2/np.sum(exp_z2,axis=1,keepdims=True)
print(probs.shape)
return probs
# print(inference(2,1))
#输出w,b都是数字难以观察,用损失函数表示出来
def calculate_loss(model):
w1, b1, w2, b2 = model['w1'], model['b1'], model['w2'], model['b2']
z1 = x.dot(w1) + b1
a1 = np.tanh(z1)
z2 = a1.dot(w2) + b2
exp_z2 = np.exp(z2)
probs = exp_z2 / np.sum(exp_z2, axis=1, keepdims=True)
log_probs = -np.log(probs[range(num_examples),y])
loss = np.sum(log_probs)
return loss/num_examples
learning_rate = 1e-2
#梯度计算
def build_model(hidden_dim,iterations=1000):
w1 = np.random.randn(nn_input_dim,hidden_dim)
b1 = np.random.randn(1,hidden_dim)
w2 = np.random.randn(hidden_dim,nn_output_dim)
b2 = np.random.randn(1,nn_output_dim)
model ={'w1':w1,'b1':b1,'w2':w2,'b2':b2}
#梯度下降
for i in range(iterations):
#forward
z1 = x.dot(w1) + b1
a1 = np.tanh(z1)
z2 = a1.dot(w2) + b2
exp_z2 = np.exp(z2)
probs = exp_z2 / np.sum(exp_z2, axis=1, keepdims=True)
#backward
delta3 = probs
delta3[range(num_examples),y] -= 1 #跳了三步,从交叉熵跳到了softmax之前
dw2 = a1.T.dot(delta3)
db2 = np.sum(delta3,axis=0,keepdims=True)
delta2 = delta3.dot(w2.T)*(1-np.power(a1,2)) #tanh求导
dw1 = np.dot(x.T,delta2)
db1 = np.sum(delta2,axis=0)
w1 -= learning_rate*dw1
b1 -= learning_rate * db1
w2 -= learning_rate * dw2
b1 -= learning_rate * db1
#画图
loss = calculate_loss(model)
axes = plt.gca()
axes.cla()
axes.set_title(f'iteration:{i},loss:{round(loss,3)}')
axes.scatter(x[:,0],x[:,1],c=y)
plt.pause(2)
model = {'w1': w1, 'b1': b1, 'w2': w2, 'b2': b2}
# print(model)
print(calculate_loss(model))
return model
build_model(hidden_dim=10)