查看全课大纲(第 84 / 93 节)
  1. 1.计算机视觉概述
  2. 2.计算机视觉应用场景
  3. 3.困难与挑战
  4. 4.开源库介绍
  5. 5.图像显示与存储
  6. 6.CLAHE
  7. 7.腐蚀膨胀与开闭运算
  8. 8.滤波与边缘填充
  9. 9.各种滤波
  10. 10.图像金字塔
  11. 11.傅里叶变换
  12. 12.短时傅里叶变换与小波变换
  13. 13.颜色特征与颜色直方图
  14. 14.几何特征_边缘
  15. 15.几何特征-角点与斑点
  16. 16.局部特征-SIFT特征描述子
  17. 17.局部特征-SURF特征描述子
  18. 18.局部特征-ORB特征描述子
  19. 19.其他特征描述子
  20. 20.传统图像分割技术
  21. 21.GraphCut
  22. 22.GrabCut
  23. 23.人脸检测的传统方法
  24. 24.行人检测的传统方法HOG+SVM
  25. 25.行人检测DPM
  26. 26.人工神经网络的架构
  27. 27.目标函数与梯度下降
  28. 28.误差反向传播
  29. 29.可手算的神经网络
  30. 30.改进目标函数与克服梯度消散
  31. 31.神经网络之传统神经网络与深度网络的差异
  32. 32.各种梯度下降算法
  33. 33.如何选择合适的梯度下降算法
  34. 34.避免过适应
  35. 35.CNN的架构
  36. 36.CNN的误差反向传播_卷积层
  37. 37.CNN的误差反向传播_池化层
  38. 38.分类所用的数据集
  39. 39.Alexnet详解
  40. 40.VGG详解
  41. 41.GoogLeNet_v1
  42. 42.BatchNormalization
  43. 43.GoogLeNet_v3v4
  44. 44.ResNet
  45. 45.ResNeXt
  46. 46.CNN设计准则
  47. 47.图像检索与推土机距离
  48. 48.基于颜色相似性
  49. 49.基于形状相似性
  50. 50.基于纹理相似性
  51. 51.基于局部特征相似性
  52. 52.DL的二值哈希编码
  53. 53.高维空间中检索KDTree
  54. 54.高维空间中检索LSH
  55. 55.目标识别任务综述
  56. 56.RCNN
  57. 57.SPP-Net
  58. 58.Fast R-CNN
  59. 59.Faster R-CNN
  60. 60.R-CNN系列模型回顾
  61. 61.R-FCN的设计思路
  62. 62.R-FCN的实现
  63. 63.YOLOv1
  64. 64.YOLOv2_9000
  65. 65.YOLOv3
  66. 66.图像分割应用场景与数据集
  67. 67.上采样的实现方式
  68. 68.FCN网络架构的由来
  69. 69.FCN构建细节
  70. 70.DeepLabv1
  71. 71.CRF
  72. 72.DeepLabv2
  73. 73.DeepLabv3
  74. 74.特定的医学影像分割任务
  75. 75.U-Net
  76. 76.3D U-Net
  77. 77.V-Net
  78. 78.DenseNet
  79. 79.病理切片分析任务及数据集
  80. 80.病理切片分析
  81. 81.图说任务及其传统处理方法
  82. 82.深度语言模型与RNN
  83. 83.LSTM及其变种
  84. 84.NIC模型
  85. 85.SAT模型
  86. 86.图说的性能指标
  87. 87.判别模型与生成模型
  88. 88.KL散度与JS散度
  89. 89.VAE
  90. 90.GAN的基本原理
  91. 91.DCGAN与CGAN
  92. 92.Wasserstein GAN
  93. 93.SRGAN

NIC模型

小象实战讲义 · 基于深度学习的计算机视觉

图像描述(Image Captioning),又称“图说”,是一项融合计算机视觉与自然语言处理的复合任务。它的目标是为一张输入图像生成一句准确、自然的描述性文字。本节我们将深入剖析该领域的一个里程碑式模型——NIC(Neural Image Caption)模型,理解其如何将图像编码与语言解码巧妙地结合在一起。

