二元分类问题中对数损失函数(LogLoss)的随机梯度下降(SGD)

上一部分(关于线性回归,梯度下降及其全部工作原理) -habr.com/zh/post/471458

在本文中,我将首先展示针对分类问题的解决方案,正如他们所说的那样,“ pens”,而没有用于SGD,LogLoss和计算梯度的第三方库,然后使用PyTorch库。

目的:对于描述泛黄和对称性的两个分类特征,确定对象所属的类别(苹果或梨)(通过模型对对象进行分类)。

首先,上传我们的数据集:

import pandas as pd data = pd.read_csv("https://raw.githubusercontent.com/DLSchool/dlschool_old/master/materials/homeworks/hw04/data/apples_pears.csv") data.head(10) 



令:x1-黄度,x2-对称度,y =靶

我们组成函数y = w1 * x1 + w2 * x2 + w0
(w0将被视为偏差(英语-偏差))

现在我们的任务简化为找到权重w1,w2和w0,它们最准确地描述了y对x1和x2的依赖性。

我们使用对数损失函数:



函数的左侧参数是当前权重w1,w2,w0的预测

该函数的正确参数是正确的值(类为0或1)

σ(x)是x的S形激活函数

log(x)-x的自然对数

显然,损失函数的值越小,我们选择的权重w1,w2,w0就越好。 为此,请选择随机梯度下降

我注意到LogLoss的公式会有所不同,因为以下事实:在SGD中,我们选择一个元素而不是整个选择(或子样本,如小批量梯度下降的情况):


解决方案进度:

初始权重w1,w2,w0被赋予随机值

我们取数据集的第i个对象(例如,随机数),为其计算LogLoss(使用我们最初分配随机值的w1,w2和w0),然后为权重w1,w2和w0中的每一个计算偏导数,然后更新每个权重。

一些准备:

 import pandas as pd import numpy as np X = data.iloc[:,:2].values #  - y = data['target'].values.reshape((-1, 1)) #  (    ) x1 = X[:, 0] x2 = X[:, 1] def sigmoid(x): return 1 / (1 + np.exp(-x)) 


实现方式:

 import random np.random.seed(62) w1 = np.random.randn(1) w2 = np.random.randn(1) w0 = np.random.randn(1) print(w1, w2, w0) # form range 0..999 idx = np.arange(1000) # random shuffling np.random.shuffle(idx) x1, x2, y = x1[idx], x2[idx], y[idx] # learning rate lr = 0.001 # number of epochs n_epochs = 10000 for epoch in range(n_epochs): i = random.randint(0, 999) yhat = w1 * x1[i] + w2 * x2[i] + w0 w1_grad = -((y[i] - sigmoid(yhat)) * x1[i]) w2_grad = -((y[i] - sigmoid(yhat)) * x2[i]) w0_grad = -(y[i] - sigmoid(yhat)) w1 -= lr * w1_grad w2 -= lr * w2_grad w0 -= lr * w0_grad print(w1, w2, w0) 

[0.49671415] [-0.1382643] [0.64768854]
[0.87991625] [-1.14098372] [0.22355905]

* _grad是相应权重的导数。 我将写出通用公式:



对于自由项w0-因子x被忽略(取等于1)。

使用导数的最终公式,我们可以看到我们不需要显式计算损失函数(我们只需要偏导数)。

让我们检查一下训练集中的对象有多少,我们的模型给出了正确的答案,还有多少-错误的答案。

 i = 0 correct = 0 incorrect = 0 for item in y: if(np.around(x1[i] * w1 + x2[i] * w2 + w0) == item): correct += 1 else: incorrect += 1 i = i + 1 print(correct, incorrect) 

925 75

np.around(x)-舍入x的值。 对于我们:如果x> 0.5,则值为1。如果x≤0.5,则值为0。

如果对象的特征数为5,我们将怎么办? 10个? 100? 并且我们将有适当数量的权重(偏倚加一)。 显然,手动处理每个砝码并为其计算梯度是不方便的。

我们将使用流行的PyTorch库。

PyTorch = NumPy + CUDA + Autograd(自动计算梯度)

PyTorch实施:

 import torch import numpy as np from torch.nn import Linear, Sigmoid def make_train_step(model, loss_fn, optimizer): def train_step(x, y): model.train() yhat = model(x) loss = loss_fn(yhat, y) loss.backward() optimizer.step() optimizer.zero_grad() return loss.item() return train_step X = torch.FloatTensor(data.iloc[:,:2].values) y = torch.FloatTensor(data['target'].values.reshape((-1, 1))) from torch import optim, nn neuron = torch.nn.Sequential( Linear(2, out_features=1), Sigmoid() ) print(neuron.state_dict()) lr = 0.1 n_epochs = 10000 loss_fn = nn.MSELoss(reduction="mean") optimizer = optim.SGD(neuron.parameters(), lr=lr) train_step = make_train_step(neuron, loss_fn, optimizer) for epoch in range(n_epochs): loss = train_step(X, y) print(neuron.state_dict()) print(loss) 

OrderedDict([['0.weight',张量([[-0.4148,-0.5838]])),('0.bias',张量([0.5448]]]))
OrderedDict([['0.weight',张量([[[[5.4915,-8.2156]])),('0.bias',张量([-1.1130]]]))
0.03930133953690529

测试样品的损失相当不错。

在此,选择MSELoss作为损耗函数。

有关线性的更多信息

简而言之:我们给输入2个参数(如上例中的x1和x2),给输出一个参数(y),然后将其馈送到激活函数的输入。 然后就已经计算出它们:误差函数的值,梯度。 最后,权重将更新。

文章中使用的材料

Source: https://habr.com/ru/post/zh-CN472300/


All Articles