%install-location $cwd/swift-install
%install '.package(path: "$cwd/FastaiNotebook_02_fully_connected")' FastaiNotebook_02_fully_connected
Installing packages: .package(path: "/home/jupyter/notebooks/swift/FastaiNotebook_02_fully_connected") FastaiNotebook_02_fully_connected With SwiftPM flags: [] Working in: /tmp/tmpf7bhzuzj/swift-install [1/5] Compiling FastaiNotebook_02_fully_connected 01_matmul.swift [2/5] Compiling FastaiNotebook_02_fully_connected 02_fully_connected.swift [3/5] Compiling FastaiNotebook_02_fully_connected 00_load_data.swift [4/5] Compiling FastaiNotebook_02_fully_connected 01a_fastai_layers.swift [5/6] Merging module FastaiNotebook_02_fully_connected [6/7] Compiling jupyterInstalledPackages jupyterInstalledPackages.swift [7/8] Merging module jupyterInstalledPackages [8/8] Linking libjupyterInstalledPackages.so Initializing Swift... Installation complete!
//export
import Foundation
import TensorFlow
import Path
import FastaiNotebook_02_fully_connected
var (xTrain, yTrain, xValid, yValid) = loadMNIST(path: Path.home/".fastai"/"data"/"mnist_tst")
let (trainMean, trainStd) = (xTrain.mean(), xTrain.standardDeviation())
xTrain = normalize(xTrain, mean: trainMean, std: trainStd)
xValid = normalize(xValid, mean: trainMean, std: trainStd)
xTrain = xTrain.reshaped(to: [xTrain.shape[0], 28, 28, 1])
xValid = xValid.reshaped(to: [xValid.shape[0], 28, 28, 1])
print(xTrain.shape, xValid.shape)
[60000, 28, 28, 1] [10000, 28, 28, 1]
let images = xTrain.shape[0]
let classes = xValid.max() + 1
let channels = 32
var layer1 = FAConv2D<Float>(filterShape: (5, 5, 1, channels)) //Conv2D(1, nh, 5)
let x = xValid[0..<100]
x.shape
▿ [100, 28, 28, 1] ▿ dimensions : 4 elements - 0 : 100 - 1 : 28 - 2 : 28 - 3 : 1
extension Tensor where Scalar: TensorFlowFloatingPoint {
func stats() -> (mean: Tensor, std: Tensor) {
return (mean: mean(), std: standardDeviation())
}
}
(filter: layer1.filter.stats(), bias: layer1.bias.stats())
▿ 2 elements ▿ filter : 2 elements - mean : -0.0027464556 - std : 0.19631124 ▿ bias : 2 elements - mean : 0.0 - std : 0.0
withDevice(.cpu){
let result = layer1(x)
}
let result = layer1(x)
result.stats()
▿ 2 elements - mean : 0.00048066635 - std : 0.9185965
This is in 1a now so this code is disabled from here:
var rng = PhiloxRandomNumberGenerator.global
extension Tensor where Scalar: TensorFlowFloatingPoint {
init(kaimingNormal shape: TensorShape, negativeSlope: Double = 1.0) {
// Assumes Leaky ReLU nonlinearity
let gain = Scalar(sqrt(2.0 / (1.0 + pow(negativeSlope, 2))))
let spatialDimCount = shape.count - 2
let receptiveField = shape[0..<spatialDimCount].contiguousSize
let fanIn = shape[shape.count - 2] * receptiveField
self.init(randomNormal: shape,
stddev: gain / sqrt(Scalar(fanIn)),
generator: &rng
)
}
}
layer1.filter = Tensor(kaimingNormal: layer1.filter.shape, negativeSlope: 1.0)
layer1(x).stats()
▿ 2 elements - mean : -0.002676351 - std : 0.8549339
// export
func leakyRelu<T: TensorFlowFloatingPoint>(
_ x: Tensor<T>,
negativeSlope: Double = 0.0
) -> Tensor<T> {
return max(0, x) + T(negativeSlope) * min(0, x)
}
layer1.filter = Tensor(kaimingNormal: layer1.filter.shape, negativeSlope: 0.0)
leakyRelu(layer1(x)).stats()
▿ 2 elements - mean : 0.40438622 - std : 0.8042958
var layer1 = FAConv2D<Float>(filterShape: (5, 5, 1, channels)) //Conv2D(1, nh, 5)
leakyRelu(layer1(x)).stats()
▿ 2 elements - mean : 0.3136924 - std : 0.6081149
layer1.filter.shape
▿ [5, 5, 1, 32] ▿ dimensions : 4 elements - 0 : 5 - 1 : 5 - 2 : 1 - 3 : 32
let spatialDimCount = layer1.filter.rank - 2
let receptiveField = layer1.filter.shape[0..<spatialDimCount].contiguousSize
receptiveField
25
let filtersIn = layer1.filter.shape[2]
let filtersOut = layer1.filter.shape[3]
print(filtersIn, filtersOut)
1 32
let fanIn = filtersIn * receptiveField
let fanOut = filtersOut * receptiveField
print(fanIn, fanOut)
25 800
func gain(_ negativeSlope: Double) -> Double {
return sqrt(2.0 / (1.0 + pow(negativeSlope, 2.0)))
}
(gain(1.0), gain(0.0), gain(0.01), gain(0.1), gain(sqrt(5.0)))
▿ 5 elements - .0 : 1.0 - .1 : 1.4142135623730951 - .2 : 1.4141428569978354 - .3 : 1.4071950894605838 - .4 : 0.5773502691896257
(2 * Tensor<Float>(randomUniform: [10000]) - 1).standardDeviation()
0.5790101
1.0 / sqrt(3.0)
0.5773502691896258
//export
extension Tensor where Scalar: TensorFlowFloatingPoint {
init(kaimingUniform shape: TensorShape, negativeSlope: Double = 1.0) {
// Assumes Leaky ReLU nonlinearity
let gain = Scalar.init(TensorFlow.sqrt(2.0 / (1.0 + TensorFlow.pow(negativeSlope, 2))))
let spatialDimCount = shape.count - 2
let receptiveField = shape[0..<spatialDimCount].contiguousSize
let fanIn = shape[shape.count - 2] * receptiveField
let bound = TensorFlow.sqrt(Scalar(3.0)) * gain / TensorFlow.sqrt(Scalar(fanIn))
self = bound * (2 * Tensor(randomUniform: shape, generator: &PhiloxRandomNumberGenerator.global) - 1)
}
}
layer1.filter = Tensor(kaimingUniform: layer1.filter.shape, negativeSlope: 0.0)
leakyRelu(layer1(x)).stats()
▿ 2 elements - mean : 0.497556 - std : 1.0267977
layer1.filter = Tensor(kaimingUniform: layer1.filter.shape, negativeSlope: sqrt(5.0))
leakyRelu(layer1(x)).stats()
▿ 2 elements - mean : 0.18083005 - std : 0.34926173
public struct Model: Layer {
public var conv1 = FAConv2D<Float>(
filterShape: (5, 5, 1, 8), strides: (2, 2), padding: .same, activation: relu
)
public var conv2 = FAConv2D<Float>(
filterShape: (3, 3, 8, 16), strides: (2, 2), padding: .same, activation: relu
)
public var conv3 = FAConv2D<Float>(
filterShape: (3, 3, 16, 32), strides: (2, 2), padding: .same, activation: relu
)
public var conv4 = FAConv2D<Float>(
filterShape: (3, 3, 32, 1), strides: (2, 2), padding: .valid
)
public var flatten = Flatten<Float>()
@differentiable
public func callAsFunction(_ input: Tensor<Float>) -> Tensor<Float> {
return input.sequenced(through: conv1, conv2, conv3, conv4, flatten)
}
}
let y = Tensor<Float>(yValid[0..<100])
var model = Model()
let prediction = model(x)
prediction.stats()
▿ 2 elements - mean : 0.1729667 - std : 0.12520388
let gradients = gradient(at: model) { model in
meanSquaredError(predicted: model(x), expected: y)
}
gradients.conv1.filter.stats()
▿ 2 elements - mean : -0.056964096 - std : 0.2776651
for keyPath in [\Model.conv1, \Model.conv2, \Model.conv3, \Model.conv4] {
model[keyPath: keyPath].filter = Tensor(kaimingUniform: model[keyPath: keyPath].filter.shape)
}
let prediction = model(x)
prediction.stats()
▿ 2 elements - mean : -0.37689942 - std : 0.32016334
let gradients = gradient(at: model) { model in
meanSquaredError(predicted: model(x), expected: y)
}
gradients.conv1.filter.stats()
▿ 2 elements - mean : 0.100767136 - std : 0.54216325
import NotebookExport
let exporter = NotebookExport(Path.cwd/"02a_why_sqrt5.ipynb")
print(exporter.export(usingPrefix: "FastaiNotebook_"))
success