M0.0 13 分鐘閱讀 2026年9月

M0.0 霧中下山:Gradient 與方向

起點:起霧了

你在一座山坡上,霧濃到看不見三步以外。手機沒訊號,地圖沒用,唯一還能用的感官是腳底:站著不動,你能感覺到地面往哪邊斜、斜得多陡。

你想盡快下到谷底。直覺的做法很自然:感覺一下哪邊最陡,就往那邊走一步,再感覺一次。

先停一下,用直覺回答三個問題,並寫下你有多確定:

  1. 「腳下最陡的方向」這件事,需要試多少個方向才能確定?要三百六十度轉一圈嗎?
  2. 沿最陡方向走,每一步都是「當下最快下降」——這保證你走到的是谷底嗎?
  3. 一步該走多大?

多數人對第 1 題會說「轉一圈試試」,對第 2 題會說「應該吧」,對第 3 題會說「越陡走越大步」。這三個答案有的對、有的錯,但重點是:直覺說不出為什麼,也說不出什麼時候會失效。 這一篇把它翻成數學,然後回來逐題判斷。

課堂提問Q1

把這個情境翻成數學問題:這裡的「函數」是什麼?我們手上有什麼資訊?我們想求的量是什麼?

先想一想,再展開看整理後的答案

最直覺的說法是「函數是山」,這差一步。山是一個高度函數 h(x,y)h(x,y):輸入是你在地面上的位置 (x,y)(x,y)(兩個座標),輸出是那裡的海拔。整座山就是 hh 的圖形。

我們手上有的資訊不是 hh 本身——霧裡看不到——而只有當下位置的傾斜。「往方向 uu 走一小段,高度變多少」,這是一個對每個方向 uu 都有一個值的量。我們暫時叫它「往 uu 方向的斜率」。

我們想求的量是:在所有方向裡,哪一個方向的斜率最負(下降最快)。這是一個對方向取最小值的問題。翻譯到這裡,問題已經比原來清楚很多:我們需要一個工具,把「每個方向的斜率」整理成一個好處理的物件,然後在上面做最小化。這個物件就是 gradient。

一張傾斜的桌子

先不用符號。想像一張桌子,四隻腳不等長,桌面因此往某個方向斜。你把一顆彈珠放在桌上,它會往一個確定的方向滾——桌面雖然有無限多個方向,但「傾斜」本身只是一件事:一個方向、一個陡度。

換句話說:在腳下那一小塊地面上(小到可以當成平面),所有方向的斜率都由同一個「傾斜」決定。往彈珠滾的方向走,最陡;往垂直的方向走,完全是平的;其他方向介於中間,而且變化的規律是固定的(後面會看到是 cosine)。

這就是為什麼你不需要轉一圈。桌面是一個平面,一個平面的傾斜只有兩個自由度——量兩個垂直方向的斜率,整張桌子的傾斜就定了。

把傾斜寫成數學

Directional derivative。 站在位置 p=(x,y)p=(x,y),往單位向量 uu(長度 1,只代表方向)走一小段 ss,高度變成 h(p+su)h(p+su)。「往 uu 方向的斜率」就是

Duh(p)=lims0h(p+su)h(p)s.D_u h(p)=\lim_{s\to0}\frac{h(p+su)-h(p)}{s}.

它對每個 uu 都有一個值。特別地,u=(1,0)u=(1,0)(東西向)與 u=(0,1)u=(0,1)(南北向)的兩個值,就是我們熟悉的 partial derivative h/x\partial h/\partial xh/y\partial h/\partial y

Gradient。 把這兩個 partial derivative 排成一個向量:

h(p)=(hx(p), hy(p)).\nabla h(p)=\Big(\frac{\partial h}{\partial x}(p),\ \frac{\partial h}{\partial y}(p)\Big).

桌子那一段說「兩個讀數決定所有方向」,寫成式子就是:只要 hhpp 附近是 differentiable 的(可以用一個平面貼近),

Duh(p)=h(p)u.D_u h(p)=\nabla h(p)\cdot u .

證明只有幾行,放在下面;主線需要的是它的結論。

展開細節為什麼 D_u h = ∇h · u(differentiable 的定義就是「局部像平面」)

hhpp 是 differentiable,定義上就是存在一個向量 gg 使得 h(p+v)=h(p)+gv+o(v)h(p+v)=h(p)+g\cdot v+o(\|v\|)——小位移 vv 造成的高度變化,主要部分是 vv 的一個 linear 函數,剩下的比 v\|v\| 更小。代 v=suv=suh(p+su)h(p)=s(gu)+o(s)h(p+su)-h(p)=s\,(g\cdot u)+o(s),除以 ss 取極限得 Duh(p)=guD_u h(p)=g\cdot u。再代 u=(1,0)u=(1,0)(0,1)(0,1),看出 gg 的兩個分量就是兩個 partial derivative,所以 g=h(p)g=\nabla h(p)

最陡方向。 現在起點問題變成:在 u=1\|u\|=1 的所有 uu 裡,讓 hu\nabla h\cdot u 最小。Cauchy–Schwarz 不等式說 huhu=h|\nabla h\cdot u|\le\|\nabla h\|\,\|u\|=\|\nabla h\|,等號在 uuh\nabla h 平行時成立。所以

