SpringBoot集成Milvus和deeplearning4j實(shí)現(xiàn)圖搜圖功能
1.什么是Milvus?
Milvus 是一種高性能、高擴(kuò)展性的向量數(shù)據(jù)庫(kù),可在從筆記本電腦到大型分布式系統(tǒng)等各種環(huán)境中高效運(yùn)行。它既可以開(kāi)源軟件的形式提供,也可以云服務(wù)的形式提供。 Milvus 是 LF AI & Data Foundation 下的一個(gè)開(kāi)源項(xiàng)目,以 Apache 2.0 許可發(fā)布。大多數(shù)貢獻(xiàn)者都是高性能計(jì)算(HPC)領(lǐng)域的專家,擅長(zhǎng)構(gòu)建大型系統(tǒng)和優(yōu)化硬件感知代碼。核心貢獻(xiàn)者包括來(lái)自 Zilliz、ARM、NVIDIA、AMD、英特爾、Meta、IBM、Salesforce、阿里巴巴和微軟的專業(yè)人士
2.什么是deeplearning4j?
Deeplearning4j(DL4J)是一個(gè)開(kāi)源的深度學(xué)習(xí)框架,專門(mén)為Java和Scala開(kāi)發(fā)。它支持分布式計(jì)算,適合在大數(shù)據(jù)環(huán)境中運(yùn)行,比如與Hadoop或Spark集成。DL4J的特點(diǎn)包括:
- 多種網(wǎng)絡(luò)架構(gòu):支持多種深度學(xué)習(xí)模型,包括卷積神經(jīng)網(wǎng)絡(luò)(CNN)、循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)和深度信念網(wǎng)絡(luò)(DBN)。
- 集成與可擴(kuò)展性:能夠與大數(shù)據(jù)處理框架(如Apache Spark)和數(shù)據(jù)處理庫(kù)(如ND4J)緊密集成,方便處理大規(guī)模數(shù)據(jù)集。
- 易于使用:提供高層API,簡(jiǎn)化模型構(gòu)建和訓(xùn)練過(guò)程,同時(shí)也允許用戶對(duì)底層實(shí)現(xiàn)進(jìn)行細(xì)致的控制。
- 模型導(dǎo)入與導(dǎo)出:支持從其他框架(如Keras和TensorFlow)導(dǎo)入模型,并將訓(xùn)練好的模型導(dǎo)出為多種格式,以便于部署。
- 性能優(yōu)化:支持多種硬件加速,包括GPU加速,能夠提高訓(xùn)練和推理的效率。
- 支持多種應(yīng)用場(chǎng)景:廣泛應(yīng)用于計(jì)算機(jī)視覺(jué)、自然語(yǔ)言處理、推薦系統(tǒng)等多個(gè)領(lǐng)域。
Deeplearning4j是企業(yè)和開(kāi)發(fā)者進(jìn)行深度學(xué)習(xí)開(kāi)發(fā)和研究的強(qiáng)大工具,特別適合于需要與Java生態(tài)系統(tǒng)兼容的場(chǎng)景。
3.環(huán)境搭建
- First, we’ll need an instance of Milvus DB. The easiest and quickest way is to get a fully managed free Milvus DB instance provided by Zilliz Cloud: zilliz.com/
- For this, we’ll need to register for a Zilliz cloud account and follow the documentation for creating a free DB cluster.
4.代碼工程
實(shí)驗(yàn)?zāi)繕?biāo)
利用Milvus和deeplearning4j實(shí)現(xiàn)圖搜圖功能
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.1</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>Milvus</artifactId> <properties> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <deeplearning4j.version>1.0.0-M2.1</deeplearning4j.version> <nd4j.version>1.0.0-M2.1</nd4j.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-autoconfigure</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>io.milvus</groupId> <artifactId>milvus-sdk-java</artifactId> <version>2.4.0</version> </dependency> <dependency> <groupId>org.deeplearning4j</groupId> <artifactId>deeplearning4j-zoo</artifactId> <version>${deeplearning4j.version}</version> </dependency> <dependency> <groupId>org.nd4j</groupId> <artifactId>nd4j-native-platform</artifactId> <version>${nd4j.version}</version> </dependency> <dependency> <groupId>org.datavec</groupId> <artifactId>datavec-data-image</artifactId> <version>${deeplearning4j.version}</version> </dependency> <dependency> <groupId>org.deeplearning4j</groupId> <artifactId>deeplearning4j-core</artifactId> <version>${deeplearning4j.version}</version> </dependency> <dependency> <groupId>org.deeplearning4j</groupId> <artifactId>deeplearning4j-modelimport</artifactId> <version>${deeplearning4j.version}</version> </dependency> </dependencies> <build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <fork>true</fork> <failOnError>false</failOnError> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.2</version> <configuration> <forkCount>0</forkCount> <failIfNoTests>false</failIfNoTests> </configuration> </plugin> </plugins> </pluginManagement> </build> </project>
特征抽取
package com.et.imagesearch; import org.deeplearning4j.zoo.model.ResNet50; import org.deeplearning4j.zoo.ZooModel; import org.deeplearning4j.nn.graph.ComputationGraph; import org.nd4j.linalg.api.ndarray.INDArray; import org.nd4j.linalg.dataset.api.preprocessor.ImagePreProcessingScaler; import org.datavec.image.loader.NativeImageLoader; import java.io.File; import java.io.IOException; public class FeatureExtractor { private ComputationGraph model; public FeatureExtractor() throws IOException { try { ZooModel<ComputationGraph> zooModel = ResNet50.builder().build(); model = (ComputationGraph) zooModel.initPretrained(); } catch (Exception e) { throw new IOException("Failed to initialize the pre-trained model: " + e.getMessage(), e); } } public INDArray extractFeatures(File imageFile) throws IOException { NativeImageLoader loader = new NativeImageLoader(224, 224, 3); INDArray image = loader.asMatrix(imageFile); ImagePreProcessingScaler scaler = new ImagePreProcessingScaler(0, 1); scaler.transform(image); return model.outputSingle(image); } }
- 加載圖像: 使用
NativeImageLoader
將圖像加載為一個(gè)INDArray
,并將圖像的大小調(diào)整為 224x224 像素,通道數(shù)為 3(即 RGB 圖像)。 - 預(yù)處理圖像: 使用
ImagePreProcessingScaler
將圖像數(shù)據(jù)縮放到 [0, 1] 的范圍,以便模型可以更好地處理。 - 特征提取: 使用模型的
outputSingle()
方法將預(yù)處理后的圖像輸入模型,返回提取的特征向量。
Milvus數(shù)據(jù)庫(kù)操作
package com.et.imagesearch; import io.milvus.client.*; import io.milvus.param.*; import io.milvus.param.collection.*; import io.milvus.param.dml.*; import io.milvus.grpc.*; import io.milvus.param.index.CreateIndexParam; import org.nd4j.linalg.api.ndarray.INDArray; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; public class MilvusManager { private MilvusServiceClient milvusClient; public MilvusManager() { milvusClient = new MilvusServiceClient( ConnectParam.newBuilder() .withUri("https://xxx.gcp-us-west1.cloud.zilliz.com") .withToken("xxx") .build()); } public void createCollection() { FieldType idField = FieldType.newBuilder() .withName("id") .withDataType(DataType.Int64) .withPrimaryKey(true) .build(); FieldType vectorField = FieldType.newBuilder() .withName("embedding") .withDataType(DataType.FloatVector) .withDimension(1000) .build(); CreateCollectionParam createCollectionParam = CreateCollectionParam.newBuilder() .withCollectionName("image_collection") .withDescription("Image collection") .withShardsNum(2) .addFieldType(idField) .addFieldType(vectorField) .build(); milvusClient.createCollection(createCollectionParam); } public void insertData(long id, INDArray features) { List<Long> ids = Collections.singletonList(id); float[] floatArray = features.toFloatVector(); List<Float> floatList = new ArrayList<>(); for (float f : floatArray) { floatList.add(f); } List<List<Float>> vectors = Collections.singletonList(floatList); List<InsertParam.Field> fields = new ArrayList<>(); fields.add(new InsertParam.Field("id",ids)); fields.add(new InsertParam.Field("embedding", vectors)); InsertParam insertParam = InsertParam.newBuilder() .withCollectionName("image_collection") .withFields(fields) .build(); milvusClient.insert(insertParam); } public void flush() { milvusClient.flush(FlushParam.newBuilder() .withCollectionNames(Collections.singletonList("image_collection")) .withSyncFlush(true) .withSyncFlushWaitingInterval(50L) .withSyncFlushWaitingTimeout(30L) .build()); } public void buildindex() { // build index System.out.println("Building AutoIndex..."); final IndexType INDEX_TYPE = IndexType.AUTOINDEX; // IndexType long startIndexTime = System.currentTimeMillis(); R<RpcStatus> indexR = milvusClient.createIndex( CreateIndexParam.newBuilder() .withCollectionName("image_collection") .withFieldName("embedding") .withIndexType(INDEX_TYPE) .withMetricType(MetricType.L2) .withSyncMode(Boolean.TRUE) .withSyncWaitingInterval(500L) .withSyncWaitingTimeout(30L) .build()); long endIndexTime = System.currentTimeMillis(); System.out.println("Succeed in " + (endIndexTime - startIndexTime) / 1000.00 + " seconds!"); } }
- createCollection():
- 創(chuàng)建一個(gè)名為
image_collection
的集合,包含兩個(gè)字段:- id: 主鍵,類型為
Int64
。 - embedding: 特征向量,類型為
FloatVector
,維度為 1000。
- id: 主鍵,類型為
- 使用
CreateCollectionParam
指定集合的名稱、描述和分片數(shù)量,并調(diào)用createCollection
方法執(zhí)行創(chuàng)建操作。
- 創(chuàng)建一個(gè)名為
- insertData(long id, INDArray features):
- 插入一條新數(shù)據(jù)到
image_collection
集合中。 - 將
INDArray
類型的特征向量轉(zhuǎn)換為List<List<Float>>
格式,以滿足 Milvus 的插入要求。 - 創(chuàng)建一個(gè)
InsertParam
實(shí)例,包含 ID 和特征向量,并調(diào)用insert
方法執(zhí)行插入操作。
- 插入一條新數(shù)據(jù)到
- flush():
- 刷新
image_collection
集合,確保所有待處理的插入操作都被寫(xiě)入數(shù)據(jù)庫(kù)。 - 使用
FlushParam
配置同步刷新模式和等待參數(shù),確保操作的可靠性。
- 刷新
- buildindex():
- 構(gòu)建
image_collection
集合中embedding
字段的索引,以加快后續(xù)的相似性搜索。 - 使用
CreateIndexParam
指定集合名稱、字段名稱、索引類型(自動(dòng)索引)和度量類型(L2距離)。 - 調(diào)用
createIndex
方法執(zhí)行索引創(chuàng)建,并輸出所用時(shí)間。
- 構(gòu)建
圖片搜索功能
package com.et.imagesearch; import io.milvus.client.MilvusServiceClient; import io.milvus.grpc.SearchResults; import io.milvus.param.ConnectParam; import io.milvus.param.MetricType; import io.milvus.param.R; import io.milvus.param.dml.SearchParam; import io.milvus.response.SearchResultsWrapper; import org.nd4j.linalg.api.ndarray.INDArray; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.stream.Collectors; public class ImageSearcher { private MilvusServiceClient milvusClient; public ImageSearcher() { milvusClient = new MilvusServiceClient( ConnectParam.newBuilder() .withUri("https://ixxxxx.gcp-us-west1.cloud.zilliz.com") .withToken("xxx") .build()); } public void search(INDArray queryFeatures) { float[] floatArray = queryFeatures.toFloatVector(); List<Float> floatList = new ArrayList<>(); for (float f : floatArray) { floatList.add(f); } List<List<Float>> vectors = Collections.singletonList(floatList); SearchParam searchParam = SearchParam.newBuilder() .withCollectionName("image_collection") .withMetricType(MetricType.L2) .withTopK(5) .withVectors(vectors) .withVectorFieldName("embedding") .build(); R<SearchResults> searchResults = milvusClient.search(searchParam); System.out.println("Searching vector: " + queryFeatures.toFloatVector()); System.out.println("Result: " + searchResults.getData().getResults().getFieldsDataList()); } }
- 特征轉(zhuǎn)換: 將
INDArray
轉(zhuǎn)換為float[]
數(shù)組,然后將其轉(zhuǎn)換為List<Float>
。這是因?yàn)?Milvus 需要特定格式的向量輸入。 - 構(gòu)建搜索參數(shù): 創(chuàng)建一個(gè)
SearchParam
對(duì)象,指定要搜索的集合名稱、度量類型(例如 L2 距離)、返回的最相似的前 K 個(gè)結(jié)果、向量字段名稱以及搜索的向量數(shù)據(jù)。 - 執(zhí)行搜索: 使用
milvusClient
的search
方法執(zhí)行搜索,并將結(jié)果存儲(chǔ)在searchResults
中。 - 結(jié)果輸出: 打印出搜索的特征向量和搜索結(jié)果。
Main主類
package com.et.imagesearch; import org.nd4j.linalg.api.ndarray.INDArray; import java.io.File; import java.io.IOException; public class Main { public static void main(String[] args) throws IOException { FeatureExtractor extractor = new FeatureExtractor(); MilvusManager milvusManager = new MilvusManager(); ImageSearcher searcher = new ImageSearcher(); milvusManager.createCollection(); // images extract File[] imageFiles = new File("/Users/liuhaihua/ai/ut-zap50k-images-square/Boots/Ankle/Columbia").listFiles(); if (imageFiles != null) { for (int i = 0; i < imageFiles.length; i++) { INDArray features = extractor.extractFeatures(imageFiles[i]); milvusManager.insertData(i, features); } } milvusManager.flush(); milvusManager.buildindex(); // query File queryImage = new File("/Users/liuhaihua/ai/ut-zap50k-images-square/Boots/Ankle/Columbia/7247580.16952.jpg"); INDArray queryFeatures = extractor.extractFeatures(queryImage); searcher.search(queryFeatures); } }
以上只是一些關(guān)鍵代碼,所有代碼請(qǐng)參見(jiàn)下面代碼倉(cāng)庫(kù)
代碼倉(cāng)庫(kù)
5.測(cè)試
- 啟動(dòng)main方法
- 查看云數(shù)據(jù)中數(shù)據(jù)
- 控制臺(tái)可以看到搜圖結(jié)果
以上就是SpringBoot集成Milvus和deeplearning4j實(shí)現(xiàn)圖搜圖功能的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot Milvus和deeplearning4圖搜圖的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java調(diào)用構(gòu)造函數(shù)和方法及使用詳解
在Java編程中,構(gòu)造函數(shù)用于初始化新創(chuàng)建的對(duì)象,而方法則用于執(zhí)行對(duì)象的行為,構(gòu)造函數(shù)在使用new關(guān)鍵字創(chuàng)建類實(shí)例時(shí)自動(dòng)調(diào)用,沒(méi)有返回類型,并且名稱與類名相同,本文通過(guò)示例詳細(xì)介紹了如何在Java中使用構(gòu)造函數(shù)和方法,感興趣的朋友一起看看吧2024-10-10關(guān)于MyBatis 查詢數(shù)據(jù)時(shí)屬性中多對(duì)一的問(wèn)題(多條數(shù)據(jù)對(duì)應(yīng)一條數(shù)據(jù))
這篇文章主要介紹了MyBatis 查詢數(shù)據(jù)時(shí)屬性中多對(duì)一的問(wèn)題(多條數(shù)據(jù)對(duì)應(yīng)一條數(shù)據(jù)),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01Java連接數(shù)據(jù)庫(kù)步驟解析(Oracle、MySQL)
本文主要介紹了Java連接Oracle數(shù)據(jù)庫(kù)和MySQL數(shù)據(jù)庫(kù)的步驟解析。具有很好的參考價(jià)值,需要的朋友一起來(lái)看下吧2016-12-12java實(shí)現(xiàn)excel導(dǎo)出合并單元格的步驟詳解
這篇文章主要介紹了java實(shí)現(xiàn)excel導(dǎo)出合并單元格,通過(guò)使用Apache POI庫(kù),我們可以方便地創(chuàng)建Excel文件、填充數(shù)據(jù)、合并單元格和導(dǎo)出Excel文件,需要的朋友可以參考下2023-04-04Java對(duì)線程池做監(jiān)控的實(shí)現(xiàn)方法
本文主要介紹了Java對(duì)線程池做監(jiān)控的實(shí)現(xiàn)方法,監(jiān)控線程池可以幫助我們了解線程池的狀態(tài),如當(dāng)前活躍線程數(shù)、任務(wù)隊(duì)列長(zhǎng)度、已完成任務(wù)數(shù)等,下面就一起來(lái)了解一下2024-07-07SpringMVC空指針異常NullPointerException解決及原理解析
這篇文章主要介紹了SpringMVC空指針異常NullPointerException解決及原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08