CryptoNets/NeuralNetworks/LLPoolLayer.cs

155 строки
6.2 KiB
C#
Исходник Обычный вид История

2019-06-04 11:16:50 +03:00
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
using MathNet.Numerics.LinearAlgebra;
using HEWrapper;
using System.Linq;
namespace NeuralNetworks
{
public class LLPoolLayer : BaseLayer
{
ConvolutionEngine convolutionEngine = new ConvolutionEngine();
double[] _Weights = null;
public double[] Weights { get { return _Weights; } set { _Weights = value; layerPrepared = false; } }
double[] _Bias = null;
public double[] Bias { get { return _Bias; } set { _Bias = value; layerPrepared = false; } }
public int[] InputShape { get { return convolutionEngine.InputShape; } set { convolutionEngine.InputShape = value; layerPrepared = false; } }
public int[] KernelShape { get { return convolutionEngine.KernelShape; } set { convolutionEngine.KernelShape = value; layerPrepared = false; } }
public double WeightsScale { get; set; } = 1.0;
public override double GetOutputScale()
{
return ((Weights == null) ? Offsets.Length : WeightsScale) * Source.GetOutputScale();
}
public int[] Stride { get { return convolutionEngine.Stride; } set { convolutionEngine.Stride = value; layerPrepared = false; } }
public bool[] Padding { get { return convolutionEngine.Padding; } set { convolutionEngine.Padding = value; layerPrepared = false; } }
public int[] Upperpadding { get { return convolutionEngine.Upperpadding; } set { convolutionEngine.Upperpadding = value; layerPrepared = false; } }
public int[] Lowerpadding { get { return convolutionEngine.Lowerpadding; } set { convolutionEngine.Lowerpadding = value; layerPrepared = false; } }
public int[] MapCount { get { return convolutionEngine.MapCount; } set { convolutionEngine.MapCount = value; layerPrepared = false; } }
private int kernelSize = -1; // the value -1 is used such that it will throw an exception if it was not computed
IVector[] weightWindows = null;
IVector[] biasVectors = null;
int[][] Offsets { get { return convolutionEngine.Offsets; } }
int[][] Corners { get { return convolutionEngine.Corners; } }
public Vector<double> HotIndices { get; set; } = null;
public override void Dispose()
{
if (weightWindows != null)
foreach (var w in weightWindows)
if (w != null) w.Dispose();
if (biasVectors != null)
foreach (var b in biasVectors)
if (b != null) b.Dispose();
weightWindows = null;
biasVectors = null;
}
public override void Prepare()
{
if (!layerPrepared)
{
convolutionEngine.Prepare();
kernelSize = KernelShape.Aggregate(1, (acc, val) => acc * val);
if (Bias == null) kernelSize++;
if (Weights == null) return;
PrepareWeightsWindows();
double BiasScale = GetOutputScale();
int maps = (MapCount == null) ? 1 : MapCount.Aggregate(1, (acc, val) => acc * val);
if (HotIndices == null)
{
HotIndices = Vector<double>.Build.Dense(Corners.Length) + 1;
}
if (Bias != null)
{
biasVectors = new IVector[maps];
ParallelProcessInEnv(maps, (env, taskIndex, mapIndex) =>
{
biasVectors[mapIndex] = Factory.GetPlainVector(HotIndices * Bias[mapIndex], EVectorFormat.dense, Source.GetOutputScale() * WeightsScale);
});
}
else
{
biasVectors = new IVector[maps];
ParallelProcessInEnv(maps, (env, taskIndex, mapIndex) =>
{
biasVectors[mapIndex] = Factory.GetPlainVector(HotIndices * Weights[(mapIndex + 1) * kernelSize - 1], EVectorFormat.dense, Source.GetOutputScale() * WeightsScale);
});
}
layerPrepared = true;
}
}
double ElementAt(double[] w, int[] Corner, int[] offset, int[] shape, int bias = 0)
{
var l = convolutionEngine.Location(Corner, offset, shape, bias);
if (l < 0) return 0;
return w[l];
}
void PrepareWeightsWindows()
{
int maps = (MapCount == null) ? 1 : MapCount.Aggregate(1, (acc, val) => acc * val);
weightWindows = new IVector[maps];
for (int m = 0; m < maps; m++)
{
var w = Offsets.Select(offset => ElementAt(Weights, null, offset, KernelShape, m * kernelSize));
weightWindows[m] = Factory.GetPlainVector(Vector<double>.Build.DenseOfEnumerable(w), EVectorFormat.sparse, WeightsScale);
}
}
public override IMatrix Apply(IMatrix m)
{
if (Weights == null) // pool without convolve
{
IVector vec = null;
ProcessInEnv(env =>
{
vec = Enumerable.Range(0, (int)m.ColumnCount).Select(i => m.GetColumn(i)).Aggregate((v1, v2) => v1.Add(v2, env));
vec.RegisterScale(vec.Scale * m.ColumnCount);
});
return Factory.GetMatrix(new IVector[] { vec }, EMatrixFormat.ColumnMajor, CopyVectors: false);
}
else
{
int maps = biasVectors.Length;
IVector[] res = new IVector[maps];
ParallelProcessInEnv(maps, (env, task, k) =>
{
using (var mul = m.Mul(weightWindows[k], env))
res[k] = mul.Add(biasVectors[k], env);
});
return Factory.GetMatrix(res, EMatrixFormat.ColumnMajor, CopyVectors: false);
}
}
public override int OutputDimension()
{
if (!layerPrepared) Prepare();
int count = Corners.Length;
if (Weights == null)
{
return count;
}
int maps = (MapCount == null) ? 1 : MapCount.Aggregate(1, (acc, val) => acc * val);
return count * maps;
}
}
}