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

本站现有博文323篇,共被浏览795710

本站已经建立2493天!

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