03-还记得大明湖畔的导数吗

求导,就是求变化率

位移的导数,是速度

速度的导数是加速度

我们现在用有mse,可以把mse理解成距离,对mse的求导,得到就是mse变化的速度。

当mse变化速度为0时, 说明误差进入了一个低谷。 这个时候的b值就是我们期待的b值

f(x) = x^2+5

1
2
3
4
5
6
7
8
import matplotlib.pyplot as plt
import numpy as np
%matplotlib notebook  
fig = plt.figure(figsize=(6, 6), dpi=80)
X = np.linspace(-10, 10, 500) 
Y = np.square(X)+5
plt.scatter(X,Y)
plt.show()

image-20191115220904383

f(2)=9

f(4)= 19

f(-2)=9

f(-4)= 19

f`(x) = 2x

image-20191115221337883

f`(2)=4

f`(4)= 8

f`(-2)=-4

f`(-4)= -8

总结规律1:

求导后值负,增加x, mse下降。

求导后值正,减小x,mse下降

这就是信号, 有了信号就知道如何行动。

总结规律2:

求导后值负的大,小小的增加x,mse下降的多

求导后值正的大,小小的减少x,mse下降的多

变化规律:

坡度陡峭走小步,免得扯着蛋 (小的学习速率)

坡度平坦跨大步,这样跑的快 (可适当增加学习速度)

梯度下降公式推导

Predict:预测值

Actual:真实值

Area:面积

MSE=\sum ^{n}_{i=1}\left( Predict_{i}-Actual_{i}\right) ^{2}

$$ MSE=\sum ^{n}{i=1}\left( m×Area+b-Actual_{i}\right) ^{2} $$ 跟之前一样,为了简单起见,我们先假设m=0 这样每一套房屋的价格就跟面积无关了 $$ MSE=\sum ^{n}{i=1}\left(b -Actual\right) ^{2} $$ MSE现在是一个函数,b变化,mse就会发生变化,,剩下来的n,Actual_i这些都是常数,不会发生变化。

我们把mseb进行求导,就可以计算出来mse对b的变化率 $$ \dfrac {MSE}{\Delta b} = 2×\sum ^{n}{i=1}\left(b -Actual\right) $$

1
2
3
4
5
from sympy import *  #导入计算库
i, n, b ,Actual_i= symbols('i, n, b ,Actual_i') #声明变量x,y,z
init_printing(pretty_print=True) #初始化latex显示
expr = Sum((b-Actual_i)**2, (i, 1, 10))
diff(expr,b)

梯度下降步骤

  1. 随机选取一个b值
  2. 计算这个b值对应的mse的斜率
  3. 如果mse的斜率非常大,那要根据mse的斜率,去修改b的值
  4. mse值越大,b的修改值越大,mse斜率为正,b需要减少,mse斜率为负,b需要增加
  5. 选取一个很小的值,叫learningrate,学习速率,可以理解为迈开的步伐
  6. 用learningrate和mse的信号去更新b的值
  7. 重复2-6的步骤,直到mse的斜率接近于0

代码实现

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import numpy as np
data = np.array([
    [80,200],
    [95,230],
    [104,245],
    [112,247],
    [125,259],
     [135,262]
])

b = 1
learningrate = 0.0001

def gradentdecent():
    global b
    slop = 0
    for item in data[:,1]:
        slop = slop + (b - item)
    b = b -slop*learningrate
    print("slop={},b={}".format(slop,b))
1
2
3
gradentdecent()
for i in range(10000):
    gradentdecent()

图表展示

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
import numpy as np
data = np.array([
    [80,200],
    [95,230],
    [104,245],
    [112,247],
    [125,259],
     [135,262]
])
bhistory = []
msehistory = []
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
b = 1
learningrate = 0.0001

def gradentdecent():
    global b
    slop = 0
    mse = 0 
    for item in data[:,1]:
        slop = slop + (b - item)
        mse = mse + (b-item)**2
    b = b -slop*learningrate
    print("slop={},b={},mse={}".format(slop,b,mse))
    bhistory.append(b)
    msehistory.append(mse)

for i in range(10000):
    gradentdecent()
1
2
3
4
5
6
7
import matplotlib.pyplot as plt
import numpy as np
%matplotlib notebook  
fig = plt.figure(figsize=(6, 6), dpi=80)

plt.scatter(bhistory,msehistory)
plt.show()

image-20191116000357724

思考题:

  • 为什么需要learningrate

  • 为什么不直接求解 \dfrac {MSE}{\Delta b} = 2×\sum ^{n}_{i=1}\left(b -Actual_{i}\right)=0 算出来b的值?

分别对mx+b中的m和b求偏导数

1
2
3
4
5
from sympy import *  #导入计算库
i, n, b ,Actual_i= symbols('i, n, b ,Actual_i') #声明变量x,y,z
init_printing(pretty_print=True) #初始化latex显示
expr = Sum((b-Actual_i)**2, (i, 1, 10))
diff(expr,b)

\dfrac {MSE}{\Delta b} = \displaystyle \sum_{i=1}^{10} \left(- 2 Actual_{i} + 2 b + 2 m x\right)

1
2
3
4
5
from sympy import *  #导入计算库
i, m,n, b ,Actual_i= symbols('i,m, n, b ,Actual_i') #声明变量x,y,z
init_printing(pretty_print=True) #初始化latex显示
expr = Sum((m*x + b-Actual_i)**2, (i, 1, 10))
diff(expr,m)

\dfrac {MSE}{\Delta m} = \displaystyle \sum_{i=1}^{10} 2 x \left(- Actual_{i} + b + m x\right)

  • 手动推导一下

代码实战

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import numpy as np
data = np.array([
    [80,200],
    [95,230],
    [104,245],
    [112,247],
    [125,259],
     [135,262]
])
mhistory = []
bhistory = []
msehistory = []

b = 1
m = 1
learningrate = 0.00001

def gradentdecent():
    global b ,m 
    bslop = 0
    mslop = 0
    mse = 0 
    for index ,item in enumerate(data[:,1]):
        bslop = bslop + (b - item + data[:,0][index] * m)
        mslop = mslop + data[:,0][index]*(b - item + data[:,0][index] * m)
        mse = mse + (m*data[:,0][index] + b-item)**2
    b = b -bslop*learningrate
    m = m - mslop*learningrate
    return mse

i = 0
for i in range(10000000):
    mse = gradentdecent()
    i = i+1
    if(i%10000 == 0):
        print("b={},m={},mse={}".format(b,m,mse))

解方程的方式求解m和b

\displaystyle \sum_{i=1}^{10} - 2 Actual_{i} + \sum_{i=1}^{10} 2 b + \sum_{i=1}^{10} 2 m x = 0
\displaystyle \sum_{i=1}^{10} - 2 Actual_{i} x + \sum_{i=1}^{10} 2 b x + \sum_{i=1}^{10} 2 m x^{2} = 0
1
2
expand(diff(expr,b)) 
expand(diff(expr,m))
1
2
solve([-(200+230+245+247+259+262)+6*b+m*(80+95+104+112+125+135),-(200*80+95*230+104*245+112*247+125*259+135*262)+
       b*(80+95+104+112+125+135)+m*(80**2+95**2+104**2+112**2+125**2+135**2)],[b,m])
\displaystyle \left\{ b : \frac{491072}{4003}, \ m : \frac{4347}{4003}\right\}

为什么深度学习采用回归法,不使用求解法

二维,三维空间,少量的数据点,计算比较容易,但是一旦上升到n维空间, 计算量就几何程度倍增, 另外不一定能直接求出解,最好的办法就是计算机去拟合,寻找一个最接近的解。

梯度下降的几何学解释

\dfrac {MSE}{\Delta b} = \displaystyle \sum_{i=1}^{10} \left(- 2 Actual_{i} + 2 b + 2 m x\right)

\dfrac {MSE}{\Delta m} = \displaystyle \sum_{i=1}^{10} 2 x \left(- Actual_{i} + b + m x\right)

\dfrac {MSE}{\Delta m} = 2 * 5 * (-2) = -20

\dfrac {MSE}{\Delta b} = -4

新的公式为:

y = (2- (-20))x + (3-(-4)) = 22x + 7

从黑线一下变成红线, 这条线从(5,15)的下方,一下子变到了(5,15)的上放, 步子太大了!!

所以我们要乘以一个learningrate, 让变化的步子变的小一点,让y=2x+3 缓缓的靠近(5,15)这个点。

假设 learningrate = 0.01

新的公式为:

y = (2- (-20*learningrate))x + (3-(-4*learningrate)) \\ = (2- (-20*0.01))x + (3-(-4*0.01)) = 2.2x + 3.04

线性回归的局限性

线性回归只适合线性问题。 如果数据模型是非线性的,可以考虑使用别的模型

image-20191117170057947

image-20191117170114891