💡 核心导读

  • 架构核心:NIC模型采用经典的Encoder-Decoder框架,用CNN编码图像,用LSTM解码生成文字。
  • 语义桥梁:模型的关键在于将图像特征映射到一个“语义空间”,作为LSTM解码器的初始输入,引导句子生成。
  • 训练技巧:模型训练分为两步;针对曝光偏差,后续工作引入 Scheduled Sampling 等技巧提升鲁棒性。
  • 推理策略:生成句子时使用Beam Search(束搜索)策略,在保证质量的同时有效控制搜索空间。
  • 历史定位:NIC是首个端到端可训练的图说模型之一,其思想为后续注意力机制等改进奠定了基础。

Encoder-Decoder:从机器翻译到图说

在深入NIC之前,我们需要理解其背后的通用框架——Encoder-Decoder。该框架最初在机器翻译领域被提出,用于解决序列到序列(Sequence-to-Sequence)的转换问题。

核心思想:

  1. 编码器(Encoder):将源序列(如一句英文)编码成一个固定长度的上下文向量(Context Vector),或称语义编码。这个向量旨在捕获输入序列的全部语义信息。
  2. 解码器(Decoder):以上下文向量为初始状态,逐步解码生成目标序列(如一句中文)。

在经典的RNN-based Encoder-Decoder中,编码器和解码器都是循环神经网络(RNN)。编码器最后一个时间步的隐藏状态被用作整个句子的上下文向量,并作为解码器的初始隐藏状态。

那么,如何将这个框架迁移到图像描述任务上呢?NIC模型的创新之处在于对编码器的替换。

NIC模型架构详解

NIC模型的结构“简单”而有效:用卷积神经网络(CNN)替换了编码器部分的RNN。

编码器:从图像到语义向量

NIC选择GoogLeNet作为编码器(GoogLeNet 即 Inception v1;NIC 后来的更新版本才改用 Inception v3)。其处理流程如下:

  1. 输入图像经过GoogLeNet的前向传播。
  2. 移除最后的Softmax分类层。
  3. 将Softmax层之前那一层全连接层的输出作为一个固定维度的向量提取出来。这个向量就是图像的“深度特征”或“语义向量”。

我们用一个小型模拟来理解从图像到特征向量的过程。虽然真实CNN特征维度很高,但我们可以用一个小向量模拟其输出。

import numpy as np

# 模拟GoogLeNet编码器输出的图像特征向量(假设维度为8)
# 在真实模型中,这个向量来自ImageNet预训练网络的倒数第二层
image_feature_vector = np.array([0.12, -0.45, 0.78, 0.01, -0.33, 0.67, -0.22, 0.55])

print("模拟的图像特征向量(语义向量):")
print(image_feature_vector)
print(f"向量维度: {image_feature_vector.shape}")
模拟的图像特征向量(语义向量):
[ 0.12 -0.45  0.78  0.01 -0.33  0.67 -0.22  0.55]
向量维度: (8,)

这个image_feature_vector就是模型从图像中提取的、用于后续生成描述的“语义种子”。

解码器:从语义向量到句子

解码器由一个长短期记忆网络(LSTM) 担任。LSTM非常适合处理像文字这样的序列数据。NIC模型将图像特征向量与LSTM的整合方式设计得非常巧妙:

  1. 初始化:LSTM 的初始隐藏状态 h_0 初始化为零向量;编码器输出的图像特征向量 v 直接作为解码器第一个时间步的输入(相当于“第一个词”)。
  2. 第一个词:图像特征仅在此时输入一次,LSTM 据此生成第一个词 y_1。
  3. 后续生成:从第二个时间步开始,LSTM的输入 x_t 变为上一个时间步预测出的词的词嵌入(Embedding)。在NIC的简化版本中,词嵌入是通过一个权重矩阵 W_e 将独热(One-hot)编码的词映射到与图像特征空间对齐的向量。 xt=We⋅one-hot(yt−1)x_t = W_e \cdot \text{one-hot}(y_{t-1})
  4. 输出:每个时间步,LSTM的输出经过一个Softmax层,产生一个在词汇表上的概率分布,从而预测当前最可能的词。

