機器學習技術棧之邏輯迴歸(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_
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章