diff --git a/CHANGELOG.md b/CHANGELOG.md index 24fa326..c334c52 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +# 0.4.4 + +- Update SDK version from `2.12.0` to `2.17.0`. +- Updated project description to make it more accurate in describing what + `synadart` actually is. + # 0.4.3 - Bumped version of `sprint` from `1.0.2+3` to `1.0.3`. diff --git a/example/example.dart b/example/example.dart index dcf8a26..4228de1 100644 --- a/example/example.dart +++ b/example/example.dart @@ -2,33 +2,36 @@ import 'package:synadart/src/layers/core/dense.dart'; import 'package:synadart/synadart.dart'; void main() { - final network = Sequential(learningRate: 0.2, layers: [ - Dense( - size: 15, - activation: ActivationAlgorithm.sigmoid, - ), - Dense( - size: 5, - activation: ActivationAlgorithm.sigmoid, - ), - Dense( - size: 1, - activation: ActivationAlgorithm.sigmoid, - ) - ]); + final network = Sequential( + learningRate: 0.2, + layers: [ + Dense( + size: 15, + activation: ActivationAlgorithm.sigmoid, + ), + Dense( + size: 5, + activation: ActivationAlgorithm.sigmoid, + ), + Dense( + size: 1, + activation: ActivationAlgorithm.sigmoid, + ) + ], + ); // We are expecting to get the number '5'. final expected = [ - [0.01], - [0.01], - [0.01], - [0.01], - [0.01], - [0.99], - [0.01], - [0.01], - [0.01], - [0.01], + [0.01], // 0 + [0.01], // 1 + [0.01], // 2 + [0.01], // 3 + [0.01], // 4 + [0.99], // 5 + [0.01], // 6 + [0.01], // 7 + [0.01], // 8 + [0.01], // 9 ]; // Training data contains different number patterns. @@ -38,8 +41,7 @@ void main() { '111001111100111'.split('').map(double.parse).toList(), '111001111001111'.split('').map(double.parse).toList(), '101101111001001'.split('').map(double.parse).toList(), - // This is the number 5 - '111100111001111'.split('').map(double.parse).toList(), + '111100111001111'.split('').map(double.parse).toList(), // 5 '111100111101111'.split('').map(double.parse).toList(), '111001001001001'.split('').map(double.parse).toList(), '111101111101111'.split('').map(double.parse).toList(), @@ -60,7 +62,7 @@ void main() { final numberFive = trainingData[5]; // Train the network using the training and expected data. - network.train(inputs: trainingData, expected: expected, iterations: 5000); + network.train(inputs: trainingData, expected: expected, iterations: 20000); print('Confidence in recognising a 5: ${network.process(numberFive)}'); for (final test in testData) { diff --git a/lib/src/activation.dart b/lib/src/activation.dart index 1b46af5..2626a32 100644 --- a/lib/src/activation.dart +++ b/lib/src/activation.dart @@ -28,14 +28,14 @@ const algorithms = >{ ActivationFunction resolveActivationAlgorithm( ActivationAlgorithm activationAlgorithm, ) => - (weightedSum) => algorithms[activationAlgorithm]![0](weightedSum()); + (weightedSum) => algorithms[activationAlgorithm]!.first(weightedSum()); /// Resolves an `ActivationAlgorithm` to the derivative of the mathematical /// function in the form of an `ActivationFunction` ActivationFunction resolveActivationDerivative( ActivationAlgorithm activationAlgorithm, ) => - (weightedSum) => algorithms[activationAlgorithm]![1](weightedSum()); + (weightedSum) => algorithms[activationAlgorithm]!.last(weightedSum()); /// Shrinks the range of values to inbetween 0 and 1 using exponentials. Results /// can be driven into saturation, which makes the sigmoid function unsuited for diff --git a/lib/src/layers/core/dense.dart b/lib/src/layers/core/dense.dart index db3bccf..8a00b38 100644 --- a/lib/src/layers/core/dense.dart +++ b/lib/src/layers/core/dense.dart @@ -6,7 +6,7 @@ import 'package:synadart/src/layers/layer.dart'; class Dense extends Layer { /// Construct a dense layer using the [activation] algorithm and [size]. Dense({ - required int size, - required ActivationAlgorithm activation, - }) : super(size: size, activation: activation); + required super.size, + required super.activation, + }); } diff --git a/lib/src/layers/layer.dart b/lib/src/layers/layer.dart index 28e823f..a2c80de 100644 --- a/lib/src/layers/layer.dart +++ b/lib/src/layers/layer.dart @@ -60,14 +60,16 @@ class Layer { }) { isInput = parentLayerSize == 0; - neurons.addAll(Iterable.generate( - size, - (_) => Neuron( - activationAlgorithm: activation, - parentLayerSize: parentLayerSize, - learningRate: learningRate, + neurons.addAll( + Iterable.generate( + size, + (_) => Neuron( + activationAlgorithm: activation, + parentLayerSize: parentLayerSize, + learningRate: learningRate, + ), ), - )); + ); } /// Accept a single input or multiple [inputs] by assigning them sequentially diff --git a/lib/src/layers/recurrent/lstm.dart b/lib/src/layers/recurrent/lstm.dart index 0033dd9..be7cb42 100644 --- a/lib/src/layers/recurrent/lstm.dart +++ b/lib/src/layers/recurrent/lstm.dart @@ -22,16 +22,10 @@ class LSTM extends Layer { /// [recurrenceActivation] - Algorithm used to activate recurrence /// connections. LSTM({ - required int size, - required ActivationAlgorithm activation, + required super.size, + required super.activation, required ActivationAlgorithm recurrenceActivation, - }) : super( - size: size, - activation: activation, - ) { - this.recurrenceActivation = - resolveActivationAlgorithm(recurrenceActivation); - } + }) : recurrenceActivation = resolveActivationAlgorithm(recurrenceActivation); /// Obtain the output by applying the recurrent memory algorithm. @override diff --git a/lib/src/networks/network.dart b/lib/src/networks/network.dart index 6a9af20..92aa474 100644 --- a/lib/src/networks/network.dart +++ b/lib/src/networks/network.dart @@ -51,8 +51,9 @@ class Network { /// Adds a `Layer` to this `Network`. void addLayer(Layer layer) { layer.initialise( - parentLayerSize: layers.isEmpty ? 0 : layers[layers.length - 1].size, - learningRate: learningRate); + parentLayerSize: layers.isEmpty ? 0 : layers.last.size, + learningRate: learningRate, + ); layers.add(layer); diff --git a/lib/src/networks/sequential.dart b/lib/src/networks/sequential.dart index 9745dab..763360c 100644 --- a/lib/src/networks/sequential.dart +++ b/lib/src/networks/sequential.dart @@ -1,4 +1,3 @@ -import 'package:synadart/src/layers/layer.dart'; import 'package:synadart/src/networks/network.dart'; import 'package:synadart/src/networks/training/backpropagation.dart'; @@ -7,7 +6,7 @@ import 'package:synadart/src/networks/training/backpropagation.dart'; class Sequential extends Network with Backpropagation { /// Creates a `Sequential` model network. Sequential({ - required double learningRate, - List? layers, - }) : super(learningRate: learningRate, layers: layers); + required super.learningRate, + super.layers, + }); } diff --git a/lib/src/networks/training/backpropagation.dart b/lib/src/networks/training/backpropagation.dart index b300ff6..24f3317 100644 --- a/lib/src/networks/training/backpropagation.dart +++ b/lib/src/networks/training/backpropagation.dart @@ -42,7 +42,8 @@ mixin Backpropagation on Network { if (inputs.length != expected.length) { log.severe( - 'Inputs and expected result lists must be of the same length.'); + 'Inputs and expected result lists must be of the same length.', + ); return; } @@ -66,14 +67,19 @@ mixin Backpropagation on Network { for (var iteration = 0; iteration < iterations; iteration++) { stopwatch.start(); + for (var index = 0; index < inputs.length; index++) { propagateBackwards(inputs[index], expected[index]); } + stopwatch.stop(); + if (iteration % 500 == 0) { log.info( - 'Iterations: $iteration/$iterations ~ ETA: ${secondsToETA((stopwatch.elapsedMicroseconds * (iterations - iteration)) ~/ 1000000)}'); + 'Iterations: $iteration/$iterations ~ ETA: ${secondsToETA((stopwatch.elapsedMicroseconds * (iterations - iteration)) ~/ 1000000)}', + ); } + stopwatch.reset(); } } diff --git a/lib/src/neurons/neuron.dart b/lib/src/neurons/neuron.dart index 283bbde..c2720c2 100644 --- a/lib/src/neurons/neuron.dart +++ b/lib/src/neurons/neuron.dart @@ -116,7 +116,7 @@ class Neuron { } if (this.inputs.isNotEmpty) { - this.inputs[0] = input!; + this.inputs.first = input!; } else { this.inputs.add(input!); } @@ -142,5 +142,5 @@ class Neuron { /// it will output the weighted sum of the [inputs] and [weights], passed /// through the activation function. double get output => - weights.isEmpty ? inputs[0] : activation(() => dot(inputs, weights)); + weights.isEmpty ? inputs.first : activation(() => dot(inputs, weights)); } diff --git a/lib/src/utils/mathematical_operations.dart b/lib/src/utils/mathematical_operations.dart index d15393a..4298e2a 100644 --- a/lib/src/utils/mathematical_operations.dart +++ b/lib/src/utils/mathematical_operations.dart @@ -1,27 +1,33 @@ /// Calculates the dot product of two lists double dot(List a, List b) { var result = 0.0; + for (var index = 0; index < a.length; index++) { result += a[index] * b[index]; } + return result; } /// Adds values in list [b] to list [a] List add(List a, List b) { final result = []; + for (var index = 0; index < a.length; index++) { result.add(a[index] + b[index]); } + return result; } /// Subtracts values in list [b] from list [a] List subtract(List a, List b) { final result = []; + for (var index = 0; index < a.length; index++) { result.add(a[index] - b[index]); } + return result; } diff --git a/lib/src/utils/value_generator.dart b/lib/src/utils/value_generator.dart index b71a625..f986e29 100644 --- a/lib/src/utils/value_generator.dart +++ b/lib/src/utils/value_generator.dart @@ -16,6 +16,9 @@ Iterable doubleIterableSync({double from = 0, double to = 0}) sync* { } /// Generates a list of size [size], filled with random `double` values. -List generateListWithRandomDoubles( - {required int size, double from = 0, double to = 0}) => +List generateListWithRandomDoubles({ + required int size, + double from = 0, + double to = 0, +}) => doubleIterableSync(from: from, to: to).take(size).toList(); diff --git a/lib/synadart.dart b/lib/synadart.dart index d87b0c8..0337127 100644 --- a/lib/synadart.dart +++ b/lib/synadart.dart @@ -1,3 +1,5 @@ +/// A limited but fully documented neural network library created for +/// educational purposes. library synadart; export 'src/activation.dart'; diff --git a/pubspec.yaml b/pubspec.yaml index 713a6cc..68a6ad1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,20 +1,20 @@ name: synadart -version: 0.4.3 +version: 0.4.4 description: >- - A simple-to-grasp, complete and fully documented Neural Network library, - written from scratch in Dart. + A limited but fully documented neural network library created for educational + purposes. homepage: https://github.com/wordcollector/synadart repository: https://github.com/wordcollector/synadart issue_tracker: https://github.com/wordcollector/synadart/issues environment: - sdk: '>=2.12.0 <3.0.0' + sdk: '>=2.17.0 <3.0.0' dependencies: # Logging - sprint: ^1.0.3 + sprint: ^1.0.4 dev_dependencies: - words: ^0.0.2+1 + words: ^0.1.1 diff --git a/test/synadart_test.dart b/test/synadart_test.dart index 4b99307..ab73b3a 100644 --- a/test/synadart_test.dart +++ b/test/synadart_test.dart @@ -1,4 +1 @@ -import 'package:synadart/synadart.dart'; - -void main() { -} +void main() {}