首页 > 解决方案 > 提高从头开始构建的多项逻辑回归模型的准确性

问题描述

我目前正在使用 numpy 创建一个多类分类器,最后使用 softmax 得到了一个工作模型,如下所示:

class MultinomialLogReg:
    def fit(self, X, y, lr=0.00001, epochs=1000):
        self.X = self.norm_x(np.insert(X, 0, 1, axis=1))
        self.y = y
        self.classes = np.unique(y)
        self.theta = np.zeros((len(self.classes), self.X.shape[1]))
        self.o_h_y = self.one_hot(y)
        
        for e in range(epochs):
            preds = self.probs(self.X)

            l, grad = self.get_loss(self.theta, self.X, self.o_h_y, preds)
            
            if e%10000 == 0:
                print("epoch: ", e, "loss: ", l)
            
            self.theta -= (lr*grad)
        
        return self
    
    def norm_x(self, X):
        for i in range(X.shape[0]):
            mn = np.amin(X[i])
            mx = np.amax(X[i])
            X[i] = (X[i] - mn)/(mx-mn)
        return X
    
    def one_hot(self, y):
        Y = np.zeros((y.shape[0], len(self.classes)))
        for i in range(Y.shape[0]):
            to_put = [0]*len(self.classes)
            to_put[y[i]] = 1
            Y[i] = to_put
        return Y
    
    def probs(self, X):
        return self.softmax(np.dot(X, self.theta.T))
    
    def get_loss(self, w,x,y,preds):
        m = x.shape[0]
        
        loss = (-1 / m) * np.sum(y * np.log(preds) + (1-y) * np.log(1-preds))
        
        grad = (1 / m) * (np.dot((preds - y).T, x)) #And compute the gradient for that loss
        
        return loss,grad

    def softmax(self, z):
        return np.exp(z) / np.sum(np.exp(z), axis=1).reshape(-1,1)
    
    def predict(self, X):
        X = np.insert(X, 0, 1, axis=1)
        return np.argmax(self.probs(X), axis=1)
        #return np.vectorize(lambda i: self.classes[i])(np.argmax(self.probs(X), axis=1))
        
    def score(self, X, y):
        return np.mean(self.predict(X) == y)

并且有几个问题:

  1. 这是一个正确的多项式逻辑回归实现吗?

  2. 使用 0.1 的学习率需要 100,000 个 epoch 才能使损失达到 1 - 0.5 并在测试集上获得 70 - 90% 的准确度。这会被认为表现不佳吗?

  3. 有哪些方法可以提高性能或加快训练(需要更少的 epoch)?

  4. 我在网上看到了这个成本函数,它提供了更好的准确性,它看起来像交叉熵,但它与我看到的交叉熵优化方程不同,有人可以解释一下两者的不同之处:

error = preds - self.o_h_y
grad = np.dot(error.T, self.X)
self.theta -= (lr*grad)

标签: pythonnumpylogistic-regression

解决方案


  1. 这看起来不错,但我认为您在 fit 函数中执行的预处理应该在模型之外完成。
  2. 很难知道这是好是坏。虽然损失情况是凸的,但获得最小值所需的时间因不同问题而异。确保您获得最佳解决方案的一种方法是添加一个阈值来测试梯度范数的大小,当您接近最优值时,该阈值很小。类似的东西np.linalg.norm(grad) < 1e-8
  3. 您可以使用更好的优化器,例如牛顿法,或准牛顿法,例如 LBFGS。我会从牛顿的方法开始,因为它更容易实现。LBFGS 是一种非平凡算法,它近似于执行牛顿法所需的 Hessian。
  4. 一样的; 梯度没有被平均。由于您正在执行梯度下降,因此平均是一个可以忽略的常数,因为无论如何都需要适当调整的学习率。一般来说,我认为平均可以更容易地在同一数据集的不同拆分上获得稳定的学习率。

给你一个问题:当你评估你的测试集时,你是否像在 fit 函数中处理训练集一样对它们进行预处理?


推荐阅读