Keras搭建孪生神经网络Siamese network比较图片相似性
作者:Bubbliiiing 发布时间:2023-01-27 04:16:28
什么是孪生神经网络
最近学习了一下如何比较两张图片的相似性,用到了孪生神经网络,一起来学习一下。
简单来说,孪生神经网络(Siamese network)就是“连体的神经网络”,神经网络的“连体”是通过共享权值来实现的,如下图所示。
所谓权值共享就是当神经网络有两个输入的时候,这两个输入使用的神经网络的权值是共享的(可以理解为使用了同一个神经网络)。
很多时候,我们需要去评判两张图片的相似性,比如比较两张人脸的相似性,我们可以很自然的想到去提取这个图片的特征再进行比较,自然而然的,我们又可以想到利用神经网络进行特征提取。
如果使用两个神经网络分别对图片进行特征提取,提取到的特征很有可能不在一个域中,此时我们可以考虑使用一个神经网络进行特征提取再进行比较。
这个时候我们就可以理解孪生神经网络为什么要进行权值共享了。
孪生神经网络有两个输入(Input1 and Input2),利用神经网络将输入映射到新的空间,形成输入在新的空间中的表示。通过Loss的计算,评价两个输入的相似度。
代码下载
孪生神经网络的实现思路
一、预测部分
1、主干网络介绍
孪生神经网络的主干特征提取网络的功能是进行特征提取,各种神经网络都可以适用,本文使用的神经网络是VGG16。关于VGG的介绍大家可以看我的另外一篇博客
https://www.jb51.net/article/246968.htm
这是一个VGG被用到烂的图,但确实很好的反应了VGG的结构:
1、一张原始图片被resize到指定大小,本文使用105x105。
2、conv1包括两次[3,3]卷积网络,一次2X2最大池化,输出的特征层为64通道。
3、conv2包括两次[3,3]卷积网络,一次2X2最大池化,输出的特征层为128通道。
4、conv3包括三次[3,3]卷积网络,一次2X2最大池化,输出的特征层为256通道。
5、conv4包括三次[3,3]卷积网络,一次2X2最大池化,输出的特征层为512通道。
6、conv5包括三次[3,3]卷积网络,一次2X2最大池化,输出的特征层为512通道。
实现代码为:
import keras
from keras.layers import Input,Dense,Conv2D
from keras.layers import MaxPooling2D,Flatten
from keras.models import Model
import os
import numpy as np
from PIL import Image
from keras.optimizers import SGD
class VGG16:
def __init__(self):
self.block1_conv1 = Conv2D(64,(3,3),activation = 'relu',padding = 'same',name = 'block1_conv1')
self.block1_conv2 = Conv2D(64,(3,3),activation = 'relu',padding = 'same', name = 'block1_conv2')
self.block1_pool = MaxPooling2D((2,2), strides = (2,2), name = 'block1_pool')
self.block2_conv1 = Conv2D(128,(3,3),activation = 'relu',padding = 'same',name = 'block2_conv1')
self.block2_conv2 = Conv2D(128,(3,3),activation = 'relu',padding = 'same',name = 'block2_conv2')
self.block2_pool = MaxPooling2D((2,2),strides = (2,2),name = 'block2_pool')
self.block3_conv1 = Conv2D(256,(3,3),activation = 'relu',padding = 'same',name = 'block3_conv1')
self.block3_conv2 = Conv2D(256,(3,3),activation = 'relu',padding = 'same',name = 'block3_conv2')
self.block3_conv3 = Conv2D(256,(3,3),activation = 'relu',padding = 'same',name = 'block3_conv3')
self.block3_pool = MaxPooling2D((2,2),strides = (2,2),name = 'block3_pool')
self.block4_conv1 = Conv2D(512,(3,3),activation = 'relu',padding = 'same', name = 'block4_conv1')
self.block4_conv2 = Conv2D(512,(3,3),activation = 'relu',padding = 'same', name = 'block4_conv2')
self.block4_conv3 = Conv2D(512,(3,3),activation = 'relu',padding = 'same', name = 'block4_conv3')
self.block4_pool = MaxPooling2D((2,2),strides = (2,2),name = 'block4_pool')
# 第五个卷积部分
self.block5_conv1 = Conv2D(512,(3,3),activation = 'relu',padding = 'same', name = 'block5_conv1')
self.block5_conv2 = Conv2D(512,(3,3),activation = 'relu',padding = 'same', name = 'block5_conv2')
self.block5_conv3 = Conv2D(512,(3,3),activation = 'relu',padding = 'same', name = 'block5_conv3')
self.block5_pool = MaxPooling2D((2,2),strides = (2,2),name = 'block5_pool')
self.flatten = Flatten(name = 'flatten')
def call(self, inputs):
x = inputs
x = self.block1_conv1(x)
x = self.block1_conv2(x)
x = self.block1_pool(x)
x = self.block2_conv1(x)
x = self.block2_conv2(x)
x = self.block2_pool(x)
x = self.block3_conv1(x)
x = self.block3_conv2(x)
x = self.block3_conv3(x)
x = self.block3_pool(x)
x = self.block4_conv1(x)
x = self.block4_conv2(x)
x = self.block4_conv3(x)
x = self.block4_pool(x)
x = self.block5_conv1(x)
x = self.block5_conv2(x)
x = self.block5_conv3(x)
x = self.block5_pool(x)
outputs = self.flatten(x)
return outputs
2、比较网络
在获得主干特征提取网络之后,我们可以获取到一个多维特征,我们可以使用flatten的方式将其平铺到一维上,这个时候我们就可以获得两个输入的一维向量了
将这两个一维向量进行相减,再进行绝对值求和,相当于求取了两个特征向量插值的L1范数。也就相当于求取了两个一维向量的距离。
然后对这个距离再进行两次全连接,第二次全连接到一个神经元上,对这个神经元的结果取sigmoid,使其值在0-1之间,代表两个输入图片的相似程度。
实现代码如下:
import keras
from keras.layers import Input,Dense,Conv2D
from keras.layers import MaxPooling2D,Flatten,Lambda
from keras.models import Model
import keras.backend as K
import os
import numpy as np
from PIL import Image
from keras.optimizers import SGD
from nets.vgg import VGG16
def siamese(input_shape):
vgg_model = VGG16()
input_image_1 = Input(shape=input_shape)
input_image_2 = Input(shape=input_shape)
encoded_image_1 = vgg_model.call(input_image_1)
encoded_image_2 = vgg_model.call(input_image_2)
l1_distance_layer = Lambda(
lambda tensors: K.abs(tensors[0] - tensors[1]))
l1_distance = l1_distance_layer([encoded_image_1, encoded_image_2])
out = Dense(512,activation='relu')(l1_distance)
out = Dense(1,activation='sigmoid')(out)
model = Model([input_image_1,input_image_2],out)
return model
二、训练部分
1、数据集的格式
本文所使用的数据集为Omniglot数据集。
其包含来自 50不同字母(语言)的1623 个不同手写字符。
每一个字符都是由 20个不同的人通过亚马逊的 Mechanical Turk 在线绘制的。
相当于每一个字符有20张图片,然后存在1623个不同的手写字符,我们需要利用神经网络进行学习,去区分这1623个不同的手写字符,比较输入进来的字符的相似性。
本博客中数据存放格式有 * :
- image_background
- Alphabet_of_the_Magi
- character01
- 0709_01.png
- 0709_02.png
- ……
- character02
- character03
- ……
- Anglo-Saxon_Futhorc
- ……
最后一级的文件夹用于分辨不同的字体,同一个文件夹里面的图片属于同一文字。在不同文件夹里面存放的图片属于不同文字。
上两个图为.\images_background\Alphabet_of_the_Magi\character01里的两幅图。它们两个属于同一个字。
上一个图为.\images_background\Alphabet_of_the_Magi\character02里的一幅图。它和上面另两幅图不属于同一个字。
2、Loss计算
对于孪生神经网络而言,其具有两个输入。
当两个输入指向同一个类型的图片时,此时标签为1。
当两个输入指向不同类型的图片时,此时标签为0。
然后将网络的输出结果和真实标签进行交叉熵运算,就可以作为最终的loss了。
本文所使用的Loss为binary_crossentropy。
当我们输入如下两个字体的时候,我们希望网络的输出为1。
我们会将预测结果和1求交叉熵。
当我们输入如下两个字体的时候,我们希望网络的输出为0。
我们会将预测结果和0求交叉熵。
训练自己的孪生神经网络
1、训练本文所使用的Omniglot例子
下载数据集,放在根目录下的dataset文件夹下。
运行train.py开始训练。
2、训练自己相似性比较的模型
如果大家想要训练自己的数据集,可以将数据集按照如下格式进行摆放。
每一个chapter里面放同类型的图片。
之后将train.py当中的train_own_data设置成True,即可开始训练。
来源:https://blog.csdn.net/weixin_44791964/article/details/107343394


