实现细粒度图像识别 Bilinear CNN Keras实现

2023-05-16

细粒度视觉识别之双线性CNN模型
[1] Lin T Y, RoyChowdhury A, Maji S. Bilinear cnn models for fine-grained visual recognition[C]//Proceedings of the IEEE International Conference on Computer Vision. 2015: 1449-1457.
[2] Lin T Y, RoyChowdhury A, Maji S. Bilinear CNNs for Fine-grained Visual Recognition//arXiv. 2017.

摘要
定义:双线性CNN模型:包含两个特征提取器,其输出经过外积(外积WiKi)相乘、池化后获得图像描述子。
优点:
该架构能够以平移不变的方式,对局部的对级(pairwise)特征交互进行建模,适用于细粒度分类。
能够泛化多种顺序无关的特征描述子,如Fisher 向量,VLAD及O2P。实验中使用使用卷积神经网络的作为特征提取器的双线性模型。
双线性形式简化了梯度计算,能够对两个网络在只有图像标签的情况下进行端到端训练。
实验结果:
对ImageNet数据集上训练的网络进行特定领域的微调,该模型在CUB200-2011数据集上,训练时达到了84.1%的准确率。
作者进行了实验及可视化以分析微调的效果,并在考虑模型速度和精确度的情况下选择了两路网络。
结果显示,该架构在大多数细粒度数据集上都可以与先前算法相媲美,并且更加简洁、易于训练。更重要的是,准确率最高的模型可以在NVIDIA Tesla K40 GPU上以8 f/s的速度高效运行。代码链接:http://vis-www.cs.umass.edu/bcnn
 


细粒度识别
对同属一个子类的物体进行分类,通常需要对高度局部化、且与图像中姿态及位置无关的特征进行识别。例如,“加利福尼亚海鸥”与“环状海鸥”的区分就要求对其身体颜色纹理,或羽毛颜色的微细差异进行识别。
通常的技术分为两种:

局部模型:先对局部定位,之后提取其特征,获得图像特征描述。缺陷:外观通常会随着位置、姿态及视角的改变的改变。
整体模型:直接构造整幅图像的特征表示。包括经典的图像表示方式,如Bag-of-Visual-Words,及其适用于纹理分析的多种变种。
基于CNN的局部模型要求对训练图像局部标注,代价昂贵,并且某些类没有明确定义的局部特征,如纹理及场景。
作者思路

局部模型高效性的原因:本文中,作者声称局部推理的高效性在于其与物体的位置及姿态无关。纹理表示通过将图像特征进行无序组合的设计,而获得平移无关性。
纹理表征性能不佳的思考:基于SIFT及CNN的纹理表征已经在细粒度物体识别上显示出高效性,但其性能还亚于基于局部模型的方法。其可能原因就是纹理表示的重要特征并没有通过端到端训练获得,因此在识别任务中没有达到最佳效果。
洞察点:某些广泛使用的纹理表征模型都可以写作将两个合适的特征提取器的输出,外积之后,经池化得到。
首先,(图像)先经过CNNs单元提取特征,之后经过双线性层及池化层,其输出是固定长度的高维特征表示,其可以结合全连接层预测类标签。最简单的双线性层就是将两个独立的特征用外积结合。这与图像语义分割中的二阶池化类似。
实验结果:作者在鸟类、飞机、汽车等细粒度识别数据集上对模型性能进行测试。表明B-CNN性能在大多细粒度识别的数据集上,都优于当前模型,甚至是基于局部监督学习的模型,并且相当高效。
 

# -*- coding: utf-8 -*-
"""
Created on Tue Sep 18 00:28:01 2018
@author: Administrator
"""
 
import matplotlib.pyplot as plt
from keras.applications.inception_v3 import InceptionV3
from keras.applications.resnet50 import ResNet50
from keras.applications.vgg16 import VGG16
from keras.models import Sequential
from keras.models import Model
from keras.utils import np_utils
from keras.layers import Convolution2D,Activation,MaxPooling2D,Flatten,Dense,Dropout,Input,Reshape,Lambda
from keras import optimizers
from keras.preprocessing.image import ImageDataGenerator
from keras import backend as K
from keras.utils import plot_model
import numpy as np
from keras.callbacks import ModelCheckpoint,EarlyStopping,LearningRateScheduler,ReduceLROnPlateau
 
