DL中常用的三种K-Lipschitz技术
文章目录
- Lipschitz continuity
- Weight clipping
- Gradient penalty
- Spectral Normalization
- 理论推导
- Power iteration
- Tensorflow 实现
在进入到正题前,首先来了解下什么是 K-Lipschitz 以及它在 DL 中能起到什么作用
Lipschitz continuity
利普希茨连续。满足如下性质的任意连续函数 fff 称为 K-Lipschitz:
∥f(x1)−f(x2)∥≤K∥x1−x2∥,∀x1,x2∈domf\| f(x_1) - f(x_2) \| \leq K \| x_1 - x_2 \|,\ \forall x_1,x_2 \in \text{dom}f ∥f(x1)−f(x2)∥≤K∥x1−x2∥, ∀x1,x2∈domf
这里的 ∥⋅∥\|\cdot\|∥⋅∥ 常用2-范。直观上看,Lipschitz 条件限制了函数变化的剧烈程度。在DL中,由于 Lipschitz continous 的函数的梯度上界被限制,因此函数会更平滑。因此利用梯度下降进行参数更新时,参数的变化不会太大/剧烈从而降低梯度爆炸的发生概率,使模型的更新更稳定。KKK 称为 Lipschitz constant。
那么在 DL 中,有哪些方法可用于将 fff 限制在 K-Lipschitz 空间中?这里介绍三种:weight clipping、gradient penality、spectral normalization,一般而言,第三种的效果最佳
Weight clipping
由 Wasserstein GAN 提出。
在利用 gradient descent 进行参数更新后,在对所有参数进行如下操作:
w={c,if w>c−c,if w<−cw,otherwisew=\begin{cases} c, & \text{if } w > c \\ -c, & \text{if } w < -c \\ w, & \text{otherwise} \end{cases} w=⎩⎪⎨⎪⎧c,−c,w,if w>cif w<−cotherwise
其中 ccc 是人为设定的阈值。注意,Weight cplipping 并无法保证 fff 位于 1-Lipschitz,而只能保证其是 K-Lipschitz的(K具体无法确定)
Gradient penalty
由 Improved Training of Wasserstein GANs 提出。
理论支持:一个可微函数 fff 是 1-Lipschitz 当且仅当它对所有的输入 xxx 均满足 ∥∇xf(x)∥≤1\| \nabla_x f(x) \| \leq 1∥∇xf(x)∥≤1,即,
f∈1-Lipschitz  ⟺  ∥∇xf(x)∥≤1,∀x∈domff \in \text{1-Lipschitz} \iff \| \nabla_x f(x) \| \leq 1, \forall x \in \text{dom}f f∈1-Lipschitz⟺∥∇xf(x)∥≤1,∀x∈domf
在具体实现时,即在 Objective function 中添加如下正则项:
minθ{L(x,θ)+λmax(0,∥∇xf(x)−1)∥}\min_{\theta} \{ \mathcal{L}(x, \theta) + \lambda \color{#F00}{\max(0, \| \nabla_x f(x) - 1) \| } \} θmin{L(x,θ)+λmax(0,∥∇xf(x)−1)∥}
公式中的 L\mathcal LL 即为 Loss/Objective function,而 fff 为 Score function。注意,优化该目标函数后,所解出的 fff 并无法保证一定满足 ∥∇xf(x)∥≤1\| \nabla_x f(x) \| \leq 1∥∇xf(x)∥≤1,但 fff 会偏向具有该属性
Spectral Normalization
谱归一化,由SN-GAN提出,是目前三种方法中效果最优的方法。
下面简要介绍其非严格的理论推导,主要来自知乎,再添加上自己的一些理解
理论推导
对于复合函数,存在如下定理:
∥f∘g∥Lip≤∥f∥Lip⋅∥g∥Lip\|f \circ g\|_{Lip} \leq \| f \|_{Lip} \cdot \| g \|_{Lip} ∥f∘g∥Lip≤∥f∥Lip⋅∥g∥Lip
neutral network 正是由多个复合函数嵌套而成,最常见的嵌套方式如下:f(g(f(g(⋯ ))))f(g(f(g(\cdots))))f(g(f(g(⋯)))),其中 f 表示激活函数,ggg 表示卷积操作(以CNN为例)。而 fff 常选取 LeakyRelu,Relu,Sigmoid,Tanh,而它们均为 1-Lipschitz。因此 ∥f∘g∥Lip≤∥f∥Lip⋅∥g∥Lip=∥g∥Lip\|f \circ g\|_{Lip} \leq \| f \|_{Lip} \cdot \| g \|_{Lip}=\| g \|_{Lip}∥f∘g∥Lip≤∥f∥Lip⋅∥g∥Lip=∥g∥Lip,故要使得复合函数 f∘gf \circ gf∘g 为 1-Lipschitz,即需保证卷积操作 ggg 是 1-Lipschitz,就可以保证整个网络都是 1-Lipschitz continous 的。
在图像上每个位置的卷积操作,正好就是做如下“局部区域“的变换:
∥unfoldraw(M)⋅unfoldcol(x)∥=y\| \text{unfold}_{raw}(M) \cdot \text{unfold}_{col}(x) \| = y ∥unfoldraw(M)⋅unfoldcol(x)∥=y
其中 x∈Rf×fx \in R^{f×f}x∈Rf×f 为 local receptive field,M∈Rf×fM \in R^{f×f}M∈Rf×f 为卷积核,yyy 为对应位置的卷积输出,unfoldraw(⋅)\text{unfold}_{raw}(\cdot)unfoldraw(⋅) 将 ⋅\cdot⋅ 按行展开成行向量,unfoldcol(⋅)\text{unfold}_{col}(\cdot)unfoldcol(⋅) 将 ⋅\cdot⋅ 按列展开成列向量。因此,只需保证 unfoldraw(M)\text{unfold}_{raw}(M)unfoldraw(M) 是 1-Lipschitz,就可以使得整个 network 是 1-Lipschitz。
对任意矩阵 AAA (unfoldraw(M)\text{unfold}_{raw}(M)unfoldraw(M) 是 AAA 的一个具例),存在如下定理:
(1)A∈K-Lipschitz,∀A:Rn→Rm/∀A∈Rm×n  ⟺  ∥Ax→∥≤K∥x→∥,∀x→∈Rn  ⟺  ⟨Ax→,Ax→⟩≤K2⟨x→,x→⟩  ⟺  x→T(ATA−K2I)x→≤0  ⟺  ⟨(ATA−K2I)x→,x→⟩≤0\begin{array}{ll} & A \in \text{K-Lipschitz}, \forall A: R^n \to R^m / \forall A \in R^{m×n} \\[.4em] \iff& \| A \overrightarrow{x} \| \leq K \| \overrightarrow{x} \|, \forall \overrightarrow{x} \in R^n \\[.4em] \iff& \langle A \overrightarrow{x}, A \overrightarrow{x} \rangle \leq K^2 \langle \overrightarrow{x}, \overrightarrow{x} \rangle \\[.4em] \iff& \overrightarrow{x}^T (A^TA - K^2I)\overrightarrow{x} \leq 0 \\[.4em] \iff& \langle (A^TA - K^2I) \overrightarrow{x}, \overrightarrow{x} \rangle \leq 0 \end{array} \tag{1} ⟺⟺⟺⟺A∈K-Lipschitz,∀A:Rn→Rm/∀A∈Rm×n∥Ax∥≤K∥x∥,∀x∈Rn⟨Ax,Ax⟩≤K2⟨x,x⟩xT(ATA−K2I)x≤0⟨(ATA−K2I)x,x⟩≤0(1)
因 ATAA^TAATA 为实对称矩阵,故不同特征值对应的特征向量两两正交,又因 ATAA^TAATA 为半正定阵,故其所有特征值非负。不妨假设 ATA∈Rn×nA^TA \in R^{n×n}ATA∈Rn×n 的特征向量为 vi→for i=1,2,⋯ ,n\overrightarrow{v_i}\ \text{for}\ i=1,2,\cdots,nvi for i=1,2,⋯,n,各自对应的特征值为 λifor i=1,2,⋯ ,n\lambda_i\ \text{for}\ i=1,2,\cdots,nλi for i=1,2,⋯,n。因为 v→i\overrightarrow{v}_ivi 两两互相正交(不严谨,因为不一定有 nnn 个),不妨令 vi→\overrightarrow{v_i}vi 已经单位化,则它们构成 RnR^nRn 空间的一组单位正交基。因此 x→=∑i=1nxivi→,for ∀x∈Rn\overrightarrow{x} = \sum_{i=1}^n x_i \overrightarrow{v_i}, \text{ for } \forall x \in R^nx=∑i=1nxivi, for ∀x∈Rn,则续 (1):
(2)⟨(ATA−K2I)x→,x→⟩≤0  ⟺  ⟨(ATA−K2I)∑i=1nxivi→,∑i=1nxivi→⟩≤0  ⟺  ∑i=1n∑j=1nxixj⟨(ATA−K2I)vi→,vj→⟩≤0  ⟺  ∑i=1n∑j=1nxixj[(ATA−K2I)vi→]Tvj→≤0\begin{array}{ll} & \langle (A^TA - K^2I) \overrightarrow{x}, \overrightarrow{x} \rangle \leq 0 \\[.4em] \iff& \langle (A^TA - K^2I) \sum_{i=1}^n x_i \overrightarrow{v_i}, \sum_{i=1}^n x_i \overrightarrow{v_i} \rangle \leq 0 \\[.4em] \iff& \sum_{i=1}^n\sum_{j=1}^n x_i x_j \langle (A^TA - K^2I) \overrightarrow{v_i}, \overrightarrow{v_j} \rangle \leq 0 \\[.4em] \iff& \sum_{i=1}^n\sum_{j=1}^n x_i x_j \left[(A^TA-K^2I) \overrightarrow{v_i}\right]^T \overrightarrow{v_j} \leq 0 \end{array} \tag{2} ⟺⟺⟺⟨(ATA−K2I)x,x⟩≤0⟨(ATA−K2I)∑i=1nxivi,∑i=1nxivi⟩≤0∑i=1n∑j=1nxixj⟨(ATA−K2I)vi,vj⟩≤0∑i=1n∑j=1nxixj[(ATA−K2I)vi]Tvj≤0(2)
又
[(ATA−K2I)vi→]Tvj→=vi→T(ATA−K2I)vj→=vi→TATAvj→−K2vi→Tvj→={0,if i≠j(λi−K2)⟨vi→,vi→⟩=λi−K2,if i=j\begin{array}{l} \left[(A^TA-K^2I) \overrightarrow{v_i}\right]^T \overrightarrow{v_j} = \overrightarrow{v_i}^T (A^TA-K^2I)\overrightarrow{v_j} = \overrightarrow{v_i}^T A^TA \overrightarrow{v_j} - K^2 \overrightarrow{v_i}^T \overrightarrow{v_j} \\[.4em] =\begin{cases} 0, &\text{if } i =\not j \\ (\lambda_i - K^2) \langle \overrightarrow{v_i}, \overrightarrow{v_i} \rangle = \lambda_i - K^2, &\text{if } i = j \end{cases} \end{array} [(ATA−K2I)vi]Tvj=viT(ATA−K2I)vj=viTATAvj−K2viTvj={0,(λi−K2)⟨vi,vi⟩=λi−K2,if i≠jif i=j
故续 (2)
∑i=1n∑j=1nxixj[(ATA−K2I)vi→]Tvj→≤0  ⟺  ∑i=1nxi2(λi−K2)≤0\sum_{i=1}^n\sum_{j=1}^n x_i x_j \left[(A^TA-K^2I) \overrightarrow{v_i}\right]^T \overrightarrow{v_j} \leq 0 \iff \sum_{i=1}^n x_i^2 (\lambda_i - K^2) \leq 0 i=1∑nj=1∑nxixj[(ATA−K2I)vi]Tvj≤0⟺i=1∑nxi2(λi−K2)≤0
即
(3)A∈K-Lipschitz,∀A:Rn→Rm/∀A∈Rm×n  ⟺  ∑i=1nxi2(K2−λi)≥0A \in \text{K-Lipschitz}, \forall A: R^n \to R^m / \forall A \in R^{m×n} \iff \sum_{i=1}^n x_i^2 (K^2 - \lambda_i) \geq 0 \tag{3} A∈K-Lipschitz,∀A:Rn→Rm/∀A∈Rm×n⟺i=1∑nxi2(K2−λi)≥0(3)
其中 λi\lambda_iλi 为 ATAA^TAATA 的第 iii 个特征值。
不妨令 K2=maxi(λi)\color{#F00}{K^2 = \max_i(\lambda_i)}K2=maxi(λi),则必有 ∑i=1nxi2(K2−λi)≥0\sum_{i=1}^n x_i^2 (K^2 - \lambda_i) \geq 0∑i=1nxi2(K2−λi)≥0 成立,因此:
(4)K2=maxi(λi)⇒(∑i=1nxi2(K2−λi)≥0  ⟺  A∈K-Lipschitz,∀A:Rn→Rm/∀A∈Rm×n)\color{#F00}{K^2 = \max_i(\lambda_i) \Rightarrow \left( \sum_{i=1}^n x_i^2 (K^2 - \lambda_i) \geq 0 \iff A \in \text{K-Lipschitz}, \forall A: R^n \to R^m / \forall A \in R^{m×n} \right)} \tag{4} K2=imax(λi)⇒(i=1∑nxi2(K2−λi)≥0⟺A∈K-Lipschitz,∀A:Rn→Rm/∀A∈Rm×n)(4)
而要令 AAA 从 K-Lipschitz 变为 1-Lipschitz,仅需对 AAA 作如下缩放即可:A:=AKA := \displaystyle\frac{A}{K}A:=KA。即,矩阵 A 除以它的 spectral norm(∥A∥2=ATA的最大特征值)可以使其具有1-Lipschitz continuity\color{#F00}{\text{矩阵 A 除以它的 spectral norm}(\|A\|_2 = \sqrt{A^TA的最大特征值})\text{可以使其具有1-Lipschitz continuity}}矩阵 A 除以它的 spectral norm(∥A∥2=ATA的最大特征值)可以使其具有1-Lipschitz continuity。
于是问题的关键就转变成如何求解 ATAA^TAATA 的最大特征值 λ1\lambda_1λ1 了(不妨令 λ1≥λ2≥⋯≥λn\lambda_1 \geq \lambda_2 \geq \cdots \geq \lambda_nλ1≥λ2≥⋯≥λn),最经典的算法为 Power iteration
Power iteration
Power iteration 是用于近似计算方阵最大特征值和其对应特征向量的常用方法,其具体步骤如下:
- 令 B=ATA∈Rn×n\color{#F00}{B = A^TA \in R^{n×n}}B=ATA∈Rn×n ,假设 BBB 是一个 n×nn×nn×n 的满秩方阵,其单位特征向量为 v1→,v2→,⋯ ,vn→∈Rn\overrightarrow{v_1},\overrightarrow{v_2},\cdots,\overrightarrow{v_n} \in R^nv1,v2,⋯,vn∈Rn,对应特征值为 λ1→,λ2→,⋯ ,λn→\overrightarrow{\lambda_1},\overrightarrow{\lambda_2},\cdots,\overrightarrow{\lambda_n}λ1,λ2,⋯,λn(因 BBB 实对称,故 v1→,⋯ ,vn→\overrightarrow{v_1},\cdots,\overrightarrow{v_n}v1,⋯,vn相互正交)。那么对任意向量 x→∈Rn\overrightarrow{x} \in R^nx∈Rn 均可写成 x→=∑i=1nxivi→\overrightarrow{x} = \sum_{i=1}^n x_i \overrightarrow{v_i}x=∑i=1nxivi,有:
Bx→=B∑i=1nxivi→=∑i=1nxiλivi→\begin{array}{lll} B \overrightarrow{x} &=& B \sum_{i=1}^n x_i \overrightarrow{v_i} \\[.4em] &=& \sum_{i=1}^n x_i \lambda_i \overrightarrow{v_i} \end{array} Bx==B∑i=1nxivi∑i=1nxiλivi
经过 kkk 次迭代后:
(5)Bkx→=∑i=1nxiλikvi→=λ1kx1v1→+∑i=2nxi(λiλ1)kvi→B^k\overrightarrow{x} = \sum_{i=1}^n x_i \lambda_i^k \overrightarrow{v_i} = \lambda_1^k x_1 \overrightarrow{v_1} + \sum_{i=2}^n x_i \left(\frac{\lambda_i}{\lambda_1}\right)^k \overrightarrow{v_i} \tag{5} Bkx=i=1∑nxiλikvi=λ1kx1v1+i=2∑nxi(λ1λi)kvi(5)
不妨假定 λ1>λ2>⋯>λn\lambda_1 > \lambda_2 > \cdots > \lambda_nλ1>λ2>⋯>λn(不考虑特征值相等的情况,因为这在实际中很少见),因此,limk→∞(λiλ1)k=0\displaystyle\lim_{k \to \infty} \left(\frac{\lambda_i}{\lambda_1}\right)^k = 0k→∞lim(λ1λi)k=0,故式 (5) 可进一步化为:
(6)Bkx→≈λ1kx1v1→B^k\overrightarrow{x} \approx \lambda_1^k x_1 \overrightarrow{v_1} \tag{6} Bkx≈λ1kx1v1(6)
即经过 kkk 次迭代后,我们将得到特征向量 v1→\overrightarrow{v_1}v1 的线性缩放,只要将 Bkx→B^k \overrightarrow{x}Bkx 归一化就可得到主特征向量 v1→\overrightarrow{v_1}v1,进而再利用 Bv1→=λ1v1→B \overrightarrow{v_1} = \lambda_1 \overrightarrow{v_1}Bv1=λ1v1 解得 λ1\lambda_1λ1。
上述为 Power iteration 的理论部分,而伪代码如下:
u, v = 随机初始化, None
for k iteration:v = A^T u / |A^T u|_2 # (1)u = A v / |A v|_2 # (2)
sqrt_lambda_1 = u^T A v # (3)
其中 A:Rn→Rm/A∈Rm×nA: R^n \to R^m / A \in R^{m×n}A:Rn→Rm/A∈Rm×n,v∈Rn,u∈Rmv \in R^n, u \in R^mv∈Rn,u∈Rm,其中 n,mn,mn,m 分别属于输入,输出空间的维度
伪代码中的 (1) 等价于公式 (6) 的原因:
v→=ATu→∥ATu→∥2=ATAv→∥Av→∥2/∥ATu→∥2=αi(ATA)v→=αiBv→\displaystyle\overrightarrow{v} = \frac{A^T \overrightarrow{u}}{\|A^T \overrightarrow{u}\|_2} = A^T \frac{A\overrightarrow{v}}{\| A\overrightarrow{v} \|_2} /\left\| A^T \overrightarrow{u} \right\|_2 = \alpha_i (A^TA)\overrightarrow{v} = \alpha_i B \overrightarrow{v}v=∥ATu∥2ATu=AT∥Av∥2Av/∥∥∥ATu∥∥∥2=αi(ATA)v=αiBv,该公式在迭代了 kkk 次后,与上面的式 (6) 仅多乘了一个常数系数 α=∏i=1kαi\alpha=\prod_{i=1}^k \alpha_iα=∏i=1kαi,这并不影响主特征向量 v1→\overrightarrow{v_1}v1 的方向,因此对 v→\overrightarrow{v}v 归一化后即可得到 v1→\overrightarrow{v_1}v1。而在实际上,在每步迭代后,都会对 v→\overrightarrow{v}v 进行归一化,因此 v1→=v→\overrightarrow{v_1}=\overrightarrow{v}v1=v
伪代码中的 (3) 可求解 λ1\lambda_1λ1 的原因:
∵ATAv→=λ1v→,且∥v∥2=1∴v→TATAv→=λ1v→Tv→=λ1即λ1=∥Av→∥2又u→=Av→∥Av→∥2→u→Tu→=u→TAv→∥Av→∥2→1=u→TAv→∥Av→∥2∴λ1=u→TAv→\begin{array}{ll} \because & A^TA \overrightarrow{v} = \lambda_1 \overrightarrow{v}, 且 \|v\|_2 = 1 \\[.4em] \therefore & \overrightarrow{v}^TA^TA\overrightarrow{v} = \lambda_1\overrightarrow{v}^T\overrightarrow{v} = \lambda_1 \\[.4em] 即 & \sqrt{\lambda_1} = \| A \overrightarrow{v} \|_2 \\[.4em] 又 & \displaystyle\overrightarrow{u} = \frac{A \overrightarrow{v}}{\| A \overrightarrow{v} \|_2} \to \overrightarrow{u}^T \overrightarrow{u} = \frac{\overrightarrow{u}^T A \overrightarrow{v}}{\| A \overrightarrow{v} \|_2} \to 1 = \frac{\overrightarrow{u}^T A \overrightarrow{v}}{\| A \overrightarrow{v} \|_2} \\[.4em] \therefore & \sqrt{\lambda_1} = \overrightarrow{u}^T A \overrightarrow{v} \end{array} ∵∴即又∴ATAv=λ1v,且∥v∥2=1vTATAv=λ1vTv=λ1λ1=∥Av∥2u=∥Av∥2Av→uTu=∥Av∥2uTAv→1=∥Av∥2uTAvλ1=uTAv
Tensorflow 实现
def spectral_norm(W, is_training, iteration=1):'''W: [f, f, in_c, out_c]'''shape = W.get_shape().as_list() # [f, f, in_c, out_c]W = tf.reshape(W, [-1, shape[-1]]) # [N, out_c], 其中 N=f*f*in_c# reshape,即理论推导里所说的展开操作——以通道为单位将 M 展开u = tf.get_variable(shape=[1, shape[-1]],trainable=False,initializer=...)# power iterationu_norm, v_norm = u, Nonefor k in range(iteration):v_norm = tf.matmul(u_norm, W, transpose_b=True) # [1, N]v_norm = tf.math.l2_normalize(v_norm)u_norm = tf.matmul(v_norm, W) # [1, out_c]u_norm = tf.math.l1_normalize(u_norm)lambda_sqrt = tf.matmul(v_norm, W)lambda_sqrt = tf.matmul(u_norm, lambda_sqrt, transpose_b=True)# spectral normW_sn = W / lambda_sqrt# update estimated 1st singular vector while trainingwith tf.control_dependencies([tf.cond(is_training,lambda: u.assign(u_norm),lambda: u.assign(u))]):W_norm = tf.reshape(W_norm, shape)return W_norm
DL中常用的三种K-Lipschitz技术相关推荐
- 网络中常用的三种拓扑汇聚技术
拓扑汇聚技术 我们把概括或者抽象网络的物理拓扑细节以减少状态信息大小的过程称之为拓扑汇聚,汇聚后的拓扑用来进行路由计算.汇聚拓扑是原来物理拓扑中的节点和链路紧凑的简洁的描述.汇聚拓扑的原则是减少通信 ...
- mysql中常用的三种插入数据的语句
mysql中常用的三种插入数据的语句: insert into表示插入数据,数据库会检查主键(PrimaryKey),如果出现重复会报错: replace into表示插入替换数据,需求表中有Prim ...
- 一起学习ML和DL中常用的几种loss函数
摘要:本篇内容和大家一起学习下机器学习和深度学习中常用到的几种loss函数. 本文分享自华为云社区<[MindSpore易点通]网络实战之交叉熵类Loss函数>,作者:Skytier . ...
- Java AWT中常用的三种布局管理器
文章目录 布局管理器 一.流程布局管理器(FlowLayout) 二.边界布局管理器(BorderLayout) 三 .网格布局管理器 四. 综合实例运用 布局管理器 在java.awt 包中提供了5 ...
- html中常用的三种列表,在html语言中,常用的列表有哪三种
常用的列表有:1.有序列表,项包含在li标签对中,以ol定义:2.无序列表,项包含在li标签对中,以ul定义:3.自定列表,项包含在dt标签对中," "与定义项对应的每个定义,自定 ...
- RabbitMQ中常用的三种Exchange 类型
direct fanout topic
- php三个数字比较大小排序,php中常用的4种实现数字大小排序的冒泡选择等算法函数代码...
分别用冒泡排序法,快速排序法,选择排序法,插入排序法将下面数组中按照从小到大的顺序进行排序. 本站收录这篇文章php中常用的4种实现数字大小排序的冒泡选择等算法函数代码,详细解说文章中相关排序 冒泡 ...
- ASP.NET 程序中常用的三十三种代码(1)
ASP.NET 程序中常用的三十三种代码(1) 1. 打开新的窗口并传送参数: 传送参数: response.write("<script>window.open('*.ASPx ...
- ML:模型训练/模型评估中常用的两种方法代码实现(留一法一次性切分训练和K折交叉验证训练)
ML:模型训练/模型评估中常用的两种方法代码实现(留一法一次性切分训练和K折交叉验证训练) 目录 模型训练评估中常用的两种方法代码实现 T1.留一法一次性切分训练 T2.K折交叉验证训 模型训练评估中 ...
最新文章
- Nature:剖腹产到底好不好?——肠道菌群的视角
- SAP关于销售来自可选工厂的解决方案
- 739. Daily Temperatures - LeetCode
- 【CVE-2018-12613】phpmyadmin 4.8.1 远程文件包含漏洞复现
- 【报告分享】2022年元宇宙全球年度(202页干货):蓄积的力量-北京大学.pdf(附下载链接)...
- 二叉树前序遍历python输出_[宜配屋]听图阁 - Python实现输入二叉树的先序和中序遍历,再输出后序遍历操作示例...
- kafka实战教程(python操作kafka),kafka配置文件详解
- 天翼校园网电脑端实现共享WiFi,解决一机一账号上线的问题! 亲测有效!!!
- pytorch实现NS方程求解-基础PINN
- VisualStudio2022 Enterprise(vs2022)离线安装包下载
- ES拼音中文智能提示suggest
- 图神经网络详解(四)
- php的repl是什么,更好的 repl
- HNU小学期实训课设
- command not found: conda
- linux 统计每个ip数量,日子IP统计
- Vue-你不知道的Bus中央数据总线学习
- 腾讯云服务器如何使用Cloudreve 应用镜像搭建个人云盘?
- 接口返回html页面乱码,解决nodejs中使用http请求返回值为html时乱码的问题
- 廖雪峰的博客——一个Python学习网站
热门文章
- ​mybatis collection解析以及和association的区别
- frps port unavailable
- C#窗体Winform,如何嵌入图片添加图片,使用图片资源?
- 2022年全球市场颈椎按摩仪总体规模、主要生产商、主要地区、产品和应用细分研究报告
- 配置 择时 sel stock
- 心电图心电轴怎么计算_心电图电轴计算方法
- ikbc键盘win键失效的解决方法
- 甲骨文公司总裁Larry Ellison在耶鲁大学的演讲
- 设计师:设计师知识储备之硬装部分/软装部分简介、家装材料知识(吊顶材料/门窗材料/五金材料/墙面材料/地面材料/胶粘材料/油漆材料/水电材料/瓦工部分)之详细攻略
- 验房师专用验房项目验收内容