Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 24 additions & 7 deletions Handwriting.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -151,19 +151,18 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0830;
LastUpgradeCheck = 0830;
LastUpgradeCheck = 1130;
ORGANIZATIONNAME = "Swift AI";
TargetAttributes = {
F082483E1EB82EC200EC951B = {
CreatedOnToolsVersion = 8.3.2;
DevelopmentTeam = 5ZHKK24J8V;
ProvisioningStyle = Automatic;
};
};
};
buildConfigurationList = F082483A1EB82EC200EC951B /* Build configuration list for PBXProject "Handwriting" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Expand Down Expand Up @@ -232,21 +231,30 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = 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_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
Expand Down Expand Up @@ -282,21 +290,30 @@
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = 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_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
Expand Down Expand Up @@ -325,27 +342,27 @@
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = 5ZHKK24J8V;
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = Handwriting/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "swift-ai.Handwriting";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
SWIFT_VERSION = 5.0;
};
name = Debug;
};
F08248531EB82EC300EC951B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = 5ZHKK24J8V;
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = Handwriting/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 10.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "swift-ai.Handwriting";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 3.0;
SWIFT_VERSION = 5.0;
};
name = Release;
};
Expand Down
2 changes: 1 addition & 1 deletion Handwriting/Activation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import Accelerate

public extension NeuralNet {

public enum ActivationFunction {
enum ActivationFunction {

// MARK: Hidden Activation Functions
// These functions may be used for all hidden layers of a `NeuralNet`.
Expand Down
2 changes: 1 addition & 1 deletion Handwriting/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?


func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

let mainViewController = MainViewController()
self.window = UIWindow(frame: UIScreen.main.bounds)
Expand Down
2 changes: 1 addition & 1 deletion Handwriting/Dataset.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import Foundation
public extension NeuralNet {

/// A complete dataset for training a neural network, including training sets and validation sets.
public struct Dataset {
struct Dataset {

/// Errors that may be thrown by `Dataset`.
public enum Error: Swift.Error {
Expand Down
4 changes: 2 additions & 2 deletions Handwriting/Error.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import Foundation
public extension NeuralNet {

/// Functions for calculating error on a validation set.
public enum ErrorFunction {
enum ErrorFunction {
/// Mean squared error function.
/// 1 / n * ∑( (a[i] - t[i]) * (a[i] - t[i]) )
case meanSquared
Expand Down Expand Up @@ -73,7 +73,7 @@ public extension NeuralNet {
let realSet = real[start..<(start + cols)]
let labelSet = target[start..<(start + cols)]
// Compare max values of outputs and labels
if realSet.index(of: realSet.max()!) != labelSet.index(of: labelSet.max()!) {
if realSet.firstIndex(of: realSet.max()!) != labelSet.firstIndex(of: labelSet.max()!) {
// Incorrect answer; increment counter
incorrect += 1
}
Expand Down
6 changes: 4 additions & 2 deletions Handwriting/MainView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,15 @@ class MainView: UIView {
outputTitleLabel.textAlignment = .center

// Output
outputLabel.font = UIFont.systemFont(ofSize: 100, weight: UIFontWeightLight)
outputLabel.font = UIFont.systemFont(ofSize: 100, weight: UIFont.Weight.light)
outputLabel.textColor = UIColor.black
outputLabel.textAlignment = .center

// Confidence
confidenceLabel.font = UIFont.systemFont(ofSize: 15)
confidenceLabel.textAlignment = .center

confidenceLabel.textColor = UIColor.black

}

/// Add subviews and set constraints.
Expand Down
2 changes: 1 addition & 1 deletion Handwriting/MainViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ extension MainViewController {
/// Extracts the output integer and confidence from the given neural network output.
private func label(from output: [Float]) -> (label: Int, confidence: Float)? {
guard let max = output.max() else { return nil }
return (output.index(of: max)!, max)
return (output.firstIndex(of: max)!, max)
}

/// Displays the given label and confidence in the output view.
Expand Down
18 changes: 9 additions & 9 deletions Handwriting/NeuralNet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,15 +107,15 @@ public extension NeuralNet {
/// This change may safely be performed at any time.
///
/// - Parameter weights: A 2D array of weights corresponding to each layer in the network.
public func setWeights(_ weights: [[Float]]) throws {
func setWeights(_ weights: [[Float]]) throws {
// TODO: ensure valid number of weights

// Reset all weights in the network
cache.layerWeights = weights
}

/// Returns an array of the network's current weights for each layer.
public func allWeights() -> [[Float]] {
func allWeights() -> [[Float]] {
return cache.layerWeights
}

Expand Down Expand Up @@ -168,7 +168,7 @@ public extension NeuralNet {
/// - Returns: The full batch of outputs corresponding to the provided inputs.
/// - Throws: An error if the number of batches or inputs per set are incorrect.
@discardableResult
public func infer(_ inputs: [[Float]]) throws -> [[Float]] {
func infer(_ inputs: [[Float]]) throws -> [[Float]] {
// Make sure the correct number of batches was provided
guard inputs.count == batchSize else {
throw Error.inference("Incorrect number of input sets provided: \(inputs.count). Expected: \(batchSize). The number of input sets must exactly match the network's batch size.")
Expand Down Expand Up @@ -206,7 +206,7 @@ public extension NeuralNet {
/// - Throws: An error if an incorrect number of inputs is provided.
/// - IMPORTANT: The number of inputs provided must exactly match the network's number of inputs (defined in its `Structure`).
@discardableResult
public func infer(_ inputs: [Float]) throws -> [Float] {
func infer(_ inputs: [Float]) throws -> [Float] {
// Ensure that the correct number of inputs is given
guard inputs.count == layerNodeCounts[0] * batchSize else {
throw Error.inference("Incorrect number of inputs provided: \(inputs.count). Expected: \(layerNodeCounts[0] * batchSize). The number of total inputs must exactly match the network's input size times its batch size.")
Expand Down Expand Up @@ -270,7 +270,7 @@ public extension NeuralNet {
/// - Parameter labels: An array of label sets corresponding to the most recent minibatch applied for inference.
/// - IMPORTANT: The labels must be given in the same order as the corresponding inputs that were provided during inference.
/// - Throws: An error if a data inconsistency is detected.
public func backpropagate(_ labels: [[Float]]) throws {
func backpropagate(_ labels: [[Float]]) throws {
// Ensure the correct number of sets is given
guard labels.count == batchSize else {
throw Error.train("Incorrect number of label sets provided: \(labels.count). Expected: \(batchSize). The number of sets in a minibatch must exactly match the network's batch size.")
Expand All @@ -297,7 +297,7 @@ public extension NeuralNet {
/// - Parameter labels: A single set of labels corresponding to the most recent inference cycle,
/// or a full minibatch of labels serialized into a single array.
/// - Throws: An error if a data inconsistency is detected.
public func backpropagate(_ labels: [Float]) throws {
func backpropagate(_ labels: [Float]) throws {
// Ensure that the correct number of labels was given
guard labels.count == layerNodeCounts[numLayers - 1] * batchSize else {
throw Error.train("Incorrect number of labels provided: \(labels.count). Expected: \(layerNodeCounts[numLayers - 1] * batchSize). The total number of labels must exactly match the network's output size times its batch size.")
Expand Down Expand Up @@ -477,9 +477,9 @@ public extension NeuralNet {
/// or perform any other logic desired.
/// - Returns: The total number of training epochs performed, and the final validation error.
/// - Throws: An error if invalid data is provided. Checks are performed in advance to avoid problems during the training cycle.
public func train(_ data: Dataset, maxEpochs: Int,
errorThreshold: Float, errorFunction: ErrorFunction,
epochCallback: ((_ epoch: Int, _ error: Float) -> Bool)?) throws -> (epochs: Int, error: Float) {
func train(_ data: Dataset, maxEpochs: Int,
errorThreshold: Float, errorFunction: ErrorFunction,
epochCallback: ((_ epoch: Int, _ error: Float) -> Bool)?) throws -> (epochs: Int, error: Float) {
// Ensure valid error threshold
guard errorThreshold > 0 else {
throw Error.train("Training error threshold must be greater than zero.")
Expand Down
4 changes: 2 additions & 2 deletions Handwriting/Storage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public extension NeuralNet {


/// Attempts to initialize a `NeuralNet` from a file stored at the given URL.
public convenience init(url: URL) throws {
convenience init(url: URL) throws {
// Read data
let data = try Data(contentsOf: url)
// Extract top-level object from data
Expand Down Expand Up @@ -96,7 +96,7 @@ public extension NeuralNet {


/// Persists the `NeuralNet` to a file at the given URL.
public func save(to url: URL) throws {
func save(to url: URL) throws {
// Create top-level JSON object
let json: [String : Any] = [
NeuralNet.layerNodeCountsKey : layerNodeCounts,
Expand Down
2 changes: 1 addition & 1 deletion Handwriting/Structure.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
public extension NeuralNet {

/// A container for the basic structure of a `NeuralNet`.
public struct Structure {
struct Structure {

/// Possible `Structure` errors.
public enum Error: Swift.Error {
Expand Down