def sign_sqrt(x):
    return K.sign(x) * K.sqrt(K.abs(x) + 1e-10)
 
def l2_norm(x):
    return K.l2_normalize(x, axis=-1)
 
def batch_dot(cnn_ab):
    return K.batch_dot(cnn_ab[0], cnn_ab[1], axes=[1, 1])
 
def bilinearnet():
    input_tensor = Input(shape=(384,512,3))
    vgg16 = VGG16(weights='imagenet', include_top=False,input_tensor=input_tensor)
#    conv2048 = Convolution2D(filters=2048,kernel_size=(3,3),)
#    vgg16_add_conv_to_2048 = Model(inputs=input_tensor,outputs=)
    resnet50 = ResNet50(weights='imagenet', include_top=False,input_tensor=input_tensor)
    model_vgg16 = Model(inputs=input_tensor,outputs=vgg16.output)
    model_resnet50 = Model(inputs=input_tensor,outputs=resnet50.output)
    model_vgg16.compile(loss='categorical_crossentropy',optimizer='adam')
    model_resnet50.compile(loss='categorical_crossentropy',optimizer='adam')
    
    resnet50_x = Reshape([model_resnet50.layers[-6].output_shape[1]*model_resnet50.layers[-6].output_shape[2],model_resnet50.layers[-6].output_shape[3]])(model_resnet50.layers[-6].output)
    vgg16_x = Reshape([model_vgg16.layers[-1].output_shape[1]*model_vgg16.layers[-1].output_shape[2],model_vgg16.layers[-1].output_shape[3]])(model_vgg16.layers[-1].output)
    
    cnn_dot_out = Lambda(batch_dot)([vgg16_x,resnet50_x])
    
    sign_sqrt_out = Lambda(sign_sqrt)(cnn_dot_out)
    l2_norm_out = Lambda(l2_norm)(sign_sqrt_out)
    flatten = Flatten()(l2_norm_out)
    dropout = Dropout(0.5)(flatten)
    output = Dense(12, activation='softmax')(dropout)
    
    model = Model(input_tensor, output)
    model.compile(loss='categorical_crossentropy', optimizer=optimizers.SGD(lr=1e-4, momentum=0.9, decay=1e-6),
                  metrics=['accuracy'])
    print(model.summary())
    plot_model(model,to_file='vgg_resnet_bilinear_model.png')
    return model
#    print(vgg16_x.shape)
#    print(resnet50_x.shape)
#    print(cnn_dot_out.shape)
#    print(model_vgg16.summary())
    '''
    vgg16
        
    block5_conv1 (Conv2D)        (None, 24, 32, 512)       2359808   
    _________________________________________________________________
    block5_conv2 (Conv2D)        (None, 24, 32, 512)       2359808   
    _________________________________________________________________
    block5_conv3 (Conv2D)        (None, 24, 32, 512)       2359808   
    _________________________________________________________________
    block5_pool (MaxPooling2D)   (None, 12, 16, 512)       0         
    
    resnet50
        
    bn5c_branch2c (BatchNormalizati (None, 12, 16, 2048) 8192        res5c_branch2c[0][0]             
    __________________________________________________________________________________________________
    add_112 (Add)                   (None, 12, 16, 2048) 0           bn5c_branch2c[0][0]              
                                                                     activation_340[0][0]             
    __________________________________________________________________________________________________
    activation_343 (Activation)     (None, 12, 16, 2048) 0           add_112[0][0]                    
    __________________________________________________________________________________________________
    '''
