Gentle Intro to Swift for TensorFlow

Hey, this is my first post. I created this gentle intro to Swift in Goolge Colab . Let me know if we can build on it and make it better.

https://colab.research.google.com/github/zaidalyafeai/Notebooks/blob/master/TF_Swift.ipynb

13 Likes

Great start! A couple of things I noticed:

  • Generally struct is used more often than class - although perhaps show both
  • protocol and extension are used frequently in swift including the lesson notebooks, so should be covered
  • map, filter, and reduce are important to mention; at the same time you can mention closures, including the neat trailing closure syntax
  • You should use the latest nightly of s4tf and jupyter notebook since a lot has changed! :slight_smile:
2 Likes

They have steps to install nightly versions in Colab, but the procedure needs to be repeated after the runtime is recycled :slight_smile:
What’s interesting, using similar approach it should be possible to register any custom jupyter kernel (e.g. Julia) in Colab, which is pretty cool! I thought it’s more restrictive.

1 Like

@jeremy the current version in Colab is Swift version 5.0-dev. I am not sure what is the latest version.

The issue isn’t swift, it’s s4tf. We’re updating the nightly every night at the moment. Last night’s is the 1st that runs all the notebooks successfully! :slight_smile:

2 Likes

Added structs, closures, operator overloading, protocols and extensions.

3 Likes

I created a new notebook for training MNIST

https://colab.research.google.com/github/zaidalyafeai/Notebooks/blob/master/TF_Swift.ipynb

1 Like

Nice notebook! :slightly_smiling_face:

In case you haven’t seen it, here’s “A Swift Tour” in notebook form. It’s originally from the “Swift Programming Language” Book and covers Swift but not machine learning.

1 Like

@dan-zheng, yes I am aware of that notebook. I included similar examples from there. I tried to make the notebook light with minimum details to introduce the bits needed for machine learning.

1 Like

@dan-zheng, btw, any idea how to run bash commands in colab when the kernel is Swift. Both % and ! don’t work.

Good question! We don’t have a %run directive for running arbitrary commands yet.

That would be certainly a nice feature for swift-jupyter - we discussed it before but no one is working on it.

cc @marcrasi who leads swift-jupyter: how do you feel about adding %run? It could be a nice starter issue. :slightly_smiling_face:

In the meantime, you could use Foundation (example from Stack Overflow) or Python to run commands.

import Foundation

@discardableResult
func shell(_ args: String...) -> Int32 {
    let task = Process()
    task.launchPath = "/usr/bin/env"
    task.arguments = args
    task.launch()
    task.waitUntilExit()
    return task.terminationStatus
}

shell("ls", "-alh")
import Python
let subprocess = Python.import("subprocess")
...
1 Like

I actually go around that by creating two notebooks one with python(running commands) and the other with swift :upside_down_face: because they operate on the same environment. Happy to work on it if it is straight forward.

I think it should be implemented as a Swift library instead of as a part of the kernel, because you can get quite nice syntax as a Swift library (e.g. the "/bin/ls".shell("/") implemented in https://github.com/fastai/fastai_docs/blob/master/dev_swift/00_load_data.ipynb is a quite nice start, I think), and it keeps complexity out of the kernel implementation.

Yeah, creating a Swift library with some nice syntax would be pretty straightforward! Write some function(s) that execute commands using Foundation. You might want to figure out some way to get a shell to parse the command, so that users can just write a single shell command instead of having to write the exact binary path and manually split out the arguments. Then distribute them as a SwiftPM package. Then anyone can use this in their notebook using an %install directive.

(%install doesn’t work in Colab yet, but a new version of the kernel that supports %install should be released in Colab around Tuesday)

1 Like

@marcrasi I don’t quite get why it is better to create a library rather than enabling it directly in the kernel (complex ? )
I find it a bit not intuitive to make functions calls for simple commands like !wget, !tar , etc …

It’s possible to define functions that make it look almost like !wget, !tar, etc:

prefix func ! (_ command: String) {
  print("Executing command: \(command)")
}

!"wget foo"
// prints "Executing command: wget foo"

Since it’s possible to get so close to !wget I think there’s not enough extra value in getting all the way to !wget to balance the extra complexity that it would add to the kernel.

Here’s some more detail about why I want to avoid extra complexity in the kernel:

  • Every non-Swift directive that we put in Jupyter cells makes “Jupyter Swift” diverge more from “Real Swift”, which makes it harder to translate from one to the other, and which may make it hard for beginners to understand what Swift is.
  • The implementation of existing directives (%install, %include, etc) is pretty complicated, with some tricky bug-prone logic required to parse and execute them in exactly the right order, and to show good error messages when something goes wrong. More directives would make it worse. (In fact, I’m pretty interested in removing %include, which might be possible now that we have %install).
  • One day I might want to migrate swift-jupyter from python to C++ (using Xeus), and minimzing the amount of Python code in the kernel will make this easier.
6 Likes

Thanks a lot for the details. I was also thinking of using the prefix notation. I will try to work on that asap.

1 Like

Some time ago I’ve made simple shell library for myself, feel free to fork and hack on it :slight_smile:
btw, %install works in colab if you update to nightly as described here.

Upd: I liked prefix bang function so much and added it too, thanks @marcrasi :slight_smile:

3 Likes

That will be a great starting example, Thanks!

So, a prefix bang definition would look like this, right?

import Python
let shell = Python.import("subprocess").getoutput

prefix func ! (_ command: String) {
  print(shell(command))
}

!"ls -al"