机器学习技术栈之逻辑回归(Logistic Regression)

机器学习技术栈之逻辑回归(Logistic Regression)


概述

逻辑回归(Logistic Regression)是根据现有数据对分类边界线(Decision Boundary)建立回归公式,以此进行分类。模型的输出转换为从 0 到 1 之间的概率值。逻辑回归直接对分类的可能性进行建模,无需事先假设数据的分布。
假设现在有一些数据点,我们用一条直线对这些点进行拟合(这条直线称为最佳拟合直线),这个拟合的过程就叫做回归。进而可以得到对这些点的拟合直线方程.


概念

Sigmoid 函数

先介绍一下二值型分类函数, 能根据任意数据输入输出二值分类。在两个类的情况下,二值函数输出 0 或 1. 该类函数称为海维塞得阶跃函数(Heaviside step function),或为 单位阶跃函数。在实践中,海维塞得阶跃函数从 0 跳跃到 1,很难处理。为了避免这个问题, 可以使用平滑和易于求导的对数机率函数 Sigmoid 来替代.
σ(z)=11+ez=11+e(ωTX+b) \sigma(z) = \dfrac{1}{1+e^{-z}} = \dfrac{1}{1+e^{-(\omega^{T_X}+b)}}
在这里插入图片描述
Sigmoid函数是一个在生物学中常见的S型函数,也称为S型生长曲线。可以将一个实数映射到(0,1)的区间. 优点是平滑并易于求导。 缺点激活函数计算量大, 反向传播求误差梯度时,求导涉及除法, 容易出现梯度消失的情况,从而无法完成深层网络的训练。

回归系数

如何使用Sigmoid 函数实现分类器? 只需要征乘以回归系数然后把所有结果值相加,将这个总和代入 Sigmoid 函数中.
假设 Sigmod 函数输出为Z, 则得到
Z=ΣωiXj Z = \Sigma{\omega_{i}X_{j}}
用向量标识,
z=ωTX z = \omega^TX
向量 X是输入数据,向量 ω\omega 是参数,求出最优参数, 也就得到了足够精确的分析器。

逻辑回归算法

极大似然估计法来估计参数ω\omega 和b.
假设
P(Y=1x)=hω(x) \Rho(Y = 1\mid x) = h_\omega(x)
, 似然函数为
Π[hω(xi)]yi[1hω(xi)](1yi) \Pi[h_\omega(x_i)]^{y_i}[1-h\omega(x_i)]^{(1-y_i)}
, 那么对数似然函数为
L(w)=i=1NlogP(yixi;w)=i=1N[yiloghw(xi)+(1yi)log(1hw(xi))] L(w) = \sum _{i=1}^{N}logP(y_i|xi;w) = \sum{i=1}^{N}[y_ilog h_w (x_i) +(1-y_i)log(1-h_w(x_i))]
minJ(ω)=min1m[i=1myiloghw(xi)+(1yi)log(1hw(xi))]minJ(\omega) = min - \frac{1}{m}[\sum _{i=1}^{m}y_ilogh_w (x_i) +(1-y_i)log(1-h_w(x_i))]
接下来我们就可以使用梯度下降算法、牛顿法或者BFGS等拟牛顿法等常用方法来求解. 下面我们可以用一个特殊的方法来求解.

正则化

在模型过于复杂的情况下,模型会学习到很多特征,从而导致可能把所有训练样本都拟合到,这样就导致了过拟合。解决过拟合可以从两个方面入手,一是减少模型复杂度,一是增加训练集个数。而正则化就是减少模型复杂度的一个方法。即以最小化损失和复杂度为目标(结构风险最小化):
J(w)=Loss(x,w)+λComplexity(w) J(w)=Loss(x,w)+λComplexity(w)
对逻辑回归来说,正则化至关重要,可以在目标函数(经验风险)中加上一个正则化项 Φ(w), 即
J(w)=1m[i=1myiloghw(xi)+(1yi)log(1hw(xi))]+λΦ(w) J(w)=−\frac{1}{m}[∑_{i=1}^my_ilogh_w(x_i)+(1−y_i)log(1−h_w(x_i))] + λΦ(w)
采用L1范数或L2范数. 其形式分别为
Φ(w)=w1Φ(w)=||w||_1 , 或 Φ(w)=w22Φ(w)=||w||_2^2
以 L2 正则化为例,
L2RegularTerm=w22=w12+w22++wn2 L_2 Regular Term=||w||_2^2=w^2_1+w^2_2+…+w^2_n

  • 复杂度等于权重的平方和
  • 减少异常大的权重
  • 对线性模型来说首选比较平缓的斜率
  • 贝叶斯先验概率:权重应该以 0 为中心,并呈正态分布
    上述目标函数中的标量λ\lambda 为正则化率, 用来调整正则化项的整体影响, 平衡模型简单化和训练数据的拟合。增大λ\lambda 将增强正则化的效果. 但过高的λ\lambda也会导致欠拟合风险. 推论λ=0\lambda=0则消除正则化.

原理

工作原理

每个回归系数初始化为 1
重复 R 次:
计算整个数据集的梯度
使用 步长 x 梯度 更新回归系数的向量
返回回归系数

算法特点

优点: 计算代价不高,易于理解和实现。
缺点: 容易欠拟合,分类精度可能不高。
适用数据类型: 数值型和标称型数据。

源码学习

下面是kubeflow的源码, 使用牛顿法回归, 用c写的, 请大家赏析一下:

