From ea368f69db20bc2fb93fbebabd7dbef645c1407e Mon Sep 17 00:00:00 2001 From: Miguel de Icaza Date: Fri, 5 Jun 2020 14:17:52 -0400 Subject: [PATCH] Add Swift/macOS sample, a port of the Windows MNist sample --- samples/swift/ReadMe.md | 54 ++ .../SwiftMnist.xcodeproj/project.pbxproj | 396 ++++++++++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcschemes/SwiftMnist.xcscheme | 85 +++ samples/swift/SwiftMnist/AppDelegate.swift | 41 ++ .../AppIcon.appiconset/Contents.json | 58 ++ .../SwiftMnist/Assets.xcassets/Contents.json | 6 + .../SwiftMnist/Base.lproj/Main.storyboard | 683 ++++++++++++++++++ samples/swift/SwiftMnist/ContentView.swift | 173 +++++ samples/swift/SwiftMnist/Info.plist | 36 + samples/swift/SwiftMnist/OnnxInterop.cpp | 73 ++ samples/swift/SwiftMnist/OnnxInterop.hpp | 16 + .../Preview Assets.xcassets/Contents.json | 6 + .../SwiftMnist/SwiftMnist-Bridging-Header.h | 12 + .../swift/SwiftMnist/SwiftMnist.entitlements | 10 + 16 files changed, 1664 insertions(+) create mode 100644 samples/swift/ReadMe.md create mode 100644 samples/swift/SwiftMnist.xcodeproj/project.pbxproj create mode 100644 samples/swift/SwiftMnist.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 samples/swift/SwiftMnist.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 samples/swift/SwiftMnist.xcodeproj/xcshareddata/xcschemes/SwiftMnist.xcscheme create mode 100644 samples/swift/SwiftMnist/AppDelegate.swift create mode 100644 samples/swift/SwiftMnist/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 samples/swift/SwiftMnist/Assets.xcassets/Contents.json create mode 100644 samples/swift/SwiftMnist/Base.lproj/Main.storyboard create mode 100644 samples/swift/SwiftMnist/ContentView.swift create mode 100644 samples/swift/SwiftMnist/Info.plist create mode 100644 samples/swift/SwiftMnist/OnnxInterop.cpp create mode 100644 samples/swift/SwiftMnist/OnnxInterop.hpp create mode 100644 samples/swift/SwiftMnist/Preview Content/Preview Assets.xcassets/Contents.json create mode 100644 samples/swift/SwiftMnist/SwiftMnist-Bridging-Header.h create mode 100644 samples/swift/SwiftMnist/SwiftMnist.entitlements diff --git a/samples/swift/ReadMe.md b/samples/swift/ReadMe.md new file mode 100644 index 0000000000..7cdf3d5065 --- /dev/null +++ b/samples/swift/ReadMe.md @@ -0,0 +1,54 @@ +# MNIST Sample - Number recognition + +This sample uses the MNIST model from the Model Zoo: https://github.com/onnx/models/tree/master/vision/classification/mnist + +![Screenshot](Screenshot.png) + +## Requirements + +* MacOS Catalina +* Xcode 11 +* Compiled libonnxruntime.dll / lib + + +## Build + +Command line: + +``` +$ xcodebuild -project SwiftMnist.xcodeproj +``` + +From Xcode, open `SwiftMnist.xcodeproj` and run with Command-R. + +## How to use it + +Just draw a number on the surface, when you lift your finger from the +mouse or the trackpad, the guess will be displayed. + +Note that when drawing numbers requiring multiple drawing strokes, the +model will be run at the end of each stroke with probably wrong +predictions (but it's amusing to see and avoids needing to press a +'run model' button). + +## How it works + +(Add once it is added) + +### Preprocessing the data + +MNIST's input is a {1,1,28,28} shaped float tensor, which is basically +a 28x28 floating point grayscale image (0.0 = background, 1.0 = +foreground). + +### Postprocessing the output + +MNIST's output is a simple {1,10} float tensor that holds the +likelihood weights per number. The number with the highest value is +the model's best guess. + +The MNIST structure uses std::max_element to do this and stores it in +result_: + +https://github.com/microsoft/onnxruntime/blob/521dc757984fbf9770d0051997178fbb9565cd52/samples/c_cxx/MNIST/MNIST.cpp#L31 + diff --git a/samples/swift/SwiftMnist.xcodeproj/project.pbxproj b/samples/swift/SwiftMnist.xcodeproj/project.pbxproj new file mode 100644 index 0000000000..a336e2dcf3 --- /dev/null +++ b/samples/swift/SwiftMnist.xcodeproj/project.pbxproj @@ -0,0 +1,396 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 49F074202485756B00A83CDC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49F0741F2485756B00A83CDC /* AppDelegate.swift */; }; + 49F074222485756B00A83CDC /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49F074212485756B00A83CDC /* ContentView.swift */; }; + 49F074242485756C00A83CDC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 49F074232485756C00A83CDC /* Assets.xcassets */; }; + 49F074272485756C00A83CDC /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 49F074262485756C00A83CDC /* Preview Assets.xcassets */; }; + 49F0742A2485756C00A83CDC /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 49F074282485756C00A83CDC /* Main.storyboard */; }; + 49F07434248575A600A83CDC /* libonnxruntime.1.3.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 49F07433248575A600A83CDC /* libonnxruntime.1.3.0.dylib */; }; + 49F07435248575A600A83CDC /* libonnxruntime.1.3.0.dylib in Embed Libraries */ = {isa = PBXBuildFile; fileRef = 49F07433248575A600A83CDC /* libonnxruntime.1.3.0.dylib */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; + 49F0743A248575CE00A83CDC /* OnnxInterop.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 49F07438248575CE00A83CDC /* OnnxInterop.cpp */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 49F07436248575A600A83CDC /* Embed Libraries */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 49F07435248575A600A83CDC /* libonnxruntime.1.3.0.dylib in Embed Libraries */, + ); + name = "Embed Libraries"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 49F0741C2485756B00A83CDC /* SwiftMnist.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SwiftMnist.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 49F0741F2485756B00A83CDC /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 49F074212485756B00A83CDC /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; + 49F074232485756C00A83CDC /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 49F074262485756C00A83CDC /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + 49F074292485756C00A83CDC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 49F0742B2485756C00A83CDC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 49F0742C2485756C00A83CDC /* SwiftMnist.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SwiftMnist.entitlements; sourceTree = ""; }; + 49F07433248575A600A83CDC /* libonnxruntime.1.3.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libonnxruntime.1.3.0.dylib; path = ../../build/Linux/RelWithDebInfo/libonnxruntime.1.3.0.dylib; sourceTree = ""; }; + 49F07437248575CE00A83CDC /* SwiftMnist-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SwiftMnist-Bridging-Header.h"; sourceTree = ""; }; + 49F07438248575CE00A83CDC /* OnnxInterop.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = OnnxInterop.cpp; sourceTree = ""; }; + 49F07439248575CE00A83CDC /* OnnxInterop.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = OnnxInterop.hpp; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 49F074192485756B00A83CDC /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 49F07434248575A600A83CDC /* libonnxruntime.1.3.0.dylib in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 49F074132485756B00A83CDC = { + isa = PBXGroup; + children = ( + 49F0741E2485756B00A83CDC /* SwiftMnist */, + 49F0741D2485756B00A83CDC /* Products */, + 49F07432248575A600A83CDC /* Frameworks */, + ); + sourceTree = ""; + }; + 49F0741D2485756B00A83CDC /* Products */ = { + isa = PBXGroup; + children = ( + 49F0741C2485756B00A83CDC /* SwiftMnist.app */, + ); + name = Products; + sourceTree = ""; + }; + 49F0741E2485756B00A83CDC /* SwiftMnist */ = { + isa = PBXGroup; + children = ( + 49F0741F2485756B00A83CDC /* AppDelegate.swift */, + 49F074212485756B00A83CDC /* ContentView.swift */, + 49F074232485756C00A83CDC /* Assets.xcassets */, + 49F074282485756C00A83CDC /* Main.storyboard */, + 49F0742B2485756C00A83CDC /* Info.plist */, + 49F0742C2485756C00A83CDC /* SwiftMnist.entitlements */, + 49F074252485756C00A83CDC /* Preview Content */, + 49F07438248575CE00A83CDC /* OnnxInterop.cpp */, + 49F07439248575CE00A83CDC /* OnnxInterop.hpp */, + 49F07437248575CE00A83CDC /* SwiftMnist-Bridging-Header.h */, + ); + path = SwiftMnist; + sourceTree = ""; + }; + 49F074252485756C00A83CDC /* Preview Content */ = { + isa = PBXGroup; + children = ( + 49F074262485756C00A83CDC /* Preview Assets.xcassets */, + ); + path = "Preview Content"; + sourceTree = ""; + }; + 49F07432248575A600A83CDC /* Frameworks */ = { + isa = PBXGroup; + children = ( + 49F07433248575A600A83CDC /* libonnxruntime.1.3.0.dylib */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 49F0741B2485756B00A83CDC /* SwiftMnist */ = { + isa = PBXNativeTarget; + buildConfigurationList = 49F0742F2485756C00A83CDC /* Build configuration list for PBXNativeTarget "SwiftMnist" */; + buildPhases = ( + 49F074182485756B00A83CDC /* Sources */, + 49F074192485756B00A83CDC /* Frameworks */, + 49F0741A2485756B00A83CDC /* Resources */, + 49F07436248575A600A83CDC /* Embed Libraries */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SwiftMnist; + productName = SwiftMnist; + productReference = 49F0741C2485756B00A83CDC /* SwiftMnist.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 49F074142485756B00A83CDC /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1150; + LastUpgradeCheck = 1150; + ORGANIZATIONNAME = "Miguel de Icaza"; + TargetAttributes = { + 49F0741B2485756B00A83CDC = { + CreatedOnToolsVersion = 11.5; + LastSwiftMigration = 1150; + }; + }; + }; + buildConfigurationList = 49F074172485756B00A83CDC /* Build configuration list for PBXProject "SwiftMnist" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 49F074132485756B00A83CDC; + productRefGroup = 49F0741D2485756B00A83CDC /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 49F0741B2485756B00A83CDC /* SwiftMnist */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 49F0741A2485756B00A83CDC /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 49F0742A2485756C00A83CDC /* Main.storyboard in Resources */, + 49F074272485756C00A83CDC /* Preview Assets.xcassets in Resources */, + 49F074242485756C00A83CDC /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 49F074182485756B00A83CDC /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 49F074222485756B00A83CDC /* ContentView.swift in Sources */, + 49F074202485756B00A83CDC /* AppDelegate.swift in Sources */, + 49F0743A248575CE00A83CDC /* OnnxInterop.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 49F074282485756C00A83CDC /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 49F074292485756C00A83CDC /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 49F0742D2485756C00A83CDC /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 49F0742E2485756C00A83CDC /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 49F074302485756C00A83CDC /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = SwiftMnist/SwiftMnist.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_ASSET_PATHS = "\"SwiftMnist/Preview Content\""; + DEVELOPMENT_TEAM = PJQC57N853; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_PREVIEWS = YES; + HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/../../include/onnxruntime/core/session"; + INFOPLIST_FILE = SwiftMnist/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/../../build/Linux/RelWithDebInfo"; + MACOSX_DEPLOYMENT_TARGET = 10.15; + PRODUCT_BUNDLE_IDENTIFIER = org.tirania.SwiftMnist; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "SwiftMnist/SwiftMnist-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 49F074312485756C00A83CDC /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = SwiftMnist/SwiftMnist.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_ASSET_PATHS = "\"SwiftMnist/Preview Content\""; + DEVELOPMENT_TEAM = PJQC57N853; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_PREVIEWS = YES; + HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/../../include/onnxruntime/core/session"; + INFOPLIST_FILE = SwiftMnist/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + LIBRARY_SEARCH_PATHS = "$(PROJECT_DIR)/../../build/Linux/RelWithDebInfo"; + MACOSX_DEPLOYMENT_TARGET = 10.15; + PRODUCT_BUNDLE_IDENTIFIER = org.tirania.SwiftMnist; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "SwiftMnist/SwiftMnist-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 49F074172485756B00A83CDC /* Build configuration list for PBXProject "SwiftMnist" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 49F0742D2485756C00A83CDC /* Debug */, + 49F0742E2485756C00A83CDC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 49F0742F2485756C00A83CDC /* Build configuration list for PBXNativeTarget "SwiftMnist" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 49F074302485756C00A83CDC /* Debug */, + 49F074312485756C00A83CDC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 49F074142485756B00A83CDC /* Project object */; +} diff --git a/samples/swift/SwiftMnist.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/samples/swift/SwiftMnist.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000000..4a385ecbec --- /dev/null +++ b/samples/swift/SwiftMnist.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/samples/swift/SwiftMnist.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/samples/swift/SwiftMnist.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000000..18d981003d --- /dev/null +++ b/samples/swift/SwiftMnist.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/samples/swift/SwiftMnist.xcodeproj/xcshareddata/xcschemes/SwiftMnist.xcscheme b/samples/swift/SwiftMnist.xcodeproj/xcshareddata/xcschemes/SwiftMnist.xcscheme new file mode 100644 index 0000000000..2c95ae0381 --- /dev/null +++ b/samples/swift/SwiftMnist.xcodeproj/xcshareddata/xcschemes/SwiftMnist.xcscheme @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/swift/SwiftMnist/AppDelegate.swift b/samples/swift/SwiftMnist/AppDelegate.swift new file mode 100644 index 0000000000..79c818e4b4 --- /dev/null +++ b/samples/swift/SwiftMnist/AppDelegate.swift @@ -0,0 +1,41 @@ +// +// AppDelegate.swift +// SwiftMnist +// +// Created by Miguel de Icaza on 6/1/20. +// Copyright © 2020 Miguel de Icaza. All rights reserved. +// + +import Cocoa +import SwiftUI + +var mnist = mnist_new() +@NSApplicationMain +class AppDelegate: NSObject, NSApplicationDelegate { + + var window: NSWindow! + + + func applicationDidFinishLaunching(_ aNotification: Notification) { + // Create the SwiftUI view that provides the window contents. + let contentView = ContentView() + + + // Create the window and set the content view. + window = NSWindow( + contentRect: NSRect(x: 0, y: 0, width: 540, height: 300), + styleMask: [.titled, .closable, .miniaturizable, .resizable, .fullSizeContentView], + backing: .buffered, defer: false) + window.center() + window.setFrameAutosaveName("Main Window") + window.contentView = NSHostingView(rootView: contentView) + window.makeKeyAndOrderFront(nil) + } + + func applicationWillTerminate(_ aNotification: Notification) { + // Insert code here to tear down your application + } + + +} + diff --git a/samples/swift/SwiftMnist/Assets.xcassets/AppIcon.appiconset/Contents.json b/samples/swift/SwiftMnist/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000000..3f00db43ec --- /dev/null +++ b/samples/swift/SwiftMnist/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,58 @@ +{ + "images" : [ + { + "idiom" : "mac", + "scale" : "1x", + "size" : "16x16" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "16x16" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "32x32" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "32x32" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "128x128" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "128x128" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "256x256" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "256x256" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "512x512" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "512x512" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/samples/swift/SwiftMnist/Assets.xcassets/Contents.json b/samples/swift/SwiftMnist/Assets.xcassets/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/samples/swift/SwiftMnist/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/samples/swift/SwiftMnist/Base.lproj/Main.storyboard b/samples/swift/SwiftMnist/Base.lproj/Main.storyboard new file mode 100644 index 0000000000..4b9fa18549 --- /dev/null +++ b/samples/swift/SwiftMnist/Base.lproj/Main.storyboard @@ -0,0 +1,683 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + Default + + + + + + + Left to Right + + + + + + + Right to Left + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/swift/SwiftMnist/ContentView.swift b/samples/swift/SwiftMnist/ContentView.swift new file mode 100644 index 0000000000..4a04e24496 --- /dev/null +++ b/samples/swift/SwiftMnist/ContentView.swift @@ -0,0 +1,173 @@ +// +// ContentView.swift +// SwiftMnist +// +// Created by Miguel de Icaza on 6/1/20. +// Copyright © 2020 Miguel de Icaza. All rights reserved. +// + +import SwiftUI +import CoreGraphics + + +let factor:CGFloat = 6.0 + +struct Drawing { + var points: [CGPoint] = [CGPoint]() +} + +struct DrawingPad: View { + @Binding var currentDrawing: Drawing + @Binding var drawings: [Drawing] + @Binding var guesses: [Float] + @Binding var result: Int + + func updateGuess () + { + // Render the vector to a bitmap of ours + let ctx = CGContext.init(data: nil, width: 28, height: 28, bitsPerComponent: 8, bytesPerRow: 28*4, space: CGColorSpaceCreateDeviceRGB(), bitmapInfo: CGImageAlphaInfo.premultipliedFirst.rawValue)! + ctx.translateBy(x: 0, y: 28) + ctx.scaleBy(x: 1, y: -1) + + ctx.setStrokeColor(NSColor.black.cgColor) + for drawing in self.drawings { + if drawing.points.count < 2 { + continue + } + + let mapped = drawing.points.map { CGPoint (x: $0.x/factor, y: $0.y/factor) } + ctx.beginPath() + ctx.move(to: mapped [0]) + for i in 1..= 0 + && currentPoint.y < geometry.size.height { + self.currentDrawing.points.append(currentPoint) + } + self.updateGuess () + }) + .onEnded({ (value) in + self.drawings.append(self.currentDrawing) + self.currentDrawing = Drawing() + self.updateGuess () + }) + ) + } + .frame(maxHeight: .infinity) + } + + private func add(drawing: Drawing, toPath path: inout Path) { + let points = drawing.points + if points.count > 1 { + for i in 0..String + { + let v = guesses [idx] + return (v >= 0 ? " " : "") + String(format: "%2.2f", v) + } + + var body: some View { + VStack(alignment: .center) { + Text("Draw a digit") + .font(.largeTitle) + HStack { + DrawingPad( + currentDrawing: $currentDrawing, + drawings: $drawings, + guesses: $guesses, + result: $result) + .frame(width: 24*factor, height: 24*factor) + .border(Color.black) + VStack { + ForEach (guesses.indices) { idx in + HStack { + Text ("x") + Rectangle () + .offset (x: 10) + .border(Color.red) + .frame(width:40, height: 20) + } + } + }.frame (width: 120) + VStack (alignment: .leading) { + Text ("Result: \(result)") + ForEach (guesses.indices) { idx in + + Text ("\(idx) -> \(self.fmt (idx))") + + } + }.frame(width: 120) + } + .font(.system(Font.TextStyle.body, design: .monospaced)) + + Button(action: {self.drawings = []; self.guesses = Array.init (repeating: 0, count: 10)}) { + Text ("Clear") + } + } + } +} + + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} diff --git a/samples/swift/SwiftMnist/Info.plist b/samples/swift/SwiftMnist/Info.plist new file mode 100644 index 0000000000..4ddbfae047 --- /dev/null +++ b/samples/swift/SwiftMnist/Info.plist @@ -0,0 +1,36 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + Copyright © 2020 Miguel de Icaza. All rights reserved. + NSMainStoryboardFile + Main + NSPrincipalClass + NSApplication + NSSupportsAutomaticTermination + + NSSupportsSuddenTermination + + + diff --git a/samples/swift/SwiftMnist/OnnxInterop.cpp b/samples/swift/SwiftMnist/OnnxInterop.cpp new file mode 100644 index 0000000000..64c23c5aff --- /dev/null +++ b/samples/swift/SwiftMnist/OnnxInterop.cpp @@ -0,0 +1,73 @@ +// +// OnnxInterop.cpp +// SwiftMnist +// +// Created by Miguel de Icaza on 6/1/20. +// Copyright © 2020 Miguel de Icaza. All rights reserved. +// +#include +#include +extern "C" { +#include "SwiftMnist-Bridging-Header.h" +} +struct MNIST { + MNIST() { + auto memory_info = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU); + input_tensor_ = Ort::Value::CreateTensor(memory_info, input_image_.data(), input_image_.size(), input_shape_.data(), input_shape_.size()); + output_tensor_ = Ort::Value::CreateTensor(memory_info, results_.data(), results_.size(), output_shape_.data(), output_shape_.size()); + } + + std::ptrdiff_t Run() { + const char* input_names[] = {"Input3"}; + const char* output_names[] = {"Plus214_Output_0"}; + + session_.Run(Ort::RunOptions{nullptr}, input_names, &input_tensor_, 1, output_names, &output_tensor_, 1); + + result_ = std::distance(results_.begin(), std::max_element(results_.begin(), results_.end())); + return result_; + } + + static constexpr const int width_ = 28; + static constexpr const int height_ = 28; + + std::array input_image_{}; + std::array results_{}; + int64_t result_{0}; + + private: + Ort::Env env; + Ort::Session session_{env, "model.onnx", Ort::SessionOptions{nullptr}}; + + Ort::Value input_tensor_{nullptr}; + std::array input_shape_{1, 1, width_, height_}; + + Ort::Value output_tensor_{nullptr}; + std::array output_shape_{1, 10}; +}; + +mnist *mnist_new () +{ + return (mnist *) new MNIST(); +} + +float *mnist_get_input_image (mnist *_mnist, size_t *out) +{ + MNIST *mnist = (MNIST *) _mnist; + *out = mnist->input_image_.size(); + return mnist->input_image_.data (); +} + +float *mnist_get_results (mnist *_mnist, size_t *out) +{ + MNIST *mnist = (MNIST *) _mnist; + *out = mnist->results_.size(); + return mnist->results_.data (); +} + +long mnist_run (mnist *_mnist) +{ + MNIST *mnist = (MNIST *) _mnist; + + mnist->Run(); + return mnist->result_; +} diff --git a/samples/swift/SwiftMnist/OnnxInterop.hpp b/samples/swift/SwiftMnist/OnnxInterop.hpp new file mode 100644 index 0000000000..1f49faf443 --- /dev/null +++ b/samples/swift/SwiftMnist/OnnxInterop.hpp @@ -0,0 +1,16 @@ +// +// OnnxInterop.hpp +// SwiftMnist +// +// Created by Miguel de Icaza on 6/1/20. +// Copyright © 2020 Miguel de Icaza. All rights reserved. +// + +#ifndef OnnxInterop_hpp +#define OnnxInterop_hpp + +#include + +#include "SwiftMnist-Bridging-Header.h" + +#endif /* OnnxInterop_hpp */ diff --git a/samples/swift/SwiftMnist/Preview Content/Preview Assets.xcassets/Contents.json b/samples/swift/SwiftMnist/Preview Content/Preview Assets.xcassets/Contents.json new file mode 100644 index 0000000000..73c00596a7 --- /dev/null +++ b/samples/swift/SwiftMnist/Preview Content/Preview Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/samples/swift/SwiftMnist/SwiftMnist-Bridging-Header.h b/samples/swift/SwiftMnist/SwiftMnist-Bridging-Header.h new file mode 100644 index 0000000000..3f24ee7af6 --- /dev/null +++ b/samples/swift/SwiftMnist/SwiftMnist-Bridging-Header.h @@ -0,0 +1,12 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + +#include "OnnxInterop.hpp" +typedef void *mnist; + + +mnist *mnist_new (); +float *mnist_get_input_image (mnist *_mnist, size_t *out); +float *mnist_get_results (mnist *_mnist, size_t *out); +long mnist_run (mnist *_mnist); diff --git a/samples/swift/SwiftMnist/SwiftMnist.entitlements b/samples/swift/SwiftMnist/SwiftMnist.entitlements new file mode 100644 index 0000000000..f2ef3ae026 --- /dev/null +++ b/samples/swift/SwiftMnist/SwiftMnist.entitlements @@ -0,0 +1,10 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.files.user-selected.read-only + + +