diff --git a/ZeroLevel.HNSW/Model/Histogram.cs b/ZeroLevel.HNSW/Model/Histogram.cs index 20c1e55..f89ec1a 100644 --- a/ZeroLevel.HNSW/Model/Histogram.cs +++ b/ZeroLevel.HNSW/Model/Histogram.cs @@ -211,65 +211,68 @@ For I=Maxes[0] to Maxes[1] public int CuttOff() { - var grad = new int[Values.Length]; - grad[0] = 0; - grad[1] = 0; - for (int k = 2; k < Values.Length; k++) + if (Values.Length > 1) { - grad[k - 1] = Values[k] - Values[k - 1]; - } - var modes = 0; - var window = 0; - var sign = 1; - var sum = 0; - var max = 0; - var maxInd = 0; - var maxes = new List(); - do - { - maxes.Clear(); - window++; - modes = 0; - sum = 0; - for (int i = 0; i < grad.Length; i += window) + var grad = new int[Values.Length]; + grad[0] = 0; + grad[1] = 0; + for (int k = 2; k < Values.Length; k++) + { + grad[k - 1] = Values[k] - Values[k - 1]; + } + var modes = 0; + var window = 0; + var sign = 1; + var sum = 0; + var max = 0; + var maxInd = 0; + var maxes = new List(); + do { - sum = grad[i]; - max = Values[i]; - maxInd = i; - for (var w = 1; w < window && (i + w) < grad.Length; w++) + maxes.Clear(); + window++; + modes = 0; + sum = 0; + for (int i = 0; i < grad.Length; i += window) { - sum += grad[i + w]; - if (Values[i + w] > max) + sum = grad[i]; + max = Values[i]; + maxInd = i; + for (var w = 1; w < window && (i + w) < grad.Length; w++) { - max = Values[i + w]; - maxInd = i + w; + sum += grad[i + w]; + if (Values[i + w] > max) + { + max = Values[i + w]; + maxInd = i + w; + } + } + if (sum > 0 && sign < 0) + { + sign = 1; + } + else if (sum < 0 && sign > 0) + { + modes++; + maxes.Add(maxInd); + sign = -1; } } - if (sum > 0 && sign < 0) - { - sign = 1; - } - else if (sum < 0 && sign > 0) - { - modes++; - maxes.Add(maxInd); - sign = -1; - } - } - } while (modes > 2); - if (modes == 2) - { - var cutoff = maxes[0]; - var min = Values[cutoff]; - for (int i = maxes[0] + 1; i < maxes[1]; i++) + } while (modes > 2); + if (modes == 2) { - if (Values[i] < min) + var cutoff = maxes[0]; + var min = Values[cutoff]; + for (int i = maxes[0] + 1; i < maxes[1]; i++) { - cutoff = i; - min = Values[i]; + if (Values[i] < min) + { + cutoff = i; + min = Values[i]; + } } + return cutoff; } - return cutoff; } return -1; } diff --git a/ZeroLevel.HNSW/Model/NSWOptions.cs b/ZeroLevel.HNSW/Model/NSWOptions.cs index 1620a75..caf47a0 100644 --- a/ZeroLevel.HNSW/Model/NSWOptions.cs +++ b/ZeroLevel.HNSW/Model/NSWOptions.cs @@ -5,7 +5,7 @@ namespace ZeroLevel.HNSW public sealed class NSWOptions { /// - /// Mox node connections on Layer + /// Max node connections on Layer /// public readonly int M; /// diff --git a/ZeroLevel.HNSW/Services/LinksSet.cs b/ZeroLevel.HNSW/Services/LinksSet.cs index f1175a8..d431975 100644 --- a/ZeroLevel.HNSW/Services/LinksSet.cs +++ b/ZeroLevel.HNSW/Services/LinksSet.cs @@ -81,10 +81,10 @@ namespace ZeroLevel.HNSW } public void Deserialize(IBinaryReader reader) { - if (reader.ReadBoolean() != false) + /*if (reader.ReadBoolean() != false) { throw new InvalidOperationException("Incompatible format"); - } + }*/ _set.Clear(); _set = null; var count = reader.ReadInt32(); diff --git a/ZeroLevel.HNSW/Utils/VisitedBitSet.cs b/ZeroLevel.HNSW/Utils/VisitedBitSet.cs index 16de598..2e2469b 100644 --- a/ZeroLevel.HNSW/Utils/VisitedBitSet.cs +++ b/ZeroLevel.HNSW/Utils/VisitedBitSet.cs @@ -2,29 +2,29 @@ namespace ZeroLevel.HNSW { - internal class VisitedBitSet + public class VisitedBitSet { // bit map private int[] Buffer; - internal VisitedBitSet(int nodesCount, int M) + public VisitedBitSet(int nodesCount, int M) { Buffer = new int[(nodesCount >> 5) + M + 1]; } - internal bool Contains(int nodeId) + public bool Contains(int nodeId) { int carrier = Buffer[nodeId >> 5]; return ((1 << (nodeId & 31)) & carrier) != 0; } - internal void Add(int nodeId) + public void Add(int nodeId) { int mask = 1 << (nodeId & 31); Buffer[nodeId >> 5] |= mask; } - internal void Clear() + public void Clear() { Array.Clear(Buffer, 0, Buffer.Length); } diff --git a/ZeroLevel.NN/Architectures/Yolo5.cs b/ZeroLevel.NN/Architectures/Yolo5.cs new file mode 100644 index 0000000..0934a03 --- /dev/null +++ b/ZeroLevel.NN/Architectures/Yolo5.cs @@ -0,0 +1,17 @@ +namespace ZeroLevel.NN.Architectures +{ + internal class Yolo5 + : SSDNN + { + public Yolo5(string modelPath, int width, int height) + : base(modelPath) + { + this.InputH = height; + this.InputW = width; + } + + public int InputW { private set; get; } + + public int InputH { private set; get; } + } +} diff --git a/ZeroLevel.NN/Models/Cluster.cs b/ZeroLevel.NN/Models/Cluster.cs new file mode 100644 index 0000000..2024699 --- /dev/null +++ b/ZeroLevel.NN/Models/Cluster.cs @@ -0,0 +1,133 @@ +namespace ZeroLevel.NN.Models +{ + public class Cluster + { + private int _key; + private readonly List _points = new List(); + + public T this[int index] => _points[index]; + public IReadOnlyList Points => _points; + public int Key { get { return _key; } set { _key = value; } } + public Cluster() + { + } + + public Cluster(T point) + { + _points.Add(point); + } + + public Cluster(IEnumerable points) + { + _points.AddRange(points); + } + + public void Add(T point) + { + _points.Add(point); + } + + public void Remove(T point) + { + _points.Remove(point); + } + /* + public bool IsNeighbor(T feature, + Func embeddingFunction, + Func similarityFunction, + float threshold, + float clusterThreshold) + { + if (_points.Count == 0) return true; + if (_points.Count == 1) + { + var similarity = similarityFunction(embeddingFunction(feature), embeddingFunction(_points[0])); + return similarity >= threshold; + } + var clusterNearestElementsCount = 0; + foreach (var f in _points) + { + var similarity = similarityFunction(embeddingFunction(feature), embeddingFunction(f)); + if (similarity >= threshold) + { + clusterNearestElementsCount++; + } + } + var clusterToFaceScore = (float)clusterNearestElementsCount / (float)_points.Count; + return clusterToFaceScore > clusterThreshold; + } + */ + public bool IsNearest(T feature, + Func distanceFunction, + double maxDistance) + { + if (_points.Count == 0) return true; + if (_points.Count == 1) + { + var distance = distanceFunction(feature, _points[0]); + return distance <= maxDistance; + } + foreach (var f in _points) + { + var distance = distanceFunction(feature, f); + if (distance > maxDistance) + { + return false; + } + } + return true; + } + + public double MinimalDistance(T feature, + Func distanceFunction) + { + if (_points.Count == 0) return int.MaxValue; + var min = distanceFunction(feature, _points[0]); + if (_points.Count == 1) + { + return min; + } + for (int i = 0; i<_points.Count; i++) + { + var distance = distanceFunction(feature, _points[i]); + if (distance < min) + { + min = distance; + } + } + return min; + } + /* + public bool IsNeighborCluster(Cluster cluster, + Func embeddingFunction, + Func similarityFunction, + float threshold, + float clusterThreshold) + { + if (_points.Count == 0) return true; + if (_points.Count == 1 && cluster.IsNeighbor(_points[0], embeddingFunction, similarityFunction, threshold, clusterThreshold)) + { + return true; + } + var clusterNearestElementsCount = 0; + foreach (var f in _points) + { + if (cluster.IsNeighbor(f, embeddingFunction, similarityFunction, threshold, clusterThreshold)) + { + clusterNearestElementsCount++; + } + } + var localCount = _points.Count; + var remoteCount = cluster._points.Count; + var localIntersection = (float)clusterNearestElementsCount / (float)localCount; + var remoteIntersection = (float)clusterNearestElementsCount / (float)remoteCount; + var score = Math.Max(localIntersection, remoteIntersection); + return score > clusterThreshold; + } + */ + public void Merge(Cluster other) + { + this._points.AddRange(other.Points); + } + } +} diff --git a/ZeroLevel.NN/Services/SSDNN.cs b/ZeroLevel.NN/Services/SSDNN.cs index 4092f8d..87b65b1 100644 --- a/ZeroLevel.NN/Services/SSDNN.cs +++ b/ZeroLevel.NN/Services/SSDNN.cs @@ -11,9 +11,26 @@ namespace ZeroLevel.NN { private readonly InferenceSession _session; - public SSDNN(string path) + public SSDNN(string modelPath, bool gpu = false) { - _session = new InferenceSession(path); + if (gpu) + { + try + { + var so = SessionOptions.MakeSessionOptionWithCudaProvider(0); + so.GraphOptimizationLevel = GraphOptimizationLevel.ORT_ENABLE_ALL; + _session = new InferenceSession(modelPath, so); + } + catch (Exception ex) + { + Log.Error(ex, "Fault create InferenceSession with CUDA"); + _session = new InferenceSession(modelPath); + } + } + else + { + _session = new InferenceSession(modelPath); + } } protected void Extract(IDictionary> input, Action>> inputHandler) diff --git a/ZeroLevel.NN/ZeroLevel.NN.csproj b/ZeroLevel.NN/ZeroLevel.NN.csproj index fb7dea4..d2c9be4 100644 --- a/ZeroLevel.NN/ZeroLevel.NN.csproj +++ b/ZeroLevel.NN/ZeroLevel.NN.csproj @@ -3,14 +3,36 @@ net6.0 enable - enable + disable + True + embedded + none + 1.0.0.0 + Ogoun + Ogoun + Copyright Ogoun 2022 + zero.png + https://github.com/ogoun/Zero/wiki + https://github.com/ogoun/Zero + git + + False + + + + + True + \ + + + - + diff --git a/ZeroLevel/ZeroLevel.csproj b/ZeroLevel/ZeroLevel.csproj index d8e744e..cd57871 100644 --- a/ZeroLevel/ZeroLevel.csproj +++ b/ZeroLevel/ZeroLevel.csproj @@ -6,21 +6,22 @@ ogoun ogoun - 3.3.6.1 - New ConcurrentHashSet implementation + 3.3.6.2 + Update distance metrics https://github.com/ogoun/Zero/wiki Copyright Ogoun 2022 https://github.com/ogoun/Zero git - 3.3.6.1 - 3.3.6.1 + 3.3.6.2 + 3.3.6.2 AnyCPU;x64;x86 zero.png - full + none none zero.ico + AnyCPU