minu=1Duh=h,在 u=hh 達到.\min_{\|u\|=1}D_u h=-\|\nabla h\|,\qquad\text{在 }u=-\frac{\nabla h}{\|\nabla h\|}\text{ 達到}.

寫成角度:若 uuh\nabla h 夾角 θ\theta,則 Duh=hcosθD_u h=\|\nabla h\|\cos\theta——這就是桌子那張圖裡「羅盤長條」的規律。最快下山的方向是 h-\nabla h,最快上山是 +h+\nabla h,垂直於 h\nabla h 走是等高線。

為什麼常常看到的是 logf\nabla\log f

有一類量天生是相對的:手機訊號強度、聲音響度、一個地區的人口密度。對這些量,我們關心的常不是「走一公尺多了多少」,而是「走一公尺多了幾成」。

f>0f>0。Chain rule 給

logf=ff.\nabla\log f=\frac{\nabla f}{f}.

右邊是「絕對變化率除以目前的值」——正是相對變化率。它有一個立刻能用的性質:ff 整體乘一個常數 cclog(cf)=logf\nabla\log(cf)=\nabla\log f 不變。 所以只要你知道 ff「長什麼形狀」,就算不知道它的整體大小(例如一個還沒 normalize 的密度),logf\nabla\log f 也算得出來。

一個值得記住的例子:f(x)=exp ⁣(xμ2/(2σ2))f(x)=\exp\!\big(-\|x-\mu\|^2/(2\sigma^2)\big)(一個鐘形,中心 μ\mu、寬度 σ\sigma)。直接算:

logf(x)=xμσ2.\nabla\log f(x)=-\frac{x-\mu}{\sigma^2}.

它永遠指向中心 μ\mu,長度與「離中心多遠」成正比、與 σ2\sigma^2 成反比。沿著 logf\nabla\log f 走,就是往密度高的地方走,而且鐘形越窄、拉力越強。這個式子之後會反覆出現。

回到情境:三個直覺逐題判斷

第 1 題(要試幾個方向)——直覺錯了,但錯得有道理。 只要地面在腳下那一小塊是 differentiable 的(沒有稜線、沒有斷崖),兩個垂直方向的讀數就決定了 h\nabla h,最陡方向是 h-\nabla h。「轉一圈」不是錯,是浪費:它隱含假設「每個方向的斜率是獨立的資訊」,而 differentiability 說它們只有兩個自由度。失效條件:站在稜線上(像 h=xh=|x| 的尖點),左右兩邊斜率不同、沒有一個平面貼得上,這時 gradient 不存在,兩個讀數也不夠。

第 2 題(每步最陡就會到谷底嗎)——直覺錯了。 h-\nabla h 只保證這一步降得最快,是一個局部的判斷。走到任何 h=0\nabla h=0 的地方(山坳、小盆地)你就停了,因為腳下感覺是平的——但那可能只是半山腰的一個小窪地,真正的谷底在霧的另一邊。「一路最陡」保證的是單調下降,不是「到最低點」。什麼時候直覺是對的?當 hh 只有一個低點、而且處處往它斜(convex 的地形),這時 h=0\nabla h=0 的地方就只有谷底一個。

第 3 題(步長)——直覺對了一半。 h\nabla h 是「腳下那一小塊」的傾斜,走出那一小塊之後它就不再準。「越陡走越大步」在平滑的長坡上合理;但坡度變化很快的地方(坡下面就是另一個坡),一大步可能跨過谷底、走到對面山坡上更高的位置。步長的合理範圍由「傾斜變化多快」決定——這件事要到 M0.2 才有工具量化,這裡先記結論:gradient 是局部資訊,步長要小到局部近似還成立。

回到情境:實際走一次

如果想用十行程式驗證,下面直接在碗形地形上跑,並刻意把步長調過頭:

import numpy as np
grad = lambda p: np.array([2*p[0], 4*p[1]])        # h = x^2 + 2 y^2 的 gradient
def descend(eta, steps=30, p=np.array([2.0, 1.5])):
    hs = []
    for _ in range(steps):
        p = p - eta * grad(p)                        # 往 -∇h 走一步
        hs.append(p[0]**2 + 2*p[1]**2)
    return np.array(hs)
print(descend(0.1)[-1])    # 收斂:高度趨近 0
print(descend(0.6)[-1])    # y 方向係數 1-4*0.6 = -1.4,每步放大 → 發散

先消化一下

想一想

你在一間大廳裡,手上的分貝計顯示目前噪音值,你想走到最安靜的地方。你在原地往東、往北各走一小步並記下讀數變化。接下來該往哪走?

想一想

下山策略「每步走 h-\nabla h」在下面哪個情況仍然有效

想一想

某地區的人口密度是 f(x)f(x),但你拿到的地圖把所有數值都乘了一個未知常數 cc(單位搞錯了)。下列哪個量不受這個常數影響?

參考文獻

  1. Strang, G. Calculus. Wellesley-Cambridge Press;MIT OpenCourseWare RES.18-001 免費全文。(partial derivative、gradient 與 directional derivative 的章節。)
  2. Marsden, J. E., Tromba, A. J. Vector Calculus. W. H. Freeman.(differentiability 的「局部像平面」定義、Cauchy–Schwarz 與最陡方向。)
  3. Nocedal, J., Wright, S. J. Numerical Optimization, 2nd ed. Springer 2006.(steepest descent、步長選擇、局部與全域最小的差別。)