Java实现LSH(Locality Sensitive Hash )
在对大批量数据进行图像处理的时候,比如说我提取SIFT特征,数据集为10W张图片,一个SIFT特征点是128维,一张图片提取出500个特征点,这样我们在处理的时候就是对5000万个128维的数据进行处理,这样处理所需要的耗时太长了,不符合实际生产的需要。我们需要用一种方法降低运算量,比如说降维。
看了一些论文,提到的较多的方法是LSH(Locality Sensitive Hash),就是局部敏感哈希。我们利用LSH方法在5000万个特征点中筛选出极少量的我们需要的特征点,在对这些极少量的数据进行计算,就可以得到我们想要的结果啦。
package com.demo.lsh; import com.demo.config.Constant;
import com.demo.dao.FeatureDao;
import com.demo.dao.FeatureTableDao;
import com.demo.dao.HashTableDao;
import com.demo.entity.HashTable;
import com.demo.utils.MD5Util;
import com.demo.utils.MathUtil;
import org.opencv.core.Mat;
import org.springframework.util.StringUtils; import java.io.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*; public class LSH {
//维度大小,例如对于sift特征来说就是128
private int dimention = Constant.DIMENTION;
//所需向量中元素可能的上限,譬如对于RGB来说,就是255
private int max = Constant.MAX;
//哈希表的数量,用于更大程度地削减false positive
private int hashCount = Constant.HASHCOUNT;
//LSH随机选取的采样位数,该值越小,则近似查找能力越大,但相应的false positive也越大;若该值等于size,则为由近似查找退化为精确匹配
private int bitCount = Constant.BITCOUNT;
//转化为01字符串之后的位数,等于max乘以dimensions
private int size = dimention * max;
//LSH哈希族,保存了随机采样点的INDEX
private int[][] hashFamily;
private HashTableDao hashTableDao;
/**
* 构造函数
*/
public LSH(HashTableDao hashTableDao) {
this.hashTableDao = hashTableDao;
dimention = Constant.DIMENTION;
max = Constant.MAX;
hashCount = Constant.HASHCOUNT;
bitCount = Constant.BITCOUNT;
size = dimention * max;
hashFamily = new int[hashCount][bitCount];
generataHashFamily();
} /**
* 生成随机的投影点 ,在程序第一次执行时生成。投影点可以理解为后面去数组的索引值
*/
private void generataHashFamily() {
if (new File("/home/fanxuan/data/1.txt").exists()) {
try {
InputStream in = new FileInputStream("/home/fanxuan/data/1.txt");
ObjectInputStream oin = new ObjectInputStream(in);
hashFamily = (int[][]) (oin.readObject());
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}else {
Random rd = new Random();
for (int i = 0; i < hashCount; i++) {
for (int j = 0; j < bitCount; j++) {
hashFamily[i][j] = rd.nextInt(size);
}
}
try {
OutputStream out = new FileOutputStream("/home/fanxuan/data/1.txt");
ObjectOutputStream oout = new ObjectOutputStream(out);
oout.writeObject(hashFamily);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
} //将向量转化为二进制字符串,比如元素的最大范围255,则元素65就被转化为65个1以及190个0
private int[] unAray(int[] data) {
int unArayData[] = new int[size];
for (int i = 0; i < data.length; i++) {
for (int j = 0; j < data[i]; j++) {
unArayData[i * max + j] = 1;
}
}
return unArayData;
} /**
* 将向量映射为LSH中的key
*/
private String generateHashKey(int[] list, int hashNum) {
StringBuilder sb = new StringBuilder();
int[] tempData = unAray(list);
int[] hashedData = new int[bitCount];
//首先将向量转为二进制字符串
for (int i = 0; i < bitCount; i++) {
hashedData[i] = tempData[hashFamily[hashNum][i]];
sb.append(hashedData[i]);
}
//再用常规hash函数比如MD5对key进行压缩
MessageDigest messageDigest = null;
try{
messageDigest = MessageDigest.getInstance("MD5");
}catch (NoSuchAlgorithmException e) { }
byte[] binary = sb.toString().getBytes();
byte[] hash = messageDigest.digest(binary);
String hashV = MD5Util.bufferToHex(hash);
return hashV;
} /**
* 将Sift特征点转换为Hash存表
*/
public void generateHashMap(String id, int[] vercotr, int featureId) {
for (int j = 0; j < hashCount; j++) {
String key = generateHashKey(vercotr, j);
HashTable hashTableUpdateOrAdd = new HashTable();
HashTable hashTable = hashTableDao.findHashTableByBucketId(key);
if (hashTable != null) {
String featureIdValue = hashTable.getFeatureId() + "," + featureId;
hashTableUpdateOrAdd.setFeatureId(featureIdValue);
hashTableUpdateOrAdd.setBucketId(key);
hashTableDao.updateHashTableFeatureId(hashTableUpdateOrAdd);
} else {
hashTableUpdateOrAdd.setBucketId(key);
hashTableUpdateOrAdd.setFeatureId(String.valueOf(featureId));
hashTableDao.insertHashTable(hashTableUpdateOrAdd);
}
}
} // 查询与输入向量最接近(海明空间)的向量
public List<String> queryList(int[] data) {
List<String> result = new ArrayList<>();
for (int j = 0; j < hashCount; j++) {
String key = generateHashKey(data, j);
result.add(key);
HashTable hashTable = hashTableDao.findHashTableByBucketId(key);
if (!StringUtils.isEmpty(hashTable.getFeatureId())) {
String[] str = hashTable.getFeatureId().split(",");
for (String string : str) {
result.add(string);
}
}
}
return result;
} }
package com.demo.config;
public class Constant {
//维度大小,例如对于sift特征来说就是128
public static final int DIMENTION = 128;
//所需向量中元素可能的上限,譬如对于RGB来说,就是255
public static final int MAX = 255;
//哈希表的数量,用于更大程度地削减false positive
public static final int HASHCOUNT = 12;
//LSH随机选取的采样位数,该值越小,则近似查找能力越大,但相应的false positive也越大;若该值等于size,则为由近似查找退化为精确匹配
public static final int BITCOUNT = 32;
}
简单的介绍下代码,构造函数LSH()用来建立LSH对象,hashTableDao为数据表操作对象,不多说;因为局部敏感哈希依赖与一套随机数,每次产生的结果都不一致,所以我们需要在程序第一次运行的时候将随机数生成并固定下来,我采用的方法是存放在本地磁盘中,也可以存放在数据库中。generateHashMap()方法为数据训练函数,int[] vercotr为特征向量,其他两个参数为我需要的标志位。queryList()方法是筛选方法。
感谢http://grunt1223.iteye.com/blog/944894的文章。
Java实现LSH(Locality Sensitive Hash )的更多相关文章
- 从NLP任务中文本向量的降维问题,引出LSH(Locality Sensitive Hash 局部敏感哈希)算法及其思想的讨论
1. 引言 - 近似近邻搜索被提出所在的时代背景和挑战 0x1:从NN(Neighbor Search)说起 ANN的前身技术是NN(Neighbor Search),简单地说,最近邻检索就是根据数据 ...
- Locality Sensitive Hash 局部敏感哈希
Locality Sensitive Hash是一种常见的用于处理高维向量的索引办法.与其它基于Tree的数据结构,诸如KD-Tree.SR-Tree相比,它较好地克服了Curse of Dimens ...
- LSH(Locality Sensitive Hashing)原理与实现
原文地址:https://blog.csdn.net/guoziqing506/article/details/53019049 LSH(Locality Sensitive Hashing)翻译成中 ...
- Locality Sensitive Hashing,LSH
1. 基本思想 局部敏感(Locality Senstitive):即空间中距离较近的点映射后发生冲突的概率高,空间中距离较远的点映射后发生冲突的概率低. 局部敏感哈希的基本思想类似于一种空间域转换思 ...
- [Algorithm] 局部敏感哈希算法(Locality Sensitive Hashing)
局部敏感哈希(Locality Sensitive Hashing,LSH)算法是我在前一段时间找工作时接触到的一种衡量文本相似度的算法.局部敏感哈希是近似最近邻搜索算法中最流行的一种,它有坚实的理论 ...
- 局部敏感哈希-Locality Sensitive Hashing
局部敏感哈希 转载请注明http://blog.csdn.net/stdcoutzyx/article/details/44456679 在检索技术中,索引一直须要研究的核心技术.当下,索引技术主要分 ...
- 局部敏感哈希算法(Locality Sensitive Hashing)
from:https://www.cnblogs.com/maybe2030/p/4953039.html 阅读目录 1. 基本思想 2. 局部敏感哈希LSH 3. 文档相似度计算 局部敏感哈希(Lo ...
- 转:locality sensitive hashing
Motivation The task of finding nearest neighbours is very common. You can think of applications like ...
- 转: memcached Java客户端spymemcached的一致性Hash算法
转自:http://colobu.com/2015/04/13/consistent-hash-algorithm-in-java-memcached-client/ memcached Java客户 ...
随机推荐
- C#类和结构(1)
1.结构功能特性? 实现代码? 结构用struct关键字定义的,与类类似,但有本质区别.结构实质是一个值类型,它不需要对分配的. 结构的特性: (1).结构作为参数传递时,是值传递. (2).结构的构 ...
- JAVA虚拟机(JVM)以及跨平台原理(JDK、JRE、JVM)
相信大家已经了解到Java具有跨平台的特性,可以“一次编译,到处运行”,在Windows下编写的程序,无需任何修改就可以在Linux下运行,这是C和C++很难做到的. 那么,跨平台是怎样实现的呢?这就 ...
- LeetCode:搜索二维矩阵【74】
LeetCode:搜索二维矩阵[74] 题目描述 编写一个高效的算法来判断 m x n 矩阵中,是否存在一个目标值.该矩阵具有如下特性: 每行中的整数从左到右按升序排列. 每行的第一个整数大于前一行的 ...
- Android:日常学习笔记(9)———探究持久化技术
Android:日常学习笔记(9)———探究持久化技术 引入持久化技术 什么是持久化技术 持久化技术就是指将那些内存中的瞬时数据保存到存储设备中,保证即使在手机或电脑关机的情况下,这些数据仍然不会丢失 ...
- 31 整数中1出现的次数(从1到n整数中1出现的次数)
题目描述 求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1.10.11.12.13因此共出现6次,但是对于后面问题他就没辙了. ...
- Apache Kudu
Apache Kudu是由Cloudera开源的存储引擎,可以同时提供低延迟的随机读写和高效的数据分析能力.Kudu支持水平扩展,使用Raft协议进行一致性保证,并且与Cloudera Impala和 ...
- ETL应用:使用Pro*C实现文件抽取的方法
/******************************************* ***** 函数功能 : ***** 抽取数据库记录 ***** ********************** ...
- jq中ajax的dataType:"json"是指什么?
dataType String 预期服务器返回的数据类型.如果不指定,jQuery 将自动根据 HTTP 包 MIME 信息来智能判断,比如XML MIME类型就被识别为XML.在1.4中,JSON就 ...
- 20145240《Java程序设计》第三周学习总结
20145240 <Java程序设计>第三周学习总结 教材学习内容总结 个人感觉第三周的学习量还是很大的,需要学习的内容更难了而且量也变多了,所以投入了更多的时间到Java的学习中去. 第 ...
- MySQL数据库基本操作(四)
在进行查询之前,我们要先建好关系表,并往数据表中插入些数据.为查询操作做好准备. 五张关系表的创建: #创建并进入数据库: mysql> CREATE DATABASE `info`; Quer ...