用 ClipCap 搭建一个图像描述与故事生成 API
项目概述
ClipCap2Story 是一个把图像变为描述与后续故事的轻量化流水线:首先用 CLIP 提取图像特征,再通过一个映射网络(projection / mapping network)把视觉特征映射到语言模型的嵌入空间,最后用 GPT‑2(或类似的自回归模型)生成自然语言的 caption 或 story。流程简化为:
- CLIP 提取图像向量(视觉特征)
- 映射网络将视觉向量转换为语言模型可消费的前缀向量
- GPT‑2 接收前缀并生成描述或续写故事
这种两阶段方案易于实现、推理速度快,但受限于训练数据匹配(图像→故事)时的稀缺性,往往不能做到端到端最优。
实现过程
我做了哪些事
- 在服务器上搭建 Conda 环境,使用 Python 3.10。
- 安装 PyTorch 2.9(匹配 CUDA 12.8)并验证 GPU(RTX 5060)可用。
- 下载并配置 ClipCap 与 GPT‑2 的预训练权重(将必要模型权重放在服务器上)。
- 解决 CLIP 离线安装问题:在可用网络的机器上手动下载 CLIP 的 ZIP 包,上传到腾讯云服务器并离线安装。
- 修复旧版权重与新版 GPT‑2 权重键名不兼容问题(主要是权重字典中
attn.bias与masked_bias等命名差异),编写了脚本转换键名以兼容当前 transformers 的加载方式。 - 使用 FastAPI 封装两个端点:
/caption(返回简短描述)与/story(基于 caption 续写故事),并将服务部署在腾讯云(使用 uvicorn 运行,绑定0.0.0.0:8000)。
示例部署命令(服务器上):
1 | conda create -n clipcap python=3.10 -y |
遇到的困难与解决
- 网络无法访问 Hugging Face:配置
HF_ENDPOINT为镜像源并启用本地缓存;关键模型文件手动下载并通过离线方式上传与加载。 - GPU 不兼容:发现 RTX 5060 在较旧的 PyTorch 版本中问题较多,升级到 PyTorch 2.9 + CUDA 12.8 后稳定运行。
- 终端环境配置反复失败:系统登录脚本与 conda 初始化在不同 shell/服务管理器下表现不一致,最终放弃自动激活,改为每次手动
conda activate clipcap。 - 版权重与新版 GPT‑2 键名不兼容:编写转换脚本,将旧权重键
attn.bias等映射到新版所需的键名(例如masked_bias),确保model.load_state_dict成功。 - 故事生成质量不稳定(核心问题):找不到合适的“图片‑故事”配对数据集,无法进行端到端训练,只能采用两阶段生成(先 caption 再续写)。两阶段会在 caption → story 之间产生信息损失,导致生成过程容易偏航。
- 尝试增强 caption 长度以保留更多视觉信息:将 ClipCap 的
entry_length从 40 增加到 80,结果模型多次在句号处结束或输出重复混乱的 token。这表明 ClipCap 在训练时已习惯于短 caption,强行增长并不能得到有意义的长描述。结论:若要获得丰富视觉信息,应考虑使用 BLIP‑2、或收集图片+故事数据进行端到端微调。
最终方案
- 接受两阶段方案的局限性,但通过调参减缓问题:
- 将生成温度
temperature适当降低(如 0.7→0.6) - 增加
repetition_penalty(如 1.2→1.5) - 调整
top_k/top_p以控制创造性与稳定性
- 将生成温度
- 将该服务定位为“创意发散”工具,而非高精度图像理解工具
- 在文末提出未来改进方向(参考:换用 BLIP‑2、端到端微调等)
API 设计与使用说明
- 接口:
- POST
/caption:接收单张图片(multipart/form-data),返回短描述 JSON:{"caption": "..."} - POST
/story:接收单张图片或前端可先调用/caption获取 caption 再发送给/story,返回故事 JSON:{"story": "..."}
- POST
请求示例(curl):
1 | curl -X POST "http://xxx.xx.xxx.xx:8000/caption" -F "file=@/path/to/image.jpg" |
成果展示(交互式前端示例)
下面是一个可以直接嵌入到 Hexo Markdown 的 HTML+JS 交互示例。前端接受图片上传(最大20M),分别调用 /caption 与 /story,并在页面上显示结果。
ClipCap2Story 在线演示
代码关键点(后端实现思路)
- 使用 CLIP 的图像编码器(或 ViT)得到图像特征向量:
img_feats = clip_model.encode_image(image_tensor) - 训练或加载一个小型映射网络
proj_net,将img_feats映射为 GPT‑2 的前缀嵌入prefix_embeds - 将
prefix_embeds拼接/注入到 GPT‑2 的初始输入(例如作为前缀 token 的嵌入),然后用 GPT‑2 做自回归生成 - 重要的工程细节:
- 离线安装 CLIP:把包与权重放在服务器路径并使用 pip
pip install ./CLIP.zip或手动导入 - 权重键名兼容:加载 state_dict 前做键名替换脚本(python dict 操作)
- 生成时调优 temperature、top_p、repetition_penalty 等参数以获得稳定输出
- 离线安装 CLIP:把包与权重放在服务器路径并使用 pip
GitHub 仓库链接
- GitHub 仓库: https://github.com/yuzhexzf/clipcap2story
总结与未来改进方向
- 总结:ClipCap2Story 在工程实现上较为轻量,能快速把图片映射为可读文本并生成创意故事,但受限于训练数据与模型结构,无法在信息完整性与故事连贯性上与端到端专门训练的系统比肩。
- 未来改进建议:
- 使用 BLIP‑2 / Flamingo 等能更好利用视觉-语言对齐的模型,以提升图像—故事的一致性。
- 收集或合成大规模“图片→故事”配对数据,进行端到端微调以减少中间信息损失。
- 将 ClipCap 的映射网络改为更强的条件生成器(如 prefix‑tuning、adapter、或者视觉指令模块),并尝试联合训练。
- 在服务端加入缓存、限流与异步任务队列(如 Celery / Redis)以支撑并发请求与大文件上传。
- 在前端加入图像剪裁与多模态提示(如手动输入风格或主题)以提升故事生成的可控性。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 yuzhexzf的博客!
评论


