热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【论文学习】《ParallelWaveGAN:Afastwaveformgenerationmodelbasedongenerativeadversarialnetworks》

《ParallelWaveGAN:AfastwaveformgenerationmodelbasedongenerativeadversarialnetworkswithMulti
《Parallel WaveGAN : A fast waveform generation model based on generative adversarial networks with Multi-Resolution Spectrogram》论文学习

文章目录

  • 《Parallel WaveGAN : A fast waveform generation model based on generative adversarial networks with Multi-Resolution Spectrogram》论文学习
    •   摘要
    •   1 介绍
    •   2 相关工作
    •   3 方法
      •     3.1 基于GAN的并行波形生成
      •     3.2 多分辨率STFT辅助损耗
    •   4 实验
      •     4.1 实验设置
        •       4.1.1 数据集
        •       4.1.2 模型细节
      •     4.2 评价
      •     4.3 从文本到语音
    •   5 结论


  摘要

       我们提出了Parallel WaveGAN,一种使用生成式对抗网络的无蒸馏、快速和占用空间小的波形生成方法。该方法通过联合优化多分辨率谱图和对抗损耗函数来训练非自回归WaveNet,能够有效地捕捉真实语音波形的时频分布。由于我们的方法不需要在传统的师生框架中使用密度蒸馏,整个模型易于训练。此外,我们的模型在结构紧凑的情况下也能生成高保真语音。其中,提出的并行WaveGAN只有1.44M个参数,在单个GPU环境下生成24kHz语音波形的速度比实时速度快28.68倍。感知听力测试结果表明,本文提出的方法在基于Transformer的文本到语音框架中获得了4.16的平均意见得分,与基于蒸馏的最好的Parallel WaveNet系统做出对比。
       
       关键词 - 神经声码器,TTS,GAN,Parallel WaveNet,Transformer
       

  1 介绍

       文本到语音(TTS)框架中的深度生成模型显著提高了合成语音信号的质量(《Statistical parametric speech synthesis using deep neural networks》,《Effective spectral and excitation modeling techniques for LSTM-RNN-based speech synthesis systems》,《Natural TTS synthesis by conditioning WaveNet on mel spectrogram predictions》)。值得注意的是,自回归生成模型如WaveNet已经显示出比传统参数声码器更优越的性能(《WaveNet: A generative model for raw audio》,《A comparison of recent waveform generation and acoustic modeling methods for neural-network-based speech synthesis》,《Speaker-dependent WaveNet vocoder》,《An investigation of multi-speaker training for WaveNet vocoder》,《Excitnet vocoder: A neural excitation model for parametric speech synthesis systems》)。然而,由于自回归的特性,其推理速度较慢,因此在实时场景中的应用受到限制。
       
       解决这种局限性的一种方法是利用基于教师-学生框架的快速波形生成方法(《Parallel WaveNet: Fast high-fidelity speech synthesis》,《ClariNet: Parallel wave generation in end-to-end text-to-speech》,《Probability density distillation with generative adversarial networks for high-quality parallel waveform generation》)。在这个框架中,定义为概率密度蒸馏的桥梁将自回归教师WaveNet的知识转移到基于逆自回归流(IAF)的学生模型(《Improved variational inference with inverse autoregressive flow》)。虽然IAF学生能够以合理的感知质量实现实时生成语音,但在训练过程中仍然存在问题:不仅需要一个训练良好的教师模型,还需要一种试错方法来优化复杂的密度蒸馏过程。
       
       为了克服上述问题,我们提出了一种基于生成式对抗网络(generative adversarial network, GAN)(《Generative adversarial nets》)的并行波形生成方法——Parallel WaveGAN。与传统的基于蒸馏的方法不同,Parallel WaveGAN不需要两个阶段,而是连续的教师-学生训练过程。
       该方法仅通过优化多分辨率短时傅里叶变换(STFT)和对抗损失函数的组合来训练非自回归WaveNet模型,使该模型能够有效地捕获真实语音波形的时频分布。因此,整个训练过程比传统方法简单得多,并且模型参数较少,可以产生自然发声的语音波形。我们的贡献总结如下:
       (1)提出了一种多分辨率短时傅立叶变换损耗和波形域对抗损耗的联合训练方法。该方法既适用于传统的基于蒸馏的Parallel WaveNet(如ClariNet),也适用于提出的无蒸馏Parallel WaveGAN
       (2)由于所提出的Parallel WaveGAN可以在没有任何教师-学生框架的情况下进行简单的训练,因此我们的方法大大减少了训练和推理时间。特别是训练过程变得快4.82倍(从13.5天到2.8天,使用两个NVIDIA Telsa V100 GPU)和推理过程变得快1.96倍(从14.6228.68 倍实时速度生成24kHz语音波形,使用单个NVIDIA Telsa V100 GPU),与传统的ClariNet模型相比。
       (3)我们将提出的Parallel WaveGAN与基于TransformerTTS声学模型相结合(《Attention is all you need》,《Neural speech synthesis with Transformer network》,《FastSpeech: Fast, robust and controllable text to speech》)。感知听力测试结果表明,提出的Parallel WaveGAN模型达到了4.16 MOS,与基于蒸馏的ClariNet模型相比具有一定的竞争力。
       

  2 相关工作

       在Parallel WaveNet框架中使用GAN的想法并不新鲜。在我们之前的工作中,IAF学生模型被纳入到生成器中,并通过最小化对抗损失以及Kullback-Leibler散度(KLD)和辅助损失(《Probability density distillation with generative adversarial networks for high-quality parallel waveform generation》)进行联合优化。由于GAN学习了真实语音信号的分布,该方法显著提高了合成信号的感知质量。但基于密度精馏的训练阶段复杂,限制了其应用。
       
       我们的目标是尽量减少训练传统教师-学生框架的两阶段管道的努力。换句话说,我们提出了一种新的方法训练Parallel WaveNet不需要任何蒸馏过程。Juvela等人(《GELP: GAN-excited linear prediction for speech synthesis from melspectrogram》)也提出了类似的方法(例如GAN激发线性预测,GELP),利用对抗式训练方法产生声门刺激。然而,由于GELP需要线性预测(LP)参数来将声门激励转换为语音波形,因此,当LP参数包含TTS声学模型不可避免的误差时,可能会出现质量下降。为了避免这个问题,我们的方法是直接估计语音波形。由于很难捕捉语音信号的动态特性,包括声带运动和声道共振(分别由GELP中的声门兴奋和LP参数表示),我们提出了对抗损耗和多分辨率STFT损耗的联合优化方法,以捕获真实语音信号的时频分布。因此,即使参数较少,整个模型也易于训练,同时有效地减少了推断时间,提高了合成语音的感知质量。
       

  3 方法


    3.1 基于GAN的并行波形生成

       GAN是生成模型,由两个独立的神经网络组成:生成器(G)和鉴别器(D)(《Generative adversarial nets》)。在我们的方法中,一个基于WaveNet型以辅助特征(如梅尔谱图)为条件作为发生器,它将输入噪声并行地转换为输出波形。生成器与原始WaveNet的不同之处在于:(1)我们使用非因果卷积而不是因果卷积;(2)输入为高斯分布的随机噪声;(3)模型在训练和推理阶段都是非自回归的。
       
       发生器学习真实波形的分布,通过试图欺骗鉴别器来识别发生器样本为真实的。这个过程是通过最小化对抗损失(Ladv)来完成的,如下所示:
Ladv(G,D)=Ez∼N(0,I)[(1−D(G(z)))2](1)L_{adv}(G,D)=\mathbb{E}_{z\sim N(0,I)}[(1-D(G(z)))^2] \tag{1} Ladv(G,D)=EzN(0,I)[(1D(G(z)))2](1)       其中zzz为输入白噪声。注意,为了简洁,GGG的辅助特性被省略了。
       
       另一方面,利用以下优化准则训练鉴别器,在将ground truth分类为真实的同时,将生成的样本正确分类为假样本:
LD(G,D)=Ex∼pdata[(1−D(x))2]+Ez∼N(0,I)[(1−D(G(z)))2](2)L_{D}(G,D)=\mathbb{E}_{x\sim p_{data}}[(1-D(x))^2]+ \mathbb{E}_{z\sim N(0,I)}[(1-D(G(z)))^2] \tag{2} LD(G,D)=Expdata[(1D(x))2]+EzN(0,I)[(1D(G(z)))2](2)       式中,xxxpdatap_{data}pdata分别表示目标波形及其分布。
       

    3.2 多分辨率STFT辅助损耗

       为了提高对抗训练过程的稳定性和效率,我们提出了一种多分辨率短时傅里叶变换辅助损失算法。图1显示了我们将多分辨率短时傅立叶变换损失与3.1节中描述的对抗训练方法相结合的框架。
