Il sistema di ricerca per immagini di seconda generazione
Questo articolo è la seconda parte di The Journey to Optimizing Billion-scale Image Search di UPYUN. Se vi siete persi la prima, fate clic qui.
Il sistema di ricerca per immagini di seconda generazione
Il sistema di ricerca per immagini di seconda generazione sceglie tecnicamente la soluzione CNN + Milvus. Il sistema si basa su vettori di caratteristiche e fornisce un supporto tecnico migliore.
Estrazione delle caratteristiche
Nel campo della computer vision, l'uso dell'intelligenza artificiale è diventato mainstream. Allo stesso modo, l'estrazione delle caratteristiche del sistema di ricerca per immagini di seconda generazione utilizza la rete neurale convoluzionale (CNN) come tecnologia di base.
Il termine CNN è difficile da capire. Qui ci concentriamo sulla risposta a due domande:
- Cosa può fare la CNN?
- Perché è possibile utilizzare la CNN per la ricerca di immagini?
1-meme.jpg
Ci sono molte competizioni nel campo dell'intelligenza artificiale e la classificazione delle immagini è una delle più importanti. Il compito della classificazione delle immagini è determinare se il contenuto dell'immagine riguarda un gatto, un cane, una mela, una pera o altri tipi di oggetti.
Cosa può fare la CNN? Può estrarre caratteristiche e riconoscere oggetti. Estrae le caratteristiche da più dimensioni e misura quanto le caratteristiche di un'immagine siano vicine a quelle di un gatto o di un cane. Possiamo scegliere quelle più vicine come risultato dell'identificazione, che indica se il contenuto di un'immagine specifica riguarda un gatto, un cane o qualcos'altro.
Qual è il legame tra la funzione di identificazione degli oggetti della CNN e la ricerca per immagini? Quello che vogliamo non è il risultato finale dell'identificazione, ma il vettore di caratteristiche estratto da più dimensioni. I vettori di caratteristiche di due immagini con contenuti simili devono essere vicini.
Quale modello CNN utilizzare?
La risposta è VGG16. Perché sceglierlo? Innanzitutto, VGG16 ha una buona capacità di generalizzazione, cioè è molto versatile. In secondo luogo, i vettori di caratteristiche estratti da VGG16 hanno 512 dimensioni. Se le dimensioni sono poche, l'accuratezza potrebbe risentirne. Se le dimensioni sono troppe, il costo della memorizzazione e del calcolo di questi vettori di caratteristiche è relativamente alto.
L'utilizzo di CNN per estrarre le caratteristiche dell'immagine è una soluzione tradizionale. Possiamo utilizzare VGG16 come modello e Keras + TensorFlow per l'implementazione tecnica. Ecco l'esempio ufficiale di Keras:
from keras.applications.vgg16 import VGG16
from keras.preprocessing import image
from keras.applications.vgg16 import preprocess_input
import numpy as np
model = VGG16(weights=’imagenet’, include_top=False)
img_path = ‘elephant.jpg’
img = image.load_img(img_path, target_size=(224, 224))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)
features = model.predict(x)
Le caratteristiche estratte sono vettori di caratteristiche.
1. Normalizzazione
Per facilitare le operazioni successive, spesso normalizziamo le caratteristiche:
Ciò che viene utilizzato successivamente è anche il vettori normalizzati norm_feat
.
2. Descrizione dell'immagine
L'immagine viene caricata utilizzando il metodo image.load_img
di keras.preprocessing
:
from keras.preprocessing import image
img_path = 'elephant.jpg'
img = image.load_img(img_path, target_size=(224, 224))
In realtà, si tratta del metodo TensorFlow chiamato da Keras. Per i dettagli, vedere la documentazione di TensorFlow. L'oggetto immagine finale è in realtà un'istanza di PIL Image (il PIL utilizzato da TensorFlow).
3. Conversione dei byte
In pratica, il contenuto delle immagini viene spesso trasmesso attraverso la rete. Pertanto, invece di caricare le immagini dal percorso, si preferisce convertire i dati dei byte direttamente in oggetti immagine, cioè in immagini PIL:
import io
from PIL import Image
# img_bytes: 图片内容 bytes
img = Image.open(io.BytesIO(img_bytes))
img = img.convert('RGB')
img = img.resize((224, 224), Image.NEAREST)
L'immagine qui sopra è uguale al risultato ottenuto con il metodo image.load_img. Ci sono due cose a cui prestare attenzione:
- È necessario eseguire la conversione RGB.
- È necessario ridimensionare (resize è il secondo parametro di
load_img method
).
4. Elaborazione del bordo nero
Le immagini, come le schermate, possono occasionalmente avere dei bordi neri. Questi bordi neri non hanno alcun valore pratico e causano molte interferenze. Per questo motivo, la rimozione dei bordi neri è una pratica comune.
Un bordo nero è essenzialmente una riga o colonna di pixel in cui tutti i pixel sono (0, 0, 0) (immagine RGB). Per rimuovere il bordo nero è necessario trovare queste righe o colonne ed eliminarle. Si tratta in realtà di una moltiplicazione matriciale 3D in NumPy.
Un esempio di rimozione dei bordi neri orizzontali:
# -*- coding: utf-8 -*-
import numpy as np
from keras.preprocessing import image
def RemoveBlackEdge(img):
Args:
img: PIL image instance
Returns:
PIL image instance
"""
width = img.width
img = image.img_to_array(img)
img_without_black = img[~np.all(img == np.zeros((1, width, 3), np.uint8), axis=(1, 2))]
img = image.array_to_img(img_without_black)
return img
Questo è più o meno ciò che voglio dire sull'uso della CNN per estrarre le caratteristiche dell'immagine e implementare altre elaborazioni dell'immagine. Ora diamo un'occhiata ai motori di ricerca vettoriali.
Motore di ricerca vettoriale
Il problema dell'estrazione dei vettori di caratteristiche dalle immagini è stato risolto. I problemi rimanenti sono:
- Come memorizzare i vettori di caratteristiche?
- Come calcolare la somiglianza dei vettori di caratteristiche, cioè come effettuare una ricerca? Il motore di ricerca vettoriale open-source Milvus può risolvere questi due problemi. Finora ha funzionato bene nel nostro ambiente di produzione.
3-milvus-logo.png
Milvus, il motore di ricerca vettoriale
L'estrazione di vettori di caratteristiche da un'immagine non è sufficiente. Dobbiamo anche gestire dinamicamente questi vettori di caratteristiche (aggiunta, eliminazione e aggiornamento), calcolare la somiglianza dei vettori e restituire i dati vettoriali nell'intervallo di prossimità. Il motore di ricerca vettoriale open-source Milvus svolge questi compiti abbastanza bene.
Nel resto dell'articolo verranno descritte le pratiche specifiche e i punti da tenere in considerazione.
1. Requisiti della CPU
Per utilizzare Milvus, la CPU deve supportare il set di istruzioni avx2. Per i sistemi Linux, utilizzare il seguente comando per verificare quali set di istruzioni supporta la propria CPU:
cat /proc/cpuinfo | grep flags
Si ottiene qualcosa di simile:
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good nopl xtopology nonstop_tsc cpuid aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 sdbg fma cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic movbe popcnt aes xsave avx f16c rdrand lahf_lm abm cpuid_fault epb invpcid_single pti intel_ppin tpr_shadow vnmi flexpriority ept vpid ept_ad fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid cqm xsaveopt cqm_llc cqm_occup_llc dtherm ida arat pln pts
Quello che segue i flag è il set di istruzioni supportato dalla vostra CPU. Naturalmente, questi sono molti di più di quelli di cui ho bisogno. Voglio solo vedere se uno specifico set di istruzioni, come avx2, è supportato. Basta aggiungere un grep per filtrarlo:
cat /proc/cpuinfo | grep flags | grep avx2
Se non viene restituito alcun risultato, significa che questo specifico set di istruzioni non è supportato. È quindi necessario cambiare macchina.
2. Pianificazione della capacità
La pianificazione della capacità è la nostra prima considerazione quando progettiamo un sistema. Quanti dati dobbiamo memorizzare? Di quanta memoria e di quanto spazio su disco necessitano i dati?
Facciamo qualche rapido calcolo. Ogni dimensione di un vettore è un float32. Un tipo float32 occupa 4 byte. Quindi un vettore di 512 dimensioni richiede 2 KB di memoria. Allo stesso modo:
- Mille vettori di 512 dimensioni richiedono 2 MB di memoria.
- Un milione di vettori a 512 dimensioni richiede 2 GB di memoria.
- 10 milioni di vettori a 512 dimensioni richiedono 20 GB di memoria.
- 100 milioni di vettori a 512 dimensioni richiedono 200 GB di memoria.
- Un miliardo di vettori a 512 dimensioni richiede 2 TB di memoria.
Se si desidera memorizzare tutti i dati nella memoria, il sistema deve avere almeno la capacità di memoria corrispondente.
Si consiglia di utilizzare lo strumento ufficiale di calcolo delle dimensioni: Milvus sizing tool.
In realtà la nostra memoria potrebbe non essere così grande (non importa se non si ha abbastanza memoria. Milvus scarica automaticamente i dati sul disco). Oltre ai dati vettoriali originali, dobbiamo anche considerare la memorizzazione di altri dati, come i log.
3. Configurazione del sistema
Per ulteriori informazioni sulla configurazione del sistema, consultare la documentazione di Milvus:
- Configurazione del server Milvus: https://milvus.io/docs/v0.10.1/milvus_config.md
4. Progettazione del database
Raccolta e partizione
- La collezione è nota anche come tabella.
- La partizione si riferisce alle partizioni all'interno di una collezione.
L'implementazione di base della partizione è in realtà identica a quella della collezione, tranne che per il fatto che una partizione si trova sotto una collezione. Ma con le partizioni, l'organizzazione dei dati diventa più flessibile. È anche possibile interrogare una partizione specifica in una collezione per ottenere risultati migliori.
Quante collezioni e partizioni si possono avere? Le informazioni di base sulle raccolte e sulle partizioni si trovano nei Metadati. Milvus utilizza SQLite (integrazione interna a Milvus) o MySQL (richiede una connessione esterna) per la gestione dei metadati interni. Se si usa SQLite per default per gestire i metadati, si avrà una grave perdita di prestazioni quando il numero di raccolte e partizioni è troppo grande. Pertanto, il numero totale di raccolte e partizioni non dovrebbe superare i 50.000 (Milvus 0.8.0 limita questo numero a 4.096). Se è necessario impostare un numero maggiore, si consiglia di utilizzare MySQL tramite una connessione esterna.
La struttura dei dati supportata dalla collezione e dalla partizione di Milvus è molto semplice, cioè ID + vector
. In altre parole, ci sono solo due colonne nella tabella: ID e dati vettoriali.
Nota:
- L'ID deve essere un numero intero.
- È necessario assicurarsi che l'ID sia unico all'interno di una collezione anziché di una partizione.
Filtraggio condizionale
Quando utilizziamo i database tradizionali, possiamo specificare i valori dei campi come condizioni di filtraggio. Sebbene Milvus non filtri esattamente nello stesso modo, possiamo implementare un semplice filtraggio condizionale utilizzando collezioni e partizioni. Ad esempio, abbiamo una grande quantità di dati di immagini e i dati appartengono a utenti specifici. Allora possiamo dividere i dati in partizioni per utente. Pertanto, utilizzare l'utente come condizione di filtro significa specificare la partizione.
Dati strutturati e mappatura vettoriale
Milvus supporta solo la struttura dei dati ID + vettoriale. Ma negli scenari aziendali, ciò di cui abbiamo bisogno sono dati strutturati che abbiano un significato commerciale. In altre parole, dobbiamo trovare i dati strutturati attraverso i vettori. Di conseguenza, è necessario mantenere le relazioni di mappatura tra dati strutturati e vettori attraverso l'ID.
structured data ID <--> mapping table <--> Milvus ID
Selezione dell'indice
È possibile fare riferimento ai seguenti articoli:
- Tipi di indice: https://www.milvus.io/docs/v0.10.1/index.md
- Come selezionare un indice: https://medium.com/@milvusio/how-to-choose-an-index-in-milvus-4f3d15259212
5. Elaborazione dei risultati della ricerca
I risultati della ricerca di Milvus sono una raccolta di ID + distanza:
- ID: l'ID in una raccolta.
- Distanza: un valore di distanza compreso tra 0 e 1 indica il livello di somiglianza; più piccolo è il valore, più simili sono i due vettori.
Filtrare i dati il cui ID è -1
Quando il numero di raccolte è troppo piccolo, i risultati della ricerca possono contenere dati il cui ID è -1. È necessario filtrarli da soli. È necessario filtrarli da soli.
Paginazione
La ricerca di vettori è molto diversa. I risultati dell'interrogazione sono ordinati in ordine decrescente di somiglianza e vengono selezionati i risultati più simili (topK) (topK è specificato dall'utente al momento dell'interrogazione).
Milvus non supporta la paginazione. Se ne abbiamo bisogno per lavoro, dobbiamo implementare la funzione di paginazione da soli. Ad esempio, se abbiamo dieci risultati in ogni pagina e vogliamo visualizzare solo la terza pagina, dobbiamo specificare che topK = 30 e restituire solo gli ultimi dieci risultati.
Soglia di somiglianza per il business
La distanza tra i vettori di due immagini è compresa tra 0 e 1. Se vogliamo decidere se due immagini sono simili in uno specifico scenario aziendale, dobbiamo specificare una soglia all'interno di questo intervallo. Le due immagini sono simili se la distanza è minore della soglia, oppure sono molto diverse tra loro se la distanza è maggiore della soglia. È necessario regolare la soglia per soddisfare le proprie esigenze aziendali.
Questo articolo è stato scritto da rifewang, utente di Milvus e ingegnere informatico di UPYUN. Se vi piace questo articolo, venite a salutarci su https://github.com/rifewang.
- Estrazione delle caratteristiche
- Motore di ricerca vettoriale
- Milvus, il motore di ricerca vettoriale
On This Page
Try Managed Milvus for Free
Zilliz Cloud is hassle-free, powered by Milvus and 10x faster.
Get StartedLike the article? Spread the word