matlab实现梯度下降法(Gradient Descent)的一个例子

  在此记录使用matlab作梯度下降法(GD)求函数极值的一个例子:

  问题设定: 

  1. 我们有一个$n$个数据点,每个数据点是一个$d$维的向量,向量组成一个data矩阵$\mathbf{X}\in \mathbb{R}^{n\times d}$,这是我们的输入特征矩阵。

  2. 我们有一个响应的响应向量$\mathbf{y}\in \mathbb{R}^n$。

  3. 我们将使用线性模型来fit上述数据。因此我们将优化问题形式化成如下形式:$$\arg\min_{\mathbf{w}}f(\mathbf{w})=\frac{1}{n}\|\mathbf{y}-\mathbf{\overline{X}}\mathbf{w}\|_2^2$$

  其中$\mathbf{\overline{X}}=(\mathbf{1,X})\in \mathbb{R}^{n\times (d+1)}$ and $\mathbf{w}=(w_0,w_1,...,w_d)^\top\in \mathbb{R}^{d+1}$

  显然这是一个回归问题,我们的目标从通俗意义上讲就是寻找合适的权重向量$\mathbf{w}$,使得线性模型能够拟合的更好。

  处理:

  1. 按列对数据矩阵进行最大最小归一化,该操作能够加快梯度下降的速度,同时保证了输入的数值都在0和1之间。$\mathbf{x}_i$为$\mathbf{X}$的第i列。 $$z_{ij}\leftarrow \frac{x_{ij}-\min(\mathbf{x}_i)}{\max(\mathbf{x}_i)-\min(\mathbf{x}_i)}$$

  这样我们的优化问题得到了转化:$$\arg\min_{\mathbf{u}}g(\mathbf{w})=\frac{1}{n}\|\mathbf{y}-\mathbf{\overline{Z}}\mathbf{u}\|_2^2$$

  2. 考虑对目标函数的Lipschitz constants进行估计。因为我们使用线性回归模型,Lipschitz constants可以方便求得,这样便于我们在梯度下降法是选择合适的步长。假如非线性模型,可能要用其他方法进行估计(可选)。

  问题解决:

  使用梯度下降法进行问题解决,算法如下:

   我们可以看到,这里涉及到求目标函数$f$对$\mathbf{x}_k$的梯度。显然在这里,因为是线性模型,梯度的求解十分的简单:$$\nabla f(\mathbf{x}_k)=-\frac{2}{n}\mathbf{\overline{X}}^\top(\mathbf{y}-\mathbf{\overline{X}}\mathbf{u}_k)$$

  进行思考,还有没有其他办法可以把这个梯度给弄出来?假如使用Tensorflow,Pytorch这样可以自动保存计算图的东东,那么梯度是可以由机器自动求出来的。当然在这里我是用matlab实现,暂时没有发现这样的利器,所以我认为假如在这里想求出梯度,那么我们必须要把梯度的闭式解搞出来,不然没法继续进行。

  下面是一段matlab的代码:  

function [g_result,u_result] = GD(N_Z,y,alpha,u0)
%GD 梯度下降法
%   Detailed explanation goes here
[n,~] = size(N_Z);
u = u0;
k = 0;
t = y-N_Z*u;
disp("g(u):");
while(合理的终止条件)
    k = k + 1;
    u = u - alpha * (-2/n)*N_Z'*t;
    t = y-N_Z*u;
    if(mod(k,10)==0)
        disp(t'*t/n);
    end
end
g_result = (y-N_Z * u)' * (y-N_Z * u)/n;
u_result = u;
end

  当然假如初始化的时候$u_0$选择不当,而且因为没有正则项,以上的算法将会有很大的问题:梯度消失,导致优化到最后的时候非常慢。我花了好多个小时才将loss讲到0.19左右,而闭式解法能够使得loss为0.06几,运行时间也不会难以忍受。

  问题推广:

  在这里,我们的问题是线性模型,回归问题。能否有更广的应用?思考后认为,只要需要优化的目标是标量,且该目标函数对输入向量的梯度容易求得即可。只是因为该算法简单朴素,可能在实际应用的时候会碰见恼人的梯度消失问题。

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
随机梯度下降(Stochastic Gradient Descent,SGD)是一种常用的优化算法,尤其在深度学习中被广泛应用。下面介绍如何用 MATLAB 实现 SGD。 假设我们需要最小化一个损失函数 $J(\theta)$,其中 $\theta$ 是模型参数。SGD 的更新公式如下: $$\theta_{i+1} = \theta_{i} - \alpha \nabla J(\theta_{i}, x_{i}, y_{i})$$ 其中 $\alpha$ 是学习率,$\nabla J(\theta_{i}, x_{i}, y_{i})$ 是对参数 $\theta_{i}$ 在样本 $(x_{i},y_{i})$ 上的梯度。每次更新时,随机选择一个样本 $(x_{i},y_{i})$,用它来计算梯度并更新参数。 下面是一个简单的 SGD 实现代码: ```matlab function [theta, J_history] = sgd(X, y, theta, alpha, num_iters) % X: 训练样本,每行表示一个样本 % y: 目标变量,每行对应一个样本 % theta: 初始参数 % alpha: 学习率 % num_iters: 迭代次数 % theta: 训练后的参数 % J_history: 每次迭代后的损失函数值 m = length(y); J_history = zeros(num_iters, 1); for iter = 1:num_iters % 随机选择一个样本 i = randi(m); % 计算梯度并更新参数 theta = theta - alpha * grad(X(i,:), y(i,:), theta); % 计算损失函数值 J_history(iter) = loss(X, y, theta); end end function g = grad(x, y, theta) % 计算梯度 g = (x * theta - y) * x'; end function J = loss(X, y, theta) % 计算损失函数值 m = length(y); J = sum((X * theta - y).^2) / (2 * m); end ``` 其中 `X` 和 `y` 分别表示训练样本和目标变量,每行表示一个样本,`theta` 是初始参数,`alpha` 是学习率,`num_iters` 是迭代次数。`sgd` 函数使用 `for` 循环进行迭代,每次随机选择一个样本,计算梯度并更新参数,同时记录损失函数值。`grad` 函数计算梯度,`loss` 函数计算损失函数值。 可以使用以下代码进行测试: ```matlab % 生成数据 m = 1000; n = 2; X = [ones(m,1), rand(m,n-1)]; theta_true = [1;2]; y = X * theta_true + randn(m,1); % 初始化参数 theta = zeros(n,1); % 运行 SGD alpha = 0.01; num_iters = 1000; [theta, J_history] = sgd(X, y, theta, alpha, num_iters); % 绘制损失函数值随迭代次数的变化 plot(J_history); xlabel('Iterations'); ylabel('Loss'); ``` 该代码生成一个二维数据集,并在其中加入噪声。然后运行 SGD 进行训练,并绘制损失函数值随迭代次数的变化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值