当前位置:   article > 正文

NNDL 作业13 优化算法3D可视化

NNDL 作业13 优化算法3D可视化

首先声明,我好几个图没整出来,不知道啥原因,求大佬们指点(╥╯﹏╰╥)ง

编程实现优化算法,并3D可视化

1. 函数3D可视化

分别画出x[0]^{2}+x[1]^{2}+x[1]^{3}+x[0]*x[1] 和 x^{2} /20+y^{2}的3D图

  1. import torch
  2. import numpy as np
  3. from matplotlib import pyplot as plt
  4. class Op(object):
  5. def __init__(self):
  6. pass
  7. def __call__(self, inputs):
  8. return self.forward(inputs)
  9. # 输入:张量inputs
  10. # 输出:张量outputs
  11. def forward(self, inputs):
  12. # return outputs
  13. raise NotImplementedError
  14. # 输入:最终输出对outputs的梯度outputs_grads
  15. # 输出:最终输出对inputs的梯度inputs_grads
  16. def backward(self, outputs_grads):
  17. # return inputs_grads
  18. raise NotImplementedError
  19. class OptimizedFunction3D(Op):
  20. def __init__(self):
  21. super(OptimizedFunction3D, self).__init__()
  22. self.params = {'x': 0}
  23. self.grads = {'x': 0}
  24. def forward(self, x):
  25. self.params['x'] = x
  26. return x[0] * x[0] / 20 + x[1] * x[1] / 1 # x[0] ** 2 + x[1] ** 2 + x[1] ** 3 + x[0] * x[1]
  27. def backward(self):
  28. x = self.params['x']
  29. gradient1 = 2 * x[0] / 20
  30. gradient2 = 2 * x[1] / 1
  31. grad1 = torch.Tensor([gradient1])
  32. grad2 = torch.Tensor([gradient2])
  33. self.grads['x'] = torch.cat([grad1, grad2])
  34. # 使用numpy.meshgrid生成x1,x2矩阵,矩阵的每一行为[-3, 3],以0.1为间隔的数值
  35. x1 = np.arange(-3, 3, 0.1)
  36. x2 = np.arange(-3, 3, 0.1)
  37. x1, x2 = np.meshgrid(x1, x2)
  38. init_x = torch.Tensor(np.array([x1, x2]))
  39. model = OptimizedFunction3D()
  40. # 绘制 f_3d函数 的 三维图像
  41. fig = plt.figure()
  42. ax = plt.axes(projection='3d')
  43. X = init_x[0].numpy()
  44. Y = init_x[1].numpy()
  45. Z = model(init_x).numpy()
  46. ax.plot_surface(X, Y, Z, cmap='rainbow')
  47. ax.set_xlabel('x1')
  48. ax.set_ylabel('x2')
  49. ax.set_zlabel('f(x1,x2)')
  50. ax.legend(loc='upper left')
  51. plt.show()

 两个函数代码的基本框架是一样的,只不过是函数不一样。只要将OptimizedFunction3D(Op)改为下面的就行

  1. class OptimizedFunction3D(Op):
  2. def __init__(self):
  3. super(OptimizedFunction3D, self).__init__()
  4. self.params = {'x': 0}
  5. self.grads = {'x': 0}
  6. def forward(self, x):
  7. self.params['x'] = x
  8. return x[0] ** 2 + x[1] ** 2 + x[1] ** 3 + x[0] * x[1]
  9. def backward(self):
  10. x = self.params['x']
  11. gradient1 = 2 * x[0] + x[1]
  12. gradient2 = 2 * x[1] + 3 * x[1] ** 2 + x[0]
  13. grad1 = torch.Tensor([gradient1])
  14. grad2 = torch.Tensor([gradient2])
  15. self.grads['x'] = torch.cat([grad1, grad2])

这段代码一开始参考学长学姐的代码跑不出开,然后根据老师给的加入优化算法的代码写出来的。

 2.加入优化算法,画出轨迹

分别画出x[0]^{2}+x[1]^{2}+x[1]^{3}+x[0]*x[1] 和 x^{2} /20+y^{2}的3D轨迹图

结合3D动画,用自己的语言,从轨迹、速度等多个角度讲解各个算法优缺点

SimpleBatchGD算法

初始化 SimpleBatchGD(init_lr, model)

    调用 Optimizer,传入 init_lr 和 model 参数

 定义step() 方法:

    如果 model.params 是字典类型

        for  key in model.params :

             更新 model.params[key] = model.params[key] - init_lr * model.grads[key]

Adagrad算法

初始化 Adagrad(init_lr, model, epsilon)

    调用 Optimizer ,传入 init_lr 和 model 参数

    初始化 G 为空字典

     for  key in model.params :

        将 epsilon参数值赋给self. epsilon

adagrad(x, gradient_x, G, init_lr):

    更新 G[key] += gradient_x ** 2

    计算 x -= init_lr / torch.sqrt(G + epsilon) * gradient_x

    return x 和 G

定义step()方法

   for  key in model.params :

   调用 adagrad 方法并赋值给 model.params[key] 和 G[key]

RMSprop算法

初始化 RMSprop(init_lr, model, beta, epsilon)

   调用 Optimizer ,传入 init_lr 和 model 参数

   初始化 G 为空字典

   for  key in model.params :

      将 beta参数值赋给self. beta

      将 epsilon参数值赋给self. epsilon

rmsprop(x, gradient_x, G, init_lr):

   更新 G = beta * G + (1 - beta) * gradient_x ** 2

   计算 x -= init_lr / torch.sqrt(G + epsilon) * gradient_x

   return x 和 G

定义step()方法

   for  key in model.params :

   调用 rmsprop 方法并赋值给 model.params[key] 和 G[key]

Momentum算法

初始化 Momentum(init_lr, model, rho)  

   调用 Optimizer ,传入 init_lr 和 model 参数

   初始化 delta_x 

   for  key in model.params :

      将rho参数值赋给self. rho

momentum(x, gradient_x, delta_x, init_lr) :

   更新 delta_x = rho * delta_x - init_lr * gradient_x

   计算  x += delta_x

   return x 和  delta_x

定义step()方法

   for  key in model.params :

   调用momentum 方法并赋值给 model.params[key] 和delta_x[key]

Adam算法

初始化 Adam(init_lr, model, beta1, beta2, epsilon)  

   调用 Optimizer ,传入 init_lr 和 model 参数

   将beta1,beta2,epsilon参数值赋给self. beta1,self.beta2,self.epsilon

   初始化 M, G 为空字典

