相似矩阵反推标签

2023-11-18

Background

有监督的多模态检索(supervised multi-modal retrieval)中,常用 label 构造相似矩阵 S。
样本集 X = { x i } i = 1 n X=\{x_i\}_{i=1}^n X={xi}i=1n,对应标签集 L = { l i } i = 1 n L=\{l_i\}_{i=1}^n L={li}i=1n。对任意两个样本 x i x_i xi x j x_j xj,若 l i l_i li l j l_j lj 至少有一个共同标签(即 l i T l j > 0 l_i^Tl_j>0 liTlj>0),则认为它们相似。计算相似矩阵 S 定义为:
S i , j = { 1 , x i 与 x j 相 似 0 , x i 与 x j 不 相 似 S_{i,j}=\begin{cases} 1, & x_i 与 x_j 相似 \\ 0, & x_i 与 x_j 不相似 \end{cases} Si,j={1,0,xixjxixj

Problem

在 supervised 设置下,一般基于 label 信息计算相似矩阵。想做的是在 UNsupervised 设置下,用一些奇技淫巧构造相似矩阵 S 之后,反求样本 label(使求得的 label 能算出同样的 S),后续用 label 搞事。

Idea 1: Learn-to-Label

像学 hash code 一样,将 label 当成参数,用网络学出来,约束就用 DLFH[1] 那条,或见 DCMH[2]

code

from tensorflow import ConfigProto, Session
from keras.backend.tensorflow_backend import set_session
config = ConfigProto()
config.gpu_options.allow_growth = True
set_session(Session(config=config))

import os
import argparse
from time import time
import numpy as np

import keras
import keras.backend as K
from keras.callbacks import Callback
from keras.models import Model
from keras.layers import Dense, Dropout, Activation, Input, Lambda

np.random.seed(int(time()))
parser = argparse.ArgumentParser()
parser.add_argument('--EPOCH', type=int, default=100)
parser.add_argument('--BATCH', type=int, default=64)
parser.add_argument('--SRC', type=str, default='data')
opt = parser.parse_args()
print(opt)


def load_data(fname):
    return np.load(os.path.join(opt.SRC, f'{fname}.npy'))


I_train = load_data('I_train')
I_val = load_data('I_val')

L_train = load_data('L_train')
L_val = load_data('L_val')

EPOCH = opt.EPOCH
BATCH = opt.BATCH
N_CLASS = L_train.shape[-1]
DIM_IMG = I_train.shape[-1]


@K.tf.custom_gradient
def Htanh(x):  # hard tanh
    def grad(dy):
        cond = (x >= -1) & (x <= 1)
        zeros = K.zeros_like(dy)
        return K.tf.where(cond, dy, zeros)
    return K.sign(x), grad


def gen_data(which='train', bat_sz=BATCH):
    if which == "train":
        Img, Lab = I_train, L_train
    elif which == "test":
        Img, Lab = I_val, L_val
    num = Lab.shape[0]
    S = (np.dot(Lab, Lab.T) > 0).astype(np.float32)
    while True:
        idx = np.random.choice(num, bat_sz)
        im, sim, lb = Img[idx], S[idx], Lab[idx]
        yield [im, sim], lb


# network
in_img = Input([DIM_IMG], name='image')
in_sim = Input([BATCH], name='similarity_matrix')

x = in_img
x = Dense(N_CLASS)(x)
x = Lambda(Htanh)(x)
l = x

m_train = Model([in_img, in_sim], l, name='train')
clf = Model(in_img, l, name='classifier')


def struct(y_true, y_pred):
    s_hat = in_sim * 2. - 1.
    theta = 0.5 * K.dot(y_pred, K.transpose(y_pred))
    loss = - K.log(0.5 * (1. - s_hat) + s_hat * K.sigmoid(theta) + 1e-9)
    return K.sum(loss)


S_val = (np.dot(L_train, L_train.T) > 0).astype(np.int)
tot = L_train.shape[0] ** 2
def test():
    l = clf.predict(I_train)
    sv = (np.dot(l, l.T) > 0).astype(np.int)
    # print('right:', np.sum(sv * S_val))
    # print('wrong:', np.sum(sv * (1 - S_val)))
    # print('--- S_val ---\n', S_val)
    # print(' --- sv ---\n', sv)
    print('S_val:', np.sum(S_val))  # 真·相似对数
    print('sv:', np.sum(sv))  # 预测的相似对数
    print('total:', tot)  # 总对数
    l_sum = np.sum(l, axis=-1)  # 各 label 的 1 个数
    L_sum = np.sum(L_train, axis=-1)
    print('mean discrepency:', np.mean(np.abs(l_sum - L_sum)))


class moniter(Callback):
    def on_epoch_end(self, epoch, logs=None):
        if epoch % 10 == 9 or epoch == 0:
            print(epoch, "> "*10)
            test()


m_train.compile('adam', loss=struct)
gen_train = gen_data('train')
gen_test = gen_data('test')
m_train.fit_generator(gen_train,
                  steps_per_epoch=I_train.shape[0]//BATCH,
                  epochs=EPOCH,
                  callbacks=[moniter()],
                  validation_data=gen_test,
                  verbose=0,
                  validation_steps=I_val.shape[0]//BATCH)

print('--- after ---')
# test()
clf.compile('adam', loss='binary_crossentropy', metrics=['binary_accuracy'])
print(clf.evaluate(I_train, L_train))

Idea 2

通过一个确定的过程构造 label。将相似矩阵 S 看成一幅无向图,贪心地染色(打标签)。

sample

a
b
i
c
g
d
e
f
h
j

code

from os.path import join
from scipy.spatial.distance import cdist
import numpy as np


def load_data(fname):
    return np.load(join('data', f'{fname}.npy'))


# L_train = load_data('L_train')
# L_val = load_data('L_val')
# L_ret = load_data('L_ret')


def construct_label(S):
    N = S.shape[0]  # 样本数
    vis_edge = np.identity(N, dtype=np.int)  # np.zeros_like(S)  # 已考虑过的边(相似关系)
    class_set = {}  # class_set[i]:i 类对应的样本 id
    class_id = 0  # class id 总数

    # 考虑孤立点(只同自己相似的样本)
    # 它们自己要拥有一个 label
    s_sum = np.sum(S, axis=-1)
    for i in range(N):
        if s_sum[i] == 1:
            vis_edge[i][i] = 0

    for now in range(N):
        # 邻接点集
        neighbour = set()
        for v in range(N):
            if S[now][v] == 1 and vis_edge[now][v] == 0:
                neighbour.add(v)

        while len(neighbour) > 0:
            v = neighbour.pop()
            if vis_edge[now][v] == 1:  # 已经考虑过
                continue
            vis_edge[now][v] = vis_edge[v][now] = 1

            elem = {now, v}  # 当前类的元素集
            for u in neighbour:
                # 看 now 的其它邻点能否加入当前类的元素集
                # 要求它同其它所有元素都是邻点
                can_in = True
                for e in elem:
                    if S[u][e] != 1:
                        can_in = False
                        break
                if can_in:
                    elem.add(u)
                    for e in elem:
                        vis_edge[u][e] = vis_edge[e][u] = 1
            
            class_set[class_id] = elem
            class_id += 1
            neighbour = neighbour - elem
    
    label = np.zeros((N, class_id))
    for lb in class_set:
        for x in class_set[lb]:
            label[x][lb] = 1

    # 检验是否已考虑所有相似关系
    for i in range(S.shape[0]):
        for j in range(S.shape[1]):
            if S[i][j] != vis_edge[i][j]:
                print(f's & vis_edge diff: ({i}, {j})')

    return label


if __name__ == '__main__':
	# 对应上图 sample
    # 样例手打的 label
    lab = np.array([
        [1, 1, 0, 0, 0, 0, 0, 0, 0],  # (1, 2)
        [1 ,0, 1, 1, 0, 0, 0, 0, 0],  # (1, 3, 4)
        [0, 0, 1, 0, 1, 0, 0, 0, 0],  # (3, 5)
        [0, 0, 0, 0, 1, 0, 0, 0, 0],  # (5)
        [0, 0, 0, 0, 1, 1, 0, 0, 0],  # (5, 6)
        [0, 0, 0, 0, 0, 0, 1, 0, 0],  # (7)
        [0, 0, 0, 1, 0, 6, 1, 1, 0],  # (4 ,6, 7, 8)
        [0, 0, 0, 0, 0, 0, 0, 1, 0],  # (8)
        [0, 1, 0, 0, 0, 0, 0, 1, 0],  # (2, 4)
        [0, 0, 0, 0, 0, 0, 0, 0, 1]   # (9),孤立点
    ])
    # 手打 label 算出的 S
    sim = (np.dot(lab, lab.T) > 0).astype(np.int)
    # 手打的 S
    sim_my = np.array([
        [1, 1, 0, 0, 0, 0, 0, 0, 1, 0],
        [1, 1, 1, 0, 0, 0, 1, 0, 0, 0],
        [0, 1, 1, 1, 1, 0, 0, 0, 0, 0],
        [0, 0, 1, 1, 1, 0, 0, 0, 0, 0],
        [0, 0, 1, 1, 1, 0, 1, 0, 0, 0],
        [0, 0, 0, 0, 0, 1, 1, 0, 0, 0],
        [0, 1, 0, 0, 1, 1, 1, 1, 1, 0],
        [0, 0, 0, 0, 0, 0, 1, 1, 1, 0],
        [1, 0, 0, 0, 0, 0, 1, 1, 1, 0],
        [0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
    ])
    ## 检验手打 S 和算出的 S 一致
    # for r in range(sim_my.shape[0]):
    #     for c in range(sim_my.shape[1]):
    #         if sim_my[r][c] != sim[r][c]:
    #             print(f'my sim diff: ({r}, {c})')
    # print('my sim finish')
    # print(sim - np.identity(sim.shape[0]))

    lab_hat = construct_label(sim)
    sim_hat = (np.dot(lab_hat, lab_hat.T) > 0).astype(np.int)
    print(lab.shape, lab_hat.shape, '\n', lab_hat)
    print(sim.shape, sim_hat.shape, '\n', sim_hat)

    # 原 S 和构造 S' 的差别
    for r in range(sim_hat.shape[0]):
        for c in range(sim_hat.shape[1]):
            if sim_hat[r][c] != sim[r][c]:
                print(f'sim diff: ({r}, {c})')
    print('sim finish')

    # 原 L 和构造 L' 的区别
    for r in range(lab_hat.shape[0]):
        for c in range(lab_hat.shape[1]):
            if lab_hat[r][c] != lab[r][c]:
                print(f'lab diff: ({r}, {c})')
    print('lab finish')

Discussion

第一种效果好像不太好。
第二种好像可以,在我构造的 sample 上虽然构造出的 label 同原来的标号有点对不上,但交换下顺序可以同原来的一样(同构)。
但当用 flickr-25k test set(2k 个 sample)的 label 测试时,发现构造的 label 虽然可以算出原来的 S,但 label 长了很多,即构造了更多的类别:原本只有 24 个,而构造的有 3412 个。而且用 training set 同用 test set 构造的 label 维度不同…显然这种构造法只是个弟弟。
而且第二种是在无向图下测试的,即 S 对称,在 supervised 下用 label 算出来的 S 可以满足,但 unsupervised 下构造的 S 可能是非对称的,如 [3],这时不知道还能不能用。

Future Work

  1. 更优的构造算法,使得构造的 class 不会多得那么夸张(最好可以同真 label 一样长,甚至可以惟一对应回原来的标签,就像在我上文构造的那个简单 sample 那样)
  2. 用于非对称 S 的构造法

References

  1. Discrete Latent Factor Model for Cross-Modal Hashing
  2. Deep Cross-Modal Hashing
  3. Unsupervised Generative Adversarial Cross-Modal Hashing
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

相似矩阵反推标签 的相关文章

  • 使用 InlineKeyboardButton python telegram bot 发送命令

    在Python电报机器人中 是否有可能InlineKeyboardButton发送类似命令 cancel当它被按下时 例如 当用户按下取消按钮时 他们将自动发送 cancel 命令 然后由机器人处理 从这里的例子来看 https githu
  • 使用单个文件的 Python 日志记录(函数名、文件名、行号)

    我正在尝试了解应用程序的工作原理 为此 我将调试命令插入作为每个函数主体的第一行 目的是记录函数的名称以及向日志输出发送消息的行号 代码内 最后 由于这个应用程序由许多文件组成 我想创建一个日志文件 以便我可以更好地理解应用程序的控制流 这
  • 安装tensorflow的正确命令

    当尝试在 Anaconda 上安装 Tensorflow 时 我尝试了两种类型的命令 conda install tensorflow gpu工作得很好 然而 当尝试conda install c anaconda tensorflow g
  • Keras ZeroDivisionError:整数除法或以零为模

    我正在尝试使用 Keras 和 Tensorflow 实现卷积神经网络 我有以下代码 from keras models import Sequential from keras layers import Conv2D MaxPoolin
  • 分配列表的多个值

    我很想知道是否有一种 Pythonic 方式将列表中的值分配给元素 为了更清楚 我要求这样的事情 myList 3 5 7 2 a b c d something myList So that a 3 b 5 c 7 d 2 我正在寻找比手
  • 如何在seaborn热图标签中使用科学计数法?

    我正在尝试在 python 中使用seaborn 获取热图 不幸的是 即使数字非常大 它也没有使用科学记数法 我想知道是否有任何简单的方法可以转换为科学记数法或任何其他合理的格式 这是显示问题的一段代码 import seaborn as
  • Django 查询:“datetime + delta”作为表达式

    好吧 我的问题如下 假设我有下一个模型 这是一个简单的情况 class Period models Model name CharField field specs here start date DateTimeField field s
  • Python函数组成

    我尝试使用良好的语法来实现函数组合 这就是我所得到的 from functools import partial class compfunc partial def lshift self y f lambda args kwargs s
  • 将多索引转换为行式多维 NumPy 数组。

    假设我有一个类似于以下示例的 MultiIndex DataFrame多索引文档 http pandas pydata org pandas docs stable advanced html gt gt gt df 0 1 2 3 fir
  • 样本()和r样本()有什么区别?

    当我从 PyTorch 中的发行版中采样时 两者sample and rsample似乎给出了类似的结果 import torch seaborn as sns x torch distributions Normal torch tens
  • 如何将 Pyspark Dataframe 标题设置到另一行?

    我有一个如下所示的数据框 col1 col2 col3 id name val 1 a01 X 2 a02 Y 我需要从中创建一个新的数据框 使用 row 1 作为新的列标题并忽略或删除 col1 col2 等行 新表应如下所示 id na
  • Python:“直接”调用方法是否实例化对象?

    我是 Python 新手 在对我的对象进行单元测试时 我注意到一些 奇怪 的东西 class Ape object def init self print ooook def say self s print s def main Ape
  • 在 pygame 中,我如何创建一个数据结构来跟踪调整大小事件和对象的坐标?

    我希望在调整屏幕大小后使鼠标事件与对象保持同步 有人告诉我需要创建一个数据结构来跟踪 调整事件大小 新坐标以匹配调整大小 如何使用简单的代数方程来完成此操作并将其集成到调整大小事件中以进行准确更新 反过来做 创建一个虚拟游戏地图 在绘制场景
  • 导入目录下的所有模块

    有没有办法导入当前目录中的所有模块 并返回它们的列表 例如 对于包含以下内容的目录 mod py mod2 py mod3 py 它会给你
  • 我可以在 if 语句中使用“as”机制吗

    是否可以使用as in if类似的声明with我们使用的 例如 with open tmp foo r as ofile do something with ofile 这是我的代码 def my list rtrn lst True if
  • 操作错误:尝试在 ubuntu 服务器中写入只读数据库

    我正在使用 FlaskApp 运行mod wsgi and apache2在 Ubuntu 服务器上 我尝试运行烧瓶应用程序localhost成功 然后部署到ubuntu服务器上 但是当我尝试更新数据库时 出现错误 Failed to up
  • 在 for 循环中访问 itertools 产品的元素

    我有一个列表列表 是附加 itertools 产品的一些其他结果的结果 我想要的是能够使用 for 循环访问列表列表中列表的每个元素 但我无法访问所有元素 我只能访问最后一个列表的元素 结果是一个非常巨大的列表列表 例如 1 2 4 3 6
  • Python matplotlib:将轴标签/图例从粗体更改为常规粗细

    我正在尝试制作一些出版质量的图 但遇到了一个小问题 默认情况下 matplotlib 轴标签和图例条目的权重似乎比轴刻度线重 是否有办法强制轴标签 图例条目与刻度线的重量相同 import matplotlib pyplot as plt
  • 避免“散点/点/蜂群”图中的数据点重叠

    使用绘制点图时matplotlib 我想偏移重叠的数据点以使它们全部可见 例如 如果我有 CategoryA 0 0 3 0 5 CategoryB 5 10 5 5 10 我想要每一个CategoryA 0 数据点并排设置 而不是彼此重叠
  • PYTHON:从 txt 文件中删除 POS 标签

    我有以下 txt 文件 其中包含 POS 词性 http en wikipedia org wiki Part of speech tagging 每个单词的标签 不用 jj到 说 vb 我 ppss是 bedz愤怒 jj在 在 dt无与伦

随机推荐

  • 支持本地挂载的网盘文件列表工具AList

    什么是 Alist AList 是一个支持多存储的文件列表程序 使用 Gin 框架和 Solidjs 库 可以将常见的 18 种网盘整合在一起 并支持 WebDAV 客户端访问 之前老苏写过一篇 Alist 但此 Alist 非彼 Alis
  • Hyperledger2.0 链码安装

    文章目录 简介 package install approveformyorg commit 半自动化安装链码 简介 以Hyperldger2 0为例 链码的安装主要分为以下几部分 package 打包源代码 install 安装链码 ap
  • Embedded world conference 2015

    本文转载至 http www embedded world eu program html 一些相关的议程 Tuesday February 24 13 30 14 30 Keynote 1 Conference Keynote 09 30
  • k3服务器端的虚拟,k3服务器 客户端配置

    k3服务器 客户端配置 内容精选 换一换 选择Windows开发环境下 安装Eclipse 安装JDK 请安装JDK1 8及以上版本 Eclipse使用支持JDK1 8及以上的版本 并安装JUnit插件 若使用IBM JDK 请确保Ecli
  • 想搞清是服务器否存在内存泄漏或jvm其他方面的问题

    解决问题 想搞清是服务器否存在内存泄漏或jvm其他方面的问题 heap dump heap dump文件是一个二进制文件 它保存了某一时刻JVM堆中对象使用情况 HeapDump文件是指定时刻的Java堆栈的快照 是一种镜像文件 Heap
  • 深度学习总结(一)

    深度学习总结 一 1 经典优化算法 1 一阶迭代法 又称梯度下降法 2 二阶迭代法 牛顿法 一般在神经网络里面 L 函数就是代价函数 2 不同梯度下降法 1 经典梯度下降法 2 随机梯度下降法 随机梯度下降法可以解决经典梯度下降法数据量大
  • 代码随想录算法训练营第一天

    704 二分查找 题目链接 力扣 二分法写代码时一般是写左闭右闭和左闭右开两种类型 左闭右闭 left right 左闭右开 left right 指右边不包含right这个值 int right size 两大问题 while left
  • 全新的刷脸支付开辟一条全新发展之路

    数字化和刷脸支付的强强联合给众多商家带去希望和惊喜 崭新的2021年 这个惊喜仍然在继续 数字化经营刷脸支付 如何为创业者带去商机 2020年 是刷脸支付发展的黄金时期 它曾因为疫情跌落到谷底 却也因为疫情再次飞上云端 重拾自信 在行业巨头
  • form 校验多个表单

    有的时候 表单需要拆开多个 这时候就需要校验多个表单
  • Qt 学习之路:线程和 QObject

    前面两个章节我们从事件循环和线程类库两个角度阐述有关线程的问题 本章我们将深入线程间得交互 探讨线程和QObject之间的关系 在某种程度上 这才是多线程编程真正需要注意的问题 现在我们已经讨论过事件循环 我们说 每一个 Qt 应用程序至少
  • c# winform对数据库进行增删改查操作

    开发工具 sqlserver2012 visoual code 2017 打开sqlserver2012 创建一个表 表结构如下 然后打开VS2017 文件 新建 项目 Windows窗体应用 这里我就在工具箱拉取了三个button和一个显
  • VS Code+Anaconda(国内源)配置python

    一 Anaconda的介绍 为何使用 优点 二 Anaconda下载和安装 三 VS Code下载及安装 四 Anaconda更换国内源 原因及操作方法 操作方法 具体操作方法 记得看上边优秀博客 五 TensorFlow环境 配置原因及优
  • equals底层

    Equals底层实现 这篇文章有抄两个博主的东西 请不要介意 学习最重要 主要怕你们什么时候删帖看不到 谢谢 在基础类型中都重写了equals方法 但是Object中的equals的方法如果不重写就没有意义 因为源代码中equals直接用
  • Equals和HashMap的重写

    一 首先 老铁们应该先了解API中的HashCode和equals解释 1 如果两个对象相同 即用equals比较返回true 那么它们的hashCode值一定要相同 2 如果两个对象的hashCode相同 它们并不一定相同 即用equal
  • 光敏传感器简介

    光敏传感器 1 简介 光敏传感器是最常见的传感器之一 它的种类繁多 主要有 光电管 光电倍增管 光敏电阻 光敏三极管 太阳能电池 红外线传感器 紫外线传感器 光纤式光电传感器 色彩传感器 CCD和CMOS图像传感器等 光传感器是目前产量最多
  • Spring boot按日切分nohup.out日志文件的方法

    过大的日志文件维护起来存在诸多问题 所以最好是能够按日或按大小切分日志文件 下面给大家带来了Spring boot按日切分spring boot的nohup out日志文件的方法 方法如下 1 安装cronolog 2 执行以下命令启动应用
  • 完美解决umi+ProLayout 部分菜单动态的问题

    项目中用到这个框架 当然是很好用且方便的 但是实际使用的时候发现项目中限制了一些自定义内容 踩了几个坑 记录一下 动态菜单调用接口异步 页面上显示空白 解决方案 将方法放在getInitialState中查询 存在initialState里
  • 线性回归算法--拟合正弦函数

    目录 步骤 代码实现 本博客参考书籍 scikit learn机器学习 常用算法原理及编程实战 本博客源码地址 码云 步骤 生成200个在 2 2
  • Jeesite权限处理,权限分配,根据不同的用户展示不同的信息,按钮权限等

    jeesite关于权限这方面的记录或者文章很少 看官方文档又看不懂 自己的业务又需要进行权限处理 怎么办 当然问大佬了 我就记录下我的解决办法 给jeesite权限方面的文章做点贡献 我先说下我的业务逻辑 我需要实现不同公司的人登陆后台 只
  • 相似矩阵反推标签

    Background 有监督的多模态检索 supervised multi modal retrieval 中 常用 label 构造相似矩阵 S 样本集 X x i