Javascript是我的“母語”,用它來學習人工智慧,記得更牢靠。
學習人工智慧門檻高不高?我入門花了2個月時間,學習了python、微積分,才大概弄懂了深度學習的基本原理,確實讓人頭大,不過現在回過頭想想,其實基本原理是沒這麼難的。
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的值繪製成圖:
可以從圖中看到,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} \)
未完待續,點個收藏日後再來看吧