如何训练神经网络来描述图片的特征?

人工智能 神经网络 机器学习 图像识别
2021-11-13 02:50:31

我收集了一组人物图片,并带有文字说明图片上人物的特征,例如“大鼻子”或“卷发”。

我想训练某种类型的模型,它可以接收任何图片并根据特征返回图片的描述。

但是,我很难弄清楚如何做到这一点。这不像给“狗”或“苹果”贴标签,因为那时我可以创建一组训练数据,然后评估它的性能,现在我不能。如果是这样,我可能会使用 CNN 和 VGG-16 来帮助我。

我只有两门 ML 课程,而且以前从未真正遇到过这样的问题。有人可以帮助我朝着正确的方向前进吗?

到目前为止,我有一个包含 13000 个标记图像的数据集,我非常有信心它被标记得很好。我不知道有任何预训练数据集在这种情况下可能会有所帮助,但如果您知道其中一个可能会有所帮助。

值得注意的是,每个标签都是或至少应该是唯一的。例如,如果存在两张带有相同标签“大鼻子”的图片,则纯属巧合。

4个回答

您正在寻找的术语是多标签分类,即您在每个图像上进行多个分类(每个标签一个分类)。您可以在网上找到的大多数示例都在 NLP 领域,但使用 CNN 也很容易,因为它本质上是由输出层的结构和使用的损失函数定义的。如果您已经熟悉 CNN,它并不像听起来那么复杂。

神经网络的输出层(对于 3 个或更多类)具有与目标一样多的单元。网络学习将这些单元中的每一个与相应的类相关联。类分类器通常将 softmax 激活函数应用于原始单元输出,从而产生概率向量。为了得到最终的分类,max()采用概率向量的 (最可能的类)。输出将如下所示:

                 Cat    Bird   Plane   Superman  Ball   Dog   
Raw output:      -1     2      3       6         -1     -1
Softmax:         0.001  0.017  0.046   0.934     0.001  0.001
Classification:  0      0      0       1         0      0

多标签分类通常使用 sigmoid 激活函数,因为可以独立处理标签出现的概率。然后由概率确定分类(>=0.5 表示 True)。对于您的问题,此输出可能如下所示:

                 Big nose  Long hair  Curly hair  Superman  Big ears  Sharp Jawline
Raw output:      -1        -2         3           6         -1        10
Sigmoid:         0.269     0.119      0.953       0.998     0.269     1.000
Classification:  0         0          1           1         0         1

二元交叉熵损失函数通常用于多标签分类器,因为n标签问题本质上是将多类分类问题分解为n 个二元分类问题。

由于从多类分类器到多标签分类器所需要做的就是更改输出层,因此使用预训练网络非常容易。如果您从 Keras 获得预训练模型,那么它就像include_top=False下载模型然后添加正确的输出层一样简单。

对于 13000 张图像,我建议使用 Keras 的ImageDataGenerator类和该flow_from_dataframe方法。这使您可以使用简单的 pandas 数据框来标记和输入所有图像。数据框如下所示:

Filename  Big nose  Long hair  Curly hair  Superman  Big ears  Sharp Jawline
0001.JPG  0         0          1           1         0         1
0002.JPG  1         0          1           0         1         1
   .      .         .          .           .         .         .

flow_from_dataframeclass_mode参数可以设置为rawmulti_outputx_colto'Filename'y_colto一起设置['Big nose', 'Long hair', 'Curly hair', 'Superman', 'Big ears', 'Sharp Jawline'](在此示例中)。查看文档以获取更多详细信息。

每个标签所需的数据量取决于许多因素,如果不尝试,基本上不可能知道。13000 听起来像是一个好的开始,但这也取决于您拥有多少标签以及它们在标签之间的分布情况。可以在此处找到有关如何设置多标签分类器以及如何使用 Keras 实现它的体面指南(众多指南之一)它还涵盖了标签频率的不平衡,非常值得一读。强烈建议您在开始调整神经网络架构之前尽可能熟悉您的数据集。

您可以尝试图像字幕。您可以为图像训练一个 CNN 模型,然后在此之上,将模型嵌入提供给另一个 LSTM 模型以学习编码特征。您可以直接使用预训练的 VGG-16 模型并使用倒数第二层来创建图像嵌入。

Show and Tell: A Neural Image Caption Generator是一篇非常好的论文。在 TensorFlow 中有一个实现:https ://www.tensorflow.org/tutorials/text/image_captioning 。该论文侧重于生成标题,但您可以向 LSTM 提供您的“特征”,以便它可以为每张图像学习它。

您可以使用图像字幕。查看文章Captioning Images with CNN and RNN, using PyTorch这个想法非常深刻。该模型将图像编码到高维空间,然后将其通过 LSTM 单元,LSTM 单元产生语言输出。

另请参阅具有视觉注意力的图像字幕

我会按照评论中的建议做。首先选择一种编码方案。我认为所谓的差异哈希对于这个应用程序来说很有效。代码如下所示。现在获取您的图像数据集并通过编码器运行它们并将结果保存在数据库中。数据库将包含“标签”文本和编码器结果。现在对于您尝试标记的新图像,将图像输入到编码器中。获取编码器结果并将其与数据库中的编码值进行比较。搜索数据库中的编码值并找到最接近的匹配项。然后,您可以使用“阈值”值来确定是否要为图像提供特定标签,或者距离是否高于阈值声明没有匹配的标签。您可以确定最佳“阈值” 通过运行具有已知标签的数据集图像并迭代阈值级别并选择具有最少错误的阈值来获得价值。我会使用 56 或 128 长度的散列。

import cv2
import os
# f_path is the full path to the image file, hash length is an integer specifies length of the hash
def get_hash(f_path, hash_length):    
    r_str=''    
    img=cv2.imread(f_path,0)        # read image as gray scale image
    img = cv2.resize(img, (hash_length+1, 1), interpolation = cv2.INTER_AREA)    
    # now compare adjacent horizontal values in a row if pixel to the left>pixel toright result=1 else 0
    for col in range (0,hash_length):
        if(img[0][col]>img[0][col+1]):
            value=str(1)
        else:
            value=str(0)
        r_str=r_str + value
    number=0
    power_of_two=1
    for char in r_str:        
        number = number + int(char) * power_of_two
        power_of_two=2 * power_of_two    
    return ( r_str, number) 
# example on an image of a bird
f_path=r'c:\Temp\birds\test\robin\1.jpg'
hash=get_hash ( f_path, 16) # 16 length hash on a bird image
print (' hash string ', hash[0], '   hash number ', hash[1])

> results is
 hash string  1111111100000000    hash number  255