自学内容网 自学内容网

【AI算法岗面试八股面经【超全整理】——深度学习】

AI算法岗面试八股面经【超全整理】

1、激活函数

激活函数特征:

  • 非线性:激活函数满足非线性时,才不会被单层网络替代,神经网络才有意义
  • 可微性:优化器大多数是用梯度下降法更新梯度,如果不可微的话,就不能求导,也不能更新参数
  • 单调性:激活函数是单调的,能够保证网络的损失函数是凸函数,更容易收敛

1、Sigmoid函数
f ( x ) = 1 1 + e − x f(x)=\frac{1}{1+e^{-x}} f(x)=1+ex1
在这里插入图片描述

该函数的导数为:
f ′ ( x ) = e − x ( 1 + e − x ) 2 = f ( x ) ( 1 − f ( x ) ) {f}'(x)=\frac{e^{-x}}{(1+e^{-x})^2}=f(x)(1-f(x)) f(x)=(1+ex)2ex=f(x)(1f(x))
导数的值在(0,0.25)之间
Sigmoid函数是二分类算法,尤其是逻辑回归算法中的常用激活函数,主要有以下几个特点:

  • 能够将自变量的值全部缩放到(0,1)之间
  • 当x无穷大的时候,函数值趋近于1;当x无穷小的时候,趋近于0。相当于对输入进行了归一化操作
  • 连续可导,0点,导函数的值最大,并且两边逐渐减小

缺点:

  • X在无穷大或者负无穷小的时候,导数(梯度)为0,即出现了梯度弥散现象(所谓梯度弥散就是梯度值越来越小)
  • 导数的值在(0,0.25)之间,在多层神经网络中,我们需要对输出层到输入层逐层进行链式求导。这样就导致多个0到0.25之间的小数相乘,造成了结果取0,梯度消失
  • Sigmoid函数存在幂运算,计算复杂度大,训练时间长

2、Tanh函数
f ( x ) = t a n h ( x ) = e x − e − x e x + e − x f(x)=tanh(x)=\frac{e^x-e^{-x}}{e^x+e^{-x}} f(x)=tanh(x)=ex+exexex
导数为:
f ′ ( x ) = 1 − ( e x − e − x e x + e − x ) 2 = 1 − t a n h ( x ) 2 {f}'(x)=1-(\frac{e^x-e^{-x}}{e^x+e^{-x}})^2=1-{tanh(x)}^2 f(x)=1(ex+exexex)2=1tanh(x)2
梯度(导数)的取值在(0, 1]之间
在这里插入图片描述

特点:

  • Tanh函数输出满足0均值
  • 当输入较大或者较小时,输出的值变化很小,导致导函数几乎为0,也就是梯度很小,从而不利于W、b的更新
  • 梯度(导数)的取值在(0, 1]之间,最大梯度为1,能够保证梯度在变化过程中不消减,缓解了Sigmoid函数梯度消失的问题;但是取值过大或者过小,仍存在梯度消失
  • 同样地函数本身存在幂运算,计算量大