adam(x, gradient_x, G, M, t, init_lr) :

   计算 M = beta1 * M + (1 - beta1) * gradient_x

   计算 G = beta2 * G + (1 - beta2) * gradient_x ** 2

   计算 M_hat = M / (1 - beta1 ** t)

   计算 G_hat = G / (1 - beta2 ** t)

   计算 x -= init_lr / torch.sqrt(G_hat + epsilon) * M_hat

   return  x, G, M 和 t

定义step()方法

   for  key in model.params :

   调用adam 方法并赋值给 model.params[key] 和delta_x[key]

  1. import torch
  2. import numpy as np
  3. import copy
  4. from matplotlib import pyplot as plt
  5. from matplotlib import animation
  6. from itertools import zip_longest
  7. class Op(object):
  8. def __init__(self):
  9. pass
  10. def __call__(self, inputs):
  11. return self.forward(inputs)
  12. # 输入:张量inputs
  13. # 输出:张量outputs
  14. def forward(self, inputs):
  15. # return outputs
  16. raise NotImplementedError
  17. # 输入:最终输出对outputs的梯度outputs_grads
  18. # 输出:最终输出对inputs的梯度inputs_grads
  19. def backward(self, outputs_grads):
  20. # return inputs_grads
  21. raise NotImplementedError
  22. class Optimizer(object): # 优化器基类
  23. def __init__(self, init_lr, model):
  24. """
  25. 优化器类初始化
  26. """
  27. # 初始化学习率,用于参数更新的计算
  28. self.init_lr = init_lr
  29. # 指定优化器需要优化的模型
  30. self.model = model
  31. def step(self):
  32. """
  33. 定义每次迭代如何更新参数
  34. """
  35. pass
  36. class SimpleBatchGD(Optimizer):
  37. def __init__(self, init_lr, model):
  38. super(SimpleBatchGD, self).__init__(init_lr=init_lr, model=model)
  39. def step(self):
  40. # 参数更新
  41. if isinstance(self.model.params, dict):
  42. for key in self.model.params.keys():
  43. self.model.params[key] = self.model.params[key] - self.init_lr * self.model.grads[key]
  44. class Adagrad(Optimizer):
  45. def __init__(self, init_lr, model, epsilon):
  46. """
  47. Adagrad 优化器初始化
  48. 输入:
  49. - init_lr: 初始学习率 - model:模型,model.params存储模型参数值 - epsilon:保持数值稳定性而设置的非常小的常数
  50. """
  51. super(Adagrad, self).__init__(init_lr=init_lr, model=model)
  52. self.G = {}
  53. for key in self.model.params.keys():
  54. self.G[key] = 0
  55. self.epsilon = epsilon
  56. def adagrad(self, x, gradient_x, G, init_lr):
  57. """
  58. adagrad算法更新参数,G为参数梯度平方的累计值。
  59. """
  60. G += gradient_x ** 2
  61. x -= init_lr / torch.sqrt(G + self.epsilon) * gradient_x
  62. return x, G
  63. def step(self):
  64. """
  65. 参数更新
  66. """
  67. for key in self.model.params.keys():
  68. self.model.params[key], self.G[key] = self.adagrad(self.model.params[key],
  69. self.model.grads[key],
  70. self.G[key],
  71. self.init_lr)
  72. class RMSprop(Optimizer):
  73. def __init__(self, init_lr, model, beta, epsilon):
  74. """
  75. RMSprop优化器初始化
  76. 输入:
  77. - init_lr:初始学习率
  78. - model:模型,model.params存储模型参数值
  79. - beta:衰减率
  80. - epsilon:保持数值稳定性而设置的常数
  81. """
  82. super(RMSprop, self).__init__(init_lr=init_lr, model=model)
  83. self.G = {}
  84. for key in self.model.params.keys():
  85. self.G[key] = 0
  86. self.beta = beta
  87. self.epsilon = epsilon
  88. def rmsprop(self, x, gradient_x, G, init_lr):
  89. """
  90. rmsprop算法更新参数,G为迭代梯度平方的加权移动平均
  91. """
  92. G = self.beta * G + (1 - self.beta) * gradient_x ** 2
  93. x -= init_lr / torch.sqrt(G + self.epsilon) * gradient_x
  94. return x, G
  95. def step(self):
  96. """参数更新"""
  97. for key in self.model.params.keys():
  98. self.model.params[key], self.G[key] = self.rmsprop(self.model.params[key],
  99. self.model.grads[key],
  100. self.G[key],
  101. self.init_lr)
  102. class Momentum(Optimizer):
  103. def __init__(self, init_lr, model, rho):
  104. """
  105. Momentum优化器初始化
  106. 输入:
  107. - init_lr:初始学习率
  108. - model:模型,model.params存储模型参数值
  109. - rho:动量因子
  110. """
  111. super(Momentum, self).__init__(init_lr=init_lr, model=model)
  112. self.delta_x = {}
  113. for key in self.model.params.keys():
  114. self.delta_x[key] = 0
  115. self.rho = rho
  116. def momentum(self, x, gradient_x, delta_x, init_lr):
  117. """
  118. momentum算法更新参数,delta_x为梯度的加权移动平均
  119. """
  120. delta_x = self.rho * delta_x - init_lr * gradient_x
  121. x += delta_x
  122. return x, delta_x
  123. def step(self):
  124. """参数更新"""
  125. for key in self.model.params.keys():
  126. self.model.params[key], self.delta_x[key] = self.momentum(self.model.params[key],
  127. self.model.grads[key],
  128. self.delta_x[key],
  129. self.init_lr)
  130. class Adam(Optimizer):
  131. def __init__(self, init_lr, model, beta1, beta2, epsilon):
  132. """
  133. Adam优化器初始化
  134. 输入:
  135. - init_lr:初始学习率
  136. - model:模型,model.params存储模型参数值
  137. - beta1, beta2:移动平均的衰减率
  138. - epsilon:保持数值稳定性而设置的常数
  139. """
  140. super(Adam, self).__init__(init_lr=init_lr, model=model)
  141. self.beta1 = beta1
  142. self.beta2 = beta2
  143. self.epsilon = epsilon
  144. self.M, self.G = {}, {}
  145. for key in self.model.params.keys():
  146. self.M[key] = 0
  147. self.G[key] = 0
  148. self.t = 1
  149. def adam(self, x, gradient_x, G, M, t, init_lr):
  150. """
  151. adam算法更新参数
  152. 输入:
  153. - x:参数
  154. - G:梯度平方的加权移动平均
  155. - M:梯度的加权移动平均
  156. - t:迭代次数
  157. - init_lr:初始学习率
  158. """
  159. M = self.beta1 * M + (1 - self.beta1) * gradient_x
  160. G = self.beta2 * G + (1 - self.beta2) * gradient_x ** 2
  161. M_hat = M / (1 - self.beta1 ** t)
  162. G_hat = G / (1 - self.beta2 ** t)
  163. t += 1
  164. x -= init_lr / torch.sqrt(G_hat + self.epsilon) * M_hat
  165. return x, G, M, t
  166. def step(self):
  167. """参数更新"""
  168. for key in self.model.params.keys():
  169. self.model.params[key], self.G[key], self.M[key], self.t = self.adam(self.model.params[key],
  170. self.model.grads[key],
  171. self.G[key],
  172. self.M[key],
  173. self.t,
  174. self.init_lr)
  175. class OptimizedFunction3D(Op):
  176. def __init__(self):
  177. super(OptimizedFunction3D, self).__init__()
  178. self.params = {'x': 0}
  179. self.grads = {'x': 0}
  180. def forward(self, x):
  181. self.params['x'] = x
  182. return x[0] ** 2 + x[1] ** 2 + x[1] ** 3 + x[0] * x[1]
  183. def backward(self):
  184. x = self.params['x']
  185. gradient1 = 2 * x[0] + x[1]
  186. gradient2 = 2 * x[1] + 3 * x[1] ** 2 + x[0]
  187. grad1 = torch.Tensor([gradient1])
  188. grad2 = torch.Tensor([gradient2])
  189. self.grads['x'] = torch.cat([grad1, grad2])
  190. class Visualization3D(animation.FuncAnimation):
  191. """ 绘制动态图像,可视化参数更新轨迹 """
  192. def __init__(self, *xy_values, z_values, labels=[], colors=[], fig, ax, interval=600, blit=True, **kwargs):
  193. """
  194. 初始化3d可视化类
  195. 输入:
  196. xy_values:三维中x,y维度的值
  197. z_values:三维中z维度的值
  198. labels:每个参数更新轨迹的标签
  199. colors:每个轨迹的颜色
  200. interval:帧之间的延迟(以毫秒为单位)
  201. blit:是否优化绘图
  202. """
  203. self.fig = fig
  204. self.ax = ax
  205. self.xy_values = xy_values
  206. self.z_values = z_values
  207. frames = max(xy_value.shape[0] for xy_value in xy_values)
  208. self.lines = [ax.plot([], [], [], label=label, color=color, lw=2)[0]
  209. for _, label, color in zip_longest(xy_values, labels, colors)]
  210. super(Visualization3D, self).__init__(fig, self.animate, init_func=self.init_animation, frames=frames,
  211. interval=interval, blit=blit, **kwargs)
  212. def init_animation(self):
  213. # 数值初始化
  214. for line in self.lines:
  215. line.set_data([], [])
  216. # line.set_3d_properties(np.asarray([])) # 源程序中有这一行,加上会报错。 Edit by David 2022.12.4
  217. return self.lines
  218. def animate(self, i):
  219. # 将x,y,z三个数据传入,绘制三维图像
  220. for line, xy_value, z_value in zip(self.lines, self.xy_values, self.z_values):
  221. line.set_data(xy_value[:i, 0], xy_value[:i, 1])
  222. line.set_3d_properties(z_value[:i])
  223. return self.lines
  224. def train_f(model, optimizer, x_init, epoch):
  225. x = x_init
  226. all_x = []
  227. losses = []
  228. for i in range(epoch):
  229. all_x.append(copy.deepcopy(x.numpy())) # 浅拷贝 改为 深拷贝, 否则List的原值会被改变。 Edit by David 2022.12.4.
  230. loss = model(x)
  231. losses.append(loss)
  232. model.backward()
  233. optimizer.step()
  234. x = model.params['x']
  235. return torch.Tensor(np.array(all_x)), losses
  236. # 构建5个模型,分别配备不同的优化器
  237. model1 = OptimizedFunction3D()
  238. opt_gd = SimpleBatchGD(init_lr=0.01, model=model1)
  239. model2 = OptimizedFunction3D()
  240. opt_adagrad = Adagrad(init_lr=0.5, model=model2, epsilon=1e-7)
  241. model3 = OptimizedFunction3D()
  242. opt_rmsprop = RMSprop(init_lr=0.1, model=model3, beta=0.9, epsilon=1e-7)
  243. model4 = OptimizedFunction3D()
  244. opt_momentum = Momentum(init_lr=0.01, model=model4, rho=0.9)
  245. model5 = OptimizedFunction3D()
  246. opt_adam = Adam(init_lr=0.1, model=model5, beta1=0.9, beta2=0.99, epsilon=1e-7)
  247. models = [model1, model2, model3, model4, model5]
  248. opts = [opt_gd, opt_adagrad, opt_rmsprop, opt_momentum, opt_adam]
  249. x_all_opts = []
  250. z_all_opts = []
  251. # 使用不同优化器训练
  252. for model, opt in zip(models, opts):
  253. x_init = torch.FloatTensor([2, 3])
  254. x_one_opt, z_one_opt = train_f(model, opt, x_init, 150) # epoch
  255. # 保存参数值
  256. x_all_opts.append(x_one_opt.numpy())
  257. z_all_opts.append(np.squeeze(z_one_opt))
  258. # 使用numpy.meshgrid生成x1,x2矩阵,矩阵的每一行为[-3, 3],以0.1为间隔的数值
  259. x1 = np.arange(-3, 3, 0.1)
  260. x2 = np.arange(-3, 3, 0.1)
  261. x1, x2 = np.meshgrid(x1, x2)
  262. init_x = torch.Tensor(np.array([x1, x2]))
  263. model = OptimizedFunction3D()
  264. # 绘制 f_3d函数 的 三维图像
  265. fig = plt.figure()
  266. ax = plt.axes(projection='3d')
  267. X = init_x[0].numpy()
  268. Y = init_x[1].numpy()
  269. Z = model(init_x).numpy() # 改为 model(init_x).numpy() David 2022.12.4
  270. ax.plot_surface(X, Y, Z, cmap='rainbow')
  271. ax.set_xlabel('x1')
  272. ax.set_ylabel('x2')
  273. ax.set_zlabel('f(x1,x2)')
  274. labels = ['SGD', 'AdaGrad', 'RMSprop', 'Momentum', 'Adam']
  275. colors = ['#f6373c', '#f6f237', '#45f637', '#37f0f6', '#000000']
  276. animator = Visualization3D(*x_all_opts, z_values=z_all_opts, labels=labels, colors=colors, fig=fig, ax=ax)
  277. ax.legend(loc='upper left')
  278. plt.show()
  279. animator.save('animation.gif') # 效果不好,估计被挡住了…… 有待进一步提高 Edit by David 2022.12.4

  1. import torch
  2. import numpy as np
  3. import copy
  4. from matplotlib import pyplot as plt
  5. from matplotlib import animation
  6. from itertools import zip_longest
  7. from matplotlib import cm
  8. class Op(object):
  9. def __init__(self):
  10. pass
  11. def __call__(self, inputs):
  12. return self.forward(inputs)
  13. # 输入:张量inputs
  14. # 输出:张量outputs
  15. def forward(self, inputs):
  16. # return outputs
  17. raise NotImplementedError
  18. # 输入:最终输出对outputs的梯度outputs_grads
  19. # 输出:最终输出对inputs的梯度inputs_grads
  20. def backward(self, outputs_grads):
  21. # return inputs_grads
  22. raise NotImplementedError
  23. class Optimizer(object): # 优化器基类
  24. def __init__(self, init_lr, model):
  25. """
  26. 优化器类初始化
  27. """
  28. # 初始化学习率,用于参数更新的计算
  29. self.init_lr = init_lr
  30. # 指定优化器需要优化的模型
  31. self.model = model
  32. def step(self):
  33. """
  34. 定义每次迭代如何更新参数
  35. """
  36. pass
  37. class SimpleBatchGD(Optimizer):
  38. def __init__(self, init_lr, model):
  39. super(SimpleBatchGD, self).__init__(init_lr=init_lr, model=model)
  40. def step(self):
  41. # 参数更新
  42. if isinstance(self.model.params, dict):
  43. for key in self.model.params.keys():
  44. self.model.params[key] = self.model.params[key] - self.init_lr * self.model.grads[key]
  45. class Adagrad(Optimizer):
  46. def __init__(self, init_lr, model, epsilon):
  47. """
  48. Adagrad 优化器初始化
  49. 输入:
  50. - init_lr: 初始学习率 - model:模型,model.params存储模型参数值 - epsilon:保持数值稳定性而设置的非常小的常数
  51. """
  52. super(Adagrad, self).__init__(init_lr=init_lr, model=model)
  53. self.G = {}
  54. for key in self.model.params.keys():
  55. self.G[key] = 0
  56. self.epsilon = epsilon
  57. def adagrad(self, x, gradient_x, G, init_lr):
  58. """
  59. adagrad算法更新参数,G为参数梯度平方的累计值。
  60. """
  61. G += gradient_x ** 2
  62. x -= init_lr / torch.sqrt(G + self.epsilon) * gradient_x
  63. return x, G
  64. def step(self):
  65. """
  66. 参数更新
  67. """
  68. for key in self.model.params.keys():
  69. self.model.params[key], self.G[key] = self.adagrad(self.model.params[key],
  70. self.model.grads[key],
  71. self.G[key],
  72. self.init_lr)
  73. class RMSprop(Optimizer):
  74. def __init__(self, init_lr, model, beta, epsilon):
  75. """
  76. RMSprop优化器初始化
  77. 输入:
  78. - init_lr:初始学习率
  79. - model:模型,model.params存储模型参数值
  80. - beta:衰减率
  81. - epsilon:保持数值稳定性而设置的常数
  82. """
  83. super(RMSprop, self).__init__(init_lr=init_lr, model=model)
  84. self.G = {}
  85. for key in self.model.params.keys():
  86. self.G[key] = 0
  87. self.beta = beta
  88. self.epsilon = epsilon
  89. def rmsprop(self, x, gradient_x, G, init_lr):
  90. """
  91. rmsprop算法更新参数,G为迭代梯度平方的加权移动平均
  92. """
  93. G = self.beta * G + (1 - self.beta) * gradient_x ** 2
  94. x -= init_lr / torch.sqrt(G + self.epsilon) * gradient_x
  95. return x, G
  96. def step(self):
  97. """参数更新"""
  98. for key in self.model.params.keys():
  99. self.model.params[key], self.G[key] = self.rmsprop(self.model.params[key],
  100. self.model.grads[key],
  101. self.G[key],
  102. self.init_lr)
  103. class Momentum(Optimizer):
  104. def __init__(self, init_lr, model, rho):
  105. """
  106. Momentum优化器初始化
  107. 输入:
  108. - init_lr:初始学习率
  109. - model:模型,model.params存储模型参数值
  110. - rho:动量因子
  111. """
  112. super(Momentum, self).__init__(init_lr=init_lr, model=model)
  113. self.delta_x = {}
  114. for key in self.model.params.keys():
  115. self.delta_x[key] = 0
  116. self.rho = rho
  117. def momentum(self, x, gradient_x, delta_x, init_lr):
  118. """
  119. momentum算法更新参数,delta_x为梯度的加权移动平均
  120. """
  121. delta_x = self.rho * delta_x - init_lr * gradient_x
  122. x += delta_x
  123. return x, delta_x
  124. def step(self):
  125. """参数更新"""
  126. for key in self.model.params.keys():
  127. self.model.params[key], self.delta_x[key] = self.momentum(self.model.params[key],
  128. self.model.grads[key],
  129. self.delta_x[key],
  130. self.init_lr)
  131. class Adam(Optimizer):
  132. def __init__(self, init_lr, model, beta1, beta2, epsilon):
  133. """
  134. Adam优化器初始化
  135. 输入:
  136. - init_lr:初始学习率
  137. - model:模型,model.params存储模型参数值
  138. - beta1, beta2:移动平均的衰减率
  139. - epsilon:保持数值稳定性而设置的常数
  140. """
  141. super(Adam, self).__init__(init_lr=init_lr, model=model)
  142. self.beta1 = beta1
  143. self.beta2 = beta2
  144. self.epsilon = epsilon
  145. self.M, self.G = {}, {}
  146. for key in self.model.params.keys():
  147. self.M[key] = 0
  148. self.G[key] = 0
  149. self.t = 1
  150. def adam(self, x, gradient_x, G, M, t, init_lr):
  151. """
  152. adam算法更新参数
  153. 输入:
  154. - x:参数
  155. - G:梯度平方的加权移动平均
  156. - M:梯度的加权移动平均
  157. - t:迭代次数
  158. - init_lr:初始学习率
  159. """
  160. M = self.beta1 * M + (1 - self.beta1) * gradient_x
  161. G = self.beta2 * G + (1 - self.beta2) * gradient_x ** 2
  162. M_hat = M / (1 - self.beta1 ** t)
  163. G_hat = G / (1 - self.beta2 ** t)
  164. t += 1
  165. x -= init_lr / torch.sqrt(G_hat + self.epsilon) * M_hat
  166. return x, G, M, t
  167. def step(self):
  168. """参数更新"""
  169. for key in self.model.params.keys():
  170. self.model.params[key], self.G[key], self.M[key], self.t = self.adam(self.model.params[key],
  171. self.model.grads[key],
  172. self.G[key],
  173. self.M[key],
  174. self.t,
  175. self.init_lr)
  176. class OptimizedFunction3D(Op):
  177. def __init__(self):
  178. super(OptimizedFunction3D, self).__init__()
  179. self.params = {'x': 0}
  180. self.grads = {'x': 0}
  181. def forward(self, x):
  182. self.params['x'] = x
  183. return x[0] * x[0] / 20 + x[1] * x[1] / 1 # x[0] ** 2 + x[1] ** 2 + x[1] ** 3 + x[0] * x[1]
  184. def backward(self):
  185. x = self.params['x']
  186. gradient1 = 2 * x[0] / 20
  187. gradient2 = 2 * x[1] / 1
  188. grad1 = torch.Tensor([gradient1])
  189. grad2 = torch.Tensor([gradient2])
  190. self.grads['x'] = torch.cat([grad1, grad2])
  191. class Visualization3D(animation.FuncAnimation):
  192. """ 绘制动态图像,可视化参数更新轨迹 """
  193. def __init__(self, *xy_values, z_values, labels=[], colors=[], fig, ax, interval=100, blit=True, **kwargs):
  194. """
  195. 初始化3d可视化类
  196. 输入:
  197. xy_values:三维中x,y维度的值
  198. z_values:三维中z维度的值
  199. labels:每个参数更新轨迹的标签
  200. colors:每个轨迹的颜色
  201. interval:帧之间的延迟(以毫秒为单位)
  202. blit:是否优化绘图
  203. """
  204. self.fig = fig
  205. self.ax = ax
  206. self.xy_values = xy_values
  207. self.z_values = z_values
  208. frames = max(xy_value.shape[0] for xy_value in xy_values)
  209. self.lines = [ax.plot([], [], [], label=label, color=color, lw=2)[0]
  210. for _, label, color in zip_longest(xy_values, labels, colors)]
  211. self.points = [ax.plot([], [], [], color=color, markeredgewidth=1, markeredgecolor='black', marker='o')[0]
  212. for _, color in zip_longest(xy_values, colors)]
  213. # print(self.lines)
  214. super(Visualization3D, self).__init__(fig, self.animate, init_func=self.init_animation, frames=frames,
  215. interval=interval, blit=blit, **kwargs)
  216. def init_animation(self):
  217. # 数值初始化
  218. for line in self.lines:
  219. line.set_data_3d([], [], [])
  220. for point in self.points:
  221. point.set_data_3d([], [], [])
  222. return self.points + self.lines
  223. def animate(self, i):
  224. # 将x,y,z三个数据传入,绘制三维图像
  225. for line, xy_value, z_value in zip(self.lines, self.xy_values, self.z_values):
  226. line.set_data_3d(xy_value[:i, 0], xy_value[:i, 1], z_value[:i])
  227. for point, xy_value, z_value in zip(self.points, self.xy_values, self.z_values):
  228. point.set_data_3d(xy_value[i, 0], xy_value[i, 1], z_value[i])
  229. return self.points + self.lines
  230. def train_f(model, optimizer, x_init, epoch):
  231. x = x_init
  232. all_x = []
  233. losses = []
  234. for i in range(epoch):
  235. all_x.append(copy.deepcopy(x.numpy())) # 浅拷贝 改为 深拷贝, 否则List的原值会被改变。 Edit by David 2022.12.4.
  236. loss = model(x)
  237. losses.append(loss)
  238. model.backward()
  239. optimizer.step()
  240. x = model.params['x']
  241. return torch.Tensor(np.array(all_x)), losses
  242. # 构建5个模型,分别配备不同的优化器
  243. model1 = OptimizedFunction3D()
  244. opt_gd = SimpleBatchGD(init_lr=0.95, model=model1)
  245. model2 = OptimizedFunction3D()
  246. opt_adagrad = Adagrad(init_lr=1.5, model=model2, epsilon=1e-7)
  247. model3 = OptimizedFunction3D()
  248. opt_rmsprop = RMSprop(init_lr=0.05, model=model3, beta=0.9, epsilon=1e-7)
  249. model4 = OptimizedFunction3D()
  250. opt_momentum = Momentum(init_lr=0.1, model=model4, rho=0.9)
  251. model5 = OptimizedFunction3D()
  252. opt_adam = Adam(init_lr=0.3, model=model5, beta1=0.9, beta2=0.99, epsilon=1e-7)
  253. models = [model1, model2, model3, model4, model5]
  254. opts = [opt_gd, opt_adagrad, opt_rmsprop, opt_momentum, opt_adam]
  255. x_all_opts = []
  256. z_all_opts = []
  257. # 使用不同优化器训练
  258. for model, opt in zip(models, opts):
  259. x_init = torch.FloatTensor([-7, 2])
  260. x_one_opt, z_one_opt = train_f(model, opt, x_init, 100) # epoch
  261. # 保存参数值
  262. x_all_opts.append(x_one_opt.numpy())
  263. z_all_opts.append(np.squeeze(z_one_opt))
  264. # 使用numpy.meshgrid生成x1,x2矩阵,矩阵的每一行为[-3, 3],以0.1为间隔的数值
  265. x1 = np.arange(-10, 10, 0.01)
  266. x2 = np.arange(-5, 5, 0.01)
  267. x1, x2 = np.meshgrid(x1, x2)
  268. init_x = torch.Tensor(np.array([x1, x2]))
  269. model = OptimizedFunction3D()
  270. # 绘制 f_3d函数 的 三维图像
  271. fig = plt.figure()
  272. ax = plt.axes(projection='3d')
  273. X = init_x[0].numpy()
  274. Y = init_x[1].numpy()
  275. Z = model(init_x).numpy() # 改为 model(init_x).numpy() David 2022.12.4
  276. surf = ax.plot_surface(X, Y, Z, edgecolor='grey', cmap=cm.coolwarm)
  277. # fig.colorbar(surf, shrink=0.5, aspect=1)
  278. # ax.set_zlim(-3, 2)
  279. ax.set_xlabel('x1')
  280. ax.set_ylabel('x2')
  281. ax.set_zlabel('f(x1,x2)')
  282. labels = ['SGD', 'AdaGrad', 'RMSprop', 'Momentum', 'Adam']
  283. colors = ['#8B0000', '#0000FF', '#000000', '#008B00', '#FF0000']
  284. animator = Visualization3D(*x_all_opts, z_values=z_all_opts, labels=labels, colors=colors, fig=fig, ax=ax)
  285. ax.legend(loc='upper right')
  286. plt.show()
  287. # animator.save('teaser' + '.gif', writer='imagemagick',fps=10) # 效果不好,估计被挡住了…… 有待进一步提高 Edit by David 2022.12.4
  288. # save不好用,不费劲了,安装个软件做gif https://pc.qq.com/detail/13/detail_23913.html

 这段代码研究了好久也没有弄明白为什么没有轨迹,尝试了很多方法,没成功,最终只能放弃了。只能将这个问题遗留下来,等考试完再解决了。下面借用老师的图看看效果。

