cv练习:看图说话(Image Captioning)--1

在这里插入图片描述
用CNN进行图像识别
在这里插入图片描述
再用LSTM文字处理,再结合DNN实现看图说话
在这里插入图片描述

涉及到的知识

  • 数字图像处理
    • 图像读取
    • 图像缩放
    • 图像数据维度变换
  • 自然语言处理
    • 文字清洗
    • 文字嵌入
  • CNN(卷积神经网络)
    • 图像特征提取
    • 迁移学习
  • LSTM(递归神经网络)
    • 文字串的特征提取
  • DNN(深度神经网络)
  • 从图像特征和文字串的特征预测下一个单词

目标

在这里插入图片描述
自动生成英文标题,与人类生成的标题越相似越好。衡量两个句子的相似度(BLEU)。一个句子与其他几个句子的相似度(Corpus BLEU)

  • BLEU,全称为Bilingual Evaluation Understudy(双语评估替
    换),是一个⽐比较候选⽂文本翻译与其他⼀一个或多个参考翻译的评价 分数

VGG16网络模型

  • 使用keras创建VGG16定义的cnn网络结构
  • VGG16⽤用于图像分类, 将输⼊入图像分为1000个类别
    在这里插入图片描述

在这里插入图片描述

实现网络

  • 根据论文中给的网络结构,我们选择绿色框内的结构,分为16个权值层,5个池化层,共21层结构
  • 卷积层的输出可以作为池化层(pool)的输入,但卷积层和池化层的输出 不能当作全连接层(Dense,FC)的输入,之间必须加一个Flatten层
from keras.models import Sequential
from keras.layers import Dense, Flatten
from keras.layers import Conv2D
from keras.layers import MaxPooling2D


def generate_vgg16():
    """
    搭建VGG16网络结构
    :return: VGG16网络
    此网络没有分支,所以使用Sequential(输入为列表)线性结构
    输入层:
        224x224,3个通道的RGB图像
    卷积层:
        padding = 'same':卷积层的输入和输出的矩阵长宽不变,深度会变
        activation = 'relu':设置激活函数为relu
    maxpool 最大池化层:
        pool_size = (2,2):每次池化把2x2的点输出做一个点
        stride = (2,2):步长
    Flatten:
        卷积层的输出可以作为池化层的输入,
        但卷积层和池化层的输出不能当作全连接层的输入,之间必须加一个Flatten层
    Dense:
        指定节点数量和激活函数
        activation = 'relu':设置激活函数为relu
    """
    input_shape = (224, 224, 3)
    model = Sequential([
        Conv2D(64, (3, 3), input_shape=input_shape, padding='same', activation='relu'),
        #64个大小为3x3滤波器
        Conv2D(64, (3, 3), padding='same', activation='relu'),
        MaxPooling2D(pool_size=(2, 2), strides=(2, 2)),
        Conv2D(128, (3, 3), padding='same', activation='relu'),
        Conv2D(128, (3, 3), padding='same', activation='relu'),
        MaxPooling2D(pool_size=(2, 2), strides=(2, 2)),
        Conv2D(256, (3, 3), padding='same', activation='relu'),
        Conv2D(256, (3, 3), padding='same', activation='relu'),
        Conv2D(256, (3, 3), padding='same', activation='relu'),
        MaxPooling2D(pool_size=(2, 2), strides=(2, 2)),
        Conv2D(512, (3, 3), padding='same', activation='relu'),
        Conv2D(512, (3, 3), padding='same', activation='relu'),
        Conv2D(512, (3, 3), padding='same', activation='relu'),
        MaxPooling2D(pool_size=(2, 2), strides=(2, 2)),
        Conv2D(512, (3, 3), padding='same', activation='relu'),
        Conv2D(512, (3, 3), padding='same', activation='relu'),
        Conv2D(512, (3, 3), padding='same', activation='relu'),
        MaxPooling2D(pool_size=(2, 2), strides=(2, 2)),
        Flatten(),
        Dense(4096, activation='relu'),
        Dense(4096, activation='relu'),
        Dense(1000, activation='softmax')
        #分类问题,所以最后一个全连接层的输出的激活函数为softmax
    ])


    return model

if __name__ == '__main__':
    model = generate_vgg16()
    model.summary()

运行可见输出
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
有运行结果可见,池化层是没有训练权值的,而卷积层因为共享权值,因此要训练的权值数也比较少,而全连接层需要训练的权值数就比较多。

图像特征提取

数据集

链接:https://pan.baidu.com/s/1DiCqRNU4kL8bB9izcp2wBQ
提取码:7qwq

  • 8000 图像, 每幅图5个标题, 描述图像⾥里里⾯面的事物和事件
  • 不包含著名⼈人物和地点
  • 分为3个集合: 6000个训练图像, 1000个开发图像, 1000个测试图像
    在这里插入图片描述
