<jupyter_start><jupyter_text>川普, 来, 跟爷一起说  WeChaty + PaddleHub  一、项目背景本项目有趣的地方在于可以使用自己说话的语音信息和其他人的照片, 逼真地生成一幅他人模仿你说话的影像。其原理是根据音频直接合成唇形动作。语音信息通过wechaty终端传入，再基于PaddleGAN的Wav2Lip模型直接端到端的生成。本项目以特朗普为例，我们说啥就让特朗普跟着说啥，不仅支持语音信息, 中英文本，还可以传入带有文字的图片。 功能上不仅能增加一定的趣味，给用户一种新的AI体验， 同时用户能基于此，扩展到其他应用，比如结合翻译模型识别图片上的外文，生成有声小说，创建点读笔应用，躺着听论文等等。本项目是参加【**AI ChatBot 创意赛**】的作品，PaddleHub携手开源聊天机器人框架WeChaty带来 AI ChatBot创意赛，为AI算法工程师提供一个全新的应用场景：Chatbot （Conversational AI），同时也为Chatbot 开发者提供一个全新的AI能力平台，拓宽视野，为未来设计更加强大的 Chatbot 提供一扇门。本项目主要难点是一方面要融合OCR， GAN， Parakeet三大模块，在兼容部署环境上和代码集成上有一定的挑战， 另一方面PaddlePaddle目前没有开源中文语音合成的模型，目前只能使用ZHTTS临时方案，后期若有时间可将此模型迁移至PaddlePaddle。关于Wechaty的安装和使用请参考我另一篇： [微信医聊自动问答 WeChaty + PaddleHub ](https://aistudio.baidu.com/aistudio/projectdetail/1868162)参考项目：[Parakeet：飞桨，你是个成熟的框架了，要学会自己读论文](https://aistudio.baidu.com/aistudio/projectdetail/676162)[基于PaddleGAN快速让你的照片动起来](http://https://aistudio.baidu.com/aistudio/projectdetail/1773529) 由于B站多次上传不成功，请在左侧下在trump.mp4本地观看。  二、关于WeChaty和PaddleHub

wechaty（https://github.com/wechaty/wechaty）是一款开源的微信SDK，它基于微信公开的API，对接口进行了一系列的封装，提供一系列简单的接口，然后开发者可以在其之上进行微信机器人的开发。

PaddleHub 是基于 PaddlePaddle 开发的预训练模型管理工具，可以借助预训练模型更便捷地开展迁移学习工作，旨在让 PaddlePaddle 生态下的开发者更便捷体验到大规模预训练模型的价值。

关于二者的结合使用请参考我的另一个公开项目：
	[微信医聊自动问答 WeChaty + PaddleHub](https://aistudio.baidu.com/aistudio/projectdetail/1868162)
    
这里使用docker脚本可方便快速部署。请将your_token处替换成你的WeChaty token (**puppet_padlocal_xxxxxxxxxxxxx)**

```
export WECHATY_LOG="verbose"
export WECHATY_PUPPET="wechaty-puppet-padlocal"
export WECHATY_PUPPET_PADLOCAL_TOKEN="<PASSWORD>"

export WECHATY_PUPPET_SERVER_PORT="8080"
export WECHATY_TOKEN="<PASSWORD>"

docker run -ti \
  --name wechaty_puppet_service_token_gateway \
  --rm \
  -e WECHATY_LOG \
  -e WECHATY_PUPPET \
  -e WECHATY_PUPPET_PADLOCAL_TOKEN \
  -e WECHATY_PUPPET_SERVER_PORT \
  -e WECHATY_TOKEN \
  -p "$WECHATY_PUPPET_SERVER_PORT:$WECHATY_PUPPET_SERVER_PORT" \
  wechaty/wechaty:latest
~                        
```

运行成功后如下图:


![](https://ai-studio-static-online.cdn.bcebos.com/73f123bb9b37410eb49f834dc512226e014f3f53a77d42888b201833e8ef6942)
  三、安装环境以及python的依赖包`!pip install -r PaddleGAN/requirements.txt imageio-ffmpeg``!pip install -U paddlehub``!pip install ruamel  -U paddle-parakeet``!pip install shapely pyclipper -i https://pypi.tuna.tsinghua.edu.cn/simple `为了将微信端slk格式的语音文件转为mp3, 需要用到silk-v3-decoder第三方库, 使用的命令如下:`sh converter.sh 33921FF3774A773BB193B6FD4AD7C33E.slk mp3`<jupyter_code>!git clone https://gitee.com/paddlepaddle/PaddleGAN
!pip install -r PaddleGAN/requirements.txt imageio-ffmpeg moviepy
#安装silk-v3-decoder
!git clone https://gitee.com/xiangjilexiaochou/silk-v3-decoder.git<jupyter_output>Cloning into 'silk-v3-decoder'...
remote: Enumerating objects: 697, done.[K
remote: Counting objects: 100% (697/697), done.[K
remote: Compressing objects: 100% (306/306), done.[K
remote: Total 697 (delta 388), reused 697 (delta 388), pack-reused 0[K
Receiving objects: 100% (697/697), 75.21 MiB | 523.00 KiB/s, done.
Resolving deltas: 100% (388/388), done.
Checking connectivity... done.<jupyter_text>四、Wav2Lip模型介绍Wav2Lip唇形同步示意图* 在训练阶段，生成器模型输入包含两部分（视频帧序列和音频），分别通过Face encoder和Audio encoder得到特征信息，并进行融合，再通过Face decoder获得唇形和音频同步的图像帧。把原始视频帧和生成图像帧输入到视觉质量判别器中，二分类结果表示是真实的图像、还是生成的图片，进而提高图像质量。把生成图像帧和音频输入到预先训练好的唇形同步判别器中，判断唇形是否生成的精准，在训练过程中，唇形同步判别器参数会一直被冻结，不参与训练、更新。* 在推理阶段，提供一段音频和视频(或图像、动画)即可合成唇形同步视频。Wav2Lip唇形同步设计方案av2Lip实现唇形与语音精准同步突破的关键在于，它采用了唇形同步判别器，以强制生成器持续产生准确而逼真的唇部运动。此外，它通过在鉴别器中使用多个连续帧而不是单个帧，并使用视觉质量损失（而不仅仅是对比损失）来考虑时间相关性，从而改善了视觉质量。Wav2Lip适用于任何人脸、任何语言，对任意视频都能达到很高都准确率，可以无缝地与原始视频融合，还可以用于转换动画人脸。使用一个强有力的嘴唇同步鉴别器迫使发生器产生精确的嘴唇形状。然而，它有时会导致变形区域稍微模糊或包含轻微的伪像。为了减轻这种微小的质量损失，我们在 GAN 设置中训练了一个简单的视觉质量鉴别器和生成器。因此，我们有两个鉴别器，一个用于同步精度，另一个用于更好的视觉质量。一方面，唇同步鉴别器不需要进一步微调，即训练过程权重被冻结。另一方面，由于视觉质量鉴别器不对嘴唇同步进行任何检查，并且只惩罚不现实的人脸生成，所以它是在生成的人脸上进行训练的。Wav2Lip模型结构如下图所示：图6：Wav2Lip结构图  图6中下半部分被遮挡的目标人脸作为姿态先验输入，这是至关重要的，因为它允许生成的人脸区域无缝地粘回原始视频，不需要进一步的后期处理。  五、将Wechaty接收到的语音格式转为mp3wav2lip代码无法直接读取slk格式文件，所以需要先借用工具转换一下。wechaty没有提供发送语音的接口，如果将slk或者mp3发回去，只能是以文件的形式。<jupyter_code>%cd silk-v3-decoder
!sh converter.sh ../message-7116130031518557320-audio.slk mp3<jupyter_output><empty_output><jupyter_text>六、将Wechaty接收到的文本信息转为语音**Parakeet模型库介绍**Parakeet是飞桨近期上新的语音合成套件，用于实现端到端的语音合成。如果您使用过各类读书app或者某些浏览器、插件的朗读功能，这些都是典型的TTS（Text To Speech）场景。本项目将使用WaveFlow语音合成模型完成相关任务，并结合Transformer TTS验证语音合成效果，比如输入“Hello World”，文字转语音效果如下：**WaveFlow模型**WaveFlow来自百度研究院的论文WaveFlow: A Compact Flow-based Model for Raw Audio，飞桨复现了该语音合成模型。根据官网介绍，只有5.9M参数量，比经典的WaveGlow语音合成模型小了15倍，同时语音合成效果也非常好。WaveFlow和WaveGlow都是基于流的生成模型，它和GAN都属于生成模型家族。需要注意的是，WaveFlow是个vocoder（声码器，一种将声学参数转换成语音波形的工具）,不能直接实现文字转语音，需要与Parakeet库中的TTS模型Deep Voice 3、Transformer TTS或FastSpeech模型结合，实现文字转语音的拟声合成。**Transformer TTS文字转语音模型**Parakeet使用PaddlePaddle动态图复现了Transformer TTS, 根据论文Neural Speech Synthesis with Transformer Network实现了基于Transformer的语音合成系统。学习资料:[WaveFlow论文地址](http://arxiv.org/abs/1912.01219)[WaveFlow: A Compact Flow-Based Model for Raw Audio](http://research.baidu.com/Blog/index-view?id=139)[Transformer TTS论文地址](http://arxiv.org/abs/1809.08895)[基于Transformer的语音合成系统](http://https://zhuanlan.zhihu.com/p/66931179)<jupyter_code>#下载预训练权重到pretrained_models
# !wget https://paddlespeech.bj.bcebos.com/Parakeet/transformer_tts_ljspeech_ckpt_0.2.zip
# !wget https://paddlespeech.bj.bcebos.com/Parakeet/waveflow_res128_ljspeech_ckpt_0.2.zip
#运行时需要先安装nltk库
import nltk
nltk.download("punkt")
nltk.download("cmudict")
#这里需要用到config文件, 可以从github里直接拷贝过来
import parakeet
from parakeet.frontend import English
from parakeet.models import TransformerTTS
from pathlib import Path
import yacs
from tts_config import get_cfg_defaults
from wavflow_config import get_cfg_defaults as wav_get_cfg_defaults
import soundfile as sf
from parakeet.models import ConditionalWaveFlow, WaveFlow
import time

#tts模型
frontend = English()
checkpoint_dir = Path("pretrained_models/transformer_tts_ljspeech_ckpt_0.2")
checkpoint_path = str(checkpoint_dir / "step-310000")
tconfig = get_cfg_defaults()
tconfig.merge_from_file(str(checkpoint_dir / "config.yaml"))
model = TransformerTTS.from_pretrained(
    frontend, tconfig, checkpoint_path)
model.eval()

#waveflow模型
w_checkpoint_dir = Path("pretrained_models/waveflow_ljspeech_ckpt_0.2")
w_checkpoint_path = str(w_checkpoint_dir / "step-2000000")
wconfig = wav_get_cfg_defaults()
wconfig.merge_from_file(str(w_checkpoint_dir / "config.yaml"))
vocoder = ConditionalWaveFlow.from_pretrained(wconfig, w_checkpoint_path)
vocoder.eval()


def infer(txt, out_path):
    stime = time.time()
    outputs = model.predict(sentence)
    mel_output = outputs["mel_output"]
    audio = vocoder.predict(mel_output.T)
    sf.write(out_path, audio, wconfig.data.sample_rate)
    print(time.time() - stime)

sentence = "Printing, in the only sense with which we are at present concerned, differs from most if not from all the arts and crafts represented in the Exhibition"
infer(sentence, "output.wav")<jupyter_output>[checkpoint] Rank 0: loaded model from pretrained_models/transformer_tts_ljspeech_ckpt_0.2/step-310000.pdparams<jupyter_text>**ZHTTS模型**因为Parakeet目前还不支持中文，后续有时间可以用中文数据集训练一下。这里暂时使用zhtts， 因为里面用到了tensorflow,所以下面的代码无法在AISTUDIO运行, 建议本地使用。zhtts在CPU上实时运行的中文语音合成系统（一个简单的示例，使用 Fastspeech2 + MbMelGan），但总体效果离“能用”还有很大差距。Github地址: https://github.com/Jackiexiao/zhtts安装方式: `!pip install zhtts --user````import zhttsdef is_chinese(string):    """    检查整个字符串是否包含中文    :param string: 需要检查的字符串    :return: bool    """    for ch in string:        if u'\u4e00' <= ch <= u'\u9fff':            return True    return Falsetext = "2020年，这是一个开源的端到端中文语音合成系统"tts = zhtts.TTS()  use fastspeech2 by defaulttts.text2wav(text, "demo.wav")```  七、将Wechaty接收到的带文字的图片转为语音 OCR的应用场景根据OCR的应用场景而言，我们可以大致分成识别特定场景下的专用OCR以及识别多种场景下的通用OCR。就前者而言，证件识别以及车牌识别就是专用OCR的典型案例。针对特定场景进行设计、优化以达到最好的特定场景下的效果展示。那通用的OCR就是使用在更多、更复杂的场景下，拥有比较好的泛性。在这个过程中由于场景的不确定性，比如：图片背景极其丰富、亮度不均衡、光照不均衡、残缺遮挡、文字扭曲、字体多样等等问题，会带来极大的挑战。现PaddleHub为大家提供的是超轻量级中文OCR模型，聚焦特定的场景，支持中英文数字组合式别、竖排文字识别、长文本识别场景。 OCR的技术路线典型的OCR技术路线如下图所示：![](https://ai-studio-static-online.cdn.bcebos.com/3dce6cab703e48139a2a9c3022ff9c55336be8179d6c452a9f3a41739eb46597)其中OCR识别的关键路径在于文字检测和文本识别部分，这也是深度学习技术可以充分发挥功效的地方。PaddleHub为大家开源的预训练模型的网络结构是Differentiable Binarization+ CRNN，基于icdar2015数据集下进行的训练。首先，DB是一种基于分割的文本检测算法。在各种文本检测算法中，基于分割的检测算法可以更好地处理弯曲等不规则形状文本，因此往往能取得更好的检测效果。但分割法后处理步骤中将分割结果转化为检测框的流程复杂，耗时严重。因此作者提出一个可微的二值化模块（Differentiable Binarization，简称DB），将二值化阈值加入训练中学习，可以获得更准确的检测边界，从而简化后处理流程。DB算法最终在5个数据集上达到了state-of-art的效果和性能。参考论文：[Real-time Scene Text Detection with Differentiable Binarization](https://arxiv.org/abs/1911.08947)下图是DB算法的结构图：![](https://ai-studio-static-online.cdn.bcebos.com/f7cb17481e84457d90f3ac4e15bf1e53e20ff53096904e36a10d048f67abddaa)接着，我们使用 CRNN（Convolutional Recurrent Neural Network）即卷积递归神经网络，是DCNN和RNN的组合，专门用于识别图像中的序列式对象。与CTC loss配合使用，进行文字识别，可以直接从文本词级或行级的标注中学习，不需要详细的字符级的标注。参考论文:[An end-to-end trainable neural network for image-based sequence recognition and its application to scene text recognition](https://arxiv.org/pdf/1507.05717.pdf)下图是CRNN的网络结构图：   PaddleHub继承了PaddleOCR部分文字识别模型，虽功能上不支持空格符识别，文本角度分类等， 有一定局限性，但是能满足本项目演示的需要了。最大的优势是可以支持一键预测，非常方便快捷。<jupyter_code>import paddlehub as hub
import cv2

ocr = hub.Module(name="chinese_ocr_db_crnn_mobile")
test_img_path = ["./ch.png", "./eng3.jpg"]
np_images =[cv2.imread(image_path) for image_path in test_img_path] 

results = ocr.recognize_text(
                    images=np_images,         # 图片数据，ndarray.shape 为 [H, W, C]，BGR格式；
                    use_gpu=False,            # 是否使用 GPU；若使用GPU，请先设置CUDA_VISIBLE_DEVICES环境变量
                    output_dir='ocr_result',  # 图片的保存路径，默认设为 ocr_result；
                    visualization=True,       # 是否将识别结果保存为图片文件；
                    box_thresh=0.5,           # 检测文本框置信度的阈值；
                    text_thresh=0.5)          # 识别中文文本置信度的阈值；

for result in results:
    data = result['data']
    save_path = result['save_path']
    txt = [d['text'] for d in data]
    txt = " ".join(txt)
    print("created text: ",  txt)<jupyter_output>[2021-05-09 23:15:00,386] [ WARNING] - The _initialize method in HubModule will soon be deprecated, you can use the __init__() to handle the initialization of the object
[2021-05-09 23:15:00,787] [ WARNING] - The _initialize method in HubModule will soon be deprecated, you can use the __init__() to handle the initialization of the object<jupyter_text>八、用语音文件生成川普附身的wav2lip视频使用上面几种不同来源的音频文件，一键生成wav2lip视频<jupyter_code>%cd ~
!export PYTHONPATH=$PYTHONPATH:/home/aistudio/PaddleGAN && python PaddleGAN/applications/tools/wav2lip.py --face trump.jpg --audio message-7116130031518557320-audio.mp3 --outfile wav2lip.mp4<jupyter_output>/home/aistudio
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/setuptools/depends.py:2: DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses
  import imp
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/layers/utils.py:26: DeprecationWarning: `np.int` is a deprecated alias for the builtin `int`. To silence this warning, use `int` by itself. Doing this will not modify any behavior and is safe. When replacing `np.int`, you may wish to use e.g. `np.int64` or `np.int32` to specify the precision. If you wish to review your current use, check the release note link for additional information.
Deprecated in NumPy 1.20; for more details and guidance: https://numpy.org/devdocs/release/1.20.0-notes.html#deprecations
  def convert_to_list(value, n, name, dtype=np.int):
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/scipy/linalg/__init__.py:217: DeprecationWa[...]
{'fraction_non_alphanumeric': 0.10104739010989011, 'fraction_numerical': 0.04163804945054945, 'mean_word_length': 6.967852257181942, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 19, 'https://': 18, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 1, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '5', 'dir': 'jupyter-structured-clean-dedup', 'id': '416709', 'license': 'Apache-2.0', 'n_tokens_mistral': 6685, 'n_tokens_neox': 7022, 'n_words': 611, 'path': '1905968.ipynb', 'repo_name': 'thunder95/Trump-Say-With-Me-Parakeet', 'size': '11648'}