©作者 | 叶耿杰
单位 | 武汉大学
研究方向 | 凝聚态物理
@Peter Griffin 的回答对我大有启发。对于一个优化问题,大的步长确实会带来混沌的可能。以一维梯度下降为例,在极值点的附近,我们可以对势函数做简谐近似,即展开到二阶项。由于常数项、一次项系数可以通过平移消去,二次项系数可以通过重新选取长度量纲而归一,我们实际上只要考虑
由此可以猜测,在一个优化问题中,目标附近的非谐效应(几乎总是存在)、过大的学习率和过慢的学习率下降是产生分岔和混沌的诱因。
import numpy as np
import copy as cp
import matplotlib.pyplot as plt
def sig(x):
return 1 / (1 + np.exp(-x))
def dsig(x):
s = sig(x)
return np.exp(-x) * s * s
def relu(x):
if x < 0: return 0.1 * x
return x
def drelu(x):
if x >= 0: return 1
return 0.1
Sig = (sig, dsig)
Relu = (np.vectorize(relu), np.vectorize(drelu))
class ConnectLayer:
def __init__(self, inp, output, func_tup, lrate_tup):
self.inp = inp
self.output = output
self.func = func_tup[0]
self.dfunc = func_tup[1]
self.lrate = lrate_tup[0]
self.lrate_decay = lrate_tup[1]
self.decay_cnt = 0
self.w = np.random.random((output, inp))
self.b = np.random.random((output, 1))
self.yjs_cache = None
self.xjs_cache = None
def forward(self, xs):
# n = xs.shape[1]
self.xjs_cache = xs
yjs = self.w @ xs + self.b
self.yjs_cache = yjs
return self.func(yjs)
def backF(self, upstream): # f对y求导
return self.dfunc(self.yjs_cache) * upstream
def backPass(self, upstream): # y对x求导
return self.w.T @ upstream
def refw(self, upstream): # y对w求导
return upstream @ self.xjs_cache.T
def refb(self, upstream): # y对b求导
# 注意:不要直接使用np.sum,否则行列不稳定
db = np.sum(upstream, axis=1)
return db.reshape(self.b.shape)
def backward(self, upstream):
M = self.backF(upstream)
self.w -= self.lrate * self.refw(M)
self.b -= self.lrate * self.refb(M)
self.decay_cnt += 1
if self.decay_cnt == 100:
self.lrate *= self.lrate_decay
self.decay_cnt = 0
return self.backPass(M)
def g(x):
return np.sin(2 * np.pi * x) / 4 + 0.5
def genData():
xs = np.arange(0, 2.001, 0.05)
n = len(xs)
ys = []
for x in xs:
ys.append(g(x))
ys = np.array(ys)
return xs.reshape(1, n), ys.reshape(1, n)
def mse(fjs, yjs):
m, n = yjs.shape
delta = fjs - yjs
return np.sum(delta * delta) / m / n
def dmse(fjs, yjs):
return 2 * (fjs - yjs)
Mse = (mse, dmse)
class ScalarLayer:
def __init__(self, inp, answer, loss_tup):
self.inp = inp
self.answer = answer
self.loss = loss_tup[0]
self.dloss = loss_tup[1]
def forward(self, fyjs):
return self.loss(fyjs, self.answer)
def backward(self, fyjs): # L对f求导
return self.dloss(fyjs, self.answer)
class nn:
def __init__(self, layer_msg, funcs_msg, loss, xs, ys, lrate):
self.layer_msg = layer_msg
self.layers = []
self.xs = xs
self.ys = ys
for i in range(len(layers_msg) - 1):
self.layers.append(ConnectLayer(
inp=layers_msg[i],
output=layers_msg[i + 1],
func_tup=funcs_msg[i],
lrate_tup=lrate
))
self.outlet = ScalarLayer(1, ys, loss)
def train(self, TURNS):
ls = []
for t in range(TURNS):
# 单步训练
data = cp.deepcopy(self.xs)
for lay in self.layers:
data = lay.forward(data)
L = self.outlet.forward(data)
data = self.outlet.backward(data)
for lay in self.layers[::-1]:
data = lay.backward(data)
ls.append(L)
return ls
def test(self):
newxs = np.hstack((self.xs - 1, self.xs + 1))
data = cp.deepcopy(newxs)
for lay in self.layers:
data = lay.forward(data)
return newxs, data
if __name__ == '__main__':
xs, ys = genData()
layers_msg = [1, 4, 2, 2, 1]
funcs_msg = [Relu, Sig, Sig, Sig]
model = nn(layers_msg, funcs_msg, Mse, xs, ys, lrate=(0.3, 0.999))
ls = model.train(40000)
plt.plot(ls)
plt.show()
print('end')
更多阅读
#投 稿 通 道#
让你的文字被更多人看到
如何才能让更多的优质内容以更短路径到达读者群体,缩短读者寻找优质内容的成本呢?答案就是:你不认识的人。
总有一些你不认识的人,知道你想知道的东西。PaperWeekly 或许可以成为一座桥梁,促使不同背景、不同方向的学者和学术灵感相互碰撞,迸发出更多的可能性。
PaperWeekly 鼓励高校实验室或个人,在我们的平台上分享各类优质内容,可以是最新论文解读,也可以是学术热点剖析、科研心得或竞赛经验讲解等。我们的目的只有一个,让知识真正流动起来。
📝 稿件基本要求:
• 文章确系个人原创作品,未曾在公开渠道发表,如为其他平台已发表或待发表的文章,请明确标注
• 稿件建议以 markdown 格式撰写,文中配图以附件形式发送,要求图片清晰,无版权问题
• PaperWeekly 尊重原作者署名权,并将为每篇被采纳的原创首发稿件,提供业内具有竞争力稿酬,具体依据文章阅读量和文章质量阶梯制结算
📬 投稿通道:
• 投稿邮箱:hr@paperweekly.site
• 来稿请备注即时联系方式(微信),以便我们在稿件选用的第一时间联系作者
• 您也可以直接添加小编微信(pwbot02)快速投稿,备注:姓名-投稿
△长按添加PaperWeekly小编
🔍
现在,在「知乎」也能找到我们了
进入知乎首页搜索「PaperWeekly」
点击「关注」订阅我们的专栏吧