数据示例

在这里插入图片描述

理想网络模型

在这里插入图片描述

简化网络模型

在这里插入图片描述

迁移学习(transfer learning)

  • VGG16 CNN 原本的⽬目标是分类, 基于ImageNet数据集进⾏训练
    训练所需的时间⽐比较⼤,需要4个GPU训练3个星期左右
  • 我们可以调整VGG16的⽹网络结构为图像标题⽣生成服务
  • VGG16 的后⼀一层是将倒数第⼆二层4096维的输出转为1000维的
    输出作为1000类别的分类概率
  • 我们可以去除后⼀一层,将倒数第⼆二层的4096维的输出作为图像标 题⽣生成模型的图像特征

将flicker8k的图像文件转为图像特征,保存为字典pickle文件

  • 从给定的VGG16网络结构文件和权值文件,创建VGG16网络。
  • 修改网络结构(去除最后一层)。
  • 利用修改的网络结构,提取flicker8k数据集中所有图像特征,使用字典存储,key为文件名(不带.jpg后缀),value为一个网络的输出。
  • 将字典保存为features.pkl文件(使用pickle库)。

代码实现

from keras.models import model_from_json
from PIL import Image as pil_image
from keras import backend as K
import numpy as np
from pickle import dump
from os import listdir
from keras.models import Model
import keras
import re
from tqdm import tqdm

def load_vgg16_model():
    """从当前目录下面的 vgg16_exported.json 和 vgg16_exported.h5 两个文件中导入 VGG16 网络并返回创建的网络模型
    # Returns
        创建的网络模型 model
    """
    json_file = open('vgg16_exported.json', 'r')
    loaded_model_json = json_file.read()
    json_file.close()

    model = model_from_json(loaded_model_json)
    model.load_weights('vgg16_exported.h5')

    return model

def preprocess_input(x):
    """预处理图像用于网络输入, 将图像由RGB格式转为BGR格式.
       将图像的每一个图像通道减去其均值

    # Arguments
        x: numpy 数组, 4维.
        data_format: Data format of the image array.

    # Returns
        Preprocessed Numpy array.
    """
    x = x[..., ::-1]
    mean = [103.939, 116.779, 123.68]
    x[..., 0] -= mean[0]
    x[..., 1] -= mean[1]
    x[..., 2] -= mean[2]

    return x


def load_img_as_np_array(path, target_size):
    """从给定文件加载图像,转换图像大小为给定target_size,返回32位浮点数numpy数组.

    # Arguments
        path: 图像文件路径
        target_size: 元组(图像高度, 图像宽度).

    # Returns
        A PIL Image instance.
    """
    img = pil_image.open(path)
    img = img.resize(target_size, pil_image.NEAREST)

    return np.asarray(img, dtype=K.floatx()) #转化为向量


def extract_features(directory):
    """提取给定文件夹中所有图像的特征, 将提取的特征保存在文件features.pkl中,
       提取的特征保存在一个dict中, key为文件名(不带.jpg后缀), value为特征值[np.array]

    Args:
        directory: 包含jpg文件的文件夹

    Returns:
        None
    """
    model = load_vgg16_model()
    # 去除模型最后一层
    model.layers.pop()
    model = Model(inputs=model.inputs, outputs=model.layers[-1].output)
    print('模型建立成功')
    features = dict()

    pbar = tqdm(total=len(listdir(directory)), desc="进度", ncols=100)
    for fn in listdir(directory):

        fn = directory + '/' + fn   #返回长,宽,通道的三维向量

        arr = load_img_as_np_array(fn, target_size=(224, 224))

        #改变数组形态,增加一个维度(批处理输入的维度)
        arr = arr.reshape((1, arr.shape[0], arr.shape[1], arr.shape[2]))
        #预处理图像作为VGG模型输入
        arr = preprocess_input(arr)
        #计算特征
        feature = model.predict(arr, verbose=0)

        #去掉文件后缀
        id = re.findall('Flicker8k_Dataset/(.*?).jpg', fn)[0]

        features[id] = feature
        pbar.update(1)
    print('特征提取完成')
    return features

if __name__ == '__main__':
    directory = 'Flicker8k_Dataset'
    features = extract_features(directory)
    print('提取特征的文件个数:%d' % len(features))
    print(keras.backend.image_data_format())
    #保存特征到文件
    dump(features, open('features.pkl', 'wb'))

在这里插入图片描述
在这里插入图片描述
最后的结果,特征提取完成
在这里插入图片描述在这里插入图片描述

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值