├── Package.resolved ├── docs └── assets │ ├── logo.png │ └── swift-tf-logo.png ├── .dockerignore ├── Tests ├── LinuxMain.swift └── STSLibraryTests │ ├── XCTestManifests.swift │ └── STSLibraryTests.swift ├── Sources ├── STSApplication │ └── main.swift └── STSLibrary │ ├── TensorFlowExample.swift │ └── Application.swift ├── Dockerfile ├── Package.swift ├── LICENSE ├── entrypoint ├── sts ├── .gitignore └── README.md /Package.resolved: -------------------------------------------------------------------------------- 1 | { 2 | "object": { 3 | "pins": [ 4 | 5 | ] 6 | }, 7 | "version": 1 8 | } 9 | -------------------------------------------------------------------------------- /docs/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zachgrayio/swift-tensorflow-starter/HEAD/docs/assets/logo.png -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | docs 2 | .build 3 | STSProject.xcodeproj 4 | /.idea/ 5 | run_app.sh 6 | run_repl.sh 7 | README.md 8 | -------------------------------------------------------------------------------- /docs/assets/swift-tf-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zachgrayio/swift-tensorflow-starter/HEAD/docs/assets/swift-tf-logo.png -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | import STSLibraryTests 4 | 5 | var tests = [XCTestCaseEntry]() 6 | tests += STSLibraryTests.allTests() 7 | XCTMain(tests) -------------------------------------------------------------------------------- /Sources/STSApplication/main.swift: -------------------------------------------------------------------------------- 1 | import STSLibrary 2 | 3 | let app = Application() 4 | do { 5 | try app.run() 6 | } catch { 7 | print("Failed to run the STS Application: \(error)") 8 | } 9 | -------------------------------------------------------------------------------- /Tests/STSLibraryTests/XCTestManifests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | 3 | #if !os(macOS) 4 | public func allTests() -> [XCTestCaseEntry] { 5 | return [ 6 | testCase(STSLibraryTests.allTests), 7 | ] 8 | } 9 | #endif -------------------------------------------------------------------------------- /Sources/STSLibrary/TensorFlowExample.swift: -------------------------------------------------------------------------------- 1 | import TensorFlow 2 | 3 | struct TensorFlowExample { 4 | static func multiplyTensor() -> Tensor { 5 | let t = Tensor([1.2, 0.8]) 6 | return t * t 7 | } 8 | } -------------------------------------------------------------------------------- /Sources/STSLibrary/Application.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public final class Application { 4 | let prefix = "STS" 5 | 6 | public init() {} 7 | 8 | public func run() throws { 9 | print("\(prefix): \(TensorFlowExample.multiplyTensor())") 10 | } 11 | } -------------------------------------------------------------------------------- /Tests/STSLibraryTests/STSLibraryTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import STSLibrary 3 | 4 | final class STSLibraryTests: XCTestCase { 5 | 6 | func testApplicationPrefix() { 7 | XCTAssertEqual(Application().prefix, "STS") 8 | } 9 | 10 | static var allTests = [ 11 | ("testApplicationPrefix", testApplicationPrefix), 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM zachgray/swift-tensorflow:4.2 2 | 3 | LABEL Description="An STS Application" 4 | 5 | WORKDIR /usr/src 6 | 7 | RUN apt-get update && apt-get install inotify-tools -y 8 | 9 | # Cache this step 10 | COPY Package.swift /usr/src 11 | RUN swift package update 12 | 13 | # Add Source 14 | ADD ./ /usr/src 15 | 16 | # user can pass in CONFIG=release to override 17 | ENV CONFIG=debug 18 | 19 | # user can pass in LIVE=true 20 | ENV LIVE=false 21 | 22 | RUN swift build -Xswiftc -O --configuration ${CONFIG} 23 | 24 | RUN cp ./.build/${CONFIG}/libSTSLibrary.so /usr/lib/libSTSLibrary.so 25 | RUN cp ./.build/${CONFIG}/STSLibrary.swiftmodule /usr/lib/STSLibrary.swiftmodule 26 | RUN cp ./.build/${CONFIG}/STSApplication /usr/bin/STSApplication 27 | 28 | ENTRYPOINT ./entrypoint $CONFIG $LIVE -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:4.0 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "STSProject", 7 | products: [ 8 | .library( 9 | name: "STSLibrary", 10 | type: .dynamic, 11 | targets: ["STSLibrary"] 12 | ) 13 | ], 14 | dependencies: [ 15 | //example: 16 | // .package(url: "https://github.com/ReactiveX/RxSwift.git", "4.0.0" ..< "5.0.0") 17 | ], 18 | targets: [ 19 | .target( 20 | name: "STSLibrary", 21 | dependencies: []), 22 | .target( 23 | name: "STSApplication", 24 | dependencies: ["STSLibrary"]), 25 | .testTarget( 26 | name: "STSLibraryTests", 27 | dependencies: ["STSLibrary"]), 28 | ] 29 | ) 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Zach Gray 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /entrypoint: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | CONFIG=$1 4 | LIVE=$2 5 | 6 | build() { 7 | swift build -Xswiftc -O --configuration ${CONFIG} 8 | } 9 | 10 | install_application() { 11 | cp ./.build/${CONFIG}/libSTSLibrary.so /usr/lib/libSTSLibrary.so 12 | cp ./.build/${CONFIG}/STSLibrary.swiftmodule /usr/lib/STSLibrary.swiftmodule 13 | cp ./.build/${CONFIG}/STSApplication /usr/bin/STSApplication 14 | } 15 | 16 | run_application() { 17 | /usr/bin/STSApplication 18 | } 19 | 20 | build_and_run() { 21 | build && install_application && run_application 22 | } 23 | 24 | watch_files() { 25 | inotifywait --quiet --recursive --monitor --event modify --format "%w%f" . \ 26 | | while read file change; do 27 | if [[ ${file} = *".swift" ]] ; then 28 | echo "Changes in file: $file, building..." 29 | if [[ ${file} = *"Package.swift" ]] ; then 30 | swift package update 31 | fi 32 | build_and_run 33 | echo "Waiting for changes to run application again." 34 | fi 35 | done 36 | } 37 | 38 | entrypoint() { 39 | build_and_run 40 | } 41 | 42 | live_entrypoint() { 43 | run_application 44 | echo "Waiting for changes to run application again." 45 | watch_files & 46 | wait 47 | } 48 | 49 | if [ ${LIVE} = true ] ; then 50 | live_entrypoint 51 | else 52 | entrypoint 53 | fi -------------------------------------------------------------------------------- /sts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | POSITIONAL=() 4 | STS_NAME=sts-application 5 | STS_BUILD_ENABLED=false 6 | STS_LIVE_ENABLED=false 7 | 8 | TXT_NC='\033[0m' 9 | TXT_GREEN='\033[0;32m' 10 | TXT_YELLOW='\033[0;33m' 11 | TXT_RED='\033[0;31m' 12 | 13 | while [ $# -gt 0 ] 14 | do 15 | key="$1" 16 | case ${key} in 17 | -n|--name) 18 | STS_NAME="$2" 19 | shift 20 | shift 21 | ;; 22 | -v|--volume) 23 | STS_VOLUME_ENABLED=true 24 | shift 25 | ;; 26 | -b|--build) 27 | STS_BUILD_ENABLED=true 28 | shift 29 | ;; 30 | -p|--prod|-r|--release) 31 | STS_RELEASE_CONFIG_ENABLED=true 32 | shift 33 | ;; 34 | -l|--live) 35 | STS_LIVE_ENABLED=true 36 | shift 37 | ;; 38 | *) # unknown option 39 | POSITIONAL+=("$1") 40 | shift 41 | ;; 42 | esac 43 | done 44 | set -- "${POSITIONAL[@]}" 45 | 46 | STS_COMMAND=${POSITIONAL[0]} 47 | STS_COMMAND_ARG=${POSITIONAL[1]} 48 | 49 | # volume flag 50 | if [ "$STS_VOLUME_ENABLED" = true ] ; then 51 | STS_VOLUME_FLAG="-v $PWD:/usr/src" 52 | else 53 | STS_VOLUME_FLAG="" 54 | fi 55 | 56 | # configuration build arg flag 57 | if [ "$STS_RELEASE_CONFIG_ENABLED" = true ] ; then 58 | STS_BUILD_COMMAND="docker build -t ${STS_NAME} --build-arg CONFIG=release . " 59 | else 60 | STS_BUILD_COMMAND="docker build -t ${STS_NAME} ." 61 | fi 62 | 63 | # live flag TODO: Fix conflict edge case with volume and live flags 64 | if [ "$STS_LIVE_ENABLED" = true ] ; then 65 | STS_VOLUME_FLAG="-v $PWD:/usr/src" 66 | STS_LIVE_FLAG="-e LIVE=true" 67 | else 68 | STS_VOLUME_FLAG="" 69 | STS_LIVE_FLAG="" 70 | fi 71 | 72 | case ${STS_COMMAND} in 73 | build) 74 | echo -e "[STS][build] Building with: ${TXT_GREEN}${STS_BUILD_COMMAND}${TXT_NC}" 75 | eval ${STS_BUILD_COMMAND} 76 | ;; 77 | run) 78 | case ${STS_COMMAND_ARG} in 79 | app) 80 | RUN_COMMAND="docker run --rm -it ${STS_LIVE_FLAG} ${STS_VOLUME_FLAG} ${STS_NAME}" 81 | ;; 82 | repl) 83 | if [ "$STS_LIVE_ENABLED" = true ] ; then 84 | echo -e "[STS][run][${STS_COMMAND_ARG}] ignoring unsupported flag: ${TXT_YELLOW}-l|--live${TXT_NC}" 85 | fi 86 | RUN_COMMAND="docker run --rm ${STS_VOLUME_FLAG} --security-opt seccomp:unconfined -it \ 87 | --entrypoint /usr/bin/swift \ 88 | ${STS_NAME} \ 89 | -I/usr/lib/swift/clang/include \ 90 | -I/usr/lib \ 91 | -L/usr/lib \ 92 | -lSTSLibrary \ 93 | -lswiftPython \ 94 | -lswiftTensorFlow" 95 | ;; 96 | test|tests) 97 | # TODO: Finish live reloaded tests; need to think about the --entrypoint usage 98 | if [ "$STS_LIVE_ENABLED" = true ] ; then 99 | echo -e "[STS][run][${STS_COMMAND_ARG}] ignoring unsupported flag: ${TXT_YELLOW}-l|--live${TXT_NC}" 100 | fi 101 | RUN_COMMAND="docker run --rm -it ${STS_LIVE_FLAG} ${STS_VOLUME_FLAG} --entrypoint "/usr/bin/swift" ${STS_NAME} test -Xswiftc -O" 102 | ;; 103 | xcode) 104 | if [ "$STS_LIVE_ENABLED" = true ] ; then 105 | echo -e "[STS][run][${STS_COMMAND_ARG}] ignoring unsupported flag: ${TXT_YELLOW}-l|--live${TXT_NC}" 106 | fi 107 | RUN_COMMAND="docker run --rm -v ${PWD}:/usr/src \ 108 | --entrypoint /usr/bin/swift \ 109 | ${STS_NAME} \ 110 | package generate-xcodeproj \ 111 | && open STSProject.xcodeproj" 112 | ;; 113 | *) 114 | echo -e "[STS][run] ${TXT_RED}Unknown or empty argument passed to run: '${STS_COMMAND_ARG}'${TXT_NC}" 115 | ;; 116 | esac 117 | if [ -n "$RUN_COMMAND" ] ; then 118 | if [ "$STS_BUILD_ENABLED" = true ] && [ -n "$STS_COMMAND_ARG" ]; then 119 | echo -e "[STS][run] -b|--build was passed; building with: ${TXT_GREEN}${STS_BUILD_COMMAND}${TXT_NC}" 120 | eval ${STS_BUILD_COMMAND} 121 | fi 122 | if [ "$(docker images -q ${STS_NAME} 2> /dev/null)" == "" ] ; then 123 | echo -e "[STS][run][${STS_COMMAND_ARG}] ${TXT_YELLOW}Image with tag '${STS_NAME}' not found;${TXT_NC} building with: ${TXT_GREEN}${STS_BUILD_COMMAND}${TXT_NC}" 124 | eval ${STS_BUILD_COMMAND} 125 | fi 126 | echo -e "[STS][run][${STS_COMMAND_ARG}] running with: ${TXT_GREEN}${RUN_COMMAND}${TXT_NC}" 127 | eval ${RUN_COMMAND} 128 | fi 129 | ;; 130 | esac 131 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | STSProject.xcodeproj 2 | .idea 3 | 4 | /.build 5 | /Packages 6 | 7 | ### C template 8 | # Prerequisites 9 | *.d 10 | 11 | # Object files 12 | *.o 13 | *.ko 14 | *.obj 15 | *.elf 16 | 17 | # Linker output 18 | *.ilk 19 | *.map 20 | *.exp 21 | 22 | # Precompiled Headers 23 | *.gch 24 | *.pch 25 | 26 | # Libraries 27 | *.lib 28 | *.a 29 | *.la 30 | *.lo 31 | 32 | # Shared objects (inc. Windows DLLs) 33 | *.dll 34 | *.so 35 | *.so.* 36 | *.dylib 37 | 38 | # Executables 39 | *.exe 40 | *.out 41 | *.app 42 | *.i*86 43 | *.x86_64 44 | *.hex 45 | 46 | # Debug files 47 | *.dSYM/ 48 | *.su 49 | *.idb 50 | *.pdb 51 | 52 | # Kernel Module Compile Results 53 | *.mod* 54 | *.cmd 55 | .tmp_versions/ 56 | modules.order 57 | Module.symvers 58 | Mkfile.old 59 | dkms.conf 60 | ### Objective-C template 61 | # Xcode 62 | # 63 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 64 | 65 | ## Build generated 66 | build/ 67 | DerivedData/ 68 | 69 | ## Various settings 70 | *.pbxuser 71 | !default.pbxuser 72 | *.mode1v3 73 | !default.mode1v3 74 | *.mode2v3 75 | !default.mode2v3 76 | *.perspectivev3 77 | !default.perspectivev3 78 | xcuserdata/ 79 | 80 | ## Other 81 | *.moved-aside 82 | *.xccheckout 83 | *.xcscmblueprint 84 | 85 | ## Obj-C/Swift specific 86 | *.hmap 87 | *.ipa 88 | *.dSYM.zip 89 | *.dSYM 90 | 91 | # CocoaPods 92 | # 93 | # We recommend against adding the Pods directory to your .gitignore. However 94 | # you should judge for yourself, the pros and cons are mentioned at: 95 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 96 | # 97 | # Pods/ 98 | 99 | # Carthage 100 | # 101 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 102 | # Carthage/Checkouts 103 | 104 | Carthage/Build 105 | 106 | # fastlane 107 | # 108 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 109 | # screenshots whenever they are needed. 110 | # For more information about the recommended setup visit: 111 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 112 | 113 | fastlane/report.xml 114 | fastlane/Preview.html 115 | fastlane/screenshots 116 | fastlane/test_output 117 | 118 | # Code Injection 119 | # 120 | # After new code Injection tools there's a generated folder /iOSInjectionProject 121 | # https://github.com/johnno1962/injectionforxcode 122 | 123 | iOSInjectionProject/ 124 | ### C++ template 125 | # Prerequisites 126 | *.d 127 | 128 | # Compiled Object files 129 | *.slo 130 | *.lo 131 | *.o 132 | *.obj 133 | 134 | # Precompiled Headers 135 | *.gch 136 | *.pch 137 | 138 | # Compiled Dynamic libraries 139 | *.so 140 | *.dylib 141 | *.dll 142 | 143 | # Fortran module files 144 | *.mod 145 | *.smod 146 | 147 | # Compiled Static libraries 148 | *.lai 149 | *.la 150 | *.a 151 | *.lib 152 | 153 | # Executables 154 | *.exe 155 | *.out 156 | *.app 157 | ### Python template 158 | # Byte-compiled / optimized / DLL files 159 | __pycache__/ 160 | *.py[cod] 161 | *$py.class 162 | 163 | # C extensions 164 | *.so 165 | 166 | # Distribution / packaging 167 | .Python 168 | build/ 169 | develop-eggs/ 170 | dist/ 171 | downloads/ 172 | eggs/ 173 | .eggs/ 174 | lib/ 175 | lib64/ 176 | parts/ 177 | sdist/ 178 | var/ 179 | wheels/ 180 | *.egg-info/ 181 | .installed.cfg 182 | *.egg 183 | MANIFEST 184 | 185 | # PyInstaller 186 | # Usually these files are written by a python script from a template 187 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 188 | *.manifest 189 | *.spec 190 | 191 | # Installer logs 192 | pip-log.txt 193 | pip-delete-this-directory.txt 194 | 195 | # Unit test / coverage reports 196 | htmlcov/ 197 | .tox/ 198 | .coverage 199 | .coverage.* 200 | .cache 201 | nosetests.xml 202 | coverage.xml 203 | *.cover 204 | .hypothesis/ 205 | .pytest_cache/ 206 | 207 | # Translations 208 | *.mo 209 | *.pot 210 | 211 | # Django stuff: 212 | *.log 213 | local_settings.py 214 | db.sqlite3 215 | 216 | # Flask stuff: 217 | instance/ 218 | .webassets-cache 219 | 220 | # Scrapy stuff: 221 | .scrapy 222 | 223 | # Sphinx documentation 224 | docs/_build/ 225 | 226 | # PyBuilder 227 | target/ 228 | 229 | # Jupyter Notebook 230 | .ipynb_checkpoints 231 | 232 | # pyenv 233 | .python-version 234 | 235 | # celery beat schedule file 236 | celerybeat-schedule 237 | 238 | # SageMath parsed files 239 | *.sage.py 240 | 241 | # Environments 242 | .env 243 | .venv 244 | env/ 245 | venv/ 246 | ENV/ 247 | env.bak/ 248 | venv.bak/ 249 | 250 | # Spyder project settings 251 | .spyderproject 252 | .spyproject 253 | 254 | # Rope project settings 255 | .ropeproject 256 | 257 | # mkdocs documentation 258 | /site 259 | 260 | # mypy 261 | .mypy_cache/ 262 | ### Windows template 263 | # Windows thumbnail cache files 264 | Thumbs.db 265 | ehthumbs.db 266 | ehthumbs_vista.db 267 | 268 | # Dump file 269 | *.stackdump 270 | 271 | # Folder config file 272 | [Dd]esktop.ini 273 | 274 | # Recycle Bin used on file shares 275 | $RECYCLE.BIN/ 276 | 277 | # Windows Installer files 278 | *.cab 279 | *.msi 280 | *.msm 281 | *.msp 282 | 283 | # Windows shortcuts 284 | *.lnk 285 | ### JetBrains template 286 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 287 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 288 | 289 | # User-specific stuff: 290 | .idea/**/workspace.xml 291 | .idea/**/tasks.xml 292 | .idea/dictionaries 293 | 294 | # Sensitive or high-churn files: 295 | .idea/**/dataSources/ 296 | .idea/**/dataSources.ids 297 | .idea/**/dataSources.local.xml 298 | .idea/**/sqlDataSources.xml 299 | .idea/**/dynamic.xml 300 | .idea/**/uiDesigner.xml 301 | 302 | # Gradle: 303 | .idea/**/gradle.xml 304 | .idea/**/libraries 305 | 306 | # CMake 307 | cmake-build-debug/ 308 | cmake-build-release/ 309 | 310 | # Mongo Explorer plugin: 311 | .idea/**/mongoSettings.xml 312 | 313 | ## File-based project format: 314 | *.iws 315 | 316 | ## Plugin-specific files: 317 | 318 | # IntelliJ 319 | out/ 320 | 321 | # mpeltonen/sbt-idea plugin 322 | .idea_modules/ 323 | 324 | # JIRA plugin 325 | atlassian-ide-plugin.xml 326 | 327 | # Cursive Clojure plugin 328 | .idea/replstate.xml 329 | 330 | # Crashlytics plugin (for Android Studio and IntelliJ) 331 | com_crashlytics_export_strings.xml 332 | crashlytics.properties 333 | crashlytics-build.properties 334 | fabric.properties 335 | ### Xcode template 336 | # Xcode 337 | # 338 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 339 | 340 | ## User settings 341 | xcuserdata/ 342 | 343 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 344 | *.xcscmblueprint 345 | *.xccheckout 346 | 347 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 348 | build/ 349 | DerivedData/ 350 | *.moved-aside 351 | *.pbxuser 352 | !default.pbxuser 353 | *.mode1v3 354 | !default.mode1v3 355 | *.mode2v3 356 | !default.mode2v3 357 | *.perspectivev3 358 | !default.perspectivev3 359 | ### macOS template 360 | # General 361 | .DS_Store 362 | .AppleDouble 363 | .LSOverride 364 | 365 | # Icon must end with two \r 366 | Icon 367 | 368 | # Thumbnails 369 | ._* 370 | 371 | # Files that might appear in the root of a volume 372 | .DocumentRevisions-V100 373 | .fseventsd 374 | .Spotlight-V100 375 | .TemporaryItems 376 | .Trashes 377 | .VolumeIcon.icns 378 | .com.apple.timemachine.donotpresent 379 | 380 | # Directories potentially created on remote AFP share 381 | .AppleDB 382 | .AppleDesktop 383 | Network Trash Folder 384 | Temporary Items 385 | .apdisk 386 | ### Swift template 387 | # Xcode 388 | # 389 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 390 | 391 | ## Build generated 392 | build/ 393 | DerivedData/ 394 | 395 | ## Various settings 396 | *.pbxuser 397 | !default.pbxuser 398 | *.mode1v3 399 | !default.mode1v3 400 | *.mode2v3 401 | !default.mode2v3 402 | *.perspectivev3 403 | !default.perspectivev3 404 | xcuserdata/ 405 | 406 | ## Other 407 | *.moved-aside 408 | *.xccheckout 409 | *.xcscmblueprint 410 | 411 | ## Obj-C/Swift specific 412 | *.hmap 413 | *.ipa 414 | *.dSYM.zip 415 | *.dSYM 416 | 417 | ## Playgrounds 418 | timeline.xctimeline 419 | playground.xcworkspace 420 | 421 | # Swift Package Manager 422 | # 423 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 424 | # Packages/ 425 | # Package.pins 426 | # Package.resolved 427 | .build/ 428 | 429 | # CocoaPods 430 | # 431 | # We recommend against adding the Pods directory to your .gitignore. However 432 | # you should judge for yourself, the pros and cons are mentioned at: 433 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 434 | # 435 | # Pods/ 436 | 437 | # Carthage 438 | # 439 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 440 | # Carthage/Checkouts 441 | 442 | Carthage/Build 443 | 444 | # fastlane 445 | # 446 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 447 | # screenshots whenever they are needed. 448 | # For more information about the recommended setup visit: 449 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 450 | 451 | fastlane/report.xml 452 | fastlane/Preview.html 453 | fastlane/screenshots 454 | fastlane/test_output 455 | 456 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |
4 |
5 | An opinionated Swift for TensorFlow starter project. 6 |
7 |
8 |

9 | 10 | 11 | # Overview 12 | 13 | STS is a [Docker](http://docker.com/)ized, [Swift Package Manager](https://swift.org/package-manager/) enabled starter repository for [Swift for TensorFlow](https://github.com/tensorflow/swift) projects. Now with hot-reload of Swift code and third-party packages! 14 | 15 | ### Swift for TensorFlow 16 | 17 |

18 | 19 |

20 | 21 | From the [official docs](https://github.com/tensorflow/swift): 22 | 23 | >Swift for TensorFlow is a new way to develop machine learning models. It gives you the power of [TensorFlow](https://www.tensorflow.org) directly integrated into the [Swift programming language](https://swift.org/about). 24 | 25 | #### Disclaimer 26 | 27 | > Note: Swift for TensorFlow is an early stage research project. It has been released to enable open source development and is not yet ready for general use by machine learning developers. 28 | 29 | ### Architecture 30 | 31 | Projects built with this template will have the following traits: 32 | 33 | 1. Build output is a deployable Docker image with an entrypoint to a release-built executable 34 | 2. Quick and easy [REPL](https://github.com/tensorflow/swift/blob/master/Usage.md#repl-read-eval-print-loop) access against the project's Swift for Tensorflow code and third-party libraries 35 | 3. Easily unit testable 36 | 4. Runs anywhere Docker is available with no additional setup necessary - zero conflicts with existing Swift or TensorFlow installations. 37 | 5. *Swift code is hot-reloaded on change; third-party libraries are downloaded automatically as well. See the `--live` flag.* 38 | 39 | This will enable both ease of use during the research phase and a rapid transition to a scalable training solution and beyond (production deployment). 40 | 41 | ### Docker 42 | 43 | The project is fully Dockerized via the [swift-tensorflow](https://github.com/zachgrayio/swift-tensorflow) image, meaning you don't need to worry about setting up local dependencies or conflicts with existing Xcode/Swift installations when developing Swift+TF applications unless you really want to - all build/run tasks can be accomplished from within the container. 44 | 45 | More information on the base docker image and avanced usage examples can be found in its [README](https://github.com/zachgrayio/swift-tensorflow/blob/master/README.md). 46 | 47 | * Note: The initial Docker build may take some time; Docker needs to download intermediate layers for the Ubuntu16 image if you haven't used it previously. However, subsequent builds should complete in under 10 seconds on a reasonable machine.* 48 | 49 | ### Swift Package Manager 50 | 51 | This project template is a [Swift Package Manager](https://swift.org/package-manager/) project - `Package.swift` defines the runnable application, the core library, and third-party dependencies. 52 | 53 | # Quickstart 54 | 55 | ### Prerequisites 56 | 57 | #### Install Docker CE 58 | 59 | Installation guides for macOS/Windows/Linux can be found [here](https://docs.docker.com/install/). 60 | 61 | #### Clone the `swift-tensorflow-starter` Repository 62 | 63 | ```bash 64 | git clone --depth 1 https://github.com/zachgrayio/swift-tensorflow-starter.git 65 | cd swift-tensorflow-starter 66 | ``` 67 | 68 | Optionally, you may reset `git` so you can commit and push to your own repository: 69 | 70 | ```bash 71 | rm -rf .git 72 | git init && git commit -am "initial" 73 | ``` 74 | 75 | ## The Easy Way 76 | 77 | Users on macOS and Linux can take advantage of the supplied run script for easy usage - no Docker expertise required! 78 | 79 | ### 1) Build and Run with Hot Reload enabled 80 | 81 | After cloning, you can start the project in a single command using the `sts` executable that's included: 82 | 83 | ```bash 84 | ./sts run app --build --live 85 | ``` 86 | 87 | After this, any changes you make to the project will result in the Swift code being rebuilt in the container and the executable started. You can exit with `CTRL+C`. 88 | 89 | ### 2) Add your Swift TensorFlow code 90 | 91 | * Add your Swift source files to the to `Sources/STSLibary` directory 92 | * If you'd like them to be part of the runnable application, add the appropriate calls to the `run()` method of `Application.swift`. Assuming you wire up valid code, you'll see your output. 93 | * If you'd rather just run the REPL, `CTRL-C` out of this session and run `./sts run repl --build` 94 | 95 | That's it! However, it's recommended to continue reading and learn more about the underlying Docker container. 96 | 97 | ## The Other Way 98 | 99 | The following 4 steps describe how to add your code, build, and run the project with nothing other than the Docker binary; this should be relatively accurate cross-platform. 100 | 101 | ### 1) Add your Swift TensorFlow code 102 | 103 | * Add your Swift source files to the to `Sources/STSLibary` directory 104 | * If you'd like them to be part of the runnable application, add the appropriate calls to the `run()` method of `Application.swift`. If you only want to access this code from the REPL, no further work is required now. 105 | 106 | ### 2) Build 107 | 108 | Debug: 109 | 110 | ```bash 111 | docker build -t sts-application . 112 | ``` 113 | 114 | Release: 115 | 116 | ```bash 117 | docker build --build-arg CONFIG=release -t sts-application . 118 | ``` 119 | 120 | *Note: you may tag your built container as anything you'd like; if you use a different tag, be sure to use it instead of `sts-application` in the following bash commands.* 121 | 122 | ### 3) Run Unit Tests 123 | 124 | ```bash 125 | docker run --rm --entrypoint "/usr/bin/swift" sts-application test 126 | ``` 127 | 128 | ### 4) Run 129 | 130 | Now you can either run the executable, or a REPL. 131 | 132 | #### Run the executable 133 | 134 | ```bash 135 | docker run --rm sts-application 136 | ... 137 | STS: [1.44, 0.64] 138 | ``` 139 | 140 | #### Run a REPL with access to the library 141 | 142 | ```bash 143 | docker run --rm --security-opt seccomp:unconfined -it \ 144 | --entrypoint /usr/bin/swift \ 145 | sts-application \ 146 | -I/usr/lib/swift/clang/include \ 147 | -I/usr/lib \ 148 | -L/usr/lib \ 149 | -lSTSLibrary \ 150 | -lswiftPython \ 151 | -lswiftTensorFlow 152 | ``` 153 | 154 | Now you can import anything defined in the `STSLibrary` module and interact with it. In this case, we're running the application. 155 | 156 | ``` 157 | Welcome to Swift version 4.2-dev (LLVM 04bdb56f3d, Clang b44dbbdf44). Type :help for assistance. 158 | 1> import STSLibrary 159 | 2> let app = Application() 160 | app: STSLibrary.Application = {} 161 | 3> app.run() 162 | STS: [1.44, 0.64] 163 | 4> :exit 164 | ``` 165 | 166 | ### Control Script 167 | 168 | A control script is included for extra convenience for users on macOS/Linux, but the Docker commands shown in steps 1-4 above also work on Windows. 169 | 170 | Some example commands: 171 | 172 | * `./sts run app --live` - automatically rebuild and run the application on code change; packages are updated automatically as well! 173 | * `./sts build --release`, `./sts build -r`, `./sts build -p`, `./sts build --prod` - build the image with a release executable 174 | * `./sts run repl --build --name myrepl -v` - run a REPL in a container named myrepl, mounting the current directory as a volume, building the project first 175 | * `./sts run test`, `./sts run tests --name testcontainer` - run unit tests 176 | * `./sts run xcode` - generate and opens a new xcode project 177 | * `./sts run app -b` - run the application, building the container first 178 | * `./sts run app -v` - runs an app tagged `myapp` with the current directory mounted as a volume to `/usr/src`. 179 | * `./sts run app -n mycontainer -b` - build and tag the current image `mycontainer` and then run it. 180 | 181 | NOTE: if you don't include the `-b|--build` flag to `app run` then the previously built image with that tag/name will be started. If an image with this tag is not found, one will be built. 182 | 183 | # Usage 184 | 185 | ### Writing TensorFlow Code 186 | 187 | Something to keep in mind when writing your TensorFlow code, as to avoid issues with send/receive (from the [official FAQ](https://github.com/tensorflow/swift/blob/master/FAQ.md#why-do-i-get-error-internal-error-generating-tensorflow-graph-graphgen-cannot-lower-a-sendreceive-to-the-host-yet)): 188 | 189 | >We recommend separating functions that do tensor computation from host code in your programs. Those functions should be marked as `@inline(never)` (and have `public` access, to be safe). Within those functions, tensor computation should not be interrupted by host code. This ensures that the arguments and results of the extracted tensor program will be values on the host, as expected. 190 | 191 | ### SwiftPM Project Settings 192 | 193 | By default the following names are used: 194 | 195 | * Executable: `STSApplication` 196 | * Library: `STSLibrary` 197 | * SwiftPM project: `STSProject` 198 | 199 | If desired, you can easily override these values with a simple find/replace in the root directory. The files which need changes are `Package.swift` and the `Dockerfile`, the example test classes and run scripts, and a few directory names in `Sources` and `Tests`. 200 | 201 | ### Third-party Libraries 202 | 203 | Third-party Swift libraries can be added to the `dependencies` collection in `Package.swift` and then imported for use. 204 | 205 | Example: 206 | 207 | ```swift 208 | ... 209 | dependencies: [ 210 | .package(url: "https://github.com/ReactiveX/RxSwift.git", "4.0.0" ..< "5.0.0") 211 | ], 212 | ... 213 | ``` 214 | 215 | ### System Dependencies 216 | 217 | The project's `Dockerfile` is based on Ubuntu 16, so you can simply add `RUN apt-get install -y ...` entries to fetch additional dependencies. 218 | 219 | ### Writing Unit Tests 220 | 221 | See `STSLibraryTests.testApplicationPrefix()` in `Tests/STSLibraryTests/STSLibraryTests.swift` for an example test. 222 | 223 | *Note: TensorFlow is not yet supported in Unit Tests.* 224 | 225 | ### Generate .xcodeproj 226 | 227 | If desired, users on macOS can generate a `.xcodeproj` that you can open with an IDE (Xcode, AppCode, CLion). This is optional, and the xcodeproj is ignored in `.gitignore` by default. Also note that you'll want to swap out your xctoolchain as described [here](https://github.com/tensorflow/swift/blob/master/Installation.md) if you go this route. 228 | 229 | The following command mounts a volume in the current directory and generates the project, resulting in the file being written to your host's disk. 230 | 231 | ```bash 232 | docker run --rm -v ${PWD}:/usr/src \ 233 | --entrypoint /usr/bin/swift \ 234 | sts-application \ 235 | package generate-xcodeproj 236 | open STSProject.xcodeproj 237 | ``` 238 | 239 | *Note: You can also run the `run_xcode.sh` script to generate and open the project.* 240 | 241 | ### Examples 242 | 243 | * Using RxSwift: [[View Diff](https://github.com/zachgrayio/swift-tensorflow-starter/commit/cde51c28c608d9e08f460944eae836881fef47d9)] 244 | * Serving TensorFlow models with HTTP: coming soon. 245 | * Training TensorFlow models over HTTP: coming soon. 246 | 247 | ### Leaving the Container 248 | 249 | If you wish to run `swift build` and `swift run` on your project outside of the docker conainer, this is possible. 250 | 251 | * On Linux: you've got this. 252 | * On macOS: ensure you've [installed](https://github.com/tensorflow/swift/blob/master/Installation.md) the Swift for TensorFlow toolchain, and then use the following commands from within the project directory: 253 | 254 | ```bash 255 | export PATH=/Library/Developer/Toolchains/swift-latest/usr/bin:"${PATH}" 256 | swift run -Xswiftc -O 257 | ``` 258 | 259 | # License 260 | 261 | This project is [MIT Licensed](https://github.com/zachgrayio/swift-tensorflow-starter/blob/master/LICENSE). 262 | --------------------------------------------------------------------------------