3.复现CS231经典动画

结合3D动画,用自己的语言,从轨迹、速度等多个角度讲解各个算法优缺点

Animations that may help your intuitions about the learning process dynamics. 

Left: Contours of a loss surface and time evolution of different optimization algorithms. Notice the "overshooting" behavior of momentum-based methods, which make the optimization look like a ball rolling down the hill. 

(左图:损失曲面的轮廓和不同优化算法的时间演化。注意基于动量的方法的“过度”行为,这使得优化看起来像一个球滚下山。)

Right: A visualization of a saddle point in the optimization landscape, where the curvature along different dimension has different signs (one dimension curves up and another down). Notice that SGD has a very hard time breaking symmetry and gets stuck on the top. Conversely, algorithms such as RMSprop will see very low gradients in the saddle direction. Due to the denominator term in the RMSprop update, this will increase the effective learning rate along this direction, helping RMSProp proceed. 

(右图:优化景观中鞍点的可视化,其中不同维度的曲率具有不同的符号(一个维度向上弯曲,另一个维度向下弯曲)。请注意,SGD很难打破对称性,并卡在顶部。相反,像RMSprop这样的算法将在鞍方向上看到非常低的梯度。由于RMSprop更新中的分母项,这将增加沿着这个方向的有效学习速率,帮助RMSProp继续。)

  1. import torch
  2. import numpy as np
  3. import copy
  4. from matplotlib import pyplot as plt
  5. from matplotlib import animation
  6. from itertools import zip_longest
  7. from matplotlib import cm
  8. class Op(object):
  9. def __init__(self):
  10. pass
  11. def __call__(self, inputs):
  12. return self.forward(inputs)
  13. # 输入:张量inputs
  14. # 输出:张量outputs
  15. def forward(self, inputs):
  16. # return outputs
  17. raise NotImplementedError
  18. # 输入:最终输出对outputs的梯度outputs_grads
  19. # 输出:最终输出对inputs的梯度inputs_grads
  20. def backward(self, outputs_grads):
  21. # return inputs_grads
  22. raise NotImplementedError
  23. class Optimizer(object): # 优化器基类
  24. def __init__(self, init_lr, model):
  25. """
  26. 优化器类初始化
  27. """
  28. # 初始化学习率,用于参数更新的计算
  29. self.init_lr = init_lr
  30. # 指定优化器需要优化的模型
  31. self.model = model
  32. def step(self):
  33. """
  34. 定义每次迭代如何更新参数
  35. """
  36. pass
  37. class SimpleBatchGD(Optimizer):
  38. def __init__(self, init_lr, model):
  39. super(SimpleBatchGD, self).__init__(init_lr=init_lr, model=model)
  40. def step(self):
  41. # 参数更新
  42. if isinstance(self.model.params, dict):
  43. for key in self.model.params.keys():
  44. self.model.params[key] = self.model.params[key] - self.init_lr * self.model.grads[key]
  45. class Adagrad(Optimizer):
  46. def __init__(self, init_lr, model, epsilon):
  47. """
  48. Adagrad 优化器初始化
  49. 输入:
  50. - init_lr: 初始学习率 - model:模型,model.params存储模型参数值 - epsilon:保持数值稳定性而设置的非常小的常数
  51. """
  52. super(Adagrad, self).__init__(init_lr=init_lr, model=model)
  53. self.G = {}
  54. for key in self.model.params.keys():
  55. self.G[key] = 0
  56. self.epsilon = epsilon
  57. def adagrad(self, x, gradient_x, G, init_lr):
  58. """
  59. adagrad算法更新参数,G为参数梯度平方的累计值。
  60. """
  61. G += gradient_x ** 2
  62. x -= init_lr / torch.sqrt(G + self.epsilon) * gradient_x
  63. return x, G
  64. def step(self):
  65. """
  66. 参数更新
  67. """
  68. for key in self.model.params.keys():
  69. self.model.params[key], self.G[key] = self.adagrad(self.model.params[key],
  70. self.model.grads[key],
  71. self.G[key],
  72. self.init_lr)
  73. class RMSprop(Optimizer):
  74. def __init__(self, init_lr, model, beta, epsilon):
  75. """
  76. RMSprop优化器初始化
  77. 输入:
  78. - init_lr:初始学习率
  79. - model:模型,model.params存储模型参数值
  80. - beta:衰减率
  81. - epsilon:保持数值稳定性而设置的常数
  82. """
  83. super(RMSprop, self).__init__(init_lr=init_lr, model=model)
  84. self.G = {}
  85. for key in self.model.params.keys():
  86. self.G[key] = 0
  87. self.beta = beta
  88. self.epsilon = epsilon
  89. def rmsprop(self, x, gradient_x, G, init_lr):
  90. """
  91. rmsprop算法更新参数,G为迭代梯度平方的加权移动平均
  92. """
  93. G = self.beta * G + (1 - self.beta) * gradient_x ** 2
  94. x -= init_lr / torch.sqrt(G + self.epsilon) * gradient_x
  95. return x, G
  96. def step(self):
  97. """参数更新"""
  98. for key in self.model.params.keys():
  99. self.model.params[key], self.G[key] = self.rmsprop(self.model.params[key],
  100. self.model.grads[key],
  101. self.G[key],
  102. self.init_lr)
  103. class Momentum(Optimizer):
  104. def __init__(self, init_lr, model, rho):
  105. """
  106. Momentum优化器初始化
  107. 输入:
  108. - init_lr:初始学习率
  109. - model:模型,model.params存储模型参数值
  110. - rho:动量因子
  111. """
  112. super(Momentum, self).__init__(init_lr=init_lr, model=model)
  113. self.delta_x = {}
  114. for key in self.model.params.keys():
  115. self.delta_x[key] = 0
  116. self.rho = rho
  117. def momentum(self, x, gradient_x, delta_x, init_lr):
  118. """
  119. momentum算法更新参数,delta_x为梯度的加权移动平均
  120. """
  121. delta_x = self.rho * delta_x - init_lr * gradient_x
  122. x += delta_x
  123. return x, delta_x
  124. def step(self):
  125. """参数更新"""
  126. for key in self.model.params.keys():
  127. self.model.params[key], self.delta_x[key] = self.momentum(self.model.params[key],
  128. self.model.grads[key],
  129. self.delta_x[key],
  130. self.init_lr)
  131. class Adam(Optimizer):
  132. def __init__(self, init_lr, model, beta1, beta2, epsilon):
  133. """
  134. Adam优化器初始化
  135. 输入:
  136. - init_lr:初始学习率
  137. - model:模型,model.params存储模型参数值
  138. - beta1, beta2:移动平均的衰减率
  139. - epsilon:保持数值稳定性而设置的常数
  140. """
  141. super(Adam, self).__init__(init_lr=init_lr, model=model)
  142. self.beta1 = beta1
  143. self.beta2 = beta2
  144. self.epsilon = epsilon
  145. self.M, self.G = {}, {}
  146. for key in self.model.params.keys():
  147. self.M[key] = 0
  148. self.G[key] = 0
  149. self.t = 1
  150. def adam(self, x, gradient_x, G, M, t, init_lr):
  151. """
  152. adam算法更新参数
  153. 输入:
  154. - x:参数
  155. - G:梯度平方的加权移动平均
  156. - M:梯度的加权移动平均
  157. - t:迭代次数
  158. - init_lr:初始学习率
  159. """
  160. M = self.beta1 * M + (1 - self.beta1) * gradient_x
  161. G = self.beta2 * G + (1 - self.beta2) * gradient_x ** 2
  162. M_hat = M / (1 - self.beta1 ** t)
  163. G_hat = G / (1 - self.beta2 ** t)
  164. t += 1
  165. x -= init_lr / torch.sqrt(G_hat + self.epsilon) * M_hat
  166. return x, G, M, t
  167. def step(self):
  168. """参数更新"""
  169. for key in self.model.params.keys():
  170. self.model.params[key], self.G[key], self.M[key], self.t = self.adam(self.model.params[key],
  171. self.model.grads[key],
  172. self.G[key],
  173. self.M[key],
  174. self.t,
  175. self.init_lr)
  176. class OptimizedFunction3D(Op):
  177. def __init__(self):
  178. super(OptimizedFunction3D, self).__init__()
  179. self.params = {'x': 0}
  180. self.grads = {'x': 0}
  181. def forward(self, x):
  182. self.params['x'] = x
  183. return - x[0] * x[0] / 2 + x[1] * x[1] / 1 # x[0] ** 2 + x[1] ** 2 + x[1] ** 3 + x[0] * x[1]
  184. def backward(self):
  185. x = self.params['x']
  186. gradient1 = - 2 * x[0] / 2
  187. gradient2 = 2 * x[1] / 1
  188. grad1 = torch.Tensor([gradient1])
  189. grad2 = torch.Tensor([gradient2])
  190. self.grads['x'] = torch.cat([grad1, grad2])
  191. class Visualization3D(animation.FuncAnimation):
  192. """ 绘制动态图像,可视化参数更新轨迹 """
  193. def __init__(self, *xy_values, z_values, labels=[], colors=[], fig, ax, interval=100, blit=True, **kwargs):
  194. """
  195. 初始化3d可视化类
  196. 输入:
  197. xy_values:三维中x,y维度的值
  198. z_values:三维中z维度的值
  199. labels:每个参数更新轨迹的标签
  200. colors:每个轨迹的颜色
  201. interval:帧之间的延迟(以毫秒为单位)
  202. blit:是否优化绘图
  203. """
  204. self.fig = fig
  205. self.ax = ax
  206. self.xy_values = xy_values
  207. self.z_values = z_values
  208. frames = max(xy_value.shape[0] for xy_value in xy_values)
  209. self.lines = [ax.plot([], [], [], label=label, color=color, lw=2)[0]
  210. for _, label, color in zip_longest(xy_values, labels, colors)]
  211. self.points = [ax.plot([], [], [], color=color, markeredgewidth=1, markeredgecolor='black', marker='o')[0]
  212. for _, color in zip_longest(xy_values, colors)]
  213. # print(self.lines)
  214. super(Visualization3D, self).__init__(fig, self.animate, init_func=self.init_animation, frames=frames,
  215. interval=interval, blit=blit, **kwargs)
  216. def init_animation(self):
  217. # 数值初始化
  218. for line in self.lines:
  219. line.set_data_3d([], [], [])
  220. for point in self.points:
  221. point.set_data_3d([], [], [])
  222. return self.points + self.lines
  223. def animate(self, i):
  224. # 将x,y,z三个数据传入,绘制三维图像
  225. for line, xy_value, z_value in zip(self.lines, self.xy_values, self.z_values):
  226. line.set_data_3d(xy_value[:i, 0], xy_value[:i, 1], z_value[:i])
  227. for point, xy_value, z_value in zip(self.points, self.xy_values, self.z_values):
  228. point.set_data_3d(xy_value[i, 0], xy_value[i, 1], z_value[i])
  229. return self.points + self.lines
  230. def train_f(model, optimizer, x_init, epoch):
  231. x = x_init
  232. all_x = []
  233. losses = []
  234. for i in range(epoch):
  235. all_x.append(copy.deepcopy(x.numpy())) # 浅拷贝 改为 深拷贝, 否则List的原值会被改变。 Edit by David 2022.12.4.
  236. loss = model(x)
  237. losses.append(loss)
  238. model.backward()
  239. optimizer.step()
  240. x = model.params['x']
  241. return torch.Tensor(np.array(all_x)), losses
  242. # 构建5个模型,分别配备不同的优化器
  243. model1 = OptimizedFunction3D()
  244. opt_gd = SimpleBatchGD(init_lr=0.05, model=model1)
  245. model2 = OptimizedFunction3D()
  246. opt_adagrad = Adagrad(init_lr=0.05, model=model2, epsilon=1e-7)
  247. model3 = OptimizedFunction3D()
  248. opt_rmsprop = RMSprop(init_lr=0.05, model=model3, beta=0.9, epsilon=1e-7)
  249. model4 = OptimizedFunction3D()
  250. opt_momentum = Momentum(init_lr=0.05, model=model4, rho=0.9)
  251. model5 = OptimizedFunction3D()
  252. opt_adam = Adam(init_lr=0.05, model=model5, beta1=0.9, beta2=0.99, epsilon=1e-7)
  253. models = [model5, model2, model3, model4, model1]
  254. opts = [opt_adam, opt_adagrad, opt_rmsprop, opt_momentum, opt_gd]
  255. x_all_opts = []
  256. z_all_opts = []
  257. # 使用不同优化器训练
  258. for model, opt in zip(models, opts):
  259. x_init = torch.FloatTensor([0.00001, 0.5])
  260. x_one_opt, z_one_opt = train_f(model, opt, x_init, 100) # epoch
  261. # 保存参数值
  262. x_all_opts.append(x_one_opt.numpy())
  263. z_all_opts.append(np.squeeze(z_one_opt))
  264. # 使用numpy.meshgrid生成x1,x2矩阵,矩阵的每一行为[-3, 3],以0.1为间隔的数值
  265. x1 = np.arange(-1, 2, 0.01)
  266. x2 = np.arange(-1, 1, 0.05)
  267. x1, x2 = np.meshgrid(x1, x2)
  268. init_x = torch.Tensor(np.array([x1, x2]))
  269. model = OptimizedFunction3D()
  270. # 绘制 f_3d函数 的 三维图像
  271. fig = plt.figure()
  272. ax = plt.axes(projection='3d')
  273. X = init_x[0].numpy()
  274. Y = init_x[1].numpy()
  275. Z = model(init_x).numpy() # 改为 model(init_x).numpy() David 2022.12.4
  276. surf = ax.plot_surface(X, Y, Z, edgecolor='grey', cmap=cm.coolwarm)
  277. # fig.colorbar(surf, shrink=0.5, aspect=1)
  278. ax.set_zlim(-3, 2)
  279. ax.set_xlabel('x1')
  280. ax.set_ylabel('x2')
  281. ax.set_zlabel('f(x1,x2)')
  282. labels = ['Adam', 'AdaGrad', 'RMSprop', 'Momentum', 'SGD']
  283. colors = ['#8B0000', '#0000FF', '#000000', '#008B00', '#FF0000']
  284. animator = Visualization3D(*x_all_opts, z_values=z_all_opts, labels=labels, colors=colors, fig=fig, ax=ax)
  285. ax.legend(loc='upper right')
  286. plt.show()

