-
Notifications
You must be signed in to change notification settings - Fork 13
Add Vector Transform Class and Operations #9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 3 commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
3591a56
Use forked branch for faiss repo. Add VectorTransform class.
aa2f667
Fix linux build and create new faiss x64 libraries with vector transf…
d97c791
Uncomment copy file code in project file that was commented out for d…
e7aeb7f
Make flattened vector signatures for vector transform and index searc…
35e44b0
Use class dimension properties for getters. Simplify VectorTransform …
a3c0e74
Adjust comment since multiple signature to the vector transform have …
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| using System; | ||
| using System.IO; | ||
| using Xunit; | ||
|
|
||
| namespace FaissMask.Test; | ||
|
|
||
| public class VectorTransformTests | ||
| { | ||
| private const string VectorTransformFileName = "data/vector_transform_1024_512.bin"; | ||
| private const int ExpectedDimensionIn = 1024; | ||
| private const int ExpectedDimensionOut = 512; | ||
| private readonly Random _random = new(42); | ||
|
|
||
| [Fact] | ||
| public void ReadsVectorTransformFile() | ||
| { | ||
| using var vectorTransform = VectorTransform.Read(VectorTransformFileName); | ||
| Assert.NotNull(vectorTransform); | ||
| Assert.Equal(ExpectedDimensionIn, vectorTransform.DimensionIn); | ||
| Assert.Equal(ExpectedDimensionOut, vectorTransform.DimensionOut); | ||
| } | ||
|
|
||
| [Theory] | ||
| [InlineData(1)] | ||
| [InlineData(10)] | ||
| public void AppliesAVectorTransform(int count) | ||
| { | ||
| using var vectorTransform = VectorTransform.Read(VectorTransformFileName); | ||
|
|
||
| var vectors = CreateRandomVectors(vectorTransform.DimensionIn, count); | ||
|
|
||
| var transformed = vectorTransform.Apply(vectors); | ||
|
|
||
| Assert.Equal(count, transformed.Length); | ||
| foreach (var vector in transformed) | ||
| { | ||
| Assert.Equal(vectorTransform.DimensionOut, vector.Length); | ||
| } | ||
|
|
||
| } | ||
|
|
||
| [Theory] | ||
| [InlineData(1)] | ||
| [InlineData(10)] | ||
| public void ThrowsExceptionWhenInputVectorsHaveInvalidLength(int count) | ||
| { | ||
| using var vectorTransform = VectorTransform.Read("data/vector_transform_1024_512.bin"); | ||
|
|
||
| var vectors = CreateRandomVectors(vectorTransform.DimensionIn - 1, count); | ||
|
|
||
| var ex = Assert.Throws<ArgumentException>(() => vectorTransform.Apply(vectors)); | ||
| Assert.Equal( | ||
| $"Invalid input vectors, each should have a length of {vectorTransform.DimensionIn} (Parameter 'vectors')", | ||
| ex.Message); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void ThrowsExceptionWhenVectorTransformFilenameParameterIsNull() | ||
| { | ||
| var ex = Assert.Throws<ArgumentNullException>(() => VectorTransform.Read(null)); | ||
| Assert.Equal("Value cannot be null. (Parameter 'filename')", ex.Message); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void ThrowsExceptionWhenVectorTransformFileDoesNotExist() | ||
| { | ||
| var ex = Assert.Throws<FileNotFoundException>(() => VectorTransform.Read("non_existent_file.bin")); | ||
| Assert.Equal("The file non_existent_file.bin does not exist", ex.Message); | ||
| } | ||
|
|
||
| private float[][] CreateRandomVectors(int dimension, int count) | ||
| { | ||
| var vectors = new float[count][]; | ||
| for (var i = 0; i < count; i++) | ||
| { | ||
| var vector = new float[dimension]; | ||
| for (var j = 0; j < vector.Length; j++) | ||
| { | ||
| vector[j] = _random.NextSingle(); | ||
| } | ||
| vectors[i] = vector; | ||
| } | ||
| return vectors; | ||
| } | ||
|
|
||
| } |
Binary file not shown.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| using System; | ||
| using System.IO; | ||
|
|
||
| namespace FaissMask.Internal | ||
| { | ||
| public class VectorTransformSafeHandle : SafeHandleZeroIsInvalid | ||
| { | ||
|
|
||
| protected internal VectorTransformSafeHandle(IntPtr pointer) : base(pointer) | ||
| { | ||
| } | ||
|
|
||
| public static THandle Read<THandle>(string filename, Func<IntPtr, THandle> createHandle) | ||
| where THandle : VectorTransformSafeHandle | ||
| { | ||
| if (string.IsNullOrEmpty(filename)) | ||
| { | ||
| throw new ArgumentNullException(nameof(filename)); | ||
| } | ||
|
|
||
| var fullPathFilename = Path.GetFullPath(filename); | ||
| if (!File.Exists(fullPathFilename)) | ||
| { | ||
| throw new FileNotFoundException($"The file {filename} does not exist", fullPathFilename); | ||
| } | ||
|
|
||
| var pointer = IntPtr.Zero; | ||
| var returnCode = NativeMethods.faiss_read_VectorTransform_fname(fullPathFilename, ref pointer); | ||
| if (returnCode != 0 || pointer == IntPtr.Zero) | ||
| { | ||
| var lastError = NativeMethods.faiss_get_last_error(); | ||
|
|
||
| if (string.IsNullOrEmpty(lastError)) | ||
| { | ||
| throw new IOException( | ||
| $"An unknown error occurred trying to read the vector transform '{fullPathFilename}' (return code {returnCode})"); | ||
| } | ||
|
|
||
| throw new IOException( | ||
| $"An error occurred trying to read the vector transform '{fullPathFilename}': {lastError} (return code {returnCode})"); | ||
| } | ||
|
|
||
| var safeHandle = createHandle(pointer); | ||
|
|
||
| return safeHandle; | ||
| } | ||
|
|
||
| public void Apply(long count, float[] vectors, float[] transformedVectors) | ||
| { | ||
| NativeMethods.faiss_VectorTransform_apply_noalloc(this, count, vectors, transformedVectors); | ||
| } | ||
|
|
||
| public int DimensionIn => NativeMethods.faiss_VectorTransform_d_in(this); | ||
|
|
||
| public int DimensionOut => NativeMethods.faiss_VectorTransform_d_out(this); | ||
|
|
||
| protected override bool ReleaseHandle() | ||
| { | ||
| if (!IsFree) | ||
| Free(); | ||
| return true; | ||
| } | ||
|
|
||
| private bool IsFree { get; set; } | ||
|
|
||
| protected internal void Free() | ||
| { | ||
| if (IsInvalid) return; | ||
| NativeMethods.faiss_VectorTransform_free(this); | ||
| IsFree = true; | ||
| } | ||
|
|
||
| } | ||
| } | ||
|
|
||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| using System; | ||
| using FaissMask.Extensions; | ||
| using FaissMask.Internal; | ||
|
|
||
| namespace FaissMask | ||
| { | ||
|
|
||
| public class VectorTransform(VectorTransformSafeHandle handle, int dimIn, int dimOut) : IDisposable | ||
| { | ||
| public static VectorTransform Read(string filename) | ||
| { | ||
| var handle = VectorTransformSafeHandle.Read(filename, ptr => new VectorTransformSafeHandle(ptr)); | ||
| var dimIn = handle.DimensionIn; | ||
| var dimOut = handle.DimensionOut; | ||
| return new VectorTransform(handle, dimIn, dimOut); | ||
| } | ||
|
|
||
| public int DimensionIn => handle.DimensionIn; | ||
| public int DimensionOut => handle.DimensionOut; | ||
|
|
||
| public float[][] Apply(float[][] vectors) | ||
| { | ||
| var count = vectors.Length; | ||
| var vectorsFlattened = vectors.Flatten(); | ||
|
|
||
| if (vectorsFlattened.Length != count * dimIn) | ||
| { | ||
| throw new ArgumentException($"Invalid input vectors, each should have a length of {dimIn}", nameof(vectors)); | ||
| } | ||
|
|
||
| var output = Apply(count, vectorsFlattened); | ||
|
|
||
| // convert to jagged array | ||
| // a possible optimization would be to use the flattened array signature | ||
| // directly and then pass that result to subsequent transforms or the search method, | ||
| // but these methods would need to be public. | ||
| var result = new float[count][]; | ||
| for (var i = 0; i < count; i++) | ||
| { | ||
| result[i] = new float[dimOut]; | ||
| Array.Copy(output, i * dimOut, result[i], 0, dimOut); | ||
| } | ||
|
|
||
| return result; | ||
| } | ||
|
|
||
| private float[] Apply(int count, float[] vectors) | ||
| { | ||
| var output = new float[count * dimOut]; | ||
| handle.Apply(count, vectors, output); | ||
| return output; | ||
| } | ||
|
|
||
| public void Dispose() | ||
| { | ||
| handle?.Free(); | ||
| handle?.Dispose(); | ||
| } | ||
| } | ||
|
|
||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,8 @@ | ||
| #!/bin/bash -e | ||
|
|
||
| FAISS_VERSION=${1:-main} | ||
| FAISS_VERSION=${1:-vector_transform_c_api} | ||
| GITHUB_ACCOUNT=${2:-makosten} | ||
| arch=amd64 | ||
| rm -f FaissMask/runtimes/linux-x64/native/* | ||
| docker-compose build --build-arg FAISS_VERSION=$FAISS_VERSION | ||
| docker run --rm -v $PWD:/host faissmask_test bash -c 'cp /src/FaissMask/runtimes/linux-x64/native/* /host/FaissMask/runtimes/linux-x64/native/' | ||
| docker-compose build --build-arg arch=$arch --build-arg FAISS_VERSION=$FAISS_VERSION --build-arg GITHUB_ACCOUNT=$GITHUB_ACCOUNT | ||
| docker run --platform=linux/${arch} --rm -v $PWD:/host faissmask-test bash -c 'cp /src/FaissMask/runtimes/linux-x64/native/* /host/FaissMask/runtimes/linux-x64/native/' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.