查看: 87|回复: 3

一些基础的训练原理整理

[复制链接]

1万

积分

425

帖子

1万

符石

玉皇大帝

Rank: 16Rank: 16Rank: 16Rank: 16

积分
16117

灌水之王论坛元老咸鱼勋章

发表于 前天 16:54 | 显示全部楼层 |阅读模式
本帖最后由 五折 于 2025-6-12 22:26 编辑

没啥可练的

DFL又是停止了更新
干脆整理一些偏向原理的东西跟大家分享
想到哪里写到哪里哈,随时补充修缮


架构概述
DF架构(DeepFake)
DF架构是一种较为简单的编码器-解码器架构,它包含:
- 一个共享的编码器(Encoder)
- 一个中间层(Inter)
- 两个独立的解码器(Decoder_src和Decoder_dst)

LIAE架构(Local-Image Adaptive Embedding)
LIAE架构是一种更复杂的架构,它包含:
- 一个共享的编码器(Encoder)
- 两个中间层(Inter_AB和Inter_B)
- 一个共享的解码器(Decoder)

详细训练步骤
1. 数据准备阶段
  1. # 初始化样本生成器
  2. training_data_src_path = self.training_data_src_path if not
  3. self.pretrain else self.get_pretraining_data_path()
  4. training_data_dst_path = self.training_data_dst_path if not
  5. self.pretrain else self.get_pretraining_data_path()

  6. # 设置样本生成器,处理源图像和目标图像
  7. self.set_training_data_generators([
  8.     SampleGeneratorFace(training_data_src_path, ...),  # 源图
  9.     像生成器
  10.     SampleGeneratorFace(training_data_dst_path, ...)   # 目标
  11.     图像生成器
  12. ])
复制代码
这一阶段主要完成:
1. 设置训练数据路径
2. 初始化样本生成器,用于加载和处理源图像和目标图像
3. 配置样本处理选项,如随机翻转、随机扭曲、HSV偏移等数据增强

2. 模型初始化阶段

DF架构初始化
  1. if 'df' in archi_type:
  2.     # 初始化编码器、中间层和解码器
  3.     self.encoder = model_archi.Encoder(in_ch=input_ch,
  4.     e_ch=e_dims, name='encoder')
  5.     encoder_out_ch = self.encoder.get_out_ch()*self.encoder.
  6.     get_out_res(resolution)**2
  7.    
  8.     self.inter = model_archi.Inter(in_ch=encoder_out_ch,
  9.     ae_ch=ae_dims, ae_out_ch=ae_dims, name='inter')
  10.     inter_out_ch = self.inter.get_out_ch()
  11.    
  12.     # 为源图像和目标图像分别初始化解码器
  13.     self.decoder_src = model_archi.Decoder
  14.     (in_ch=inter_out_ch, d_ch=d_dims, d_mask_ch=d_mask_dims,
  15.     name='decoder_src')
  16.     self.decoder_dst = model_archi.Decoder
  17.     (in_ch=inter_out_ch, d_ch=d_dims, d_mask_ch=d_mask_dims,
  18.     name='decoder_dst')
复制代码

LIAE架构初始化
  1. elif 'liae' in archi_type:
  2.     # 初始化编码器
  3.     self.encoder = model_archi.Encoder(in_ch=input_ch,
  4.     e_ch=e_dims, name='encoder')
  5.     encoder_out_ch = self.encoder.get_out_ch()*self.encoder.
  6.     get_out_res(resolution)**2
  7.    
  8.     # 初始化两个中间层
  9.     self.inter_AB = model_archi.Inter(in_ch=encoder_out_ch,
  10.     ae_ch=ae_dims, ae_out_ch=ae_dims*2, name='inter_AB')
  11.     self.inter_B = model_archi.Inter(in_ch=encoder_out_ch,
  12.     ae_ch=ae_dims, ae_out_ch=ae_dims*2, name='inter_B')
  13.    
  14.     inter_out_ch = self.inter_AB.get_out_ch()
  15.     inters_out_ch = inter_out_ch*2
  16.    
  17.     # 初始化共享解码器
  18.     self.decoder = model_archi.Decoder(in_ch=inters_out_ch,
  19.     d_ch=d_dims, d_mask_ch=d_mask_dims, name='decoder')