一个关键细节:在NIC的简化模型中,图像特征仅在解码开始时输入一次,后续生成过程不再使用。这意味着模型需要仅凭初始的“图像印象”和已生成的文字,来推演出完整的描述。这也是后续改进模型(如引入注意力机制)的主要批评点和优化方向。

模型联合:数学表述

将上述过程形式化,给定图像 I,生成描述句子 S(由词序列 y_1, y_2, ..., y_T 组成)的概率被建模为: p(S∣I)=∏t=1Tp(yt∣I,y1,...,yt−1)p(S|I) = \prod_{t=1}^{T} p(y_t | I, y_1, ..., y_{t-1})

其中,每个条件概率由LSTM解码器给出: p(yt∣I,y1,...,yt−1)=Softmax(Wo⋅ht)p(y_t | I, y_1, ..., y_{t-1}) = \text{Softmax}(W_o \cdot h_t) h_t 是LSTM在时间步 t 的隐藏状态,其更新依赖于图像向量 v(在 t=1 时)和之前词的嵌入。

训练的目标是最大化训练集中所有图像-描述对的对数似然: θ∗=arg⁡max⁡θ∑(I,S)log⁡p(S∣I;θ)\theta^* = \arg\max_{\theta} \sum_{(I, S)} \log p(S|I; \theta) 其中 θ 代表模型所有可训练参数(CNN的部分权重、LSTM的权重、映射矩阵 W_e, W_h, W_o 等)。

训练细节与技巧

NIC模型的训练并非一蹴而就,其中包含了一些精心设计的步骤和技巧:

两阶段训练

  1. 第一阶段:固定CNN的权重(使用在ImageNet上预训练好的参数),仅训练LSTM部分。在此阶段,使用无动量(Momentum)的优化器训练约50万步。这是因为语言模型的目标函数地形往往非常“陡峭”,使用动量容易导致更新步伐过大而“跌落”。
  2. 第二阶段:对CNN参数进行微调(Fine-tuning),与LSTM一起联合训练约10万步。这一步至关重要,因为ImageNet预训练任务(1000类物体分类)可能丢弃了与分类无关但对描述重要的信息,例如颜色。微调能让CNN重新学习捕捉这些对生成描述有用的视觉特征。

Scheduled Sampling

在训练时,一个常见问题是“曝光偏差”(Exposure Bias):模型总是用完全正确的上一个词作为当前输入,但在测试时,它必须使用自己预测的(可能出错的)上一个词。这会导致错误累积。

为缓解这一问题,后来的图说模型常用一种叫 Scheduled Sampling 的技巧(该方法由 Bengio 等人于 2015 年提出,并非 NIC 原论文的训练内容):在训练过程中,以一定概率随机地将LSTM上一时间步自己的预测输出作为当前输入,而不是总是使用真实标签。这强迫模型学会在接收到有噪声或不完全正确的输入时,仍能生成合理的后续文本,从而提升了模型的鲁棒性。

词表处理

为了控制模型复杂度并减少噪声,通常会构建一个词表,并剔除在数据集中出现次数少于5次的稀有词,将它们统一标记为<UNK>(未知词)。

推理:Beam Search(束搜索)

在测试阶段,我们需要为图像生成描述。最朴素的方法是贪婪搜索(Greedy Search):每个时间步都选择概率最高的词。但这种方法无法回溯,可能错过全局更优的序列。

NIC模型采用 Beam Search 来生成更好的结果。其核心思想是:在每一步,保留得分最高的 k 个候选序列(k 称为束宽,Beam Size),然后基于这些候选序列进行下一步扩展。

