Run this notebook online: or Colab:

# 11.1. 优化和深度学习¶

## 11.1.1. 优化的目标¶

%load ../utils/djl-imports

import org.apache.commons.lang3.ArrayUtils;


// Saved in Functions class for later use
public float[] callFunc(float[] x, Function<Float, Float> func) {
float[] y = new float[x.length];
for (int i = 0; i < x.length; i++) {
y[i] = func.apply(x[i]);
}
return y;
}

Function<Float, Float> f = x -> x * (float)Math.cos(Math.PI * x);

Function<Float, Float> g = x -> f.apply(x) + 0.2f * (float)Math.cos(5 * Math.PI * x);

NDManager manager = NDManager.newBaseManager();

NDArray X = manager.arange(0.5f, 1.5f, 0.01f);
float[] x = X.toFloatArray();
float[] fx = callFunc(x, f);
float[] gx = callFunc(x, g);

String[] grouping = new String[x.length * 2];
for (int i = 0; i < x.length; i++) {
grouping[i] = "Expected Risk";
grouping[i + x.length] = "Empirical Risk";
}

Table data = Table.create("Data")
StringColumn.create("grouping", grouping)
);

LinePlot.create("Risk", data, "x", "risk", "grouping");


## 11.1.2. 深度学习中的优化挑战¶

### 11.1.2.1. 局部最小值¶

(11.1.1)$f(x) = x \cdot \text{cos}(\pi x) \text{ for } -1.0 \leq x \leq 2.0,$

NDArray X = manager.arange(-1.0f, 2.0f, 0.01f);
float[] x = X.toFloatArray();
float[] fx = callFunc(x, f);

Table data = Table.create("Data")
FloatColumn.create("x", x),
FloatColumn.create("f(x)", fx)
);

LinePlot.create("x * cos(pi * x)", data, "x", "f(x)");


### 11.1.2.2. 鞍点¶

Function<Float, Float> cube = x -> x * x * x;

NDArray X = manager.arange(-2.0f, 2.0f, 0.01f);
float[] x = X.toFloatArray();
float[] fx = callFunc(x, cube);

Table data = Table.create("Data")
FloatColumn.create("x", x),
FloatColumn.create("f(x)", fx)
);

LinePlot.create("x^3", data, "x", "f(x)");


• 当函数在零梯度位置处的Hessian矩阵的特征值全部为正值时，我们有该函数的局部最小值。

• 当函数在零梯度位置处的Hessian矩阵的特征值全部为负值时，我们有该函数的局部最大值。

• 当函数在零梯度位置处的Hessian矩阵的特征值为负值和正值时，我们对函数有一个鞍点。

### 11.1.2.3. 梯度消失¶

Function<Float, Float> tanh = x -> (float)Math.tanh(x);

NDArray X = manager.arange(-2.0f, 5.0f, 0.01f);
float[] x = X.toFloatArray();
float[] fx = callFunc(x, tanh);

Table data = Table.create("Data")
FloatColumn.create("x", x),
FloatColumn.create("f(x)", fx)
);

LinePlot.create("tanh", data, "x", "f(x)");


## 11.1.3. 小结¶

• 最小化训练误差并不能保证我们找到最佳的参数集来最小化泛化误差。

• 优化问题可能有许多局部最小值。

• 问题可能有更多的鞍点，因为通常问题不是凸的。

• 梯度消失可能会导致优化停滞，重参数化通常会有所帮助。对参数进行良好的初始化也可能是有益的。

## 11.1.4. 练习¶

1. 考虑一个简单的的MLP，它有一个隐藏层，比如，隐藏层中维度为$$d$$和一个输出。证明对于任何局部最小值，至少有$$d！$$个等效方案。

2. 假设我们有一个对称随机矩阵$$\mathbf{M}$$，其中条目$$M_{ij} = M_{ji}$$各自从某种概率分布$$p_{ij}$$中抽取。此外，假设$$p_{ij}(x) = p_{ij}(-x)$$，即分布是对称的（详情请参见 [Wigner, 1958]）。

1. 证明特征值的分布也是对称的。也就是说，对于任何特征向量$$\mathbf{v}$$，关联的特征值$$\lambda$$满足$$P(\lambda > 0) = P(\lambda < 0)$$的概率为$$P(\lambda > 0) = P(\lambda < 0)$$

2. 为什么以上没有暗示$$P(\lambda > 0) = 0.5$$

3. 你能想到深度学习优化还涉及哪些其他挑战？

4. 假设你想在（真实的）鞍上平衡一个（真实的）球。

1. 为什么这很难？

2. 你也能利用这种效应来优化算法吗？