逻辑回归原理参考链接:线性分类|机器学习推导系列(四)
一、逻辑回归从零开始实现
1. 导入所需要的库
import numpy as np import matplotlib.pyplot as plt
2. 人工构造数据集
构造一个比较简单的二分类数据集,满足高斯分布,并进行了数据的可视化。
def create_data(size): X0=np.random.normal(2,1,(size,2)) y0=np.zeros(size) X1=np.random.normal(-2,1,(size,2)) y1=np.ones(size) X=np.concatenate((X0,X1),axis=0) y=np.concatenate((y0,y1),axis=0) return X,y X,y=create_data(1000) X_test,y_test=create_data(100) # 可视化数据 plt.scatter(X[:,0],X[:,1],c=y,s=40,lw=0, cmap='RdYlGn') plt.show() # 添加偏置 X=np.insert(X,0,1,axis=1) y=y.reshape(y.shape[0],-1) X_test=np.insert(X_test,0,1,axis=1) y_test=y_test.reshape(y_test.shape[0],-1)
3. 初始化模型参数
n_samples,n_features=np.shape(X) limit=np.sqrt(n_features) w=np.random.uniform(-limit,limit,(n_features,1)) # 学习参数 lr=.1 # 学习率 iters=1001 # 迭代次数
4. 定义sigmoid函数
def sigmoid(x): return 1/(1+np.exp(-x))
5. 定义优化算法
def gradient_descent(X,y,w,lr): y_pred=sigmoid(X@w) gradient=-((y-y_pred)*X).sum(axis=0) gradient=gradient.reshape(gradient.shape[0],-1) w=w-lr*gradient return w
6. 定义损失函数
def loss(X,y,w): y_pred=sigmoid(X@w) delta=1e-7 left_log=np.log(y_pred+delta) right_log=np.log(1-y_pred+delta) l=-(y*left_log+(1-y)*right_log).sum() return l
7. 训练模型
定义测试函数。
def test(X_test,y_test): y_test_pred=sigmoid(X_test@w) y_test_pred[y_test_pred>=0.5]=1.0 y_test_pred[y_test_pred<0.5]=0.0 correct_list=[] for i,pred in enumerate(y_test_pred): is_correct = 1 if pred==y_test[i] else 0 correct_list.append(is_correct) acc = sum(correct_list) / len(y_test) return acc
定义训练过程,并且进行记录。
iter_num=[] acc_num=[] loss_num=[] for i in range(iters): w=gradient_descent(X,y,w,lr) if i%50 == 0: iter_num.append(i) acc_num.append(test(X_test,y_test)) loss_num.append(loss(X,y,w))
8. 结果可视化
plt.subplot(221) plt.plot(iter_num,acc_num,color='r',label='acc') plt.xlabel('epochs') plt.ylabel('acc') plt.title("acc") plt.legend() plt.show() plt.subplot(222) plt.plot(iter_num,loss_num,color='r',label='loss') plt.xlabel('epochs') plt.ylabel('loss') plt.title("loss") plt.legend() plt.show()
二、使用torch.nn实现逻辑回归
1. 导入所需要的库
import torch import torch.nn as nn import numpy as np import matplotlib.pyplot as plt
2. 人工构造数据集
使用与之前同样的数据。
def create_data(size): n_data=torch.ones(size,2) X0=torch.normal(2*n_data,1) y0=torch.zeros(size) X1=torch.normal(-2*n_data,1) y1=torch.ones(size) X=torch.cat((X0,X1),0).type(torch.FloatTensor) y=torch.cat((y0,y1),0).type(torch.FloatTensor) return X,y X,y=create_data(1000) X_test,y_test=create_data(100) plt.scatter(X.data.numpy()[:,0],X.data.numpy()[:,1],c=y.data.numpy(),s=40,lw=0,cmap='RdYlGn') plt.show()
3. 定义模型
逻辑回归相当于一个两层神经网络,输出层只有一个节点,并且激活函数为sigmoid函数。
class LogisticRegression(nn.Module): def __init__(self): super(LogisticRegression,self).__init__() self.lr = nn.Linear(2,1) self.sigmoid = nn.Sigmoid() def forward(self,X): X=self.lr(X) X=self.sigmoid(X) return X model = LogisticRegression()
4. 定义损失函数和优化器
criterion=nn.BCELoss() optimizer=torch.optim.Adam(model.parameters(),lr=1e-3)
5. 训练模型
iter_num=[] acc_num=[] loss_num=[] for epoch in range(3): logit=model(X) loss=criterion(logit,y) y_pred=logit.ge(0.5).float() correct=(y_pred==y).sum() acc=correct.item()/X.size(0) optimizer.zero_grad() loss.backward() optimizer.step() if (epoch+1)%1==0: iter_num.append(epoch) acc_num.append(acc) loss_num.append(loss.data.item()) print('epoch:{}'.format(epoch+1),',','loss:{:.4f}'.format(loss.data.item()),',','acc:{:.4f}'.format(acc))
6. 结果可视化
plt.subplot(221) plt.plot(iter_num,acc_num,color='r',label='acc') plt.xlabel('epochs') plt.ylabel('acc') plt.title("acc") plt.legend() plt.show() plt.subplot(222) plt.plot(iter_num,loss_num,color='r',label='loss') plt.xlabel('epochs') plt.ylabel('loss') plt.title("loss") plt.legend() plt.show()