Beam Search 工作流程(假设束宽 k=2,词表 {A, B, C}):

  1. 起始时,有一个空序列。
  2. 第一步:生成第一个词的所有可能(A, B, C),计算概率。保留概率最高的2个词,比如是 A 和 C。当前候选序列集为 {A, C}。
  3. 第二步:分别对候选序列 A 和 C 进行扩展。
    • 扩展 A:得到 AA, AB, AC,计算每个序列的总概率(概率连乘)。
    • 扩展 C:得到 CA, CB, CC,计算每个序列的总概率。
    • 现在有6个候选序列:{AA, AB, AC, CA, CB, CC}。从中选出总概率最高的2个,比如是 AB 和 CB。更新候选序列集为 {AB, CB}。
  4. 后续步骤:重复第二步的过程,直到所有候选序列都生成了结束符<END>,或达到最大长度。最后从完整的候选序列中选出总概率最高的一个作为最终输出。

Beam Search 通过保留多个候选路径,在搜索广度和效率之间取得了平衡。下面的代码模拟了一个极简的Beam Search步骤:

import numpy as np

# 模拟第一步:三个词的概率 (已取log,实际是log概率)
log_probs_step1 = np.log(np.array([0.6, 0.3, 0.1]))  # 对应词 A, B, C
beam_size = 2

# 找出概率最高的 beam_size 个索引(即词)
top_k_indices_step1 = np.argsort(log_probs_step1)[-beam_size:][::-1]
top_k_log_probs_step1 = log_probs_step1[top_k_indices_step1]

print("第一步后保留的候选词及其log概率:")
for idx, prob in zip(top_k_indices_step1, top_k_log_probs_step1):
    word = ['A', 'B', 'C'][idx]
    print(f"  词 '{word}': log概率 = {prob:.4f}")
第一步后保留的候选词及其log概率:
  词 'A': log概率 = -0.5108
  词 'B': log概率 = -1.2040

模型的意义与局限

NIC模型是图像描述领域的一个重要里程碑。它首次证明了使用一个端到端、统一的深度学习模型(CNN + RNN)来完成从图像到文字的直接映射是可行且有效的。其Encoder-Decoder的范式被后续绝大多数工作所继承。

然而,它也存在明显的局限性:

  • 信息瓶颈:将整张图片压缩为一个固定向量,可能会丢失大量细节信息。
  • 注意力缺失:图像特征只在开始时使用,生成每个词时无法动态地关注图像的不同区域。这导致描述可能不够精细和准确。

这些局限性也直接催生了下一代图说模型,其中最著名的改进就是引入了注意力机制(Attention Mechanism),使得模型在生成每个词时都能“看”一眼图像的相关部分,从而生成更贴合、更丰富的描述。

2026视角

自2015年NIC模型提出以来,图像描述领域经历了从特定模型到通用大模型的范式转移。

  1. 注意力成为标配:NIC之后,Show, Attend and Tell (SAT) 等模型迅速引入注意力机制,让解码过程能动态聚焦于图像不同区域,大幅提升了描述的准确性。注意力机制已成为现代序列生成模型的基石。
  2. 多模态预训练的兴起:2021 年,以CLIP (Contrastive Language-Image Pre-training) 为代表的多模态预训练模型出现革命性突破。CLIP通过在海量图像-文本对上进行对比学习,将图像和文本映射到统一的语义空间;它本身不是描述生成模型,但其视觉编码器常被后续图说模型直接复用,成为强大的图文对齐基础。
  3. 大语言模型(LLM)主导:进入多模态大模型时代,图像描述通常作为视觉-语言大模型(VLM) 的一项核心能力。模型如BLIP系列、Flamingo、GPT-4V等,能够接受图像和文本指令,进行开放域的视觉问答、详细描述、推理等任务。图像描述不再是孤立任务,而是通用视觉理解能力的一种体现。
  4. 评估标准演进:随着模型生成能力的增强,传统的BLEU、METEOR等基于n-gram匹配的指标已不足以衡量生成文本的质量、一致性和创造性。CIDEr(2015)虽仍属 n-gram 体系,但通过 TF-IDF 加权与多参考共识提升了与人类判断的相关性;SPICE 则转向场景图级的语义匹配。此外,基于大模型(如GPT-4)的评估方法也变得越来越重要。