复制代码
这一阶段主要完成:
1. 根据选择的架构类型(DF或LIAE)初始化相应的模型组件
2. 设置各组件的通道数、维度等参数
3. 如果启用GAN,还会初始化判别器

3. 优化器初始化阶段
  1. # 初始化优化器
  2. lr=5e-5
  3. if self.options['lr_dropout'] in ['y','cpu'] and not self.
  4. pretrain:
  5.     lr_cos = 500
  6.     lr_dropout = 0.3
  7. else:
  8.     lr_cos = 0
  9.     lr_dropout = 1.0
  10. OptimizerClass = nn.AdaBelief if adabelief else nn.RMSprop
  11. clipnorm = 1.0 if self.options['clipgrad'] else 0.0

  12. # 设置可训练权重
  13. if 'df' in archi_type:
  14.     self.src_dst_saveable_weights = self.encoder.get_weights
  15.     () + self.inter.get_weights() + self.decoder_src.
  16.     get_weights() + self.decoder_dst.get_weights()
  17.     self.src_dst_trainable_weights = self.
  18.     src_dst_saveable_weights
  19. elif 'liae' in archi_type:
  20.     self.src_dst_saveable_weights = self.encoder.get_weights
  21.     () + self.inter_AB.get_weights() + self.inter_B.
  22.     get_weights() + self.decoder.get_weights()
  23.     if random_warp:
  24.         self.src_dst_trainable_weights = self.
  25.         src_dst_saveable_weights
  26.     else:
  27.         self.src_dst_trainable_weights = self.encoder.
  28.         get_weights() + self.inter_B.get_weights() + self.
  29.         decoder.get_weights()

  30. # 初始化优化器
  31. self.src_dst_opt = OptimizerClass(lr=lr,
  32. lr_dropout=lr_dropout, lr_cos=lr_cos, clipnorm=clipnorm,
  33. name='src_dst_opt')
  34. self.src_dst_opt.initialize_variables(self.
  35. src_dst_saveable_weights, vars_on_cpu=optimizer_vars_on_cpu,
  36. lr_dropout_on_cpu=self.options['lr_dropout']=='cpu')
复制代码
这一阶段主要完成:
1. 设置学习率、学习率衰减等优化器参数
2. 根据架构类型确定可训练权重
3. 初始化优化器(AdaBelief或RMSprop)
4. 如果启用GAN,还会初始化GAN判别器的优化器

4. 计算图构建阶段
DF架构的前向传播
  1. if 'df' in archi_type:
  2.     # 编码
  3.     gpu_src_code = self.inter(self.encoder(gpu_warped_src))
  4.     gpu_dst_code = self.inter(self.encoder(gpu_warped_dst))
  5.    
  6.     # 解码
  7.     gpu_pred_src_src, gpu_pred_src_srcm = self.decoder_src
  8.     (gpu_src_code)  # 源到源的重建
  9.     gpu_pred_dst_dst, gpu_pred_dst_dstm = self.decoder_dst
  10.     (gpu_dst_code)  # 目标到目标的重建
  11.     gpu_pred_src_dst, gpu_pred_src_dstm = self.decoder_src
  12.     (gpu_dst_code)  # 目标到源的转换(换脸结果)
复制代码

LIAE架构的前向传播
  1. elif 'liae' in archi_type:
  2.     # 编码
  3.     gpu_src_code = self.encoder(gpu_warped_src)
  4.     gpu_src_inter_AB_code = self.inter_AB(gpu_src_code)
  5.     gpu_src_code = tf.concat([gpu_src_inter_AB_code,
  6.     gpu_src_inter_AB_code], nn.conv2d_ch_axis)
  7.    
  8.     gpu_dst_code = self.encoder(gpu_warped_dst)
  9.     gpu_dst_inter_B_code = self.inter_B(gpu_dst_code)
  10.     gpu_dst_inter_AB_code = self.inter_AB(gpu_dst_code)
  11.     gpu_dst_code = tf.concat([gpu_dst_inter_B_code,
  12.     gpu_dst_inter_AB_code], nn.conv2d_ch_axis)
  13.     gpu_src_dst_code = tf.concat([gpu_dst_inter_AB_code,
  14.     gpu_dst_inter_AB_code], nn.conv2d_ch_axis)
  15.    
  16.     # 解码
  17.     gpu_pred_src_src, gpu_pred_src_srcm = self.decoder
  18.     (gpu_src_code)  # 源到源的重建
  19.     gpu_pred_dst_dst, gpu_pred_dst_dstm = self.decoder
  20.     (gpu_dst_code)  # 目标到目标的重建
  21.     gpu_pred_src_dst, gpu_pred_src_dstm = self.decoder
  22.     (gpu_src_dst_code)  # 目标到源的转换(换脸结果)