下面是我跑出来的结果,还是没有轨迹, 然后开始找原因,发现在别被打脸学长的文章中也发现了相同的问题。学长说这是深拷贝和浅拷贝的问题,我根据学长给出的线索改了改我的代码,但是没有成功。

 既然提到了深拷贝和浅拷贝顺便就查了一下资料:

浅拷贝:

        浅拷贝是会将对象的每个属性进行依次复制,但是当对象的属性值是引用类型时,实质复制的是其引用,当引用指向的值改变时也会跟着变化。
        可以使用 for in、 Object.assign、 扩展运算符 ... 、Array.prototype.slice()、Array.prototype.concat() 等

深拷贝:

        深拷贝和浅拷贝是针对复杂数据类型(对象及数组)来说的,浅拷贝只拷贝一层,而深拷贝是层层拷贝。

        深拷贝复制变量值,对于非基本类型的变量,则递归至基本类型变量后,再复制。 深拷贝后的对象与原来的对象是完全隔离的,互不影响,对一个对象的修改并不会影响另一个对象。

浅拷贝使用copy.copy()函数

深拷贝使用copy.deepcopy()函数

 只能先放一张老师的图分析各个算法的优缺点:

 

 由不同的指南针来对比不同的优化算法:

SGD:SGD就像拿着一个指南针在森林里走,每次只朝一个方向走一小步,但方向是随机的。因为每次都要看指南针,所以走得比较慢。