#    print(model_resnet50.summary())
#    vgg16.layers[]
 
 
#
#def categorical_crossentropy(y_true, y_pred):
#    return K.categorical_crossentropy(y_true, y_pred)
#
#
#model = VGG16(weights='imagenet', include_top=False,input_shape=(384, 512,3))
##print('youdianmeng')
#top_model = Sequential()
#top_model.add(Flatten(input_shape=model.output_shape[1:]))  # model.output_shape[1:])  
#top_model.add(Dropout(0.5))  
#top_model.add(Dense(12, activation='softmax'))  
## 载入上一模型的权重  
#
#ftvggmodel = Model(inputs=model.input, outputs=top_model(model.output))
##for layer in ftvggmodel.layers[:25]:
##    layer.trainable=True
#    
#ftvggmodel.compile(loss=categorical_crossentropy,
#              optimizer=optimizers.SGD(lr=1e-4, momentum=0.90,decay=1e-5),metrics=['accuracy'])
##              
train_data_gen = ImageDataGenerator(rescale=1/255.,
                 samplewise_center=True,
                 samplewise_std_normalization=True,
#                 zca_whitening=True,
#                 zca_epsilon=1e-6,
                
                 width_shift_range=0.05,
                 height_shift_range=0.05,
                 fill_mode='reflect',
                 horizontal_flip=True,
                 vertical_flip=True)     
         
test_data_gen = ImageDataGenerator(rescale=1/255.)
#
train_gen = train_data_gen.flow_from_directory(directory='D:\\xkkAI\\ZZN\\guangdong\\train',
                            target_size=(384, 512), color_mode='rgb',
                            class_mode='categorical',
                            batch_size=5, shuffle=True, seed=222
                            )
 
val_gen = test_data_gen.flow_from_directory(directory='D:\\xkkAI\\ZZN\\guangdong\\val',
                            target_size=(384, 512), color_mode='rgb',
                            class_mode='categorical',
                            batch_size=5, shuffle=True, seed=222
                            )
test_gen = test_data_gen.flow_from_directory(directory='D:\\xkkAI\\ZZN\\guangdong\\test',
                            target_size=(384, 512), color_mode='rgb',
                            class_mode='categorical',
                            batch_size=5
                            )
cp = ModelCheckpoint('guangdong_best_vgg16.h5', monitor='val_loss', verbose=1,
                 save_best_only=True, save_weights_only=False,
                 mode='auto', period=1)
es = EarlyStopping(monitor='val_loss',
                  patience=8, verbose=1, mode='auto') 
lr_reduce = ReduceLROnPlateau(monitor='val_loss', factor=0.1, epsilon=1e-5, patience=2, verbose=1, min_lr = 0.00000001)    
callbackslist = [cp,es,lr_reduce]
 
ftvggmodel = bilinearnet()
ftvggmodel.fit_generator(train_gen,
                          epochs=1111,
                          verbose=1,
                          callbacks=callbackslist,
                          validation_data=val_gen,
                          shuffle=True)
 
#ftvggmodel.load_weights('guangdong_best_vgg16.h5')
pred = ftvggmodel.predict_generator(test_gen)
 
defectlist=['norm','defect1','defect2','defect3','defect4','defect5','defect6','defect7','defect8','defect9','defect10','defect11']
import csv
with open('lvcai_result.csv','w') as f:
    w = csv.writer(f)
    for i in range(len(pred)):
        w.writerow([str(i)+'.jpg',defectlist[np.argmax(pred[i])]])
 

VGG16迁移学习

import numpy as np
from keras.models import Sequential, Model
from keras.layers import Input, Reshape, Lambda
from keras.layers import Dropout, Flatten, Dense
from keras.preprocessing.image import ImageDataGenerator
from keras.callbacks import ModelCheckpoint, EarlyStopping, ReduceLROnPlateau
from keras import optimizers
from keras.applications.vgg16 import VGG16
from keras import backend as K
 
 
def batch_dot(cnn_ab):
    return K.batch_dot(cnn_ab[0], cnn_ab[1], axes=[1, 1])
 
 
def sign_sqrt(x):
    return K.sign(x) * K.sqrt(K.abs(x) + 1e-10)
 
 