复制代码

这一阶段主要完成:
1. 构建模型的前向传播计算图
2. DF架构:通过共享编码器和中间层,但使用独立解码器实现换脸
3. LIAE架构:通过共享编码器和解码器,但使用两个中间层(Inter_AB和Inter_B)实现换脸

5. 损失计算阶段
  1. # 计算源图像和目标图像的损失
  2. if resolution < 256:
  3.     gpu_src_loss = tf.reduce_mean(10*nn.dssim
  4.     (gpu_target_src_masked_opt, gpu_pred_src_src_masked_opt,
  5.     max_val=1.0, filter_size=int(resolution/11.6)), axis=[1])
  6. else:
  7.     gpu_src_loss = tf.reduce_mean(5*nn.dssim
  8.     (gpu_target_src_masked_opt, gpu_pred_src_src_masked_opt,
  9.     max_val=1.0, filter_size=int(resolution/11.6)), axis=[1])
  10.     gpu_src_loss += tf.reduce_mean(5*nn.dssim
  11.     (gpu_target_src_masked_opt, gpu_pred_src_src_masked_opt,
  12.     max_val=1.0, filter_size=int(resolution/23.2)), axis=[1])

  13. gpu_src_loss += tf.reduce_mean(10*tf.square
  14. (gpu_target_src_masked_opt - gpu_pred_src_src_masked_opt),
  15. axis=[1,2,3])

  16. # 如果启用眼睛嘴巴优先级
  17. if eyes_mouth_prio:
  18.     gpu_src_loss += tf.reduce_mean(300*tf.abs
  19.     (gpu_target_src*gpu_target_srcm_em -
  20.     gpu_pred_src_src*gpu_target_srcm_em), axis=[1,2,3])

  21. # 遮罩损失
  22. gpu_src_loss += tf.reduce_mean(10*tf.square(gpu_target_srcm -
  23. gpu_pred_src_srcm), axis=[1,2,3])

  24. # 风格损失
  25. face_style_power = self.options['face_style_power'] / 100.0
  26. if face_style_power != 0 and not self.pretrain:
  27.     gpu_src_loss += nn.style_loss(...)

  28. # 背景风格损失
  29. bg_style_power = self.options['bg_style_power'] / 100.0
  30. if bg_style_power != 0 and not self.pretrain:
  31.     gpu_src_loss += ...

  32. # 目标图像损失计算(类似源图像)
  33. ...

  34. # 总损失
  35. gpu_G_loss = gpu_src_loss + gpu_dst_loss

  36. # GAN损失(如果启用)
  37. if gan_power != 0:
  38.     gpu_G_loss += gan_power*(DLoss(gpu_pred_src_src_d_ones,
  39.     gpu_pred_src_src_d) + DLoss(gpu_pred_src_src_d2_ones,
  40.     gpu_pred_src_src_d2))
复制代码

这一阶段主要完成:
1. 计算源图像和目标图像的重建损失(DSSIM和MSE)
2. 计算遮罩损失
3. 如果启用,计算风格损失、GAN损失等
4. 汇总总损失

6. 梯度计算和优化器更新阶段
  1. # 计算梯度
  2. gpu_G_loss_gvs += [nn.gradients(gpu_G_loss, self.
  3. src_dst_trainable_weights)]

  4. # 在CPU上拼接不同GPU的结果
  5. with tf.devICE(f'/CPU:0'):
  6.     pred_src_src = nn.concat(gpu_pred_src_src_list, 0)
  7.     pred_dst_dst = nn.concat(gpu_pred_dst_dst_list, 0)
  8.     pred_src_dst = nn.concat(gpu_pred_src_dst_list, 0)
  9.     pred_src_srcm = nn.concat(gpu_pred_src_srcm_list, 0)
  10.     pred_dst_dstm = nn.concat(gpu_pred_dst_dstm_list, 0)
  11.     pred_src_dstm = nn.concat(gpu_pred_src_dstm_list, 0)

  12. # 平均梯度并创建优化器更新操作
  13. with tf.device(models_opt_device):
  14.     src_loss = tf.concat(gpu_src_losses, 0)
  15.     dst_loss = tf.concat(gpu_dst_losses, 0)
  16.     src_dst_loss_gv_op = self.src_dst_opt.get_update_op(nn.
  17.     average_gv_list(gpu_G_loss_gvs))
