5分鐘帶你通過Javascript瞭解人工智慧的基本原理

6666發表於2022-05-14

Javascript是我的“母語”,用它來學習人工智慧,記得更牢靠。

學習人工智慧門檻高不高?我入門花了2個月時間,學習了python、微積分,才大概弄懂了深度學習的基本原理,確實讓人頭大,不過現在回過頭想想,其實基本原理是沒這麼難的。

image.png

1. 基本原理

這個小節不需要什麼基礎,各位工程師應該都可以看得懂。

經過我的消化之後,表達出來的人工智慧的流程就是:有一些資料,假設這些資料遵循某種規律,但是這個規律裡的具體引數是未知的,讓電腦多次猜測這些引數的值,並從中找到誤差最小的那組引數,就可以對新的資料進行預測

比如有一組身高x、年齡y的資料:

arr = [
 {x: 10, y: 131},
 {x: 11, y: 135},
 {x: 12, y: 139},
 {x: 13, y: 145},
]

年齡越大,身高越高唄,所以假設身高和年齡遵循的規律是:

y = kx + b

k和b是多少,電腦是個學渣,看了公式和資料一臉懵逼,那就瞎猜一下吧。

k = 10
b = 15
則
10*10 + 15 = 115
10*11 + 15 = 125
10*12 + 15 = 135
10*13 + 15 = 145

看這個瞎猜和實際的值差別是多少,我們中學學過一個評估的方式,叫做方差,這裡用類似的方式來評估loss:

let yArr = [131, 135, 139, 145]
let zArr = [115, 125, 135, 145]
let loss = 0
yArr.forEach((y, index) => {
    let z = zArr[index]
    loss += Math.pow(z - y, 2) // (z - y)²
})
loss = loss / data.length
// loss = 93

loss評估出來是93,是大了還是小了,電腦學渣也不太清楚,所以電腦需要進行更多的猜測,從所有猜測中取loss最小時的k和b,當成最終值。


用程式碼完整得實現就是:

model = {
  xArr: [10, 11, 12, 13],
  yArr: [131, 135, 139, 145],
  k: 10, // 引數1
  b: 15, // 引數2
  // 損失函式:評估誤差用的
  getLoss (k, b) {
    let zArr = this.xArr.map(x => this.getY(x, k, b))
    let loss = 0
    this.yArr.forEach((y, index) => {
        let z = zArr[index]
      loss += Math.pow(y - z, 2) // (y - z)²
    })
    loss = loss / this.yArr.length
    return loss
  },
  // 規律的公式
  getY(x, k, b) {
    return k * x + b
  },
  // 訓練:讓電腦瞎猜,實際開發中不是像以下程式碼這樣猜的,但是雖然手段不同,原理卻是一樣的
  learn () {
    // 讓k和b分別取1到100
    let kArr = Array.from(Array(100), (v,i) => i + 1)
    let bArr = Array.from(Array(100), (v,i) => i + 1)
    let lossArr = []
    kArr.forEach(k => {
      bArr.forEach(b => {
        lossArr.push({
          loss: this.getLoss(k, b), // 通通計算一遍,算出loss
          k: k,
          b: b
        })
      })
    })
    let result = {loss: Infinity}
    lossArr.forEach(d => {
      if (d.loss < result.loss) {
        result = d // 找出最小的loss
      }
    })
    console.log(result.loss)
    this.k = result.k
    this.b = result.b
  }
}
model.learn()
console.log(model.k, model.b)
console.log(model.yArr)
console.log(model.xArr.map(x => model.getY(x, model.k, model.b)))

最後,求得

k = 5
b = 80
yArr = [131, 135, 139, 145]
zArr = [130, 135, 140, 145]

來試試預測個14歲的身高

y = kx + b
y = 5 * 14 + 80
y = 150

150cm很合理,這就是人工智慧,帶著從這裡學到的知識,去開發人臉識別吧,呵呵?

都看到這裡了,給個贊好不好???

2. 優化猜測演算法

這個小節,需要提前瞭解導數、偏導數、向量的乘積等數學知識

在上一節中,我們暴力強猜,把k和b在1~100裡挨個猜了一遍,但是有可能最優解不在1~100中,所以我們來優化一下猜測的演算法。

首先,重溫一下公式:

\(y = kx + b\)

\( L = \sum_{i=1}^N (y_{i} - z_{i})^2 \)

\( y_{i} \)是實際的值,\( z_{i} \)是電腦猜測的值,N是yArr的長度,這裡loss我們不用程式碼表示了,改用數學公式表達,L = loss,看不懂的同學先去學習一下再回來重新看。

看清問題的本質,才能更好地優化演算法,需要了解k、b、L之間的關係,我們把k和b和L的值繪製成圖:
image.png

可以從圖中看到,L是一個面,我們要求這個面的最低點,假如這時候放個玻璃珠在面上,那麼這個玻璃珠回朝著最低點滾動,利用這個現象的原理優化演算法,就可以讓電腦在最短時間內找到L的最小值了。

玻璃珠自動向最低點運動的演算法叫:梯度下降法,在L這個面上的某一點,求k、b的偏導數,這個偏導數的乘積就能算出梯度下降的方向,推導流程如下。

\( \frac{\mathrm{d} L}{\mathrm{d} k} = \frac{\mathrm{d} L}{\mathrm{d} z} \frac{\mathrm{d} z}{\mathrm{d} k} \)

先求 \( \frac{\mathrm{d} L}{\mathrm{d} z} \)

\( L = \sum_{i=1}^N (y_{i} - z_{i})^2 \)

\( \frac{\mathrm{d} L}{\mathrm{d} z} = \sum_{i=1}^N (2y_{i} - 2z_{i}) \)

\( \frac{\mathrm{d} L}{\mathrm{d} z} = \sum_{i=1}^N (2y_{i} - 2kx_{i} - 2b) \)

再求 \( \frac{\mathrm{d} z}{\mathrm{d} k} \)

\( z_{i} = kx_{i} + b \)

\( \frac{\mathrm{d} z}{\mathrm{d} k} = x_{i} \)

未完待續,點個收藏日後再來看吧

相關文章