Adagrad:Adagrad就像有一个能快速调整方向的指南针。起初,可能会走得很快,但随着时间推移,方向调整得越来越小,走得也就慢了。因为指南针调整方向很快,所以走得比SGD快。

RMSprop:RMSprop就像有一个能记住之前方向的指南针。这样,你就不会突然大幅度改变方向,可以保持一个相对稳定的步伐。和Adagrad差不多,但更稳定。

Momentum:Momentum就像有一个可以预判的指南针。这个指南针不仅看当前的方向,还会历史方向预判下一个方向,这样就可以少做很多不必要的调整。虽然还是要看指南针,但因为预判的关系,走得比SGD和Adagrad/RMSprop都快。

Nesterov:Nesterov就像有一个超级聪明的指南针,它不仅预判方向,还会考虑到未来的方向。这样就可以少走弯路。比Momentum更快,因为它更聪明。

Adam:Adam就像你有一个超级智能的指南针,它不仅预判方向,还会记住之前的方向和步幅。这样就可以走得更稳、更快。所以走得最快。

 啊啊啊啊啊啊!!为什么我的小球出不来!!!!!

参考链接:

【23-24 秋学期】NNDL 作业13 优化算法3D可视化-CSDN博客

NNDL实验 优化算法3D轨迹 复现cs231经典动画_深度学习 优化算法 动画展示-CSDN博客

理解深拷贝和浅拷贝-CSDN博客

NNDL 实验八 网络优化与正则化(3)不同优化算法比较_逐元素平方的公式表示-CSDN博客

NNDL 作业12 优化算法2D可视化-CSDN博客

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/article/detail/38908
推荐阅读
相关标签
  

闽ICP备14008679号