复制代码

这一阶段主要完成:
1. 计算损失相对于可训练权重的梯度
2. 在多GPU训练时,合并不同GPU上的结果
3. 创建优化器更新操作

7. 训练函数定义阶段
  1. # 定义源图像和目标图像的训练函数
  2. def src_dst_train(warped_src, target_src, target_srcm,
  3. target_srcm_em, warped_dst, target_dst, target_dstm,
  4. target_dstm_em):
  5.     s, d = nn.tf_sess.run([src_loss, dst_loss,
  6.     src_dst_loss_gv_op],
  7.                          feed_dict={self.warped_src:
  8.                          warped_src,
  9.                                    self.target_src:
  10.                                    target_src,
  11.                                    self.target_srcm:
  12.                                    target_srcm,
  13.                                    self.target_srcm_em:
  14.                                    target_srcm_em,
  15.                                    self.warped_dst:
  16.                                    warped_dst,
  17.                                    self.target_dst:
  18.                                    target_dst,
  19.                                    self.target_dstm:
  20.                                    target_dstm,
  21.                                    self.target_dstm_em:
  22.                                    target_dstm_em})[:2]
  23.     return s, d
  24. self.src_dst_train = src_dst_train

  25. # 如果启用GAN,定义判别器训练函数
  26. if gan_power != 0:
  27.     def D_src_dst_train(warped_src, target_src, target_srcm,
  28.     target_srcm_em, warped_dst, target_dst, target_dstm,
  29.     target_dstm_em):
  30.         nn.tf_sess.run([src_D_src_dst_loss_gv_op], feed_dict=
  31.         {...})
  32.     self.D_src_dst_train = D_src_dst_train
复制代码

这一阶段主要完成:
1. 定义实际的训练函数,用于执行前向传播、损失计算和反向传播
2. 如果启用GAN,定义判别器的训练函数

8. 单次迭代训练阶段
  1. def onTrainOneIter(self):
  2.     # 生成下一批样本
  3.     ((warped_src, target_src, target_srcm, target_srcm_em),
  4.      (warped_dst, target_dst, target_dstm, target_dstm_em)) =
  5.      self.generate_next_samples()
  6.    
  7.     # 训练源图像和目标图像
  8.     src_loss, dst_loss = self.src_dst_train(warped_src,
  9.     target_src, target_srcm, target_srcm_em,
  10.                                            warped_dst,
  11.                                            target_dst,
  12.                                            target_dstm,
  13.                                            target_dstm_em)
  14.    
  15.     # 如果启用真脸判别器,训练判别器
  16.     if self.options['true_face_power'] != 0 and not self.
  17.     pretrain:
  18.         self.D_train(warped_src, warped_dst)
  19.    
  20.     # 如果启用GAN,训练GAN判别器
  21.     if self.gan_power != 0:
  22.         self.D_src_dst_train(warped_src, target_src,
  23.         target_srcm, target_srcm_em,
  24.                             warped_dst, target_dst,
  25.                             target_dstm, target_dstm_em)
  26.    
  27.     return (('src_loss', np.mean(src_loss)), ('dst_loss', np.
  28.     mean(dst_loss)))
复制代码

这一阶段主要完成:
1. 生成下一批训练样本
2. 执行模型训练
3. 如果启用,训练判别器
4. 返回损失值用于显示

9. 模型保存和加载阶段
  1. # 加载/初始化所有模型/优化器权重
  2. for model, filename in io.progress_bar_generator(self.
  3. model_filename_list, "初始化模型"):
  4.     # 判断是否需要初始化
  5.     do_init = self.is_first_run()
  6.    
  7.     # 尝试加载权重
  8.     if not do_init:
  9.         do_init = not model.load_weights(self.
  10.         get_strpath_storage_for_file(filename))
  11.    
  12.     # 如果需要初始化,则初始化权重
  13.     if do_init:
  14.         model.init_weights()

  15. # 保存模型
  16. def onSave(self):
  17.     for model, filename in io.progress_bar_generator(self.
  18.     get_model_filename_list(), "Saving", leave=False):
  19.         model.save_weights(self.get_strpath_storage_for_file
  20.         (filename))
