神经网络学习小记录51——Keras搭建孪生神经网络(Siamese network)比较图片相似性

2023-10-29

学习前言

最近学习了一下如何比较两张图片的相似性,用到了孪生神经网络,一起来学习一下。
在这里插入图片描述

什么是孪生神经网络

简单来说,孪生神经网络(Siamese network)就是“连体的神经网络”,神经网络的“连体”是通过共享权值来实现的,如下图所示。
在这里插入图片描述
所谓权值共享就是当神经网络有两个输入的时候,这两个输入使用的神经网络的权值是共享的(可以理解为使用了同一个神经网络)。

很多时候,我们需要去评判两张图片的相似性,比如比较两张人脸的相似性,我们可以很自然的想到去提取这个图片的特征再进行比较,自然而然的,我们又可以想到利用神经网络进行特征提取
如果使用两个神经网络分别对图片进行特征提取,提取到的特征很有可能不在一个域中,此时我们可以考虑使用一个神经网络进行特征提取再进行比较。这个时候我们就可以理解孪生神经网络为什么要进行权值共享了。

孪生神经网络有两个输入(Input1 and Input2),利用神经网络将输入映射到新的空间,形成输入在新的空间中的表示。通过Loss的计算,评价两个输入的相似度。

代码下载

https://github.com/bubbliiiing/Siamese-keras

孪生神经网络的实现思路

一、预测部分

1、主干网络介绍

在这里插入图片描述
孪生神经网络的主干特征提取网络的功能是进行特征提取,各种神经网络都可以适用,本文使用的神经网络是VGG16。
关于VGG的介绍大家可以看我的另外一篇博客https://blog.csdn.net/weixin_44791964/article/details/102779878
在这里插入图片描述
这是一个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,即可开始训练。
在这里插入图片描述

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

神经网络学习小记录51——Keras搭建孪生神经网络(Siamese network)比较图片相似性 的相关文章