def l2_norm(x):
    return K.l2_normalize(x, axis=-1)
 
 
def bilinear_vgg16(size, class_num):
    input_tensor = Input(shape=(size[0], size[1], 3))
    model_vgg16 = VGG16(include_top=False, weights='imagenet',
                        input_tensor=input_tensor)
    cnn_out_a = model_vgg16.layers[-2].output
    cnn_out_shape = model_vgg16.layers[-2].output_shape
    cnn_out_a = Reshape([cnn_out_shape[1]*cnn_out_shape[2],
                         cnn_out_shape[-1]])(cnn_out_a)
    cnn_out_b = cnn_out_a
    cnn_out_dot = Lambda(batch_dot)([cnn_out_a, cnn_out_b])
    cnn_out_dot = Reshape([cnn_out_shape[-1]*cnn_out_shape[-1]])(cnn_out_dot)
 
    sign_sqrt_out = Lambda(sign_sqrt)(cnn_out_dot)
    l2_norm_out = Lambda(l2_norm)(sign_sqrt_out)
    output = Dense(class_num, activation='softmax')(l2_norm_out)
    model = Model(input_tensor, output)
    model.compile(loss='categorical_crossentropy', optimizer=optimizers.SGD(lr=1e-4, momentum=0.9, decay=1e-6),
                  metrics=['accuracy'])
    print(model.summary())
    return model_vgg16
 
 
if __name__ == '__main__':
    size=(320,320)
    class_num=5
    model_vgg16 = bilinear_vgg16(size,class_num)

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

