diff --git a/LLama.Examples/LLama.Examples.csproj b/LLama.Examples/LLama.Examples.csproj index f46a381d3..9bc41b0b7 100644 --- a/LLama.Examples/LLama.Examples.csproj +++ b/LLama.Examples/LLama.Examples.csproj @@ -29,6 +29,7 @@ + diff --git a/LLama.Experimental/Extensions/NativeLibraryAutoDownloadExtension.cs b/LLama.Experimental/Extensions/NativeLibraryAutoDownloadExtension.cs new file mode 100644 index 000000000..106c322d1 --- /dev/null +++ b/LLama.Experimental/Extensions/NativeLibraryAutoDownloadExtension.cs @@ -0,0 +1,76 @@ +using LLama.Experimental.Native; + +namespace LLama.Native +{ +#if NET6_0_OR_GREATER + public static class NativeLibraryAutoDownloadExtension + { + /// + /// Set whether to download the best-matched native library file automatically if there's no backend or specified file to load. + /// You could add a setting here to customize the behavior of the download. + /// + /// * If auto-download is enabled, please call after you have finished setting your configurations. + /// + /// + /// + /// + /// + /// + public static NativeLibraryConfig WithAutoDownload(this NativeLibraryConfig config, bool enable = true, NativeLibraryDownloadSettings? settings = null) + { + if (config.LibraryHasLoaded) + { + throw new Exception("The library has already loaded, you can't change the configurations. " + + "Please finish the configuration setting before any call to LLamaSharp native APIs." + + "Please use NativeLibraryConfig.DryRun if you want to see whether it's loaded successfully " + + "but still have chance to modify the configurations."); + } + if (enable) + { + if(settings is null) + { + settings = NativeLibraryDownloadSettings.Create(); + } + // Don't modify and pass the original object to `Description`, create a new one instead. + // Also, we need to set the default local directory if the user does not. + if (string.IsNullOrEmpty(settings.Tag)) + { + settings = settings.WithTag(GetNativeLibraryCommitHash()); + } + var defaultLocalDir = NativeLibraryDownloadSettings.GetDefaultLocalDir(settings.Tag); + settings = settings.WithLocalDir(settings.LocalDir ?? defaultLocalDir); + + // When using auto-download, this should be the only search directory. + List searchDirectoriesForDownload = [settings.LocalDir!]; + // unless extra search paths are added by the user. + searchDirectoriesForDownload.AddRange(settings.ExtraSearchDirectories ?? []); + config.WithSearchDirectories(searchDirectoriesForDownload); + + config.WithSelectingPolicy(new SelectingPolicyWithAutoDownload(settings)); + } + return config; + } + + private const string COMMIT_HASH = "a743d7"; + + private static string GetNativeLibraryCommitHash() => COMMIT_HASH; + + /// + /// Set whether to download the best-matched native library file automatically if there's no backend or specified file to load. + /// You could add a setting here to customize the behavior of the download. + /// + /// If auto-download is enabled, please call after you have finished setting your configurations. + /// + /// + /// + /// + /// + public static NativeLibraryConfigContainer WithAutoDownload(this NativeLibraryConfigContainer container, + bool enable = true, NativeLibraryDownloadSettings? settings = null) + { + container.ForEach((config) => config.WithAutoDownload(enable, settings)); + return container; + } + } +#endif +} diff --git a/LLama.Experimental/LLama.Experimental.csproj b/LLama.Experimental/LLama.Experimental.csproj new file mode 100644 index 000000000..80d84084d --- /dev/null +++ b/LLama.Experimental/LLama.Experimental.csproj @@ -0,0 +1,42 @@ + + + + net6;net7;net8;netstandard2.0 + enable + enable + 12 + LLama + + 0.12.0 + Rinne + SciSharp STACK + true + MIT, SciSharp STACK $([System.DateTime]::UtcNow.ToString(yyyy)) + https://github.com/SciSharp/LLamaSharp + git + https://avatars3.githubusercontent.com/u/44989469?s=200&v=4 + LLama, LLM, GPT, ChatGPT, NLP, AI, Chat Bot, SciSharp + + LLamaSharp.Experimental is a package with some experimental features and aggressive updates. + This package includes some important features in advance, but is less stable. + + + Support native library auto-download. + + MIT + $(SolutionDir)/packages + AnyCPU;x64;Arm64 + LLamaSharp.Experimental + Debug;Release;GPU + false + + + + + + + + + + + diff --git a/LLama.Experimental/Native/AutoDownloadedLibraries.cs b/LLama.Experimental/Native/AutoDownloadedLibraries.cs new file mode 100644 index 000000000..9a98bec76 --- /dev/null +++ b/LLama.Experimental/Native/AutoDownloadedLibraries.cs @@ -0,0 +1,91 @@ +using LLama.Abstractions; +using LLama.Native; + +namespace LLama.Experimental.Native +{ +#if NET6_0_OR_GREATER + public class AutoDownloadedLibraries + { + public class Cuda: INativeLibrary + { + private NativeLibraryWithCuda _cudaLibrary; + private NativeLibraryDownloadSettings _settings; + + public Cuda(NativeLibraryWithCuda cudaLibrary, NativeLibraryDownloadSettings settings) + { + _cudaLibrary = cudaLibrary; + _settings = settings; + } + + public NativeLibraryMetadata? Metadata => _cudaLibrary.Metadata; + + public IEnumerable Prepare(SystemInfo systemInfo, NativeLogConfig.LLamaLogCallback? logCallback = null) + { + foreach(var relativePath in _cudaLibrary.Prepare(systemInfo, logCallback)) + { + yield return relativePath; + var path = NativeLibraryDownloader.DownloadLibraryFile(_settings, relativePath, logCallback).Result; + if (path is not null) + { + yield return path; + } + } + } + } + + public class Avx : INativeLibrary + { + private NativeLibraryWithAvx _avxLibrary; + private NativeLibraryDownloadSettings _settings; + + public Avx(NativeLibraryWithAvx avxLibrary, NativeLibraryDownloadSettings settings) + { + _avxLibrary = avxLibrary; + _settings = settings; + } + + public NativeLibraryMetadata? Metadata => _avxLibrary.Metadata; + + public IEnumerable Prepare(SystemInfo systemInfo, NativeLogConfig.LLamaLogCallback? logCallback = null) + { + foreach (var relativePath in _avxLibrary.Prepare(systemInfo, logCallback)) + { + yield return relativePath; + var path = NativeLibraryDownloader.DownloadLibraryFile(_settings, relativePath, logCallback).Result; + if (path is not null) + { + yield return path; + } + } + } + } + + public class MacOrFallback : INativeLibrary + { + private NativeLibraryWithMacOrFallback _macLibrary; + private NativeLibraryDownloadSettings _settings; + + public MacOrFallback(NativeLibraryWithMacOrFallback macLibrary, NativeLibraryDownloadSettings settings) + { + _macLibrary = macLibrary; + _settings = settings; + } + + public NativeLibraryMetadata? Metadata => _macLibrary.Metadata; + + public IEnumerable Prepare(SystemInfo systemInfo, NativeLogConfig.LLamaLogCallback? logCallback = null) + { + foreach (var relativePath in _macLibrary.Prepare(systemInfo, logCallback)) + { + yield return relativePath; + var path = NativeLibraryDownloader.DownloadLibraryFile(_settings, relativePath, logCallback).Result; + if (path is not null) + { + yield return path; + } + } + } + } + } +#endif +} diff --git a/LLama.Experimental/Native/NativeLibraryDownloader.cs b/LLama.Experimental/Native/NativeLibraryDownloader.cs new file mode 100644 index 000000000..4e12aa502 --- /dev/null +++ b/LLama.Experimental/Native/NativeLibraryDownloader.cs @@ -0,0 +1,268 @@ +using HuggingfaceHub; + +namespace LLama.Native +{ + internal class NativeLibraryDownloader + { + /// + /// Download the library file + /// + /// + /// + /// + /// The local path of the file if successful otherwise null. + public static async Task DownloadLibraryFile(NativeLibraryDownloadSettings settings, string remoteFilePath, NativeLogConfig.LLamaLogCallback? logCallback = null) + { + if (settings.LocalDir is null) + { + // Null local directory is not expected here (it will make things more complex if we want to handle it). + // It should always be set when gathering the description. + throw new Exception("Auto-download is enabled for native library but the `LocalDir` is null. " + + "It's an unexpected behavior and please report an issue to LLamaSharp."); + } + HFGlobalConfig.DefaultDownloadTimeout = settings.Timeout; + + HashSet endpointSet = new([settings.Endpoint]); + if (settings.EndpointFallbacks is not null) + { + foreach (var endpoint in settings.EndpointFallbacks) + { + endpointSet.Add(endpoint); + } + } + var endpoints = endpointSet.ToArray(); + + Dictionary exceptionMap = new(); + foreach(var endpoint in endpoints) + { + logCallback?.Invoke(LLamaLogLevel.Debug, $"Downloading the native library file '{remoteFilePath}' from {endpoint} with repo = {settings.RepoId}, tag = {settings.Tag}"); + var path = await HFDownloader.DownloadFileAsync(settings.RepoId, remoteFilePath, revision: settings.Tag, cacheDir: settings.CacheDir, + localDir: settings.LocalDir, token: settings.Token, endpoint: endpoint); + if (path is not null) + { + logCallback?.Invoke(LLamaLogLevel.Debug, $"Successfully downloaded the native library file to {path}"); + return path; + } + else + { + logCallback?.Invoke(LLamaLogLevel.Warning, "The download failed without an explicit error, please check your configuration or report an issue to LLamaSharp."); + } + } + + // means that the download finally fails. + return null; + } + } + + /// + /// Settings for downloading the native library. + /// + public class NativeLibraryDownloadSettings + { + /// + /// The endpoint to download from, by default the official site of HuggingFace. + /// + public string Endpoint { get; private set; } = "https://huggingface.co"; + + /// + /// Endpoints to fallback to if downloading with the main endpoint fails. + /// + /// Generally this is an option for those countries or regions where the main endpoint is blocked. + /// You should not put too many endpoints here, as it will slow down the downloading process. + /// + public string[]? EndpointFallbacks { get; private set; } = null; + + /// + /// The version of the library to download. Please use LLamaSharp version in format `[major].[minor].[patch]` as tag + /// or go to https://huggingface.co/AsakusaRinne/LLamaSharpNative + /// to see all available tags, or use your own repo and tags. + /// + public string Tag { get; private set; } = string.Empty; + + /// + /// The repo id to download the native library files. + /// + public string RepoId { get; private set; } = "AsakusaRinne/LLamaSharpNative"; + + /// + /// The directory to cache the downloaded files. If you only want to make the downloaded files appear in a directory, + /// regardless of whether the file will have a copy in another place, please set instead. + /// + public string CacheDir { get; private set; } + + /// + /// If provided, the downloaded file will be placed under this directory, + /// either as a symlink (default) or a regular file. + /// + public string? LocalDir { get; private set; } = null; + + /// + /// If you are using your own private repo as remote source, you could set the token to get the access. + /// + public string? Token { get; private set; } = null; + + /// + /// The timeout (second) of the native library file download. + /// + public int Timeout { get; private set; } = 10; + + /// + /// Extra search directories. They will only be used when finding files downloaded from remote. + /// Generally it will be useful when you want to replace the downloading process with your custom implementation. + /// If you are not sure how it works, please leave it empty. + /// + public string[]? ExtraSearchDirectories { get; private set; } = null; + + internal NativeLibraryDownloadSettings() + { + var home = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".cache"); + CacheDir = Path.Combine(home, "llama_sharp"); + } + + internal static string GetDefaultLocalDir(string tag) + { + var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile); + return Path.Combine(home, ".llama_sharp", tag); + } + + /// + /// Create a with default settings. + /// + /// + public static NativeLibraryDownloadSettings Create() + { + return new NativeLibraryDownloadSettings(); + } + + /// + /// Set the default endpoint to download file from. + /// + /// + /// + public NativeLibraryDownloadSettings WithEndpoint(string endpoint) + { + Endpoint = endpoint; + return this; + } + + /// + /// Set the endpoints to try when the download fails with the default endpoint. + /// + /// + /// + public NativeLibraryDownloadSettings WithEndpointFallbacks(params string[] endpoints) + { + EndpointFallbacks = endpoints; + return this; + } + + /// + /// Set the + /// + /// + /// + public NativeLibraryDownloadSettings WithTag(string tag) + { + Tag = tag; + return this; + } + + /// + /// Set the + /// + /// + /// + public NativeLibraryDownloadSettings WithRepoId(string repoId) + { + RepoId = repoId; + return this; + } + + /// + /// Set the . If you only want to make the downloaded files appear in a directory, + /// regardless of whether the file may have a copy in another place, please use instead. + /// + /// + /// + public NativeLibraryDownloadSettings WithCacheDir(string cacheDir) + { + CacheDir = cacheDir; + return this; + } + + /// + /// Set the + /// + /// + /// + public NativeLibraryDownloadSettings WithLocalDir(string localDir) + { + LocalDir = localDir; + return this; + } + + /// + /// Set the + /// + /// + /// + public NativeLibraryDownloadSettings WithToken(string token) + { + Token = token; + return this; + } + + /// + /// Set the + /// + /// + /// + public NativeLibraryDownloadSettings WithTimeout(int timeout) + { + Timeout = timeout; + return this; + } + + /// + /// Set . They will only be used when finding files downloaded from remote. + /// Generally it will be useful when you want to replace the downloading process with your custom implementation. + /// If you are not sure how it works, please ignore this method. + /// + /// + /// + public NativeLibraryDownloadSettings WithExtraSearchDirectories(string[] directories) + { + ExtraSearchDirectories = directories; + return this; + } + + /// + public override string ToString() + { + // Token should be hidden when printing it. + string hiddenToken = ""; + if (Token is not null) + { + if (Token.Length <= 10) + { + hiddenToken = new string('*', Token.Length - 1) + Token.Last(); + } + else + { + hiddenToken += Token.Substring(0, 2); + hiddenToken += new string('*', Token.Length - 3); + hiddenToken += Token.Last(); + } + } + + return $"(Endpoint = {Endpoint}, " + + $"EndpointFallbacks = {string.Join(", ", EndpointFallbacks ?? new string[0])}, " + + $"Tag = {Tag}, " + + $"RepoId = {RepoId}, " + + $"CacheDir = {CacheDir}, " + + $"LocalDir = {LocalDir}, " + + $"Token = {hiddenToken}, " + + $"Timeout = {Timeout}s)"; + } + } +} diff --git a/LLama.Experimental/Native/SelectingPolicyWithAutoDownload.cs b/LLama.Experimental/Native/SelectingPolicyWithAutoDownload.cs new file mode 100644 index 000000000..c794d9c5d --- /dev/null +++ b/LLama.Experimental/Native/SelectingPolicyWithAutoDownload.cs @@ -0,0 +1,59 @@ +using LLama.Abstractions; +using LLama.Native; + +namespace LLama.Experimental.Native +{ +#if NET6_0_OR_GREATER + public class SelectingPolicyWithAutoDownload: INativeLibrarySelectingPolicy + { + private DefaultNativeLibrarySelectingPolicy _defaultPolicy = new(); + private NativeLibraryDownloadSettings _downloadSettings; + + internal SelectingPolicyWithAutoDownload(NativeLibraryDownloadSettings downloadSettings) + { + _downloadSettings = downloadSettings; + } + + public IEnumerable Apply(NativeLibraryConfig.Description description, SystemInfo systemInfo, NativeLogConfig.LLamaLogCallback? logCallback) + { + Log($""" + Auto-download of native library has been enabled, with the following settings: + {_downloadSettings} + """, LLamaLogLevel.Info, logCallback); + foreach(var library in _defaultPolicy.Apply(description, systemInfo, logCallback)) + { + if(library is NativeLibraryWithCuda cudaLibrary) + { + yield return new AutoDownloadedLibraries.Cuda(cudaLibrary, _downloadSettings); + } + else if(library is NativeLibraryWithAvx avxLibrary) + { + yield return new AutoDownloadedLibraries.Avx(avxLibrary, _downloadSettings); + } + else if(library is NativeLibraryWithMacOrFallback macLibrary) + { + yield return new AutoDownloadedLibraries.MacOrFallback(macLibrary, _downloadSettings); + } + else if(library is NativeLibraryFromPath) + { + yield return library; // No need to download + } + else + { + Log($"Unknown native library type of auto-download: {library.GetType()}. " + + $"Please ignore this warning if you are using self-defined native library", LLamaLogLevel.Warning, logCallback); + yield return library; + } + } + } + + private void Log(string message, LLamaLogLevel level, NativeLogConfig.LLamaLogCallback? logCallback) + { + if (!message.EndsWith("\n")) + message += "\n"; + + logCallback?.Invoke(level, message); + } + } +#endif +} diff --git a/LLama/LLamaSharp.csproj b/LLama/LLamaSharp.csproj index 87728cc73..f6e18e21a 100644 --- a/LLama/LLamaSharp.csproj +++ b/LLama/LLamaSharp.csproj @@ -25,7 +25,7 @@ Updated llama.cpp version to include better support for LLama3 tokenization. MIT - packages + $(SolutionDir)/packages AnyCPU;x64;Arm64 LLamaSharp Debug;Release;GPU diff --git a/LLama/Native/Load/NativeLibraryConfig.cs b/LLama/Native/Load/NativeLibraryConfig.cs index 26d05909a..478102177 100644 --- a/LLama/Native/Load/NativeLibraryConfig.cs +++ b/LLama/Native/Load/NativeLibraryConfig.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using LLama.Abstractions; @@ -282,21 +282,6 @@ public sealed partial class NativeLibraryConfig /// public static NativeLibraryConfig LLava { get; } - - /// - /// The current version. - /// - public static string CurrentVersion => VERSION; // This should be changed before publishing new version. TODO: any better approach? - - private const string COMMIT_HASH = "f7001c"; - private const string VERSION = "master"; - - /// - /// Get the llama.cpp commit hash of the current version. - /// - /// - public static string GetNativeLibraryCommitHash() => COMMIT_HASH; - static NativeLibraryConfig() { LLama = new(NativeLibraryName.LLama); @@ -387,6 +372,18 @@ internal NativeLibraryConfigContainer(params NativeLibraryConfig[] configs) _configs = configs; } + /// + /// Do an action for all the configs in this container. + /// + /// + public void ForEach(Action action) + { + foreach (var config in _configs) + { + action(config); + } + } + #region configurators #if NET6_0_OR_GREATER diff --git a/LLamaSharp.sln b/LLamaSharp.sln index 8039982e5..7c970aa99 100644 --- a/LLamaSharp.sln +++ b/LLamaSharp.sln @@ -17,112 +17,183 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LLamaSharp.SemanticKernel", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LLamaSharp.KernelMemory", "LLama.KernelMemory\LLamaSharp.KernelMemory.csproj", "{E5589AE7-B86F-4343-A1CC-8E5D34596E52}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LLama.Benchmark", "LLama.Benchmark\LLama.Benchmark.csproj", "{90D38FEE-68EA-459E-A4EE-268B9DFA1CD5}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LLama.Experimental", "LLama.Experimental\LLama.Experimental.csproj", "{BE4F977B-D4D9-472F-B506-EAE17542A810}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LLama.Benchmark", "LLama.Benchmark\LLama.Benchmark.csproj", "{90D38FEE-68EA-459E-A4EE-268B9DFA1CD5}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|Arm64 = Debug|Arm64 Debug|x64 = Debug|x64 GPU|Any CPU = GPU|Any CPU + GPU|Arm64 = GPU|Arm64 GPU|x64 = GPU|x64 Release|Any CPU = Release|Any CPU + Release|Arm64 = Release|Arm64 Release|x64 = Release|x64 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {BAC1CFA9-E6AC-4BD0-A548-A8066D3C467E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BAC1CFA9-E6AC-4BD0-A548-A8066D3C467E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BAC1CFA9-E6AC-4BD0-A548-A8066D3C467E}.Debug|Arm64.ActiveCfg = Debug|Any CPU + {BAC1CFA9-E6AC-4BD0-A548-A8066D3C467E}.Debug|Arm64.Build.0 = Debug|Any CPU {BAC1CFA9-E6AC-4BD0-A548-A8066D3C467E}.Debug|x64.ActiveCfg = Debug|x64 {BAC1CFA9-E6AC-4BD0-A548-A8066D3C467E}.Debug|x64.Build.0 = Debug|x64 {BAC1CFA9-E6AC-4BD0-A548-A8066D3C467E}.GPU|Any CPU.ActiveCfg = Release|Any CPU {BAC1CFA9-E6AC-4BD0-A548-A8066D3C467E}.GPU|Any CPU.Build.0 = Release|Any CPU + {BAC1CFA9-E6AC-4BD0-A548-A8066D3C467E}.GPU|Arm64.ActiveCfg = Release|Any CPU + {BAC1CFA9-E6AC-4BD0-A548-A8066D3C467E}.GPU|Arm64.Build.0 = Release|Any CPU {BAC1CFA9-E6AC-4BD0-A548-A8066D3C467E}.GPU|x64.ActiveCfg = Release|x64 {BAC1CFA9-E6AC-4BD0-A548-A8066D3C467E}.GPU|x64.Build.0 = Release|x64 {BAC1CFA9-E6AC-4BD0-A548-A8066D3C467E}.Release|Any CPU.ActiveCfg = Release|Any CPU {BAC1CFA9-E6AC-4BD0-A548-A8066D3C467E}.Release|Any CPU.Build.0 = Release|Any CPU + {BAC1CFA9-E6AC-4BD0-A548-A8066D3C467E}.Release|Arm64.ActiveCfg = Release|Any CPU + {BAC1CFA9-E6AC-4BD0-A548-A8066D3C467E}.Release|Arm64.Build.0 = Release|Any CPU {BAC1CFA9-E6AC-4BD0-A548-A8066D3C467E}.Release|x64.ActiveCfg = Release|x64 {BAC1CFA9-E6AC-4BD0-A548-A8066D3C467E}.Release|x64.Build.0 = Release|x64 {BD1909AD-E1F8-476E-BC49-E394FF0470CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {BD1909AD-E1F8-476E-BC49-E394FF0470CE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BD1909AD-E1F8-476E-BC49-E394FF0470CE}.Debug|Arm64.ActiveCfg = Debug|Any CPU + {BD1909AD-E1F8-476E-BC49-E394FF0470CE}.Debug|Arm64.Build.0 = Debug|Any CPU {BD1909AD-E1F8-476E-BC49-E394FF0470CE}.Debug|x64.ActiveCfg = Debug|x64 {BD1909AD-E1F8-476E-BC49-E394FF0470CE}.Debug|x64.Build.0 = Debug|x64 {BD1909AD-E1F8-476E-BC49-E394FF0470CE}.GPU|Any CPU.ActiveCfg = Release|Any CPU {BD1909AD-E1F8-476E-BC49-E394FF0470CE}.GPU|Any CPU.Build.0 = Release|Any CPU + {BD1909AD-E1F8-476E-BC49-E394FF0470CE}.GPU|Arm64.ActiveCfg = Release|Any CPU + {BD1909AD-E1F8-476E-BC49-E394FF0470CE}.GPU|Arm64.Build.0 = Release|Any CPU {BD1909AD-E1F8-476E-BC49-E394FF0470CE}.GPU|x64.ActiveCfg = Release|x64 {BD1909AD-E1F8-476E-BC49-E394FF0470CE}.GPU|x64.Build.0 = Release|x64 {BD1909AD-E1F8-476E-BC49-E394FF0470CE}.Release|Any CPU.ActiveCfg = Release|Any CPU {BD1909AD-E1F8-476E-BC49-E394FF0470CE}.Release|Any CPU.Build.0 = Release|Any CPU + {BD1909AD-E1F8-476E-BC49-E394FF0470CE}.Release|Arm64.ActiveCfg = Release|Any CPU + {BD1909AD-E1F8-476E-BC49-E394FF0470CE}.Release|Arm64.Build.0 = Release|Any CPU {BD1909AD-E1F8-476E-BC49-E394FF0470CE}.Release|x64.ActiveCfg = Release|x64 {BD1909AD-E1F8-476E-BC49-E394FF0470CE}.Release|x64.Build.0 = Release|x64 {01A12D68-DE95-425E-AEEE-2D099305036D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {01A12D68-DE95-425E-AEEE-2D099305036D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {01A12D68-DE95-425E-AEEE-2D099305036D}.Debug|Arm64.ActiveCfg = Debug|Arm64 + {01A12D68-DE95-425E-AEEE-2D099305036D}.Debug|Arm64.Build.0 = Debug|Arm64 {01A12D68-DE95-425E-AEEE-2D099305036D}.Debug|x64.ActiveCfg = Debug|x64 {01A12D68-DE95-425E-AEEE-2D099305036D}.Debug|x64.Build.0 = Debug|x64 {01A12D68-DE95-425E-AEEE-2D099305036D}.GPU|Any CPU.ActiveCfg = GPU|Any CPU {01A12D68-DE95-425E-AEEE-2D099305036D}.GPU|Any CPU.Build.0 = GPU|Any CPU + {01A12D68-DE95-425E-AEEE-2D099305036D}.GPU|Arm64.ActiveCfg = GPU|Arm64 + {01A12D68-DE95-425E-AEEE-2D099305036D}.GPU|Arm64.Build.0 = GPU|Arm64 {01A12D68-DE95-425E-AEEE-2D099305036D}.GPU|x64.ActiveCfg = GPU|x64 {01A12D68-DE95-425E-AEEE-2D099305036D}.GPU|x64.Build.0 = GPU|x64 {01A12D68-DE95-425E-AEEE-2D099305036D}.Release|Any CPU.ActiveCfg = Release|Any CPU {01A12D68-DE95-425E-AEEE-2D099305036D}.Release|Any CPU.Build.0 = Release|Any CPU + {01A12D68-DE95-425E-AEEE-2D099305036D}.Release|Arm64.ActiveCfg = Release|Arm64 + {01A12D68-DE95-425E-AEEE-2D099305036D}.Release|Arm64.Build.0 = Release|Arm64 {01A12D68-DE95-425E-AEEE-2D099305036D}.Release|x64.ActiveCfg = Release|x64 {01A12D68-DE95-425E-AEEE-2D099305036D}.Release|x64.Build.0 = Release|x64 {D3CEC57A-9027-4DA4-AAAC-612A1EB50ADF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D3CEC57A-9027-4DA4-AAAC-612A1EB50ADF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D3CEC57A-9027-4DA4-AAAC-612A1EB50ADF}.Debug|Arm64.ActiveCfg = Debug|Any CPU + {D3CEC57A-9027-4DA4-AAAC-612A1EB50ADF}.Debug|Arm64.Build.0 = Debug|Any CPU {D3CEC57A-9027-4DA4-AAAC-612A1EB50ADF}.Debug|x64.ActiveCfg = Debug|Any CPU {D3CEC57A-9027-4DA4-AAAC-612A1EB50ADF}.Debug|x64.Build.0 = Debug|Any CPU {D3CEC57A-9027-4DA4-AAAC-612A1EB50ADF}.GPU|Any CPU.ActiveCfg = Debug|Any CPU {D3CEC57A-9027-4DA4-AAAC-612A1EB50ADF}.GPU|Any CPU.Build.0 = Debug|Any CPU + {D3CEC57A-9027-4DA4-AAAC-612A1EB50ADF}.GPU|Arm64.ActiveCfg = Release|Any CPU + {D3CEC57A-9027-4DA4-AAAC-612A1EB50ADF}.GPU|Arm64.Build.0 = Release|Any CPU {D3CEC57A-9027-4DA4-AAAC-612A1EB50ADF}.GPU|x64.ActiveCfg = Debug|Any CPU {D3CEC57A-9027-4DA4-AAAC-612A1EB50ADF}.GPU|x64.Build.0 = Debug|Any CPU {D3CEC57A-9027-4DA4-AAAC-612A1EB50ADF}.Release|Any CPU.ActiveCfg = Release|Any CPU {D3CEC57A-9027-4DA4-AAAC-612A1EB50ADF}.Release|Any CPU.Build.0 = Release|Any CPU + {D3CEC57A-9027-4DA4-AAAC-612A1EB50ADF}.Release|Arm64.ActiveCfg = Release|Any CPU + {D3CEC57A-9027-4DA4-AAAC-612A1EB50ADF}.Release|Arm64.Build.0 = Release|Any CPU {D3CEC57A-9027-4DA4-AAAC-612A1EB50ADF}.Release|x64.ActiveCfg = Release|Any CPU {D3CEC57A-9027-4DA4-AAAC-612A1EB50ADF}.Release|x64.Build.0 = Release|Any CPU {C3531DB2-1B2B-433C-8DE6-3541E3620DB1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C3531DB2-1B2B-433C-8DE6-3541E3620DB1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C3531DB2-1B2B-433C-8DE6-3541E3620DB1}.Debug|Arm64.ActiveCfg = Debug|Any CPU + {C3531DB2-1B2B-433C-8DE6-3541E3620DB1}.Debug|Arm64.Build.0 = Debug|Any CPU {C3531DB2-1B2B-433C-8DE6-3541E3620DB1}.Debug|x64.ActiveCfg = Debug|Any CPU {C3531DB2-1B2B-433C-8DE6-3541E3620DB1}.Debug|x64.Build.0 = Debug|Any CPU {C3531DB2-1B2B-433C-8DE6-3541E3620DB1}.GPU|Any CPU.ActiveCfg = Debug|Any CPU {C3531DB2-1B2B-433C-8DE6-3541E3620DB1}.GPU|Any CPU.Build.0 = Debug|Any CPU + {C3531DB2-1B2B-433C-8DE6-3541E3620DB1}.GPU|Arm64.ActiveCfg = Release|Any CPU + {C3531DB2-1B2B-433C-8DE6-3541E3620DB1}.GPU|Arm64.Build.0 = Release|Any CPU {C3531DB2-1B2B-433C-8DE6-3541E3620DB1}.GPU|x64.ActiveCfg = Debug|Any CPU {C3531DB2-1B2B-433C-8DE6-3541E3620DB1}.GPU|x64.Build.0 = Debug|Any CPU {C3531DB2-1B2B-433C-8DE6-3541E3620DB1}.Release|Any CPU.ActiveCfg = Release|Any CPU {C3531DB2-1B2B-433C-8DE6-3541E3620DB1}.Release|Any CPU.Build.0 = Release|Any CPU + {C3531DB2-1B2B-433C-8DE6-3541E3620DB1}.Release|Arm64.ActiveCfg = Release|Any CPU + {C3531DB2-1B2B-433C-8DE6-3541E3620DB1}.Release|Arm64.Build.0 = Release|Any CPU {C3531DB2-1B2B-433C-8DE6-3541E3620DB1}.Release|x64.ActiveCfg = Release|Any CPU {C3531DB2-1B2B-433C-8DE6-3541E3620DB1}.Release|x64.Build.0 = Release|Any CPU {D98F93E3-B344-4F9D-86BB-FDBF6768B587}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {D98F93E3-B344-4F9D-86BB-FDBF6768B587}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D98F93E3-B344-4F9D-86BB-FDBF6768B587}.Debug|Arm64.ActiveCfg = Debug|Arm64 + {D98F93E3-B344-4F9D-86BB-FDBF6768B587}.Debug|Arm64.Build.0 = Debug|Arm64 {D98F93E3-B344-4F9D-86BB-FDBF6768B587}.Debug|x64.ActiveCfg = Debug|Any CPU {D98F93E3-B344-4F9D-86BB-FDBF6768B587}.Debug|x64.Build.0 = Debug|Any CPU {D98F93E3-B344-4F9D-86BB-FDBF6768B587}.GPU|Any CPU.ActiveCfg = Debug|Any CPU {D98F93E3-B344-4F9D-86BB-FDBF6768B587}.GPU|Any CPU.Build.0 = Debug|Any CPU + {D98F93E3-B344-4F9D-86BB-FDBF6768B587}.GPU|Arm64.ActiveCfg = GPU|Arm64 + {D98F93E3-B344-4F9D-86BB-FDBF6768B587}.GPU|Arm64.Build.0 = GPU|Arm64 {D98F93E3-B344-4F9D-86BB-FDBF6768B587}.GPU|x64.ActiveCfg = Debug|Any CPU {D98F93E3-B344-4F9D-86BB-FDBF6768B587}.GPU|x64.Build.0 = Debug|Any CPU {D98F93E3-B344-4F9D-86BB-FDBF6768B587}.Release|Any CPU.ActiveCfg = Release|Any CPU {D98F93E3-B344-4F9D-86BB-FDBF6768B587}.Release|Any CPU.Build.0 = Release|Any CPU + {D98F93E3-B344-4F9D-86BB-FDBF6768B587}.Release|Arm64.ActiveCfg = Release|Arm64 + {D98F93E3-B344-4F9D-86BB-FDBF6768B587}.Release|Arm64.Build.0 = Release|Arm64 {D98F93E3-B344-4F9D-86BB-FDBF6768B587}.Release|x64.ActiveCfg = Release|Any CPU {D98F93E3-B344-4F9D-86BB-FDBF6768B587}.Release|x64.Build.0 = Release|Any CPU {E5589AE7-B86F-4343-A1CC-8E5D34596E52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E5589AE7-B86F-4343-A1CC-8E5D34596E52}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E5589AE7-B86F-4343-A1CC-8E5D34596E52}.Debug|Arm64.ActiveCfg = Debug|Arm64 + {E5589AE7-B86F-4343-A1CC-8E5D34596E52}.Debug|Arm64.Build.0 = Debug|Arm64 {E5589AE7-B86F-4343-A1CC-8E5D34596E52}.Debug|x64.ActiveCfg = Debug|Any CPU {E5589AE7-B86F-4343-A1CC-8E5D34596E52}.Debug|x64.Build.0 = Debug|Any CPU {E5589AE7-B86F-4343-A1CC-8E5D34596E52}.GPU|Any CPU.ActiveCfg = Debug|Any CPU {E5589AE7-B86F-4343-A1CC-8E5D34596E52}.GPU|Any CPU.Build.0 = Debug|Any CPU + {E5589AE7-B86F-4343-A1CC-8E5D34596E52}.GPU|Arm64.ActiveCfg = GPU|Arm64 + {E5589AE7-B86F-4343-A1CC-8E5D34596E52}.GPU|Arm64.Build.0 = GPU|Arm64 {E5589AE7-B86F-4343-A1CC-8E5D34596E52}.GPU|x64.ActiveCfg = Debug|Any CPU {E5589AE7-B86F-4343-A1CC-8E5D34596E52}.GPU|x64.Build.0 = Debug|Any CPU {E5589AE7-B86F-4343-A1CC-8E5D34596E52}.Release|Any CPU.ActiveCfg = Release|Any CPU {E5589AE7-B86F-4343-A1CC-8E5D34596E52}.Release|Any CPU.Build.0 = Release|Any CPU + {E5589AE7-B86F-4343-A1CC-8E5D34596E52}.Release|Arm64.ActiveCfg = Release|Arm64 + {E5589AE7-B86F-4343-A1CC-8E5D34596E52}.Release|Arm64.Build.0 = Release|Arm64 {E5589AE7-B86F-4343-A1CC-8E5D34596E52}.Release|x64.ActiveCfg = Release|Any CPU {E5589AE7-B86F-4343-A1CC-8E5D34596E52}.Release|x64.Build.0 = Release|Any CPU + {BE4F977B-D4D9-472F-B506-EAE17542A810}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BE4F977B-D4D9-472F-B506-EAE17542A810}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BE4F977B-D4D9-472F-B506-EAE17542A810}.Debug|Arm64.ActiveCfg = Debug|Any CPU + {BE4F977B-D4D9-472F-B506-EAE17542A810}.Debug|Arm64.Build.0 = Debug|Any CPU + {BE4F977B-D4D9-472F-B506-EAE17542A810}.Debug|x64.ActiveCfg = Debug|Any CPU + {BE4F977B-D4D9-472F-B506-EAE17542A810}.Debug|x64.Build.0 = Debug|Any CPU + {BE4F977B-D4D9-472F-B506-EAE17542A810}.GPU|Any CPU.ActiveCfg = Debug|Any CPU + {BE4F977B-D4D9-472F-B506-EAE17542A810}.GPU|Any CPU.Build.0 = Debug|Any CPU + {BE4F977B-D4D9-472F-B506-EAE17542A810}.GPU|Arm64.ActiveCfg = Debug|Any CPU + {BE4F977B-D4D9-472F-B506-EAE17542A810}.GPU|Arm64.Build.0 = Debug|Any CPU + {BE4F977B-D4D9-472F-B506-EAE17542A810}.GPU|x64.ActiveCfg = Debug|Any CPU + {BE4F977B-D4D9-472F-B506-EAE17542A810}.GPU|x64.Build.0 = Debug|Any CPU + {BE4F977B-D4D9-472F-B506-EAE17542A810}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BE4F977B-D4D9-472F-B506-EAE17542A810}.Release|Any CPU.Build.0 = Release|Any CPU + {BE4F977B-D4D9-472F-B506-EAE17542A810}.Release|Arm64.ActiveCfg = Release|Any CPU + {BE4F977B-D4D9-472F-B506-EAE17542A810}.Release|Arm64.Build.0 = Release|Any CPU + {BE4F977B-D4D9-472F-B506-EAE17542A810}.Release|x64.ActiveCfg = Release|Any CPU + {BE4F977B-D4D9-472F-B506-EAE17542A810}.Release|x64.Build.0 = Release|Any CPU {90D38FEE-68EA-459E-A4EE-268B9DFA1CD5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {90D38FEE-68EA-459E-A4EE-268B9DFA1CD5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {90D38FEE-68EA-459E-A4EE-268B9DFA1CD5}.Debug|Arm64.ActiveCfg = Debug|Any CPU + {90D38FEE-68EA-459E-A4EE-268B9DFA1CD5}.Debug|Arm64.Build.0 = Debug|Any CPU {90D38FEE-68EA-459E-A4EE-268B9DFA1CD5}.Debug|x64.ActiveCfg = Debug|Any CPU {90D38FEE-68EA-459E-A4EE-268B9DFA1CD5}.Debug|x64.Build.0 = Debug|Any CPU {90D38FEE-68EA-459E-A4EE-268B9DFA1CD5}.GPU|Any CPU.ActiveCfg = Debug|Any CPU {90D38FEE-68EA-459E-A4EE-268B9DFA1CD5}.GPU|Any CPU.Build.0 = Debug|Any CPU + {90D38FEE-68EA-459E-A4EE-268B9DFA1CD5}.GPU|Arm64.ActiveCfg = Debug|Any CPU + {90D38FEE-68EA-459E-A4EE-268B9DFA1CD5}.GPU|Arm64.Build.0 = Debug|Any CPU {90D38FEE-68EA-459E-A4EE-268B9DFA1CD5}.GPU|x64.ActiveCfg = Debug|Any CPU {90D38FEE-68EA-459E-A4EE-268B9DFA1CD5}.GPU|x64.Build.0 = Debug|Any CPU {90D38FEE-68EA-459E-A4EE-268B9DFA1CD5}.Release|Any CPU.ActiveCfg = Release|Any CPU {90D38FEE-68EA-459E-A4EE-268B9DFA1CD5}.Release|Any CPU.Build.0 = Release|Any CPU + {90D38FEE-68EA-459E-A4EE-268B9DFA1CD5}.Release|Arm64.ActiveCfg = Release|Any CPU + {90D38FEE-68EA-459E-A4EE-268B9DFA1CD5}.Release|Arm64.Build.0 = Release|Any CPU {90D38FEE-68EA-459E-A4EE-268B9DFA1CD5}.Release|x64.ActiveCfg = Release|Any CPU {90D38FEE-68EA-459E-A4EE-268B9DFA1CD5}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection