diff --git a/Directory.Build.targets b/Directory.Build.targets index 56648dd5b7..14c8da9b80 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -38,6 +38,20 @@ + + + + + + + + $(NativeOutputPath)%(_OneDalNativeDependency.Identity) + + diff --git a/src/Native/Native.proj b/src/Native/Native.proj index 9e829fe250..c7ff95cb63 100644 --- a/src/Native/Native.proj +++ b/src/Native/Native.proj @@ -93,6 +93,15 @@ libtbbmalloc.2.dylib + + <_OneDalNativeDependency Include="$(NuGetPackageRoot)inteldal.redist.$(PackageRid)\$(OneDalPkgVersion)\build\native\daal\latest\$(OneDalLibDir)\$(NativeLibPrefix)onedal_core$(OneDalLibExtension)" /> + <_OneDalNativeDependency Include="$(NuGetPackageRoot)inteldal.redist.$(PackageRid)\$(OneDalPkgVersion)\build\native\daal\latest\$(OneDalLibDir)\$(NativeLibPrefix)onedal_thread$(OneDalLibExtension)" /> + <_OneDalNativeDependency Include="$(NuGetPackageRoot)inteltbb.$(TbbPkgType).$(TbbSystem)\$(OneTbbPkgVersion)\runtimes\$(PackageRid)\native\$(TbbLibrary)" /> + <_OneDalNativeDependency Include="$(NuGetPackageRoot)inteltbb.$(TbbPkgType).$(TbbSystem)\$(OneTbbPkgVersion)\runtimes\$(PackageRid)\native\$(TbbMallocLibrary)" /> + + + + @@ -151,35 +160,7 @@ - - - - - - - - - - - - - + - - - - - @@ -237,6 +199,8 @@ RelativePath="Microsoft.ML.Mkl.Redist\runtimes\$(PackageRid)\native" /> + diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 10ff4aad95..1115738c99 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -24,6 +24,8 @@ trx $(OutputPath) + + $(MSBuildThisFileDirectory)Microsoft.ML.TestFrameworkCommon\xunit.runner.json true diff --git a/test/Microsoft.ML.Core.Tests/UnitTests/NativeLibraryTests.cs b/test/Microsoft.ML.Core.Tests/UnitTests/NativeLibraryTests.cs new file mode 100644 index 0000000000..b63d1d796c --- /dev/null +++ b/test/Microsoft.ML.Core.Tests/UnitTests/NativeLibraryTests.cs @@ -0,0 +1,53 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Runtime.InteropServices; +using Microsoft.ML.TestFramework; +using Microsoft.ML.TestFramework.Attributes; +using Xunit; +using Xunit.Abstractions; +using NativeLibrary = Microsoft.ML.TestFrameworkCommon.Utility.NativeLibrary; + +namespace Microsoft.ML.RunTests +{ + public sealed class NativeLibraryTests : BaseTestClass + { + private static bool IsOneDalSupported => + RuntimeInformation.ProcessArchitecture == Architecture.X64 && + // We don't test macOS x64 for OneDAL. + !RuntimeInformation.IsOSPlatform(OSPlatform.OSX); + + public NativeLibraryTests(ITestOutputHelper output) : base(output) + { + } + + [Fact] + public void SystemNativeLibraryCanBeLoaded() + { + string library = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) + ? "kernel32" + : RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? "libc.so.6" : "libSystem.B.dylib"; + + Assert.True(NativeLibrary.NativeLibraryExists(library)); + } + + [Fact] + public void MissingNativeLibraryReturnsFalse() + { + Assert.False(NativeLibrary.NativeLibraryExists("MLNetNonexistentNativeLibrary")); + } + + [X64Fact("The LightGBM native package supports x64 only.")] + public void PackageNativeLibraryCanBeLoaded() + { + Assert.True(NativeLibrary.NativeLibraryExists("lib_lightgbm")); + } + + [ConditionalFact(nameof(IsOneDalSupported))] + public void OneDalNativeLibraryCanBeLoaded() + { + Assert.True(NativeLibrary.NativeLibraryExists("OneDalNative")); + } + } +} diff --git a/test/Microsoft.ML.TestFramework/Attributes/LightGBMFactAttribute.cs b/test/Microsoft.ML.TestFramework/Attributes/LightGBMFactAttribute.cs index 634b8a5251..89d0bec9fa 100644 --- a/test/Microsoft.ML.TestFramework/Attributes/LightGBMFactAttribute.cs +++ b/test/Microsoft.ML.TestFramework/Attributes/LightGBMFactAttribute.cs @@ -13,7 +13,7 @@ namespace Microsoft.ML.TestFramework.Attributes /// public sealed class LightGBMFactAttribute : EnvironmentSpecificFactAttribute { - public LightGBMFactAttribute() : base("LightGBM is 64-bit only") + public LightGBMFactAttribute() : base("LightGBM requires a 64-bit process and a loadable native library.") { } diff --git a/test/Microsoft.ML.TestFramework/Attributes/LightGBMTheoryAttribute.cs b/test/Microsoft.ML.TestFramework/Attributes/LightGBMTheoryAttribute.cs index 829f51eb69..de1335b1f1 100644 --- a/test/Microsoft.ML.TestFramework/Attributes/LightGBMTheoryAttribute.cs +++ b/test/Microsoft.ML.TestFramework/Attributes/LightGBMTheoryAttribute.cs @@ -13,7 +13,7 @@ namespace Microsoft.ML.TestFramework.Attributes /// public sealed class LightGBMTheoryAttribute : EnvironmentSpecificTheoryAttribute { - public LightGBMTheoryAttribute() : base("LightGBM is 64-bit only") + public LightGBMTheoryAttribute() : base("LightGBM requires a 64-bit process and a loadable native library.") { } diff --git a/test/Microsoft.ML.TestFramework/Attributes/OnnxTheoryAttribute.cs b/test/Microsoft.ML.TestFramework/Attributes/OnnxTheoryAttribute.cs index bd46e402b5..dcbb17c3cf 100644 --- a/test/Microsoft.ML.TestFramework/Attributes/OnnxTheoryAttribute.cs +++ b/test/Microsoft.ML.TestFramework/Attributes/OnnxTheoryAttribute.cs @@ -11,7 +11,7 @@ namespace Microsoft.ML.TestFramework.Attributes /// public sealed class OnnxTheoryAttribute : EnvironmentSpecificTheoryAttribute { - public OnnxTheoryAttribute() : base("Onnx is 64-bit only and is not supported on Linux with libc < v2.23") + public OnnxTheoryAttribute() : base("ONNX Runtime requires a supported platform and a loadable native library.") { } diff --git a/test/Microsoft.ML.TestFramework/Attributes/TensorflowFactAttribute.cs b/test/Microsoft.ML.TestFramework/Attributes/TensorflowFactAttribute.cs index 2455d61381..5dd4e8a45c 100644 --- a/test/Microsoft.ML.TestFramework/Attributes/TensorflowFactAttribute.cs +++ b/test/Microsoft.ML.TestFramework/Attributes/TensorflowFactAttribute.cs @@ -13,7 +13,7 @@ namespace Microsoft.ML.TestFramework.Attributes /// public sealed class TensorFlowFactAttribute : EnvironmentSpecificFactAttribute { - public TensorFlowFactAttribute() : base("TensorFlow is 64-bit only and is not supported on Linux with libc < v2.23") + public TensorFlowFactAttribute() : base("TensorFlow requires a 64-bit process, a supported platform, and a loadable native library.") { } diff --git a/test/Microsoft.ML.TestFramework/Attributes/TensorflowTheoryAttribute.cs b/test/Microsoft.ML.TestFramework/Attributes/TensorflowTheoryAttribute.cs index 9c6de5fd4c..89f9d310e4 100644 --- a/test/Microsoft.ML.TestFramework/Attributes/TensorflowTheoryAttribute.cs +++ b/test/Microsoft.ML.TestFramework/Attributes/TensorflowTheoryAttribute.cs @@ -13,7 +13,7 @@ namespace Microsoft.ML.TestFramework.Attributes /// public sealed class TensorFlowTheoryAttribute : EnvironmentSpecificTheoryAttribute { - public TensorFlowTheoryAttribute() : base("TensorFlow is 64-bit only and is not supported on Linux with libc < v2.23") + public TensorFlowTheoryAttribute() : base("TensorFlow requires a 64-bit process, a supported platform, and a loadable native library.") { } diff --git a/test/Microsoft.ML.TestFrameworkCommon/Attributes/FieldAwareFactorizationMachineFactAttribute.cs b/test/Microsoft.ML.TestFrameworkCommon/Attributes/FieldAwareFactorizationMachineFactAttribute.cs index f9636f112d..2ecc3247bc 100644 --- a/test/Microsoft.ML.TestFrameworkCommon/Attributes/FieldAwareFactorizationMachineFactAttribute.cs +++ b/test/Microsoft.ML.TestFrameworkCommon/Attributes/FieldAwareFactorizationMachineFactAttribute.cs @@ -9,7 +9,7 @@ namespace Microsoft.ML.TestFramework.Attributes { public class FieldAwareFactorizationMachineFactAttribute : EnvironmentSpecificFactAttribute { - private const string SkipMessage = "FieldAwareFactorizationMachine doesn't currently support non x86/x64. https://github.com/dotnet/machinelearning/issues/5871"; + private const string SkipMessage = "FieldAwareFactorizationMachine requires a loadable CpuMathNative library."; public FieldAwareFactorizationMachineFactAttribute() : base(SkipMessage) { diff --git a/test/Microsoft.ML.TestFrameworkCommon/Attributes/NativeDependencyFactAttribute.cs b/test/Microsoft.ML.TestFrameworkCommon/Attributes/NativeDependencyFactAttribute.cs index f40f8e1be2..acfdb6ec56 100644 --- a/test/Microsoft.ML.TestFrameworkCommon/Attributes/NativeDependencyFactAttribute.cs +++ b/test/Microsoft.ML.TestFrameworkCommon/Attributes/NativeDependencyFactAttribute.cs @@ -11,7 +11,7 @@ public sealed class NativeDependencyFactAttribute : EnvironmentSpecificFactAttri { private readonly string _library; - public NativeDependencyFactAttribute(string library) : base($"This test requires a native library {library} that wasn't found.") + public NativeDependencyFactAttribute(string library) : base($"This test requires a supported platform and a loadable native library {library}.") { _library = library; } diff --git a/test/Microsoft.ML.TestFrameworkCommon/Attributes/NativeDependencyTheoryAttribute.cs b/test/Microsoft.ML.TestFrameworkCommon/Attributes/NativeDependencyTheoryAttribute.cs index 1f4e1e6b1a..97a46f2943 100644 --- a/test/Microsoft.ML.TestFrameworkCommon/Attributes/NativeDependencyTheoryAttribute.cs +++ b/test/Microsoft.ML.TestFrameworkCommon/Attributes/NativeDependencyTheoryAttribute.cs @@ -11,7 +11,7 @@ public sealed class NativeDependencyTheoryAttribute : EnvironmentSpecificTheoryA { private readonly string _library; - public NativeDependencyTheoryAttribute(string library) : base($"This test requires a native library {library} that wasn't found.") + public NativeDependencyTheoryAttribute(string library) : base($"This test requires a supported platform and a loadable native library {library}.") { _library = library; } diff --git a/test/Microsoft.ML.TestFrameworkCommon/Attributes/OnnxFactAttribute.cs b/test/Microsoft.ML.TestFrameworkCommon/Attributes/OnnxFactAttribute.cs index 5fe6cf9ce4..168aef1e7a 100644 --- a/test/Microsoft.ML.TestFrameworkCommon/Attributes/OnnxFactAttribute.cs +++ b/test/Microsoft.ML.TestFrameworkCommon/Attributes/OnnxFactAttribute.cs @@ -14,7 +14,7 @@ namespace Microsoft.ML.TestFrameworkCommon.Attributes /// public sealed class OnnxFactAttribute : EnvironmentSpecificFactAttribute { - public OnnxFactAttribute() : base("Onnx is 64-bit only and is not supported on Linux with libc < v2.23") + public OnnxFactAttribute() : base("ONNX Runtime requires a supported platform and a loadable native library.") { } diff --git a/test/Microsoft.ML.TestFrameworkCommon/Utility/Kernel32.cs b/test/Microsoft.ML.TestFrameworkCommon/Utility/Kernel32.cs index 2018677335..d02cacf4f4 100644 --- a/test/Microsoft.ML.TestFrameworkCommon/Utility/Kernel32.cs +++ b/test/Microsoft.ML.TestFrameworkCommon/Utility/Kernel32.cs @@ -6,9 +6,14 @@ namespace Microsoft.ML.TestFrameworkCommon.Utility { internal static class Kernel32 { + public const uint LoadWithAlteredSearchPath = 0x00000008; + [DllImport("kernel32")] public static extern IntPtr LoadLibrary(string fileName); + [DllImport("kernel32", CharSet = CharSet.Unicode)] + public static extern IntPtr LoadLibraryEx(string fileName, IntPtr file, uint flags); + [DllImport("kernel32")] public static extern IntPtr GetProcAddress(IntPtr module, string procName); diff --git a/test/Microsoft.ML.TestFrameworkCommon/Utility/LibraryLoader.cs b/test/Microsoft.ML.TestFrameworkCommon/Utility/LibraryLoader.cs index 3fb89075ea..6e75271e36 100644 --- a/test/Microsoft.ML.TestFrameworkCommon/Utility/LibraryLoader.cs +++ b/test/Microsoft.ML.TestFrameworkCommon/Utility/LibraryLoader.cs @@ -194,6 +194,10 @@ protected override IntPtr CoreLoadFunctionPointer(IntPtr handle, string function protected override IntPtr CoreLoadNativeLibrary(string name) { + // Resolve dependencies beside the DLL, not just beside the test host. + if (Path.IsPathRooted(name)) + return Kernel32.LoadLibraryEx(Path.GetFullPath(name), IntPtr.Zero, Kernel32.LoadWithAlteredSearchPath); + return Kernel32.LoadLibrary(name); } } diff --git a/test/Microsoft.ML.TestFrameworkCommon/Utility/NativeLibrary.cs b/test/Microsoft.ML.TestFrameworkCommon/Utility/NativeLibrary.cs index 92eb50743f..cc7e67c9e0 100644 --- a/test/Microsoft.ML.TestFrameworkCommon/Utility/NativeLibrary.cs +++ b/test/Microsoft.ML.TestFrameworkCommon/Utility/NativeLibrary.cs @@ -1,12 +1,14 @@ // Taken from https://github.com/mellinoe/nativelibraryloader/blob/586f9738ff12688df8f0662027da8c319aee3841/NativeLibraryLoader/NativeLibrary.cs using System; using System.Runtime.InteropServices; +#if NET5_0_OR_GREATER +using RuntimeNativeLibrary = System.Runtime.InteropServices.NativeLibrary; +#endif namespace Microsoft.ML.TestFrameworkCommon.Utility { /// /// Represents a native shared library opened by the operating system. - /// This type can be used to load native function pointers by name. /// public class NativeLibrary : IDisposable { @@ -15,6 +17,22 @@ public class NativeLibrary : IDisposable public static bool NativeLibraryExists(string name) { +#if NET5_0_OR_GREATER + // Use the runtime's assembly-aware loader to honor native NuGet asset probing. + // The legacy loader below can falsely report missing libraries on Linux: its "libdl" + // import may not resolve to libdl.so.2, and its distro-specific RID lookup can miss + // portable linux-x64 assets. Passing the owning assembly avoids that custom probing. + var assembly = typeof(NativeLibrary).Assembly; + if (!RuntimeNativeLibrary.TryLoad(name, assembly, null, out var handle) && + !RuntimeNativeLibrary.TryLoad("lib" + name, assembly, null, out handle) && + !RuntimeNativeLibrary.TryLoad("lib_" + name, assembly, null, out handle)) + { + return false; + } + + RuntimeNativeLibrary.Free(handle); + return true; +#else NativeLibrary nativeLibrary = default; string extension = default; string prefix = "lib"; @@ -60,102 +78,26 @@ public static bool NativeLibraryExists(string name) { nativeLibrary?.Dispose(); } +#endif } /// /// The operating system handle of the loaded library. /// - public IntPtr Handle { get; } + private IntPtr Handle { get; } /// /// Constructs a new NativeLibrary using the platform's default library loader. /// /// The name of the library to load. - public NativeLibrary(string name) : this(name, _platformDefaultLoader, PathResolver.Default) - { - } - - /// - /// Constructs a new NativeLibrary using the platform's default library loader. - /// - /// An ordered list of names to attempt to load. - public NativeLibrary(string[] names) : this(names, _platformDefaultLoader, PathResolver.Default) - { - } - - /// - /// Constructs a new NativeLibrary using the specified library loader. - /// - /// The name of the library to load. - /// The loader used to open and close the library, and to load function pointers. - public NativeLibrary(string name, LibraryLoader loader) : this(name, loader, PathResolver.Default) - { - } - - /// - /// Constructs a new NativeLibrary using the specified library loader. - /// - /// An ordered list of names to attempt to load. - /// The loader used to open and close the library, and to load function pointers. - public NativeLibrary(string[] names, LibraryLoader loader) : this(names, loader, PathResolver.Default) - { - } - - /// - /// Constructs a new NativeLibrary using the specified library loader. - /// - /// The name of the library to load. - /// The loader used to open and close the library, and to load function pointers. - /// The path resolver, used to identify possible load targets for the library. - public NativeLibrary(string name, LibraryLoader loader, PathResolver pathResolver) - { - _loader = loader; - Handle = _loader.LoadNativeLibrary(name, pathResolver); - } - - /// - /// Constructs a new NativeLibrary using the specified library loader. - /// - /// An ordered list of names to attempt to load. - /// The loader used to open and close the library, and to load function pointers. - /// The path resolver, used to identify possible load targets for the library. - public NativeLibrary(string[] names, LibraryLoader loader, PathResolver pathResolver) - { - _loader = loader; - Handle = _loader.LoadNativeLibrary(names, pathResolver); - } - - /// - /// Loads a function whose signature matches the given delegate type's signature. - /// - /// The type of delegate to return. - /// The name of the native export. - /// A delegate wrapping the native function. - /// Thrown when no function with the given name - /// is exported from the native library. - public T LoadFunction(string name) - { - IntPtr functionPtr = _loader.LoadFunctionPointer(Handle, name); - if (functionPtr == IntPtr.Zero) - { - throw new InvalidOperationException($"No function was found with the name {name}."); - } - - return Marshal.GetDelegateForFunctionPointer(functionPtr); - } - - /// - /// Loads a function pointer with the given name. - /// - /// The name of the native export. - /// A function pointer for the given name, or 0 if no function with that name exists. - public IntPtr LoadFunction(string name) + private NativeLibrary(string name) { - return _loader.LoadFunctionPointer(Handle, name); + _loader = _platformDefaultLoader; + Handle = _loader.LoadNativeLibrary(name, PathResolver.Default); } /// - /// Frees the native library. Function pointers retrieved from this library will be void. + /// Frees the native library. /// public void Dispose() { diff --git a/test/Microsoft.ML.TestFrameworkCommon/Utility/PathResolver.cs b/test/Microsoft.ML.TestFrameworkCommon/Utility/PathResolver.cs index d56ab680e8..805fa73e55 100644 --- a/test/Microsoft.ML.TestFrameworkCommon/Utility/PathResolver.cs +++ b/test/Microsoft.ML.TestFrameworkCommon/Utility/PathResolver.cs @@ -30,7 +30,7 @@ public abstract class PathResolver /// Enumerates possible library load targets. This default implementation returns the following load targets: /// First: The library contained in the applications base folder. /// Second: The simple name, unchanged. - /// Third: The library as resolved via the default DependencyContext, in the default nuget package cache folder. + /// Third: The library as resolved via the default DependencyContext, in the configured NuGet package cache folder. /// public class DefaultPathResolver : PathResolver { @@ -147,7 +147,10 @@ private bool AddFallbacks(List fallbacks, string rid, IReadOnlyList + diff --git a/test/Microsoft.ML.Tests/TrainerEstimators/OneDalEstimators.cs b/test/Microsoft.ML.Tests/TrainerEstimators/OneDalEstimators.cs index 50edbd48ef..ac9130a42c 100644 --- a/test/Microsoft.ML.Tests/TrainerEstimators/OneDalEstimators.cs +++ b/test/Microsoft.ML.Tests/TrainerEstimators/OneDalEstimators.cs @@ -3,24 +3,12 @@ // See the LICENSE file in the project root for more information. using System; -using System.Collections.Generic; -using System.Linq; -using System.Text.RegularExpressions; -using System.Threading; -using System.Threading.Tasks; -using Microsoft.DotNet.PlatformAbstractions; -using Microsoft.Extensions.DependencyModel; -using Microsoft.ML.Calibrators; +using System.IO; +using Microsoft.DotNet.RemoteExecutor; using Microsoft.ML.Data; -using Microsoft.ML.Internal.Utilities; -using Microsoft.ML.Model; using Microsoft.ML.RunTests; -using Microsoft.ML.Runtime; using Microsoft.ML.TestFramework.Attributes; -using Microsoft.ML.Trainers; using Microsoft.ML.Trainers.FastTree; -using Microsoft.ML.Trainers.LightGbm; -using Microsoft.ML.Transforms; using Xunit; namespace Microsoft.ML.Tests.TrainerEstimators @@ -28,15 +16,36 @@ namespace Microsoft.ML.Tests.TrainerEstimators public partial class TrainerEstimators : TestDataPipeBase { - // [Fact] [NativeDependencyFact("OneDalNative")] public void OneDalFastTreeBinaryEstimator() { - Environment.SetEnvironmentVariable("MLNET_BACKEND", "ONEDAL"); + var originalBackend = Environment.GetEnvironmentVariable("MLNET_BACKEND"); var trainDataPath = GetDataPath("binary_synth_data_train.csv"); var testDataPath = GetDataPath("binary_synth_data_test.csv"); - var loader = ML.Data.CreateTextLoader(columns: new[] { + // oneDAL has to be selected before static initialization of MLContext runs, which means using RemoteExecutor here. + var options = new RemoteInvokeOptions(); + options.StartInfo.EnvironmentVariables["MLNET_BACKEND"] = "ONEDAL"; + // Enable verbose output for oneDAL, so that the output check below can verify that oneDAL is being used. + options.StartInfo.EnvironmentVariables["MLNET_BACKEND_VERBOSE"] = "1"; + // oneDAL loads its threading runtime dynamically; test dependencies are beside the test assembly. + options.StartInfo.EnvironmentVariables["PATH"] = + Path.GetDirectoryName(typeof(TrainerEstimators).Assembly.Location) + Path.PathSeparator + Environment.GetEnvironmentVariable("PATH"); + options.StartInfo.RedirectStandardOutput = true; + var remote = RemoteExecutor.Invoke(TrainOneDalFastForest, trainDataPath, testDataPath, options); + var output = remote.Process.StandardOutput.ReadToEndAsync(); + remote.Dispose(); + + Assert.Contains("Decision Forest Classification parameters:", output.GetAwaiter().GetResult()); + Assert.Equal(originalBackend, Environment.GetEnvironmentVariable("MLNET_BACKEND")); + } + + private static void TrainOneDalFastForest(string trainDataPath, string testDataPath) + { + var ml = new MLContext(seed: 1); + Assert.True(MLContext.OneDalDispatchingEnabled); + + var loader = ml.Data.CreateTextLoader(columns: new[] { new TextLoader.Column("f0", DataKind.Single, 0), new TextLoader.Column("f1", DataKind.Single, 1), new TextLoader.Column("f2", DataKind.Single, 2), @@ -53,13 +62,11 @@ public void OneDalFastTreeBinaryEstimator() var trainingData = loader.Load(trainDataPath); var testingData = loader.Load(testDataPath); - var preprocessingPipeline = ML.Transforms.Concatenate("Features", new string[] { "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7" }); + var preprocessingPipeline = ml.Transforms.Concatenate("Features", new string[] { "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7" }); var preprocessedTrainingData = preprocessingPipeline.Fit(trainingData).Transform(trainingData); var preprocessedTestingData = preprocessingPipeline.Fit(trainingData).Transform(testingData); - // Output.WriteLine($"**** After preprocessing the data got {preprocessedTrainingData.Schema.Count} columns."); - FastForestBinaryTrainer.Options options = new FastForestBinaryTrainer.Options(); options.LabelColumnName = "target"; options.FeatureColumnName = "Features"; @@ -68,12 +75,12 @@ public void OneDalFastTreeBinaryEstimator() options.MinimumExampleCountPerLeaf = 5; options.FeatureFraction = 1.0; - var trainer = ML.BinaryClassification.Trainers.FastForest(options); + var trainer = ml.BinaryClassification.Trainers.FastForest(options); var model = trainer.Fit(preprocessedTrainingData); var trainingPredictions = model.Transform(preprocessedTrainingData); - var trainingMetrics = ML.BinaryClassification.EvaluateNonCalibrated(trainingPredictions, labelColumnName: "target"); + var trainingMetrics = ml.BinaryClassification.EvaluateNonCalibrated(trainingPredictions, labelColumnName: "target"); var testingPredictions = model.Transform(preprocessedTestingData); - var testingMetrics = ML.BinaryClassification.EvaluateNonCalibrated(testingPredictions, labelColumnName: "target"); + var testingMetrics = ml.BinaryClassification.EvaluateNonCalibrated(testingPredictions, labelColumnName: "target"); Assert.True(testingMetrics.Accuracy > 0.8); } diff --git a/test/Microsoft.ML.Tests/TrainerEstimators/SymSgdClassificationTests.cs b/test/Microsoft.ML.Tests/TrainerEstimators/SymSgdClassificationTests.cs index b1597469d6..7670e4d0a7 100644 --- a/test/Microsoft.ML.Tests/TrainerEstimators/SymSgdClassificationTests.cs +++ b/test/Microsoft.ML.Tests/TrainerEstimators/SymSgdClassificationTests.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System.Linq; +using System.Runtime.InteropServices; using Microsoft.ML.Data; using Microsoft.ML.Runtime; using Microsoft.ML.TestFramework.Attributes; @@ -13,7 +14,14 @@ namespace Microsoft.ML.Tests.TrainerEstimators { public partial class TrainerEstimators { - [NativeDependencyFact("SymSgdNative")] + private static bool IsLinuxArm32 => + RuntimeInformation.IsOSPlatform(OSPlatform.Linux) && RuntimeInformation.ProcessArchitecture == Architecture.Arm; + + // Skip Linux ARM32 due to active issue https://github.com/dotnet/machinelearning/issues/7837. + private static bool CanRunSymSgdEstimatorTests => + !IsLinuxArm32 && new NativeDependencyFactAttribute("SymSgdNative").Skip == null; + + [ConditionalFact(nameof(CanRunSymSgdEstimatorTests))] public void TestEstimatorSymSgdClassificationTrainer() { (var pipe, var dataView) = GetBinaryClassificationPipeline(); @@ -27,7 +35,7 @@ public void TestEstimatorSymSgdClassificationTrainer() Done(); } - [NativeDependencyFact("SymSgdNative")] + [ConditionalFact(nameof(CanRunSymSgdEstimatorTests))] public void TestEstimatorSymSgdInitPredictor() { (var pipe, var dataView) = GetBinaryClassificationPipeline();