EADST

CLAP 模型:对齐音频与文本的跨模态

跨模态对齐一直是人工智能研究的重要方向,尤其是在音频理解与自然语言处理的结合上。传统上,音频和文本的处理方法差异较大,导致跨模态对齐的难度较高。而由 LAION 团队 提出的 CLAP (Contrastive Language-Audio Pretraining) 模型,正是为了解决这一问题,通过对比学习的方法,将音频与文本对齐到同一语义空间中。

在 Hugging Face 上,CLAP 模型 已经开源并可直接使用,极大方便了研究人员和开发者在音频-文本任务中的应用。


模型简介

CLAP 模型的核心思想与 CLIP 类似:通过对比学习,将 音频嵌入文本嵌入 投射到一个共享的语义空间,从而实现 跨模态检索、分类和理解。例如:

  • 给定一句文本,可以检索与其语义最接近的音频。
  • 给定一段音频,可以找到对应描述的文本。

这种能力对于 音乐检索、声音识别、多模态内容推荐 等任务有着重要意义。


模型结构

CLAP 的整体结构主要由 文本编码器 (Text Encoder)音频编码器 (Audio Encoder) 组成,分别将输入的文本与音频特征映射到语义向量空间,再通过投影层进行对齐。

1. 文本编码器

文本部分继承了 Transformer 架构,类似 BERT:

  • 嵌入层:包括词嵌入、位置嵌入和 LayerNorm。
  • 编码层:由 12 层 Transformer 组成,每层包括自注意力、前馈网络和归一化。
  • 池化层:将序列信息汇聚为固定长度的文本表示。

最终,文本表示会通过一个 投影层 (Projection Layer) 映射到 512 维的共享语义空间。

2. 音频编码器

音频部分使用卷积与 Transformer 混合结构,提取多层次的音频特征:

  • Patch Embedding:通过卷积将声谱图切分为 patch,并进行归一化。
  • 多层 Stage:每个 Stage 包含多层自注意力机制 (Audio Self-Attention),逐步抽取局部与全局特征。
  • 融合机制 (AFF Block):结合局部注意力与全局注意力,对音频 patch 特征进行加权。
  • 下采样与池化:逐步降低维度,得到全局音频表示。

最后,音频表示同样通过 Projection Layer 投射到 512 维语义空间。

3. 对比学习目标

训练时,CLAP 使用大规模 音频-文本配对数据集,通过对比学习损失(Contrastive Loss),最大化正确配对的相似度,最小化错误配对的相似度,从而实现跨模态对齐。


模型代码与使用

CLAP 已在 Hugging Face 提供预训练权重,可以轻松调用:

from transformers import ClapProcessor, ClapModel
import torch

processor = ClapProcessor.from_pretrained("laion/clap-htsat-fused")
model = ClapModel.from_pretrained("laion/clap-htsat-fused")

inputs = processor(text=["a dog barking"], audios=["dog_bark.wav"], return_tensors="pt", padding=True)

with torch.no_grad():
    outputs = model(**inputs)
    text_embeds = outputs.text_embeds
    audio_embeds = outputs.audio_embeds

similarity = torch.cosine_similarity(text_embeds, audio_embeds)
print(similarity)

通过这种方式,用户可以直接获取 音频与文本的对齐嵌入,并进行相似度计算。


模型结构

CLAP 模型的结构

  • 文本输入 → 文本编码器 → 投影层 → 共享语义空间

  • 音频输入 → 音频编码器 → 投影层 → 共享语义空间

