Skip to content

Commit 48d8410

Browse files
authored
Merge pull request #79 from Sergio0694/feature_batch-normalization
Feature batch normalization
2 parents 4bf0f20 + d5cc5a1 commit 48d8410

21 files changed

+1403
-63
lines changed

NeuralNetwork.NET/APIs/CuDnnNetworkLayers.cs

Lines changed: 10 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
using System;
2-
using System.Linq;
3-
using JetBrains.Annotations;
1+
using JetBrains.Annotations;
42
using NeuralNetworkNET.APIs.Delegates;
53
using NeuralNetworkNET.APIs.Enums;
64
using NeuralNetworkNET.APIs.Structs;
7-
using NeuralNetworkNET.Extensions;
5+
using NeuralNetworkNET.cuDNN;
86
using NeuralNetworkNET.Networks.Layers.Cuda;
97

108
namespace NeuralNetworkNET.APIs
@@ -17,22 +15,7 @@ public static class CuDnnNetworkLayers
1715
/// <summary>
1816
/// Gets whether or not the Cuda acceleration is supported on the current system
1917
/// </summary>
20-
public static bool IsCudaSupportAvailable
21-
{
22-
get
23-
{
24-
try
25-
{
26-
// Calling this directly would could a crash in the <Module> loader due to the missing .dll files
27-
return CuDnnSupportHelper.IsGpuAccelerationSupported();
28-
}
29-
catch (TypeInitializationException)
30-
{
31-
// Missing .dll file
32-
return false;
33-
}
34-
}
35-
}
18+
public static bool IsCudaSupportAvailable => CuDnnService.IsAvailable;
3619

3720
/// <summary>
3821
/// Creates a new fully connected layer with the specified number of input and output neurons, and the given activation function
@@ -132,41 +115,14 @@ public static LayerFactory Convolutional(
132115
public static LayerFactory Inception(InceptionInfo info, BiasInitializationMode biasMode = BiasInitializationMode.Zero)
133116
=> input => new CuDnnInceptionLayer(input, info, biasMode);
134117

135-
#region Feature helper
136-
137118
/// <summary>
138-
/// A private class that is used to create a new standalone type that contains the actual test method (decoupling is needed to &lt;Module&gt; loading crashes)
119+
/// Creates a new batch normalization layer
139120
/// </summary>
140-
private static class CuDnnSupportHelper
141-
{
142-
/// <summary>
143-
/// Checks whether or not the Cuda features are currently supported
144-
/// </summary>
145-
public static bool IsGpuAccelerationSupported()
146-
{
147-
try
148-
{
149-
// CUDA test
150-
Alea.Gpu gpu = Alea.Gpu.Default;
151-
if (gpu == null) return false;
152-
if (!Alea.cuDNN.Dnn.IsAvailable) return false; // cuDNN
153-
using (Alea.DeviceMemory<float> sample_gpu = gpu.AllocateDevice<float>(1024))
154-
{
155-
Alea.deviceptr<float> ptr = sample_gpu.Ptr;
156-
void Kernel(int i) => ptr[i] = i;
157-
Alea.Parallel.GpuExtension.For(gpu, 0, 1024, Kernel); // JIT test
158-
float[] sample = Alea.Gpu.CopyToHost(sample_gpu);
159-
return Enumerable.Range(0, 1024).Select<int, float>(i => i).ToArray().ContentEquals(sample);
160-
}
161-
}
162-
catch
163-
{
164-
// Missing .dll or other errors
165-
return false;
166-
}
167-
}
168-
}
169-
170-
#endregion
121+
/// <param name="mode">The normalization mode to use for the new layer</param>
122+
/// <param name="activation">The desired activation function to use in the network layer</param>
123+
[PublicAPI]
124+
[Pure, NotNull]
125+
public static LayerFactory BatchNormalization(NormalizationMode mode, ActivationType activation)
126+
=> input => new CuDnnBatchNormalizationLayer(input, mode, activation);
171127
}
172128
}