随机推荐

  • 百度坐标(BD-09)、国测局坐标(火星坐标,GCJ-02)、和 WGS-84 坐标系之间的转换

    百度坐标 BD 09 国测局坐标 火星坐标 GCJ 02 和 WGS 84 坐标系之间的转换 Created by Wandergis on 2015 7 8 提供了百度坐标 BD 09 国测局坐标 火星坐标 GCJ 02 和 WGS 84
  • CentOS 7安装Zabbix 4.4

    我们当前部署Zabbix是在Centos7的基础上部署Zabbix4 4版本 我的服务器配置是双路四核CPU 8GBRAM 以下安装步骤仅供参考 大家也可以参考官方资料 https www zabbix com documentation
  • 142 环形链表

    142 环形链表 给定一个链表的头节点 head 返回链表开始入环的第一个节点 如果链表无环 则返回 null 重点在于如何判断是否有环 采用快慢指针的做法 快指针每次走2步 慢指针每次走1步 快指针相对慢指针每次多走一步 这样确保如果有环
  • Map Reduce和流处理

    欢迎大家前往腾讯云 社区 获取更多腾讯海量技术实践干货哦 本文由 从流域到海域翻译 发表于腾讯云 社区 map 和reduce 是在集群式设备上用来做大规模数据处理的方法 用户定义一个特定的映射 函数将使用该映射对一系列键值对进行处理 直接
  • C++日期累加

    日期累加 题目描述 设计一个程序能计算一个日期加上若干天后是什么日期 输入描述 输入第一行表示样例个数m 接下来m行每行四个整数分别表示年月日和累加的天数 输出描述 输出m行 每行按yyyy mm dd的个数输出 include
  • 深度学习(二):张量和基本运算

    张量是一个类型化的n维数组 tf Tensor 是tensorflow基本数据格式 张量的阶就是数组的维度 张量的属性 图 形状 名字 op print a graph 输出程序所在的内存地址 print a shape 输出张量a的维度
  • QtIFW学习

    1 构建Qt安装程序 1 1 Qt应用程序结构 1 2 不同操作系统常用的打包工具 1 2 1 多平台 GUI 安装程序 跨平台安装工具 1 2 2 windows 1 2 3 Linux 1 3 静态库与动态库的区别 2 程序打包过程 3
  • 一个注解就能下载任意对象?SpringBoot如此强大?

    下载功能应该是比较常见的功能了 虽然一个项目里面可能出现的不多 但是基本上每个项目都会有 而且有些下载功能其实还是比较繁杂的 倒不是难 而是麻烦 如果我说现在只需要一个注解就能帮你下载任意的对象 是不是觉得非常的方便 Download so
  • github一些有趣的使用场景和基本使用方法

    文章目录 github的使用入门 安装 Git 创建 GitHub 帐户 在本地设置 Git 克隆仓库 进行修改和提交 推送更改 拉取更新 删除Github上废弃的仓库 注意 github更多有趣的使用场景 协作和社交编程 文档和知识库 学
  • Spring Data JPA 使用Specification 实现动态查询

    实体对象 package com zzg entity import java util Date import javax persistence Column import javax persistence Entity import
  • 游戏开发UE4杂项系列:更换默认c++编辑器

    更换项目中使用的c 编辑器 编辑器 Edit gt 编辑器偏好设置 Edit Preference gt 通用 General gt 源代码 source code gt 源代码编辑器 source code edit 附加一个UE4使用交
  • 【死磕NIO】— 跨进程文件锁:FileLock

    大家好 我是大明哥 一个专注于 死磕 Java 系列创作的程序员 死磕 Java 系列为作者 chenssy 倾情打造的 Java 系列文章 深入分析 Java 相关技术核心原理及源码 死磕 Java https www cmsblogs
  • cin.get()处理输入的问题

    在C primer 中经常遇见while cin cin get n 的语句 此循环就是处理掉多余的流 实验代码如下 1 string b char a 10 cin get a 10 while cin get n continue ci
  • # 逆向神器:Ghidra简介及使用方法

    逆向神器 Ghidra简介及使用方法 https github com NationalSecurityAgency ghidra jdk https adoptium net zh CN temurin releases binwalk
  • mysql获取按日期排序获取最新的记录

    今天让一个数据查询难了 主要是对group by 理解的不够深入 才出现这样的情况 这种需求 我想很多人都遇到过 下面是我模拟我的内容表 我现在需要取出每个分类中最新的内容 select from test group by categor
  • Stable Diffusion 原理介绍与源码分析(二、DDPM、DDIM、PLMS算法分析)

    Stable Diffusion 原理介绍与源码分析 二 DDPM DDIM PLMS 文章目录 Stable Diffusion 原理介绍与源码分析 二 DDPM DDIM PLMS 系列文章 前言 与正文无关 可忽略 总览 DDPM 对
  • Maven学习笔记十七:Maven坐标和依赖(最佳实践之优化依赖)

    Maven坐标和依赖 最佳实践之优化依赖 在软件开发过程中 程序员会通过重构等方式不断地优化自己的代码 使其变得更简洁 更灵活 同理 程序员也应该能够对maven项目的依赖了然于胸 并对其进行优化 如去除多余的依赖 显式地声明某些必要的依赖
  • Objective-C中堆和栈的区别是什么?

    堆空间的内存是动态分配的 一般用于存放Objective C对象 并且需要手动释放内存 ARC环境下Objective C对象由编译器管理 不需要手动释放 栈空间的内存由系统自动分配 一般存放非Objective C对象的基本数据类型 例如
  • 【Linux】之 命令大全

    目录 一 帮助指令 二 目录操作指令 三 日期时间类 四 用户权限管理 root 五 文件属性 六 文件搜索类 七 压缩解压命令 八 磁盘查看和分区类 九 进程管理 十 系统定时任务 crontab 服务管理 十一 软件包管理 下载软件 十
  • 神经网络学习小记录51——Keras搭建孪生神经网络(Siamese network)比较图片相似性

    神经网络学习小记录51 Keras搭建孪生神经网络 Siamese network 比较图片相似性 学习前言 什么是孪生神经网络 代码下载 孪生神经网络的实现思路 一 预测部分 1 主干网络介绍 2 比较网络 二 训练部分 1 数据集的格式