Skip to content

Instantly share code, notes, and snippets.

@steverichey
Created March 17, 2016 03:21
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save steverichey/592073bcda918b47a4b5 to your computer and use it in GitHub Desktop.
Save steverichey/592073bcda918b47a4b5 to your computer and use it in GitHub Desktop.
NeuralSwift - A very simple neural network written in Swift.
// see http://lumiverse.io/series/neural-networks-demystified
import Foundation
let startTime = NSDate()
defer {
let endTime = NSDate()
print("Total time \(endTime.timeIntervalSinceDate(startTime))")
}
extension Array {
subscript (safe index: Int) -> Element? {
return indices ~= index ? self[index] : nil
}
}
extension _ArrayType where Generator.Element == Double {
var sum: Double {
return reduce(0) { $0 + $1 }
}
}
func randd() -> Double {
return Double(rand()) / Double(RAND_MAX)
}
func rand(width: Int, _ height: Int) -> Matrix {
var result = Matrix(width: width, height: height)
result.fill { randd() }
return result
}
typealias Matrix = [[Double]]
// We can't do an extension for Matrix any other way
extension _ArrayType where Generator.Element == [Double] {
init(width: Int, height: Int, value: Double = 0) {
let row = [Double](count: width, repeatedValue: value)
self.init(count: height, repeatedValue: row)
}
var width: Int {
return self[0].count
}
var height: Int {
return count
}
var rows: Self {
return self
}
var columns: Matrix {
return transpose()
}
var sum: Double {
return reduce(0) { $0 + $1.sum}
}
mutating func fill(withMethod method: () -> Double) {
for x in 0..<width {
for y in 0..<height {
self[y][x] = method()
}
}
}
func transpose() -> Matrix {
var result = Matrix(width: height, height: width)
for x in 0..<width {
for y in 0..<height {
result[x][y] = self[y][x]
}
}
return result
}
mutating func set(index index: Int, toValue value: Double) {
var x = index
var y = 0
while (x >= width) {
x -= width
y += 1
}
self[y][x] = value
}
}
func exp(value: [Double]) -> [Double] {
return value.map { exp($0) }
}
func exp(value: Matrix) -> Matrix {
return value.map { exp($0) }
}
prefix func - (value: [Double]) -> [Double] {
return value.map { -$0 }
}
prefix func - (value: Matrix) -> Matrix {
return value.map { -$0 }
}
func + (lhs: Double, rhs: [Double]) -> [Double] {
return rhs.map { lhs + $0 }
}
func + (lhs: Double, rhs: Matrix) -> Matrix {
return rhs.map { lhs + $0 }
}
func * (lhs: Double, rhs: [Double]) -> [Double] {
return rhs.map { lhs * $0 }
}
func * (lhs: Double, rhs: Matrix) -> Matrix {
return rhs.map { lhs * $0 }
}
func / (lhs: Double, rhs: [Double]) -> [Double] {
return rhs.map { lhs / $0 }
}
func / (lhs: Double, rhs: Matrix) -> Matrix {
return rhs.map { lhs / $0 }
}
func sigmoid(z: Double) -> Double {
return 1.0 / (1.0 + exp(-z))
}
func sigmoid(z: [Double]) -> [Double] {
return 1.0 / (1.0 + exp(-z))
}
func sigmoid(z: Matrix) -> Matrix {
return 1.0 / (1.0 + exp(-z))
}
/**
Requires that # of lhs columns equal # of rhs rows.
*/
func * (lhs: Matrix, rhs: Matrix) -> Matrix {
assert(lhs.columns.count == rhs.rows.count)
let width = lhs.rows.count
let height = rhs.columns.count
var result = Matrix(width: width, height: height)
var index = 0
for row in lhs.rows {
for column in rhs.columns {
var total = 0.0
for (index, lhsElement) in row.enumerate() {
total += lhsElement * column[index]
}
result.set(index: index, toValue: total)
index++
}
}
return result
}
/**
Creates a (very dumb) neural network with no training, but with forward propagation.
*/
class NeuralNetwork {
/**
The number of neurons in the input layer.
*/
let inputLayerSize: Int
/**
The number of neurons in the hidden layer.
Assumes a single hidden layer.
*/
let hiddenLayerSize: Int
/**
The number of neurons in the output layer.
*/
let outputLayerSize: Int
/**
First-layer weights.
*/
var w1: Matrix
/**
Second-layer weights.
*/
var w2: Matrix
/**
The activity of our first layer.
*/
var z2: Matrix = []
/**
The activity of our second layer.
*/
var a2: Matrix = []
/**
The activity of our third layer.
*/
var z3: Matrix = []
init(inputLayerSize: Int, outputLayerSize: Int, hiddenLayerSize: Int) {
self.inputLayerSize = inputLayerSize
self.outputLayerSize = outputLayerSize
self.hiddenLayerSize = hiddenLayerSize
w1 = rand(hiddenLayerSize, inputLayerSize)
w2 = rand(outputLayerSize, hiddenLayerSize)
}
func forward(x: Matrix) -> Matrix {
// Propagate inputs through first layer
z2 = x * w1
// Apply activation function
a2 = sigmoid(z2)
// Propagate values through third layer
z3 = a2 * w2
// Apply activation function
return sigmoid(z3)
}
}
let inputX: Matrix = [[3, 5], [5, 1], [10, 2]]
let inputY: Matrix = [[0.75], [0.82], [0.93]]
let network = NeuralNetwork(inputLayerSize: 2, outputLayerSize: 1, hiddenLayerSize: 3)
let yHat = network.forward(inputX)
print("y is \(inputY)")
print("yHat is \(yHat)")
@mklarmann
Copy link

you made an error. it should be in row 153
let height = lhs.rows.count
let width = rhs.columns.count

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment