梯度下降法在地理信息方向的应用

梯度下降法在地理信息方向的应用

背景

在地理科学类专业中,地理信息系统专业已改为地理信息科学专业。研究地理信息采集、分析、存储、显示、管理、传播与应用,及研究地理信息流的产生、传输和转化规律的一门科学。主要培养具备地理信息科学与地图学、遥感技术方面的基本理论、基本知识、基本技能,能在科研机构或高等学校从事科学研究或教学工作,能在城市、区域、资源、环境、交通、人口、住房、土地、灾害、基础设施和规划管理等领域的政府部门、金融机构、公司、高校、规划设计院所,从事与地理信息系统有关的应用研究、技术开发、生产管理和行政管理等工作的高级专门人才。

波士顿房价预测是一个经典的机器学习任务,和大家对房价的普遍认知相同,房价是由诸多因素影响的。而地理信息科学专业对一个地区进行信息收集整理,并对地区做出整体规划,并期望构建一个基于13个因素进行房价预测的模型。

所学知识

偏导数partial derivative

一个多变量的函数(多元函数),对其中一个变量微分,而保持其他变量恒定。

函数f可以解释为y为自变量而x为常数的函数:

\[f(x,y) = f_x(y) = \,\! x^2 + xy + y^2 \]

也就是说,每一个x的值定义了一个函数,记为fx,它是一个一元函数。也就是说:

\[f_x(y) = x^2 + xy + y^2 \]

在这个表达式中,a常数,而不是变量,因此fa是只有一个变量的函数,这个变量是y。这样,便可以使用一元函数的导数的定义:

\[f_a'(y)= a + 2y \]

以上的步骤适用于任何a的选择。把这些导数合并起来,便得到了一个函数,它描述了fy方向上的变化:

\[{\displaystyle {\frac {\partial f}{\partial y}}(x,y)=x+2y} \]

梯度gradient

在向量微积分中,梯度是一种关于多元导数的概括。平常的一元(单变量)函数的导数是标量值函数,而多元函数的梯度为向量值函数。多元可微函数\(f\)在点\(P\)上的梯度,是以\(f\)\(P\)上的偏导数为分量的向量。

就像一元函数的导数表示这个函数图形的切线的斜率,如果多元函数在点\(P\)上的梯度不是零向量,则它的方向是这个函数在\(P\)上最大增长的方向,而它的量是这个方向上的增长率

\[𝑔𝑟𝑎𝑑𝑖𝑒𝑛𝑡 = (\frac{\partial{L}}{\partial{w_0}},\frac{\partial{L}}{\partial{w_1}}, ... ,\frac{\partial{L}}{\partial{w_12}} ,\frac{\partial{L}}{\partial{b}}) \]

运用

img

假设房价和各影响因素之间能够用线性关系来描述:

\[y = {\sum_{j=1}^Mx_j w_j} + b \]

则对于给定数据来说我们如果能通过给定数据来反向推导函数的\(w_j和b\)即可得到所需模型

我们需要使最后的\(w_j\)尽可能拟合真实的\(w_{realj}\),即最小化\({\sum_{j=1}^M|w_{realj}-w_j|}\)

但在不知道最终的权重\(w_{realj}\)的情况下,我们用模型预测的结果与真实值的差值的大小来评价模型是否准确,即使\(w_j\)尽可能拟合\(w_{realj}\)

我们将均方差作为损失函数,来衡量预测房价和真实房价差异

\[J_{train} = \frac{1}{n} \sum_{i=1}^n(\hat{Y_i} - {Y_i})^{2} \]

因此我们只需要求出该函数的偏导,并

\[\frac{\partial{L}}{\partial{w}}=0 \]

\[\frac{\partial{L}}{\partial{b}}=0 \]

![1](C:\Users\Melodit\OneDrive - s.upc.edu.cn\中国石油大学\高数\小组讨论作业\1.png)

针对具有多维输入的函数,我们需要用到 偏导数(partial derivative)的概念。 偏导数\(\frac{∂}{∂x_i} f(x)\) 衡量点 x 处只有\(x_i\)增加时 \(f(x)\)如何变化。 梯度(gradient)是相 对一个向量求导的导数:f 的导数是包含所有偏导数的向量,记为 \(∇xf(x)\)。梯度的第 i 个元素是 f 关于 xi 的偏导数。在多维情况下,临界点是梯度中所有元素都为零的 点。

我们将损失函数定义为

\[L= \frac{1}{2N} \sum_{i=1}^n({y_i} - {z_i})^{2} \]

\(z_i\)即为对每个样本的预测值

则针对此问题求出L对\(w\)\(b\)的偏导数

\[\frac{\partial{L}}{\partial{w_j}} = \frac{1}{N}\sum_{i=1}^N{(z_i - y_i)\frac{\partial{z_i}}{\partial{w_j}}} = \frac{1}{N}\sum_{i=1}^N{(z_i - y_i)x_i^{j}} \]

\[\frac{\partial{L}}{\partial{b}} = \frac{1}{N}\sum_{i=1}^N{(z_i - y_i)\frac{\partial{z_i}}{\partial{b}}} = \frac{1}{N}\sum_{i=1}^N{(z_i - y_i)} \]

下面我们考虑只有一个样本的情况下,计算梯度:

\[L= \frac{1}{2}{(y_i - z_i)^2} \]

\[z_1 = {x_1^{0}\cdot w_0} + {x_1^{1}\cdot w_1} + ... + {x_1^{12}\cdot w_12} + b \]

可以计算出:

\[L= \frac{1}{2}{({x_1^{0}\cdot w_0} + {x_1^{1}\cdot w_1} + ... + {x_1^{12}\cdot w_12} + b - y_1)^2} \]

可以计算出\(L\)\(w\)\(b\)的偏导数:

\[\frac{\partial{L}}{\partial{w_0}} = ({x_1^{0}\cdot w_0} + {x_1^{1}\cdot w_1} + ... + {x_1^{12}\cdot w_12} + b - y_1)\cdot x_1^{0}=({z_1} - {y_1})\cdot x_1^{0} \]

\[\frac{\partial{L}}{\partial{b}} = ({x_1^{0}\cdot w_0} + {x_1^{1}\cdot w_1} + ... + {x_1^{12}\cdot w_12} + b - y_1)\cdot 1 = ({z_1} - {y_1}) \]

则当我们在一步计算完成梯度后,我们可以顺着梯度的反方向来进行对wi的修正

比如我们设置学习率\(r_{learn}\)来对梯度进行修正

则对于每一个\(w_i\),我们就可以在每一步训练出的梯度,来逐步修正\(w_i\),即

\[w_i=w_i-r_{learn}*\frac{\partial{L}}{\partial{w_i}} \]

其中学习率我们应该设置为合适的大小或者动态学习率,来避免进入局部最优解的结果

即类似下图中,我们可能通过梯度方法,将模型回归到一个梯度几乎为0的局部最优解,但这并不是全局中损失最小的点,故这种情况我们可以通过其他各种方式如随机梯度下降或我们这学期学过的拉格朗日乘数法等等来尽可能避免。

img

则通过python我们可以写出训练函数类

class Network(object):
    def __init__(self, num_of_weights):
        # 随机产生w的初始值
        # 为了保持程序每次运行结果的一致性,此处设置固定的随机数种子
        np.random.seed(0)
        self.w = np.random.randn(num_of_weights,1)
        self.w[5] = -100.
        self.w[9] = -100.
        self.b = 0.
        
    def forward(self, x):
        z = np.dot(x, self.w) + self.b
        return z
    
    def loss(self, z, y):
        error = z - y
        num_samples = error.shape[0]
        cost = error * error
        cost = np.sum(cost) / num_samples
        return cost
    
    def gradient(self, x, y):
        z = self.forward(x)
        gradient_w = (z-y)*x
        gradient_w = np.mean(gradient_w, axis=0)
        gradient_w = gradient_w[:, np.newaxis]
        gradient_b = (z - y)
        gradient_b = np.mean(gradient_b)        
        return gradient_w, gradient_b
    
    def update(self, graident_w5, gradient_w9, eta=0.01):
        net.w[5] = net.w[5] - eta * gradient_w5
        net.w[9] = net.w[9] - eta * gradient_w9
        
    def train(self, x, y, iterations=100, eta=0.01):
        points = []
        losses = []
        for i in range(iterations):
            points.append([net.w[5][0], net.w[9][0]])
            z = self.forward(x)
            L = self.loss(z, y)
            gradient_w, gradient_b = self.gradient(x, y)
            gradient_w5 = gradient_w[5][0]
            gradient_w9 = gradient_w[9][0]
            self.update(gradient_w5, gradient_w9, eta)
            losses.append(L)
            if i % 50 == 0:
                print('iter {}, point {}, loss {}'.format(i, [net.w[5][0], net.w[9][0]], L))
        return points, losses

即可通过梯度下降法来获取尽可能拟合的函数的各项参数

参考文献

[1]Bengio, Yoshua; LeCun, Yann; Hinton, Geoffrey. Deep Learning. Nature. 2015, 521: 436–444.

[2] 使用Python和Numpy构建神经网络模型

[3] 维基百科:梯度

posted @ 2022-05-05 16:28  melodit  阅读(211)  评论(0)    收藏  举报