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

本站现有博文319篇,共被浏览751640

本站已经建立2407天!

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