你是否曾想在TensorFlow或PyTorch編寫的代碼中使用二階優化器?使用SciPy最小化來優化一個張量字典呢?若是是這樣,可能須要不少麻煩的代碼。對於另外一種方法,請看dict-minimize包,它兼顧一切,讓用戶輕鬆優化在TensorFlow、PyTorch或JAX中實現的目標。html
背景
現代深度學習框架及其內置的優化工具,都是圍繞着用戶想要使用隨機梯度降低(SGD)或其變體(如ADAM)進行優化的假設而設計的。許多深度學習從業者甚至可能不知道在優化界有大量關於更廣泛的方法的文獻,這些方法在深度學習興起以前是占主導地位的。git
特別是,像L-BFGS和共軛梯度(CG)這樣的方法是前深度學習時代的經常使用方法(有些人可能還記得使用 minim.m)。那麼,是什麼改變了呢?在深度學習中,咱們要處理巨大的數據集。所以,爲訓練網絡得到準確的梯度須要整個時代的數據,這在計算上是不可行的。所以,咱們改用作數據子採樣來得到訓練損失梯度的隨機(無偏)估計,並使用SGD。深度學習的奇蹟是,對於訓練深度神經網絡的權重,使用隨機梯度實際上比批量優化效果更好。這是由於隱性正則化和其餘緣由。github
然而,優化不只僅是訓練深度神經網絡的權重。對於許多問題來講,準確的梯度是廉價的,像L-BFGS這樣的傳統優化方法效果更好。它們在默認的超參數下也能很好地工做。相比之下,在SGD的大多數應用中,必須對超參數進行一些調整以得到良好的性能。在適用的狀況下,將L-BFGS這樣的方法做爲優化的一個選項是很是有用的。api
傳統的精確梯度優化方法已經在scipy-minimize中使用多年了。然而,這些SciPy優化例程對現代用戶來講是不方便的。首先,這些例程的SciPy API假定用戶已經在NumPy中編碼了一個目標函數,並手動編碼了它的梯度。現代用戶在TensorFlow、PyTorch或JAX等框架中實現他們的目標,這樣他們就能夠經過自動微分得到梯度,而咱們的軟件包容許這樣作。第二,SciPy API假設用戶想要優化一個一維NumPy向量。現代用戶但願同時優化幾個張量參數的集合。這就是爲何咱們實現了咱們的包,dict-minimize,做爲一個張量的字典。數組
在Twitter,咱們用dict-minimize來訓練樣本外分類校準器的參數,這些校準器的訓練集較小。由於衆所周知,深度網絡在預測中給出的校準機率不好,因此可使用少許的保留數據,例如1%,來訓練β校準階段。在這種狀況下,精確梯度很便宜,由於用於訓練校準器的數據集大小要小得多。較小的校準網絡也使反向傳播的速度更快。在這種狀況下,咱們能夠對收斂性更有信心,而不須要進行超參數調整,這比咱們對SGD更有信心。網絡
使用實例
咱們在dict-minimize包中支持TensorFlow、PyTorch、JAX和NumPy,能夠互換。不管你對深度學習框架的偏好如何,你均可以使用dict-minimize進行優化。咱們也支持NumPy,由於想要優化NumPy數組的字典的用戶也不能簡單地直接使用SciPy。框架
在這個例子中,咱們展現瞭如何從PyTorch的實現中優化一個Rosenbrock函數。出於演示的目的,數值被分割成兩個參數。函數
import torch
from dict_minimize.torch_api import minimize
def rosen_obj(params, shift):
"""Based on augmented Rosenbrock from botorch."""
X, Y = params["x_half_a"], params["x_half_b"]
X = X - shift
Y = Y - shift
obj = 100 * (X[1] - X[0] ** 2) ** 2 + 100 * (Y[1] - Y[0] ** 2) ** 2
return obj
def d_rosen_obj(params, shift):
obj = rosen_obj(params, shift=shift)
da, db = torch.autograd.grad(obj, [params["x_half_a"], params["x_half_b"]])
d_obj = OrderedDict([("x_half_a", da), ("x_half_b", db)])
return obj, d_obj
torch.manual_seed(123)
n_a = 2
n_b = 2
shift = -1.0
params = OrderedDict([("x_half_a", torch.randn((n_a,))), ("x_half_b", torch.randn((n_b,)))])
params = minimize(d_rosen_obj, params, args=(shift,), method="L-BFGS-B", options={"disp": True})
複製代碼
在上面的代碼塊中,咱們簡單地導入工具
from dict_minimize.torch_api import minimize
複製代碼
而不是post
This Tweet is unavailable
from scipy.optimize import minimize
複製代碼
這個接口與原來的scipy-minimize本質上是同樣的。然而,在這裏咱們使用了一個張量的字典,而不是簡單的NumPy向量。一樣地,目標函數程序是梯度張量的字典,而不是簡單的NumPy向量。對於大多數現代的實際問題來講,這是一個更天然的框架,在這些問題中,有許多不一樣的參數須要同時進行優化。
在深度夢境中應用Dict-Minimize
即便在深度學習中,也有許多優化的例子,其中準確的梯度不須要在大規模的訓練集上評估損失。這些都是可使用dict-minimize的狀況。也許最知名的例子是對抗性例子。在對抗性例子中,梯度是一個在單一訓練例子上訓練的深度網絡的輸出。在這些狀況下,從業者應用SGD是出於習慣而不是嚴格的須要。
在這篇博文中,咱們看一下另外一個能夠精確梯度的例子:深度夢境。深度夢想背後的想法是將視覺的深度神經網絡的輸入可視化,例如InceptionV3,它能使神經網絡中的內部層的神經元的反應最大化。它能夠做爲一個可解釋的工具,甚至只是用於藝術。關於深度夢境的工做代表,神經網絡的第一層的反應是如何被紋理等低層次的概念最大化的;而深層的反應則是被更高層次的概念最大化的。
深度夢想變得如此流行,以致於它成爲了一個標準的TensorFlow演示。因爲是在TensorFlow中實現的,做者簡單地使用了SGD(多是因爲缺少可供嘗試的替代品)。在這裏,咱們展現了L-BFGS,在沒有任何超參數調整的狀況下,如何得到比演示中的SGD更快的收斂。
在這裏,咱們用L-BFGS優化一幅圖像。咱們將原始演示中的SGD優化的主循環替換爲。
from dict_minimize.tensorflow_api import minimize
lb = OrderedDict({"img": -tf.ones_like(img)})
ub = OrderedDict({"img": tf.ones_like(img)})
params0 = OrderedDict({"img": img})
params = minimize(
deepdream.obj_and_grad_dict,
params0,
lb_dict=lb,
ub_dict=ub,
method="L-BFGS-B",
options={"disp": True, "maxfun": 100},
)
複製代碼
請注意,咱們能夠更天然地表達約束條件,好比圖像在白色和黑色之間有界限,使用界限參數。在SGD中,必須週期性地剪輯張量,以確保它保持在界限以內。
在這個例子中,咱們優化了InceptionV3中 "mixed5 "層的神經元1,它是在ImageNet數據集上訓練的。這個神經元對相似於鱷魚皮的紋理有反應。
下面咱們看到,默認的L-BFGS在收斂性方面優於調整後的演示中的SGD,是梯度評價的一個函數。
結論
dict-minimize包提供了方便的選項,能夠與現代深度學習框架對接,其中有自動區分功能。更高級的擴展選項有不少。例如,在較小的搜索空間中,當與具備Hessian能力的JAX相結合時,徹底的二階方法如牛頓優化也是可能的。dict-minimize軟件包提供了一個簡單而方便的接口。當用戶有一個新的優化問題時,他們應該考慮它,由於精確的梯度是能夠獲得的。
若是以上文章對您有幫助,請給咱們的開源項目點點star: http://github.crmeb.net/u/defu 不勝感激!
來自 「開源世界 」 ,連接:https://ym.baisou.ltd/post/724.html,如需轉載,請註明出處,不然將追究法律責任。