NeuralNetwork.NET/APIs/Enums/LayerType.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ public enum LayerType : byte
3030
/// </summary>
3131
Softmax,
3232

33+
/// <summary>
34+
/// A batch normalization layer, used to scale the input batch into a 0-mean, 1-variance activations map
35+
/// </summary>
36+
BatchNormalization,
37+
3338
/// <summary>
3439
/// An inception module, combining different kinds of convolution with a pooling operation
3540
/// </summary>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
namespace NeuralNetworkNET.APIs.Enums
2+
{
3+
/// <summary>
4+
/// An <see langword="enum"/> indicating the normalization mode to apply to the input data of a layer
5+
/// </summary>
6+
public enum NormalizationMode : byte
7+
{
8+
/// <summary>
9+
/// Activation-wise normalization, with a separate mean and variance value per activation
10+
/// </summary>
11+
PerActivation = 0,
12+
13+
/// <summary>
14+
/// Spatial normalization, with a single mean and variance value per input channel (feature map)
15+
/// </summary>
16+
Spatial = 1
17+
}
18+
}

NeuralNetwork.NET/APIs/NetworkLayers.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,5 +75,15 @@ public static LayerFactory Convolutional(
7575
[PublicAPI]
7676
[Pure, NotNull]
7777
public static LayerFactory Pooling(ActivationType activation) => input => new PoolingLayer(input, PoolingInfo.Default, activation);
78+
79+
/// <summary>
80+
/// Creates a new batch normalization layer
81+
/// </summary>
82+
/// <param name="mode">The normalization mode to use for the new layer</param>
83+
/// <param name="activation">The desired activation function to use in the network layer</param>
84+
[PublicAPI]
85+
[Pure, NotNull]
86+
public static LayerFactory BatchNormalization(NormalizationMode mode, ActivationType activation)
87+
=> input => new BatchNormalizationLayer(input, mode, activation);
7888
}
7989
}

NeuralNetwork.NET/APIs/NetworkLoader.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ internal static INetworkLayer CpuLayerDeserialize([NotNull] Stream stream, Layer
9090
case LayerType.Pooling: return PoolingLayer.Deserialize(stream);
9191
case LayerType.Output: return OutputLayer.Deserialize(stream);
9292
case LayerType.Softmax: return SoftmaxLayer.Deserialize(stream);
93+
case LayerType.BatchNormalization: return BatchNormalizationLayer.Deserialize(stream);
9394
default: throw new ArgumentOutOfRangeException(nameof(type), $"The {type} layer type is not supported by the default deserializer");
9495
}
9596
}

NeuralNetwork.NET/APIs/NetworkManager.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using NeuralNetworkNET.APIs.Interfaces;
99
using NeuralNetworkNET.APIs.Interfaces.Data;
1010
using NeuralNetworkNET.APIs.Results;
11+
using NeuralNetworkNET.APIs.Settings;
1112
using NeuralNetworkNET.APIs.Structs;
1213
using NeuralNetworkNET.Extensions;
1314
using NeuralNetworkNET.Networks.Graph;
@@ -141,13 +142,18 @@ private static TrainingSessionResult TrainNetworkCore(
141142
if (dropout < 0 || dropout >= 1) throw new ArgumentOutOfRangeException(nameof(dropout), "The dropout probability is invalid");
142143

143144
// Start the training
144-
return NetworkTrainer.TrainNetwork(
145+
NetworkSettings.TrainingInProgress = NetworkSettings.TrainingInProgress
146+
? throw new InvalidOperationException("Can't train two networks at the same time") // This would cause problems with cuDNN
147+
: true;
148+
TrainingSessionResult result = NetworkTrainer.TrainNetwork(
145149
network as NeuralNetworkBase ?? throw new ArgumentException("The input network instance isn't valid", nameof(network)),
146150
dataset as BatchesCollection ?? throw new ArgumentException("The input dataset instance isn't valid", nameof(dataset)),
147151
epochs, dropout, algorithm, batchProgress, trainingProgress,
148152
validationDataset as ValidationDataset,
149153
testDataset as TestDataset,
150154
token);
155+
NetworkSettings.TrainingInProgress = false;
156+
return result;
151157
}
152158
}
153159
}