复制代码
这一阶段主要完成:
1. 加载预训练模型权重或初始化新权重
2. 定义模型保存函数

10. 预览生成阶段
  1. def onGetPreview(self, samples, for_history=False):
  2.     # 解包样本
  3.     ((warped_src, target_src, target_srcm, target_srcm_em),
  4.      (warped_dst, target_dst, target_dstm, target_dstm_em)) =
  5.      samples
  6.    
  7.     # 生成预览图像
  8.     S, D, SS, DD, DDM, SD, SDM = [np.clip(nn.to_data_format
  9.     (x, "NHWC", self.model_data_format), 0.0, 1.0)
  10.                                 for x in ([target_src,
  11.                                 target_dst] + self.AE_view
  12.                                 (target_src, target_dst))]
  13.    
  14.     # 生成预览结果
  15.     result = []
  16.     # ...
  17.     return result
复制代码

这一阶段主要完成:
1. 生成预览图像,用于显示训练进度
2. 包括源图像、目标图像、重建图像和换脸结果

DF和LIAE架构的主要区别
1. 架构结构
- DF架构 :使用一个共享的编码器和中间层,但有两个独立的解码器(一个用于源图像,一个用于目标图像)
- LIAE架构 :使用一个共享的编码器和解码器,但有两个中间层(Inter_AB和Inter_B)

2. 编码和解码过程
- DF架构 :
  1.   源图像 → 编码器 → 中间层 → 解码器_源 → 重建源图像
  2.   目标图像 → 编码器 → 中间层 → 解码器_目标 → 重建目标图像
  3.   目标图像 → 编码器 → 中间层 → 解码器_源 → 换脸结果
复制代码

- LIAE架构 :
  1.   源图像 → 编码器 → Inter_AB → [Inter_AB, Inter_AB] → 解码器 → 重
  2.   建源图像
  3.   目标图像 → 编码器 → [Inter_B, Inter_AB] → 解码器 → 重建目标图像
  4.   目标图像 → 编码器 → [Inter_AB, Inter_AB] → 解码器 → 换脸结果
复制代码

3. 训练特点
- DF架构 :训练所有组件(编码器、中间层、两个解码器)
- LIAE架构 :如果启用随机扭曲,训练所有组件;否则,只训练编码器、Inter_B和解码器

4. 适用场景
- DF架构 :更适合源和目标人脸差异较小的情况
- LIAE架构 :更适合处理源和目标人脸差异较大的情况,能更好地保留身份特征

总结
deepfacelab中的DF和LIAE架构都是基于编码器-解码器结构的深度学习模型,但它们在架构设计和训练过程上有明显区别。DF架构使用独立的解码器来处理源和目标图像,而LIAE架构使用共享解码器但有两个中间层来处理不同的身份信息。这两种架构各有优势,用户可以根据具体的换脸需求选择合适的架构。



补充一下,关于Liae模型删AB的原理解释:


inter_AB.npy文件的作用
在LIAE(Local Identity and Appearance Encoder)架构中, inter_AB.npy 是一个关键组件的权重文件,它存储了 inter_AB 模块的参数。从代码中可以看出:
1. LIAE架构使用了两个中间编码器: inter_B 和 inter_AB
   - inter_B :处理身份特征(identity features)
   - inter_AB :处理外观特征(appearance features)

2. 在前向传播过程中,LIAE架构的工作流程是:
  1.   # 编码
  2.    gpu_dst_code = self.encoder(self.warped_dst)
  3.    gpu_dst_inter_B_code = self.inter_B(gpu_dst_code)
  4.    gpu_dst_inter_AB_code = self.inter_AB(gpu_dst_code)
  5.    
  6.    # 合并特征
  7.    gpu_dst_code = tf.concat([gpu_dst_inter_B_code,
  8.    gpu_dst_inter_AB_code], nn.conv2d_ch_axis)
  9.    gpu_src_dst_code = tf.concat([gpu_dst_inter_B_code,
  10.    gpu_dst_inter_AB_code], nn.conv2d_ch_axis)
  11.    
  12.    # 解码生成结果
  13.    gpu_pred_src_dst, gpu_pred_src_dstm = self.decoder
  14.    (gpu_src_dst_code)