尽管技术路径已大为不同,但NIC模型所确立的“视觉理解-语言生成”的基本范式,以及端到端学习的思想,依然是当今多模态人工智能的底层逻辑之一。学习NIC有助于我们理解现代更复杂模型所解决的根本问题。

📝 动手练一练

  1. 概念辨析:NIC模型中的编码器(Encoder)和解码器(Decoder)分别由什么网络实现?图像特征在解码过程中是如何被使用的(与经典机器翻译的Encoder-Decoder有何不同)?
👉 点击查看参考答案
  • 编码器:由卷积神经网络(CNN)实现,具体是GoogLeNet(即 Inception v1;NIC 后续的更新版本改用 Inception v3)。它负责将输入图像编码成一个固定维度的语义特征向量。
  • 解码器:由长短期记忆网络(LSTM)实现。它负责以上述语义特征向量为起点,逐步生成描述文字的序列。
  • 图像特征的使用:在NIC的简化模型中,图像特征向量仅在解码过程的最开始被输入一次(作为解码器第一个时间步的输入;LSTM 的初始隐藏状态 h_0 与初始细胞状态均初始化为零向量),后续生成词时不再使用该图像特征。这与经典(Sutskever 式)机器翻译的Encoder-Decoder做法不同:那边把编码器最后一个时间步的隐藏状态直接作为解码器的初始隐藏状态,而不是第一个时间步的输入;NIC 则把图像特征当作首步输入、隐藏状态置零。让上下文向量在解码器每一个时间步都参与计算,是后来注意力机制的特点,也正是NIC“一次性输入”这一局限的改进方向。
  1. 束搜索模拟:假设束宽(Beam Size)k=2,词表为[“一只”, “猫”, “在”, “睡觉”]。第一步生成“一只”的概率为0.7,“猫”的概率为0.2,“在”的概率为0.1。对于候选序列“一只”,下一步生成“猫”的条件概率是0.8,生成“在”的条件概率是0.2;对于候选序列“猫”,下一步生成“在”的条件概率是0.9,生成“睡觉”的条件概率是0.1。请计算经过两步束搜索后,保留的得分最高的两个序列及其得分(假设得分为概率的乘积)。
👉 点击查看参考答案

第一步:

  • 候选词:“一只”(0.7), “猫”(0.2)。保留这两个。

第二步:

  • 扩展“一只”:
    • “一只 猫”:得分 = 0.7 * 0.8 = 0.56
    • “一只 在”:得分 = 0.7 * 0.2 = 0.14
  • 扩展“猫”:
    • “猫 在”:得分 = 0.2 * 0.9 = 0.18
    • “猫 睡觉”:得分 = 0.2 * 0.1 = 0.02

合并并排序所有候选序列得分:

  1. “一只 猫”: 0.56
  2. “猫 在”: 0.18
  3. “一只 在”: 0.14
  4. “猫 睡觉”: 0.02

保留 top k=2: 最终保留的序列是:“一只 猫” (得分0.56) 和 “猫 在” (得分0.18)。

本章小结

本节我们深入学习了图像描述领域的经典模型——NIC(Neural Image Caption)。它创造性地将用于机器翻译的Encoder-Decoder框架应用于视觉-语言任务,用CNN编码图像,用LSTM生成文字,实现了端到端的训练。我们剖析了其架构细节、训练的两阶段策略(固定CNN训练LSTM,再联合微调)、用于缓解曝光偏差的Scheduled Sampling技巧,以及用于生成高质量描述的Beam Search推理策略。理解NIC是理解现代更复杂图说模型(如引入注意力机制的模型)的重要基础。

📋 行动清单

  • 在脑海中复现NIC模型的数据流:图像 -> CNN -> 特征向量 -> (仅作为解码器第一个时间步的输入) -> LSTM -> 逐个生成词。
  • 理解Beam Search与贪婪搜索的区别,并能手动模拟小规模束搜索的过程。
  • 思考NIC模型“图像特征仅输入一次”的设计可能带来什么问题,这如何引出了后续的注意力机制?

—— 小象教研组