Paket hnsw implementiert hierarchische schiffbare kleine Weltgrafiken in Go. Sie können sich darüber nachlesen, wie sie hier arbeiten. Im Wesentlichen ermöglichen sie eine schnelle ungefähre Suche nach dem nächsten Nachbarn mit hochdimensionalen Vektordaten.
Dieses Paket kann als In-Memory-Alternative zu Ihrer bevorzugten Vektordatenbank (z. B. Pnecone, WeaViate) betrachtet werden. Es implementiert nur die wesentlichen Operationen:
| Betrieb | Komplexität | Beschreibung |
|---|---|---|
| Einfügen | Fügen Sie einen Vektor in die Grafik ein | |
| Löschen | Löschen Sie einen Vektor aus der Grafik | |
| Suchen | Suchen Sie nach den nächsten Nachbarn eines Vektors | |
| Nachschlagen | Einen Vektor mit ID abrufen |
Notiz
Komplexitäten sind ungefähr wo
go get github.com/coder/hnsw@main
g := hnsw . NewGraph [ int ]()
g . Add (
hnsw . MakeNode ( 1 , [] float32 { 1 , 1 , 1 }),
hnsw . MakeNode ( 2 , [] float32 { 1 , - 1 , 0.999 }),
hnsw . MakeNode ( 3 , [] float32 { 1 , 0 , - 0.5 }),
)
neighbors := g . Search (
[] float32 { 0.5 , 0.5 , 0.5 },
1 ,
)
fmt . Printf ( "best friend: %v n " , neighbors [ 0 ]. Vec )
// Output: best friend: [1 1 1] Während alle Grafikvorgänge in Memory sind, bietet hnsw Einrichtungen zum Laden/Einsparungen durch anhaltendem Speicher.
Verwenden Sie für eine io.Reader / io.Writer -Schnittstelle Graph.Export und Graph.Import .
Wenn Sie eine einzelne Datei als Backend verwenden, bietet HNSW stattdessen einen praktischen SavedGraph -Typ:
path := "some.graph"
g1 , err := LoadSavedGraph [ int ]( path )
if err != nil {
panic ( err )
}
// Insert some vectors
for i := 0 ; i < 128 ; i ++ {
g1 . Add ( hnsw . MakeNode ( i , [] float32 { float32 ( i )}))
}
// Save to disk
err = g1 . Save ()
if err != nil {
panic ( err )
}
// Later...
// g2 is a copy of g1
g2 , err := LoadSavedGraph [ int ]( path )
if err != nil {
panic ( err )
}Weitere: mehr:
Wir verwenden eine schnelle Binärcodierung für das Diagramm, sodass Sie rechnen können, nahezu bei Scheibengeschwindigkeit zu speichern/zu laden. Auf meinem M3 -MacBook erhalte ich diese Benchmark -Ergebnisse:
goos: darwin
goarch: arm64
pkg: github.com/coder/hnsw
BenchmarkGraph_Import-16 4029 259927 ns/op 796.85 MB/s 496022 B/op 3212 allocs/op
BenchmarkGraph_Export-16 7042 168028 ns/op 1232.49 MB/s 239886 B/op 2388 allocs/op
PASS
ok github.com/coder/hnsw 2.624s
beim Speichern/Laden eines Diagramms von 100 Vektoren mit 256 Abmessungen.
Im Großen und Ganzen ist der größte Effekt, den Sie auf die Leistung des Diagramms haben können, die Dimensionalität Ihrer Daten. Bei 1536 Abmessungen (OpenAI -Standard) werden 70% des Abfragebegels unter Standardparametern in der Entfernungsfunktion ausgegeben.
Wenn Sie mit Langsamkeit / Latenz zu kämpfen haben, sollten Sie:
Und wenn Sie mit übermäßiger Speicherverwendung zu kämpfen haben, sollten Sie sich überlegen:
Graph.M (die maximale Anzahl der Nachbarn, die jeder Knoten haben kann)Graph.Ml (der Parameter der Ebenegenerierung) Der Speicheraufwand einer Grafik sieht aus wie:
Wo:
Sie können das schließen:
Im Beispiel eines Diagramms mit 256 Dimensionen und
und Gedächtniswachstum ist meistens linear.