猜你喜欢
- 为了提高工作效率(偷懒),用python去解决。工作需要,需要将excel文件转化为csv文件,要是手工的一个个去转换,每个sheet页不但
- QQ登录Banner增加了剧情的概念之后,已经推出了春节和情人节两期。这之后设想能围绕Banner做的更加丰富,对传统文化的体现也能更为深入
- 每个被捕获的参数将被作为纯Python字符串来发送,而不管正则表达式中的格式。 举个例子,在这行URLConf中:(r'^artic
- 前言本文将由浅入深详细介绍yield以及generator,包括以下内容:什么generator,生成generator的方法,genera
- 1. 数据集基本信息df = pd.read_csv()df.head():前五行;df.info():rangeindex:行索引;dat
- HTML与CSS在Flash中的应用:不小心看到同事Den在弄个小东西:在Flash里使用HTML和CSS,代码是这样:var m
- 有时候需要一次性将SQL Server中的数据导出给其他部门的也许进行关联或分析,这种需求对于SSIS
- 编写兼容IE和FireFox的脚本确定的件很烦人的事,今日又经历了一次。一、正式表达式问题试图用以下表达式提取中括号“]”后面的内容,连接调
- 一、前言最近趁空闲之余,在对MySQL数据库进行插入数据测试,对于如何快速插入数据的操作无从下手,在仅1W数据量的情况下,竟花费接近47s,
- 问题1:解决没有NVSMI文件夹去英伟达官网下载显卡驱动,对显卡进行升级即可。问题2:nvidia-smi‘ 不是内部或
- argparse库是python下的一个命令行参数管理库,支持int、str、float、bool、数组等5种基本数据类型。在解析命令行参数
- python创建一个类很简单只需要定义它就可以了.class Cat: pass就像这样就可以了,通过创建子类我们可以继承他的父
- 一、建造者模式建造者模式,顾名思义类似于建筑工人,他们按照有条理的施工顺序(e.g. 打桩 => 浇筑框架 => 砌墙 =>
- python菜鸟,每天都要进步一点点。二维元组的例子:A = ((1, 1, 1), (1, 1, 1),(1, 1, 1),(0, 0,
- 此功能已进入试用一周了,都没有问题,奇怪的是今天出现了问题?? AjaxRequestObj.createEqStatusParameter
- 1 导言 Microsoft 在Microsoft SQL Server 2000中推出了与XML相关的功能以及Transact-SQL 关
- 开发工具:Microsoft Visual Studio 2005 数据库:Microsoft SQL Server 2005 说明:这里建
- 最近将Jesse James Garrett的《用户体验的要素》一书读了两遍,做一些简要的摘录并添加一些个人注释。当然,一本好书绝对不是简单
- 索引并不是时时都会生效的,比如以下几种情况,将导致索引失效:如果条件中有or,即使其中有条件带索引也不会使用(这也是为什么尽量少用or的原因
- 目录介绍:原理:1.标准import2.reload函数实现:总结:介绍:热更新,就是在服务器不重启的的情况下,对游戏增加新的功能或者修复出