Note 5 - (深度)前馈神经网络((Deep) Feedforward Neural Networks)及相关实例
5.1 FNN的定义和动机
粗略地说,前馈神经网络(FNN)是一种特殊的函数类,在最小化任何一种预期损失方面都非常强大,但代价是要训练大量的参数。更确切地说,考虑一个输入变量 X ∈ R p \mathcal{X} \in \mathbb{R}^{p} X∈Rp 和一个函数类 F \mathcal{F} F,我们想从中找出一个函数 f f f,使某个损失函数 L L L的期望值最小。例如,考虑简单的损失函数 L ( f ( X ) ) = ∥ f ( X ) − X ∥ 2 2 L(f(\mathcal{X}))=\|f(\mathcal{X})-\mathcal{X}\|_{2}^{2} L(f(X))=∥f(X)−X∥22,用于旨在重建 X \mathcal{X} X样本的自动编码器。这里, f f f由编码器函数(映射到一个低维空间)和解码器函数(映射回原始数据空间)的连接组成。
监督学习的另一个例子是回归,我们有一个输入和输出变量的联合分布 ( X , Y ) (\mathcal{X}, \mathcal{Y}) (X,Y),目的是在 F \mathcal{F} F中找到最佳 f f f,使 L ( f ( X ) , Y ) = ∥ f ( X ) − Y ∥ 2 2 L(f(\mathcal{X}), \mathcal{Y})=\|f(\mathcal{X})-\mathcal{Y}\|_{2}^{2} L(f(X),Y)=∥f(X)−Y∥22的期望最小。我们在本节后面讨论多级分类。
如果 F \mathcal{F} F中的所有函数都可以用一组参数来描述,比如说 Θ ∈ R N \Theta\in \mathbb{R}^{N} Θ∈RN,如果给定一些训练用的样本,比如说 n n n,那么这些学习问题就会产生一个最小化过程
Θ ^ = arg min Θ ∈ R N 1 n ∑ i L ( f Θ ( x i ) ) . (5.) \hat{\Theta}=\arg \min _{\Theta \in \mathbb{R}^{N}} \frac{1}{n} \sum_{i} L\left(f_{\Theta}\left(\mathbf{x}_{i}\right)\right) . \tag{5.} Θ^=argΘ∈RNminn1i∑L(fΘ(xi)).(5.)
许多应用中非常重要的一类函数是所谓的前馈神经网络 ( F N N ) (F N N) (FNN)。前馈神经网络是线性函数 1 { }^{1} 1的串联。
φ W : R p → R m , h ↦ W h (5.) \varphi_{\mathbf{W}}: \mathbb{R}^{p} \rightarrow \mathbb{R}^{m}, \mathbf{h} \mapsto \mathbf{W h}\tag{5.} φW:Rp→Rm,h↦Wh(5.)
1 { }^{1} 1 这也包括仿射函数,因为我们可以简单地将额外的分量1附加到我们的输入向量上。
后面是所谓的激活函数,对一个向量进行分量操作。激活函数的例子有:线性整流函数(Rectified Linear Unit, ReLU)
σ ( t ) : = max { 0 , t } , (5.) \sigma(t):=\max \{0, t\},\tag{5.} σ(t):=max{
0,t},(5.)
和其他一些激活函数,见维基百科。通过对符号的轻微滥用,我们也用以下方式表示向量激活函数
σ : R m → R m , x ↦ [ σ ( x 1 ) ⋮ σ ( x m ) ] (5.) \sigma: \mathbb{R}^{m} \rightarrow \mathbb{R}^{m}, \quad \mathbf{x} \mapsto\left[\begin{array}{c} \sigma\left(x_{1}\right) \\ \vdots \\ \sigma\left(x_{m}\right) \end{array}\right]\tag{5.} σ:Rm→Rm,x↦⎣⎢⎡σ(x1)⋮σ(xm)⎦⎥⎤(5.)
一个前馈神经网络是一个函数
f : R p → R o , x ↦ σ l ∘ φ W l ∘ ⋯ ∘ σ 1 ∘ φ W 1 ( x ) , (5.) f: \mathbb{R}^{p} \rightarrow \mathbb{R}^{o}, \quad \mathbf{x} \mapsto \sigma_{l} \circ \varphi_{\mathbf{W}_{l}} \circ \cdots \circ \sigma_{1} \circ \varphi_{\mathbf{W}_{1}}(\mathbf{x}),\tag{5.} f:Rp→Ro,x↦σl∘φWl∘⋯∘σ1∘φW1(x),(5.)
其中,像往常一样, ∘ \circ ∘表示函数的连接,不同的函数类 F \mathcal{F} F由不同的激活函数、层数 l l l和矩阵的尺寸 W i ∈ R n i × m i \mathbf{W}_{i} \in \mathbb{R}^{n_{i} \times m_{i}} Wi∈Rni×mi定义。如果层数超过三层,我们通常称这样的FNN为深度前馈神经网络。注意,输出维度 o o o是由损失函数决定的,因为FNN的输出可以作为损失的输入。
5.2 训练FNNs
在实践中训练FNN本身就是一门艺术,有许多技巧和正则化技术决定了学习一个强大的FNN的失败或成功。在这一节中,我们重点讨论为一般问题(5.1)寻找最佳FNN的基本方法,即在给定的FNN类别中寻找最佳权重 Θ ^ = ( W 1 , … W L ) \hat{\Theta}=\left(\mathbf{W}_{1}, \ldots \mathbf{W}_{L}\right) Θ^=(W1,…WL)。事实上,它是一种迭代更新权重的梯度下降方法,该方法在文献中被称为反向传播(backpropagation)。在下文中,我们将描述它的工作原理。
在这里,我们在本科数学课程中需要的最重要的工具是链式法则和雅可比矩阵。回顾一下,如果 g : R k ⇒ R l g:\mathbb{R}^{k} \Rightarrow\mathbb{R}^{l} g:Rk⇒Rl 和 h : R l → R m h: \mathbb{R}^{l} \rightarrow \mathbb{R}^{m} h:Rl→Rm是两个函数, g g g在 x \mathbf{x} x处可微, h h h在 y = g ( x ) \mathbf{y}=g(\mathbf{x}) y=g(x)处可微,雅可比矩阵 J g ( x ) \mathbf{J}_{g}(\mathbf{x}) Jg(x)和 J h ( y ) \mathbf{J}_{h}(\mathbf{y}) Jh(y)。那么关于 x \mathbf{x} x的函数 h ∘ g : R k → R m h \circ g: \mathbb{R}^{k} \rightarrow \mathbb{R}^{m} h∘g:Rk→Rm在雅可比矩阵 J h ∘ g ( x ) = J h ( g ( x ) ⋅ J g ( x ) \mathbf{J}_{h\circ g}(\mathbf{x})=\mathbf{J}_{h}(g(\mathbf{x}) \cdot \mathbf{J}_{g}(\mathbf{x}) Jh∘g(x)=Jh(g(x)⋅Jg(x)处是可微的。
Examples
- (导数的线性)如果在上述介绍的背景中, h h h是一个简单的线性变换,由矩阵乘以 W \mathbf{W} W得到,那么
J W ⋅ g ( x ) = W ⋅ J g ( x ) \mathbf{J}_{\mathbf{W} \cdot g}(\mathbf{x})=\mathbf{W} \cdot \mathbf{J}_{g}(\mathbf{x}) JW⋅g(x)=W⋅Jg(x)
-
由于第 i i i次输出只取决于 x i x_{i} xi,(5.4)中 σ \sigma σ的雅可比矩阵是一个平方对角矩阵,其形式为
J σ ( x ) = [ σ ′ ( x 1 ) ⋱ σ ′ ( x m ) ] \mathbf{J}_{\sigma}(\mathbf{x})=\left[\begin{array}{lll} \sigma^{\prime}\left(x_{1}\right) & & \\ & \ddots & \\ & & \sigma^{\prime}\left(x_{m}\right) \end{array}\right] Jσ(x)=⎣⎡σ′(x1)⋱σ′(xm)⎦⎤ -
为了定义函数的雅可比矩阵,与右边的一个矢量相乘
mult ( x ) : R m × n → R m , W ↦ W x , \operatorname{mult}(\mathbf{x}): \mathbb{R}^{m \times n} \rightarrow \mathbb{R}^{m}, \quad \mathbf{W} \mapsto \mathbf{W} \mathbf{x}, mult(x):Rm×n→Rm,W↦Wx,
我们首先需要将 m n m n mn变量(这里以矩阵结构给出)嵌入 R m n \mathbb{R}^{m n} Rmn。这可以通过各种方式实现,但如果我们选择一行接一行地嵌入,即
π : W = [ w 1 ⊤ ⋮ w m ⊤ ] ↦ [ w 1 ⋮ w m ] ∈ R m n \pi: \mathbf{W}=\left[\begin{array}{c} \mathbf{w}_{1}^{\top} \\ \vdots \\ \mathbf{w}_{m}^{\top} \end{array}\right] \mapsto\left[\begin{array}{c} \mathbf{w}_{1} \\ \vdots \\ \mathbf{w}_{m} \end{array}\right] \in \mathbf{R}^{m n} π:W=⎣⎢⎡w1⊤⋮wm⊤⎦⎥⎤↦⎣⎢⎡w1⋮wm⎦⎥⎤∈Rmn
注意: π \pi π是将 m × n m \times n m×n维的矩阵映射成一个单一维度的向量,该向量的长度为 m ⋅ n m\cdot n m⋅n.
那么雅可比矩阵具有良好的排列形式
J m u l t ( x ) = [ x ⊤ ⋱ x ⊤ ] ∈ R m × m n . \mathbf{J}_{\mathrm{mult}(\mathbf{x})}=\left[\begin{array}{ccc} \mathbf{x}^{\top} & & \\ & \ddots & \\ & & \mathbf{x}^{\top} \end{array}\right] \in \mathbb{R}^{m \times m n} . Jmult(x)=⎣⎡x⊤⋱x⊤⎦⎤∈Rm×mn.
注意,由于 m u l t ( x ) \mathrm{mult}(\mathbf{x}) mult(x)的线性,雅可比矩阵不依赖于W。
为了计算成本函数(5.1)相对于权重的梯度 Θ = ( W l , … W 1 ) \Theta=\left(\mathbf{W}_{l}, \ldots \mathbf{W}_{1}\right) Θ=(Wl,…W1),我们注意到它是一个输入数据 x \mathbf{x} x的损失函数梯度的平均值,即
F ( W l , … , W 1 ) : = L ∘ σ l ∘ φ W l ∘ ⋯ ∘ σ 1 ∘ φ W 1 ( x ) . F\left(\mathbf{W}_{l}, \ldots, \mathbf{W}_{1}\right):=L \circ \sigma_{l} \circ \varphi_{\mathbf{W}_{l}} \circ \cdots \circ \sigma_{1} \circ \varphi_{\mathbf{W}_{1}}(\mathbf{x}) . F(Wl,…,W1):=L∘σl∘φWl∘⋯∘σ1∘φW1(x).
因此,只需计算取决于一个输入信号的 F F F的梯度,然后对所有训练数据 x i \mathbf{x}_{i} xi进行平均。为方便起见,我们表示为
h j : = σ j ∘ φ W j ∘ ⋯ ∘ σ 1 ∘ φ W 1 ( x ) \mathbf{h}_{j}:=\sigma_{j} \circ \varphi_{\mathbf{W}_{j}} \circ \cdots \circ \sigma_{1} \circ \varphi_{\mathbf{W}_{1}}(\mathbf{x}) hj:=σj∘φWj∘⋯∘σ1∘φW1(x)
是FNN的第 j j j层后的输出。对于 0 < j < l 0<j<l 0<j<l, h j \mathbf{h}_{j} hj被称为FNN的第 j j j隐藏层, h l \mathbf{h}_{l} hl被称为输出层, h 0 : = x \mathbf{h}_{0}:=\mathbf{x} h0:=x为FNN的输入。
我们定义函数的雅克比矩阵通过 2 ^{2} 2 ∂ ∂ W j F ∈ R 1 × m j n j \frac{\partial}{\partial \mathbf{W}_{j}} F \in \mathbb{R}^{1 \times m_{j} n_{j}} ∂Wj∂F∈R1×mjnj
W j ↦ F ( W l , … , W j , … , W 1 ) . (5.13) \mathbf{W}_{j} \mapsto F\left(\mathbf{W}_{l}, \ldots, \mathbf{W}_{j}, \ldots, \mathbf{W}_{1}\right) . \tag{5.13} Wj↦F(Wl,…,Wj,…,W1).(5.13)
2 { }^{2} 2 由于 F F F是实值的,这也是梯度的转置。
利用链式规则和上一节的例子,关于不同权重矩阵 W i \mathbf{W}_{i} Wi的导数由以下公式给出
∂ ∂ W l F = J L ( h l ) ⋅ J σ l ( W l h l − 1 ) ⋅ J m u l t ( h l − 1 ) ∂ ∂ W l − 1 F = J L ( h l ) ⋅ J σ l ( W l h l − 1 ) ⋅ W 1 ⋅ J σ l − 1 ( W l − 1 h l − 2 ) ⋅ J mult ( h l − 2 ) … ∂ ∂ W j F = J L ( h l ) ⋅ J σ l ( W l h l − 1 ) ⋅ W 1 ⋅ J σ l − 1 ( W l − 1 h l − 2 ) ⋅ J l − 1 ⋯ ⋯ J mult ( h j − 1 ) , \begin{aligned} \frac{\partial}{\partial \mathbf{W}_{l}} F &=\mathbf{J}_{L}\left(\mathbf{h}_{l}\right) \cdot \mathbf{J}_{\sigma_{l}}\left(\mathbf{W}_{l} \mathbf{h}_{l-1}\right) \cdot \mathbf{J}_{\mathbf{m u l t}\left(\mathbf{h}_{l-1}\right)} \\ \frac{\partial}{\partial \mathbf{W}_{l-1}} F &=\mathbf{J}_{L}\left(\mathbf{h}_{l}\right) \cdot \mathbf{J}_{\sigma_{l}}\left(\mathbf{W}_{l} \mathbf{h}_{l-1}\right) \cdot \mathbf{W}_{1} \cdot \mathbf{J}_{\sigma_{l-1}}\left(\mathbf{W}_{l-1} \mathbf{h}_{l-2}\right) \cdot \mathbf{J}_{\text {mult }\left(\mathbf{h}_{l-2}\right)} \\ \quad &\ldots \\ \frac{\partial}{\partial \mathbf{W}_{j}} F&=\mathbf{J}_{L}\left(\mathbf{h}_{l}\right) \cdot \mathbf{J}_{\sigma_{l}}\left(\mathbf{W}_{l} \mathbf{h}_{l-1}\right) \cdot \mathbf{W}_{1} \cdot \mathbf{J}_{\sigma_{l-1}}\left(\mathbf{W}_{l-1} \mathbf{h}_{l-2}\right) \cdot \mathbf{J}_{l-1} \cdots \cdots \mathbf{J}_{\text {mult }\left(\mathbf{h}_{j-1}\right)}, \end{aligned} ∂Wl∂F∂Wl−1∂F∂Wj∂F=JL(hl)⋅Jσl(Wlhl−1)⋅Jmult(hl−1)=JL(hl)⋅Jσl(Wlhl−1)⋅W1⋅Jσl−1(Wl−1hl−2)⋅Jmult (hl−2)…=JL(hl)⋅Jσl(Wlhl−1)⋅W1⋅Jσl−1(Wl−1hl−2)⋅Jl−1⋯⋯Jmult (hj−1),
在实践中,初始权重通常从正态分布中随机选择,然后用上述梯度和步长 α > 0 \alpha>0 α>0单独更新。选择步长的算法和方法已经超出了本讲座的范围。注意,我们必须 "重塑(reshape) "梯度(即 ∂ ∂ W i F \frac{\partial}{\partial \mathbf{W}_{i}} F ∂Wi∂F的转置)成矩阵形式通过将(5.9)中的矩阵嵌入 π j \pi_{j} πj进行倒置。我们最后得到了更新规则
W j ← W j − α π j − 1 ( ∂ ∂ W j F ) ⊤ . (5.14) \mathbf{W}_{j} \leftarrow \mathbf{W}_{j}-\alpha \pi_{j}^{-1}\left(\frac{\partial}{\partial \mathbf{W}_{j}} F\right)^{\top} . \tag{5.14} Wj←Wj−απj−1(∂Wj∂F)⊤.(5.14)
5.3 用FNNs进行多类分类
多类分类考虑的问题是将输入的 X ∈ R p \mathcal{X}\in \mathbb{R}^{p} X∈Rp分配给多个(比如 C C C)类中的一个。我们通过随机变量 ( X , Y ) (\mathcal{X}, \mathcal{Y}) (X,Y)对该问题进行建模,其中 X ∈ R p \mathcal{X} \in\mathbb{R}^{p} X∈Rp和 Y ∈ { e 1 , … , e C } \mathcal{Y} \in\left\{\mathbf{e}_{1}, \ldots, \mathbf{e}_{C}\right\} Y∈{ e1,…,eC}是 R C \mathbb{R}^{C} RC中的 C C C标准基向量之一。一个实现 y = e c \mathbf{y}=\mathbf{e}_{c} y=ec意味着属于 c c c类的事件是真的。这种对输出变量的建模也被称为独热码(one-hot-encoding)。
用FNN进行多类分类的思路是: X \mathcal{X} X作为网络的输入,输出是 R C \mathbb{R}^{C} RC中的一个向量,应该反映给定 X \mathcal{X} X的类分布的概率。更确切地说,如果 x \mathbf{x} x是 X \mathcal{X} X的实现,如果 f f f表示FNN,那么输出向量 h l : = f ( x ) \mathbf{h}_{l}:=f(\mathbf{x}) hl:=f(x)的第 c c c分量应该是 Y \mathcal{Y} Y属于 c c c类的概率,给定 x \mathrm{x} x,即
h l ≈ [ Pr ( Y = e 1 ∣ X = x ) ⋮ Pr ( Y = e C ∣ X = x ) ] \mathbf{h}_{l} \approx\left[\begin{array}{c} \operatorname{Pr}\left(\mathcal{Y}=\mathbf{e}_{1} \mid \mathcal{X}=\mathbf{x}\right) \\ \vdots \\ \operatorname{Pr}\left(\mathcal{Y}=\mathbf{e}_{C} \mid \mathcal{X}=\mathbf{x}\right) \end{array}\right] hl≈⎣⎢⎡Pr(Y=e1∣X=x)⋮Pr(Y=eC∣X=x)⎦⎥⎤
因此,最后一个激活函数 σ l \sigma_{l} σl的动机是为 C C C类输出一个概率分布,实际上意味着输出向量的条目在0和1之间,并且它们加起来是1。这里一个突出的选择是softmax函数,由以下公式给出
σ : R C → R C , [ a 1 ⋮ a C ] ↦ 1 ∑ c exp a c [ exp a 1 ⋮ exp a C ] \sigma: \mathbb{R}^{C} \rightarrow \mathbb{R}^{C}, \quad\left[\begin{array}{c} a_{1} \\ \vdots \\ a_{C} \end{array}\right] \mapsto \frac{1}{\sum_{c} \exp a_{c}}\left[\begin{array}{c} \exp a_{1} \\ \vdots \\ \exp a_{C} \end{array}\right] σ:RC→RC,⎣⎢⎡a1⋮aC⎦⎥⎤↦∑cexpac1⎣⎢⎡expa1⋮expaC⎦⎥⎤
练习:计算softmax函数的Jacobi-Matrix
我们训练网络所需要的损失函数必须衡量预测的分布与通过我们的训练集观察到的分布的对应程度 ( x i , y i ) , i = 1 , … , n \left(\mathbf{x}_{i}, \mathbf{y}_{i}\right), i=1, \ldots, n (xi,yi),i=1,…,n。注意,这些观察到的分布是确定的,也就是说,如果 x i \mathbf{x}_{i} xi被标记为 c c c或0类,那么 y c : = Pr ( Y = e c ∣ X = x i ) = 1 y_{c}:=\operatorname{Pr}\left(\mathcal{Y}=\mathbf{e}_{c} \mid \mathcal{X}=\mathbf{x}_{i}\right)=1 yc:=Pr(Y=ec∣X=xi)=1。一般来说,比较两个概率分布 P = ( p 1 , … p C ) \mathbb{P}=\left(p_{1}, \ldots p_{C}\right) P=(p1,…pC)和 Q = ( q 1 , … q C ) \mathbb{Q}=\left(q_{1}, \ldots q_{C}\right) Q=(q1,…qC)在同一基础的 C C C事件集合的一种常见方法是使用交叉熵,见维基百科。
H ( P , Q ) = − ∑ c = 1 C p c log q c . H(\mathbb{P}, \mathbb{Q})=-\sum_{c=1}^{C} p_{c} \log q_{c} . H(P,Q)=−c=1∑Cpclogqc.
在我们的案例中,有一个分布是确定性的,这可以简化为损失函数
L ( f ( X ) , y c ) = − log f ( X ) c L\left(f(\mathcal{X}), \mathbf{y}_{c}\right)=-\log f(\mathcal{X})_{c} L(f(X),yc)=−logf(X)c
其中 f f f是一个以softmax为输出的FNN, f ( X ) c f(\mathcal{X})_{c} f(X)c表示其 c c c的条目。对于训练,像往常一样,我们使用训练数据上的损失的经验期望值,这导致了优化问题
( W ^ l , … , W ^ 1 ) = arg min ( W l , … , W 1 ) { − 1 n ∑ i log f ( W l , … , W 1 ) ( x i ) c i } \left(\hat{\mathbf{W}}_{l}, \ldots, \hat{\mathbf{W}}_{1}\right)=\arg \min _{\left(\mathbf{W}_{l}, \ldots, \mathbf{W}_{1}\right)}\left\{-\frac{1}{n} \sum_{i} \log f_{\left(\mathbf{W}_{l, \ldots}, \mathbf{W}_{1}\right)}\left(\mathbf{x}_{i}\right)_{c_{i}}\right\} (W^l,…,W^1)=arg(Wl,…,W1)min{
−n1i∑logf(Wl,…,W1)(xi)ci}
5.4 CVXOPT 实例
机器学习任务通常被认为是优化问题,例如,最小化误差函数或最大化概率。理想情况下,优化问题是凸的,这意味着任何局部最小值都是配方的全局最小值。假设已经有一些关于凸优化的基本知识。这个任务的目的是让我们熟悉CVXOPT,这是一个使用最广泛的凸优化工具箱。注意:如果CVXOPT不接受NumPy数组,请尝试将其转换为double
。
- 进入cvxopt.org,按照发行版本的安装说明进行安装。对于conda,需要运行
conda install -c conda-forge crxopt
- 浏览cvxopt.org上的例子部分,了解CVXOPT不同求解器的功能概况。
- 实现一个函数
minsq
,它输入一个形状为(m, n)
的NumPy数组A,和一个形状为(m,)
的NumPy数组y作为参数,并返回一个形状为(n,)
的NumPy数组 x x x,解决以下问题。
min x ∥ A x − y ∥ \min _{\mathbf{x}}\| \mathbf{A x}-\mathbf{y}\| xmin∥Ax−y∥
用适当的输入来测试函数,并将结果与使用np.linalg.pinv
得到的结果进行比较。通过向y添加白高斯噪声来进行实验。
5.4.1 CVXOPT 简介
5.4.1.1 创建矩阵
CVXOPT 具有分离的密集和稀疏矩阵对象。此示例说明了创建密集和稀疏矩阵的不同方法。
使用该matrix()
函数创建一个密集矩阵;它可以从列表(或迭代器)创建:
>>> from cvxopt import matrix
>>> A = matrix([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], (2,3))
>>> print(A)
[ 1.00e+00 3.00e+00 5.00e+00]
[ 2.00e+00 4.00e+00 6.00e+00]
>>> A.size
(2, 3)
或来自列表列表,其中每个内部列表表示矩阵的一列:
>>> B = matrix([ [1.0, 2.0], [3.0, 4.0] ])
>>> print(B)
[ 1.00e+00 3.00e+00]
[ 2.00e+00 4.00e+00]
更广泛地说,内部列表可以代表块状列。
print(matrix([ [A] ,[B] ]))
[ 1.00e+00 3.00e+00 5.00e+00 1.00e+00 3.00e+00]
[ 2.00e+00 4.00e+00 6.00e+00 2.00e+00 4.00e+00]
更多的,参考文档。
5.4.1.2 矩阵索引
索引稠密矩阵和稀疏矩阵有两种方法:单参数索引和双参数索引。在双参数索引中,使用两个索引集I和J对矩阵进行索引 。
>>> from cvxopt import matrix
>>> A = matrix(range(16),(4,4))
>>> print(A)
[ 0 4 8 12]
[ 1 5 9 13]
[ 2 6 10 14]
[ 3 7 11 15]
>>> print(A[[0,1,2,3],[0,2]])
[ 0 8]
[ 1 9]
[ 2 10]
[ 3 11]
索引集可以是整数、列表、整数矩阵或切片。
>>> print(A[1,:])
[ 1 5 9 13]
>>> print(A[::-1,::-1])
[ 15 11 7 3]
[ 14 10 6 2]
[ 13 9 5 1]
[ 12 8 4 0]
在单参数索引中,通过按列优先顺序考虑矩阵(即,通过从左到右堆叠列)以向量形式对矩阵进行索引。
>>> A[::5] = -1
>>> print(A)
[ -1 4 8 12]
[ 1 -1 9 13]
[ 2 6 -1 14]
[ 3 7 11 -1]
这对于访问不是子矩阵的矩阵部分非常有用,例如,矩阵的对角线部分。
5.4.1.3 求解线性规划
可以通过该solvers.lp()
函数指定线性程序。举个例子,我们可以解决这个问题
minimize 2 x 1 + x 2 subject to − x 1 + x 2 ≤ 1 x 1 + x 2 ≥ 2 x 2 ≥ 0 x 1 − 2 x 2 ≤ 4 \begin{array}{ll} \text{minimize} & 2x_1 + x_2 \\ \text{subject to} & -x_1 + x_2 \leq 1 \\ & x_1 + x_2 \geq 2 \\ & x_2 \geq 0 \\ & x_1 -2x_2 \leq 4 \end{array} minimizesubject to2x1+x2−x1+x2≤1x1+x2≥2x2≥0x1−2x2≤4
如下:
>>> from cvxopt import matrix, solvers
>>> A = matrix([ [-1.0, -1.0, 0.0, 1.0], [1.0, -1.0, -1.0, -2.0] ]) # the factors of the bounds
>>> b = matrix([ 1.0, -2.0, 0.0, 4.0 ]) # constants
>>> c = matrix([ 2.0, 1.0 ]) # minimized function
>>> sol=solvers.lp(c,A,b)
pcost dcost gap pres dres k/t
0: 2.6471e+00 -7.0588e-01 2e+01 8e-01 2e+00 1e+00
1: 3.0726e+00 2.8437e+00 1e+00 1e-01 2e-01 3e-01
2: 2.4891e+00 2.4808e+00 1e-01 1e-02 2e-02 5e-02
3: 2.4999e+00 2.4998e+00 1e-03 1e-04 2e-04 5e-04
4: 2.5000e+00 2.5000e+00 1e-05 1e-06 2e-06 5e-06
5: 2.5000e+00 2.5000e+00 1e-07 1e-08 2e-08 5e-08
>>> print(sol['x'])
[ 5.00e-01]
[ 1.50e+00]
5.4.1.4 求解二次规划
二次规划可以通过该solvers.qp()
函数求解。例如,我们可以解决 QP
minimize 2 x 1 2 + x 2 2 + x 1 x 2 + x 1 + x 2 subject to x 1 ≥ 0 x 2 ≥ 0 x 1 + x 2 = 1 \begin{array}{ll} \text{minimize} & 2x_1^2 + x_2^2 + x_1 x_2 + x_1 + x_2 \\ \text{subject to} & x_1 \geq 0 \\ & x_2 \geq 0 \\ & x_1 + x_2 = 1 \end{array} minimizesubject to2x12+x22+x1x2+x1+x2x1≥0x2≥0x1+x2=1
如下:
>>> from cvxopt import matrix, solvers
>>> Q = 2*matrix([ [2, .5], [.5, 1] ])
>>> p = matrix([1.0, 1.0])
>>> G = matrix([[-1.0,0.0],[0.0,-1.0]])
>>> h = matrix([0.0,0.0])
>>> A = matrix([1.0, 1.0], (1,2))
>>> b = matrix(1.0)
>>> sol=solvers.qp(Q, p, G, h, A, b)
pcost dcost gap pres dres
0: 0.0000e+00 0.0000e+00 3e+00 1e+00 0e+00
1: 9.9743e-01 1.4372e+00 5e-01 4e-01 3e-16
2: 1.8062e+00 1.8319e+00 5e-02 4e-02 5e-16
3: 1.8704e+00 1.8693e+00 6e-03 2e-03 1e-15
4: 1.8749e+00 1.8748e+00 2e-04 6e-05 6e-16
5: 1.8750e+00 1.8750e+00 2e-06 6e-07 7e-16
6: 1.8750e+00 1.8750e+00 2e-08 6e-09 1e-15
>>> print(sol['x'])
[ 2.50e-01]
[ 7.50e-01]
5.4.2 实例的解决方法
实现一个函数minsq
,它输入一个形状为(m, n)
的NumPy数组A,和一个形状为(m,)
的NumPy数组y作为参数,并返回一个形状为(n,)
的NumPy数组 x x x,解决以下问题。
min x ∥ A x − y ∥ \min _{\mathbf{x}}\| \mathbf{A x}-\mathbf{y}\| xmin∥Ax−y∥
用适当的输入来测试函数,并将结果与使用np.linalg.pinv
得到的结果进行比较。通过向y添加白高斯噪声来进行实验。
from cvxopt import matrix, solvers
import numpy as np
def minsq(A, y):
P=matrix(np.dot(A.T,A).astype('double'))
q=matrix(-np.dot(A.T,y).astype('double'))
x=solvers.qp(P,q)
return np.array(x['x'])
A=np.array([[10, 40],[20, 0],[-30, 40]])
y=np.array([50,20,10])+np.random.randn(3,)
print('A:', A)
print('y:', y)
print('x:', minsq(A,y).squeeze())
print('np.dot(pinv(A),y):', np.dot(np.linalg.pinv(A),y))
结果如下
A: [[ 10 40]
[ 20 0]
[-30 40]]
y: [49.88665691 19.21406554 9.38923507]
x: [0.99519146 0.98974651]
np.dot(pinv(A),y): [0.99519146 0.98974651]