/* Copyright 2016 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
    http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#ifndef TENSORFLOW_CORE_KERNELS_LOGISTIC_LOSS_H_
#define TENSORFLOW_CORE_KERNELS_LOGISTIC_LOSS_H_

#include <cmath>

#include "tensorflow/core/kernels/loss.h"
#include "tensorflow/core/lib/core/errors.h"

namespace tensorflow {

class LogisticLossUpdater : public DualLossUpdater {
 public:
  // Adding vs. Averaging in Distributed Primal-Dual Optimization.
  // Chenxin Ma, Virginia Smith, Martin Jaggi, Michael I. Jordan, Peter
  // Richtarik, Martin Takac http://arxiv.org/abs/1502.03508
  // 一种分布式加平均对偶优化算法
  double ComputeUpdatedDual(const int num_loss_partitions, const double label,
                            const double example_weight,
                            const double current_dual, const double wx,
                            const double weighted_example_norm) const final {
    // Newton algorithm converges quadratically so 10 steps will be largely
    // enough to achieve a very good precision
    // 牛顿法10步就足以获得很精确的结果
    static const int newton_total_steps = 10;
    double x = 0;
    for (int i = 0; i < newton_total_steps; ++i) {
      x = NewtonStep(x, num_loss_partitions, label, wx, example_weight,
                     weighted_example_norm, current_dual);
    }
    return 0.5 * (1 + tanh(x)) / label;
  }

  // Dual of logistic loss function.
  // https://en.wikipedia.org/wiki/Convex_conjugate
  // 双逻辑回归损失函数
  double ComputeDualLoss(const double current_dual, const double example_label,
                         const double example_weight) const final {
    // Dual of the logistic loss function is
    // ay * log(ay) + (1-ay) * log (1-ay), where a is the dual variable.
    const double ay = current_dual * example_label;
    const double log_ay = (ay > 0) ? log(ay) : 0;
    const double one_minus_ay = 1 - ay;
    const double log_one_minus_ay = (one_minus_ay > 0) ? log(one_minus_ay) : 0;
    return ((ay * log_ay) + (one_minus_ay * log_one_minus_ay)) * example_weight;
  }

  // Logistic loss for binary classification.
  // https://en.wikipedia.org/wiki/Loss_functions_for_classification
  // 二分法逻辑回归损失函数
  double ComputePrimalLoss(const double wx, const double example_label,
                           const double example_weight) const final {
    // Logistic loss:
    //   log(1 + e^(-ywx))
    //   log(e^0 + e^(-ywx))
    //   a + log(e^(0-a) + e^(-ywx - a)),  where a is max(0, -ywx)
    // https://hips.seas.harvard.edu/blog/2013/01/09/computing-log-sum-exp/
    const double y_wx = example_label * wx;
    if (y_wx > 0) {
      // 0 + log(e^(0) + e^(-ywx - 0))
      // log(1 + e^(-ywx))
      return log1p(exp(-y_wx)) * example_weight;
    }
    // -ywx + log(e^(ywx) + e^(-ywx + ywx))
    // log(e^(ywx) + e^(0)) - ywx
    // log(1 + e^(ywx)) - ywx
    return (log1p(exp(y_wx)) - y_wx) * example_weight;
  }

  // Derivative of logistic loss
  // 衍生逻辑回归
  double PrimalLossDerivative(const double wx, const double label,
                              const double example_weight) const final {
    double inverse_exp_term = 0;
    if (label * wx > 0) {
      inverse_exp_term = exp(-label * wx) / (1 + exp(-label * wx));
    } else {
      inverse_exp_term = 1 / (1 + exp(label * wx));
    }
    return -inverse_exp_term * label * example_weight;
  }

  // The smoothness constant is 4 since the derivative of logistic loss, which
  // is exp(-x) / (1 + exp(-x)) can be shown to 0.25-Lipschitz (its derivative
  // is bounded by 0.25)
  // 衍生逻辑回归平滑常数为4
  double SmoothnessConstant() const final { return 4; }

  // Converts binary example labels from 0.0 or 1.0 to -1.0 or 1.0 respectively
  // as expected by logistic regression.
  // 将样例标签从0 至1, 变换到 -1 至 1
  Status ConvertLabel(float* const example_label) const final {
    if (*example_label == 0.0) {
      *example_label = -1;
      return Status::OK();
    }
    if (*example_label == 1.0) {
      return Status::OK();
    }
    return errors::InvalidArgument(
        "Only labels of 0.0 or 1.0 are supported right now. "
        "Found example with label: ",
        *example_label);
  }

 private:
  // We use Newton algorithm on a modified function (see readme.md).
  // 牛顿法
  double NewtonStep(const double x, const int num_loss_partitions,
                    const double label, const double wx,
                    const double example_weight,
                    const double weighted_example_norm,
                    const double current_dual) const {
    const double tanhx = tanh(x);
    const double numerator = -2 * label * x - wx -
                             num_loss_partitions * weighted_example_norm *
                                 example_weight *
                                 (0.5 * (1 + tanhx) / label - current_dual);
    const double denominator =
        -2 * label - num_loss_partitions * weighted_example_norm *
                         example_weight * (1 - tanhx * tanhx) * 0.5 / label;
    return x - numerator / denominator;
  }
};

}  // namespace tensorflow

#endif  // TENSORFLOW_CORE_KERNELS_LOGISTIC_LOSS_H_
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章