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

本站现有博文311篇,共被浏览742577

本站已经建立2382天!

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