開發與維運

零基礎入門機器學習:如何識別一隻貓?

image.png

一 是什麼是機器學習,為什麼我們要機器學習

什麼是機器學習

先看兩個例子:

我們是如何習得“貓”這個動物的?

想象一下一個從來沒有見過貓的人(比如一個小嬰兒),他的詞彙裡面甚至沒有貓這個詞。有一天他看到了一個毛茸茸的動物:

image.png

這時候他不知道這是什麼東西,你告訴他這是 ”貓“。這時候可能小嬰兒記住了,這個就是貓。

又過了段時間他又看見了這樣一個動物:

image.png

你又告訴他這也是貓。他記住了這也是貓。

後來又過了段時間,他又看見了一個動物:

image.png

這時他直接告訴你他看見了一隻“貓”。

以上就是我們認識世界的基本方法,模式識別:人們通過大量的經驗,得到結論,從而判斷它就是貓。

在這個過程中我們通過接觸樣本(各種貓)學習到了貓的特徵(人們通過閱讀進行學習,觀察它會叫、兩隻耳朵、四條腿、一條尾巴、有鬍鬚,得到結論),從而知道什麼是貓。

我們如何知道 npm 包判斷一個 npm 包是測試 npm 包呢?

我貼一段小夥伴的代碼:

SELECT * FROM
  tianma.module_xx
WHERE
  pt = TO_CHAR(DATEADD(GETDATE(), - 1, ‘dd’), ‘yyyymmdd’)
  AND name NOT LIKE ‘%test%’
  AND name NOT LIKE ‘%demo%’
  AND name NOT LIKE ‘%測試%’
  AND keywords NOT LIKE ‘%test%’
  AND keywords NOT LIKE ‘%測試%’
  AND keywords NOT LIKE ‘%demo%’

很明顯我們判斷的方式是這個模塊的名稱和關鍵字中是否包含:test、demo、測試這三個字符。如果有那麼我們就認為他是測試模塊。我們把規則告訴了數據庫,然後數據庫就幫我們篩選了非測試模塊。

識別是否是貓或者識別一個模塊是否是測試模塊本質上是一樣的,都是在找特徵:

  • 貓的特徵:會叫、兩隻耳朵、四條腿、一條尾巴、有鬍鬚
  • 測試模塊的特徵:test、demo、測試

再進一步將特徵程序化表述:

  • 貓的特徵 叫:true、耳朵:2、腿:4、尾巴:1、鬍鬚:10
  • 測試模塊的特徵:test:count>0、demo:count >0、測試:count > 0

有了這些特徵無論是人還是機器都能正確的識別貓或者測試模塊了。

簡單的理解機器學習就是通過特徵和特徵的權重來實現數據的分類。(此處為了便於理解,更準確說法請參考:AiLearning/1.機器學習基礎.md at master · apachecn/AiLearning · GitHub)

為什麼要用機器識別呢?

原因是當某種分類任務的特徵數量巨大之後我們就很難用 if else 的方法去做簡單的分類了。比如我們常見的商品推薦算法,要確定某個商品是否適合推薦給某人可能的特徵數量會達到上百上千個。

二 如何訓練機器,並獲得模型?

準備數據

數據的準備在整個機器學習的任務中時間佔比可能超過 75%,是最重要的一部分,也是最困難的一部分。主要是:

  1. 採集基本的數據
  2. 清理異常值
  3. 挑選可能的特徵:特徵工程
  4. 數據打標

準備算法

讓你的數據進行擬合的一個函數:y=f(x)

比如線性函數也就是一元一次函數:y=ax+b

評估算法

如何確定找到的 a、b 值是否合適,那就需要一個評估函數。

評估函數描述訓練得到的參數和實際的值之前的差距(損失值)。比如下圖:

image.png

右邊的藍色線條更加貼近真實的數據點。

最常見的損失評估函數就是均方誤差函數了。通過計算預測的值和真實值的差的平方和來判斷預測值的優劣程度。

如上圖:樣本黃色的小圓圈座標為:

[

[x1, y1],
[x2, y2],
[x3, y3],
[x4, y4],
[x5, y5],
[x6, y6]

],

藍色的線預測的座標為:

[

[x1, y’1],
[x2, y‘2],
[x3, y’3],
[x4, y‘4],
[x5, y’5],
[x6, y‘6]

],

那麼損失值為:

const cost = ((y’1-y1)^2 + (y’2-y2)^2 + (y’3-y3)^2 + (y’4-y4)^2 + (y’5-y5)^2 + (y’6-y6)^2 ) / 6

訓練算法

如何找到合適的 a、b 值:拋物線的最低端

以上述的線性函數為例,訓練算法實際上就是在尋找合適的 a,b 值。如果我們在茫茫的數字海洋中隨機尋找 a,b 的值那應該是永遠找不到的了。這時候我們就需要用到梯度下降算法來尋找 a,b 值了。

再明確一下目標,將上述的損失值計算公式替換為:y=ax+b

// 函數 2
const cost = (((a*x1+b)-y1)^2 + ((a*x2+b)-y2)^2 + ((a*x3+b)-y3)^2 + ((a*x4+b)-y4)^2 + ((a*x5+b)-y5)^2 + ((a*x6+b)-y6)^2 )/ 6

目標是找到一組 a、b 的值使得 cost 最小。有了這個目標就好辦多了。

不知道你還記不記得初中的拋物線函數,也就是一元二次方程:y = ax^2+bx+c

而我們上述的 cost 函數雖然看起來很長,但是正好也是一個二次函數。它的圖大概是這樣的:

image.png

只要我們找到最低點的 a,b 值就完成我們的目標了。

怎麼知道到達拋物線的低端:拋物線的低端斜率為 0