3、ReLU函数
f ( x ) = R e L U ( x ) = m a x ( x , 0 ) = s i g n ( x ) = { 0 x <=0 x x>0 f(x)=ReLU(x)=max(x,0)=sign(x)=\begin{cases} 0& \text{x <=0}\\x& \text{x>0} \end{cases} f(x)=ReLU(x)=max(x,0)=sign(x)={0xx <=0x>0
在这里插入图片描述

导数:
f ′ ( x ) = { 0 x <=0 1 x>0 {f}'(x)=\begin{cases} 0& \text{x <=0}\\1& \text{x>0} \end{cases} f(x)={01x <=0x>0
特点:

  • 函数本身在输入大于0的时候,输出逐渐增加,这样梯度值也一直存在,从而避免了梯度的饱和:正区间解决梯度消失问题
  • 函数本身是线性函数,比Sigmoid或者Tanh函数要计算速度快;同时函数的收敛速度要大于Sigmoid或者Tanh函数
  • 函数的输出不是以0为均值,收敛慢
  • Dead ReLU问题:在负输入部分,输入的值为0,从而梯度为0,导致参数无法更新,造成神经元死亡;在实际处理中,我们可以减少过多的负数特征进入网络

4、Leaky ReLU问题
在小于0的部分引入一个斜率,使得小于0的取值不再是0(通常a的值为0.01左右)

f ( x ) = { a ⋅ x x <=0 x x>0 f(x)=\begin{cases} a \cdot x& \text{x <=0}\\x& \text{x>0} \end{cases} f(x)={axxx <=0x>0
在这里插入图片描述

导数:
f ′ ( x ) = { a x <=0 1 x>0 {f}'(x)=\begin{cases} a& \text{x <=0}\\1& \text{x>0} \end{cases} f(x)={a1x <=0x>0

特点:

  • 具有和ReLU完全相同的特点,而且不会造成Dead ReLU问题
  • 函数本身的取值在负无穷到正无穷;负区间梯度也存在,从而避免了梯度消失。
  • 但是实际运用中,尚未完全证明Leaky ReLU总是比ReLU更好

2、Softmax函数及求导

Softmax函数又称归一化指数函数,是基于Sigmoid二分类函数在多分类任务上的推广,在多分类网络中,常用Softmax作为最后一层进行分类。它将一个包含任意实数的K维向量(K是类别数量)映射为一个概率分布,每个类别的预测值都在0到1之间,所有类别的概率总和为1。Softmax函数的作用是将原始得分转换为概率值,使得模型的输出更符合实际的概率分布。
函数公式:
S i = e a i ∑ K = 1 K e a k S_i=\frac{e^{a_i}}{\sum_{K=1}^K{e^{a_k}}} Si=K=1Keakeai
其中, a a a是输入向量,上述公式表示第 i i i个类别的输出概率
Softmax可以使正样本(正数)的结果趋近于1,使负样本(负数)的结果趋近于0;且样本的绝对值越大,两极化越明显。
函数求导分类讨论:
i = j i=j i=j时:
∂ s i ∂ a j = e a i ∑ − e a i e a j ∑ 2 = s i − s i s j \frac{\partial s_i}{\partial a_j} = \frac{e^{a_i}\sum-e^{a_i}e^{a_j}}{\sum^2}=s_i-s_is_j ajsi=2eaieaieaj=sisisj
i ≠ j i\neq j i=j时:
∂ s i ∂ a j = 0 − e a i e a j ∑ 2 = − s i s j \frac{\partial s_i}{\partial a_j} = \frac{0-e^{a_i}e^{a_j}}{\sum^2}=-s_is_j ajsi=20eaieaj=sisj

3、优化器

在深度学习中,优化器(optimizer)是一种用于调整神经网络模型参数以最小化损失函数的算法。优化器的目标是分局输入数据和期望的输出标签来调整模型的权重和偏置,使得模型能够更好地拟合训练数据并在未见过的数据上表现良好。
1、BGD(Batch Gradient Descent)
在更新参数时使用所有样本进行更新,假设样本综述为N:
θ ( t + 1 ) = θ ( t ) − α ⋅ 1 N ∑ i = 1 N ∇ θ J ( θ i ( t ) ) \theta ^{(t+1)} = \theta^{(t)}-\alpha \cdot \frac{1}{N}\sum_{i=1}^N\nabla_\theta J(\theta_i^{(t)}) θ(t+1)=θ(t)αN1i=1NθJ(θi(t))
其中, θ ( t ) \theta^{(t)} θ(t)为第t次迭代时的参数值, α \alpha α为学习率, ∇ θ J ( θ i ( t ) ) \nabla_\theta J(\theta_i^{(t)}) θJ(θi(t))为损失函数 J ( θ ) J(\theta) J(θ)关于模型参数 θ \theta θ的梯度。
BGD得到的是一个全局最优解,但是每迭代一步,都要用到训练集的所有数据,如果样本数巨大,那上述公式迭代起来则非常耗时,模型训练速度很慢。

2、SGD(随机梯度下降)
更新参数时使用随机选取的一个样本来进行更新。
θ ( t + 1 ) = θ ( t ) − ∇ θ J ( θ i ( t ) ) \theta ^{(t+1)} = \theta^{(t)}-\nabla_\theta J(\theta_i^{(t)}) θ(t+1)=θ(t)θJ(θi(t))
SGD的优点是实现简单、效率高,缺点是收敛速度慢,容易陷入局部最小值。

3、MDGD(Mini Batch梯度下降)
介于批梯度下降和随机梯度下降之间,每次更新参数时使用b个样本。
θ ( t + 1 ) = θ ( t ) − α ⋅ 1 b ∑ i = 1 b ∇ θ J ( θ i ( t ) ) \theta ^{(t+1)} = \theta^{(t)}-\alpha \cdot \frac{1}{b}\sum_{i=1}^b\nabla_\theta J(\theta_i^{(t)}) θ(t+1)=θ(t)αb1i=1bθJ(θi(t))
训练过程比较稳定;BGD可以找到局部最优解,不一定是全局最优解;若损失函数为凸函数,则BGD所求解一定为全局最优解。

4、AdaGrad(Adaptive Gradient,自适应梯度优化器/自适应学习率优化器)
AdaGrad优点是可以自适应学习率。该优化算法在较为平缓处学习速率达,有比较高的学习效率,在陡峭处学习率小,在一定程度上可以避免越过极小值。
σ t = 1 t + 1 ∑ i = 0 t ( g i ) 2 ‌ g t , i = ∇ θ J ( θ i ( t ) ) \sigma ^t=\sqrt{\frac{1}{t+1}\sum_{i=0}^t{(g_i)}^2} ‌\quad g_{t,i}=\nabla_\theta J(\theta_i^{(t)}) σt=t+11i=0t(gi)2 gt,i=θJ(θi(t))
θ ( t + 1 ) = θ ( t ) − α σ t + φ ∇ θ J ( θ i ( t ) ) \theta ^{(t+1)}=\theta^{(t)}-\frac{\alpha}{\sigma^t+\varphi}\nabla_\theta J(\theta_i^{(t)}) θ(t+1)=θ(t)σt+φαθJ(θi(t))
其中 g i g_i gi代表函数第 i i i次迭代的维度, σ t \sigma ^t σt就是前面所有梯度的均值平方根。 φ \varphi φ为常数,一般取 1 0 − 7 10^{-7} 107,这是为了避免公式分母存在等于0的情况, α \alpha α为学习率。
AdaGrad可以自适应地调整学习率,但随着迭代次数,学习率不断降低,可能导致训练过程中停滞。

5、RMSProp(Root Mean Square Propagation)
AdaGrad算法虽然解决了学习率无法根据当前梯度自动调整的问题,但是过于依赖之前的梯度,在梯度突然变化时无法快速响应。RMSProp为了解决这一问题,在AdaGrad的基础上增加了衰减速率参数。也就是说在当前梯度与之前梯度之间添加了权重,如果当前梯度的权重较大,那么响应速度也就更快。
σ t = η ( 1 t ∑ i = 0 t − 1 ( g i ) 2 ) + ( 1 − η ) ( g t ) 2 \sigma ^t=\sqrt{\eta(\frac{1}{t}\sum_{i=0}^{t-1}{(g_i)}^2)+(1-\eta){(g_t)}^2} σt=η(t1i=0t1(gi)2)+(1η)(gt)2
θ ( t + 1 ) = θ ( t ) − α σ t + φ ∇ θ J ( θ i ( t ) ) \theta ^{(t+1)}=\theta^{(t)}-\frac{\alpha}{\sigma^t+\varphi}\nabla_\theta J(\theta_i^{(t)}) θ(t+1)=θ(t)σt+φαθJ(θi(t))

6、Adam(Adaptive Momen Estimation,自适应动量估计)
Adam优化算法是在RMSProp的基础上增加了动量。有时候通过RMSProp优化算法得到的值不是最优解,有可能是局部最优解,引入动量的概念后,求最小值就像是一个球从高处落下,落到局部最低点时会继续向前探索,有可能得到更小的值。
m t = β ⋅ m t − 1 + ( 1 − β ) g t − 1 m_t = \beta\cdot m_{t-1}+(1-\beta)g^{t-1} mt=βmt1+(1β)gt1
σ t = η ( 1 t ∑ i = 0 t − 1 ( g i ) 2 ) + ( 1 − η ) ( g t ) 2 \sigma ^t=\sqrt{\eta(\frac{1}{t}\sum_{i=0}^{t-1}{(g_i)}^2)+(1-\eta){(g_t)}^2} σt=η(t1i=0t1(gi)2)+(1η)(gt)2
θ ( t + 1 ) = θ ( t ) − α σ t + φ m t \theta ^{(t+1)}=\theta^{(t)}-\frac{\alpha}{\sigma^t+\varphi}m_t θ(t+1)=θ(t)σt+φαmt
其中, m t m_t mt表示第 t t t次迭代时的动量,同时在上一次动量和本次梯度之间加上一个权重系数 β \beta β,当 β \beta β越大,受到上一次动量的影响就越大。

4、残差连接

残差连接使用跳跃连接技术,在模型中将输入信号与输出信号进行直接连接。
作用:

  • 促进信息传递: 使模型更容易传递信息和梯度,避免梯度消失或梯度爆炸,特别是在处理深层网络时;
  • 简化优化问题: 可以简化优化问题,使模型更容易优化和训练;
  • 提高模型表达能力: 允许模型保留更多的低层特征信息,使模型更好地捕捉输入序列中的细节和上下文信息。

5、梯度消失和梯度爆炸

1、梯度消失原因:

  • 隐藏层的层数过多
  • 采用了不合适的激活函数(容易产生梯度消失,也有可能产生梯度爆炸)

2、梯度爆炸原因:

  • 隐藏层的层数过多
  • 权重的初始化值过大

3、解决方法:

  • 使用ReLU(导数为1)、Leaky ReLU等
  • Batch Normalization
    BN就是对每一层的输出规范为均值和方差一致的方法,消除了权重带来的放大缩小的影响,进而解决梯度消失和爆炸的问题,或者可以理解为BN将输出从饱和区拉到非饱和区(比如Sigmoid函数)
    Batch Normalization作用:
    (1)允许较大的学习率
    (2)减弱对初始化的强依赖性
    (3)保持隐藏层中数值的均值、方差不变,让数值更稳定,为后面网络提供坚实的基础
    (4)有轻微的正则化作用(相当于给隐藏层加入噪声,类似Dropout)
  • LSTM
  • ResNet残差网络
  • 预训练加微调
  • 权重正则化:解决梯度爆炸

6、归一化

归一化指把数据转换到[0, 1]之间或者[-1, 1]之间
1、最小最大归一化(离散标准化):
x ′ = x − m i n ( x ) m a x ( x ) − m i n ( x ) {x}'=\frac{x-min(x)}{max(x)-min(x)} x=max(x)min(x)xmin(x)
2、零一均值归一化
x ′ = x − μ δ {x}'=\frac{x-\mu}{\delta} x=δxμ
3、Softmax
x ′ = = e x ∑ e x {x}'==\frac{e^x}{\sum{e^x}} x==exex

7、评价指标

1、TP、TN、FP、FN

  • TP(True Positives)预测为正样本,并且预测对了(真阳性)
  • TN(True Negatives)预测为负样本,并且预测对了(真阴性)
  • FP(False Positives)预测为正样本,但是预测错了(假阳性)
  • FN(False Negatives)预测为负样本,但是预测错了(假阴性)

2、准确率(Accuracy)、精确率(Precision)、召回率(Recall)、F1-Score
A c c u r a c y = T P + T N P + N Accuracy=\frac{TP+TN}{P+N} Accuracy=P+NTP+TN(所有预测正确的正例和负例,占所有样本的比例)
P r e c i s i o n = T P T P + F P Precision=\frac{TP}{TP+FP} Precision=TP+FPTP(预测为正例并且确实是正例的部分,占所有预测为正例的比例)
R e c a l l = T P T P + F N Recall=\frac{TP}{TP+FN} Recall=TP+FNTP(预测为正例并且确实正例的部分,占所有确实是正例的比例)
F 1 − S c o r e = 2 1 P r e s i c i o n + 1 R e c a l l = 2 P r e c i s i o n ⋅ R e c a l l P r e c i s i o n + R e c a l l = 2 T P F P + 2 T P + F N F1-Score=\frac{2}{\frac{1}{Presicion}+\frac{1}{Recall}}=\frac{2Precision\cdot Recall}{Precision+Recall}=\frac{2TP}{FP+2TP+FN} F1Score=Presicion1+Recall12=Precision+Recall2PrecisionRecall=FP+2TP+FN2TP
3、UF1、UAR(Unweighted Average Recall)
由于标签分布不均,采用传统的评价指标,如(Accuracy、Precision、Recall、F1)将会导致对样本量多的那类过于乐观。使用未加权F1-Score(UF1)和未加权平均召回率(UAR)作为性能度量,以避免所提出的方法对某个类别的过拟合。给定c个类别,真阳性(TPc)、假阳性(FPc)和假阴性(FNc)可计算。
U F 1 = ∑ i C U F 1 i C UF1=\frac{\sum_i^C{UF1_i}}{C} UF1=CiCUF1i
UAR作为模型的评价指标,表示没类数据样本召回率(Recall)的平均值。通过UAR反应异常检测诊断模型的整体性能。
U A R = ∑ i C R e c a l l i C UAR=\frac{\sum_i^C{Recall_i}}{C} UAR=CiCRecalli

8、浅层、深层网络区别

  • 神经网络中,权重参数是给数据做线性变换,而激活函数给数据带来的非线性变换。增加某一层神经元数量是在增加线性变换的复杂性,而增加网络层数是在增加非线性变换的复杂性。
  • 理论上,浅层神经网络就能模拟任何函数,但需要巨大的数据量,而深层神经网络可以用更少的数据量来学习到更好的拟合。

解决欠拟合:

  • 增加网络复杂度
  • 增加特征

9、防止过拟合

  • Dropout。 每次训练时,有一部分神经元不参与更新,而且每次不参与更新的神经元是随机的。防止参数过分依赖训练数据,增加参数对数据集的泛化能力。因为在实际训练的时候,每个参数都有可能被随机Drop掉,所有参数不会过分地依赖某一个特征。
  • 增大数据量。 过拟合是学习到了部分数据集的特有特征,那么增大数据集就能有效的防止这种情况出现。
  • Early Stop。 将数据集分为训练集、验证集、测试集,每个epoch后都用验证集验证一下,如果随着训练的进行训练集Loss持续下降,而验证集Loss先下降后上升,说明出现过拟合,应该立即停止训练。
  • Batch Normalization。 BN有两个功能,一个是可以加快训练和收敛速度,另外一个可以防止过拟合。
    BN算法在实际使用的时候会把特征给强制性的归到均值为0,方差为1的数学模型下。深度网络在训练过程中,如果每层的数据分布都不一样的话,将会导致网络非常难收敛和训练。而如果能把每层的数据转换到均值为0,方差为1的状态下,在梯度计算时会产生比较大的梯度值,可以加快参数的训练,更直观地说,是把数据从饱和区直接拉到飞饱和区。更进一步,这也可以很好地控制梯度爆炸和梯度消失现象,因为这两种现象都和梯度有关。
    在训练中,BN的使用使得一个mini-batch中的所有样本都被关联在一起,因此网络不再从某一个训练样本中生成确定的结果。
  • L1正则化。 在原Loss上加入L1正则化后, L = L 0 + λ 2 n ∣ W ∣ L=L_0+\frac{\lambda}{2n}|W| L=L0+2nλW,如果W为正,相对于原梯度就减小,如果W为负,相对于原梯度就增大,所以L1正则化使得参数W在更新时向0靠近使得参数具有稀疏性。而权重趋近于0,也就相当于减小了网络复杂度,防止过拟合。
  • L2正则化。 在原Loss上加入L2正则化后, L = L 0 + λ 2 n ∣ W ∣ 2 L=L_0+\frac{\lambda}{2n}|W|^2 L=L0+2nλW2。在过拟合中,由于对每个数据都拟合得很好,所以函数的变化在小范围内往往很剧烈,而要使函数在小范围内剧烈变化,就是要W参数值很大。L2正则化抑制了这种小范围剧烈变化。不同于L1正则化,L2正则化则是趋向于把所有参数w都变得比较小,一般认为参数w比较小的时候,模型比较简单。直观上来说,L2正则化的解都比较小,抗扰动能力强。

L1、L2对比:

  • L0范数是指向量中非0元素的个数
  • L1(拉格朗日Lasso)正则假设参数先验分布是Laplace分布,可以使权重稀疏,保证模型的稀疏性,某些参数等于0,产生稀疏权值矩阵,用于特征选择;L1可以进行特征选择,趋向于产生少量的特征,其他的特征都是0;
  • L2(岭回归Ridge)正则假设参数先验分布是Gaussian分布,可以使权重平滑,保证模型的稳定性,也就是参数的值不会太大或太小;L2会选择更多的特征,这些特征都会接近于0;
  • 在实际使用中,如果特征是高维稀疏的,则使用L1正则;如果特征是低维稠密的,则使用L2正则

梯度饱和:
当激活函数的输入值非常大或非常小的时候,激活函数对于输入的导数(梯度)会变得非常小,接近于0(Sigmoid、Tanh)

10、Batch Normalization和Layer Normalization

为什么需要对输入数据做归一化处理

  • 一方面,神经网络学习过程本质就是为了学习数据特征以及数据的分布特征,一旦训练数据与测试数据的分布不同,那么网络的泛化性能也大大降低
  • 另外一方面,一旦每批训练数据的分布各不相同(Batch梯度下降),那么网络就要在每次迭代都去学习适应不同的分布,这样将会大大降低网络的训练速度,这也正是为什么我们需要对数据都要做一个归一化预处理的原因

Batch Normalization

旨在提高神经网络的训练速度和稳定性。通过对每个小批量数据的输入进行归一化处理,使得网络各层的输入分布保持相对稳定,有助于解决训练过程中的内部协变量偏移问题。
对于具有形状【b,c,h,w】的输入,其中:

  • B是批量大小(Batch size)
  • C是通道数(channel count)
  • H是高度(height)
  • W是宽度(width)
    Batch Normalization会针对每个通道独立地进行,对于给定的通道,它将计算该通道内所有元素(考虑所有的批量大小、高度、宽度)的平均值和方差,然后使用这些统计量来归一化该通道的值。
    Layer Normalization

与 Batch Normalization 不同,层归一化是对单个样本中所有特征进行归一化,而不是在批量的维度上。这意味着层归一化不依赖于批量的大小,使其特别适用于批量大小不一或需要归一化单个样本的场景。
层归一化会对每个样本的所有 chw 个特征一起进行归一化。具体来说,对于每个样本,在计算均值和方差时会考虑所有的通道、高度和宽度。
应用场景:
BN一般用于CV,LN一般用于NLP。对于不定长序列,如果使用BN,序列中的Padding会扰乱非padding的特征。

11、全连接层作用

  • 特征融合
  • 分类。将前层(卷积、池化等)计算得到的特征空间映射到样本标记空间。简单地说就是将特征表示整合成一个值,其优点在于减少特征位置对于分类结果的影响,提高了整个网络的鲁棒性。
  • FC可一定程度保留模型复杂度(微调和迁移)不含FC的网络微调后的结果要差于含FC的网络。因此FC可视作模型表示能力的“防火墙”,特别是在源域与目标域差异较大的情况下,FC可保持较大的模型capacity从而保证模型表示能力的迁移。

12、深度学习模型与树模型的优缺点

1、深度学习
优点:

  • 擅长处理复杂数据: 对于大规模数据、高维数据和非线性关系,深度学习模型通常能够提供更好的拟合能力。
  • 特征学习能力强: 能够自动学习和提取数据的特征,减少对特征工程的需求。
  • 泛化能力强: 在大数据集上训练时,深度学习模型可能会产生更好的泛化效果,适用于更广泛的场景。

缺点:

  • 需要大量数据和计算资源: 深度学习模型对于大规模数据集和复杂模型的训练需要大量的数据和高性能计算资源。
  • 需要调参和调优: 模型架构复杂,需要仔细调整超参数和优化模型结构。
  • 可解释性差

2、树模型
优点:

  • 易解释性强:能够直观地展示特征重要性和决策过程。
  • 对少量数据处理得当: 在数据较少或者数据质量较差的情况下,树模型表现通常较好。
  • 训练和预测速度快: 相对于深度学习模型,树模型的训练速度快,适合于处理中小规模的数据集。

缺点:

  • 容易过拟合: 在某些情况下,树模型容易过拟合,尤其是当树的深度较大或没有采用适当的剪枝措施时。
  • 不擅长处理复杂关系: 对于复杂的非线性关系,树模型可能不如深度学习模型表现得好。
  • 需要人工特征工程: 对于传统的决策树模型,通常需要手动进行特征工程,挑选和构建合适的特征

原文地址:https://blog.csdn.net/weixin_46570668/article/details/142419167

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!