图1
       与前面的工作(《Probability density distillation with generative adversarial networks for high-quality parallel waveform generation》)相似,我们定义单个STFT损耗如下:
Ls(G)=Ez∼p(z),x∼pdata[Lsc(x,x^)+Lmag(x,x^)](3)L_{s}(G)=\mathbb{E}_{z \sim p(z), x\sim p_{data}}[L_{sc}(x,\hat{x})+L_{mag}(x,\hat{x})] \tag{3} Ls(G)=Ezp(z),xpdata[Lsc(x,x^)+Lmag(x,x^)](3)       其中x^\hat{x}x^表示生成的样本(即G(z)G(z)G(z)), LscL_{sc}LscLmagL_{mag}Lmag分别表示光谱收敛性和对数STFT幅值损失,定义如下(《Fast spectrogram inversion using multi-head convolutional neural networks》):
Lsc(x,x^)=∥∣STFT(x)∣−∣STFT(x^)∣∥F∥∣STFT(x)∣∥F(4)L_{sc}(x,\hat{x})=\frac {\Vert \vert STFT(x)\vert - \vert STFT(\hat{x})\vert \Vert _F}{\Vert \vert STFT(x)\vert \Vert _F} \tag{4} Lsc(x,x^)=STFT(x)FSTFT(x)STFT(x^)F(4)Lmag(x,x^)=1N∥log∣STFT(x)∣−log∣STFT(x^)∣∥1(5)L_{mag}(x,\hat{x}) = \frac {1}{N} \Vert log\vert STFT(x)\vert-log\vert STFT(\hat{x})\vert\Vert _1 \tag{5} Lmag(x,x^)=N1logSTFT(x)logSTFT(x^)1(5)       其中∥⋅∥F\Vert \cdot \Vert _FF∥⋅∥1\Vert \cdot \Vert _11分别为Frobenius范数和L1L_1L1范数;∣STFT(⋅)∣\vert STFT(\cdot) \vertSTFT()NNN分别表示STFT幅值和幅值中元素个数。
       
       我们的多分辨率STFT损失是不同分析参数(即FFT大小、窗口大小和帧移)下STFT损失的总和。设MSTFT损耗数,则多分辨率STFT辅助损耗(LauxL_{aux}Laux)表示为:
Laux(G)=1M∑m=1MLs(m)(G)(6)L_{aux}(G) = \frac {1}{M} \sum_{m=1}^M L_s^{(m)}(G) \tag{6} Laux(G)=M1m=1MLs(m)(G)(6)       在基于STFT的信号时频表示中,存在时间分辨率和频率分辨率之间的权衡;例如,增加窗口大小可以获得更高的频率分辨率,而降低时间分辨率(《The wavelet transform, time-frequency localization and signal analysis》)。通过结合不同分析参数的多种短时傅立叶变换损耗,极大地帮助生成器了解语音(《Neural source-filterbased waveform model for statistical parametric speech synthesis》)的时频特性。此外,它还防止生成器过拟合到固定的STFT表示,这可能导致在波形域的次优性能。
       
       我们对生成器的最终损失函数定义为多分辨率STFT损失和对抗损失的线性组合,如下所示:
LG(G,D)=Laux(G)+λadvLadv(G,D)(7)L_G(G,D)=L_{aux}(G)+\lambda_{adv}L_{adv}(G,D) \tag{7} LG(G,D)=Laux(G)+λadvLadv(G,D)(7)       其中λadv\lambda_{adv}λadv表示平衡两个损失项的超参数。通过对波形域对抗损耗和多分辨率STFT损耗的联合优化,可以有效地了解真实语音波形的分布。
       

  4 实验


    4.1 实验设置


      4.1.1 数据集

       在实验中,我们使用了一个由一位女性日语专业人士记录的语音和平实平衡的语料库。语音信号以24kHz采样,每个采样用16比特量化。共使用11449个话语(23.09小时)进行训练,使用250个话语(0.35小时)进行验证,使用250个话语(0.34小时)进行评价。提取限频(70 ~ 8000Hz)的80波段log-mel谱图作为波形生成模型(即局部条件(《WaveNet: A generative model for raw audio》))的输入辅助特征。帧长设置为50ms,移位长度设置为12.5ms。训练前将梅尔谱图特征归一化,使其均值和单位方差均为零。
       

      4.1.2 模型细节

       提出的Parallel WaveGAN30层扩张剩余卷积块组成,以指数方式增加三个扩张周期。剩余通道和跳跃通道数设为64,卷积滤波器大小设为3。该鉴别器由10层非因果扩张的一维卷积组成,具有泄漏的ReLU激活函数(α = 0.2)。步幅设置为1,从18的一维卷积应用线性增加的扩张,除了第一层和最后一层。通道的数量和滤波器的大小与发生器相同。我们对生成器和鉴别器(《Weight normalization: A simple reparameterization to accelerate training of deep neural networks》)的所有卷积层都进行了权值归一化。
       
       在训练阶段,由三种不同的STFT损失之和计算多分辨率STFT损失,如表1所示。鉴别器损耗由鉴别器的每个时间步长标量预测的平均值计算。根据初步实验结果,将式 (7) 中的λadv\lambda_{adv}λadv设定为4.0。用RAdam优化器(ϵ=1e−6\epsilon = 1e^{-6}ϵ=1e6对模型进行400K步的训练,以稳定训练(《On the variance of the adaptive learning rate and beyond》)。注意,前100K步的鉴别器是固定的,之后联合训练两个模型。迷你批大小设置为8个,每个音频剪辑的长度设置为24K时间样本(1.0秒)。对生成器和鉴别器分别设置初始学习率为0.00010.00005。每200K步学习率降低一半。
表1
       
       作为基线系统,我们同时使用了自回归Gaussian WaveNetParallel WaveNet(即ClariNet)(《ClariNet: Parallel wave generation in end-to-end text-to-speech》,《Probability density distillation with generative adversarial networks for high-quality parallel waveform generation》)。该WaveNet24层膨胀剩余卷积块组成,具有4个膨胀周期。剩余通道和跳跃通道的数量设置为128个,过滤器大小设置为3个。采用RAdam优化器对模型进行1.5M步的训练。学习率设置为0.001,每200K步学习率降低一半。迷你批大小设置为8个,每个音频剪辑的长度设置为12K时间样本(0.5秒)。
       
       为了训练基线ClariNet,我们使用上述的自回归WaveNet作为教师模型。ClariNet以高斯IAFs为基础,由六个流程组成。每个流的参数由10层膨胀剩余卷积块以指数增长的膨胀周期进行参数化。剩余通道和跳跃通道的数量设置为64个,过滤器大小设置为3个。
       平衡KLDSTFT辅助损失的权重系数分别设为0.51.0。使用与Parallel WaveGAN相同的优化器设置,对模型进行了400K步的训练。我们还研究了对抗损失ClariNet作为GAN和密度蒸馏的混合方法。模型结构与基线ClariNet相同,但采用KLDSTFT和对抗损失的混合训练,其中平衡它们的权重系数分别设为0.051.04.0。采用固定的鉴别器对模型进行200K步的训练,对其余200K步的生成器和鉴别器进行联合优化。
       
       在整个波形生成模型中,对输入辅助特征进行最近邻上采样,然后进行二维卷积,使辅助特征的时间分辨率与语音波形的采样率相匹配(《Probability density distillation with generative adversarial networks for high-quality parallel waveform generation》,《Deconvolution and checkerboard artifacts》)。注意,辅助特征不用于鉴别器。所有模型都使用了两个NVIDIA Tesla V100 GPU进行训练。实验在NAVER智能机器学习(NSML)平台(《NSML: Meet the mlaas platform with a real-world case study》)上进行。
       

    4.2 评价

       为评价知觉质量,采用平均意见评分(MOS)检验。18位以日语为母语的人被要求对合成语音样本做出高质量的判断,使用以下5种可能的回答:1 = Bad; 2 = Poor; 3 = Fair; 4 = Good; and 5 = Excellent。从评价集合中随机抽取20个话语,然后使用不同的模型进行合成。
表2
       
       表2给出了不同生成模型的推理速度和MOS测试结果。结果表明:(1)有短时傅立叶变换损失的系统比没有短时傅立叶变换损失的系统(即自回归WaveNet)表现更好。注意,大多数听者对自回归波网系统产生的高频噪声不满意。这可以用以下事实来解释:在WaveNet中,只有频段有限(70 - 8000Hz)的梅尔光谱图用于局部调节,而其他系统能够通过STFT损失直接学习全频带频率信息。(2)所提出的基于短时傅立叶变换损失的多分辨率模型比传统的单一短时傅立叶变换损失模型具有更高的感知质量(分别比较系统3和系统6与系统2和系统5)。这证实了多分辨率STFT损耗有效地捕获了语音信号的时频特性,使其能够获得更好的性能。(3)提出的对抗性损失在ClariNet上没有很好地工作。然而,当它与TTS框架相结合时,可以发现它的优点,这将在下一节中讨论。(4)最后,提出的Parallel WaveGAN达到4.06 MOS。虽然与ClariNet相比,Parallel WaveGAN的感知质量相对较差,但它产生语音信号的速度是ClariNet1.96倍。此外,该方法的优点在于训练过程简单。我们测量了获得最优模型的总训练时间,如表3所示。由于Parallel WaveGAN不需要任何复杂的密度蒸馏,优化只需要2.8天的训练时间,比自回归WaveNetClariNet分别快2.644.82倍。
表3
       

    4.3 从文本到语音

       为了验证所提方法作为TTS框架声码器的有效性,我们将Parallel WaveGAN与基于Transformer的参数估计相结合(《Attention is all you need》,《Neural speech synthesis with Transformer network》,《FastSpeech: Fast, robust and controllable text to speech》)。
       
       为了训练变换器,我们使用音素序列作为输入,从录音语音中提取梅尔谱图作为输出。该模型由一个六层编码器和一个六层解码器组成,每个编码器和解码器都是基于多头注意(有8个头)。配置遵循之前的工作(《FastSpeech: Fast, robust and controllable text to speech》),但模型被修改为接受重音作为音高重音语言(如日语)(《Investigation of enhanced Tacotron text-to-speech synthesis systems with self-attention for pitch accent language》)的外部输入。该模型使用RAdam优化器进行1000个周期的训练,并使用预热学习率调度(《Attention is all you need》)。初始学习率设置为1.0,使用动态批大小(平均64)策略稳定训练。
       
       在合成步骤中,输入的音素和重音序列通过Transformer TTS模型转换为相应的梅尔谱图。通过输入得到的声学参数,声码器模型生成时域语音信号。
       
       为了评估生成的语音样本的质量,我们进行了MOS测试。测试设置与4.2节中描述的相同,但我们在测试中使用了自回归WaveNet和经过多分辨率STFT损失训练的并行生成模型(分别在表2中描述的系统1346)。MOS试验结果如表4所示,其中可以总结如下:(1)有对抗损失的ClariNet比没有对抗损失的ClariNet表现更好,尽管在分析/合成情况下,他们的知觉质量几乎相同(系统3和系统4如表2所示)。这意味着使用对抗损失有利于提高模型对由声学模型引起的预测措辞误差的稳健性。(2)对抗性训练的优点也有利于提出的Parallel WaveGAN系统。因此,采用Transformer TTS模型的Parallel WaveNet达到了4.16 MOS,达到了最佳的基于蒸馏的Parallel WaveNet(ClariNet-GAN)。
       

  5 结论

       提出了一种基于GAN的无蒸馏、快速、小足迹的并行波形生成方法。通过联合优化波形域对抗损耗和多分辨率STFT损耗,我们的模型能够学习如何生成真实的波形,而不需要任何复杂的概率密度蒸馏。实验结果表明,该方法在基于TransformerTTS框架内达到了4.16 MOS,在仅1.44M模型参数的情况下,生成24kHz语音波形的速度是实时的28.68倍。未来的研究包括改进多分辨率短时傅里叶变换的辅助损失,以更好地捕捉语音特征(如引入相位相关损失),并验证其在各种语料库(包括表达语料库)中的性能。
       


推荐阅读
  • 在Android 4.4系统中,通过使用 `Intent` 对象并设置动作 `ACTION_GET_CONTENT` 或 `ACTION_OPEN_DOCUMENT`,可以从相册中选择图片并获取其路径。具体实现时,需要为 `Intent` 添加相应的类别,并处理返回的 Uri 以提取图片的文件路径。此方法适用于需要从用户相册中选择图片的应用场景,能够确保兼容性和用户体验。 ... [详细]
  • com.sun.javadoc.PackageDoc.exceptions()方法的使用及代码示例 ... [详细]
  • 单片微机原理P3:80C51外部拓展系统
      外部拓展其实是个相对来说很好玩的章节,可以真正开始用单片机写程序了,比较重要的是外部存储器拓展,81C55拓展,矩阵键盘,动态显示,DAC和ADC。0.IO接口电路概念与存 ... [详细]
  • 本指南从零开始介绍Scala编程语言的基础知识,重点讲解了Scala解释器REPL(读取-求值-打印-循环)的使用方法。REPL是Scala开发中的重要工具,能够帮助初学者快速理解和实践Scala的基本语法和特性。通过详细的示例和练习,读者将能够熟练掌握Scala的基础概念和编程技巧。 ... [详细]
  • 本文介绍了如何在iOS平台上使用GLSL着色器将YV12格式的视频帧数据转换为RGB格式,并展示了转换后的图像效果。通过详细的技术实现步骤和代码示例,读者可以轻松掌握这一过程,适用于需要进行视频处理的应用开发。 ... [详细]
  • 投融资周报 | Circle 达成 4 亿美元融资协议,唯一艺术平台 A 轮融资超千万美元 ... [详细]
  • 如果应用程序经常播放密集、急促而又短暂的音效(如游戏音效)那么使用MediaPlayer显得有些不太适合了。因为MediaPlayer存在如下缺点:1)延时时间较长,且资源占用率高 ... [详细]
  • Spring – Bean Life Cycle
    Spring – Bean Life Cycle ... [详细]
  • Android 构建基础流程详解
    Android 构建基础流程详解 ... [详细]
  • 在Android开发中,BroadcastReceiver(广播接收器)是一个重要的组件,广泛应用于多种场景。本文将深入解析BroadcastReceiver的工作原理、应用场景及其具体实现方法,帮助开发者更好地理解和使用这一组件。通过实例分析,文章详细探讨了静态广播的注册方式、生命周期管理以及常见问题的解决策略,为开发者提供全面的技术指导。 ... [详细]
  • 每日前端实战:148# 视频教程展示纯 CSS 实现按钮两侧滑入装饰元素的悬停效果
    通过点击页面右侧的“预览”按钮,您可以直接在当前页面查看效果,或点击链接进入全屏预览模式。该视频教程展示了如何使用纯 CSS 实现按钮两侧滑入装饰元素的悬停效果。视频内容具有互动性,观众可以实时调整代码并观察变化。访问以下链接体验完整效果:https://codepen.io/comehope/pen/yRyOZr。 ... [详细]
  • Vue ElementUI 实现邮箱地址自动补全功能详解 ... [详细]
  • 每日学术推荐:异质图神经网络在抽取式文档摘要中的应用研究
    在抽取式文档摘要任务中,学习跨句子关系是至关重要的一步。本文探讨了利用异质图神经网络来捕捉句子间复杂关系的有效方法。通过构建包含不同类型节点和边的图结构,模型能够更准确地识别和提取关键信息,从而生成高质量的摘要。实验结果表明,该方法在多个基准数据集上显著优于传统方法。 ... [详细]
  • 探索聚类分析中的K-Means与DBSCAN算法及其应用
    聚类分析是一种用于解决样本或特征分类问题的统计分析方法,也是数据挖掘领域的重要算法之一。本文主要探讨了K-Means和DBSCAN两种聚类算法的原理及其应用场景。K-Means算法通过迭代优化簇中心来实现数据点的划分,适用于球形分布的数据集;而DBSCAN算法则基于密度进行聚类,能够有效识别任意形状的簇,并且对噪声数据具有较好的鲁棒性。通过对这两种算法的对比分析,本文旨在为实际应用中选择合适的聚类方法提供参考。 ... [详细]
  • 从2019年AI顶级会议最佳论文,探索深度学习的理论根基与前沿进展 ... [详细]
author-avatar
-VIVEN-
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有