假設我們隨機初始化一個 a 值為 1, 這時我們的點就在拋物線的左上方位置,距離最低點(cost 最小)的位置還距離很遠呢。

看圖可知我們只要增加 a 的值就可以靠近最低點了。那看圖機器可不會,這時候我們要祭出本篇文章中最複雜的數學知識了:導數。在這個點上的切線斜率值即為這個拋物線的導數,如上圖最低點(斜率為 0 處)。

通過這個導數可以計算出這個位置的切線(紅色的斜線)斜率。如果這個斜線的斜率為負數就意味著 a 太小了,需要增加才能更靠近底部。反之如果斜率為正意味著過了最低點了,需要減少才能更靠近底部。

如何求 cost 函數的導數呢?

不展開了,直接看代碼吧。關鍵字:偏導數、複合求導

// 函數 3
// a參數的偏導數
const costDaoA = (((a*x1+b)-y1)*2*x1 + ((a*x2+b)-y2)*2*x1 + ((a*x3+b)-y3)*2*x1 + ((a*x4+b)-y4)*2*x1 + ((a*x5+b)-y5)*2*x1 + ((a*x6+b)-y6)*2*x1 )/ 6

// b參數的偏導數
const costDaoB = (((a*x1+b)-y1)*2 + ((a*x2+b)-y2)*2 + ((a*x3+b)-y3)*2 + ((a*x4+b)-y4)*2 + ((a*x5+b)-y5)*2 + ((a*x6+b)-y6)*2 )/ 6

也就是隻要將 a,b 值帶入 costDaoA 函數就可以得到一個斜率,這個斜率指導參數 a 該如何調整以便更靠近底部。

同理 costDaoB 指導參數 b 改如何靠近底部。

循環 500 次吧

就這樣循環 500 次,基本上就能非常靠近底部了,從而獲得合適的 a,b 值。

獲得模型

當你獲得了 a,b 值之後,那麼我們就獲得了 y=ax+b 這樣一個模型,這個模型就可以幫助我們做預測了。

三 實踐一下先從簡單的開始:線性迴歸

什麼是線性迴歸

人們早就知曉 ,相比涼爽的天氣,蟋蟀在較為炎熱的天氣裡鳴叫更為頻繁。我們記錄了氣溫和每分鐘叫聲的一個表格,並且在 Excel 中繪製了下圖(案例來自 google tf 的官方教程):

image.png

是不是很清晰,這些小紅點幾乎排在了一條直線上:

image.png

那麼我們就認為這些數據的分佈是線性的,繪製的這條直線的過程就是線性迴歸。有了這條曲線我們就能準確的預測任何問題下鳴叫的次數了。

用瀏覽器做一個線性迴歸演示

地址:測試梯度下降
https://jshare.com.cn/feeqi/CtGy0a/share?spm=ata.13261165.0.0.6d8c3ebfIOhvAq

image.png

為了可視化採用了 highcharts 做數據可視化,同時為了省下 75% 的時間直接用了 highcharts 的默認數據點:
https://www.highcharts.com.cn/demo/highcharts/scatter

當訓練完成後繪製了一條藍色的線疊加在了圖上,同時增加了每次訓練的 a,b 值的損失率曲線。

代碼介紹

/**

* 代價函數 均方差計算

*/

function cost(a, b) {

    let sum = data.reduce((pre, current) = >{

        return pre + ((a + current[0] * b) - current[1]) * ((a + current[0] * b) - current[1]);

    },
    0);

    return sum / 2 / data.length;

}

/**

* 計算梯度

* @param a

* @param b

*/

function gradientA(a, b) {

    let sum = data.reduce((pre, current) = >{

        return pre + ((a + current[0] * b) - current[1]) * (a + current[0] * b);

    },
    0);

    return sum / data.length;

}

function gradientB(a, b) {

    let sum = data.reduce((pre, current) = >{

        return pre + ((a + current[0] * b) - current[1]);

    },
    0);

    return sum / data.length;

}

// 訓練次數
let batch = 200;

// 每次的靠近底部的速度,也就是學習速率。過高會導致在底部彈跳遲遲不能到到底部,過低會導致學習效率降低。
let alpha = 0.001;

let args = [0, 0]; // 初始化 a b 值
function step() {

    let costNumber = (cost(args[0], args[1]));

    console.log(‘cost’, costNumber);

    chartLoss.series[0].addPoint(costNumber, true, false, false);

    args[0] -= alpha * gradientA(args[0], args[1]);

    args[1] -= alpha * gradientB(args[0], args[1]);

    if ((—batch > 0)) {

        window.requestAnimationFrame(() = >{
            step()
        });

    } else {

        drawLine(args[0], args[1]);

    }

}

step();

四 接下來要做的

當特徵更多的時候,我們需要更多的計算、更長時間的訓練來獲得訓練模型。

上述描述都比較簡單,但是相信機器學習對你已經不再神祕,那麼可以參考更專業的入門文章。

參考
[1] GitHub - apachecn/AiLearning: AiLearning: 機器學習 - MachineLearning - ML、深度學習 - DeepLearning - DL、自然語言處理 NLP

[2] https://developers.google.com/machine-learning/crash-course/descending-into-ml/video-lecture?hl=zh-cn
[3] 從 0 開始機器學習 - 手把手用 Python 實現梯度下降法!- 掘金

福利來了 | 阿里雲 AI 視覺訓練營

加入阿里雲高校計劃 AI 視覺訓練營,與達摩院視覺導師親密接觸。五天時間玩轉身份證識別應用、電子相冊應用、圖像識別項目、車輛識別項目。

識別下方二維碼或點擊“閱讀原文”馬上參與:
image.png

Leave a Reply

Your email address will not be published. Required fields are marked *