实现细粒度图像识别 Bilinear CNN Keras实现 的相关文章

  • dev 调试

    问题集锦 xff1a 1 dev的代码自动补全功能 xff08 vs的智能提示功能 xff09 的快捷键 2 调试时 xff0c 二维字符数组的样子 如图很是怪异 xff1a 3 这篇博文可以供以后出现问题后参考 xff0c 其主要改变的是
  • c语言scanf接收字符的问题

    scanf xff08 c xff0c amp c xff09 xff1b 与scanf xff08 c xff0c amp c xff09 xff1b 看上去差别很小实际上第二个仅仅多了一个空格 却差别很大 尤其是scanf接收的数据之前
  • 浮点错误

    转载部分 xff1a 浮点错误 您的程序运行时发生浮点错误 xff0c 比如遇到了除以 0 的情况 所以发生浮点错误应该考虑程序中 xff1a 是否可能出现了一个数除以0的情况 是否可能出现了一个数取余0的情况 是否发生了数据溢出而导致的除
  • 猿辅导2017 笔试题

    题目描述 小明认为某些数字不吉利 xff0c 付账时会尽可能少的多付一些钱 xff0c 使得价格中不包含这些不吉利数字 xff0c 并且不出现0 例如 xff0c 不吉利数字为1 xff0c 4 xff0c 7 xff0c 8 xff0c
  • 数据挖掘期末考试

    1理解概念 1 1数据挖掘 1 2关联规则 1 3数据预处理 1 4置信度 1 5聚类 1 6KNN 1 7SVM 2 分类器设计的三个过程 3 分类时常将样本怎样划分 xff1f 4 评估分类器性能的常用指标 5 数据挖掘常用技术有哪些
  • npm超时

    有时使用npm下载很慢出现超时 xff0c 可以尝试使用cnpm xff0c 国内镜像 安装 npm install cnpm g registry 61 https registry npm taobao org 测试是否成功 cnpm
  • 机试第一节

    问题 xff1a 1 6中的n的阶乘太大时发生溢出怎么处理 分割线 1 双精度浮点类型的定义 xff1a double 输出 lf 单精度浮点类型的定义 xff1a float 输出 xff1a f 2鸡兔同笼问题 xff0c 判断所给样例
  • Python小技巧之——巧用with语句实现异常处理

    Python的异常处理语句try except大家都很熟悉了 xff0c 例如 xff1a try 1 0 except Exception as ex print ex integer division or modulo by zero
  • 将lwip1.4.1工程移植至lwip2.1.2记录

    将lwip1 4 1工程移植至lwip2 1 2记录 1 ip addr结构体2 etharp h3 cc h与arch h4 tcp impl h 关于二者文件 功能等差异网上已有很多文章介绍 xff0c 类似这个文档有简单说了下这两个版
  • 在Windows和Ubuntu上安装VNC连接远程服务器

    如果你是公用的服务器的管理员需要添加一些用户 xff0c 并配置VNC服务以便远程访问 xff0c 简要介绍一下配置方法 具体的命令可以参照命令手册去查看 man span class hljs command span class hlj
  • 变频器的工作原理及其电路分析

    变频器简单的说就是结合了变频技术和微电子技术研制出来的可以改变输入电源的频率得到另外一种频率电源输出的设备 其输入的电源就是我们工业上面使用的电源 xff0c 一般都是电压和频率都固定不变的交流电 240v或者380v交流电 通过内置的一些
  • 欠拟合、过拟合及其解决方法

    在我们机器学习或者训练深度神经网络的时候经常会出现欠拟合和过拟合这两个问题 xff0c 但是 xff0c 一开始我们的模型往往是欠拟合的 xff0c 也正是因为如此才有了优化的空间 xff0c 我们需要不断的调整算法来使得模型的表达能拿更强
  • ubuntu18.04安装ROS Melodic的详细过程以及填坑经历

    一 版本说明 ROS官方将在2021年不再维护Kinetic xff0c 后续使用Ubuntu18 04 43 Melodic组合 xff0c Melodic支持时间到2023年5月 二 安装前Ubuntu18 04设置 打开Ubuntu1
  • win10和ubuntu20双系统设置默认启动系统为win10

    在win10下安装了Ubuntu20 04系统 xff0c 默认情况下 xff0c 启动的是Ubuntu系统 要将默认启动系统设置成win10 xff0c 方法如下 xff1a 1 进入ubuntu系统 xff0c 按住Ctrl 43 Al
  • Keil添加芯片支持包(Pack)

    1 前言 一直用STM32的芯片 xff0c 现在想看看工程是否可以在其他厂家的芯片上跑 xff0c 可是keil的Device中只有ST厂家的 因此 xff0c 尝试在keil中添加其他厂家的芯片支持包 2 keil软件内安装 点击工具栏
  • Qt 设置窗体大小和背景颜色

    1 一种方法是设置它的最大窗口值和最小窗口值 xff0c 并且使最大值和最小值相等 简单的示例 xff1a setMinimumSize 370 150 setMaximumSize 370 150 此时窗口大小便被固定为 xff08 37
  • Shell 脚本详解

    简介 shell xff1a 蛋 壳 shell脚本是在操作系统外 xff0c 可以直接调用系统内核命令的一个脚本语言 shell脚本可以分为两大类组成 xff1a 1 命令行 xff08 系统命令行 xff09 2 脚本语法 xff08
  • Windows——电脑不能连接手机热点(WLAN显示已经禁用)的解决办法

    笔记本电脑提示 xff1a 已关闭无线功能 基于这篇博客之上 xff0c 在第二步中 xff0c 关闭WLAN AutoConfig 服务 xff0c 之后重新打开WLAN AutoConfig 服务 xff0c 即可
  • Ubuntu——系统语言由英文切换到中文的方法

    一 方法一 ubuntu设置系统语言为中文 二 方法二 若方法一中不能拖动中文输入法到第一行 xff0c 则可以直接采取卸载英文输入法 xff0c 这样就中文输入法到第一行了 xff0c 切换成中文了 英文输入法可以根据需要考虑是否安装 一
  • RealSense D435——基本介绍

    一 结构介绍 采用的是结构光Tof成像方案 正面的四个摄像头从左至右 xff0c 依次是左红外相机 红外点阵投影仪 右红外相机 RGB相机 xff08 前三个负责形成深度图 xff0c 最后一个就形成RGB图 xff09 二 小贴士 RGB

随机推荐