很多时候我们想找一个简单的分类器示例,却找来找去都是图像分类,而且看起来云里雾里,很难入门。今天我们用 PyTorch 教大家实现一个很简单的二分类器,所用的数据来自 Scikit learn。
我们首先来生成数据,一共 200 个样本:
1 2 | import sklearn.datasets X,y = sklearn.datasets.make_moons(200,noise=0.2) |
绘制以下样本的散点图:
1 2 | import matplotlib.pyplot as plt plt.scatter(X[:,0],X[:,1],s=40,c=y,cmap=sklearn.cm.Spectral) |
可以看到我们生成了两类数据,分别用 0 和 1 来表示。我们接下来将要在这个样本数据上构造一个分类器,采用的是一个很简单的全连接网络,网络结构如下:
这个网络包含一个输入层,一个中间层,一个输出层。中间层包含 3 个神经元,使用的激活函数是 tanh。当然,中间层的神经元越多,分类效果一般越好,但这个 3 层的网络对于我们的样本数据已经足够用了。我们来算一下参数数量:上图中一共有 6 6 = 12 条线,就是 12 个权重,加上 3 2 = 5 个 bias,一共 17 个参数需要训练。
首先我们将样本数据从 numpy 转成 tensor:
1 2 | X = torch.from_numpy(X).type(torch.FloatTensor) y = torch.from_numpy(y).type(torch.LongTensor) |
然后构建我们的神经网络:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | import torch.nn as nn import torch.nn.functional as F class MyClassifier(nn.Module): def __init__(self): super(MyClassifier,self).__init__() self.fc1 = nn.Linear(2,3) self.fc2 = nn.Linear(3,2) def forward(self,x): x = self.fc1(x) x = F.tanh(x) x = self.fc2(x) return x def predict(self,x): pred = F.softmax(self.forward(x)) ans = [] for t in pred: if t[0]>t[1]: ans.append(0) else: ans.append(1) return torch.tensor(ans) |
我们的损失函数用 CrossEntropyLoss
,梯度优化器使用 Adam:
1 2 3 | model = Net() criterion = nn.CrossEntropyLoss() optimizer = torch.optim.Adam(model.parameters(), lr=0.01) |
开始训练:
1 2 3 4 5 6 7 8 9 | epochs = 10000 losses = [] for i in range(epochs): y_pred = model.forward(X) loss = criterion(y_pred,y) losses.append(loss.item()) optimizer.zero_grad() loss.backward() optimizer.step() |
我们来看一下 training error:
1 2 3 4 5 | from sklearn.metrics import accuracy_score print(accuracy_score(model.predict(X),y)) OUTPUT : 0.97 |
为了更直观地展示分类结果,我们将结果可视化:
1 2 3 4 | def predict(x): x = torch.from_numpy(x).type(torch.FloatTensor) ans = model.predict(x) return ans.numpy() |
下面的函数帮助我们在两个分类之间画一条分界线:
1 2 3 4 5 6 7 8 9 | def plot_decision_boundary(pred_func,X,y): x_min, x_max = X[:, 0].min() - .5, X[:, 0].max() .5 y_min, y_max = X[:, 1].min() - .5, X[:, 1].max() .5 h = 0.01 xx,yy=np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h)) Z = pred_func(np.c_[xx.ravel(), yy.ravel()]) Z = Z.reshape(xx.shape) plt.contourf(xx, yy, Z, cmap=plt.cm.Spectral) plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.binary) |
输出图像:
1 | plot_decision_boundary(lambda x : predict(x) ,X.numpy(), y.numpy()) |
可以看出,分类效果还是很不错的。
完整代码:Github
本站微信群、QQ群(三群号 726282629):
model = Net()中的Net从哪来的?