NeuralNetwork.NET/APIs/Settings/NetworkSettings.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,15 @@ public static AccuracyTester AccuracyTester
3535
get => _AccuracyTester;
3636
set => _AccuracyTester = value ?? throw new ArgumentNullException(nameof(AccuracyTester), "The input delegate can't be null");
3737
}
38+
39+
/// <summary>
40+
/// Gets whether or not a neural network is currently being trained
41+
/// </summary>
42+
public static bool TrainingInProgress { get; internal set; }
43+
44+
/// <summary>
45+
/// Gets whether or not a neural network is currently processing the training samples through backpropagation (as opposed to evaluating them)
46+
/// </summary>
47+
internal static bool BackpropagationInProgress { get; set; }
3848
}
3949
}

NeuralNetwork.NET/APIs/Structs/Tensor.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ public static unsafe void TryFree([NotNull] params Tensor[] tensors)
340340
/// <summary>
341341
/// A proxy type to debug instances of the <see cref="Tensor"/> <see langword="struct"/>
342342
/// </summary>
343-
private struct _TensorProxy
343+
private readonly struct _TensorProxy
344344
{
345345
/// <summary>
346346
/// Gets a preview of the underlying memory area wrapped by this instance
@@ -352,7 +352,7 @@ private struct _TensorProxy
352352

353353
private const int MaximumRowsCount = 10;
354354

355-
private const int MaximumItemsCount = 40000;
355+
private const int MaximumItemsCount = 30000;
356356

357357
[SuppressMessage("ReSharper", "UnusedMember.Local")]
358358
public _TensorProxy(Tensor obj)

NeuralNetwork.NET/Extensions/DebugExtensions.cs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,13 @@ public static unsafe bool ContentEquals(this Span<float> x1, Span<float> x2, flo
2222
fixed (float* p1 = &x1.DangerousGetPinnableReference(), p2 = &x2.DangerousGetPinnableReference())
2323
{
2424
for (int i = 0; i < x1.Length; i++)
25-
if (!p1[i].EqualsWithDelta(p2[i], absolute, relative)) return false;
25+
if (!p1[i].EqualsWithDelta(p2[i], absolute, relative))
26+
{
27+
#if DEBUG
28+
System.Diagnostics.Debug.WriteLine($"[NO MATCH] {p1[i]} | {p2[i]} | diff: {(p1[i] - p2[i]).Abs()}");
29+
#endif
30+
return false;
31+
}
2632
}
2733
return true;
2834
}

NeuralNetwork.NET/Extensions/MiscExtensions.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,30 @@ public static ref T SwitchRef<T>(this bool flag, ref T left, ref T right)
7979
[MethodImpl(MethodImplOptions.AggressiveInlining)]
8080
public static float Abs(this float value) => value >= 0 ? value : -value;
8181

82+
/// <summary>
83+
/// Returns the minimum possible upper <see cref="float"/> approximation of the given <see cref="double"/> value
84+
/// </summary>
85+
/// <param name="value">The value to approximate</param>
86+
public static unsafe float ToApproximatedFloat(this double value)
87+
{
88+
// Get the bit representation of the double value
89+
ulong bits = *((ulong*)&value);
90+
91+
// Extract and re-bias the exponent field
92+
ulong exponent = ((bits >> 52) & 0x7FF) - 1023 + 127;
93+
94+
// Extract the significand bits and truncate the excess
95+
ulong significand = (bits >> 29) & 0x7FFFFF;
96+
97+
// Assemble the result in 32-bit unsigned integer format, then add 1
98+
ulong converted = (((bits >> 32) & 0x80000000u)
99+
| (exponent << 23)
100+
| significand) + 1;
101+
102+
// Reinterpret the bit pattern as a float
103+
return *((float*)&converted);
104+
}
105+
82106
/// <summary>
83107
/// Calculates if two values are within a given distance from one another
84108
/// </summary>

0 commit comments

Comments
 (0)