复制代码

删除inter_AB.npy的影响
当你删除 inter_AB.npy 文件时,会产生以下影响:
1. 模型重新初始化 :根据代码中的加载逻辑,当模型无法加载权重文件时,它会重新初始化相应组件的权重:
  1.    if not do_init:
  2.        do_init = not model.load_weights(self.
  3.        get_strpath_storage_for_file(filename))
  4.    
  5.    if do_init:
  6.        model.init_weights()
复制代码

2. 外观特征重置 :由于 inter_AB 模块负责处理外观特征,删除其权重文件会导致这部分特征被重置为随机初始化的状态。
3. 抑制DST脸型特征 :这就是为什么网上教程说删除 inter_AB.npy 可以抑制生成的人脸过于趋向DST(目标人脸)。因为:
   - inter_AB 模块主要负责捕获和转移外观特征(如肤色、纹理等)
   - 当这些特征被重置时,模型会减少对DST脸型特征的依赖
   - 重新训练后,模型会重新学习外观特征,但此时可能会更多地保留SRC(源人脸)的结构特征
4. 训练进度部分丢失 :删除文件后,模型需要重新学习外观特征的转换,这意味着在这方面的训练进度会部分丢失。

为什么这种方法有效
在LIAE架构中,身份和外观特征是分开处理的:
- inter_B 保留了身份信息(脸型结构)
- inter_AB 处理外观信息(肤色、纹理等)
当你删除 inter_AB.npy 时,模型会通过 inter_B保留已学习的身份特征,但重置外观特征的处理。这样在继续训练时,模型会在保留原有身份特征的基础上重新学习外观特征,从而可能减少DST脸型对结果的影响。

Zhatv换脸论坛免责声明
全站默认解压密码:zhatv.cn
【Zhatv】论坛里的文章仅代表作者本人的观点,与本网站立场无关。
所有文章、内容、信息、资料,都不保证其准确性、完整性、有效性、时效性,请依据情况自身做出判断。
因阅读本站内容而被误导等其他因素所造成的损失责任自负,【Zhatv】不承担任何责任。
高性能DFL训练云主机

通用直播丹代练

QQ:1453174

1140

积分

30

帖子

426

符石

化神丹师

Rank: 5

积分
1140
发表于 前天 22:36 | 显示全部楼层
本帖最后由 51816588 于 2025-6-12 22:39 编辑

DFL又是停止了更新,可以用ICE,
这个论坛不就是 ICE 用的多吗
难道管理都不用 ICE 吗
回复

使用道具 举报

1万

积分

425

帖子

1万

符石

玉皇大帝

Rank: 16Rank: 16Rank: 16Rank: 16

积分
16117

灌水之王论坛元老咸鱼勋章

 楼主| 发表于 前天 22:45 | 显示全部楼层
51816588 发表于 2025-6-12 22:36
DFL又是停止了更新,可以用ICE,
这个论坛不就是 ICE 用的多吗
难道管理都不用 ICE 吗 ...

没有官方支持、没开源、没有完善的说明文档
只用ICE软件本身,不怎么玩木兰模型,尤其是木兰的新构架。。。

评分

参与人数 1金钱 +1 收起 理由
davio + 1 是啊是啊,好可惜

查看全部评分

高性能DFL训练云主机

通用直播丹代练

QQ:1453174
回复

使用道具 举报

7157

积分

97

帖子

5739

符石

太乙金仙

Rank: 10Rank: 10

积分
7157

土豪勋章

发表于 前天 22:47 | 显示全部楼层
51816588 发表于 2025-6-12 22:36
DFL又是停止了更新,可以用ICE,
这个论坛不就是 ICE 用的多吗
难道管理都不用 ICE 吗 ...

ICE太封闭了
木兰效率应该更高的但是没有什么教程
软件又是闭源,基本不可能自己看代码学习使用
所以......
回复

使用道具 举报

小黑屋|ZhaTV ( 滇ICP备15003127号-4 ) |网站地图

GMT+8, 2025-6-14 01:53

Powered by Zhatv.cn

© 2022-2023

快速回复 返回顶部 返回列表