接上一个博客《Machine Learning In Action 学习笔记之 Logistic regression》,这使用的是Numpy进行回归,但我想改用Pytorch框架来写这个程序。
给定数据集(前两列为特征x1, x2,第三列为标签y) 如下所示:
-0.017612 14.053064 0
-1.395634 4.662541 1
-0.752157 6.538620 0
-1.322371 7.152853 0
0.423363 11.054677 0
0.406704 7.067335 1
0.667394 12.741452 0
-2.460150 6.866805 1
0.569411 9.548755 0
-0.026632 10.427743 0
0.850433 6.920334 1
1.347183 13.175500 0
1.176813 3.167020 1
…
原来是将数据转化为np.array形式,而为了使用Pytorch,就需要将numpy转化为tensor数据,使用torch.from_numpy()进行转化,数据导入与转换代码如下:
def loadData():
fr = open('testSet.txt')
X = []
y = []
for line in fr.readlines():
lineArr = line.strip().split()
X.append([float(lineArr[0]), float(lineArr[1])])
y.append(int(lineArr[2]))
X, y = loadData()
X = np.array(X)
y = np.array(y)
# 转为tensor类型
X = torch.from_numpy(X)
y = torch.from_numpy(y)
return X, y
但这里会出现一个问题:
意思就是期望的数据类型为Float,但是给的数据类型是Double,所以报错。查了很久从这篇博客中发现了 from_numpy() 的一个问题:博客地址 , 其中,当 ndarray的类型是float64时,from_numpy(ndarray) 转化为 torch.DoubleTensor ,所以不能使用这样的转化函数,另辟蹊径,选择 torch.Tensor() 进行numpy的转化就没有错了。
X = torch.Tensor(X)
因为Logistics Regression 的原理就是这张图:
所以可以用Pytorch设计这样的神经网络:
一层为线性层,一层为sigmoid,
则代码如下:
class Logistic(nn.Module):
def __init__(self, input_size, hidden_size):
super(Logistic, self).__init__()
self.layer = nn.Linear(input_size, hidden_size)
self.sigmoid = nn.Sigmoid()
def forward(self, X):
out = self.layer(X)
out = self.sigmoid(out)
return out
然后开始 训练模型:
def main():
X, y = loadData()
# print(y)
# 一定要将y的shape转化一下
y = y.reshape([100, 1])
#print(X)
#print(y)
# m为数据个数,n为特征数即input_size
m, n = X.shape
h_size = 1
# 模型为model
model = Logistic(n, h_size)
# 损失函数
criterion = nn.MSELoss()
# 优化器
optimizer = optim.SGD(model.parameters(), lr = 0.01)
for t in range(10000):
# 通过模型生成y_pred
y_pred = model(X)
#print(y_pred)
# 如果不转换为float,会出ValueError: only one element tensors can be converted to Python scalars
loss = criterion(y.float(), y_pred.float())
# 统计正确预测的个数
mask = y_pred.ge(0.5).float()
correct = (mask == y.float()).sum()
accuracy = correct.item()/X.size(0)
if t % 100 == 99:
print("第{}次损失为{},正确率为{}".format(t, loss.item(), accuracy))
# 把梯度置零(必须要)
optimizer.zero_grad()
# 求loss
loss.backward()
# 反向传播求step
optimizer.step()
运行一下,结果如下:
编写一下画图函数:
def plot(weights, bias):
# 加载数据集
dataMat, labelMat = loadData()
# 转换成numpy的array数组
dataArr = np.array(dataMat)
#print(dataArr)
# 数据个数
# 例如建立一个4*2的矩阵c,c.shape[1]为第一维的长度2, c.shape[0]为第二维的长度4
n = np.shape(dataMat)[0]
# 正样本
xcord1 = []
ycord1 = []
# 负样本
xcord2 = []
ycord2 = []
# 根据数据集标签进行分类
for i in range(n):
if int(labelMat[i]) == 1:
# 1为正样本
xcord1.append(dataArr[i, 0])
ycord1.append(dataArr[i, 1])
else:
# 0为负样本
xcord2.append(dataArr[i, 0])
ycord2.append(dataArr[i, 1])
# 新建图框
fig = plt.figure()
# 添加subplot
ax = fig.add_subplot(111)
# 绘制正样本
ax.scatter(xcord1, ycord1, s=20, c='red', marker='s', alpha=.5)
# 绘制负样本
ax.scatter(xcord2, ycord2, s=20, c='green', alpha=.5)
# x轴坐标
x = np.arange(-3.0, 3.0, 0.1)
# w1*x1 + w2*x2 + b = 0
# x1 = x, x2 = y
y = (- bias - weights[0][0] * x ) / weights[0][1]
ax.plot(x, y)
# 绘制title
plt.title('BestFit')
# 绘制label
plt.xlabel('x1')
plt.ylabel('y2')
# 显示
plt.show()
从模型中取出线性层的参数,然后画图即可
# 取出线性层参数
params=model.state_dict()
weights = params['layer.weight']
bias = params['layer.bias']
#print(weights.numpy())
#print(bias.numpy()[0])
plot(weights.numpy(), bias.numpy()[0])
最后显示为: