第2章:多模态数据表示与预处理
各位同学好,我是你们这堂课的主讲。今天咱们聊点实在的——多模态数据怎么变成机器能懂的东西。
说实话,我刚开始接触多模态时,最头疼的就是数据预处理。图像、文本、音频,三种完全不同的东西,怎么让模型统一理解?嗯,这背后其实有一套成熟的方法论。
2.1 图像数据的向量化表示
图像在计算机眼里是什么?说白了就是一堆数字矩阵。一张彩色图片,其实就是三个二维矩阵叠在一起——红、绿、蓝三个通道。
我习惯把图像向量化分成三个层次:
- 像素级表示:直接展平所有像素值,得到一个长向量。比如224x224的RGB图,展平后就是224*224*3=150,528维。这方法简单粗暴,但维度太高,计算量巨大。
- 特征级表示:用卷积神经网络(CNN)提取特征。比如用ResNet-50的最后一层输出,通常只有2048维。我在项目中常用这种方法,效果稳定。
- 语义级表示:用CLIP这类多模态模型,把图像映射到和文本相同的语义空间。这样图像和文本可以直接做相似度计算。
核心要点:图像向量化的目标不是保留所有信息,而是保留对下游任务有用的信息。别想着"无损",那是死胡同。
2.2 文本数据的向量化表示
文本向量化,我估计大家比较熟悉。但多模态场景下,有几个坑我得提醒你。
传统做法是词袋模型或TF-IDF,但说实话,现在基本没人用了。主流方案是:
- Word2Vec / GloVe:静态词向量,每个词只有一个向量。遇到"苹果"(水果)和"苹果"(公司)就傻眼了。
- BERT / RoBERTa:动态词向量,根据上下文生成不同表示。我强烈推荐这个,尤其是做图文匹配时。
- Sentence-BERT:直接生成句子级别的向量。如果你要做文本和图像的相似度比较,这个最合适。
我的经验:做多模态对齐时,文本向量和图像向量的维度最好保持一致。比如都用768维,这样后续计算余弦相似度时不用做维度变换。
2.3 音频数据的向量化表示
音频这块,我踩过不少坑。一开始我以为音频就是波形图,直接拿原始采样点当特征。结果模型训练出来,效果惨不忍睹。
后来我学乖了,用以下方法:
- 梅尔频谱图(Mel-spectrogram):把音频转成类似图像的二维表示。横轴是时间,纵轴是频率,颜色深浅代表能量大小。这样就能用CNN来处理了。
- MFCC(梅尔频率倒谱系数):进一步压缩特征,提取人耳最敏感的部分。语音识别任务中很常用。
- Whisper编码器输出:OpenAI的Whisper模型,内部有一个编码器,可以直接输出音频的语义向量。我在做音频-文本检索时,直接用这个,效果出奇的好。
注意:音频采样率一定要统一。我见过有人用16kHz采样,有人用44.1kHz采样,最后模型根本没法对齐。建议统一用16kHz,这是Whisper的标准采样率。
2.4 数据清洗与对齐
数据清洗,说白了就是"去垃圾"。多模态数据里垃圾特别多,我总结了几类常见问题:
| 问题类型 | 具体表现 | 我的处理方式 |
|---|---|---|
| 图像-文本不匹配 | 图片是猫,文本写的是狗 | 用CLIP计算相似度,低于阈值直接丢弃 |
| 音频质量差 | 背景噪音大、人声模糊 | 用Voice Activity Detection(VAD)检测有效片段 |
| 文本乱码 | 特殊符号、HTML标签混入 | 正则表达式清洗,保留中英文和标点 |
| 数据重复 | 同一张图配不同文本 | 计算图像哈希值,去重 |
对齐这块,我特别想强调时间对齐。比如视频和字幕,字幕的时间戳可能不准。我曾经做过一个项目,字幕比音频慢了2秒,模型学到的全是"看图说话"的假关联。
避坑指南:我曾经用Whisper做音频-文本对齐,发现它自带时间戳输出。直接用这个时间戳去切分音频和文本,比人工标注准多了。
2.5 常用工具库实战
工具库这块,我挑三个最常用的说。每个都是我亲手用过的,不是纸上谈兵。
Pillow:图像处理的老黄牛
from PIL import Image
# 打开图像
img = Image.open('cat.jpg')
# 统一尺寸(多模态任务常用224x224)
img_resized = img.resize((224, 224))
# 转成RGB(防止RGBA或灰度图捣乱)
img_rgb = img_resized.convert('RGB')
# 转成numpy数组
import numpy as np
img_array = np.array(img_rgb) / 255.0 # 归一化到[0,1]
print(img_array.shape) # (224, 224, 3)
Pillow的好处是轻量,适合快速预览和简单处理。但如果你要做批量数据增强,建议用下面这个。
OpenCV:工业级图像处理
import cv2
# 读取图像(OpenCV默认是BGR格式)
img = cv2.imread('cat.jpg')
# 转成RGB
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 数据增强:随机裁剪
h, w = img_rgb.shape[:2]
x = np.random.randint(0, w - 224)
y = np.random.randint(0, h - 224)
img_crop = img_rgb[y:y+224, x:x+224]
# 水平翻转
img_flip = cv2.flip(img_crop, 1)
OpenCV速度极快,我处理百万级图像数据集时,全靠它。但要注意BGR和RGB的坑,我刚开始就栽过跟头。
Whisper:音频转文本的利器
import whisper
# 加载模型(我一般用medium,速度和精度平衡)
model = whisper.load_model("medium")
# 转录音频
result = model.transcribe("speech.mp3")
# 获取文本和对应的时间戳
for segment in result["segments"]:
start = segment["start"]
end = segment["end"]
text = segment["text"]
print(f"[{start:.2f}s - {end:.2f}s] {text}")
Whisper的厉害之处在于,它不仅能转文字,还能给出每个词的时间戳。我做视频字幕对齐时,直接用它生成的时间戳去切视频片段,省了大事。
小技巧:Whisper支持多种语言,但中文识别时,建议把语言参数设为"zh",能提高准确率。我试过不设参数,它有时会误判成英文。
2.6 多模态数据预处理流水线
最后,我分享一个我常用的预处理流水线。这个流程我用了两年,迭代了好几个版本,目前比较稳定。
- 数据收集:从不同来源拉取图像、文本、音频,统一命名规则。
- 格式统一:图像统一为RGB、224x224;音频统一为16kHz、单声道;文本统一为UTF-8编码。
- 质量过滤:用CLIP过滤图文不匹配对,用VAD过滤静音片段。
- 向量化:图像用CLIP编码器,文本用Sentence-BERT,音频用Whisper编码器。
- 对齐存储:把三种向量存成numpy数组,按样本ID索引。
嗯,这套流程跑下来,数据质量基本有保障。但说实话,没有万能的流水线。不同任务对数据的要求不一样,你得根据实际情况调整。
好了,这一章的内容就到这。下一章我们聊聊多模态模型的结构设计,到时候我会拿几个经典模型拆开来讲。
课后思考:如果你手头有一个视频数据集(包含画面、语音、字幕),你会怎么设计预处理流程?试着用今天讲的方法画一个流程图出来。