ClapModel(
  (text_model): ClapTextModel(
    (embeddings): ClapTextEmbeddings(
      (word_embeddings): Embedding(50265, 768, padding_idx=1)
      (position_embeddings): Embedding(514, 768, padding_idx=1)
      (token_type_embeddings): Embedding(1, 768)
      (LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
      (dropout): Dropout(p=0.1, inplace=False)
    )
    (encoder): ClapTextEncoder(
      (layer): ModuleList(
        (0-11): 12 x ClapTextLayer(
          (attention): ClapTextAttention(
            (self): ClapTextSelfAttention(
              (query): Linear(in_features=768, out_features=768, bias=True)
              (key): Linear(in_features=768, out_features=768, bias=True)
              (value): Linear(in_features=768, out_features=768, bias=True)
              (dropout): Dropout(p=0.1, inplace=False)
            )
            (output): ClapTextSelfOutput(
              (dense): Linear(in_features=768, out_features=768, bias=True)
              (LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
              (dropout): Dropout(p=0.1, inplace=False)
            )
          )
          (intermediate): ClapTextIntermediate(
            (dense): Linear(in_features=768, out_features=3072, bias=True)
            (intermediate_act_fn): GELUActivation()
          )
          (output): ClapTextOutput(
            (dense): Linear(in_features=3072, out_features=768, bias=True)
            (LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
            (dropout): Dropout(p=0.1, inplace=False)
          )
        )
      )
    )
    (pooler): ClapTextPooler(
      (dense): Linear(in_features=768, out_features=768, bias=True)
      (activation): Tanh()
    )
  )
  (text_projection): ClapProjectionLayer(
    (linear1): Linear(in_features=768, out_features=512, bias=True)
    (activation): ReLU()
    (linear2): Linear(in_features=512, out_features=512, bias=True)
  )
  (audio_model): ClapAudioModel(
    (audio_encoder): ClapAudioEncoder(
      (patch_embed): ClapAudioPatchEmbed(
        (proj): Conv2d(1, 96, kernel_size=(4, 4), stride=(4, 4))
        (norm): LayerNorm((96,), eps=1e-05, elementwise_affine=True)
        (fusion_model): ClapAudioAFFBlock(
          (local_att): Sequential(
            (0): Conv2d(96, 24, kernel_size=(1, 1), stride=(1, 1))
            (1): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            (2): ReLU(inplace=True)
            (3): Conv2d(24, 96, kernel_size=(1, 1), stride=(1, 1))
            (4): BatchNorm2d(96, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
          )
          (global_att): Sequential(
            (0): AdaptiveAvgPool2d(output_size=1)
            (1): Conv2d(96, 24, kernel_size=(1, 1), stride=(1, 1))
            (2): BatchNorm2d(24, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
            (3): ReLU(inplace=True)
            (4): Conv2d(24, 96, kernel_size=(1, 1), stride=(1, 1))
            (5): BatchNorm2d(96, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
          )
          (sigmoid): Sigmoid()
        )
        (mel_conv2d): Conv2d(1, 96, kernel_size=(4, 12), stride=(4, 12))
      )
      (layers): ModuleList(
        (0): ClapAudioStage(
          (blocks): ModuleList(
            (0-1): 2 x ClapAudioLayer(
              (layernorm_before): LayerNorm((96,), eps=1e-05, elementwise_affine=True)
              (attention): ClapAudioAttention(
                (self): ClapAudioSelfAttention(
                  (query): Linear(in_features=96, out_features=96, bias=True)
                  (key): Linear(in_features=96, out_features=96, bias=True)
                  (value): Linear(in_features=96, out_features=96, bias=True)
                  (dropout): Dropout(p=0.0, inplace=False)
                )
                (output): ClapAudioSelfOutput(
                  (dense): Linear(in_features=96, out_features=96, bias=True)
                  (dropout): Dropout(p=0.0, inplace=False)
                )
              )
              (drop_path): Identity()
              (layernorm_after): LayerNorm((96,), eps=1e-05, elementwise_affine=True)
              (intermediate): ClapAudioIntermediate(
                (dense): Linear(in_features=96, out_features=384, bias=True)
                (intermediate_act_fn): GELUActivation()
              )
              (output): ClapAudioOutput(
                (dense): Linear(in_features=384, out_features=96, bias=True)
                (dropout): Dropout(p=0.1, inplace=False)
              )
            )
          )
          (downsample): ClapAudioPatchMerging(
            (reduction): Linear(in_features=384, out_features=192, bias=False)
            (norm): LayerNorm((384,), eps=1e-05, elementwise_affine=True)
          )
        )
        (1): ClapAudioStage(
          (blocks): ModuleList(
            (0-1): 2 x ClapAudioLayer(
              (layernorm_before): LayerNorm((192,), eps=1e-05, elementwise_affine=True)
              (attention): ClapAudioAttention(
                (self): ClapAudioSelfAttention(
                  (query): Linear(in_features=192, out_features=192, bias=True)
                  (key): Linear(in_features=192, out_features=192, bias=True)
                  (value): Linear(in_features=192, out_features=192, bias=True)
                  (dropout): Dropout(p=0.0, inplace=False)
                )
                (output): ClapAudioSelfOutput(
                  (dense): Linear(in_features=192, out_features=192, bias=True)
                  (dropout): Dropout(p=0.0, inplace=False)
                )
              )
              (drop_path): Identity()
              (layernorm_after): LayerNorm((192,), eps=1e-05, elementwise_affine=True)
              (intermediate): ClapAudioIntermediate(
                (dense): Linear(in_features=192, out_features=768, bias=True)
                (intermediate_act_fn): GELUActivation()
              )
              (output): ClapAudioOutput(
                (dense): Linear(in_features=768, out_features=192, bias=True)
                (dropout): Dropout(p=0.1, inplace=False)
              )
            )
          )
          (downsample): ClapAudioPatchMerging(
            (reduction): Linear(in_features=768, out_features=384, bias=False)
            (norm): LayerNorm((768,), eps=1e-05, elementwise_affine=True)
          )
        )
        (2): ClapAudioStage(
          (blocks): ModuleList(
            (0-5): 6 x ClapAudioLayer(
              (layernorm_before): LayerNorm((384,), eps=1e-05, elementwise_affine=True)
              (attention): ClapAudioAttention(
                (self): ClapAudioSelfAttention(
                  (query): Linear(in_features=384, out_features=384, bias=True)
                  (key): Linear(in_features=384, out_features=384, bias=True)
                  (value): Linear(in_features=384, out_features=384, bias=True)
                  (dropout): Dropout(p=0.0, inplace=False)
                )
                (output): ClapAudioSelfOutput(
                  (dense): Linear(in_features=384, out_features=384, bias=True)
                  (dropout): Dropout(p=0.0, inplace=False)
                )
              )
              (drop_path): Identity()
              (layernorm_after): LayerNorm((384,), eps=1e-05, elementwise_affine=True)
              (intermediate): ClapAudioIntermediate(
                (dense): Linear(in_features=384, out_features=1536, bias=True)
                (intermediate_act_fn): GELUActivation()
              )
              (output): ClapAudioOutput(
                (dense): Linear(in_features=1536, out_features=384, bias=True)
                (dropout): Dropout(p=0.1, inplace=False)
              )
            )
          )
          (downsample): ClapAudioPatchMerging(
            (reduction): Linear(in_features=1536, out_features=768, bias=False)
            (norm): LayerNorm((1536,), eps=1e-05, elementwise_affine=True)
          )
        )
        (3): ClapAudioStage(
          (blocks): ModuleList(
            (0-1): 2 x ClapAudioLayer(
              (layernorm_before): LayerNorm((768,), eps=1e-05, elementwise_affine=True)
              (attention): ClapAudioAttention(
                (self): ClapAudioSelfAttention(
                  (query): Linear(in_features=768, out_features=768, bias=True)
                  (key): Linear(in_features=768, out_features=768, bias=True)
                  (value): Linear(in_features=768, out_features=768, bias=True)
                  (dropout): Dropout(p=0.0, inplace=False)
                )
                (output): ClapAudioSelfOutput(
                  (dense): Linear(in_features=768, out_features=768, bias=True)
                  (dropout): Dropout(p=0.0, inplace=False)
                )
              )
              (drop_path): Identity()
              (layernorm_after): LayerNorm((768,), eps=1e-05, elementwise_affine=True)
              (intermediate): ClapAudioIntermediate(
                (dense): Linear(in_features=768, out_features=3072, bias=True)
                (intermediate_act_fn): GELUActivation()
              )
              (output): ClapAudioOutput(
                (dense): Linear(in_features=3072, out_features=768, bias=True)
                (dropout): Dropout(p=0.1, inplace=False)
              )
            )
          )
        )
      )
      (batch_norm): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
      (norm): LayerNorm((768,), eps=1e-05, elementwise_affine=True)
      (avgpool): AdaptiveAvgPool1d(output_size=1)
    )
  )
  (audio_projection): ClapProjectionLayer(
    (linear1): Linear(in_features=768, out_features=512, bias=True)
    (activation): ReLU()
    (linear2): Linear(in_features=512, out_features=512, bias=True)
  )
)

应用场景

  1. 音乐检索:根据文字描述找到对应的音乐或音效。
  2. 声音识别:结合自然语言描述进行环境声音识别。
  3. 多模态搜索引擎:输入文本检索音频,或输入音频检索文本。
  4. 内容推荐:在音乐平台中实现跨模态推荐。

总结

CLAP 模型为音频与文本的跨模态理解提供了强大的基础设施。借助对比学习,它能高效地对齐不同模态的数据,使得 音频-文本跨模态检索和理解 成为可能。随着更大规模数据和更强模型的加入,CLAP 有望在音乐、语音助手、内容检索等场景中发挥更大作用。


要深入研究,可以参考:

相关标签
About Me
XD
Goals determine what you are going to be.
Category
标签云
ResNet-50 Search Firewall Python 音频 News Template 报税 Hungarian BF16 Animate PyTorch Heatmap llama.cpp CV LLAMA Website Paddle icon Data CUDA SAM LaTeX Attention Ptyhon Crawler AI Web NameSilo Clash Magnet SPIE 公式 VPN PIP Pillow InvalidArgumentError C++ Anaconda Gemma ModelScope torchinfo 财报 CSV git OCR Qwen2.5 FP32 Windows 版权 Docker SQL Mixtral Color uWSGI 阿里云 Hilton GPT4 Breakpoint Bitcoin Dataset transformers v2ray Github 多进程 Tracking tqdm TTS Shortcut Pytorch Quantization Bin Vim Vmess Hotel Miniforge Claude OpenAI Ubuntu Sklearn TensorRT LoRA git-lfs 域名 Jetson 算法题 UNIX 论文 Permission Safetensors mmap DeepStream CAM ms-swift tar CC Git Distillation Augmentation Linux Llama EXCEL 签证 API logger FP16 NLTK Video Domain Pickle Card Tensor 飞书 Food Excel GPTQ Logo 腾讯云 ChatGPT 净利润 Michelin 论文速读 printf Baidu Django HuggingFace Review RL PDB COCO DeepSeek 第一性原理 CTC Disk GGML Rebuttal 关于博主 Google 图形思考法 SVR VSCode FP8 Algorithm HaggingFace 顶会 WAN Conda Statistics UI LeetCode scipy Use LLM YOLO 多线程 VGG-16 diffusers IndexTTS2 Proxy 云服务器 FlashAttention Markdown CLAP GoogLeNet 递归学习法 继承 Plotly 证件照 图标 Cloudreve ONNX SQLite RAR Quantize Zip Interview Tiktoken XML Agent Password Translation Pandas Qwen2 Nginx Transformers Qwen v0.dev Math WebCrawler JSON Diagram Image2Text GIT Plate Jupyter CEIR FastAPI Input Random Bipartite BeautifulSoup QWEN Knowledge Freesound TSV Paper Base64 RGB OpenCV FP64 PDF TensorFlow PyCharm Land 搞笑 强化学习 Streamlit Numpy Bert NLP MD5 BTC uwsgi XGBoost hf Datetime
站点统计

本站现有博文332篇,共被浏览883283

本站已经建立2588天!

热门文章
文章归档
回到顶部